When a property is a "legacy name alias", any time it is used in CSS or
via the CSSOM its aliased name is used instead.
(See https://drafts.csswg.org/css-cascade-5/#legacy-name-alias)
This means we only care about the alias when parsing a string as a
PropertyID - and we can just return the PropertyID it is an alias for.
No need for a distinct PropertyID for it, and no need for LibWeb to
care about it at all.
Previously, we had a bunch of these properties, which misused our code
for "logical aliases", some of which I've discovered were not even
fully implemented. But with this change, all that code can go away, and
making a legacy alias is just a case of putting it in the JSON. This
also shrinks `StyleProperties` as it doesn't need to contain data for
these aliases, and removes a whole load of `-webkit-*` spam from the
style inspector.
The spec allows us to either treat them as part of the UA origin, or as
its own origin before author styles. This second behaviour turns out to
be what we are currently doing, which is nice!
Funnily enough this was clarified in the spec barely a month after this
original comment was written. :^)
`revert` is supposed to revert to the previous cascade origin, but we
previously had it reverting to the previous layer. To support both,
track them separately during the cascade.
As part of this, we make `set_property_expanding_shorthands()` fall back
to `initial` if it can't find a previous value to revert to. Previously
we would just shrug and do nothing if that happened, which only works
if the value you want to revert to is whatever is currently in `style`.
That's no longer the case, because `revert` should skip over any layer
styles that have been applied since the previous origin.
If we don't recognize a given transition-property value as a known CSS
property (one that we know about, not necessarily an invalid one),
we should not extrapolate the other transition-foo values for it.
Fixes#1480
As useful as they may be to web developers, :has() selectors complicate
the style invalidation process quite a lot.
Let's have StyleComputer keep track of whether they are present at all
in the current set of active style sheets. This will allow us to
implement fast-path optimizations when there are no :has() selectors.
The web server for WPT has a tendency to just disconnect after sending
us a resource. This makes curl think an error occurred, but it's
actually still recoverable and we have the data.
So instead of just bailing, do what we already do for other kinds of
resources and try to parse the data we got. If it works out, great!
It would be nice to solve this in the networking layer instead, but
I'll leave that as an exercise for our future selves.
Instead of throwing all pseudo-element rules in one bucket, let's have
one bucket per pseudo-element.
This means we only run ::before rules for ::before pseudo-elements,
only ::after rules for ::after, etc.
Average style update time on https://tailwindcss.com/ 250ms -> 215ms.
Once we know the final value of the `content` property for a
pseudo-element, we can bail early if the value is `none` or `normal`
(note that `normal` only applies to ::before and ::after).
In those cases, no pseudo-element will be generated, so everything
that follows in StyleComputer would be wasted work.
This noticeably improves performance on many pages, such as
https://tailwindcss.com/ where style updates go from 360ms -> 250ms.
This makes the way we've implemented the CSS `revert` keyword a lot less
expensive.
Until now, we were making a deep copy of all property values at the
start of each cascade origin. (Those are the values that `revert` would
bring us back to if encountered.)
With this patch, the revert property set becomes a shallow copy, and we
only clone the property set if the cascade ends up writing something.
This knocks a 5% profile item down to 1.3% on https://tailwindcss.com
Skia is more permissive when it comes to font loading, compared to our
own OpenType implementation, which it has superseded, parsing an invalid
TTF does not result in an error but rather produces a font that is
incorrectly displayed. This change updates the FontLoader to address
this behavior and to stop attempting to parse a font as a last resort
when format detection has failed.
Fixes regression on x.com when text is not displayed introduced in
a9d5a99568
Instead of only bucketing these by class name, let's also bucket by
tag name and ID.
Reduces the number of selectors evaluated on https://tailwindcss.com/
from 2.9% to 1.9%.
By filtering first, we end up allocating much less vector space
most of the time.
This is mostly helpful in pathological cases where there's a huge number
of rules present, but most of them get rejected early.
By bucketing these seletors by class or ID, we can avoid running them
in more cases.
Before, we were only avoiding them if the context element wasn't a div.
Now we avoid them for any element that doesn't have that specific class
or ID.
This reduces the number of selectors ran on https://vercel.com by a bit
more, from 1.90% to 1.65%.
These are just roundabout ways of writing .foo, so we can still put them
in the rules-by-class bucket and skip running them when the element
doesn't have that class.
Note that :is(.foo .bar) is also bucketed as a class rule, since the
context element must have the `bar` class for the selector to match.
This is a massive speedup on https://vercel.com/ as it cuts the number
of selectors we actually evaluate from 7.0% to 1.9%.
You can now build with STYLE_INVALIDATION_DEBUG and get a debug stream
of reasons why style invalidations are happening and where.
I've rewritten this code many times, so instead of throwing it away once
again, I figured we should at least have it behind a flag.
Before this change, we were cascading custom properties for each layer,
and then replacing any previously cascaded properties for the element
with only the set from this latest layer.
The patch fixes the issue by making each pass of the custom property
cascade add to the same set, and then finally assigning that set of
properties to the element.
Before this change, we were only checking for actual glyph containment
in a font if unicode ranges were specified. However that is not
sufficient for emoji support, where we want to continue searching for
a font until one containing emojis is found.
This change should move us forward toward emoji support, as we are no
longer limited by our own OpenType implementation, which was failing
to parse the TrueType Collection format used to store emoji fonts
(at least on macOS).
Currently we rely on parser returning an error if encoded data cannot be
parsed into a valid WOFF or WOFF2 font, which is not going to be true
after switching to Skia that sometimes does not fail even if a data does
not represent a valid font.
This is only used for CSS style sheets. One case wants it as a String,
and the others don't care, but will in future also want to have the
source as a String.
Instead of CSSColorValue holding a Gfx::Color, make it an abstract class
with subclasses for each different color function, to match the Typed-OM
spec. This means moving the color calculations from the parsing code to
the `to_color()` method on the style value.
This lets us have calc() inside a color function, instead of having to
fully resolve the color at parse time. The canvas fillStyle tests have
been updated to reflect this.
The other test change is Screenshot/css-color-functions.html: previously
we produced slightly different colors for an alpha of 0.5 and one of
50%, and this incorrect behavior was baked into the test. So now it's
more correct. :^)
Soon, CSSColorValue will be an abstract class, and we'll instead create
a CSSRGB, CSSHSL, or other specific color type from the Typed-OM spec.
However, it's still useful to have an easy "just give me a style value
for this color" method. So change the name to distinguish this from the
usual StyleValue::create() methods.
We previously had 4 single-instance StyleValues for these keywords.
CSS-Typed-OM expects them keywords to be exposed as CSSKeywordValue, so
it's simpler to treat them the same. The single-instance behaviour is
kept by having StyleValue::create() use a cached instance for each of
these.
For a long time, we've used two terms, inconsistently:
- "Identifier" is a spec term, but refers to a sequence of alphanumeric
characters, which may or may not be a keyword. (Keywords are a
subset of all identifiers.)
- "ValueID" is entirely non-spec, and is directly called a "keyword" in
the CSS specs.
So to avoid confusion as much as possible, let's align with the spec
terminology. I've attempted to change variable names as well, but
obviously we use Keywords in a lot of places in LibWeb and so I may
have missed some.
One exception is that I've not renamed "valid-identifiers" in
Properties.json... I'd like to combine that and the "valid-types" array
together eventually, so there's no benefit to doing an extra rename
now.
Not every value in a StyleProperties will be non-null by the time we
perform `revert`, so let's make a specialized function for reverting a
property instead of using the path that requires the value to be
non-null.
We were saving to source declarations for *every* property, even though
we only ever looked it up for animation-name.
This patch gets rid of the per-property source pointer and we now keep
a single pointer to the animation-name source only.
This shrinks StyleProperties from 6512 bytes to 4368 bytes per instance.
The :host family of pseudo class selectors select the shadow host
element when matching against a rule from within the element's shadow
tree.
This is a bit convoluted due to the fact that the document-level
StyleComputer keeps track of *all* style rules, and not just the
document-level ones.
In the future, we should refactor style storage so that shadow roots
have their own style scope, and we can simplify a lot of this.
This change removes wrappers inherited from Gfx::Typeface for WOFF and
WOFF2 fonts. The only purpose they served is owning of ttf ByteBuffer
produced by decoding a WOFF/WOFF2 font. Now new FontData class is
responsible for holding ByteBuffer when a font is constructed from
non-externally owned memory.
We already have a FlyString of its value from parsing, and most users
also want a FlyString from it, so let's use that instead of converting
backwards and forwards.
The two users that did want a String are:
- Quotes, which make sense as FlyString instead, so I've converted that.
- Animation names, which should probably be FlyString too, but the code
currently also allows for other kinds of StyleValue, and I don't want
to dive into this right now to figure out if that's needed or not.