Commit Graph

28 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
Aliaksandr Kalenik
37ec6a08a8 LibWeb: Rename is_clip_or_mask to is_clip
The mask case was removed when AddMask was replaced with saveLayer+DstIn
compositing, so this flag now only applies to clip commands.
2026-02-24 07:14:16 +01:00
Aliaksandr Kalenik
0ac72e40d4 LibWeb: Remove the unused AddMask display list command
All mask call sites now use saveLayer+DstIn compositing, so the AddMask
command, its SkSL runtime shaders, and CachedRuntimeEffects are no
longer needed.
2026-02-24 07:14:16 +01:00
Aliaksandr Kalenik
5ef132ba1a LibWeb: Replace AddMask/clipShader with saveLayer+DstIn compositing
This applies the same pattern used for background-clip: text (commit
f2e6f70fbb).

Results in visible performance improvement in Discord app where
previously, according to profiles, we spent lots of time allocating
surfaces for masks.
2026-02-24 07:14:16 +01:00
Aliaksandr Kalenik
c7dc2ba0d3 LibWeb: Remove DrawPaintingSurface
No callers of draw_painting_surface remain after the previous commits
migrated canvas, video, and SVG to use ExternalContentSource or
ImmutableBitmap snapshots.
2026-02-20 18:41:33 +01:00
Aliaksandr Kalenik
291078dd87 LibWeb: Introduce ExternalContentSource
Two related problems exist in the current display list architecture:

1. DrawPaintingSurface thread safety: CanvasPaintable::paint() records
   the *same* PaintingSurface that the canvas rendering context draws
   to. The rendering thread later reads from it, but the main thread
   may be concurrently drawing — a data race.

2. Video frames force display list rebuilds: each new video frame
   triggers set_needs_display() → full display list rebuild.

Both stem from display list commands holding direct references to
content (surface/bitmap) rather than going through an indirection
layer.

ExternalContentSource is a thread-safe, atomically-refcounted
container that holds an ImmutableBitmap snapshot. The accompanying
DrawExternalContent display list command reads from it during replay,
so producers can swap in new content without rebuilding the list.

Subsequent commits migrate canvas, video, and SVG painting to
ExternalContentSource and then remove DrawPaintingSurface.
2026-02-20 18:41:33 +01:00
Aliaksandr Kalenik
44d90af3d6 LibGfx+LibWeb: Cache SkTextBlob in GlyphRun
Previously, SkTextBlob was built on every paint in
DisplayListPlayerSkia::draw_glyph_run(), which meant:
- Repeated work when the same display list is painted multiple times
- Glyph arrays were allocated and populated on each paint

Now the blob is built once during display list recording and cached in
GlyphRun.
2026-01-24 15:22:03 +01:00
Aliaksandr Kalenik
fcd155b257 LibWeb: Remove ApplyTransform display list command
ApplyTransform is no longer recorded to the display list. Transforms are
now applied inline during display list execution when switching between
accumulated visual contexts.

Change apply_transform to accept parameters directly instead of the
ApplyTransform struct.
2026-01-23 18:56:24 +01: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
7fc4ead027 LibWeb: Add bounding_rect() to DrawLine command
Computes the bounding rectangle from the line's start and end points,
inflated by the line thickness.
2026-01-22 17:01:59 +01:00
Aliaksandr Kalenik
cf39a17444 LibWeb: Add bounding_rect() to DrawRepeatedImmutableBitmap command
Returns the clip_rect as the bounding rectangle for this display list
command.
2026-01-22 17:01:59 +01:00
Aliaksandr Kalenik
ea0c02d21a LibWeb: Implement bounding_rect() for ApplyMaskBitmap 2026-01-22 12:18:34 +01:00
Aliaksandr Kalenik
98afd82491 LibWeb: Integrate clip-path into AccumulatedVisualContext
Previously, clip-path was applied only during painting in
StackingContext::paint(), which meant hit testing did not respect
clip-path boundaries. Clicks outside the visible clipped region but
inside the element's bounding box would incorrectly register as hits.

By moving clip-path into AccumulatedVisualContext, it becomes part of
the same system that handles transforms, clips, and scroll offsets for
both painting and hit testing, ensuring consistent behavior.
2026-01-16 13:39:02 +01:00
Aliaksandr Kalenik
932c2999e4 LibWeb: Delete unused Push{Pop}StackingContext commands
Remove the PushStackingContext and PopStackingContext display list
commands that are no longer used after the AccumulatedVisualContext
integration.

Previously, PushStackingContext was responsible for:
- Applying CSS transforms via its StackingContextTransform field
- Managing opacity layers
- Handling clip paths
- Tracking blend modes

