Commit graph

2556 commits

Author SHA1 Message Date
R-Goc
520a7c8ebd AK+LibWeb: Centralize FFI helper functions
This commit creates a central FFIHelpers.h header which implements
common conversions from FFI.
2026-05-28 14:15:43 -05:00
Andreas Kling
43b9cfe5a9 LibWebView: Avoid white initial web view fills in dark mode
Seed the page background fallback from the platform color scheme before
WebContent has painted. Update the same fallback when the platform theme
changes, and when the preferred color scheme is forced through the debug
menu, so unpainted web view areas use the matching Canvas color.
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
540b53ac1a LibWeb: Preserve grid layout geometry for DevTools
Store grid container layout data on the grid container's paintable box
during layout.

The data includes computed track, line, and named-area geometry for
Firefox DevTools protocol serialization. It also carries the resolved
grid-template-columns and grid-template-rows values used by
getComputedStyle(), so PaintableBox does not need separate grid
template storage.
2026-05-27 17:47:50 +01:00
Sam Atkins
904a0dcf95 LibWeb/CSS: Resolve implicit scope roots
Resolve prelude-less @scope roots from the owning stylesheet context
during matching. This lets implicit scoped declarations target a style
element's parent. It also lets implicit shadow-root scopes use the
shadow host as the scoping root.
2026-05-27 15:32:11 +01:00
Sam Atkins
b3f6ec3ef2 LibWeb/CSS: Use :scope for scoped declarations
Use :where(:scope) for nested declarations directly inside `@scope`.

The concrete scoping root is supplied by `@scope` resolution during
selector matching, so CSSNestedDeclarations does not need to encode the
scope-start selector itself.
2026-05-27 15:32:11 +01:00
Shannon Booth
7893f02150 LibWeb: Port a bunch of GC::Root to GC::Ref / GC::Ptr 2026-05-26 21:43:55 +02:00
Aliaksandr Kalenik
6577d3f5b1 Compositor+LibWeb: Make display list flushing explicit
DisplayListPlayer::execute() used to flush the active painting surface
as part of replay. That made replay and submission inseparable, so
callers could not add extra painting after replay without either
accepting a stale submission boundary or flushing again.

Expose flush(PaintingSurface&) on the player and make execute() only
replay commands. Existing callers now issue an explicit flush at the
same point where the implicit flush used to happen, keeping behavior
unchanged while making the submission boundary visible to compositor
code.
2026-05-26 18:25:59 +01:00
Andreas Kling
fd6614215e LibWeb: Skip no-op custom property updates
Avoid rewriting CSSOM custom properties when the parsed value and
priority match the existing declaration. This mirrors the longhand
setProperty path and prevents repeated identical root custom property
writes from invalidating inherited style across the whole document.

Extend the style invalidation counter test to cover identical and
changed custom property assignments.
2026-05-25 21:17:16 +02:00
Andreas Kling
fac08ff8c6 LibWeb: Track compound inherited style dependencies
Use StyleValue's computational-independence predicate when deciding
which specified values to retain for inherited-style recomputation.
Compound values such as shadows, filters, lists, and calc trees now
reuse their existing dependency tracking instead of the old bare-length
check.

Treat missing tuple entries and keyword-only edge offsets as
computationally independent. These nullable slots are part of the
parsed value representation, and the inherited dependency tracking now
uses the shared computational-independence query for specified values.

Add viewport resize coverage for media query changes that update root
font metrics while a descendant uses font-relative lengths inside
box-shadow and filter values.
2026-05-25 19:18:10 +02:00
Andreas Kling
2a35973abd LibWeb: Target media query change invalidation
When @media rules change match state, avoid treating that as a
whole-document stylesheet change. Record the rules under the query
that became effective or ineffective, build the normal stylesheet
invalidation set from those rules, and invalidate only matching
elements. Keep broad invalidation for rule kinds whose effects are not
selector-targetable.

Preserve cascade-wide fallout by reusing stylesheet-change shadow
effect analysis for broad invalidations inside shadow roots. This keeps
:host and slotted content current when active rules in the same shadow
scope can match there.

Also report an imported stylesheet's owner rule when the imported
sheet's own media gate changes. Layered @import rules can affect layer
ordering even when the imported sheet contributes no rules, so they
need the same broad invalidation treatment as other cascade-wide rules.

