Commit graph

761 commits

Author SHA1 Message Date
Andreas Kling
f47b6f3270 LibWeb: Reduce CSS parser token memory usage
Store CSS token payloads in a variant so each token only carries the
state needed by its type. Keep delimiter, number, hash, string, and
dimension data separate instead of storing every possible payload on
every token.

Use a smaller component-value token for function and block boundary
metadata. These component values only need token type, original source
text, and source positions, so avoid embedding full token payload
storage inside every Function and SimpleBlock.

Shrink CSS source positions to explicit 32-bit counters. Guard the C++
and Rust tokenizer paths against overflow. Add size assertions for the
hot Token and ComponentValue types so future growth is intentional.
2026-06-13 14:57:52 +02:00
Sam Atkins
4050c32dab Everywhere: Make use of Badge with multiple or derived types
Now that Badge can have multiple types, and a Badge of a derived class
can convert into a Badge of the superclass, we can simplify a few method
signatures and overloads.
2026-06-11 21:55:56 +02:00
Jelle Raaijmakers
1a5b7f9ea2 LibWeb/CSS: Implement contrast-color() function 2026-06-09 17:23:26 +02:00
Andreas Kling
df7c715b4e LibWeb: Remove FlyString property-name overload
Remove the PropertyNameAndID::from_name overload that accepted
FlyString. Parser declarations still store their token names as
FlyString, but the conversion to UTF-16 now happens explicitly at those
boundaries.
2026-06-09 11:48:02 +02:00
Andreas Kling
7272c26c7b LibWeb: Store CSS descriptor names as UTF-16
Move DescriptorNameAndID to Utf16FlyString so CSS descriptor APIs can
keep using the CSSOM property-name string without round-tripping through
FlyString.

Keep parser declaration tokens and DevTools error payloads on their
existing FlyString types at their boundaries.
2026-06-09 11:48:02 +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
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
39106f9326 LibWeb/CSS: Parse authored declarations for DevTools
Add a parser entry point that preserves authored CSS declarations for
DevTools. The Rules panel needs the original property names, shorthand
values, invalid declarations, custom properties, and !important flags
rather than only the expanded computed representation.
2026-06-04 20:54:33 +01:00
Sam Atkins
ee24561ab4 LibWeb/CSS: Store source positions on CSS rules
DevTools needs rule-level source positions to link applied style
rules back to their source sheets. The parser already tracks token
line and column information, so carry that through qualified rules
and nested declarations when creating CSSRule objects.
2026-06-04 20:54:33 +01:00
Sam Atkins
df41e7a1cf LibWeb/CSS: Move Token::Position into SourcePosition
There's nothing about this that's specific to Tokens, and moving it
makes it easier to use for other types. We'll need this for the
following commits.
2026-06-04 20:54:33 +01:00
Sam Atkins
538dca4448 LibWeb: Parse scoped CSS import rules
Parse and store the optional `scope` clause in `@import` preludes.

WPT doesn't directly test the serialization behaviour for this, so add a
custom test for it.
2026-06-04 20:52:28 +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
Andreas Kling
ff13ac2b79 LibWeb: Avoid copying ASF argument component values
Parse arbitrary substitution function arguments as spans into the
existing component value list. This avoids copying each argument into a
new vector for var(), attr(), env(), if(), and inherit() parsing.

Expose a span-returning declaration-value parser that shares the same
walker as the existing vector-returning API, so the argument parser does
not duplicate declaration-value grammar logic. Substitution output still
uses owned vectors, and the unresolved Typed OM reifier now consumes
spans too.
2026-06-03 22:28:54 +02:00
Andreas Kling
70e82d39ed LibWeb: Store unresolved style values as text
Store the source text for unresolved CSS values instead of retaining
the full parsed component value tree. Values that need the component
tree now parse it on demand from the stored text.

This preserves equality, tokenization, variable substitution, and Typed
OM reification. Custom properties keep their original source text.
Unresolved values synthesized from component values store serialized
text.
2026-06-03 22:28:54 +02:00
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
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
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
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
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
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
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
Sam Atkins
cb74affdcb LibWeb/CSS: Treat general-enclosed in @container as unknown 2026-05-20 13:00:50 +01:00
Sam Atkins
9996403e73 LibWeb/CSS: Extract base class from MediaFeature
`<media-feature>` and the upcoming `<size-feature>` from `@container`,
share the same syntax and almost all of their behaviour. To avoid a lot
of duplication, pull as much as possible into a FeatureQuery template
class that they will both inherit from.

MediaFeatureValue is renamed FeatureValue as it's also shared by both.

