Commit Graph

35 Commits

Author SHA1 Message Date
Jelle Raaijmakers
90a211bf47 LibWeb: Use device-pixel coordinates in display list and AVC
Stop converting between CSS and device pixels as part of rendering - the
display list should be as simple as possible, so convert to DevicePixels
once when constructing the display list.
2026-02-26 07:43:00 +01:00
Andreas Kling
7f830a0533 LibWeb: Pass ResolvedBackground by const reference in paint_background
It was passed by value, copying a Vector<ResolvedBackgroundLayerData>
on every call. This function is called for every PaintableBox on every
frame.
2026-02-21 15:53:22 +01:00
Jelle Raaijmakers
f2e6f70fbb LibWeb: Use saveLayer compositing for background-clip: text
Instead of rendering text glyphs into a separate mask surface and using
clipShader, paint the backgrounds first and then composite the text
glyphs via saveLayer with SkBlendMode::kDstIn. Skia's saveLayer
automatically sizes its backing at device resolution including CSS
transforms, so no manual scale computation is needed.

Fixes pixelation when zooming in on clipped backgrounds on e.g. the
title of https://modern-css.com/.
2026-02-17 18:59:33 +01:00
Jelle Raaijmakers
aa2a95c775 LibWeb: Pass through background image painting even if area is empty
We should decide at a later stage, when we've calculated the final
background painting area, whether that area is empty and we can skip
painting the background.

Fixes #7973
2026-02-16 19:33:01 +01:00
Jonathan Gamble
b8ee6ec476 LibWeb: Use SizeWithAspectRatio struct 2026-02-02 14:36:49 +00:00
Aliaksandr Kalenik
cb8ecb3c11 LibGfx+LibWeb: Move SVG mask/clip composition from CPU to GPU
Previously, both mask and clip-path were rendered to separate mutable
Gfx::Bitmap objects which forced CPU rasterization. They were then
combined using a CPU pixel-by-pixel operation before being returned
as an ImmutableBitmap.

Instead of including mask in the final bitmap as already rasterized
images, we now use display lists which opens opportunity to utilize
GPU if available.

Bitmap::apply_mask() and ApplyMaskBitmap display list command are no
longer used and have been removed.
2026-01-23 16:23:06 +01:00
Aliaksandr Kalenik
009ddd4823 LibWeb: Integrate AccumulatedVisualContext with display list
Integrate AccumulatedVisualContext with display list recording and
playback. This is the main commit of the refactoring that delivers the
architectural improvements enabled by AccumulatedVisualContext.

Recording changes:

Each display list command now stores a single
RefPtr<AccumulatedVisualContext> instead of separate scroll_frame_id
and ClipFrame. The recorder simply captures the current accumulated
context when appending commands.

The before_paint()/after_paint() hooks that pushed/popped scroll frame
IDs are replaced by directly setting accumulated_visual_context on the
recorder before painting each element.

Playback changes:

The display list player now uses LCA (Lowest Common Ancestor) based
traversal to switch between visual contexts efficiently. When
transitioning from context A to context B:

1. Find the LCA of A and B in the context tree
2. Pop (restore) states back to the LCA depth
3. Push (save + apply) states from LCA down to B

This approach minimizes redundant save/restore operations. For example,
when rendering siblings that share a common scroll container, the
player keeps that scroll state applied and only switches the divergent
parts of their context chains.

Key deletions:

- Remove translate_by() from all 45 display list commands - commands
  are now immutable
- Remove transform/perspective fields from PushStackingContext -
  transforms are tracked via AccumulatedVisualContext
- Remove push_scroll_frame_id()/pop_scroll_frame_id() from
  DisplayListRecorder
- Remove before_paint()/after_paint() hooks from Paintable
- Merge ApplyOpacity, ApplyCompositeAndBlendingOperator, ApplyFilter
  into single ApplyEffects command

Stacking context painting changes:

The StackingContext::paint() method is significantly simplified.
Instead of building a PushStackingContextParams struct with transform
matrices and pushing/popping stacking contexts, it now:

1. Sets the accumulated visual context (which already contains
   transforms)
2. Applies effects (opacity, blend mode, filters) if needed
3. Applies clip path if needed
4. Paints the content
5. Restores state