Add viewport resize coverage for media query breakpoints, broad
shadow-root media invalidation, and empty layered imports whose media
gate changes layer order.
2026-05-25 19:18:10 +02:00
Andreas Kling
19e5b57672 LibWeb: Parse CSS grid subgrid track listings
Parse subgrid track listings for grid-template rows and columns,
including fixed and auto-fill name-repeat line-name lists. Preserve
the subgrid keyword through computed values and shorthand serialization,
and make interpolation discrete instead of routing subgrid lists through
the explicit track interpolation path.

Import WPT coverage for subgrid grid-template parsing and computed
values, and add text coverage for discrete subgrid track-list animation.
2026-05-25 18:11:38 +02:00
Andreas Kling
b4ef1e9c15 LibWeb: Track viewport metric style dependencies
Record when computed properties depend on viewport metrics while
resolving lengths. Carry that information through font metrics so
font-relative lengths can be associated with viewport-sized fonts.

This keeps the dependency tracking local to style computation and gives
later viewport resize invalidation a way to find affected elements.
2026-05-25 11:35:35 +02:00
Aliaksandr Kalenik
35b582048e LibWeb: Avoid stale CSS image style GC pointers
ImageStyleValue stored GC-managed request, stylesheet, and animation
timer references as strong GC::Ptr fields even though image style values
are refcounted objects. When such a style value outlives the GC object
that normally visits it, those fields can keep stale pointers after GC
collects the referents. On Steam this allowed a stale image resource
request to be read as unrelated image data, making carousel SVG arrows
render at the wrong size.

Store these back references as GC::Weak instead. Reachable style values
still use live requests, stylesheets, and timers normally, but detached
values observe null after the GC collects the referent and can reload or
skip the now-dead association instead of dereferencing reused GC memory.
Keep a local timer handle while installing the timeout callback so setup
does not rely on the weak member.

With the image style values no longer hiding strong GC edges, remove the
obsolete IGNORE_GC annotation from CSSStyleSheet's pending image list.
2026-05-25 11:06:23 +02:00
Andreas Kling
b01ce45c14 LibWeb: Guard non-subject pseudo-class invalidations
Compound selectors with a non-rightmost pseudo-class used to register
their descendant and sibling invalidation plans directly under the
pseudo-class property. A selector like `.item:hover * .target` ran
the descendant plan for every hovered element, even when that element
could not match `.item`.

Store those non-rightmost plans behind a guard made from stable class
and id subject features in the same compound selector. Deliberately
leave pseudo-classes out of guards, since one mutation can change
multiple state pseudo-classes at once. Also leave tag and attribute
selectors out, since their matching depends on document and namespace
case-sensitivity that the guard property does not carry.

The new style-invalidation test covers the GitHub-shaped
`:hover * :not(...)` case, co-invalidated `:link` and `:any-link`,
partial or complex `:is()`/`:where()` alternatives, and case-sensitive
SVG tag and attribute selectors.
2026-05-24 15:32:39 +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
817cb7432f LibWeb: Keep shadow rule caches for user styles
Do not invalidate shadow-root rule caches when the document user style
sheet changes. Shadow trees still need style invalidation because
document user rules can match their descendants, but their local author
rule caches do not include the document user sheet.

Since user and content-blocker sheets now live only in the document
scope, shadow-DOM state changes also have to consult the document user
selector insights for :has() and pseudo-class invalidation.

Add content blocker coverage for user-style refreshes, shadow :has()
state changes, and shadow pseudo-class invalidation.
2026-05-23 22:03:46 +02:00
Andreas Kling
44a6da5165 LibWeb: Avoid cold rule cache builds for :has() checks
Cache lightweight selector insights on each stylesheet so cold style
scopes can answer whether :has() invalidation is relevant without
building a complete rule cache. This avoids forcing rule caches for
shadow roots whose active sheets do not contain :has() selectors.

Imported sheets contribute to their parent sheet's effective rules, so
an imported sheet load or CSSOM change also clears ancestor selector
insight caches.

Add test-only counters and regression coverage for cold shadow roots
with and without :has() selectors, plus delayed imported :has() rules.
2026-05-23 22:03:46 +02:00
Andreas Kling
2118396905 LibWeb: Skip :has() invalidation for unstyled shadow roots
Do not process pending :has() mutation invalidation for shadow roots
that have no active style sheets. Such scopes cannot contain shadow
rules with :has(), and document-level user rules are handled by the
document style scope before shadow roots are visited.