No behaviour change.
2026-05-20 13:00:50 +01:00
Andreas Kling
f4960d9d7d LibWeb: Honor requested CSS tokenizer encoding
Keep decoded CSS text separate from tokenizer byte input. CSSOM and
already-decoded stylesheet text preserve code point preprocessing, so a
lone surrogate maps to one replacement character instead of being
re-decoded as malformed UTF-8 bytes.

Decode tokenizer byte input with the requested encoding unless that
encoding is UTF-8 and the byte stream is strictly valid UTF-8. Keep the
fast path by constructing the decoded string without validating twice
after strict validation succeeds.

Preserve UTF-8 decoder behavior on the byte fast path by stripping an
initial UTF-8 BOM and rejecting encoded surrogate bytes. Invalid UTF-8
still goes through the decoder. Add tokenizer coverage for both the C++
and Rust backends across decoded text, UTF-8 aliases, BOM-prefixed
input, invalid UTF-8, and non-UTF requested encodings.
2026-05-18 14:08:22 +02:00
Andreas Kling
318fb4f2d0 LibWeb: Preserve immutable consumed body bytes
Keep consumed response body bytes in Core::ImmutableBytes instead of
requiring a ByteBuffer. This lets responses that already arrived as
file-backed immutable data keep that representation through body
consumption, while streamed responses can still adopt their
accumulated ByteBuffer without another copy.

Update the body consumers that only inspect bytes to read from
immutable byte views. Font loading still copies at its existing
ownership boundary, where the off-thread preparation path takes a
ByteBuffer.
2026-05-18 01:21:34 +02:00
Callum Law
33705dc12f LibWeb: Generate CSS <paint> parsing
This changes the shape of the parsed value when we don't have a fallback
color for a `<url>` value from having no second value in the
`StyleValueList` to having an `EmptyOptionalStyleValue`.
2026-05-13 11:26:20 +01:00
Sam Atkins
88aea2e11d LibWeb: Give BooleanExpression an evaluation context
Different users of BooleanExpression have different requirements for
evaluation:
- `@media` needs a Document
- `@supports` doesn't need anything
- `@container` needs a container Element

To support these without expanding the API, replace the Document*
parameter with a BooleanExpressionEvaluationContext type which contains
these different values.

No behaviour changes.
2026-05-13 11:05:31 +01:00
Sam Atkins
442319c676 LibWeb/CSS: Update grammar for @container
Corresponds to
efc0c6f847
2026-05-13 11:05:31 +01:00
Sam Atkins
35b43f7d3a LibWeb/CSS: Insert a combinator before all pseudo-element selectors
Previously, and according to the spec, `a::part(foo)::before` would be a
single CompoundSelector, even though it matches against 3 different
targets. This meant some awkward swapping of targets in the middle of
matching, and in particular it made `::part()` and `::slotted()` quite
hacky, requiring them to track extra data on the MatchContext to then
use later. This was scattered around and difficult to follow.

Partly inspired by Gecko, this commit instead introduces an invisible
PseudoElement combinator. After parsing a selector, we find any
CompoundSelectors that contain a pseudo-element and split them up, so
that each CompoundSelector only has a single target in the end. Where
the pseudo-element was at the start of a CompoundSelector, we insert an
invisible universal selector before it to represent its originating
element.

So now, a CompoundSelector deals with one target, and switching targets
is done at the combinator.

The one inconsistency is that we match the target of ::slotted()
and ::part() in pseudo_element_transition_target(), instead of before
then when processing the SimpleSelector. This is to avoid repeating the
same computations twice.

No outward-facing behaviour changes, though the invalidation metrics
have changed.
2026-05-13 11:03:02 +01:00
Callum Law
f578d95be0 LibWeb: Support multiple keywords in parse_specific_keyword_value
This will allow us to combine multiple calls into one and avoid
repeatedly parsing and then discarding `KeywordStyleValue`s
2026-05-13 11:00:07 +01:00
mikiubo
b9ed64d1ce LibWeb: Add dedicated overflow-clip-margin style value
Store overflow-clip-margin as a structured style value instead of
collapsing it into generic keyword/length lists during parsing.

Keep omitted visual-box as a distinct state so painting can apply
the spec default per element type (content-box for replaced,
padding-box otherwise), while preserving canonical serialization.
2026-05-12 14:09:13 +02:00
mikiubo
a3e420bb9e LibWeb: Parse visual-box in overflow-clip-margin
Support content-box, padding-box, and border-box in
overflow-clip-margin parsing, including combinations with length.

