Commit graph

669 commits

Author SHA1 Message Date
Andreas Kling
c419bb526b LibWeb: Track connected SVG use elements in a per-document list
Every SVG element insertion, removal, attribute change, and children
change walked the entire document looking for use elements to notify
about possible referenced-subtree changes. On pages with large SVG
documents this is quadratic: loading chatgpt.com spent 7% of all CPU
samples in these full-document scans, nearly all of it while parsing
an SVG icon sprite sheet.

Instead, keep every use element connected to a document's node tree in
an intrusive list owned by that document, and only iterate that list
(usually empty or tiny) when an SVG element changes.

Subtleties:

- A use element inserted by the same subtree insertion as its
  referenced element, but after it in tree order, used to be found by
  the document-wide scan from the referenced element's insertion
  steps. Now SVGUseElement::inserted() re-resolves the reference if
  the shadow tree is still unpopulated. A new test covers both tree
  orders.

- Node.moveBefore() runs moving steps without insertion or removal
  hooks. Now SVGUseElement::moved_from() updates list membership when
  moving across document-tree and shadow-tree boundaries. A new test
  covers both directions.

- Removal hooks run after the subtree has been detached, so use
  elements being removed alongside the changed element may still be
  registered. Filter them out structurally via root().is_document(),
  since Node::is_connected() is a flag that is updated in hook order
  and can still be stale at this point.
2026-06-11 15:28:59 +02:00
Sam Atkins
e7aad5a9d3 LibWeb: Connect iframe referrerpolicy to ancestorOrigins
Corresponds to:
e161310ae7

This unfortunately isn't testable as we don't implement enough of
ancestorOrigins to be able to observe it.
2026-06-11 14:25:27 +01:00
Sam Atkins
935b9e8e41 LibWeb/DOM: Give Document ancestor origin lists 2026-06-11 14:25:27 +01:00
Andreas Kling
af8557c3b5 LibWeb: Avoid pruning live CSS image resources
Keep decoded image resources alive while they are backing a CSS image
resource for the document. Pruning these entries can make background
images temporarily non-paintable during display-list recording, causing
visible blank frames until the resource is requested again.
2026-06-11 01:27:57 +02:00
Andreas Kling
d641bfd7e2 LibWeb: Store custom property names as UTF-16
Move PropertyNameAndID, custom property data, registered custom
properties, and Typed OM associated property names to Utf16FlyString.

This removes the FlyString storage boundary from CSS property-name
handling and lets CSSStyleProperties keep the name it receives from
CSSOM instead of converting it back to UTF-8.
2026-06-09 11:48:02 +02:00
sideshowbarker
a82c7939d9 LibWeb+UI/AppKit: Implement macOS IME support
This makes macOS IME input in web content work as expected.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/9712
2026-06-08 10:23:14 +09:00
Andreas Kling
998fa908db LibWeb: Skip stale find-in-page range endpoints
Text blocks used by find-in-page can contain positions for nodes that no
longer form a valid live Range by the time matches are converted back to
DOM ranges. The offset checks handled stale text lengths, but endpoints
could also be disconnected or belong to different roots.

Reject those stale matches before constructing the Range. Add reduced
crash coverage for inserting text after a textarea and immediately using
window.find() to select that text.
2026-06-08 01:04:08 +02:00
Andreas Kling
51b831af9d LibWeb: Skip stale find-in-page text matches
Find-in-page builds live ranges from layout text block offsets. If the
DOM text node no longer contains the cached offset, constructing the
Range violates its boundary invariants.

Skip stale matches whose mapped offsets are outside the current text
node length. Add coverage for mutating text before window.find().
2026-06-08 01:04:08 +02:00
Andreas Kling
b42cf66a9a LibWeb: Handle child navigables without active documents
A queued document unload can capture child navigables whose active
document is gone by the time the task runs. In that state there is no
child document to unload, but the parent's lifecycle counter still needs
to advance.