Add a text test that mutates an unstyled shadow root while document
:has() invalidation is active, covering the safety boundary for this
shortcut.
2026-05-23 22:03:46 +02:00
Andreas Kling
56077a7c88 LibWeb: Share constructed shadow style caches with ad blocking
Content blocker cosmetic rules now live in the document style scope, so
single constructed stylesheet shadow roots can still reuse their shared
style cache when cosmetic rules are enabled. This keeps the existing
sharing fast path active on pages with many constructed shadow roots.
2026-05-23 22:03:46 +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
Tim Ledbetter
c64c60b020 LibWeb: Absolutize @font-face font-style descriptor before reading
This change matches the style used in the previous commits. No
regression tests have been added because this change is not observable,
as `FontStyleStyleValue` currently ignores the oblique angle.
2026-05-23 15:44:57 +02:00
Tim Ledbetter
8cd82627ff LibWeb: Absolutize @font-face font-weight descriptor before reading 2026-05-23 15:44:57 +02:00
Tim Ledbetter
5079324f95 LibWeb: Absolutize @font-face font-width descriptor before reading
Previously, a font width/stretch descriptor with a calc() expression
containing font-relative units cause a crash when read because
`set_stretch_impl()` expects values to be absolutized. This change
moves absolutization into `set_stretch_impl()`, sourcing the length
resolution context from the connected stylesheet's owning document.
2026-05-23 15:44:57 +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
Andreas Kling
9abdc9fb62 LibWeb: Handle inserts into detached grouping rules
Use an empty namespace table when parsing a nested rule through a
grouping rule that no longer has a parent stylesheet, and skip owner
invalidation in that detached case.

Add a crash test covering selectorText mutation and nested insertRule
after a top-level style rule has been deleted from its constructable
stylesheet.
2026-05-23 11:36:45 +02:00
Andreas Kling
2a46037628 LibWeb: Avoid transform interpolation without a reference box
Fall back to discrete transform interpolation when a remaining
transform list needs a reference box to become a matrix and none is
available. Percentage translate values otherwise reached
Length::from_style_value() without a percentage basis.

Add a crash test covering computed Typed OM access to an interpolated
transform that mixes percentage translation with rotation.
2026-05-23 11:36:45 +02:00
Andreas Kling
bcdd4cfaa3 LibWeb: Normalize overflow-clip-margin Typed OM values
Allow overflow-clip-margin's object-valued Typed OM path to use the
property parser before the value reaches CSSStyleProperties.
CSSKeywordValue("border-box") otherwise arrived as a bare keyword for
a shorthand, tripping the shorthand expansion guard.

Keep the normalization scoped to the overflow-clip-margin shorthand
family so existing Typed OM shorthand behavior remains unchanged. Add
a crash test for the keyword and length forms from the WPT coverage.
2026-05-23 11:36:45 +02:00
Andreas Kling
16dcd2ab23 LibWeb: Absolutize connected font-width descriptors
Resolve connected @font-face font-width descriptors with the rule's
document context before updating the cached width used for font
selection. This matches the font-style and font-weight descriptor
handling and lets relative units inside calculations simplify safely.

Add crash coverage for an @font-face font-width descriptor using
sign() with rem units.
2026-05-23 11:36:45 +02:00
Pavel Shliak
fed6186201 LibWeb: Remove unused ReportTime include from StyleScope 2026-05-23 09:16:09 +02:00
Sam Atkins
f6b1625e12 LibWeb/CSS: Mark @scope as a supported at-rule
Also add a test that covers the various at-rules we support which are
missed by the WPT test.
2026-05-22 13:12:27 +01:00
mikiubo
fab4292711 LibWeb: Reject safe/unsafe as standalone self-alignment values
safe and unsafe are <overflow-position> modifiers per css-align-3
and must accompany an alignment value. Reject them as standalone
keywords for align-items, align-self, justify-items and
justify-self.

The check only applies when these properties are parsed as
longhands; their use inside the place-items and place-self
shorthands goes through a separate code path and is unaffected.
2026-05-22 10:36:04 +01:00
Sam Atkins
5c928eb7eb LibWeb/CSS: Implement the @scope rule
`@scope (a) to (b) {}` applies its contained style rules to elements
that have `a` as a parent, and do not have `a b` as a parent. Both the
`a` and `b` selector lists are optional.

Because it's situational whether a `@scope` will apply to a given
element, we store the ancestor scope on the `MatchingRule`, similar to
`@container`, and then determine during matching whether all the parent
`@scope`s match or not.

