1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 05:07:35 +00:00
Commit graph

681 commits

Author SHA1 Message Date
MacDue
163b6bb401 LibWeb: Special case SVG masks during layout
Rather than try to lay out masks normally, this updates the TreeBuilder
to create layout nodes for masks as a child of their user (i.e. the
masked element). This allows each use of a mask to be laid out
differently, which makes supporting `maskContentUnits=objectBoundingBox`
fairly easy.

The `SVGFormattingContext` is then updated to lay out masks last (as
their sizing may depend on their parent), and treats them like
viewports.

This is pretty ad-hoc, but the SVG specification does not give any
guidance on how to actually implement this.
2024-03-12 08:51:50 +01:00
Timothy Flynn
842caf5e8c LibWeb: Do not shrink the CPU painter's corner clipping vector
If the provided ID is smaller than the corner clipping vector, we would
shrink the vector to match. This causes a crash when we have nested
PaintContext instances (as these IDs are allocated by PaintContext),
each of which perform radius painting.

This is seen on https://www.strava.com/login when it loads a reCAPTCHA.
The outer div has a border radius, which contains the reCAPTCHA in an
iframe. That iframe contains an SVG which also has a border radius.
2024-03-10 00:39:49 +01:00
Aliaksandr Kalenik
16f33aafda LibWeb: Always check paintable boxes children during hit-testing
Children of a paintable box are not guaranteed to be contained within
its border box. Therefore, during hit-testing, we must always check
them.

Fixes https://github.com/SerenityOS/serenity/issues/23219
2024-03-05 15:43:17 +01:00
Aliaksandr Kalenik
ee1d8a534d LibWeb: Remove wrappers for gradient painting command recording
These were adding unnecessary indirection, whereas recording painter
could be called directly.
2024-03-03 18:19:20 +01:00
Zac Brannelly
9165faca5e LibWeb: Support CSS property background-clip: text
From https://drafts.csswg.org/css-backgrounds-4/#background-clip
"The background is painted within (clipped to) the intersection of the
border box and the geometry of the text in the element and its in-flow
and floated descendants"

This change implements it in the following way:
1. Traverse the descendants of the element, collecting the Gfx::Path of
   glyphs into a vector.
2. The vector of collected paths is saved in the background painting
   command.
3. The painting commands executor uses the list of glyphs to paint a
   mask for background clipping.

Co-authored-by: Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
2024-03-03 15:33:12 +01:00
Aliaksandr Kalenik
d5e74b1bdc LibWeb: Use a precalculated list of positioned descendants for painting
This allows us to avoid the need for costly traversals to gather
boxes that have been saved during the construction of the stacking
context tree.

No behavior change intended.
2024-03-03 08:40:46 +01:00
Aliaksandr Kalenik
1bd20a4595 LibWeb: Skip large stacking context in gpu painter only if it allocates
Skipping all stacking contexts with a size larger than 10000px in one
dimension was a mistake because it also affects pages that are simply
tall due to having a lot of content. Instead, we only need to skip if
the stacking context requires the allocation of a framebuffer that
could possibly fail.

Fixes https://github.com/SerenityOS/serenity/issues/23397
2024-03-02 14:36:33 +01:00
Andreas Kling
1e14264d13 LibWeb: Avoid repeated layout lookups in resolve_paint_only_properties()
By caching the layout node and its computed values in locals, we can
avoid the small amount of redundant work needed to look them up every
single time.
2024-03-02 13:00:09 +01:00
Andreas Kling
8303e61912 LibWeb: Pass BorderRadiusData const& to normalize_border_radii_data()
This avoids making a bunch of temporary copies for no reason.
2024-03-02 13:00:09 +01:00
Andreas Kling
3ff5beb229 LibWeb: Add fast_is<T>() for SVGPaintable 2024-03-02 13:00:09 +01:00
Andreas Kling
881e7fcee1 LibWeb: Copy various flags from layout node to paintable
This removes indirection when asking if a paintable is positioned,
floating, etc.

