Commit graph

338 commits

Author SHA1 Message Date
Callum Law
46153910ec LibWeb: Update to_color to take ColorResolutionContext
Using a generic context argument will allow us to resolve colors in
places where we have all the required information but not in the form of
a layout node as was expected previously.
2025-08-04 11:29:05 +01:00
norbiros
190745fd58 LibWeb/CSS: Parse initial value using syntax from @property
Now we pass all WPT tests in:
`css/css-properties-values-api/at-property-cssom`.

Note: Failing tests were false positives.
Proper handling of inheriting values and detecting computational
independence will be done in another PR.
2025-08-04 11:08:46 +01:00
Sam Atkins
1adddb158a WebContent+LibWeb/CSS: Add debug request to dump CSS errors 2025-08-04 10:50:09 +01:00
Sam Atkins
01661503b9 LibWeb/CSS: Remove unused Debug.h include from GradientParsing.cpp 2025-08-04 10:50:09 +01:00
Sam Atkins
dc91688f18 LibWeb/CSS: Use ErrorReporter for property/descriptor parsing errors 2025-08-04 10:50:09 +01:00
Sam Atkins
cebdcd9f69 LibWeb/CSS: Use ErrorReporter for value-parsing errors
Also remove some redundant reporting for `<urange>` parsing errors.
2025-08-04 10:50:09 +01:00
Sam Atkins
3b7aa736e7 LibWeb/CSS: Use ErrorReporter for media query parsing 2025-08-04 10:50:09 +01:00
Sam Atkins
1a599ceb98 LibWeb/CSS: Reject @font-face and margin rules that have a prelude
I couldn't find any WPT coverage for this, so here's a homemade test.
2025-08-04 10:50:09 +01:00
Sam Atkins
e072ddfebd LibWeb/CSS: Use ErrorReporter for rule-parsing errors
Unfortunately we already have an InvalidRuleError type defined in the
CSS Parser, so it has to be qualified here, at least for now.
2025-08-04 10:50:09 +01:00
Sam Atkins
0bd83dd996 LibWeb/CSS: Use ErrorReporter for "rule X not allowed in Y" errors
QualifiedRule::for_each_as_declaration_list() now takes a rule_name, so
that the error message can actually be useful - we only know what a
qualified rule is by context.
2025-08-04 10:50:09 +01:00
Sam Atkins
d6cfd56ae6 LibWeb/CSS: Use ErrorReporter for selector parsing errors
Also removed the error reporting from parse_a_n_plus_b_pattern() as its
caller already reports that error.
2025-08-04 10:50:09 +01:00
Sam Atkins
2a2a1986cc LibWeb/CSS: Add dump_string() method to TokenStream
This is to support error reporting. It's not the most elegant way of
getting the source CSS, but it works.
2025-08-04 10:50:09 +01:00
Sam Atkins
012f4735a7 LibWeb/CSS: Introduce structured reporting for CSS errors
Instead of random dbgln_if(CSS_PARSER_DEBUG) messages, this lets us
report what kind of error it was. Repeated errors are combined instead
of spamming the console.

Ideally this would also record where the error occurred, but not yet.
2025-08-04 10:50:09 +01:00
Sam Atkins
b7a108d7cb LibWeb/CSS: Remove unused ParseError::InternalError 2025-08-04 10:50:09 +01:00
Sam Atkins
d55626dc32 LibWeb/CSS: Remove debug logging I left in by accident 2025-08-04 10:50:09 +01:00
Sam Atkins
d86bcc795d LibWeb/CSS: Remove duplicate error reporting for invalid descriptors
parse_descriptor_value() already logs this.
2025-08-04 10:50:09 +01:00
Tim Ledbetter
1d9e4a6f62 LibWeb: Parse anchor() function for inset properties 2025-08-03 22:09:31 +02:00
Jelle Raaijmakers
c4f5e7bee3 LibWeb: Implement anchor-size(..) function parsing
This parses `anchor-size(..)` functions in CSS, but does not yet result
in a useful `Size`: we need style & layout interleaving similar to
container queries for this, since the resulting value depends on layout
results.