The rules for how selectors inside `@scope` are adjusted and interpreted
are a bit confusing. Unlike for other at-rules, nested style rules
inside `@scope` do not get a leading `&` added during parsing. To
support this, `adapt_nested_relative_selector_list()` now takes a flag
for whether its parent is a `@scope` or not.

`@scope` can also contain nested declarations without itself being
nested inside a style rule.

When determining their selectors, nested declarations rules adopt the
`@scope`'s scoping root if it has one, or otherwise fall back to the
parent element of the `<style>` element (not implemented here,) or the
`:root`. These are required to have zero specificity, so we wrap the
selector in `:where()`.
2026-05-22 10:00:42 +01:00
Sam Atkins
14a06add85 LibWeb/CSS: Invalidate style sheet owners on rule insertion/deletion 2026-05-22 10:00:42 +01:00
Sam Atkins
c67172f368 LibWeb/CSS: Ask CSSNestedDeclarations for selectors and layer directly
This is preparation for nested declarations inside `@scope`. User code
no longer makes assumptions about there being a style rule parent, as
there may not be one.

We cache the absolutized selectors because `@scope` will require us to
modify the parent's selectors instead of using them directly.
2026-05-22 10:00:42 +01:00
Sam Atkins
43f4ecde5c LibWeb/CSS: Simplify absolutize_selectors_relative_to nesting check 2026-05-22 10:00:42 +01:00
Sam Atkins
f88c093f93 LibWeb/CSS: Maintain rule-parsing context when converting to CSSRules
Specifically we will need to know the parent rules for a nested style
rule inside `@scope` in order to resolve its selectors correctly.
Reusing our existing m_rule_context stack is the simplest option - once
we reach the point of converting rules, this context stack is empty, so
we can populate it as we go.
2026-05-22 10:00:42 +01:00
Sam Atkins
1b97f83075 LibWeb/CSS: Replace & selectors with :where(:scope) when appropriate
We previously just ignored `&` when absolutizing it would become
`:scope`, because of specificity, but we can actually directly replace
it with `:where(:scope)` in that situation instead.

This commit also renames parent_style_rule() to nesting_parent_rule()
and it doesn't just return CSSStyleRules - in a later commit, we'll
also detect CSSScopeRules here.
2026-05-22 10:00:42 +01:00
Sam Atkins
c408a7165a LibWeb: Adapt CSSStyleRule::parent_style_rule() -> nesting_parent_rule()
Once we implement `@scope`, the rule used as the parent for nesting
selectors won't always be a style rule, but could be a `@scope` rule.
This will get adjusted once those are added.
2026-05-22 10:00:42 +01:00
Sam Atkins
e83478f21d LibWeb/CSS: Move Selector absolutization into Selector.[h,cpp]
Just a move with very minor adjustments. We're going to need to run the
absolutization process on other selectors besides those in a
CSSStyleRule - specifically the scope target of CSSScopeRule. So put the
code where it's accessible.
2026-05-22 10:00:42 +01:00
Sam Atkins
03f9ab7602 LibWeb/CSS: Include absolutized selectors in CSSStyleRule dump
Useful when debugging absolutization.
2026-05-22 10:00:42 +01:00
Sam Atkins
b61227d540 LibWeb/CSS: Implement @supports at-rule(@foo)
Matches if we support the at-rule in some form.

Keeping this list up to date is a bit awkward, but we don't add at-rules
too often, and having all at-rules defined in JSON would just move the
awkward-to-maintain list somewhere else.
2026-05-22 09:59:52 +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
c974e616c0 LibWeb: Add cosmetic rules to ContentBlocker
Split cosmetic blocker rules out from network patterns. Expose matching
rules as user CSS through StyleScope.

Invalidate affected user style caches when blocker state changes.
Generated cosmetic CSS now respects disabled content blocking.
2026-05-21 21:16:56 +02:00
Callum Law
883199cb39 LibWeb: Make TransformationSV::to_matrix infallible
Parameter values are absolutized at style computation time (or are
confirmed to be resolvable in the case of reification or DOMMatrix) so
there is no reason this function should fail.
2026-05-21 17:07:58 +01:00
Callum Law
e07ba236d1 LibWeb: Don't generate LRC in TransformationSV::to_matrix
All relative lengths will have been absolutized at style computation
time (or disallowed at parse time in the case of DOMMatrix) so we don't
need to resolve them again here.
2026-05-21 17:07:58 +01:00