All of this functionality has been replaced by:
- Transform/perspective tracking via AccumulatedVisualContext nodes
- The ApplyEffects command for opacity, blend modes, and filters
- The AddClipPath command for clip paths
2026-01-15 19:50:53 +01:00
Aliaksandr Kalenik
a87b5c722d LibWeb: Add AccumulatedVisualContext debugging infrastructure 2026-01-15 19:50:53 +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
Aliaksandr Kalenik
98660ad2b7 LibWeb: Introduce AddClipPath display list item
Introduce a new AddClipPath display list command that applies a
path-based clip region. This command is needed for the upcoming removal
of PushStackingContext, which currently handles clip paths as part of
its functionality. By extracting clip path handling into a dedicated
command, we can eliminate PushStackingContext entirely in favor of the
more granular AccumulatedVisualContext approach.
2026-01-15 19:50:53 +01:00
InvalidUsernameException
28ba610f32 Everywhere: Avoid large rebuilds when editing (Immutable)Bitmap headers
This reduces the number of recompiled files as follow:
- Bitmap.h: 1309 -> 101
- ImmutableBitmap.h: 1218 -> 75
2025-11-28 18:32:48 +01:00
Aliaksandr Kalenik
ba2926f8b3 LibWeb: Calculate and use bounds for "simple" stacking contexts
Teach the display list executor to derive a bounding rectangle for
stacking contexts whose inner commands can all report bounds, that is,
most contexts without nested stacking contexts.

This yields a large performance improvement on https://tc39.es/ecma262/
where the display list contains thousands of groups like:
```
PushStackingContext blending=Multiply
    DrawGlyphRun
PopStackingContext
```
Previously, `PushStackingContext` triggered an unbounded `saveLayer()`
even when the glyph run lies wholly outside the viewport. With this
change, we (1) cull stacking contexts that fall outside the viewport and
(2) provide bounds to `saveLayer()` when they are visible.

With this change rendering thread goes from 70% to 1% in profiles of
https://tc39.es/ecma262/. Also makes a huge performance difference on
Discord.
2025-09-24 22:11:24 +02:00
Aliaksandr Kalenik
2cf10981af LibGfx+LibWeb: Implement GlyphRun::bounding_rect()
Allows us to skip painting of glyph runs lying outside of viewport.
2025-09-23 17:55:32 +02:00
Tim Ledbetter
cfc6439c12 LibWeb: Use shape-rendering to control anti aliasing for SVG paths
Anti-aliasing is disabled if `shape-rendering` is set to
`optimizeSpeed` or `crispEdges`.
2025-08-19 09:47:28 +01:00
Aliaksandr Kalenik
41e3ddb7fa LibGfx+LibWeb: Remove aa_translation from StrokePath and FillPath
`aa_translation` is something we inherited from times when
AntiAliasingPainter was a thing. This change replaces it by applying
offset directly to path.
2025-08-03 10:42:33 +02:00
Aliaksandr Kalenik
a41d586117 LibWeb: Merge FillPathUsingPaintStyle and FillPathUsingColor
Use `Variant<PaintStyle, Gfx::Color>` in new `FillPath` instead of
duplicating two almost identical display list items.
2025-08-03 10:42:33 +02:00
Aliaksandr Kalenik
5c11a541d3 LibWeb: Merge StrokePathUsingPaintStyle and StrokePathUsingColor
Use `Variant<PaintStyle, Gfx::Color>` in new `StrokePath` instead of
duplicating two almost identical display list items.
2025-08-03 10:42:33 +02:00
Aliaksandr Kalenik
e41c85ec47 LibWeb: Replace DrawTriangleWave with StrokePathUsingColor
There's no need to have separate display list item for drawing triangle
wave when we could simply use StrokePathUsingColor. By switching to
StrokePathUsingColor we could also reduce painting because it supports
filtering out by bounding box.
2025-08-03 10:42:33 +02:00
Jelle Raaijmakers
525f609c9b LibWeb: Reuse display list command nesting level change for verification
No functional changes.
2025-08-01 14:20:51 +02:00
Jelle Raaijmakers
f28b7064ee LibWeb: Add indentation to display list dumps
Output display list dumps with an indentation level to show balanced
commands. It makes it much easier to see what is happening between e.g.
PushStackingContext and PopStackingContext, or SaveLayer and Restore.
2025-08-01 14:20:51 +02:00
Aliaksandr Kalenik
b265618bfb LibWeb: Rename Command to DisplayListCommand
Gives name more consistent with other display list related classes.
2025-08-01 05:25:56 -04:00