Commit graph

1055 commits

Author SHA1 Message Date
Shannon Booth
f890f289a7 LibWeb: Use resolved subgrid inline size for row contributions
Row subgrid contribution sizing reused the parent grid's available
width, so descendants in flexible columns could contribute an unwrapped
height and then wrap during layout.

Use the resolved subgrid item width when measuring row contributions.
2026-06-22 18:27:22 +02:00
Shannon Booth
870aaa8a1f LibWeb: Resolve subgrid inline sizing before row contributions
When collecting row-axis contributions from subgrid descendants,
resolve the subgrid column metrics first so intrinsic height measurement
uses the correct inline size. This prevents text from being measured as
if it had no usable width, which inflated auto row sizes.
2026-06-22 18:27:22 +02:00
Andreas Kling
a1bc2a6223 LibWeb: Use Utf16StringBuilder for UTF-16 text assembly
Replace the remaining UTF-16-mode StringBuilder instances in LibWeb
with Utf16StringBuilder when they assemble Utf16String values or UTF-16
text views. This keeps those paths in UTF-16 throughout and uses
explicit ASCII append helpers for ASCII-only pieces.

Keep StringBuilder in place for JSON, markup, CSS serialization, and
other byte-oriented string construction paths.
2026-06-22 16:10:40 +02:00
Tim Ledbetter
0ec95a606f LibWeb: Use computed display value for ::first-letter layout wrappers
Previously, `::first-letter` elements were always wrapped in an inline
box, meaning these elements were not correctly blockified when floated.
2026-06-22 09:43:07 +02:00
Tim Ledbetter
360bfd66f6 LibWeb: Apply the font-variant-emoji property to font selection 2026-06-20 23:51:46 +02:00
Tim Ledbetter
57103da08d LibGfx+LibWeb: Make emoji font fallback presentation-aware
Previously, font selection ignored the Unicode emoji presentation of a
code point. Emoji-capable code points were always resolved through
pre-baked color emoji and symbol fonts. Text-default code points which
lacked the `Emoji_Presentation` property, were therefore rendered as
color emoji rather than text. We now classify each code point's default
presentation from its `Emoji_Presentation` property and any trailing
variation selector.
2026-06-20 23:51:46 +02:00
Andreas Kling
2bf1f41805 LibWeb: Make computed properties immutable
Move CSS animation values into a mutable overlay on computed properties
and make base computed style data immutable after construction. Base
style mutation now goes through a builder that is consumed on publish,
so installed styles no longer expose mutation APIs.

Build new base style data for inherited style updates instead of cloning
and mutating installed computed properties. Element-specific computed
style adjustments now run before publication, while animation and
transition updates continue to mutate only the animated overlay.
2026-06-20 23:43:17 +02:00
Tim Ledbetter
340ef361d8 LibWeb: Support anchor() in calc() trees
Previously, `anchor()`  was only resolved when it appeared bare in an
inset property. We now allow it to appear anywhere inside a `calc()`
tree.
2026-06-18 17:36:56 +01:00
Callum Law
2c6aa4d272 LibWeb: Apply null transform properties on style recomputation
When applying style in `Layout::Node::apply_style` we previously ignored
null `rotate`, `translate`, and `scale` values which left the old values
in place in the case of nonnull -> null changes.

Fixes #10125
2026-06-18 12:26:22 +02:00
Callum Law
8ebdaeab69 LibWeb: Transfer animation ownership to AnimatedBitmapDecodedImageData
Previously animation ownership was a messy split between
`AnimatedBitmapDecodedImageData` and the consumers (i.e.
`ImageStyleValueResource`, `HTMLImageElement`, and `SVGImageElement`)
with `AnimatedBitmapDecodedImageData` owning the frames and a current
frame index, and the consumers owning the rest of the state (e.g. loop
count, timers to drive the animation forward, their own current index).

This had a couple of main issues:
 - While `AnimatedDecodedImageData` partially synchronized animations by
   dropping unexpected advancement notifications, this didn't apply to
   other animation state which meant, for instance, that a later started
   consumer could drive the animation of an earlier one past the max
   loop count (albeit without invalidating the earlier consumer).
 - Multiple consumers didn't share frame timings, meaning animations
   could be up to a full frame out of sync visually.
 - Animations were paused depending on whether there were any consumers,
   this is different to the behavior in other browsers (where they
   continue regardless of whether there are any consumers).
 - It was an overgeneralization of how animations need to work - only
   `AnimatedBitmapDecodedImageData` works with an indexed frame model,
   with animated SVGs (although not yet implemented) relying on their
   internal event loop to be driven forward.

