Commit graph

205 commits

Author SHA1 Message Date
Andreas Kling
884ae80699 LibHTML+Browser: Show target URL of hovered links in Browser statusbar
HtmlView will now invoke the on_link_hover hook when the cursor enters
or leaves a DOM node that has an enclosing link element.

This patch also updates the meaning of Node::enclosing_link_element()
to find the nearest HTMLAnchorElementAncestor *with an href attribute*.
2019-10-19 21:25:49 +02:00
Andreas Kling
73af2f8d02 LibHTML: DOM fixup should handle a completely empty document
We were forgetting to check if there was even a first child of the
root Document node.
2019-10-19 21:20:42 +02:00
Andreas Kling
b472229781 LibHTML: Do DOM tree fixup before firing insertion callbacks
There's no reason to run the callbacks before fixing up the tree.
2019-10-19 20:54:47 +02:00
Andreas Kling
f970578cd4 LibDraw: Rename ImageLoader => ImageDecoder
ImageLoader was not the right name for this, as there is no loading
happening, only decoding. :^)
2019-10-19 20:54:47 +02:00
Andreas Kling
025d3b49ab LibHTML: Make "display: inline-block" generate a LayoutBlock for now
We're gonna need some more smarts for this, but this at least gives
us something instead of an assertion.
2019-10-19 19:02:02 +02:00
Andreas Kling
96f34d26c9 LibHTML: Batch style updates and make them start from the root
Use a zero-timer to schedule a style update after invalidating style
on any node. Nodes now have a needs_style_update flag which helps us
batch and coalesce the work.

We also start style updates at the root and work our way through the
document, updating any node that has the needs_style_update flag set.
This is slower than what we were doing before, but far more correct.

There is a ton of room for improvement here. :^)
2019-10-19 19:00:31 +02:00
Andreas Kling
b3a63e1d50 LibHTML: Add TreeNode<T>::for_each_in_subtree(callback)
This helper invokes a callback for the node and each of its descendants
in pre-order.
2019-10-19 18:14:54 +02:00
Andreas Kling
fed668f20f LibHTML: Skip over CSS @media rules for now 2019-10-19 17:39:38 +02:00
Andreas Kling
6cbf8a3426 LibHTML: Use the correct inherited color for LayoutListItemMarker 2019-10-19 11:54:28 +02:00
Andreas Kling
5a34225999 LibHTML: Implement basic tiled background image support
It's now possible to set a page background image via <body background>.
Also, HtmlView now officially handles rendering the body element's
background (color, image or both.) LayoutBox is responsible for all
other background rendering.

Note that it's not yet possible to use CSS background-image properties
directly, since we can't parse them yet. :^)
2019-10-19 11:49:46 +02:00
Andreas Kling
762f20944c LibHTML: Replaced elements should not break lines at start of line
If the current line box already has zero width, there's no point in
inserting a line break to make space, since we'll just be at x=0 after
breaking as well.

This removes an ugly unnecessary line break before images wider than
their containing block. :^)
2019-10-19 09:44:40 +02:00
Andreas Kling
a5f3f332ed LibHTML: Ignore completed image loads for already-destroyed <img>'s
Capture a weak pointer to the element and pass that to the load finish
callback in HTMLImageElement::load_image(). This allows us to ignore
completed loads if the <img> element is no longer around.
2019-10-19 09:43:05 +02:00
Andreas Kling
877ff6bc13 LibHTML: Make TreeNode inherit from Weakable by default
This makes Node and LayoutNode weakable. Frame was already weakable.
2019-10-19 09:42:20 +02:00
Andreas Kling
87d13930ef LibHTML: Allow loading of PNG's directly into the HtmlView
When loading a URL that ends in ".png", we now construct a simple
DOM document to contain the image. It also shows the image dimensions
in the document title.

Because we use <img src> to load the image into the synthetic document,
we end up loading the image resource twice. This issue will go away
once we have a smarter, caching, loader mechanism.
2019-10-19 09:31:52 +02:00
Andreas Kling
60be51f908 LibHTML: Add a simple font cache
The FontCache caches the result of font lookups. The cache key is a
simple object called FontSelector which consists of the font family
and font weight (both strings.)

