Commit Graph

220 Commits

Author SHA1 Message Date
Sam Atkins
f657a4b71b LibWeb/CSS: Parse @font-face { font-weight } with two values
WPT has coverage for matching but not parsing, so the test is homemade.
2026-02-24 10:05:09 +00:00
Callum Law
e6669482e6 LibWeb: Parse font-variant-alternates functions 2026-02-20 22:01:44 +00:00
Callum Law
04fd7e00e9 LibWeb: Disallow disjointed numeric component of font-variant
The grammar groups this component together meaning that all
sub-components must occur together i.e.
`ordinal slashed-zero small-caps` is valid but
`ordinal small-caps slashed-zero` is not.

We also reuse the logic for parsing from the longhand
`font-variant-numeric` property for simplicity.
2026-02-20 22:01:44 +00:00
Callum Law
d97098ec80 LibWeb: Disallow disjointed ligatures component of font-variant
The grammar groups this component together meaning that all
sub-components must occur together i.e.
`common-ligatures no-contextual small-caps` is valid but
`common-ligatures small-caps no-contextual` is not.

We also reuse the logic for parsing from the longhand
`font-variant-ligatures` property for simplicity.
2026-02-20 22:01:44 +00:00
Callum Law
75dd7b767f LibWeb: Disallow disjointed east asian component of font-variant
The grammar groups this component together meaning that all
sub-components must occur together i.e. `jis78 full-width small-caps` is
valid but `jis78 small-caps full-width` is not.

We also reuse the logic for parsing from the longhand
`font-variant-east-asian` property for simplicity.
2026-02-20 22:01:44 +00:00
Tim Ledbetter
fd24ca898c LibWeb: Skip hit-testing for elements with non-invertible transforms 2026-02-19 14:33:31 +00:00
Callum Law
caa5705edf LibWeb: Clamp blur() calculated values 2026-02-16 12:09:23 +00:00
Callum Law
68c596942c LibWeb: Store FilterOperation::Color::amount as StyleValue
This simplifies handling and means we now support tree counting
functions.
2026-02-16 12:09:23 +00:00
Callum Law
33e590dddb LibWeb: Ensure that computation context cache is always cleared
Previously we didn't clear the computation context caches after:
 - Recomputing inherited style
 - Computing keyframe values

We now clear the caches in those two cases and verify it has been
cleared before using it.

Fixes #7959
2026-02-15 17:52:11 +01:00
Andreas Kling
9e8e568b43 LibWeb: Use structural sharing for CSS custom properties
Replace per-element OrderedHashMap storage for custom properties with
a RefCounted chain (CustomPropertyData) that enables structural
sharing. Each chain node stores only the properties declared directly
on its element, with a parent pointer to the inherited chain.

Elements that don't override any custom properties share the parent's
data directly (just a RefPtr copy). During cascade, only entries that
actually differ from the parent are stored in own_values - the rest
are inherited through the chain. During var() resolution, resolved
values are compared against the parent's and matching entries are
dropped, enabling further sharing.

The chain uses a depth limit (max 32) with flattening, plus
absorption of small parent nodes (threshold 8) to keep lookups fast.

This reduces custom property memory from ~79 MB to ~5.7 MB on
cloudflare.com.
2026-02-13 14:57:15 +01:00
Andreas Kling
31cbe2061a LibWeb: Add comprehensive tests for slot style inheritance
Test that slotted elements correctly inherit styles from their
assigned slot in various scenarios: inline styles, CSS rules,
named slots, nested shadow hosts, own style overrides, deep
inheritance chains, dynamic slot reassignment, JS-created shadow
DOM, class toggles on slots, and moving elements between hosts.
2026-02-13 10:22:30 +01:00
Andreas Kling
fb11732526 LibWeb: Fix style inheritance for slotted elements
Two issues prevented slotted elements from correctly inheriting
styles from their assigned slot:

1. Element::element_to_inherit_style_from() was skipping the slot
   element and returning the shadow host instead. This meant slotted
   elements inherited from the host, completely ignoring any styles
   on the slot itself.

2. When a slot element's style changed during the style tree walk,
   its assigned (slotted) nodes were never marked for recomputation.
   The tree walk follows the DOM tree, but slotted elements are DOM
   children of the shadow host, not the slot, so they were missed.