Given the above the new approach implemented in this commit is:
 - The API for `DecodedImageData` is animation system agnostic, only
   exposing `default_frame`, `current_frame`, and `restart_animation`
   methods not reliant on providing a specific frame index.
 - `AnimatedBitmapDecodedImageData` owns its own timer, loop count,
   etc. The animation starts when the first consumer registers and ends
   when the document is hidden or becomes inactive (or completes in the
   case of finite animations).
 - Consumers are invalidated by `AnimatedBitmapDecodedImageData` when
   required.

Tests have been added for:
 - Animations being paused when the document becomes inactive and
   restarted when it becomes active again.
 - Frame timings being synchronized across consumers.
 - Restarts triggered by `HTMLImageElement` applying to all consumers.
 - Processing ending once a non-infinite animation plays to completion.

The tests to ensure animations are cancelled when consumers are removed
(e.g. `animated-background-image-timer-stops-when-hidden.html`) have
been updated to assert the inverse since animation state is now per
resource not per consumer.
2026-06-18 10:44:25 +02:00
Callum Law
a7881ca3eb LibWeb: Register DecodedImageData consumers as clients
In a future commit, ownership of animation will be transferred from
these clients to `AnimatedDecodedImageData` and we will need a way to
invalidate them for new frames.

This also revealed some `ImageProvider`s which don't yet support
animated images (e.g. `<input type="file">`, `<object>`, etc) but that
is left as a FIXME for now.
2026-06-18 10:44:25 +02:00
Callum Law
74e04ed258 LibWeb: Add DecodedImageData::default_frame helper
The index based `frame(size_t, ...)` getter is going to be removed in a
future commit.
2026-06-18 10:44:25 +02:00
Callum Law
2335941e43 LibWeb: Register ImageObservers for all mask-images
As of 114c8a7 we paint all mask layers, not just the first, so we should
likewise observe all `mask-image` values, not just the first.
2026-06-18 10:44:25 +02:00
Tim Ledbetter
4ecfd0903f LibWeb: Allow transforms to apply to pseudo elements
Previously `is_transformable()` didn't take pseudo elements into
account.
2026-06-16 11:32:02 +02:00
Jelle Raaijmakers
cf3bb8c129 LibWeb: Distinguish first and last baseline sets in box_baseline()
box_baseline() applied CSS2's bottom margin edge rule for non-visible
overflow to every caller, so flex items with hidden overflow were
baseline-aligned by their margin edge instead of their text. CSS Align
scopes that rule to a box's last baseline set, while flex baseline
alignment and table cells use the first set, which always derives from
content. Parameterize box_baseline() on the requested baseline set and
propagate it through the recursive child lookup.
2026-06-16 10:39:02 +02:00
Callum Law
1fa1de72fd LibWeb: Simplify ImageProvider frame getters
Merge `current_image_frame` and `current_image_frame_sized` into a
single method which takes an `Optional<Gfx::IntSize>`.

Rename `default_image_frame_sized` to `default_image_frame` and make
it's `Gfx::IntSize` argument `Optional`.
2026-06-16 09:26:15 +02:00
Callum Law
a40b1183ad LibWeb: Hoist overloaded ImageProvider methods to base class
All of these overloads did the same thing so lets just define them in
the base class
2026-06-16 09:26:15 +02:00
Callum Law
60c6cc2f0f LibWeb: Remove unused ImageProvider methods 2026-06-16 09:26:15 +02:00
Shannon Booth
0d656c3027 LibWeb: Record abspos inline static positions as line-box markers
The static position of an absolutely positioned inline child is the
in-flow insertion point on the line where it appears. Previously this
was reconstructed after layout by walking previous siblings for a
line-box fragment. That lookup could match a fragment from an earlier
line and collapse multiple abspos children onto the same position,
especially in white-space preserving content.

Instead, drop a zero-width static-position marker into the line box at
the insertion point when each abspos child is encountered. The marker is
carried through normal line post-processing, including float intrusion,
text-align, justification, trailing-whitespace trimming and ellipsis, so
the final static position is resolved from the line itself.