The visual state management that was interleaved throughout the
painting code is now handled uniformly by the context tree.
2026-01-15 19:50:53 +01:00
Jonathan Gamble
555681bdb5 LibWeb: Split PaintableWithLines from PaintableBox
No functional changes. I just hope to improve code navigation.
2026-01-12 11:00:14 +00:00
Callum Law
79740b04b3 LibWeb: Don't generate layer for background-image none entry
Reduces the time spent in `background_layers()` from 1.5% to 0.04% when
loading https://en.wikipedia.org/wiki/2023_in_American_television
2026-01-05 11:35:26 +00:00
Callum Law
1708ce2e2b LibWeb: Propagate background-clip value for color layer separately
This is required for an optimization in a later commit
2026-01-05 11:35:26 +00:00
Callum Law
6964593377 LibWeb: Add absolutized method to EdgeStyleValue
Fixes #7192.

We absolutize `EdgeStyleValue` to always be relative to the top/left
edge which allows for some simplification.
2026-01-02 11:43:10 +01:00
Gingeh
5c0e707f01 LibWeb: Don't crash when rounded background image is too large 2025-12-30 12:26:55 +01:00
Jelle Raaijmakers
d352c4673c LibWeb: Pass sizes instead of rects to to_gfx_scaling_mode()
Position is irrelevant when determining the right scaling mode. No
functional changes.
2025-11-12 15:59:01 +01:00
Luke Wilde
eeb5446c1b LibWeb: Avoid including Navigable.h in headers
This greatly reduces how much is recompiled when changing Navigable.h,
from >1000 to 82.
2025-10-20 10:16:55 +01:00
Aliaksandr Kalenik
81aeee3fb4 LibWeb: Get rid of PaintableBox::is_viewport()
This function used layout node pointer to check if it's corresponding to
viewport. There is no need for that, since `is_viewport_paintable()`
does exactly the same check without going through layout node.
2025-10-14 11:23:29 +02:00
Sam Atkins
04622f3940 LibWeb/CSS: Use LengthPercentageOrAuto for background sizes
...instead of `auto` Lengths.

This also fixes interpolating between two `auto` `<bg-size>`s, which
fixes a lot of animation tests for both `background-size` and `mask`.
2025-09-04 13:31:24 +01:00
Tim Ledbetter
cb1a1a5cb5 LibWeb: Replace is<T>() with as_if<T>() where possible 2025-08-25 18:45:00 +02:00
Jelle Raaijmakers
64acef30ec LibWeb: Simplify filling rects with rounded corners
We can use BorderRadiiData::as_corners() to avoid converting the corners
one by one. Instead of passing all four corners one by one, use a
reference to CornerRadii.

No functional changes.
2025-08-19 21:53:46 +02:00
InvalidUsernameException
add3a095d8 LibWeb/CSS: Rename background-repeat related symbols to align with spec
These will be used for the mask-repeat property as well in an upcoming
commit, hence the more generic names. Also, this more closely matches
the names used in the spec.
2025-08-06 23:09:07 +01:00
Aliaksandr Kalenik
61114f6d16 LibWeb: Rename PaintContext to DisplayListRecordingContext
PaintContext dates back to a time when display lists didn't exist and it
truly represented "paint context". Renaming it to better align with its
current role.
2025-08-01 05:25:56 -04:00
Aliaksandr Kalenik
789016841e LibWeb: Pass device_pixels_per_css_pixel into DisplayList constructor
Having a setter for `device_pixels_per_css_pixel` was confusing because
display lists are immutable, so it doesn't make sense to override this
value after the display list has been created.
2025-07-27 10:20:18 +02:00
Aliaksandr Kalenik
0e8d70d8c3 LibWeb: Rename draw_text_run to draw_glyph_run in DisplayListRecorder
For consistency with corresponding display list item name.
2025-07-27 10:20:18 +02:00
Aliaksandr Kalenik
7e333cdcf7 LibWeb: Separate device pixel conversion helpers from PaintContext
In the upcoming change, device pixel conversion of ClipFrame will
happen during display list replay, where PaintContext is not available,
so let’s move it out of PaintContext.
2025-07-14 15:48:28 +02:00
Aliaksandr Kalenik
410e82c9fd LibWeb: Rearrange code such that a lot less files include Command.h
With this change number of recompiled files after modification of
`Command.h` goes down from >1000 to <100.
2025-07-11 17:37:27 +02:00
Aliaksandr Kalenik
46097c6753 LibWeb: Avoid unnecessary save/restore in paint_background()
`paint_background()` is invoked for each PaintableBox, so by avoiding
save/restore pair emitted for each call, we substantially decrease
display list size.