Fix (1) by returning the slot directly as the inheritance parent.
Fix (2) by marking assigned nodes dirty in update_style_recursively
when a slot's style changes.
2026-02-13 10:22:30 +01:00
Andreas Kling
8804eb89e0 LibWeb: Add test for targeted style update in getComputedStyle
Cover various scenarios: element's own style change, ancestor style
change affecting inheritance, sibling changes not affecting our element,
shadow DOM elements, pseudo-elements, and repeated reads.

Also documents a pre-existing bug where slotted elements don't pick up
inherited style changes from their assigned slot.
2026-02-13 10:22:30 +01:00
Callum Law
b0274268f8 LibWeb: Support calculated values in @counter-style range descriptor
Calculated values are resolved and confirmed to be valid (in line with
non-calculated values) at parse time
2026-02-12 01:26:52 +01:00
Callum Law
a541c09d61 LibWeb: Support calculated value in additive-symbols descriptor
Calculated weight values are resolved and verified to be in strictly
decreasing order (as with non-calculated values) at parse time.
2026-02-12 01:26:52 +01:00
Callum Law
3783dd96a3 LibWeb: Support calculated value in @counter-style pad descriptor 2026-02-12 01:26:52 +01:00
Andreas Kling
803e71ba9f Tests/LibWeb: Add comprehensive abspos height constraint solving test
Test all major code paths in the CSS2 10.6.4 algorithm for computing
height of absolutely positioned non-replaced elements:

- Rules 4, 5, 6 (one auto among top/height/bottom)
- Over-constrained case (none auto)
- Auto margin solving (one auto, both auto)
- Min-height and max-height re-solve for rules 4, 5, 6
- Min/max with auto margins
- Borders and padding interaction with min-height
2026-02-10 11:58:15 +01:00
Praise-Garfield
e2cdd84fcb LibWeb: Throw NotFoundError in MediaList::delete_medium()
Per the CSSOM specification, throw a NotFoundError DOMException when
the specified medium is not found in the collection. Invalid input
that fails to parse continues to return silently per step 2.
2026-02-09 21:44:47 +01:00
Jelle Raaijmakers
f55fe69d4d LibWeb: Rework Internals' mouse control
Instead of defining somewhat high level mouse actions, allow granular
control of mouse clicks and mouse down/up/move events. We will want to
simulate things like holding down a mouse button after double clicking
and then dragging the mouse to another position in the future, and this
enables that.
2026-02-06 14:18:10 +00:00
Andreas Kling
5f434a442a LibWeb: Use targeted style invalidation when adding a new stylesheet
Instead of doing a full document style invalidation when a stylesheet is
dynamically added, we now analyze the new sheet's selectors to determine
which elements could potentially be affected, and only invalidate those.

This works by building an InvalidationSet from the rightmost compound
selector (the "subject") of each rule in the new stylesheet, extracting
class, ID, tag name, attribute, and pseudo-class features. We then walk
the DOM tree and only mark elements matching those features as needing a
style update.

If any selector has a rightmost compound that is purely universal (no
identifying features), or uses a pseudo-class not supported by the
invalidation set matching logic, we fall back to full invalidation.
2026-02-02 21:08:30 +01:00
Andreas Kling
6b9797f480 LibWeb: Scope pseudo-class invalidation to common ancestor
When a pseudo-class state changed, we always walked the entire
document (or shadow root) tree to find affected elements, even
though only the subtree rooted at the old/new common ancestor
can be affected.

Narrow the tree walk to start from old_new_common_ancestor
instead of the root. To ensure ancestor-dependent selectors are
still correctly evaluated, we seed the style computer's ancestor
filter by walking up from the common ancestor to the root before
the invalidation walk.

This reduces the work from O(total elements) to
O(subtree elements) + O(tree depth), which is a large improvement
on pages where pseudo-class changes (hover, focus, active, target)
occur deep in the DOM.

This was extremely hot (10%+) when hovering mailboxes on GMail.
2026-01-27 10:58:47 +01:00
Andreas Kling
3b90eb1d49 LibWeb: Recompute child style when parent's display changes
When a parent element's display property changes (e.g., to flex or
grid), children may need to be blockified or un-blockified.
Previously, children only received a recompute_inherited_style() call
which doesn't run the blockification logic.

