Functionally this is the same before, as result is always True or False
before this point, and `True && Foo` evaluates to `Foo`. But this is
more clearly correct, instead of correct by coincidence.
This commit on its own has no observable behaviour changes, as we still
only return True or False, but for the next commit, we'll need to be
able to return the Unknown state here, and without this change we'd get
regressions.
This is very hacky and wrong, but it means there's one place to fix,
instead of one for UnresolvedStyleValue, and one for invalid
MediaFeatureValues which I'm about to implement.
The current spec defines this simply as `<ident>`, but does apparently
serialize as lowercase.
Because of this change, we no longer need to care about the deprecated
media types, as they all behave the same as unknown ones.
We still keep an enum around for KnownMediaType, to avoid repeated
string comparisons when evaluating it.
Gets us 2 WPT passes.
In a recent refactor of font styles, the new FontStyleStyleValue was
introduced; however, the `to_font_slope()` function was not changed to
understand this new type. When it tries to convert such a font style to
a keyword, it fails. We then rendered the wrong font-style.
Which has an optmization if both size of the string being passed
through are FlyStrings, which actually ends up being the case
in some places during selector matching comparing attribute names.
Instead of maintaining more overloads of
Infra::is_ascii_case_insensitive_match, switch
everything over to equals_ignoring_ascii_case instead.
When position changes, we may need to make larger structural updates
to the layout tree. A simple relayout is not sufficient.
This was a source of flakiness in the engine, and gives us at least
+28 new WPT subtest passes.
This fixes an issue where we'd serialize some floating point numbers
with excessive precision, resulting in unpleasant-looking numbers like
0.49999999999999999 and such.
At least 90 new subtests passing on WPT, possibly more. :^)
There's discussion in the linked spec issue, but the short version is,
this algorithm will see "foo,bar," as a list of two groups, with "foo"
in the first group and "bar" in the second. However, users of this want
to get a list of three groups, with the last one being empty. So, do
that!
Some dimensions would always serialize in a canonical unit, others never
did, and others we manually would do so in their StyleValue. This
commit moves all of that into the dimension types, which means for
example that Length can apply its special rounding.
Our local serialization test now produces the same output as other
browsers. :^)
Selector::serialize() is used for both normal and relative selectors.
For the latter, we need to serialize their initial combinator, and for
the former, we always set the initial combinator as None anyway, so
this would be a no-op there.
Gets us 3 WPT passes.
The spec requires us to accept any ident here, not just ltr/rtl, and
also serialize it back out. That means we need to keep the original
string around.
In order to not call keyword_from_string() every time we want to match
a :dir() selector, we still attempt to parse the keyword and keep it
around.
A small behaviour change is that now we'll serialize the ident with its
original casing, instead of always lowercase. Chrome and Firefox
disagree on this, so I think either is fine until that can be
officially decided.
Gets us 2 WPT passes (including 1 from the as-yet-unmerged :dir() test).
The spec gives us a hard-coded list of functional pseudo-classes and how
to serialize them - but this list is incomplete and likely to always be
outdated compared to the list of pseudo-classes that exist. So instead,
use the generated metadata we already have to serialize their arguments
based on their type.
This fixes :dir() and :has(), which previously did not serialize their
arguments.
Gets us 26 passes (including 6 from that as-yet-unmerged :dir() test).
The main motivation here is that the CSS Parser needs to know about
PageSelectorList so that we can parse one in
`CSSPageRule::set_selector_text()`. Including all of `CSSPageRule.h`
there would pull in a lot of other headers that aren't needed.
Previously we only matched against the first attribute with a given
local name. What we actually want to do is look at each attribute with
that local name in turn and only return false if none of them match.
Also remove a hack for HTML elements in HTML documents, where we would
refuse to match any namespaced attributes. This doesn't seem to be
based on the spec, but we had regressions without it, until now. :^)
Gets us 21 more WPT subtest passes.
The HTML spec gives us a list of HTML attributes that must have their
values compared case-insensitively by default (when the attribute
selector does not specify a case-sensitiveness). However, ifwe have a
namespace, then we are not looking for an HTML attribute, so this
should not apply.
Gets us 8 more WPT subtest passes.
This is a bit under-specced, specifically there's no definition of
CSSMarginDescriptors so I've gone with CSSStyleProperties for now. Gets
us 17 WPT subtests.
With this, we pass the 8 ref tests in css/selectors/selectors-4/ which
previously failed. This is not technically a full implementation, as we
are supposed to first canonicalize the language range and tag, but that
will require downloading and processing the IANA language subtag
registry:
https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
That's significantly more work, and WPT doesn't seem to test any cases
that require that, so we can leave it for now.
I was wrong when I added those notes before about this being impossible,
it's *very* possible, for example with the `@page margin` descriptor.
However, until we have a large number of these shorthands and not just a
single example, we can get away with hard-coding support for it.
Ideally we'd be able to share the code between page selectors and style
ones, but given how simple page selectors are, some code duplication is
the simpler option.
Previously, we would just assign the UnresolvedStyleValue to each
longhand, which was completely wrong but happened to work if it was a
ShorthandStyleValue (because that's basically a list of "set property X
to Y", and doesn't care which property it's the value of).
For example, the included `var-in-margin-shorthand.html` test would:
1. Set `margin-top` to `var(--a) 10px`
2. Resolve it to `margin-top: 5px 10px`
3. Reject that as invalid
What now happens is:
1. Set `margin-top` to a PendingSubstitutionValue
2. Resolve `margin` to `5px 10px`
3. Expand that out into its longhands
4. `margin-top` is `5px` 🎉
In order to support this, `for_each_property_expanding_shorthands()` now
runs the callback for the shorthand too if it's an unresolved or
pending-substitution value. This is so that we can store those in the
CascadedProperties until they can be resolved - otherwise, by the time
we want to resolve them, we don't have them any more.
`cascade_declarations()` has an unfortunate hack: it tracks, for each
declaration, which properties have already been given values, so that
it can avoid overwriting an actual value with a pending one. This is
necessary because of the unfortunate way that CSSStyleProperties holds
expanded longhands, and not just the original declarations. The spec
disagrees with itself about this, but we do need to do that expansion
for `element.style` to work correctly. This HashTable is unfortunate
but it does solve the problem until a better solution can be found.
If `value` was UnresolvedStyleValue, we'd attempt to `set_property...()`
with its resolved value, then call that again with the original
UnresolvedStyleValue. For any other kind of `value`, we'd simply call
call `set_property...()` twice with the same parameters.