By storing a list of positioned and floating descendants within the
stacking context tree node, we can eliminate the need for costly
paintable tree traversals during hit-testing.
This optimization results in hit-testing being 2 to 2.5 times faster
on https://ziglang.org/documentation/master/
This change modifies hit_test() to no longer return the first paintable
encountered at a specified position. Instead, this function accepts a
callback that is invoked for each paintable located at a position, in
hit-testing order.
This modification will allow us to reuse this call for
`Document.elementsFromPoint()` in upcoming changes.
Now, instead of resolving "transform" and "transform-origin" during the
construction of the stacking context tree, we do so during the layout
commit.
This is part of a refactoring effort to make the paintable tree
independent from the layout tree.
With this change, a stacking context can be established by any
paintable, including inline paintables. The stacking context traversal
is updated to remove the assumption that the stacking context root is
paintable box.
Grid specification https://www.w3.org/TR/css-grid-2/#z-order defines
special painting order for grid items which should be the same as for
defined for inline-blocks in CSS2.
Eventually we should not need the layout tree for anything when painting
and this code will only look at the paint tree. For now, this is just
another step in that direction.
Previously stacking contexts were only painted in steps 3, 8, and 9.
These steps are only meant to cover positioned elements (as per
https://www.w3.org/TR/CSS22/zindex.html). This meant that elements with
opacity (which forms a stacking context) could end up painted above
elements that actually occlude them.
Stacking contexts are sorted after building a tree of them. They are
sorted by z-index first, DOM tree order second.
Sorting was previously *very* slow on pages with many stacking contexts.
That was because the sort() function used Node::is_before() in the
quick_sort comparator to see if one StackingContext was before another.
is_before() does tree traversal and can take quite a long time per call.
This patch avoids all that by letting StackingContext know its index
among all StackingContexts within the same document in tree order.
There's a noticeable snappiness increase on the CSS-FLEXBOX-1 spec page,
for instance. :^)
...and also for hit testing, which is involved in most of them.
Much of this is temporary conversions and other awkwardness, which
should resolve itself as the rest of LibWeb is converted to these new
types. Hopefully. :thousandyakstare:
When mousing over twitter, 17% of time was spent computing stacking
context transform origins. Since this never changes after the stacking
context is created, we can cache it and avoid all that work.
This is mainly so we can easily read that matrix later, but also has the
benefit of only calculating the matrix once, instead of every time we
paint. :^)
Since there is currently no easy way to handle rotations and skews
with LibGfx this only implements translation and scaling by first
constructing a general 4x4 transformation matrix like outlined in
the css-transforms-1 specification. This is then downgraded to a
Gfx::AffineTransform in order to transform the destination rectangle
used with draw_scaled_bitmap()
While rotation would be nice this already looks pretty good :^)
Instead of calling quick_sort() every time a StackingContext child
is added to a parent, we now do a single pass of sorting work after the
full StackingContext tree has been built.
Before this change, the quick_sort() was ~13.5% of the profile while
hovering links on GitHub in the Browser. After the change, it's down to
~0.6%. Pretty good! :^)
SPDX License Identifiers are a more compact / standardized
way of representing file license information.
See: https://spdx.dev/resources/use/#identifiers
This was done with the `ambr` search and replace tool.
ambr --no-parent-ignore --key-from-file --rep-from-file key.txt rep.txt *