Commit graph

61 commits

Author SHA1 Message Date
Tim Ledbetter
5d57723ebf LibWeb: Implement CSSImportRule.supportsText
Returns the supports condition specified by the given import at-rule.
2025-03-19 16:42:51 +01:00
Sam Atkins
9b06f66571 LibWeb/CSS: Return GC::Ref from Parser::convert_to_style_declaration() 2025-03-19 13:53:00 +00:00
Sam Atkins
83bb92c4e0 LibWeb/CSS: Merge style declaration subclasses into CSSStyleProperties
We previously had PropertyOwningCSSStyleDeclaration and
ResolvedCSSStyleDeclaration, representing the current style properties
and resolved style respectively. Both of these were the
CSSStyleDeclaration type in the CSSOM. (We also had
ElementInlineCSSStyleDeclaration but I removed that in a previous
commit.)

In the meantime, the spec has changed so that these should now be a new
CSSStyleProperties type in the CSSOM. Also, we need to subclass
CSSStyleDeclaration for things like CSSFontFaceRule's list of
descriptors, which means it wouldn't hold style properties.

So, this commit does the fairly messy work of combining these two types
into a new CSSStyleProperties class. A lot of what previously was done
as separate methods in the two classes, now follows the spec steps of
"if the readonly flag is set, do X" instead, which is hopefully easier
to follow too.

There is still some functionality in CSSStyleDeclaration that belongs in
CSSStyleProperties, but I'll do that next. To avoid a huge diff for
"CSSStyleDeclaration-all-supported-properties-and-default-values.txt"
both here and in the following commit, we don't apply the (currently
empty) CSSStyleProperties prototype yet.
2025-03-19 13:53:00 +00:00
Sam Atkins
50455c2f5e LibWeb: Stop constructing temporary ElementInlineCSSStyleDeclarations
Previously, parse_css_style_attribute() would parse the string, extract
the properties, add them to a newly-created
ElementInlineCSSStyleDeclarations, and then user code would take the
properties back out of it again and throw it away. Instead, just return
the list of properties, and the caller can create an EICSD if it needs
one.
2025-03-19 13:53:00 +00:00
Sam Atkins
db597843d6 LibWeb/CSS: Correct parsing of @supports selector()
A couple of fixes here:
- Parse a `<complex-selector>` instead of a `<selector-list>`
- Don't match if any unknown `::-webkit-*` pseudo-elements are found
2025-03-17 10:00:19 +00:00
Sam Atkins
b6fb4baeb7 LibWeb/CSS: Implement @supports font-format() and font-tech()
These let authors query whether we support font formats and features.
2025-03-17 10:00:19 +00:00
Sam Atkins
0f5e054f97 LibWeb: Implement generic boolean logic for media/supports queries
CSS Values 5 now defines a `<boolean-expr[]>` type that is used in place
of the bespoke grammar that previously existed for `@media` and
`@supports` queries. This commit implements some BooleanExpression
types to represent the nodes in a `<boolean-expr[]>`, and reimplements
`@media` and `@supports` queries using this.

The one part of this implementation I'm not convinced on is that the
`evaluate()` methods take a `HTML::Window*`. This is a compromise
because `@media` requires a Window, and `@supports` does not require
anything at all. As more users of `<boolean-expr[]>` get implemented in
the future, it will become clear if this is sufficient, or if we need
to do something smarter.

As a bonus, this actually improves our serialization of media queries!
2025-03-17 10:00:19 +00:00
Sam Atkins
84a695c958 LibWeb/CSS: Evaluate Supports query components during parsing
Instead of parsing the parts of a `@supports` query, then only
evaluating them when constructing the Supports itself, we can instead
evaluate them as we parse them. This simplifies things as we no longer
need to pass a Realm around, and don't have to re-parse the conditions
again with a new Parser instance.
2025-03-17 10:00:19 +00:00
Shannon Booth
53826995f6 LibURL+LibWeb: Port URL::complete_url to Optional
Removing one more source of the URL::is_valid API.
2025-02-15 17:05:55 +00:00
Sam Atkins
6a4d80b9b6 LibWeb/CSS: Integrate ParsingContext into the Parser
This is not really a context, but more of a set of parameters for
creating a Parser. So, treat it as such: Rename it to ParsingParams,
and store its values and methods directly in the Parser instead of
keeping the ParsingContext around.