Not supported yet: `anchor-size()` appearing inside a `calc()` node.

Adds 4280 WPT subtest passes in `css/css-anchor-position`.
2025-07-30 18:13:59 +01:00
Jelle Raaijmakers
02598040ad LibWeb: Add CSS::Parser::parse_dashed_ident() 2025-07-30 18:13:59 +01:00
Aliaksandr Kalenik
d1fbb7b51e LibWeb: Invalidate less elements affected by CSS custom properties
Before this change, whenever element's attributes changed, we would add
a flag to "pending invalidation", indicating that all descendants whose
style uses CSS custom properties needed to be recomputed. This resulted
in severe overinvalidation, because we would run invalidation regardless
of whether any custom property on affected element actually changed.

This change takes another approach, and now we decide whether
descendant's style needs to be recomputed based on whether ancestor's
style recomputation results in a change of custom properties, though
this approach adds a little overhead to style computation as now we have
to compare old vs new hashmap of custom properties.

This brings substantial improvement on discord and x.com where, before
this change, advantage of using invalidation sets was lost and we had
to recompute all descendants, because almost all of them use custom
properties.
2025-07-30 11:06:05 +02:00
Aliaksandr Kalenik
cbe4ba60c3 LibWeb: Implement faster equals() for UnresolvedStyleValue
Compare `Vector<Parser::ComponentValue>` directly instead of
serializing them into strings first.

This is required for the upcoming changes where we would compare
previous and new sets of custom properties to figure out whether we need
to invalidate descendant elements. Without this change `equals()` would
show up being hot in profiles.
2025-07-30 11:06:05 +02:00
Aliaksandr Kalenik
b1efd62ce6 LibWeb: Save more details about ASF presence in UnresolvedStyleValue
In the upcoming changes we would have to know specifically whether
`var()`, `attr()` or both are included in UnresolvedStyleValue.
2025-07-30 11:06:05 +02:00
Sam Atkins
943cc0e32a LibWeb/CSS: Implement "legacy value aliases" in generated code
This uses a `foo>bar` notation in the `valid-identifiers` field of
Properties.json, to say "replace `foo` with `bar`".

