Commit graph

627 commits

Author SHA1 Message Date
Aliaksandr Kalenik
c78dd59cc3 LibWeb: Move async scrolling recording to paintables
Async scrolling display-list items were still recorded by helper
functions in LibWeb/Compositor even though they are produced while
walking the paint tree. That kept paint-time knowledge about boxes,
viewport state, and wheel-event regions in the compositor-facing code.

Move viewport setup and final metadata emission to ViewportPaintable,
and move per-box scroll-node, hit-test, scrollbar, wheel-region, and
sticky-area item recording to PaintableBox. AsyncScrollingState now
keeps the compositor-side conversion and lookup logic for consuming the
recorded metadata.
2026-05-25 00:45:24 +02:00
Andreas Kling
8be96396d9 LibWebView: Use page background color while resizing
Notify the UI process with the solid canvas background color recorded
for the top-level document. This is the Canvas system color with the
effective document background composited over it, matching the color
used before normal painting.

Store that color on the view and use it when AppKit, Qt, and Gtk need
to fill areas exposed while an older bitmap is still on screen during a
window resize.
2026-05-24 23:41:41 +02:00
Andreas Kling
8d491d72f0 LibWeb: Keep flushing layout dirtied during layout
The layout loop added for container queries intentionally caps repeated
style/layout passes, since each layout can enqueue more size-query style
work. That cap should still apply, but absence of post-layout style work
does not by itself mean the document is clean.

Only leave the loop when there is no pending post-layout style work and
layout is up to date. Otherwise spend another capped pass flushing the
layout-only invalidation instead of falling through to the final
layout_is_up_to_date() verification.

Add crash coverage for a clientHeight read after nested container query
invalidations, matching the synchronous layout flush path.
2026-05-24 19:55:12 +02:00
Andreas Kling
412a66ad5e LibWeb: Repaint iframe containers after render unblocking
When an embedded document was render-blocked, the parent display list
recording skipped drawing that iframe's compositor surface. Once the
child document later unblocked, only the child surface was repainted, so
the parent could keep replaying a display list that had no surface draw
command until another invalidation, such as resize, forced a recording.

Invalidate the containing iframe when a document's render-blocking set
becomes empty so the parent display list records the child surface. Add
a deterministic reftest that gates a render-blocking stylesheet on a
test-server signal, forcing the parent to paint the blocked iframe
before unblocking it.
2026-05-24 12:24:50 +02:00
Andreas Kling
ca97f68cb7 LibWeb: Normalize decoded HTML string parsing
Preserve leading BOMs when parsing already-decoded HTML strings, since
those strings do not go through the encoded byte decoder path.

Decoded markup from JS strings can also contain WTF-8 for lone surrogate
code units. Keep the common scalar UTF-8 path to a single validation and
copy, but replace surrogates before handing bytes to the Rust tokenizer.

Add text coverage for DOMParser and innerHTML string parsing, including
leading BOMs, text and attributes, lone high and low surrogates, and a
valid surrogate pair.
2026-05-24 10:14:17 +02:00
Andreas Kling
762aea0568 LibWeb: Skip cosmetic blocking in SVG images
Do not build content blocker cosmetic style sheets for decoded SVG
image documents. These documents are resource documents created for
image painting rather than ordinary navigable documents, and other
engines keep extension cosmetic CSS out of them.

Add text coverage that verifies a generic cosmetic rule still applies
to the embedding HTML document while a matching element inside an SVG
loaded through <img> keeps rendering.
2026-05-24 09:58:10 +02:00
Andreas Kling
6ea2a4eff5 LibWeb: Refresh blocker CSS after relevant class/id changes
Refresh content blocker styles when connected elements gain or change
class or id tokens that can affect generic cosmetic selectors. Cache the
class and id tokens covered by each document's content blocker
stylesheet, then ask the adblock engine whether newly-added tokens can
unlock selectors before invalidating user style for the whole page.

This keeps dynamic cosmetic hiding correct without refreshing blocker
CSS for unrelated class and id mutations.