This drastically reduces time spent in font lookup.
2019-10-18 23:06:03 +02:00
Andreas Kling
07cbe2daa4 LibHTML: Preserve UTF-8 codepoints when collapsing whitespace
This is extremely awkward and I'm sure there are many better ways to
achieve this..
2019-10-18 22:50:44 +02:00
Andreas Kling
39546303da LibHTML: CSS parser should trim whitespace from values
This makes sure that values like "auto !important" don't have a space
character after "auto".
2019-10-18 17:14:25 +02:00
Andreas Kling
2305dee455 LibHTML: Add LayoutNode::first_ancestor_of_type<T>() 2019-10-18 10:16:33 +02:00
Andreas Kling
65ad6c35f0 LibHTML: Add typed child/sibling traversal helpers for LayoutNode
Also add some special variants for the table classes, to make it a bit
more pleasant to write table code. :^)
2019-10-18 09:38:12 +02:00
Andreas Kling
6202a0ab32 LibHTML: Only accumulate Text children's content in inline stylesheets
Some inline stylesheets use HTML comments like "<!--blah blah-->".
The HTML parser currently generates a comment child node of the <style>
element whenever this happens, and we don't want the comment itself to
be interpreted as part of the stylesheet.
2019-10-17 23:54:27 +02:00
Andreas Kling
9ac7b6fad1 LibHTML: Don't assert when encountering an unknown font-weight 2019-10-17 23:54:19 +02:00
Andreas Kling
6c22b46b37 LibHTML: Hard-code LayoutTable to never have inline children
This is a total hack to get around the auto-detection mechanism for
whether a block has inline or block children. We'll say that tables
never have inline children for now, and then anything that actually
turns out to be an inline child will just be ignored by layout.
2019-10-17 23:39:31 +02:00
Andreas Kling
b4c2621ed7 LibHTML: Add is<T> helpers for the table-related LayoutNode subclasses 2019-10-17 23:39:31 +02:00
Andreas Kling
5e29238a49 LibHTML: Make "children are inline" flag imperative
Instead of computing whether a block's children are inline based on the
first child, make it an imperatively-set flag.

This gives us some flexibility to ignore things like text nodes inside
a <table>, for example. I'm still unsure what the "correct" way to deal
with those will be. We'll find out sooner or later. :^)
2019-10-17 23:39:31 +02:00
Andreas Kling
41896ff521 LibHTML: Add stub classes for basic table layout
This class introduces LayoutTable, LayoutTableRow and LayoutTableCell.
These are produced by "display" values table, table-row and table-cell
respectively.

Note that there's no layout happening yet, I'm just adding the classes.
2019-10-17 23:39:31 +02:00
Andreas Kling
14f380f87a LibHTML: Use is_inline() instead of !is_block() when building tree 2019-10-17 23:39:31 +02:00
Andreas Kling
775cbbb422 LibHTML: Add basic keyboard navigation (up/down/pgdn/pgup/home/end/etc) 2019-10-17 23:39:31 +02:00
Andreas Kling
06f084fedd LibHTML: Add the <center> element
This is really just "center { display: block; text-align: center; }" in
the default stylesheet, but it totally works!
2019-10-16 20:33:00 +02:00
Andreas Kling
6dbba6ad85 LibHTML: Implement CSS text-align: left/center/right
This was easier than I imagined; we just shift each line box to the
left based on the alignment and the remaining space on each line. :^)
2019-10-16 20:32:17 +02:00
Andreas Kling
38b55ee067 LibHTML: LayoutBlock::hit_test() was calling the wrong parent class
Oops, we now need to call LayoutBox instead of LayoutNode for blocks
with non-inline children.
2019-10-15 22:02:58 +02:00
Andreas Kling
18fa662eb2 LibHTML: Use ImageLoader for <img> elements to defer bitmap decoding
We now wait until the pixels are actually needed before fully decoding
images in <img> elements.

This needs some more work and is currently a bit memory-wasteful since
we'll hang on to the raw image data forever.
2019-10-15 21:53:08 +02:00
Andreas Kling
b4c0ea89d5 LibHTML: Add the currently visible viewport rect to RenderingContext
This will allow rendering code to skip various things sometimes. :^)
2019-10-15 21:52:01 +02:00
Andreas Kling
5c2b21705a LibHTML: LayoutNode::set_needs_display() needs to invalidate fragments
If a LayoutNode is split into line box fragments, we need to walk our
fragments and invalidate them. It was not enough to do this only for
LayoutBox nodes.
2019-10-15 20:45:52 +02:00
Andreas Kling
110b2d52f2 LibHTML: Fix missing backgrounds an borders after LayoutBox refactoring
The render() implementation in both LayoutBlock and LayoutBox need to
be calling the immediate parent class. :^)
2019-10-15 19:12:56 +02:00
Andreas Kling
4814253589 LibHTML: Introduce LayoutBox and LayoutNodeWithStyleAndBoxModelMetrics
To streamline the layout tree and remove irrelevant data from classes
that don't need it, this patch adds two new LayoutNode subclasses.

LayoutNodeWithStyleAndBoxModelMetrics should be inherited by any layout
node that cares about box model metrics (margin, border, and padding.)
LayoutBox should be inherited by any layout node that can have a rect.

This makes LayoutText significantly smaller (from 140 to 40 bytes) and
clarifies a lot of things about the layout tree.

I'm also adding next_sibling() and previous_sibling() overloads to
LayoutBlock that return a LayoutBlock*. This is okay since blocks only
ever have block siblings.