Removes a bunch of 1-1.5% items in the profile when hovering links
on ziglang.org.
2024-03-02 13:00:09 +01:00
Andreas Kling
20ff69cd41 LibWeb: Add fast_is<T>() for InlinePaintable
dynamic_cast<InlinePaintable> was showing up in profiles when hovering
links on ziglang.org.
2024-03-02 13:00:09 +01:00
Andreas Kling
c4403fd28c LibWeb: Fix bogus ReplacedBox type check in StackingContext
We should be asking if the layout node is a ReplacedBox, not the
paintable.
2024-03-02 13:00:09 +01:00
Aliaksandr Kalenik
06c176bbfb LibGfx+LibWeb: Use ref-counted object to store glyph run
...to avoid allocating a copy of glyph run for painting commands. We
can't simply save pointers to a glyph run in layout/paintable tree
because it should be safe to deallocate layout and paintable trees
after painting commands are recorded, if in the future we decide to
move command execution to a separate thread.
2024-03-02 09:09:10 +01:00
Aliaksandr Kalenik
cf6999f5f3 LibWeb: Remove glyph run allocation in paint_text_fragment()
Instead of allocating a new glyph run to scale glyph positions and
fonts, a scale factor could be encoded in a paint command and applied
later during command execution.
2024-03-02 09:09:10 +01:00
Aliaksandr Kalenik
aeb5a0d9e8 LibWeb: Remove glyph run allocation in RecordingPainter::draw_text_run
Instead of allocating a new glyph run solely to shift each glyph by the
painter's offset, this offset could be encoded in a paint command and
applied later during command execution.
2024-03-02 09:09:10 +01:00
Andreas Kling
d1b5f55f91 LibWeb: Make Paintable::containing_block() return a PaintableBox*
Every single client of this function was immediately calling paintable()
on the result anyway, so there was no need to return a layout node!

This automatically leverages the cached containing block pointer we
already have in Paintable, which melts away a bunch of unnecessary
traversal in hit testing and painting. :^)
2024-03-01 17:57:10 +01:00
Aliaksandr Kalenik
2764966ccc LibWeb: Reduce paintable tree traversals during hit-testing
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/
2024-03-01 13:03:53 +01:00
Aliaksandr Kalenik
b821f7b283 LibWeb: Implement scrollbar painting
Introduces the rendering of scroll thumbs in vertical and horizontal
directions. Currently, the thumbs are purely graphical elements that
do not respond to mouse events. Nevertheless, this is beneficial as it
makes it easier to identify elements that should respond to scrolling
events.

Painting of scrollbars uncovers numerous bugs in the calculation of
scrollable overflow rectangles highlighting all the places where
elements are made scrollable whey they shouldn't be. Positively, this
issue might motivate us to pay more attention to this problem to
eliminate unnecessary scrollbars.

Currently, the scrollbar style is uniform across all platforms: a
semi-transparent gray rectangle with rounded corners.

Also here we add `scrollbar-width: none` to all existing scrolling
ref-tests, so they keep working with this change.
2024-02-28 07:51:13 -05:00
Aliaksandr Kalenik
c74fc4c171 LibWeb: Clean previous border radii clips in refresh_clip_state()
The list of border radii clips needs to be reset before being populated
with new clips that have refreshed positions. Besides fixing painting,
this also improves performance because the number of sample/blit
commands does not increase as we scroll.
2024-02-28 07:44:12 -05:00
Aliaksandr Kalenik
91378ded96 LibWeb: Apply scroll offset after clip in PaintableBox::before_paint()
The order is important because clip rectangles are calculated with the
scroll offset taken into account. Therefore, they need to be applied
before the scroll offset is changed, to avoid accounting for the scroll
offset twice.
2024-02-28 07:44:12 -05:00
Aliaksandr Kalenik
a0dc9584de LibWeb: Add "object-position" CSS property into ComputedValues 2024-02-27 16:53:13 +01:00
Aliaksandr Kalenik
677a00ed92 LibWeb: Add "object-fit" CSS property into ComputedValues 2024-02-27 16:53:13 +01:00
Aliaksandr Kalenik
22da83c295 LibWeb: Resolve "object-position" without unwrapping raw percentage
Use `to_px()` that accepts reference value instead.

No behaviour change intended.
2024-02-27 16:53:13 +01:00
Aliaksandr Kalenik
6f5a0bd5de LibWeb: Save image provider in ImagePaintable
Refactoring towards making paintable be independant from layout nodes.

No behaviour change intended.
2024-02-27 16:53:13 +01:00
Aliaksandr Kalenik
9fa22b60cf LibWeb: Save alt text in ImagePaintable
By saving string with alt text, image paintable no longer need to reach
into layout and DOM nodes while painting commands recording.