Add text coverage for irrelevant class/id mutations that should preserve
author style invalidation without refreshing blocker CSS. Also prove
matching tokens still hide elements.
2026-05-24 08:16:46 +02:00
Andreas Kling
fa579754bf LibWeb: Use invalidation plans for pseudo-class changes
Replace PseudoClassInvalidator's subtree scan with targeted
invalidation for elements whose pseudo-class state changes. This scopes
state changes to affected selectors instead of rechecking a whole
common-ancestor subtree.

Use the ancestor chain that matches each pseudo-class. Hover walks the
shadow-including chain. :focus-within walks the flat-tree chain, so
slotted content invalidates its assigned slot and relevant shadow-tree
descendants. Focus, FocusVisible, and Target invalidate just the state
node.

Route each affected element through Element::invalidate_style with the
pseudo-class property. This uses the same invalidation-plan machinery as
Disabled, Checked, and other pseudo-class state changes.

Interaction state pseudo classes are not tracked in :has() metadata, so
schedule :has() ancestor invalidation explicitly when the state flips.
The callers no longer need cross-scope branching. The chain walk handles
shadow boundaries, and property invalidation already visits every
observer style scope.
2026-05-23 23:37:36 +02:00
Andreas Kling
5cc6cb106d LibWeb: Cache content blocker styles per document
Build the user stylesheet only for document style scopes, since user
rules are already considered relevant across shadow boundaries during
rule matching. This avoids regenerating and reparsing the same cosmetic
content blocker stylesheet for every shadow root in the document.

Keep the generated cosmetic stylesheet cached on the Document and clear
it whenever user style is invalidated, so content blocker changes still
produce fresh CSS for the next style update.
2026-05-23 22:03:46 +02:00
Tim Ledbetter
988dce3e7a LibWeb: Drop :local-link rule-cache gate from base URL change handler
The base URL change handler checked whether any style scope contained
a `:local-link` rule before walking the document's links, this forced
a rule cache rebuild, which is generally slower than the link walk we
were trying to avoid.

On Speedometer2 the duplicated rule-cache and invalidation-set
construction accounted for roughly 4% of total samples. Removing the
gate lets the URL-unchanged early-exit handle the no-op case and runs
the link walk only when the URL actually changes, which the profile
showed to be inexpensive on its own.
2026-05-23 19:43:42 +01:00
Shannon Booth
637fd51595 LibWeb: Unify WebIDL C++ type generation
Represent WebIDL C++ types with a single CppType model that tracks
nullability, optional presence, and contained storage.

GC-like values now use GC::Ref/GC::Ptr directly, while containers choose
"plain", "Root", or "Conservative" container types depending on what
they contain. For example, sequence<Element> becomes a RootVector of
GC::Ref values, while sequence<SomeDictionary> becomes a
ConservativeVector only when the dictionary contains GC-like values.
This moves the generated bindings away from wrapping GC values in
GC::Root by default.

This has broad fallout as the types passed to interfaces for GC
objects changes almost fully across the board.
2026-05-23 18:26:12 +02:00
Andreas Kling
17902b02ab LibWeb: Stop idle animated CSS image timers
Keep animated ImageStyleValue frame advancement owned by the
style value. The current frame and loop state live there, so a
separate document scheduler would duplicate ownership of that state.

Start the ImageStyleValue timer only while it has layout clients.
Stop it when the last client unregisters, or when a finite animation
completes. Expose a document-scoped active timer count through
internals for focused regression tests.

Clear image observers when layout nodes detach. Use current-node
cleanup for per-DOM-node clearing, and explicit subtree cleanup for
tree replacement, full tree teardown, and synthetic pseudo-elements.
This keeps large document clearing linear.

Unregister generated-content image providers during layout detach
instead of waiting for GC to finalize the provider.