Resolve marker-only trailing lines before removing them, so they can
provide static position without contributing line height.
2026-06-14 22:12:06 +02:00
Shannon Booth
96aa4b3ad3 LibWeb: Only apply CSS transforms to transformable elements
Add Node::is_transformable() per the CSS Transforms spec and gate
transform handling on it, so non-replaced inline boxes are no longer
transformed.
2026-06-14 22:12:00 +02:00
Andreas Kling
2464e2ebfa LibWeb: Allocate layout used values with bump allocator
Store UsedValues separately from the sparse layout index pages. The
pages now hold pointers for O(1) lookup by layout index, while the
values are allocated from a uniform bump allocator owned by the paged
store.

This keeps pointer stability for containing-block links and avoids
placing large Optional<UsedValues> slots directly in every page.
2026-06-13 22:49:00 +02:00
Andreas Kling
956a2b96d5 LibWeb: Allocate layout and painting objects with mimalloc
Add class-local allocation macros for operator new/delete through AK's
malloc helpers. The macros can optionally choose a HeapPartition.
Add Layout and Painting partitions, plus basic partition stats helpers.

Use the new partitions for LibWeb layout and painting object hierarchies
and layout-state side data.
2026-06-13 19:08:08 +02:00
Jelle Raaijmakers
e0ca142184 LibWeb: Prevent flex/grid margin collapsing with its contents 2026-06-10 13:11:47 +02:00
Tim Ledbetter
e3b359ccab LibWeb: Stop mutating the input glyph run in append_glyph_run 2026-06-09 17:35:54 +02:00
Andreas Kling
048facc0b1 LibWeb: Avoid min-content sizing for fitting fit-content heights
Measure max-content before min-content for definite fit-content heights.
When the max-content height is no larger than stretch-fit, the clamp
resolves to max-content and min-content cannot affect the result.

Both intrinsic height measurements use the same available width, so this
preserves the existing width-dependent sizing behavior.
2026-06-08 19:10:25 +02:00
Andreas Kling
a92418c812 LibWeb: Avoid min-content sizing for fitting fit-content widths
Measure max-content before min-content for definite fit-content widths.
When the max-content width is no larger than stretch-fit, the clamp
resolves to max-content and min-content cannot affect the result.

Leave height sizing unchanged because its intrinsic measurements depend
on the width passed into the layout.
2026-06-08 18:10:13 +02:00
Andreas Kling
d7a5fca98b LibWeb: Avoid min-content sizing for fitting abspos boxes
Measure the preferred width first in absolutely positioned
shrink-to-fit cases. When it fits within the constraint equation's
available width, the preferred minimum width cannot change the result.

Keep the static-position branch setting the resolved content width
before reading the static position, but avoid the min-content layout
when it is not needed.
2026-06-08 18:10:13 +02:00
Andreas Kling
565df0da77 LibWeb: Avoid min-content sizing for fitting floats
Measure a floating auto-width box's max-content width before falling
back to its min-content width in the definite available-width branch.
If max-content already fits, shrink-to-fit resolves to that value and
the min-content contribution cannot affect the used width.

Also avoid the paired shrink-to-fit intrinsic measurement when an
intrinsic sizing constraint only needs one side of the contribution.
2026-06-08 18:10:13 +02:00
Andreas Kling
62d8757298 LibWeb: Avoid unneeded shrink-to-fit layout passes
When an inline-level box uses shrink-to-fit sizing, we do not always
need both intrinsic width calculations. Definite available space can use
the max-content width alone when it already fits, while min-content and
indefinite constraints only need the corresponding intrinsic width.

Avoiding the unused intrinsic layout pass keeps the sizing logic
equivalent while reducing work for common inline-block layouts.
2026-06-08 18:10:13 +02:00
Andreas Kling
8c63243b51 LibWeb: Avoid inflating 0fr grid rows from hidden overflow
Use the grid item minimum contribution when an intrinsic flexible track
sizing pass sees a scroll-container item crossing only zero-flex
tracks. This keeps collapsed 0fr rows from contributing their hidden
contents to an ancestor flex item's automatic height.

Add a text test covering an overflow-hidden grid item in a 0fr row
inside a column flex container, matching the dashboard sidebar pattern.
2026-06-08 10:06:07 +02:00
Andreas Kling
e23c657144 LibWeb: Avoid SVG getBBox paintable downcasts
SVG foreignObject elements expose SVGGraphicsElement methods, including
getBBox(), but their layout boxes create SVGForeignObjectPaintable,
rather than SVGGraphicsPaintable. Only SVGGraphicsPaintable stores the
computed SVG transform data, so use it only when that paintable kind is
present.