Canonicalize parsed values to match the grammar and expected CSSOM
serialization in css-overflow parsing tests.
2026-05-12 14:09:13 +02:00
Sam Atkins
d7344a96bb LibWeb: Parse and propagate container and container-name properties 2026-05-07 17:48:53 +02:00
Aliaksandr Kalenik
f8640d813a LibGfx+LibWeb: Make DecodedImageFrame a value type
DecodedImageFrame only wraps a ref-counted Bitmap and color-space
metadata. The frame object itself does not provide shared mutable
state or lifetime ownership beyond those members, so ref-counting it
adds an unnecessary layer of indirection.
2026-05-07 16:08:13 +02:00
Callum Law
b1d0746292 LibWeb: Absolutize <paint> fallback colors
Previously we stored these within the `URLStyleValue` which didn't
itself have an `absolutized` method so wouldn't absolutize the fallback
color. We now store the two values alongside each other in a
`StyleValueList` which correctly handles absolutization
2026-05-07 10:07:09 +01:00
Aliaksandr Kalenik
76c79ee522 LibGfx: Remove ImmutableBitmap
DecodedImageFrame now owns decoded bitmap pixels directly, so the
separate ImmutableBitmap wrapper no longer carries useful semantics.
Remove the class and pass decoded image frames or bitmaps at the
boundaries where pixels are actually required.

The Skia image cache now keys off DecodedImageFrame, matching the
display-list commands that paint decoded images. Video frames stay
owned by LibMedia, with the explicit YUV-to-bitmap conversion living
at HTMLVideoElement's decoded-frame entry point for canvas and WebGL
callers.
2026-05-05 14:39:17 -05:00
Andreas Kling
355fb6b825 LibWeb: Stream Rust CSS tokenizer tokens over FFI
Avoid building a temporary Rust token vector before calling back into
C++. The tokenizer now invokes the callback as each token is produced,
while borrowing the already-filtered input for source slices.

Reserve an initial C++ token capacity from the input size so the common
path avoids repeated growth while appending the converted tokens.

With this change, the Rust CSS tokenizer is now ~1.3x faster than the
C++ CSS tokenizer at churning through all the https://vercel.com/ CSS.
2026-05-03 17:22:17 +02:00
Sam Atkins
4278194d96 LibWeb/CSS: Port the CSS Tokenizer to Rust
test-css-tokenizer is updated to run both the C++ and Rust tokenizers
and compare their output, to ensure they behave identically. The Parser
still uses the C++ Tokenizer.

The LibWeb crate, FFI layer etc are all based on the existing ones for
other libraries.

This is a direct AI translation to get us started, and not idiomatic
Rust. Future work can be done to make it more sensible.
2026-05-03 09:49:00 +02:00
Sam Atkins
8b09a8e568 LibWeb/CSS: Add missing spec comment to consume_string_token() 2026-05-03 09:49:00 +02:00
Sam Atkins
30043210e3 LibWeb/CSS: Stop using a define for the replacement character 2026-05-03 09:49:00 +02:00
Zaggy1024
ccaaefbf27 LibWeb+Meta: Don't require the custom ident blacklist parameter
With a default parameter, we can avoid having to store None for the
blacklist when it's not applicable.
2026-04-30 09:32:22 +02:00
Callum Law
66c10ed190 LibWeb: Generate `<font-weight-absolute> parsing 2026-04-29 11:42:57 +01:00
Callum Law
9a3f2b23a1 LibWeb: Add method to parse specific CSS keyword
This revealed an issue with `@counter-style/range` where parsing could
consume and ignore invalid keywords
2026-04-29 11:42:57 +01:00
Callum Law
44ad7e30b4 LibWeb: Generate <symbol> parsing 2026-04-29 11:42:57 +01:00
Callum Law
8849435d6f Meta+LibWeb: Initial scaffolding for CSS value type parsing code gen
In the future we should switch to using a better file format for this,
i.e. one that supports directly pasting CSS grammar production blocks
(https://drafts.csswg.org/css-values-4/#css-grammar-production-block)
and has support for inline comments, but we use JSON for now for
simplicity's sake.
2026-04-29 11:42:57 +01:00
Andreas Kling
61d79a1e47 LibWeb: Parse CSS image-set()
Add an abstract image style value for image-set() and parse both the
standard and -webkit-prefixed spellings through the existing <image>
value path. The parser accepts URL and string image candidates,
optional resolution descriptors, and type() filters.

Track attr-taint through substituted component values so image-set()
candidates using attr()-derived URL-producing tokens are rejected when
resolved for URL-using properties.

Update the relevant WPT baselines now that image-set() parsing is
supported in additional value contexts.
2026-04-25 14:54:10 +02:00
Callum Law
6b7fb4b273 LibWeb: Replace ViewFunctionStyleValue with FunctionStyleValue 2026-04-24 07:34:54 +01:00
Callum Law
6aeaf69cd3 LibWeb: Replace ScrollFunctionStyleValue with FunctionStyleValue 2026-04-24 07:34:54 +01:00