Cover hidden animated background images, generated content images,
layout node replacement, full layout tree teardown, and document
scoping for the internals counter.
2026-05-23 11:36:53 +02:00
Zaggy1024
a0b3b21011 LibWeb: Only fire document observers' fully active callbacks on change
Previously, the fully active callback could fire when the document was
never actually deactivated, which could cause a verification failure in
HTMLMediaElement due to its assumption that the callbacks only fire
when a document's fully active state genuinely changed.
2026-05-23 09:14:13 +02:00
Andreas Kling
7b6be1201d LibWeb: Resolve element style without a full document flush
Add a targeted update_style_for_element() mode that resolves one
flat-tree inheritance chain. Normal callers still get computed style in
display:none subtrees. Focusability stops when that chain resolves to
display:none.

The targeted path falls back to normal document style traversal for
document invalidation, full rebuilds, and selector work. That keeps
global dirty state consumed atomically. Local recomputation preserves
layout, display-list, slot, visual-context, and stacking-context
invalidation. It marks children dirty when a recomputed element can
affect descendant style.

Use StopAtDisplayNone for focusable-area rendering checks so incidental
is_focusable() queries do not repeatedly force unrelated document style
work. Rebaseline style invalidation counters for the reduced
getComputedStyle() recomputation scope.
2026-05-22 21:25:58 +02:00
Andreas Kling
b3e4372404 LibWeb: Share style invalidation side effects
Factor the element-level and document-level side effects from style
recomputation into helpers used by normal document style traversal. This
keeps existing behavior unchanged while letting the later targeted style
update path reuse the same invalidation bookkeeping.
2026-05-22 21:25:58 +02:00
Shannon Booth
2ae54d77e0 LibWeb: Reuse initial about:blank window for first same-origin load
Follow the spec reuse of the initial same-origin about:blank window for
a browsing context's first real navigation. This fixes a crash in
promise-job-entry-different-function-realm.html by preserving the
correct iframe realm.

However, reusing the initial about:blank Window means
create-and-initialize can associate that Window with the pending
Document before session history activation has made the Document active.
Treating a browsing context's active document as its active Window's
associated Document therefore exposes the pending Document too early.

To fix this, add an explicit active document slot to BrowsingContext and
update it when a Document is made active.

A similar fix was attempted in 7fc7263a4d,
but that version still queued navigation tasks through the reused active
Window, tagging them with the pending Document before it was active.
This caused parser-created iframe loads to hang in encoding WPTs. This
commit instead queues those navigation-internal tasks against the
navigable's currently active Document.

The newly added iframe-initial-load-chunked-body.html mimics the same
type of failure seen by the WPT regressions mentioned above.
2026-05-22 18:17:58 +02:00
Callum Law
4fd1635b17 LibWeb: Use correct event type for cancelled CSS transition
Previously we incorrectly dispatched a "animationstart" event instead of
a "transitioncancel" one
2026-05-22 11:59:19 +01:00
Callum Law
b0a818a476 LibWeb: Use correct scheduled time for Transition and Animation events
The spec doesn't say what time to use here but in other places where we
schedule animation events it says to use "the result of applying the
procedure to convert timeline time to origin-relative time to the
current time of the timeline with which animation is associated", so we
do that here as well.

This time is stable per animation frame per timeline so we now correctly
fall back to composite ordering of animation/transition events where we
previously wouldn't (since the scheduled time was so precise that it was
always unique), which causes the imported test to no longer be flakey.
2026-05-22 11:59:19 +01:00
Callum Law
b3a80f0415 LibWeb: Dispatch events for CSS animations without timelines 2026-05-22 11:59:19 +01:00
Callum Law
2a65e7c80c LibWeb: Use owning element as AnimationEvent target
The spec says we should always use the owning element even if the
effect's target element has changed
2026-05-22 11:59:19 +01:00
Callum Law
869ac61147 LibWeb: Apply animations without timelines when updating animated style
Previously we would only apply animations which were associated with a
timeline.
2026-05-22 11:59:19 +01:00
Callum Law
a1632cb1c1 LibWeb: Respect composite order in update_animated_style_if_needed 2026-05-22 11:59:19 +01:00
sideshowbarker
c1f38f92fe LibWeb: Keep repaints pending inside visibility:hidden iframes
Problem: An iframe whose content changes while it (or an ancestor)
has visibility:hidden isn’t painted once it becomes visible again.
The stale previous frame stays on screen until an unrelated
repaint (e.g., window resize) happens to occur.