Run the unload completion step directly when a child navigable has no
active document. Add coverage for removing an iframe during a child
navigation.
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
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
Sam Atkins
52e1d30404 LibWeb+LibDevTools: Report applied style rules to Firefox
Collect the style rules that apply to an inspected element and expose
them through the existing DOM node inspection path. This gives Firefox's
Rules panel real rule forms instead of the previous empty getApplied
response.
2026-06-04 20:54:33 +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
Aliaksandr Kalenik
5595efd46b LibWeb: Avoid display list rebuilds for VV changes
Visual viewport scroll and pinch zoom used to invalidate the full
accumulated visual context tree and display list, even though those
changes only modify the root visual viewport transform. That forced a
full display list rerecord before sending updated compositor state.

Patch the reserved visual viewport AVC node in place instead.
VisualViewport marks the tree for compositor update without
invalidating the display list, and Navigable sends the replacement tree
through the new IPC path before updating scroll state.
2026-06-03 02:12:39 +01:00
Aliaksandr Kalenik
78cda6a97e LibWeb: Reserve visual viewport AVC root
The accumulated visual context tree used index 0 as a null sentinel, so
visual viewport transforms were only represented by adding a normal
transform node when the transform was non-identity. That made callers
treat index 0 as a special no-context value and kept the tree shape
dependent on the visual viewport state.

Reserve index 0 as the visual viewport transform node instead. AVC
traversal, display-list replay, hit testing, debug dumping, and root
paint state now treat that node as a real root. Rebaseline the affected
display-list and async-scrolling text expectations so the explicit root
node appears in AVC dumps.
2026-06-03 02:12:39 +01:00
Andreas Kling
60847b9937 LibWeb: Respect page client focus for navigables
Make navigable focus depend on whether the page client currently has
system focus. WebContent already receives focus changes from the UI
process, but LibWeb did not consult that state when deciding whether the
top-level traversable was focused.

Repaint the text caret when WebContent focus changes so a focused text
control stops showing an active caret as soon as browser chrome takes
focus, and resets the blink cycle when page focus returns.
2026-06-03 02:53:37 +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
c4e8817246 LibWeb+Tests: Update layout before accessibility tree dumps
The accessibility tree builder consults layout nodes while applying
inclusion and exclusion rules. DevTools can request an accessibility
tree after style or layout has been dirtied, which made those
layout-node lookups trip the stale-layout verification.

Update layout before serializing the accessibility tree, matching the
DOM tree dump path. Add an internals regression test that dirties
layout before requesting an accessibility dump.
2026-06-01 08:28:45 +01: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
Andreas Kling
fe188b7d57 LibWeb: Make message drag selection more eager
Use selection-specific caret hit testing while starting and extending
mouse selections. The public caret-position API keeps its normal line
ranking, but selection drags now snap below-line movement to line edges
and prefer the previous line when starting in a nearby inter-line gap.

Add coverage for dragging from message text, after-text space, gutters,
author names, avatar-adjacent areas, and row bottoms so these inert
message regions reliably start selection.
2026-05-30 21:36:47 +02:00
Tim Ledbetter
eb9d4f6a20 LibWeb: Apply transform attribute to inner <svg> elements
Previously, transforms were ignored for SVGSVGElements.
2026-05-30 18:32:15 +01:00
Andreas Kling
acc86e9eb1 LibWeb: Add a caret hit-test debug overlay
Add a debug-menu toggle for caret hit testing at the mouse position.
Paint the insertion rect and log the result so selection bugs can be
inspected without temporary probes.

Request frames and repaint invalidation when the overlay state changes.
Also repaint when the caret rect moves within the same text node.
2026-05-30 13:50:48 +02:00
Andreas Kling
5c26e86354 LibWeb: Expose document caretPositionFromPoint
Add the CSSOM View CaretPosition interface and expose the Document API.
Use retained hit-test data to populate offsetNode, offset, and
getClientRect().

Update IDL coverage and the window property baseline. Add a text test.
2026-05-30 13:50:48 +02:00
Andreas Kling
7445cff5e8 LibWeb: Use retained data for hit testing
Build a hit-test display list while recording paint output. Use it as
source of truth for point hit testing instead of recursively walking the
paintable tree in reverse paint order.

