Relative font-sizes like "2em" were previously resolved against the
fallback value (10px) which led to incorrect layouts in many places.
Fix this by resolving relative font-sizes against the absolutized
font-size of the parent or root element as appropriate.
Let's make it very clear that these are *computed* values, and not at
all the specified values. The specified values are currently discarded
by the CSS cascade algorithm.
Get rid of the old, roundabout way of invalidating the rule cache by
incrementing the StyleSheetList "generation".
Instead, when something wants to invalidate the rule cache, just have it
directly invalidate the rule cache. This makes it much easier to see
what's happening anyway.
Style computation always happens *before* layout, so we can't rely on
things having (or not having) layout nodes, as that information will
always be one step behind.
Instead, we have to use the DOM to find all the information we need.
Previously we were making a copy of the full set of custom properties
that applied to a DOM element. This was very costly and dominated the
profile when mousing around on GitHub.
Note that this may break custom properties on pseudo elements a little
bit, and that's something we'll have to look into.
Previously this queried the root layout-node's font, which was both
wrong and could crash if the layout wasn't ready yet. Now, it's just
wrong. But at least all the font-related wrongness is grouped together
in StyleComputer. :^)
Build the final custom property map right away instead of first making
a temporary pointer-only map. We also precompute the final needed
capacity for the map to avoid incremental rehashing.
Let's have one function that determines the type of transformation
needed, and another to actually perform the transformation.
This makes it much easier to read, and we don't have to duplicate the
logic for doing the transformation.
Instead of awkwardly visiting and mutating lengths inside StyleValues,
we now simply create a new StyleValue instead.
This fixes an issue where inherited relative lengths could get
absolutized using a parent as reference, and then not having the correct
values when used in a child context.
Use the new Gfx::Font::AllowInexactSizeMatch parameter when doing CSS
font lookups. This fixes a long-standing issue where text with e.g text
with "font-size:12px" would be larger than "font-size:13px" since there
was an exact match for 12, but none for 13 (so we'd fall back to 10).
This works a little differently from the other caches - ALL rules
containing a pseudo-element are in this bucket. This lets us only look
at this bucket when finding styles for a pseudo-element, and ignore it
if we're not.
Since each selector can only have zero or one pseudo-element, we match
against it as a separate step, before matching the rest of the
selector. This should be faster, but mostly I did this because I could
not figure out how else to stop selectors without a pseudo-element from
matching the pseudo-element, eg so `.foo` styles don't affect
`.foo::before`.
"5em" means 5*font-size, but by forcing "em" to mean the presentation
size of the bitmap font actually used, we broke a bunch of layouts that
depended on a correct interpretation of "em".
This means that "em" units will no longer be relative to the exact
size of the bitmap font in use, but I think that's a compromise we'll
have to make, since accurate layouts are more important.
This yields a visual progression on both ACID2 and ACID3. :^)
The ICB (initial containing block) gets its style from StyleComputer's
create_document_style(). It's basically a generic style for the root of
the layout tree.
With this patch, we now assign the width and height of the viewport rect
as two CSS "px" lengths to the "width" and "height" properties of the
ICB style. (Previously they were just defaulting to "auto" and we
assigned override dimensions during layout.)
This fixes an issue where position:absolute elements with relative width
and/or height were not dimensioned correctly, since the values were
relative to the width and/or height of the ICB style.
After style computation, every StyleProperties has a value for every
PropertyID. Given this, it's simpler, faster and less memory-heavy to
use an Array instead of a HashMap. :^)
This patch introduces the StyleComputer::RuleCache, which divides all of
our (author) CSS rules into buckets.
Currently, there are two buckets:
- Rules where a specific class must be present.
- All other rules.
This allows us to check a significantly smaller set of rules for each
element, since we can skip over any rule that requires a class attribute
not present on the element.
This takes the typical numer of rules tested per element on Discord from
~16000 to ~550. :^)
We can definitely improve the cache invalidation. It currently happens
too often due to media queries. And we also need to make sure we
invalidate when mutating style through CSSOM APIs.
Previously we would re-run the entire CSS selector machinery for each
property resolved. Instead of doing that, we now resolve a final set of
custom property key/value pairs at the start of the cascade.
- Replace "auto" with "auto const" where appropriate.
- Remove an unused struct.
- Make sort_matching_rules() a file-local static function.
- Remove some unnecessary includes.
Modified the test-page because FontDatabase looks for exact font-weight
matches, so requesting weight 800 in a font that only has 700, causes
it to return the default font instead. So, we ask for 700 here.
The actual fix is to improve our font-matching but I am trying not to
get distracted today. :^)
CSS has rules about automatic blockification or inlinification of boxes
in certain circumstances.
This patch implements automatic blockification of absolutely positioned
and floating elements. This makes the smile appear on ACID2. :^)
We now detect situations like this, where variables infinitely recur,
without crashing:
```css
div {
--a: var(--b);
--b: var(--a);
background: var(--a);
}
p {
--foo: var(--foo);
background: var(--foo);
}
```
We now stop processing variables once a length of 16384 tokens is
reached. This is an arbitrary number, but should be far beyond what
anyone will reasonably use, and small enough to not crash.
If a property is custom or contains a `var()` reference, it cannot be
parsed into a proper StyleValue immediately, so we store it as an
UnresolvedStyleValue until the property is compute. Then, at compute
time, we resolve them by expanding out any `var()` references, and
parsing the result.
The implementation here is very naive, and involves copying the
UnresolvedStyleValue's tree of StyleComponentValueRules while copying
the contents of any `var()`s it finds along the way. This is quite an
expensive operation to do every time that the style is computed.