Cause: set_needs_repaint() returns early for any document inside an
iframe with a visibility:hidden ancestor — discarding the request
entirely. The navigable’s needs_repaint flag is never set. Nothing
sets it again when the iframe becomes visible — so the rendering
loop keeps skipping it — and its display list stays stale.

Fix: Stop discarding the request in set_needs_repaint(). Instead,
skip painting hidden navigables in the rendering loop — while
leaving needs_repaint set. Once an ancestor iframe becomes
visible, the still-set flag makes the rendering loop paint the
navigable on the next frame.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/9305
2026-05-22 09:58:10 +01:00
Andreas Kling
e548c97b6d LibWeb: Limit non-inherited inherit tracking to direct children
Track explicit inherit of non-inherited properties only on the direct
parent shadow root. A deeper descendant with margin-left: inherit still
inherits from its own parent, so a host margin change does not require
marking every ancestor as possibly affected.

Extend the shadow-root inherited style test to cover both the direct
child case that must still update and the deeper descendant case that
must not trigger broad inherited-style recomputation.
2026-05-22 09:38:59 +02:00
Andreas Kling
ddce686ed0 LibWeb: Propagate inherited style across slot boundaries
Make style updates reach a fixed point when slot invalidation dirties
assigned nodes after their traversal point. During inherited-style
cascades, only the topmost changed element scans for descendant slots.

Animation inherited-style updates now include the target slot and walk
shadow-including descendants, so host animations propagate inherited
values through shadow trees and assigned slottables. Animated inherited
longhands also carry the same inherited-style invalidation signal as
regular style changes.

Mark custom elements dirty when their :defined state flips, so upgraded
elements do not keep stale :not(:defined) computed style. Add coverage
for slotted menu invalidation, descendant-slot scan counts, target slot
animations, host shadow-tree animations, and explicit inherit from an
animated non-inherited longhand.
2026-05-22 09:38:59 +02:00
Andreas Kling
d0b47e32c9 LibWeb: Propagate inherited style into shadow roots
Track when style recomputation may require inherited-style work in a
shadow tree, and use that signal when crossing from a shadow host into
its shadow root. Shadow descendants can explicitly inherit normally
non-inherited host properties, so any host style change may need
inherited-style recomputation there.

Use the CSS property definition to tell whether changed longhands need
to propagate to shadow descendants. Do the same after recomputing
inheritance-dependent values, such as host font-size: 2em after a parent
font-size change.

The shadow DOM tests cover inline and class-driven inherited host style
changes, explicit inherit for non-inherited host properties, relative
units on hosts, and nested slotted inheritance updates.
2026-05-22 09:38:59 +02:00
Andreas Kling
3f1a6926f4 LibWeb: Set about base URL before document URL
Install the inherited about base URL before setting the document URL so
fallback-base URL consumers see the correct source during URL-dependent
style and content blocker work.
2026-05-21 21:16:56 +02:00
Callum Law
0f92554427 LibWeb: Introduce Element::pseudo_element_unsafe_layout_node
This is used whereever we use `unsafe_layout_node`. There's no
difference in behavior for `SyntheticPseudoElement` but once we
implement element-reference pseudo-elements it will call
`unsafe_layout_node` on the referenced element rather than `layout_node`
2026-05-21 14:26:22 +01:00
Callum Law
28afdb327a LibWeb: Limit some pseudo-element functionality to synthetic only
Most of this functionality was already implicitly disallowed for
element-reference pseudo-elements by the fact that we weren't creating
entries in `m_pseudo_element_data` for them, but we need to explicitly
limit it in preparation of creating those entries.