Add reduced crash coverage for calling getBBox() on a rendered
foreignObject element.
2026-06-08 01:04:08 +02:00
Andreas Kling
8f1dd07ae0 LibWeb: Stop SVG continuation recreation at non-box elements
When inline continuation restructuring recreates an inline ancestor
chain, SVG resource descendants can decline to create layout nodes.
Stop reconstruction at that point instead of dereferencing a null
layout node, and create the before wrapper when the nearest block
ancestor has no last child.

Add a reduced Crash/SVG test covering a block gradient inside a
paint server, reduced from the domato fuzz-00436 sanitizer finding.
2026-06-08 01:04:08 +02:00
Andreas Kling
227ca68d36 LibWeb: Skip style containment checks without style
The layout tree builder checks style containment after updating a node.
This scopes quote nesting to the containing subtree. Some layout nodes
lack style or a styled layout parent.

Only ask for style containment when computed values are available. Add
reduced crash coverage for the domato assertion.
2026-06-08 01:04:08 +02:00
Andreas Kling
dfa698b75e LibWeb: Avoid user-select lookup on unstyled layout nodes
Selection painting can happen before layout settles. Some layout nodes
then have no style or styled ancestor. They cannot contribute a
user-select exclusion.

Treat them as selectable for this check. Add a crash test reduced from a
domato case.
2026-06-08 01:04:08 +02:00
Andreas Kling
9340d2d1a3 LibWeb: Make layout nodes refcounted
Move the layout tree from GC allocation to refcounted ownership so
removed layout and paint subtrees are destroyed synchronously instead
of waiting for the next GC sweep. This dramatically reduces GC memory
usage peaks after layout tree churn and makes it easier for memory use
to fall back after large document updates.

Update layout factories, tree traversal, SVG layout node creation,
paintable back-pointers, and pseudo-element layout links to use RefPtr
ownership.

Make display: contents follow the same shape as Blink and WebKit: the
element itself does not create a layout node, and its children are
flattened into the nearest layout parent. Wrap direct non-whitespace
text in an anonymous inline node when the boxless element contributes
inherited style to that text.

Use an internal inline wrapper for display: contents pseudo-elements
so generated content can still participate in layout, painting, hit
testing, and pseudo-element queries. Keep CSSOM reporting the computed
display value from the pseudo style, not the internal wrapper.

Remove the retained out-of-tree layout node list and its testing hook,
since the flattened model does not need a side owner for boxless
elements. Add coverage for inherited text style, dynamic insertion
order, pseudo-element hit testing, and computed style queries.
2026-06-07 20:52:49 +02:00
Andreas Kling
0b94af1109 LibWeb: Stop tracing CSS style values
Remove the visit_edges hook from CSS::StyleValue and stop asking CSS
properties, descriptors, computed values, and layout nodes to trace
through their style values.

Style values are refcounted data objects, so they should not be part of
the GC graph. Keeping this cleanup separate makes the later layout tree
ownership change smaller and easier to review.
2026-06-07 20:52:49 +02:00
Andreas Kling
9c040f1dd3 LibWeb: Make generated content text layout-owned
Stop creating unattached DOM Text nodes for string items in generated
CSS content. These text nodes are layout artifacts, so store their text
directly in a GeneratedTextNode instead of pretending they have DOM
backing.

Teach text shaping and first-letter splitting to read text through the
layout text source while keeping DOM-specific behavior behind an
optional DOM text accessor. This preserves generated first-letter
handling without rooting fake DOM nodes.

Add crash coverage for generated content surviving GC and rebaseline
layout dumps that now identify generated text explicitly.
2026-06-07 20:52:49 +02:00
Andreas Kling
7c06c3fd14 LibWeb: Make computed style data refcounted
Move ComputedProperties and CascadedProperties out of the GC. They no
longer contain strong references to GC-managed data.

Keep computed styles alive from DOM elements and animation updates with
RefPtr. Pass style into layout constructors by reference, since layout
only copies the values it needs while building nodes.

Use GC::Weak for cascade source links, so entries no longer keep the
style declaration or shadow root alive.
2026-06-06 23:29:48 +02:00
Andreas Kling
222c1f7044 LibWeb: Move CSS image loading state to Document
Move the SharedResourceRequest, animation timer, and current frame
state out of ImageStyleValue and into a Document-owned table keyed
by resolved image URL. ImageStyleValue now keeps only URL metadata
and its client list, so image style values no longer need to trace
GC edges themselves.

Thread the Document through AbstractImageStyleValue APIs that need
decoded image data. CSS image fetches snapshot the stylesheet base URL,
referrer behavior, and origin-clean state instead of retaining the
stylesheet.