This patch adds a parent_display_changed flag to the recursive style
update that forces children to get a full style recompute when their
parent's display change triggers a layout tree rebuild.
2026-01-26 12:40:36 +01:00
Callum Law
afdde488c3 LibWeb: Correctly parse logical border-*-*-radius shorthands
Builds on #7609 by parsing these properties correctly in the first place
2026-01-25 10:22:10 +01:00
Tim Ledbetter
191e0e8c18 LibWeb: Support @-webkit-keyframes as an alias for @keyframes
This is listed as mandatory in the compat spec.
2026-01-25 09:33:24 +01:00
Aliaksandr Kalenik
2075eddbf1 LibWeb: Fix logical border-radius properties not being applied
Logical border-radius properties are parsed as Percentage/Length values,
not BorderRadiusStyleValue. Handle these types when applying style.
2026-01-24 21:43:23 +01:00
Callum Law
2c3ddc294f LibWeb: Compute math-depth in line with other font properties
The main change here is that we now properly absolutize values which
means we now support `random()` and `sibling-{count,index}()`

We are also more consistent with how we handle computation for the other
font properties
2026-01-15 12:03:16 +00:00
Callum Law
27dd77a538 LibWeb: Don't store resolved math depth directly
There's no need to store this twice

We also now use `set_property_without_modifying_flags` to avoid
overwriting inherited/important flags
2026-01-15 12:03:16 +00:00
Tim Ledbetter
40d217bde2 LibWeb/CSS: Serialize shorthands with var() to original value 2026-01-15 11:50:45 +00:00
Callum Law
668d3afde0 LibWeb: Properly parse attributes for CSS-connected FontFace
Previously we would just set the attributes to the serialized
descriptors, even if they were the empty string.

We now apply defaults when we have empty descriptors and apply parsing
logic from the various `set_*` methods (only applicable to `font-family`
so far where we now extract the value from either a string or a
custom-ident)

Fixes an issue in some css/css-shapes WPT tests where we weren't
properly matching fonts.
2026-01-13 10:40:00 +00:00
Callum Law
bbfe7c64fe LibWeb: Disconnect font face if descriptor change makes it invalid 2026-01-13 10:40:00 +00:00
Callum Law
9af90f81bf LibWeb: Use correct base-url for CSS-connected FontFace
Previously we would always try to load the font URL relative to the
document's base URL. This commit means that for CSS-connected
`FontFace`s we now try to load relative to the URL of the stylesheet
that contains the associated `CSSFontFaceRule`
2026-01-13 10:40:00 +00:00
Callum Law
3996d9ec82 LibWeb: Support setting FontFace::family with StringStyleValue 2026-01-13 10:40:00 +00:00
Callum Law
06313acac0 LibWeb: Store updated attributes directly within FontFace
The spec states that updates to descriptors in a `@font-face` rule
should be reflected in the connected `FontFace`'s attributes.

Previously this was achieved by directly accessing those descriptors
when calling the attribute getters, but this has a couple of issues:
 a) The changes are only reflected if we use the accessors (i.e.
    `FontFace::family()` rather than `FontFace::m_family`) which isn't
     the case everywhere
 b) The changes aren't persisted after the `FontFace` is disconnected
    from it's `CSSFontFaceRule`

To fix these issues we now reparse and store the `FontFace`'s attributes
whenever the `CSSFontFaceRule`'s descriptors change.
2026-01-13 10:40:00 +00:00
Callum Law
df03c31e13 LibWeb: Don't crash when serializing @font-face without font-family 2026-01-13 10:40:00 +00:00
Callum Law
e114c7341e LibWeb: Support <custom-ident> in FontFaceSet::load()
This exposed a false positive in our test suite which has been fixed and
made more robust
2026-01-13 10:40:00 +00:00
Tim Ledbetter
49f8fafc2e LibWeb: Treat content-visibility auto as non-hidden in interpolation
This matches the interpolation behavior of the `visibility` property
and of other engines.
2026-01-13 10:49:31 +01:00
Callum Law
df39394a7e LibWeb: Remove font face from document font source when disconnecting
When a CSS-connected FontFace is disconnected from it's associated
`CSSFontFaceRule` it should be removed from the Document's font source
2026-01-10 03:33:03 +00:00
Callum Law
d8f9caf853 LibWeb: Only run handle_src_descriptor_change once
Previously we would run it once within `set_src()` and then again within
`set_property()` which would lead to us creating two new `FontFace`s
instead of just one
2026-01-10 03:33:03 +00:00
Sam Atkins
960558f30a LibWeb: Register and unregister @property rules when added or removed
Previously, we registered `@property` rules during parsing, and treated
them the same as `CSS.registerProperty()` calls. This is not correct
for a couple of reasons: One, the spec wants us to distinguish between
those two sources of registered custom properties, with
`CSS.registerProperty()` calls taking precedence. Two, we never removed
the registered property when its `@property` was removed from the
document.