Due to the above this is mostly non-functional apart from a regression
where we no longer support custom properties on element-reference
pseudo-elements. Previously when setting custom properties for an
element-reference pseudo-element we would call `ensure_pseudo_element()`
which created a synthetic pseudo-element entry distinct from the
referenced element which only stored custom property data - this was
clearly wrong and will be implemented properly in a future commit.
2026-05-21 14:26:22 +01:00
Callum Law
468c696ec7 LibWeb: Combine pseudo element clearing methods
These two methods were the same just with slightly different names and
badges so let's combine them.
2026-05-21 14:26:22 +01:00
Tim Ledbetter
d760cec702 LibWeb: Stop retaining fragment-parsing documents after adoption
When adopting an element, we now set the node document of each of its
attributes to the new document. Without this, `Attr` objects retained
document pointers back to a temporary document created during fragment
parsing, these documents were then kept alive after the parsed nodes
were moved into the real document.
2026-05-21 08:56:41 +02:00
Andreas Kling
94302775bf LibWeb: Map document element focus to the viewport
Apply the focusing steps' get-the-focusable-area mapping before
rejecting a non-focusable target. This preserves documentElement.focus()
by mapping the non-focusable document element to the Document viewport.

Also map rendered navigable containers with content navigables to their
active document, while leaving hidden containers unfocused. Preserve
Window focus events for child document viewports reached through iframe
focus, while still suppressing the top-level viewport surrogate events.

Treat rendered object elements as focusable through their default
non-null tabindex, even when they show fallback or image content instead
of a child navigable.

Keep the spec focus-chain common-tail handling intact for viewport
focus. The Document object is only our surrogate for the viewport, so
designate viewport focus from the new focus target without dispatching
Window focus/focusin events for that top-level surrogate.

Pass that viewport surrogate as the fallback target for fragment
scrolling and NavigateEvent focus reset, so unfocusable body or fragment
targets still clear stale element focus.

Cover documentElement.focus() in both the activeElement and focus-chain
tests, including a tabindex document element that remains focused as an
element. Cover object focus with and without a child navigable, hidden
object focus attempts, iframe focus events, hidden iframe focus, and
blurring a focused iframe after it becomes hidden. Also cover viewport
fallback for intercepted navigation focus reset and fragment scrolling
to an unfocusable target.
2026-05-21 08:56:05 +02:00
Shannon Booth
de6aec04e8 LibGC: Default-construct ConservativeVector from the global heap 2026-05-20 20:37:55 +02:00
Shannon Booth
387cd6e2e2 LibGC: Default-construct RootVector from the global heap
Similar to GC::Root<T>, make GC::RootVector<T> constructible without
explicitly passing a Heap.

This is implemented by having RootVectorBase use GC::Heap::the() for
heap-free construction.
2026-05-20 20:37:55 +02:00
Andreas Kling
1f358ae8f7 LibWeb: Fix nested SVG partial relayout transform lookup
Partial SVG relayout builds a throwaway layout state rooted at the
nearest dirty SVG viewport. SVG graphics layout can still walk past
intermediate SVG viewports when looking for ancestor transforms, so
pre-populate every SVG graphics ancestor instead of stopping at the
first ancestor SVG viewport.

Fixes an issue where the typing indicator would crash Discord when
someone starts typing a message. :^)
2026-05-20 14:55:18 +02:00
Sam Atkins
585849fcf0 LibWeb: Parse and evaluate @container <size-feature>s
e.g., `@container (width >= 300px) {}` and similar.

During style computation, flag any elements whose style depends on a
size container. Then re-evaluate their style after the initial layout
has been computed and size containers have a size. This may take
multiple passes, as these may have further descendants that depend on
their size, etc. We limit this to 8 passes currently.

SizeFeature itself is very similar to MediaFeature, but queries the
container element instead. There are only 6 size features specified, so
they're hard-coded instead of generated from JSON.

Also add a counter test for the narrower restyle path.
2026-05-20 13:00:50 +01:00
Andreas Kling
5d9641dd11 LibWeb: Precompute hover boundary event offsets
Avoid recomputing boundary event offsets after dispatch has started.
Boundary event listeners can invalidate layout while set_hovered_node()
is still synthesizing the rest of the event batch, and transformed
targets need the document paintable's visual context tree for offset
calculation.