No behaviour change intended.
2024-02-27 16:53:13 +01:00
Aliaksandr Kalenik
18d26142f0 LibWeb: Skip StackingContext with erroneously large rect in GPU painter
If the GPU painter encounters a stacking context that requires the
allocation of a framebuffer so large, it is likely due to a layout
mistake, for now, we can skip it instead of crashing because of a
failed allocation.

Fixes https://github.com/SerenityOS/serenity/issues/22608
2024-02-26 07:40:42 +01:00
Aliaksandr Kalenik
bc640b72b1 LibWeb: Remove spammy dbgln about unsupported SVG mask content units
This one was annoying because it was printed before each repaint on
pages where this FIXME is relevant.
2024-02-25 11:11:25 +01:00
Aliaksandr Kalenik
9968c9f7a6 LibWeb: Fix hit-testing by excluding CSS transform from clip rect check
Transforms are applied to both clip rectangle and position, so we need
to remove the transform from clip rectangle before checking if position
falls within the clip rectangle.

In this change, the removal of transform is moved into
`Paintable::clip_rect()` that is shared between hit-testing and
painting.

This change fixes hit-testing in Discord's multifactor authentication
form.
2024-02-22 07:36:20 +01:00
Aliaksandr Kalenik
155070cfd8 LibWeb: Clamp scroll offset to valid range in set_scroll_offset()
By moving scroll offset clamp from `PaintableBox::scroll_by()` to
`PaintableBox::set_scroll_offset()`, we ensure that updates from
`Element::set_scroll_top()` and `Element::set_scroll_left()` are
constrained to a valid range.
2024-02-22 07:35:30 +01:00
Timothy Flynn
45a47cb32b LibWeb: Generalize ImageBox and ImagePaintable for any ImageProvider
They currently assume the DOM node is an HTMLImageElement with respect
to handling the alt attribute. The HTMLInputElement will require the
same behavior.
2024-02-19 11:07:30 +01:00
Aliaksandr Kalenik
cb97eef2cf LibWeb+WebContent: Remove "Painting" prefix from command executor names
Painting command executors are defined within the "Painting" namespace,
allowing us to remove this prefix from their names.

This commit performs the following renamings:

- Painting::PaintingCommandExecutor to Painting::CommandExecutor
- Painting::PaintingCommandExecutorCPU to Painting::CommandExecutorCPU
- Painting::PaintingCommandExecutorGPU to Painting::CommandExecutorGPU
2024-02-18 18:45:25 +01:00
Aliaksandr Kalenik
11d746a67f LibWeb+WebContent: Separate painting command list from RecordingPainter
Separating the recorder list from the painter will allow us to save it
for later execution without carrying along the painter's state. This
will be useful once we have a separate thread for executing painting
commands, to which we will have to transfer commands from the main
thread.

Preparation for https://github.com/SerenityOS/serenity/pull/23108
2024-02-18 18:45:25 +01:00
MacDue
957c20b676 LibWeb: Avoid infinite recursion when hit testing SVGs
Previously, step 5 of the stacking context hit testing would just call
`hit_test()` on the stacking context's paintable box. Which (at least
for SVGs) is just indirect infinite recursion (it'll end up right back
where it started after going through a few functions).

This now explicitly hit tests the descendants, which seems more correct,
and avoids the crash for SVGs, but nothing really seems to depend on
this step. Another solution (which I've done for a while working on
SVGs) is just to delete step 5 entirely, and nothing seems to break.

Fixes #22305
2024-02-18 18:33:11 +01:00
Aliaksandr Kalenik
9c99182b1e LibWeb: Change StackingContext::hit_test() to accept callback
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.
2024-02-14 06:56:22 +01:00
Aliaksandr Kalenik
95d91a37d2 LibWeb: Resolve outline CSS property before paint commands recording
Refactor to resolve paint-only properties before painting, aiming to
stop using layout nodes during recording of painting commands.

Also adds a test, as we have not had any for outlines yet.
2024-02-12 13:38:24 +01:00
Aliaksandr Kalenik
d4932196cc LibWeb: Account for all clipped border radii in containing block chain
With this change, instead of applying only the border-radius clipping
from the closest containing block with hidden overflow, we now collect
all boxes within the containing block chain and apply the clipping from
all of them.
2024-02-11 08:12:31 +01:00
Aliaksandr Kalenik
1ae416fa94 LibWeb: Add compute_combined_css_transform() for PaintableBox
This prepares for upcoming changes where the code that finds combined
CSS transform will be reused in `clear_clip_overflow_rect()`.
2024-02-11 08:12:31 +01:00
Aliaksandr Kalenik
76d1536307 LibWeb: Optimize scroll offset and clip state recalculation
In this commit we have optimized the handling of scroll offsets and
clip rectangles to improve performance. Previously, the process
involved multiple full traversals of the paintable tree before each
repaint, which was highly inefficient, especially on pages with a
large number of paintables. The steps were:

1. Traverse the paintable tree to identify all boxes with scrollable or
   clipped overflow.
2. Gather the accumulated scroll offset or clip rectangle for each box.
3. Perform another traversal to apply the corresponding scroll offset
   and clip rectangle to each paintable.

To address this, we've adopted a new strategy that separates the
assignment of the scroll/clip frame from the refresh of accumulated
scroll offsets and clip rectangles, thus reducing the workload:

1. Post-relayout: Identify all boxes with overflow and link each
   paintable to the state of its containing scroll/clip frame.
2. Pre-repaint: Update the clip rectangle and scroll offset only in the
   previously identified boxes.

This adjustment ensures that the costly tree traversals are only
necessary after a relayout, substantially decreasing the amount of work
required before each repaint.
2024-02-09 16:45:44 +01:00
Aliaksandr Kalenik
4a41a65ec5 LibWeb: Shift button paintable clip rectangle by scroll offset
Rectangles should be recorded using absolute coordinates, including
the scroll offset.
2024-02-06 13:06:16 +01:00
Aliaksandr Kalenik
d43dbe2842 LibWeb: Shift SVG paintable clip rectangle by scroll offset
Rectangles should be recorded using absolute coordinates, including
the scroll offset.
2024-02-06 13:06:16 +01:00
Aliaksandr Kalenik
36553d4566 LibWeb: Do not add CSS transforms into clip rect in PaintableWithLines
Painting command executor already accounts for CSS transforms so clip
rect only needs to be adjusted by scroll offset.
2024-02-03 20:05:09 +01:00
Aliaksandr Kalenik
1af466babf LibWeb: Fix invalidation of CSS properties that do not affect layout
Recently, we moved the resolution of CSS properties that do not affect
layout to occur within LayoutState::commit(). This decision was a
mistake as it breaks invalidation. With this change, we now re-resolve
all properties that do not affect layout before each repaint.
2024-02-03 09:28:03 +01:00
Aliaksandr Kalenik
5484062095 LibWeb: Apply scroll offset to PushStackingContext command
In cases where the stacking context painting requires a separate
bitmap, the destination position needs to be translated by the
scrolling offset to ensure it ends up in the correct position.
2024-02-01 13:38:45 +01:00
Aliaksandr Kalenik
dc47d01fdc LibWeb: Remove contained_by_inline_node flag in PaintableFragment
No longer used after we made inline paintables own their fragments.
2024-01-31 07:15:49 +01:00
Aliaksandr Kalenik
9dddd6b028 LibWeb: Account for scroll offset in overflow clip rect calculation
This change addresses an issue with overflow clipping in scenarios
where `overflow: hidden` is applied to boxes nested within elements
with `overflow: scroll`.

Fixes https://github.com/SerenityOS/serenity/issues/22733
2024-01-31 07:15:25 +01:00
Aliaksandr Kalenik
96d5f555e1 LibWeb: Simplify InlinePaintable::bounding_rect() implementation
No behavior change expected.
2024-01-30 14:50:25 +01:00
Aliaksandr Kalenik
16f1962f10 LibWeb: Use clip rectangles assigned to paintables in hit-testing
This change makes hit-testing more consistent in the handling of hidden
overflow by reusing the same clip-rectangles.

Also, it fixes bugs where the box is visible for hit-testing even
though it is clipped by the hidden overflow of the containing block.
2024-01-30 11:22:22 +01:00
Aliaksandr Kalenik
d3b983b201 LibWeb: Ensure scroll offsets and clip rects updated before hit-testing
Hit-testing relies on updated clip rectangles and containing scroll
offsets, so it's necessary to ensure that paintables have these elements
updated.

This also removes the enclosing scroll offsets update from
`Internals::hit_test()`, as it is no longer needed.
2024-01-30 11:22:22 +01:00
Aliaksandr Kalenik
d27b376699 LibWeb: Store clip border radii in CSSPixels instead of DevicePixels
Paintable boxes should not hold information stored in device pixels.
It should be converted from CSS pixels only by the time painting
command recording occurs.
2024-01-30 11:22:22 +01:00