This commit deals with this by iterating active CSSPropertyRules to find
which ones currently apply, and storing those in a cache. This cache is
invalidated whenever the Document's style is invalidated, which happens
whenever a CSSRule is added or removed from the Document.

The attached test demonstrates this now working as it should.
2026-01-09 10:54:37 +00:00
Shannon Booth
d901e937b6 LibWeb/CSS: Do not give internal stylesheets a location URL
This fixes Acid3 numbered test 72.
2026-01-09 10:54:11 +00:00
Tim Ledbetter
7b8099bb89 LibWeb: Disconnect and replace FontFace on @font-face src change 2026-01-05 16:15:58 +00:00
Tim Ledbetter
dab22f770d LibWeb: Add a corresponding FontFace object for a parsed @font-face rule 2026-01-05 16:15:58 +00:00
Aliaksandr Kalenik
3353ec9663 LibWeb: Add result caching for :has() pseudo-class matching
The `:has()` pseudo-class requires traversing descendants (or siblings)
to find matches.

With this change we cache results keyed by `(Selector*, Element*)`
pairs. The cache is stored in `StyleComputer` and cleared at the start
of each style computation pass in `Document::update_style()`.

When `:has()` uses a descendant combinator and we find a match, we also
cache that all ancestors between the matching descendant and the
anchor match. For example with `div:has(.target)`:

```html
<div id="A">  <!-- checking :has(.target) here -->
  <div id="B">
    <div id="C">
      <span class="target"/>
    </div>
  </div>
</div>
```

When we find `.target` while checking `div#A`, we also cache that
`div#B` and `div#C` match `:has(.target)` since they also contain
`.target`. Later when styling these elements, we get cache hits and skip
traversal.
2026-01-04 19:36:40 +01:00
Callum Law
acc8b90549 LibWeb: Improve gradient position serialization
`EdgeStyleValues` which consist of an offset of a `calc()`s which
resolves to 50% should be considered "centered" for
`SerializationMode::ResolvedValue` for the purpose of omitting the
position value from gradient serialization.
2026-01-02 11:43:10 +01:00
Callum Law
e79644bf6b LibWeb: Mark scrollbar-color property as inherited 2025-12-29 16:11:13 +01:00
Callum Law
ad1083f14e LibWeb: Don't serialize omitted circle() position argument
This should only be defaulted to `center` at use time
2025-12-12 12:20:16 +00:00
Timothy Flynn
7114872073 LibWeb: Include "url(" in the original source text of URL tokens
When we invoke Tokenizer::consume_a_url_token, we have already consumed
the "url(" text from the source. Thus we would set the original source
text to the text starting just after those consumed code points. Let's
instead pass in the known starting position from the caller.

This fixes a bug seen on https://lichess.org, where they perform a
`substring(4)` on the property value to remove the "url(" text. This
would strip away the "http" part of the URL, and we would try to load
"s://lichess.org/image.svg". With this fixed, we can play chess games
on this site.
2025-12-10 20:50:02 +01:00
Timothy Flynn
96806a3f90 LibWeb: Update cursor and tooltip UI state regardless of event handlers
If a script on the page cancels a mousemove event, we would return early
and neglect to update the cursor. This is seen regularly on "Diablo Web"
where they set the cursor to "none" on the main canvas, and also cancel
mousemove events.
2025-12-03 12:23:56 +01:00
Callum Law
758432c1cd LibWeb: Don't mark mask-type as list-valued
This is distinct from the other `mask-*` properties and is not a
longhand of `mask`, and is thus not a coordinating value list longhand
2025-12-02 12:14:27 +00:00
Callum Law
d7d4f90a2c LibWeb: Update style attribute when calling attributeStyleMap.set()
We also now invalidate the element
2025-12-02 11:37:11 +00:00