Compute every target-specific offset before firing the first boundary
event, while the paint tree from the platform hit-test is still intact.
Keep a defensive fallback for a missing viewport paintable when applying
transforms.

Add a UIEvents text test that opens a popover from pointerout and then
continues into a transformed target.
2026-05-20 13:14:59 +02:00
Tim Ledbetter
b67d73a661 LibWeb: Apply ::first-letter pseudo-element styles
We now apply first letter styles by splitting text with a first-letter
style applied into 2 `TextSliceNode` objects.  The
`DOM::Text` layout  node always points at the non first-letter slice
and the first-letter slice is  reachable via
`TextSliceNode::first_letter_slice()`.

First letter splitting works by `TreeBuilder` walking a block
container's inline descendants to find the first typographic letter
unit per the pattern given in  css-pseudo level 4, which is then
wrapped in an anonymous inline box styled with the `::first-letter`
computed properties.

Consumers that map between DOM offsets and layout geometry
are updated to visit all slices of a `DOM::Text` through
`TextOffsetMapping`.
2026-05-20 12:09:19 +01:00
Andreas Kling
c4a31617ed LibWeb: Compute boundary event offsets per target
Recompute offsetX and offsetY for each synthesized mouse and pointer
boundary event target instead of reusing the offset for the original hit
target. Boundary event listeners on ancestors now observe coordinates
relative to their own targets.

Add a UIEvents text test that covers bubbling over/out events, enter
and leave events across multiple nested targets, partial exits into an
ancestor, and full exits to the test output element.
2026-05-19 11:22:02 +02:00
Andreas Kling
720e8e6db0 LibWeb: Populate platform mouse event data
Set platform pointer events as primary mouse pointer events. This lets
pages recognize real mouse input from pointermove before they install
mouse tracking behavior.

Also thread platform mouse coordinates through hover target changes.
This makes mouseover, mouseout, mouseenter, mouseleave, and matching
pointer boundary events trusted and gives them the coordinate data from
the originating platform mouse event.

Cover both paths with UIEvents text tests.
2026-05-19 11:22:02 +02:00
Tim Ledbetter
52e082c01f LibWeb: Skip style update inside display:none subtrees
Descendants of a display:none element are not rendered and their
computed style is only observable through on-demand reads. Skip the
recursive style descent at display:none ancestors during the
top-down traversal in `update_style_recursively()`.
2026-05-18 11:31:26 +02:00
Andreas Kling
1c7519f9ef LibWeb: Treat fragment parser documents as disconnected
Keep the temporary document used by HTML fragment parsing from
running post-connection work while the parser is staging nodes there.
This lets scripts from Range.createContextualFragment() remain
unstarted until the returned fragment is inserted into the real
document, and removes the script-specific preparation guard.

Strengthen parser coverage so contextual fragment scripts must wait
until the fragment is applied before running.
2026-05-17 15:35:56 +02:00
Andreas Kling
ccf5a278ab LibWeb: Keep deferred document.close cleanup on its parser
document.close() can defer script-created parser cleanup while a
parser-blocking script is pending. If document.open() installs a new
parser before the old parser resumes, the deferred action must clean up
the parser that scheduled it instead of the document's current parser.

Capture that parser before installing the deferred action. This keeps
the parked cleanup from affecting a parser installed by a later
document.open() call.
2026-05-17 15:35:56 +02:00
Andreas Kling
54879bc916 LibWeb: Complete Rust HTML tree construction
Finish the Rust implementation of the spec tree-construction algorithms
needed by the LibWeb test suite. Add the remaining table modes, foster
parenting, scope helpers, adoption agency handling, ruby/list/form and
select cases, frameset state, foreign-content edge cases, and parser
host callbacks.