This has a nice side-effect of not including DOM/Document.h everywhere
that needs a Parser.
2025-02-06 16:47:25 +00:00
Sam Atkins
4d0537ee80 LibWeb/CSS: Make CSS Parser non-copyable/movable
We never actually need to do this, and doing so was complicated because
of the token stream, so just disable it altogether.
2025-02-06 16:47:25 +00:00
Sam Atkins
0ac133d73b LibWeb/CSS: Replace is_generic_font_family() with a CSS enum
Also add the missing "math" value to it.
2025-02-06 16:47:25 +00:00
Sam Atkins
6da7a6eab5 LibWeb/CSS: Un-template some CSS Parser methods
A few of these are only ever called with T=Token, so let's simplify them
a bit.

As a drive-by change: Also correct the "unnecessairy" typos and use
discard_a_token().
2025-02-06 16:47:25 +00:00
Sam Atkins
1413760047 LibWeb/CSS: Split up Parser.cpp
This file has been a pain to edit for a while, even with the previous
splits. So, I've divided it up into 3 parts:
- Parser.cpp has the "base" code. It's the algorithms and entry-points
  defined in the Syntax spec.
- ValueParsing.cpp contains code for parsing single values, such as a
  length, or a color, or a calculation.
- PropertyParsing.cpp contains code for parsing an entire property's
  value. A few of these sit in a grey area between being a property's
  value and a value in their own right, but the rule I've used is "is
  this useful outside of a single property and its shorthands?"

This only moves code, with as few modifications as possible to make that
work. I did add explicit instantiations for the template implementations
as part of this, which revealed a few that are actually only compatible
with a single type, so I'll clear those up in a subsequent commit.
2025-02-06 16:47:25 +00:00
Sam Atkins
f8cc990bcd LibWeb/CSS: Remove ad-hoc calc simplification from var/attr() expansion
Now that we simplify calculations after parsing them, this is redundant.
2025-01-30 19:31:54 +01:00
Sam Atkins
ee712bd98f LibWeb/CSS: Simplify calculations after parsing them
If a calculation was simplified down to a single numeric node, then most
of the time we can instead return a regular StyleValue, for example
`calc(2px + 3px)` would be simplified down to a `5px` LengthStyleValue.
This means that parse_calculated_value() can't return a
CalculatedStyleValue directly, and its callers all have to handle
non-calculated values as well as calculated ones.