Website      | DisplayList Items Before | DisplayList Items After
-------------|--------------------------|-------------------------
ladybird.org | 2753                     | 1431
null.com     | 5298                     | 4714
discord.com  | 6598                     | 5360
2025-07-08 10:24:11 +02:00
Psychpsyo
93ae57114d LibWeb: Stop clipping the root element's background 2025-07-04 16:18:57 +01:00
Gingeh
fa410a67d9 LibWeb: Don't crash with near-zero background sizes 2025-07-02 11:45:34 +01:00
Jelle Raaijmakers
70b52e0994 LibWeb: Use efficient background repeat path for either direction
We're able to efficiently draw repeated bitmaps through Skia, but for
backgrounds we only did so if the background was `repeat-x` _and_
`repeat-y`, and not if just one was set. This meant that for backgrounds
that were only repeating in one direction, we were taking the slow path.
Turns out that this slow path also produced graphical artifacts when
zooming in and out, so let's not do that :^)
2025-05-09 21:37:48 +02:00
Glenn Skrzypczak
9973b01848 LibWeb/CSS: Improved implementation of background-blend-mode
This is a improved version of a73cd88f0c
The old commit was reverted in 552dd18696

The new version only paints an element into a new layer if background
blend modes other than normal are used. The rasterization performance
of most websites should therefore not suffer.

Co-Authored-By: Alexander Kalenik <kalenik.aliaksandr@gmail.com>
2025-04-01 13:38:00 +02:00
Aliaksandr Kalenik
552dd18696 Revert "LibWeb/CSS: Implement 'background-blend-mode'"
This reverts commit a73cd88f0c.

Emitting SaveLayer for each paintable made rasterization a lot slower
on every website because now Skia has to allocate enormous amounts of
temporary surfaces. Let's revert it for now and figure how to implement
it with less aggressive SaveLayer usage.
2025-03-28 16:48:03 +00:00
Glenn Skrzypczak
a73cd88f0c LibWeb/CSS: Implement 'background-blend-mode'
This implements the 'background-blend-mode' CSS property.
2025-03-28 09:41:06 +00:00
InvalidUsernameException
be47f95180 LibWeb: Reduce number of recompiled files for display list headers
This reduces the number of `.cpp` files that need to be recompiled when
one of the below header files changes as follows:

Painting/Command.h: 1030 -> 61
Painting/DisplayList.h: 1030 -> 60
Painting/DisplayListRecorder.h: 557 -> 59
2025-02-23 10:14:39 -05:00
Jelle Raaijmakers
7eb4f3da37 LibGfx: Add Rect::unite()
The existing `::unite_horizontally()` and `::unite_vertically()` tests
did not properly test the edge cases where left/top in the Rect were
updated, so they get re-arranged a bit.
2025-01-23 09:33:10 +01:00
Jelle Raaijmakers
4d9f17eddf LibGfx+LibWeb: Draw glyph runs with subpixel accuracy
This improves the quality of our font rendering, especially when
animations are involved. Relevant changes:

  * Skia fonts have their subpixel flag set, which means that individual
    glyphs are rendered at subpixel offsets causing glyph runs as a
    whole to look better.

  * Fragment offsets are no longer rounded to whole device pixels, and
    instead the floating point offset is kept. This allows us to pass
    through the floating point baseline position all the way to the Skia
    calls, which already expected that to be a float position.

The `scrollable-contains-table.html` ref test needed different table
headings since they would slightly inflate the column size in the test
file, but not the reference.
2024-12-21 23:09:52 +01:00
Timothy Flynn
93712b24bf Everywhere: Hoist the Libraries folder to the top-level 2024-11-10 12:50:45 +01:00