Preserve behavior that depends on the C++ DOM integration, including
parser-created custom element reactions, fragment quirks mode, arbitrary
fragment namespaces, template fragment mode, fragment form ownership,
MathML annotation-xml boundaries, contextual fragment scripts, parser
script source positions, document.close() parser state, void-element
insertion, and duplicate attribute tracking.

Add focused tests for the parser edge cases that are easy to regress at
the boundary between the Rust tree builder and the C++ DOM host.
2026-05-17 15:35:56 +02:00
Andreas Kling
d312c4f427 LibWeb: Avoid repainting for unchanged animations
Animation updates need a rendering opportunity so current time can
advance and effects can update computed properties. They should not mark
the document as needing paint before any animated value changed.

Request a frame for pending animation style updates. The existing
AnimationUpdateContext invalidation will decide whether layout or paint
work is needed. This avoids presenting unchanged frames for infinite
animations on pages like x.com.
2026-05-17 00:29:45 +02:00
Andreas Kling
fe31d205a5 LibWeb: Bound per-document decoded image caches
Prune decoded image resources retained by active documents once they
grow beyond a recent working set. Route-heavy applications can load
many unique images through one Document, and the shared resource and
available-image caches would otherwise keep decoded image data alive
after the DOM stopped using those images.

Track cache touches and evict least recently used decoded images from
both caches. This keeps active documents from accumulating unbounded
decoded image resources while preserving a small hot cache for repeat
loads.
2026-05-17 00:29:18 +02:00
Aliaksandr Kalenik
8906011a6b LibWeb: Synchronize display list resources via transactions
Display lists used to own the resource storage needed to replay their
command bytes. That kept the compositor tied to in-process object
ownership: sending a display list update also meant sharing the same
resource container with the recording side.

Move resource storage out of DisplayList and make display list updates
carry a transaction of resources to add and remove. Navigable now tracks
the resources referenced by the current display list, sends only the
delta to the compositor, and trims its recording-side storage to the
active set. The compositor applies those transactions to its own storage
before replacing the cached display list.

This still carries in-process resource objects, but it puts the
ownership boundary in the right place. Command bytes and resource
lifetime are now synchronized explicitly, which is the shape needed
before the compositor can receive serializable resource updates across a
process boundary.
2026-05-16 19:35:24 +02:00
Andreas Kling
a36f8aa36d LibWeb: Keep ResizeObserver targets weakly
Store ResizeObservation targets weakly, matching Blink and WebKit. A
ResizeObserver can be kept alive by the document while it has observed
targets, but the observation itself should not keep a removed target and
its subtree alive forever.

Prune dead observations before gathering active resize observations.
Snapshot the document observer list before pruning so unregistering an
observer cannot mutate the intrusive list being iterated. Keep gathered
active targets rooted while broadcasting callbacks, since an earlier
callback can remove a later target and trigger GC before delivery.

Expose an internals helper to force environment-bound test objects to be
treated as garbage. Add text coverage for both pruning a dead observer
during gather and GC during an earlier resize observer callback.
2026-05-16 18:48:52 +02:00
Andreas Kling
8f194f8385 LibWeb: Drop removed ID elements from named cache
Remove every element from Document's potentially named element cache
when its id-bearing element is removed from the document. Dynamic id
changes add all elements to this cache so Window named properties can
observe them, but removal only pruned object and image elements. This
left ordinary removed elements, such as divs, strongly reachable from
the active document and kept their subtrees alive.
2026-05-16 14:39:04 +02:00
Tim Ledbetter
da210eaa9d LibWeb: Refresh stale inherited custom-property data on ancestor change
When an ancestor's custom property changes, intermediate elements that
don't themselves consume `var()`/`inherit()` were skipped during style
recomputation, leaving their `m_custom_property_data` pointing at the
ancestor's stale `CustomPropertyData`. Deeper descendants that did
consume `var()` then resolved against the out-of-date chain.

This change adds `Element::refresh_inherited_custom_property_data()` to
re-link an element's inherited chain to its parent's current data
without re-cascading. This is called during `update_style_recursively()`
for elements that don't need a full recompute.
2026-05-13 18:46:12 +02:00