The retained list records target paintables, visual context indices,
border radii, caret rects, and line metadata needed by hit testing. It
also keeps a spatial index so point queries inspect nearby items before
checking containment in paint order.

Refresh scroll state before hit testing so visual context transforms use
current scroll offsets. Add text tests for rounded hit regions and
selection across non-text content.
2026-05-30 13:50:48 +02:00
Aliaksandr Kalenik
c2f1cad2d7 LibWeb: Remove unused code from Document 2026-05-28 21:50:01 +02:00
Timothy Flynn
47b6f5e607 LibWeb: Do not send every decoded favicon to the UI process
If a page contains multiple <link rel="icon"> elements, we would send
each of them to the UI process. We would then just use whichever was
sent last as the favicon in the UI.

We now only send the favicon that was chosen for the document. This
will either be the largest icon decoded from a link element, or the
singular fallback icon.
2026-05-28 16:01:30 +02:00
Timothy Flynn
5f3ea017f5 LibWeb: Select the largest decoded favicon as the active page favicon
We currently pick the first favicon in reverse tree order. But we are
encouraged by the spec to pick the most appropraite icon. We now
consider the size of the decoded icon, and choose the largest.
2026-05-28 16:01:30 +02:00
Sam Atkins
5b2c649eda LibWeb/Painting: Paint flexbox inspector overlays 2026-05-28 12:58:46 +01:00
Andreas Kling
39ef840a51 LibWeb: Limit loading canvas fallback to pre-content documents
Only use the preferred color scheme for a loading top-level canvas
when the root used color scheme has not been computed yet. Once a
layout tree exists, non-opted pages still resolve system colors with
the default light scheme, so forcing a dark canvas makes them disagree
until parsing finishes.

Extend the loading canvas test to cover the non-opted case and reset
the test-only preferred color scheme override before finishing.
2026-05-27 20:57:38 +02:00
Andreas Kling
6ca9214b4c LibWeb: Respect root color scheme for loading canvases
Only use the loading-time top-level canvas fallback when the root
color-scheme value is still normal. An explicit light scheme on the
root element already gives the canvas a light used scheme, so replacing
it with the preferred dark scheme makes the viewport disagree with the
computed system colors until readiness advances.

Add internals coverage for the document canvas scheme and a text test
that exercises the loading state with a dark preferred color scheme.
2026-05-27 20:57:38 +02:00
Andreas Kling
203885be59 LibWeb: Use document schemes for canvas colors
Use document color schemes when choosing the canvas color for a root
whose color-scheme property is still normal. This keeps the transient
canvas aligned with the preferred scheme once a meta color-scheme has
been parsed, before style later recomputes the root used color scheme.

This avoids a light canvas frame while loading dark-capable pages in
dark mode without changing pages that explicitly force the root color
scheme.
2026-05-27 20:57:38 +02:00
Andreas Kling
1f8918aabd LibWeb: Update canvas colors for color-scheme changes
Recompute supported color schemes through a setter that invalidates
style and media queries. Use the preferred color scheme for a loading
top-level document until metadata or root style gives it a more specific
canvas scheme.

Add coverage for dynamically inserting a meta color-scheme element.
2026-05-27 20:57:38 +02:00
Andreas Kling
ab4356edea LibWeb: Let about:blank use dark color schemes
Opt empty about:blank documents into both light and dark supported
color schemes. This covers both navigation-created about:blank documents
and the initial about:blank document created with a browsing context, so
dark mode can choose the dark Canvas color before page content arrives.
2026-05-27 20:57:38 +02:00
Aliaksandr Kalenik
b36e6c9b97 Compositor+LibWeb: Pass AVC trees separately from display lists
Display lists owned the accumulated visual context tree through a
ref-counted pointer. That tied visual-context state to display-list
lifetime and made compositor updates treat the two as one unit, even
though AVC trees need to become independently updateable compositor
state.

Make accumulated visual context trees plain versioned values, have each
display list store the compatible tree version, and pass the matching
tree alongside display-list updates and replay calls. Replay verifies
that the provided tree matches the display list before executing it.

