HTMLObjectElement will need to be both a FormAssociatedElement and a
BrowsingContextContainer. Currently, both of these classes inherit from
HTMLElement. This can work in C++, but is generally frowned upon, and
doesn't play particularly well with the rest of LibWeb.
Instead, we can essentially revert commit 3bb5c62 to remove HTMLElement
from FormAssociatedElement's hierarchy. This means that objects such as
HTMLObjectElement individually inherit from FormAssociatedElement and
HTMLElement now.
Some caveats are:
* FormAssociatedElement still needs to know when the HTMLElement is
inserted into and removed from the DOM. This hook is automatically
injected via a macro now, while still allowing classes like
HTMLInputElement to also know when the element is inserted.
* Casting from a DOM::Element to a FormAssociatedElement is now a
sideways cast, rather than directly following an inheritance chain.
This means static_cast cannot be used here; but we can safely use
dynamic_cast since the only 2 instances of this already use RTTI to
verify the cast.
If invoking a NodeFilter ends up deleting a node from the DOM, it's not
enough to only adjust the NodeIterator reference nodes in the
pre-removing steps. We must also adjust the current traversal pointer.
This is not in the spec, but it's how other engines behave, so let's do
the same.
I've encapsulated the Node + before-or-after-flag in a struct called
NodePointer so that we can use the same pre-removing steps for both the
traversal pointer and for the NodeIterator's reference node.
Note that when invoking the NodeFilter, we have to remember the node we
passed to the filter function, so that we can return it if accepted by
the filter.
This gets us another point on Acid3. :^)
This will help reduce the quite repetitive pattern of:
auto result_or_error = dom_node->do_something();
if (result_or_error.is_exception())
return result_or_error.exception();
auto result = result_or_error.release_value();
Similar to LibJS completions, this adds an alias to the error accessors.
This also removes the requirement on release_value() for ValueType to
not be Empty, which we also had to do for TRY compatibility in LibJS.
We were passing the wrong length argument to substring() when
stringifying a range where start and end are the same text node.
Also, make sure we visit all the contained text nodes when appending
them to the output.
This was caught by an Acid3 subtest.
I came across some websites that change an elements CSS "opacity" in
their :hover selectors. That caused us to relayout on hover, which we'd
like to avoid.
With this patch, we now check if a property only affects the stacking
context tree, and if nothing layout-affecting has changed, we only
invalidate the stacking context tree, causing it to be rebuilt on next
paint or hit test.
This makes :hover { opacity: ... } rules much faster. :^)
There's no actual need to build the stacking context tree before
performing layout. Instead, make it lazy and build the tree when it's
actually needed for something.
This avoids a bunch of work in situations where multiple synchronous
layouts are forced (typically by JavaScript) without painting or hit
testing taking place in between.
It also opens up for style invalidations that only target the stacking
context tree.
When updating layout inside a nested browsing context, try first to
perform layout in the parent document (the nested browsing context's
container's document).
This ensures that nested browsing contexts have the right viewport
dimensions in case the parent layout changes them somehow.
We were hanging on to element inline style, even after the style
attribute was removed. This made inline style sticky and impossible to
remove. This patch fixes that. :^)
Add a flag to DOM::Document that means the whole document needs a style
update. This saves us the trouble of traversing the entire DOM to mark
all nodes as needing a style update.
The old mode names, while mechanically accurate, didn't really reflect
their relationship to the CSS specifications.
This patch renames them as follows:
Default => Normal
AllPossibleLineBreaks => MinContent
OnlyRequiredLineBreaks => MaxContent
There's also now an explainer comment with the LayoutMode enum about the
specific implications of layout in each mode.
It makes no sense to require passing a global object and doing a stack
space check in some cases where running out of stack is highly unlikely,
we can't recover from errors, and currently ignore the result anyway.
This is most commonly in constructors and when setting things up, rather
than regular function calls.
This was causing us to miss layout invalidations. With this fixed, we
can remove the invalidation from Element::recompute_style() along with
the associated FIXME.
Thanks to Idan for spotting this! :^)
Instead of invalidating style for the entire document, we now locate the
nearest common ancestor between the old and new innermost hovered node,
and only invalidate that ancestor and its descendants.
This drastically reduces the amount of style update work when mousing
around on GitHub (and any other pages, really.) It's actually really
really snappy now. Very cool! :^)
Use the new CSS::property_affects_layout() helper to figure out if we
actually need to perform a full relayout after recomputing style.
There are three tiers of required invalidation after an element receives
new style: none, repaint only, or full relayout.
This avoids the need to rebuild the layout tree (and perform layout on
it) when trivial properties like "color" etc are changed.