Remember each client's registered resolved URL when unregistering. This
keeps a later document base change from leaving an animated image
resource alive.

Add text coverage for inline relative image base URLs, stylesheet
referrers, imported stylesheet origin-clean behavior, inline @import
initiator type, and unregistering an animated background image after a
base element change.
2026-06-06 23:29:48 +02:00
Zaggy1024
e6664213ac LibWeb: Fall back to TextInputBox for unsupported input types
This isn't strictly correct as it stands currently, since the size
attribute isn't supposed to affect type="time" and others, but those
types currently end up with zero width instead.

Size could probably be applied through shadow DOM style, and the input
layout box would simply allow content sizing.
2026-06-05 12:49:24 +02:00
sideshowbarker
4df6ecd176 LibWeb: Ignore vertical-align on flex and grid items in box_baseline
Problem: Borked layout on (flex-styled) “D&D Beyond” site.

Cause: FormattingContext::box_baseline() was applying the box’s
vertical-align unconditionally. But vertical-align shouldn’t be
consulted for flex items or grid items.

Fix: Skip vertical-align handling in box_baseline() when the box is a
flex or grid item.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/9840
2026-06-05 10:11:06 +01:00
Andreas Kling
164ed80244 Meta: Enable exit-time destructor warnings for libraries
Enable -Wexit-time-destructors for all in-tree library targets and
update process-lifetime library statics so they no longer register
exit-time destructors. Long-lived caches, lookup tables, singleton
registries, and generated constants now use NeverDestroyed or leaked
references where the data is intended to live until process exit.

Update LibWeb, LibLine, and the binding generators so regenerated
sources follow the same rule instead of reintroducing destructed
statics.
2026-06-04 19:20:49 +02:00
Callum Law
65134fc5da LibWeb: Remove dead code around resolving accent-color <system-color>s
While the spec says that `accentcolor` and `accentcolortext` resolve
relative to the `accent-color` property this isn't implemented by any
other browsers.

This effectively reverts d04b745 but doesn't change behavior since that
was already done in 92897a1.
2026-06-04 16:14:05 +02:00
Tim Ledbetter
9de60cd4f9 LibWeb: Apply the text-anchor property to SVG textPath offset 2026-06-04 16:01:56 +02:00
Tim Ledbetter
ad7105b570 LibGfx+LibWeb: Implement SVGTextPathElement.startOffset 2026-06-04 16:01:56 +02:00
Tim Ledbetter
d92f93f34e LibWeb: Skip non-rendered text nodes in SVG textPath layout 2026-06-04 16:01:56 +02:00
Sam Atkins
26fdc5c09d LibWeb: Collect layout inspection data only when DevTools is connected
Grid and flex inspector payloads are only consumed by DevTools, but
layout currently builds them for every page. Gate that collection on an
active DevTools client so ordinary browsing avoids the extra CPU work
and retained memory.

DevTools may connect after the page has already completed layout, so
force one catch-up layout pass when the first DevTools client attaches.
After that, normal relayouts keep the data fresh until DevTools
disconnects. Inspection requests only flush dirty layout instead of
forcing repeated collection passes.

When DevTools detaches, clear the stored inspection data and overlays.
2026-06-01 17:39:32 +01:00
Sam Atkins
8c60d20dfc LibWeb: Keep grid template used values outside DevTools data
Resolved grid-template-columns and grid-template-rows values are needed
for getComputedStyle(), even when DevTools is not connected. Store them
separately from GridLayoutData again so the later lazy DevTools data
work can skip inspector-only geometry without changing CSSOM behavior.

Partly reverts 540b53ac1a.
2026-06-01 17:39:32 +01:00
Andreas Kling
3f45675731 LibWeb: Suppress assigned slot fallback layout
Skip layout tree construction for a slot's DOM children while it has
assigned nodes. These children are fallback content, and should only
produce boxes while assignment is empty.
2026-05-31 12:29:14 +02:00
Aliaksandr Kalenik
d725c36129 LibWeb: Store cached display list commands without resources
Cached display list command sequences used to carry their own
DisplayListResourceStorage. That kept resource ID sets and referenced
fonts, images, video frames, and nested display lists alive on every
cached phase, even though the command bytes already contain enough
information to discover those references when they are needed.

This makes cached command sequences store only command bytes. Resource
references are collected transiently from those bytes when a cache entry
is installed or invalidated. The navigable's central display list
resource storage now keeps cache reference counts, so compositor pruning
retains resources used by live cached commands without duplicating
storage in each sequence.
2026-05-31 00:21:25 +01:00