This simplification is reflected in the new test results. Serialization
is not yet correct in all cases but we're closer than we were. :^)
2025-01-30 19:31:54 +01:00
Sam Atkins
39cefd7abf LibWeb/CSS: Tell CalculationContext whether to treat numbers as integers
Calc simplification eventually produces a single style-value as its
output. This extra context data will let us know whether a calculated
number should be treated as a `<number>` or an `<integer>`, so that for
example, `z-index: 12` and `z-index: calc(12)` both produce an
`IntegerStyleValue` containing 12.
2025-01-30 19:31:54 +01:00
Sam Atkins
b947ae60db LibWeb/CSS: Remove custom <integer> parsing from math-depth 2025-01-30 19:31:54 +01:00
Sam Atkins
c3d61020e7 LibWeb/CSS: Make CalculationNodes ref-counted
Calc simplification (which I'm working towards) involves repeatedly
deriving a new calculation tree from an existing one, and in many
cases, either the whole result or a portion of it will be identical to
that of the original. Using RefPtr lets us avoid making unnecessary
copies. As a bonus it will also make it easier to return either `this`
or a new node.

In future we could also cache commonly-used nodes, similar to how we do
so for 1px and 0px LengthStyleValues and various keywords.
2025-01-30 19:31:54 +01:00
Sam Atkins
1d71662f31 LibWeb/CSS: Wrap calc()-resolution data in a struct
Initially I added this to the existing CalculationContext, but in
reality, we have some data at parse-time and different data at
resolve-time, so it made more sense to keep those separate.

Instead of needing a variety of methods for resolving a Foo, depending
on whether we have a Layout::Node available, or a percentage basis, or
a length resolution context... put those in a
CalculationResolutionContext, and just pass that one thing to these
methods. This also removes the need for separate resolve_*_percentage()
methods, because we can just pass the percentage basis in to the regular
resolve_foo() method.

This also corrects the issue that *any* calculation may need to resolve
lengths, but we previously only passed a length resolution context to
specific types in some situations. Now, they can all have one available,
though it's up to the caller to provide it.
2025-01-30 19:31:54 +01:00
Sam Atkins
8877a4f691 LibWeb/CSS: Hide "No property (from N properties) matched foo" message
This greatly reduces the amount of log spam on certain websites.
2025-01-29 12:04:14 +00:00
Aliaksandr Kalenik
d79bb1aac2 LibWeb: Fix underinvalidation when inline style has custom properties
We have an optimization that allows us to invalidate only the style of
the element itself and mark descendants for inherited properties update
when the "style" attribute changes (unless there are any CSS rules that
use the "style" attribute, then we also invalidate all descendants that
might be affected by those rules). This optimization was not taking into
account that when the inline style has custom properties, we also need
to invalidate all descendants whose style might be affected by them.

This change fixes this bug by saving a flag in Element that indicates
whether its style depends on any custom properties and then invalidating
all descendants with this flag set when the "style" attribute changes.
Unlike font relative lengths invalidation, for elements that depend on
custom properties, we need to actually recompute the style, instead of
individual properties, because values without expanded custom properties
are gone after cascading, and it has to be done again.

The test added for this change is a version of an existing test we had
restructured such that it doesn't trigger aggressive style invalidation
caused by DOM structured changes until the last moment when test results
are printed.
2025-01-28 11:38:06 +00:00
Sam Atkins
b3b9eea986 LibWeb/CSS: Merge RotationStyleValue into TransformationStyleValue
Same again, although rotation is more complicated: `rotate`
is "equivalent to" multiple different transform function depending on
its arguments. So we can parse as one of those instead of the full
`rotate3d()`, but then need to handle this when serializing.
2025-01-17 10:12:39 +01:00
Sam Atkins
03a4ecce19 LibWeb/CSS: Merge TranslationStyleValue into TransformationStyleValue
As with ScaleStyleValue, the serialization is the only unique part of
this class, and we can just move it over.
2025-01-17 10:12:39 +01:00
Sam Atkins
ac15e626dd LibWeb/CSS: Merge ScaleStyleValue into TransformationStyleValue
The only ways this varies from the `scale()` function is with parsing
and serialization. Parsing stays separate, and serialization is done by
telling `TransformationStyleValue` which property it is, and overriding
its normal `to_string()` code for properties other than `transform`.
2025-01-17 10:12:39 +01:00
Sam Atkins
4efdb76857 LibWeb/CSS: Give calc() a CalculationContext for resolving percentages
This is passed in at construction, meaning we will be able to refer to
it later, when we're no longer inside the Parser.
2025-01-13 10:59:16 +00:00
Sam Atkins
bc00ef8314 LibWeb/CSS: Replace Parser "current property" with a stack of contexts
`current_property_id()` is insufficient to determine if a quirk is
allowed. For example, unitless lengths are allowed in certain
properties, but NOT if they are inside a calc() or other function. It's
also incorrect when we are parsing a longhand inside a shorthand. So
instead, replace that with a stack of value-parsing contexts. For now,
this is either properties or CSS functions, but in future can be
expanded to include media features and other places.

This lets us disallow quirks inside functions, like we're supposed to.

It also lays the groundwork for being able to more easily determine
what type a percentage inside a calculation should become, as this is
based on the same stack of contexts.
2025-01-13 10:59:16 +00:00
Sam Atkins
ba43dfe49a LibWeb/CSS: Remove use of Dimension in calc() parsing
Rather than partly-converting number, dimension, and ident tokens at the
start of parsing a calculation, and then later finishing it off, we can
just do the whole step in convert_to_calculation_node(). This is a
little less code, but mainly means we are left with only a single use
of the Dimension type in the codebase, so that can be removed soon.
2025-01-08 14:28:54 +00:00
Sam Atkins
5cda2ac961 LibWeb/CSS: Remove illegal <number-percentage> type
Various places in the spec allow for `<number> | <percentage>`, but this
is either/or, and they are not allowed to be combined like dimensions
and percentages are. (For example, `calc(12 + 50%)` is never valid.)

User code generally doesn't need to care about this distinction, but it
does now need to check if a calculation resolves to a number, or to a
percentage, instead of a single call.

The existing parse_number_percentage[_value]() methods have been kept
for simplicity, but updated to check for number/percentage separately.
2025-01-08 14:28:54 +00:00
Sam Atkins
ab5ac82db6 LibWeb/CSS: Parse dimension and number types individually
An upcoming change requires that we can determine which property we are
parsing before we parse the value. That's the opposite of what this
code previously did, which was to parse a generic dimension or calc()
and then figure out what property would accept it.
2025-01-08 14:28:54 +00:00
Sam Atkins
87da0453c8 LibWeb/CSS: Use parse_length_percentage() in parse_position_value()
Also some minor TokenStream-usage tweaks to make that possible.
2025-01-08 14:28:54 +00:00
Sam Atkins
34523f67cc LibWeb/CSS: Reuse dimension style value parsing code
Otherwise we're doing the same thing in two places.
2025-01-08 14:28:54 +00:00
Sam Atkins
f3a3344b9b LibWeb/CSS: Simplify parse_hue_none_value()
The motivation was to remove the parse_dimension() call, but this got a
lot smaller.
2025-01-08 14:28:54 +00:00
Sam Atkins
563f8572d5 LibWeb/CSS: Expand out parse_dimension_value()
When we know what kind of dimension we want, it's awkward to attempt to
parse any dimension type, including quirks that only affect lengths, to
then throw it away unless it's the type we wanted in the first place.

Additionally, move the unitless angle/length behavior for SVG attributes
into these methods, where it belongs.

Instead, only try to parse the type of dimension we want. This is
currently more code, but some could be factored together later.
2025-01-08 14:28:54 +00:00
Sam Atkins
f5b716c24d LibWeb/CSS: Simplify parsing of transform-function arguments
This was duplicating the logic in parse_length_value() and pals, so we
can switch to using those directly.
2025-01-08 14:28:54 +00:00
Gingeh
8e56109515 LibWeb/CSS: Implement the light-dark color function 2025-01-08 11:18:13 +00:00
Gingeh
ce5cd012b9 LibWeb/CSS: Implement the color-scheme CSS property 2025-01-08 11:18:13 +00:00
Gingeh
436417aabe LibWeb: Parse background positions as shorthands 2024-12-30 11:07:53 +01:00
Andreas Kling
3bfb0534be LibGC: Rename MarkedVector => RootVector
Let's try to make it a bit more clear that this is a Vector of GC roots.
2024-12-26 19:10:44 +01:00
Sam Atkins
eb11c35640 LibWeb/CSS: Use CSSNumericType for CalculationResult's numeric type
When we originally implemented calc(), the result of a calculation was
guaranteed to be a single CSS type like a Length or Angle. However, CSS
Values 4 now allows more complex type arithmetic, which is represented
by the CSSNumericType class. Using that directly makes us more correct,
and allows us to remove a large amount of now ad-hoc code.

Unfortunately this is a large commit but the changes it makes are
interconnected enough that doing one at a time causes test
regressions.

In no particular order:

- Update our "determine the type of a calculation" code to match the
  newest spec, which sets percent hints in a couple more cases. (One of
  these we're skipping for now, I think it fails because of the FIXMEs
  in CSSNumericType::matches_foo().)
- Make the generated math-function-parsing code aware of the difference
  between arguments being the same type, and being "consistent" types,
  for each function. Otherwise those extra percent hints would cause
  them to fail validation incorrectly.
- Use the CSSNumericType as the type for the CalculationResult.
- Calculate and assign each math function's type in its constructor,
  instead of calculating it repeatedly on-demand.

The `CalculationNode::resolved_type()` method is now entirely unused and
has been removed.
2024-12-21 18:14:28 +01:00
Sam Atkins
69a0f28d04 Revert "LibWeb/CSS: Rename CalculatedStyleValue -> CSSMathValue"
This reverts commit 76daba3069.

We're going to need separate types for the JS-exposed style values, so
it doesn't make sense for us to match their names with our internal
types.
2024-12-21 18:14:28 +01:00
Lucien Fiorini
9fd1223992 LibWeb+LibGfx: Refactor CSS filters into LibGfx
CSS filters work similarly to canvas filters, so it makes sense to have
Gfx::Filter that can be used by both libraries in an analogous way
as Gfx::Color.
2024-12-18 18:54:20 +01:00
Sam Atkins
6969d1eba3 LibWeb/CSS: Parse calc() as intermediate types instead of UnparsedCN
Previously we created a tree of CalculationNodes with dummy
UnparsedCalculationNode children, and then swapped those with the real
children. This matched the spec closely but had the unfortunate
downside that CalculationNodes couldn't be immutable, and couldn't know
their properties at construct-time. UnparsedCalculationNode is also a
footgun, as if it gets left in the tree accidentally we would VERIFY().

So instead, let's parse the calc() tree into an intermediate format, and
then convert each node in that tree, depth-first, into its
corresponding CalculationNode. This means each CalculationNode knows
what its children are when it is constructed, and they never change.

Apart from deleting UnparsedCalculationNode, we can also get rid of the
for_each_child_node() method that was only used by this "replace the
children" code.
2024-12-18 12:21:22 +00:00
Johan Dahlin
aabbe87628 LibWeb: Parse font-variant-* css properties 2024-12-17 19:07:13 +01:00
Gingeh
84150f972f LibWeb: Properly serialize position/edge style values 2024-12-13 11:35:38 +00:00
Lucas CHOLLET
dd283768a8 LibWeb/CSS: Allow none values in the color() function 2024-12-11 22:38:14 +00:00
Andreas Kling
e85c3c97fb LibWeb: Add mode flag to CSSStyleValue::to_string()
This will be used to differentiate between serialization for resolved
style (i.e window.getComputedStyle()) and serialization for all other
purposes.
2024-12-07 08:31:03 +00:00
Sam Atkins
2c3c821305 LibWeb: Remove Realm parameter from property_initial_value()
We don't need the Realm to parse a style value.

Fixes #2720
2024-12-05 19:59:57 +01:00
Gingeh
0afd7f166a LibWeb: Improve grid-template-area parsing and serialization 2024-12-02 16:19:47 +00:00
Jonne Ransijn
3f5e32ee84 LibWeb: Stop allocating Tokens and ComponentValues unnecessarily
When the "Consume a component value from input, and do nothing."
step in `Parser::consume_the_remnants_of_a_bad_declaration` was
executed, it would allocate a `ComponentValue` that was then
immediately discarded.

Add explicitly `{}_and_do_nothing` functions for this case that never
allocate a `ComponentValue` in the first place.

Also remove a `(Token)` cast, which was unnecessarily copying a `Token`
as well.
2024-12-01 11:30:06 +01:00