Do also note that the semantics of is<T> slightly change in this patch:
is<T>(nullptr) now returns true, to facilitate allowing to<T>(nullptr).
2019-10-15 16:48:38 +02:00
Andreas Kling
f4f5ede10a LibHTML: Simplify Node::create_layout_node()
There's no need to pass the StyleResolver to this function. Nodes that
need it can just get it from the document.
2019-10-15 15:06:16 +02:00
Andreas Kling
f7cd5662ef LibHTML: Move layout tree building to a LayoutTreeBuilder class
Building a whole layout tree shouldn't be a concern of Node, so this
patch moves it to a separate class.
2019-10-15 14:24:26 +02:00
Andreas Kling
d14b60533f LibHTML: Add is<T> and to<T> helpers for LayoutNode class family 2019-10-15 14:24:26 +02:00
Andreas Kling
735f02900b LibHTML: Implement basic partial style invalidation
This patch makes it possible to call Node::invalidate_style() and have
that node and all of its ancestors recompute their style.

We then figure out if the new style is visually different from the old
style, and if so do a paint invalidation with set_needs_display().
Note that the "are they visually different" code is very incomplete!

Use this to make hover effects a lot more efficient. They no longer
cause a full relayout+repaint, but only a style invalidation.
Style invalidations are still quite heavy though, and there's a lot of
room for improvement there. :^)
2019-10-14 18:33:23 +02:00
Andreas Kling
667b31746a LibHTML: Rename Document's invalidate_{style,layout}() to update_foo() 2019-10-14 17:57:06 +02:00
Andreas Kling
61ef17b87a LibHTML: Implement basic :hover pseudo-class support
This is currently very aggressive. Whenever the Document's hovered node
changes, we invalidate all style and do a full relayout.

It does look cool though. So cool that I'm adding it to the default
stylesheet. :^)
2019-10-14 17:55:04 +02:00
Andreas Kling
605a225b53 LibHTML: Parse the :link and :hover CSS pseudo-classes
We don't actually do anything with these yet, but now the values will
be there for the selector engine to look at when it feels ready. :^)
2019-10-14 17:31:52 +02:00
Andreas Kling
3309bdf722 LibHTML: Add some convenient geometry getters on LayoutNode
Add x(), y(), size() and position() and use them around the codebase.
2019-10-13 18:47:16 +02:00
Andreas Kling
aefc7f9b22 LibHTML: Use LayoutBlock::add_line_box() in LayoutBreak 2019-10-13 18:47:16 +02:00
Andreas Kling
44979ad7a5 LibHTML: Fix broken line splitting behavior in LayoutReplaced
Replaced elements will now properly create line breaks when they use up
the available horizontal space.

This fixes an issue with <img>'s lining up instead of breaking.
2019-10-13 18:47:16 +02:00
Andreas Kling
0e61d84749 LibHTML: Run second layout pass if first layout adds/removes scrollbars
If you do a layout and it turns out that the page contents don't fit in
the viewport vertically, we add a vertical scrollbar. Since the
scrollbar takes up some horizontal space, this reduces the amount of
space available to the page. So we have to do a second layout pass. :^)

Fixes #650.
2019-10-13 16:31:31 +02:00
Andreas Kling
2c035f5072 LibHTML: Split layout invalidation into style and layout invalidation
When style is invalidated (for example when an external stylesheet
finishes loading) we delete the whole layout tree and build a new one.
This is necessary since the new style information may result in a
different layout tree.

When layout is invalidated (window resized, image dimensions learned,
etc..) we keep the existing layout tree but run the layout algorithm
once again.

There's obviously lots of room for improvement here. :^)
2019-10-13 12:51:16 +02:00
Andreas Kling
49ac0c2e24 LibHTML: Move layout root from HtmlView to Document
The layout root is now kept alive via Document::m_layout_root.
This will allow us to do more layout-related things inside the inner
layer of LibHTML without reaching out to the HtmlView.

I'd like to keep HtmlView at a slightly higher level, to prevent it
from getting too complex.

This patch also fixes accidental disconnection of the layout tree from
the DOM after doing a layout tree rebuild. ~LayoutNode() now only
unsets the DOM node's layout_node() if it's itself.
2019-10-13 12:43:31 +02:00
Andreas Kling
08209cc665 LibHTML: Handle comments in the CSS parser
Turn consume_whitespace() into consume_whitespace_or_comments() and
have it swallow /* comments */ as well.
2019-10-13 00:28:15 +02:00
Andreas Kling
b083a233d8 LibHTML: Add Comment and CharacterData nodes and improve HTML parsing
This patch adds the CharacterData subclass of Node, which is now the
parent class of Text and a new Comment class.

A Comment node is one of these in HTML: <!--hello friends-->
Since these occur somewhat frequently on the web, we need to be able
to parse them.

This patch also adds a child rejection mechanism to the DOM tree.
Nodes can now override is_child_allowed(Node) and return false if they
don't want a particular Node to become a child of theirs. This is used
to prevent Document from taking on unwanted children.
2019-10-12 23:34:05 +02:00