This prepares the compositor for receiving AVC tree updates separately
from display-list updates: it now accepts the tree as a separate update
parameter, stores it next to the display list, and uses that stored tree
for replay and async-scroll hit testing. Nested display-list resources
carry their own tree snapshots for the same version check.
2026-05-27 18:29:42 +01:00
Sam Atkins
2e430bb0b4 DevTools: Add grid layout WebContent plumbing
Add IPC structures and requests for inspecting grid layout data from
WebContent.

WebView forwards the async replies to LibDevTools and exposes the grid
highlighter hooks used by the protocol layer.

Parse Firefox grid highlighter options in WebContent and store them with
the active grid highlight.
2026-05-27 17:47:50 +01:00
Sam Atkins
4c55808bcb WebContent: Buffer DevTools DOM mutations until layout is safe
Snapshot DevTools DOM mutation payloads immediately, but defer subtree
serialization until the target document's layout is up to date.

This avoids re-entering layout-backed DOM serialization from style and
layout updates, which could crash WebContent while DevTools was
listening for mutations.
2026-05-27 15:52:46 +01:00
Andreas Kling
42f89bb679 LibWebView: Fast-close pages without beforeunload prompts
Track whether WebContent still needs a beforeunload check and let the
frontends immediately remove a tab or window when no prompt can be
shown. WebContent still receives the close request so pagehide, unload,
and cleanup steps can run.

When the visible view is removed immediately, keep detached ownership of
the WebContent page until it reports that the top-level traversable
closed. If no acknowledgement arrives, release detached ownership and
ask ProcessManager to shut down the unused WebContent process.
2026-05-26 20:40:25 +02:00
Andreas Kling
5a740161b3 LibWeb: Refresh animations after inherited restyles
Use the existing animated style update path when document style
recalculation reaches an element through inherited style recomputation.
Paused or filled animations can contain inherit, rem, rch, or other
font-relative keyframe values that depend on parent or root metrics.
Those dependencies can change even when the target's inherited computed
values do not otherwise change.

Make the document traversal opt in explicitly so animation-driven
inherited recomputation does not schedule another animation update while
propagating animated inherited values.

Add coverage for a media-gated root font-size change affecting a paused
rem-based animation. Update the font-stretch WPT expectation now that
its inherited-animation case passes.
2026-05-25 19:18:10 +02:00
Andreas Kling
ceb25e10d4 LibWeb: Avoid full viewport resize style invalidations
Use the viewport metric dependency flags to restyle only elements whose
computed values can change after a viewport resize. Descendants that
inherit changed values are reached through the existing inherited-style
update path.

Keep targeted style reads correct by treating pending media query
evaluation as style dirtiness. Seed the style computer with the latest
viewport before resolving pending animated style, so viewport-unit
keyframes do not use stale metrics.

Share pseudo-element recomputation with inherited-style updates, so
pseudos stay current when their originating element changes only via
inherited values.

Schedule animated style updates when inherited style recomputation can
affect existing animations.

Add viewport resize coverage for media queries, inherited font metrics,
monospace font-size recascade, line-height percentages, font-relative
and pending viewport-unit animations, inherited pseudo-elements, direct
pseudo viewport dependencies, and canvas currentColor reads.
2026-05-25 11:35:35 +02:00
Aliaksandr Kalenik
d149e55ff8 LibWeb: Store document intersection observers weakly
Use GC::WeakHashSet for the registry instead of IGNORE_GC. The notify
and layout update paths now snapshot the live weak entries into
RootVector before iterating, preserving the existing protection against
mutation while avoiding an unvisited strong GC container field.
2026-05-25 11:06:23 +02:00
Andreas Kling
1a9c7f564b LibWeb: Resume rendering after documents become visible
Request a rendering update after document visibility changes back to
visible. Hidden documents can leave animation frame callbacks or CSS
animation work pending after their last rendering update is skipped,
so showing the page needs to schedule a fresh rendering tick.
2026-05-25 01:32:20 +02:00
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