The motivation here is to avoid calling `parse_css_value_for_property()`
inside the per-property switch in `parse_css_value()`. Eventually we'll
need to be able to call that switch from
`parse_css_value_for_properties()` so that shorthands can make use of
any bespoke parsing code to parse their longhands.
2025-07-23 12:50:42 +01:00
norbiros
90c0decd95 LibWeb/CSS: Add CSS.registerProperty JS method
This adds an *almost* complete implementation of `CSS.registerProperty`
method enabling further progress on the `@property` feature.
2025-07-22 10:57:54 +01:00
Andreas Kling
038d8ade50 LibWeb: Always parse calc() inside CSS color functions consistently
Some checks are pending
CI / macOS, arm64, Sanitizer, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer, Clang (push) Waiting to run
Package the js repl as a binary artifact / Linux, arm64 (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / Linux, x86_64 (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
Before this change, calc() would resolve to different types depending on
the nearest containing value context. This meant that rgb(calc(), ...)
by itself worked correctly due to fallbacks, but rgb(calc(), ...) inside
e.g a linear-gradient would create a calc() value that resolves to a
length, which subsequently got rejected by the color value parser.

Fixing this makes various little gradients show up on Discord.
2025-07-22 08:47:22 +01:00
Sam Atkins
11e2dbb555 LibWeb/CSS: Support text-justify: distribute legacy value alias
...for `text-justify: inter-character`.

We previously had this mapped in Enums.json, but the behaviour is
different: `a=b` in Enums.json keeps `a` around but makes it behave the
same as `b`. A legacy name alias is instead expected to replace `a`
with `b`, so we have to do that separately.
2025-07-21 10:04:42 +01:00
Sam Atkins
db75405881 LibWeb/CSS: Support overlay keyword as alias to auto in overflow
We don't yet have a system for "legacy value aliases", but until we have
a lot of them we can handle them manually.

We also have to do this in two places because
parse_css_value_for_property() doesn't call any property-specific
parsing code.
2025-07-21 10:04:42 +01:00
Gingeh
f38e07e0c5 LibWeb: Don't crash when an unknown property begins with a single dash 2025-07-20 08:54:53 +02:00
Callum Law
4ee8110449 LibWeb: Handle flood-opacity in line with other opacity properties
We now do the proper thing in terms of:
 - Allowing percentages
 - Returning the computed value in getComputedStyle
 - Handling values out of the [0,1] range

Gains us 13 WPT passes in the imported tests.
2025-07-18 11:04:55 -04:00
norbiros
7ad01d28a8 LibWeb/CSS: Add basic registered properties with initial values
Add global registry for registered properties and partial support
for `@property` rule. Enables registering properties with initial
values. Also adds basic retrieval via `var()`.

Note: This is not a complete `@property` implementation.
2025-07-18 11:12:39 +01:00
Sam Atkins
0ff61e5e7b LibWeb/CSS: Implement path() basic shape 2025-07-17 13:59:23 -04:00
Callum Law
3d7c5115d8 LibWeb: Move Transformation::to_matrix to new CSV resolve methods
This gains us 2 WPT passes as we now correctly disallow relative lengths
in more places in the `DOMMatrix` constructor.
2025-07-17 08:31:52 +02:00
Sam Atkins
27a666f3b2 LibWeb/CSS: Implement type(<syntax>) in attr()
Some checks are pending
CI / macOS, arm64, Sanitizer, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer, Clang (push) Waiting to run
Build Dev Container Image / build (push) Waiting to run
Package the js repl as a binary artifact / Linux, arm64 (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / Linux, x86_64 (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
This lets the `attr()` interpret the attribute's contents as an
arbitrary type instead of just as a string or number.
2025-07-16 14:47:45 +01:00
Sam Atkins
0a5e8c2865 LibWeb/CSS: Implement "parse with a <syntax>"
Uses the SyntaxNode tree to parse a list of ComponentValues into some
kind of StyleValue.
2025-07-16 14:47:45 +01:00
Sam Atkins
ded2207762 LibWeb/CSS: Parse the CSS <syntax> type into a tree
`<syntax>` is a limited subset of the "value definition syntax" used in
CSS specs. It's used for `@property`'s `syntax` descriptor, and for the
`type()` function in `attr()`.
2025-07-16 14:47:45 +01:00
Sam Atkins
72a7a18502 LibWeb/CSS: Use parse_value() to shrink parse_css_value_for_properties() 2025-07-16 14:47:45 +01:00
Sam Atkins
c7d4c4fbff LibWeb/CSS: Add a method to parse a value based on a ValueType 2025-07-16 14:47:45 +01:00
Sam Atkins
d18b0c07ca LibWeb/CSS: Make UnresolvedStyleValue figure out if it contains ASFs
UnresolvedStyleValue::create() has one user where we know if there are
any arbitrary substitution functions in the list of CVs, and two users
where we don't know and just hope there aren't any. I'm about to add
another user that also doesn't know, and so it seems worth just making
UnresolvedStyleValue::create() do that work instead.

We keep the parameter, now Optional<>, so that we save some redundant
work in that one place where we do already know.
2025-07-16 14:47:45 +01:00
Callum Law
afa95c2815 LibWeb: Mark CalculatedStyleValue::resolve_* methods as deprecated
The existing resolve methods are not to spec and we are working to
replace them with new ones based on the `simplify_a_calculation_tree`
method.

These are marked as deprecated rather than replaced outright as work
will need to be done on the caller side to be made compatible with the
new methods, for instance the new methods can fail to resolve (e.g.
if we are missing required context), where the existing methods will
always resolve (albeit sometimes with an incorrect value).

No functionality changes.
2025-07-16 13:05:33 +01:00
Callum Law
927cd969b2 LibWeb: Generically serialize "positional-value-list-shorthand"s
We were previously handling this ad-hoc via logic in
`get_property_internal` but this didn't cover all contexts (for
instance `CSSStyleProperties::serialized`.

Gains us 9 more WPT tests as we now cover properties which weren't
included in the previous ad-hoc approach.
2025-07-15 14:26:02 +01:00
Shannon Booth
9054ff29f0 LibWeb/CSS: Parse the ::slotted pseudo-element 2025-07-15 13:54:17 +01:00
Shannon Booth
0151a088ad LibWeb/CSS: Fix missing ':' in debug logging for pt-name-selector 2025-07-15 13:54:17 +01:00
Tim Ledbetter
c4cf1ccede LibWeb: Don't crash when parsing ASF with non comma-separated arguments 2025-07-09 19:47:12 +01:00
Lucien Fiorini
635adc8aa7 LibWeb/SVG: Implement resolution for a subset of SVG filters 2025-07-09 18:07:12 +01:00
Callum Law
a8fc15c6b3 LibWeb: Don't fail on non-fill keyword parsing <border-image-slice>
Previously if we encountered a keyword other than `fill` when parsing
`<border-image-slice` we would return a nullptr.

This could cause issues when we parse `<border-image-slice>` as part of
parsing `border-image`, for example `border-image: 100% none` would fail
as we would try parse `none` as part of the `<border-image-slice>`
instead of `<border-image-source>`.

This change makes it so that we don't consume the token and leave it to
be parsed as part of the next section of the grammar.
2025-07-09 16:59:22 +01:00
Callum Law
cfafb3bf36 LibWeb: Remove unused code in for_each_property_expanding_shorthands
This case is already handled by this point as `value` is a shorthand.

No functionality changes.
2025-07-09 16:59:22 +01:00
Sam Atkins
ce79bc793c LibWeb/CSS: Protect against the billion-laughs attack
The attack unfortunately still slows us down, but this prevents us from
OOMing. Currently, we don't save the value of `var(--foo)` after
computing it once, so in this example, we end up computing `--prop1` 4
times to compute `--prop3`, but then we start again from scratch when
computing `--prop4`:

```css
  --prop1: lol;
  --prop2: var(--prop1) var(--prop1);
  --prop3: var(--prop2) var(--prop2);
  --prop4: var(--prop3) var(--prop3);
}
```

This should be solvable later if we update the computed values as we go.
2025-07-09 16:44:20 +01:00
Sam Atkins
b6032b0fcd LibWeb/CSS: Reimplement var()/attr() as arbitrary substitution functions
"Arbitrary substitution functions" are a family of functions that
includes var() and attr(). All of them resolve to an arbitrary set of
component values that are not known at parse-time, so they have to be
substituted at computed-value time.

Besides it being nice to follow the spec closely, this means we'll be
able to implement the others (such as `if()` and `inherit()`) more
easily.

The main omission here is the new "spread syntax", which can be
implemented in the future.
2025-07-09 16:44:20 +01:00
Sam Atkins
b417d13a7b LibWeb/CSS: Add method to parse <declaration-value>
This has an extra parameter to allow stopping at the first comma token,
which we need for var() and attr()'s "argument grammar".

Co-authored-by: Tim Ledbetter <tim.ledbetter@ladybird.org>
2025-07-09 16:44:20 +01:00
Sam Atkins
26acd897bf LibWeb: Produce computed values for custom properties
Custom properties are required to produce a computed value just like
regular properties. The computed value is defined in the spec as
"specified value with variables substituted, or the guaranteed-invalid
value", though in reality all arbitrary substitution functions should be
substituted, not just `var()`.

To support this, we parse the CSS-wide keywords normally in custom
properties, instead of ignoring them. We don't yet handle all of them
properly, and because that will require us to cascade them like regular
properties. This is just enough to prevent regressions when implementing
ASFs.

Our output in this new test is not quite correct, because of the awkward
way we handle whitespace in property values - so it has 3 spaces in the
middle instead of 1, until that's fixed.

It's possible this computed-value production should go in
cascade_custom_properties(), but I had issues with that. Hopefully once
we start cascading custom properties properly, it'll be clearer how
this should all work.
2025-07-09 16:44:20 +01:00