Although DistinctNumeric, which is supposed to abstract the underlying
type, was used to represent CSSPixels, we have a whole bunch of places
in the layout code that assume CSSPixels::value() returns a
floating-point type. This assumption makes it difficult to replace the
underlying type in CSSPixels with a non-floating type.
To make it easier to transition CSSPixels to fixed-point math, one step
we can take is to prevent access to the underlying type using value()
and instead use explicit conversions with the to_float(), to_double(),
and to_int() methods.
Now that we have a way to resolve calc() lengths without a layout node,
we can finally support calc() values in font-size.
This wasn't possible before because font-related properties have to be
resolved eagerly in StyleComputer due to font-relative CSS length units
depending on the computed font being known.
Unlike DOM mutations, CSS animations don't affect the style of the
entire subtree of the element being animated. This means we only have to
recompute style for the animating element, which is significantly
faster than doing the whole subtree.
This takes idle CPU usage on https://shopify.com/ from 100% to 30% on my
(not massively powerful) laptop. :^)
This commit makes the StyleComputer avoid restarting finished animations
(e.g. animations with finite iteration counts that have run to
completion).
As a bonus, it also disables the animation timer when all animations
have finished running.
This partially implements CSS-Animations-1 (though there are references
to CSS-Animations-2).
Current limitations:
- Multi-selector keyframes are not supported.
- Most animation properties are ignored.
- Timing functions are not applied.
- Non-absolute values are not interpolated unless the target is also of
the same non-absolute type (e.g. 10% -> 25%, but not 10% -> 20px).
- The JavaScript interface is left as an exercise for the next poor soul
looking at this code.
With those said, this commit implements:
- Interpolation for most common types
- Proper keyframe resolution (including the synthetic from-keyframe
containing the initial state)
- Properly driven animations, and proper style invalidation
Co-Authored-By: Andreas Kling <kling@serenityos.org>
This allows us to figure out where a specific CSS property comes from,
which is going to be used in a future commit to uniquely identify
running animations.
Specifically, stop letting NumericStyleValues holding `0` from
pretending to hold a Length. The parser is now smart enough that we
don't have to do this. :^)
Introduces incomplete parsing of grid shorthand property. Only
<grid-template> part of syntax is supported for now but it is enough
to significantly improve rendering of websites that use this shorthand
to define grid :)
If CSS requests a font that we have loaded, but we didn't associate it
with a specific weight and/or slope, let's still use it if it matches
the family name.
This is a hack until we implement proper CSS font selection.
This fixes a plethora of rounding problems on many websites.
In the future, we may want to replace this with fixed-point arithmetic
(bug #18566) for performance (and consistency with other engines),
but in the meantime this makes the web look a bit better. :^)
There's a lot more things that could be converted to doubles, which
would reduce the amount of casting necessary in this patch.
We can do that incrementally, however.
SVG presentation attributes are parsed as CSS values, so we also need to
handle CSS variable expansion when handling them.
This (roughly) matches the behavior of other engines. It's also used on
the web, for example on https://stripe.com/ :^)
The resolved property sets are stored with the element in a
per-pseudo-element array (same as for pseudo element layout nodes).
Longer term, we should stop storing this with elements entirely and make
it temporary state in StyleComputer somehow, so we don't waste memory
keeping all the resolved properties around.
This makes various gradients show up on https://shopify.com/ :^)
The root element font metrics were getting queried again and again
during style computation. Before this change we would do some work to
recalculate them each time.
This patch simply caches them in a StyleComputer member. Since style
updates always start with the root element, we know that it'll be
up-to-date by the time we look at any other element.
Before this change, we were spending ~5% of CPU time on Google Groups
in root_element_font_metrics().
This necessitated returning `nullptr` instead of just `{}` in a lot of
places. Also, some temporary hackiness in `parse_css_value()`: That
returns a special `ParseError` type already, so we now have a
`FIXME_TRY()` macro which logs the error and then returns a generic
`ParseError::InternalError` value. Eventually this macro will go away,
once I figure out how to deal with this more nicely.
In particular, we now blockify layout internal boxes (e.g table parts)
by turning them into `block flow`. This fixes a crash when viewing
our GitHub repo :^)
The Display class already supported all specific values, and now they
will be parsed too. The display property now has a special type
DisplayStyleValue.
Rather than passing an increasingly-unwieldy number of font parameters
individually to every function that resolves lengths, let's wrap them
up.
This is frustratingly close to being `Gfx::FontPixelMetrics`, but bitmap
fonts cause issues: We choose the closest font to what the CSS
requests, but that might have a wildly different size than what the
page expects, so we have to fudge the numbers.
No behaviour changes.
When deciding on a box type transformation (blockify/inlinify) for a
pseudo element, we have to use the originating element as a reference
rather than the parent.
(The originating element *is* the parent for its pseudo elements.)
This fixes multi-layer backgrounds with background positions. This
is a little awkard, so maybe it would be better to refactor the
parsing code to make these lists directly, but right now this is
the simplest fix.
This parses the new background-position-x/y longhands and properly
hooks up them up. This requires converting PositionStyleValue to
just contain two EdgeStyleValues so that it can be easily expanded
into the longhands.