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.
Fragments contained by the inline node should be painted in the
foreground phase for this node, instead of being painted as a part of
the containing PaintableWithLines. This change implements that by
marking all fragments contained by inline nodes so they can be skipped
while painting the content of PaintableWithLines. This is an ugly way,
and instead, we should make InlinePaintables own all fragments
contained by them.
Instead of implementing stacking context painting order exactly as it
is defined in CSS2.2 "Appendix E. Elaborate description of Stacking
Contexts" we need to account for changes in the latest standards where
a box can establish a stacking context without being positioned, for
example, by having an opacity different from 1.
Fixes https://github.com/SerenityOS/serenity/issues/21137
Using a vector to represent a list of painting commands results in many
reallocations, especially on pages with a lot of content.
This change addresses it by introducing a SegmentedVector, which allows
fast appending by representing a list as a sequence of fixed-size
vectors. Currently, this new data structure supports only the
operations used in RecordingPainter, which are appending and iterating.
With this change, we create substantially fewer border painting
commands, which means fewer reallocations of the vector that stores
commands.
This makes the rendering of
https://html.spec.whatwg.org/multipage/browsing-the-web.html visibly
faster, where we allocated ~10 of such commands now vs ~8000 before.
With this change, instead of applying scroll offsets during the
recording of the painting command list, we do the following:
1. Collect all boxes with scrollable overflow into a PaintContext,
each with an id and the total amount of scrolling offset accumulated
from ancestor scrollable boxes.
2. During the recording phase assign a corresponding scroll_frame_id to
each command that paints content within a scrollable box.
3. Before executing the recorded commands, translate each command that
has a scroll_frame_id by the accumulated scroll offset.
This approach has following advantages:
- Implementing nested scrollables becomes much simpler, as the
recording phase only requires the correct assignment of the nearest
scrollable's scroll_frame_id, while the accumulated offset from
ancestors is applied subsequently.
- The recording of painting commands is not tied to a specific offset
within scrollable boxes, which means in the future, it will be
possible to update the scrolling offset and repaint without the need
to re-record painting commands.
If an image element has no alt attribute, other browsers don't fall back
to using the src attribute like we did.
This gave us a janky look while loading pages that other browsers don't
have, and it's not like seeing a partial URL is really helpful to the
user anyway.
Instead, we now pass String if we have one. In particular, this fixes an
issue where image elements with a data: URL src would copy the entire
URL string every time we painted (before the image had been decoded).
This was very noticeable on "fully downloaded" web pages where every
single image has been turned into a data: URL.
Before this change, we would only cache and reuse Gfx::ScaledFont
instances for downloaded CSS fonts.
By moving it into Gfx::VectorFont, we get caching for all vector fonts,
including local system TTFs etc.
This avoids a *lot* of style invalidations in LibWeb, since we now vend
the same Gfx::Font pointer for the same font when used repeatedly.
It is implemented in the way identical to how it works in CPU painter:
1. SampleUnderCorners command saves pixels within corners into a
texture.
2. BlitCornerClipping command uses the texture prepared earlier to
restore pixels within corners.
This commit un-deprecates DeprecatedString, and repurposes it as a byte
string.
As the null state has already been removed, there are no other
particularly hairy blockers in repurposing this type as a byte string
(what it _really_ is).
This commit is auto-generated:
$ xs=$(ack -l \bDeprecatedString\b\|deprecated_string AK Userland \
Meta Ports Ladybird Tests Kernel)
$ perl -pie 's/\bDeprecatedString\b/ByteString/g;
s/deprecated_string/byte_string/g' $xs
$ clang-format --style=file -i \
$(git diff --name-only | grep \.cpp\|\.h)
$ gn format $(git ls-files '*.gn' '*.gni')
Let's not assume there is one global OpenGL context because it might
change once we will start creating >1 page inside single WebContent
process or contexts for WebGL.
This fixes the issue that occurred when, after clicking an inline
paintable page would always scroll to the top. The problem was that
`scroll_an_element_into_view()` relies on `get_bounding_client_rect()`
to produce the correct scroll position and for inline paintables we
were always returning zero rect before this change.
Out-of-flow boxes (floating and absolutely-positioned elements) were
previously collected and put in the anonymous block wrapper as well, but
this actually made hit testing not able to find them, since they were
breaking expectations about tree structure that hit testing relies on.
After this change, we simply let out-of-flow boxes stay in their
original parent, preserving the author's intended box tree structure.
According to the CSS font matching algorithm specification, it is
supposed to be executed for each glyph instead of each text run, as is
currently done. This change partially implements this by having the
font matching algorithm produce a list of fonts against which each
glyph will be tested to find its suitable font.
Now, it becomes possible to have per-glyph fallback fonts: if the
needed glyph is not present in a font, we can check the subsequent
fonts in the list.
This change fixes a problem that we should not call `to_px()` to
resolve any length or percentage values during paintables traversal
because that is supposed to happen while performing layout.
Also it improves performance because before we were resolving border
radii during each painting phase but now it happens only once during
layout.
BorderRadiusCornerClipper usage to clip border radius is specific to
CPU painter so it should not be stored in painting commands.
Also with this change bitmaps for corner sampling are allocated during
painting commands replaying instead of commands recording.
Given that we have a glyph run where the position of each glyph is
calculated for text fragments during layout, we can reuse it to avoid
this work during painting.
Previously, we determined the positions of glyphs for each text run at
the time of painting, which constituted a significant portion of the
painting process according to profiles. However, since we already go
through each glyph to figure out the width of each fragment during
layout, we can simultaneously gather data about the position of each
glyph in the layout phase and utilize this information in the painting
phase.
I had to update expectations for a couple of reference tests. These
updates are due to the fact that we now measure glyph positions during
layout using a 1x font, and then linearly scale each glyph's position
to device pixels during painting. This approach should be acceptable,
considering we measure a fragment's width and height with an unscaled
font during layout.
If `SkipStackingContext` is returned we also need to restore saved
painter state because corresponding pop_stacking_context command that
is supposed to do that will be skipped.
Fixes https://github.com/SerenityOS/serenity/issues/22092
This change ensures that the GPU painting executor follows the pattern
of the CPU executor, where the state is stored for each stacking
context, but a painter is created only for those with opacity.
Fixes crashing on apple.com because now save() and restore() are called
on correct painters.