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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
`@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()`.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Previously we applied them ad-hoc when computing the style for the
referenced element but we now apply it as part of the cascade. This
fixes a couple bugs:
- Computing the style for the pseudo-element (rather than the
referenced element itself) as we do in the case we don't have a
layout node in `get_direct_property` now includes the inline style.
- Inline style is applied according to the cascade (i.e. it can be
overriden by non-inline `!important` styles).
- Properties go through the computation process.
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.
LibWeb still exposed the concrete CompositorThread to Page,
Navigable, and EventHandler, so compositor IPC would have leaked the
thread implementation into callers. The old thread APIs also bundled
page presentation callbacks and main-thread wakeups into the same
object, which made it awkward for WebContent to put an actor boundary
in between.
Introduce CompositorHost and context handles as the caller-facing API,
and move shared compositor protocol values out of CompositorThread. Add
WebContentCompositor IPC endpoints and route PageHost through a paired
in-process transport. The actor owns CompositorThread with explicit
main-thread and UI presentation clients, while screenshot completion is
serialized on the WebContent event loop using request IDs.
The intention for introducing IPC here is to prepare for moving the
compositor thread into a separate process.
Include ::part() rules when comparing pseudo-class rule matches during
focus state invalidation. For observer style scopes, also walk the
containing shadow roots of the old and new focused nodes so document and
ancestor shadow scopes can invalidate exported part targets.
Add coverage for direct and exported parts using :focus, :focus-visible,
and :focus-within.
Match :focus-within by walking flat-tree parents so shadow hosts and
slotted content follow the Selectors definition instead of DOM ancestry.
When focus state changes, also run pseudo-class invalidation in shadow
style scopes that can observe the focused node. This lets shadow-root
rules such as :host(:focus-within)::before and ::slotted(:focus) update
without waiting for an unrelated DOM mutation to restyle the host.
Add focused coverage for host pseudo-elements, shadow descendants, and
slotted controls, and update the style-invalidation counter baseline for
the lower focus-family no-op restyle counts.