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.
Due to CSSImportRule::has_import_result() being backwards, we never
actually entered imported style sheets when traversing style rules or
media queries.
With this fixed, we no longer need the "collect style sheets" step in
StyleComputer, as normal for_each_effective_style_rule() will now
actually find all the rules. :^)
We don't support all parts of the font formats we assume as "supported"
in the CSS parser. For example, if an open type font has a CFF table, we
reject loading it. This meant that until now, when such an
unsupported-supported font url was first in the list of urls, we
couldn't load it at all, even when we would support a later url.
To resolve that, try loading all font urls one after each other, in case
we are not able to load the higher priority one.
This also resolves a FIXME related to spec compliant url prioritization.
Our CSS parser already filters and prioritizes font src urls in
compliance with the spec. However, we still had to resort to brittle
file extension matching, because some websites don't set the `format`
and if the first url in a src list happened to be one we don't support,
the font could not be loaded at all. This now is unnecessary because we
can try and discard the urls instead.
It is not sufficient to just invalidate layout when a new font has
loaded, because while it was loading we might have chosen a fallback
font-family value instead.
Invalidate style instead.
Before this patch, we would build full computed style for these pseudo
elements, for every DOM element, even if no ::before/::after selector
actually matched.
This was a colossal waste of time, and we can also just not do that.
Instead, just abort pseudo element style resolution early if no relevant
selectors matched. :^)
Percentage line-height values are relative to 1em (i.e the font-size
of the element). We have to resolve their computed values before
proceeding with inheritance.
Use FlyString::from_deprecated_fly_string() in these instances instead
of FlyString::from_utf8(). As we convert to new FlyString/String we want
to be aware of these potential unnecessary allocations.
Instead of putting every rule that matches a pseudo element in the
same bucket, let them go in the best ID/class/tag name bucket instead.
Then, add a flag to MatchingRule that says whether it contains a
pseudo element in the rightmost compound selector.
When deciding which selectors to run for an element, we can now simply
filter in/out pseudo element selectors as appropriate depending on what
we're trying to match.
This fixes an issue where pages using Font Awesome had 1700+ rules in the
pseudo-element rule cache. (This meant all those rules had to run
against every element twice or more while instantiating pseudo elements.)
We were already sorting the author style selectors into buckets.
Now we do it for the built-in UA style as well.
This means less work for the selector engine everywhere :^)
This relied on pulling the current realm from the main thread VM, which
requires an execution context to be on the VM's stack. This heavily
relied on the dummy execution context that is always on the stack, for
example, when parsing the UA style sheets where no JavaScript is
running.
This class had slightly confusing semantics and the added weirdness
doesn't seem worth it just so we can say "." instead of "->" when
iterating over a vector of NNRPs.
This patch replaces NonnullRefPtrVector<T> with Vector<NNRP<T>>.
DeprecatedFlyString relies heavily on DeprecatedString's StringImpl, so
let's rename it to A) match the name of DeprecatedString, B) write a new
FlyString class that is tied to String.
Previously when resolving an attr or var-defined property
with a 'not-set' value like this `property: var(--ValueNotSet)`,
we left the property unchanged (as an unresolved) and
added it to the computed-style of the element.
We still don't change the property but rather we now also don't set
unresolved properties in the computed-style.
This is an intended behavior.
The specification suggests that, on resolving an attr or var property
(custom properties) we have an invalid property when neither the
variable inside the var, nor the backup value could be resolved.
An invalid property must be inherited or defaulted depending on it's
type. We already do this with every 'untouched'
(as in m_property_values contains no entry for it) value.
So not setting the property results in an inherited (or initial)
value by a later-called function.
This also fixes another problem, where
`text-decoration: var(--NotSet)`
wouldn't be inherited because the computed-style of the
parent element hasn't set `text-decoration` but rather
all it's long-versions like `text-decoration-line` and so on.
This will make it easier to support both string types at the same time
while we convert code, and tracking down remaining uses.
One big exception is Value::to_string() in LibJS, where the name is
dictated by the ToString AO.
We have a new, improved string type coming up in AK (OOM aware, no null
state), and while it's going to use UTF-8, the name UTF8String is a
mouthful - so let's free up the String name by renaming the existing
class.
Making the old one have an annoying name will hopefully also help with
quick adoption :^)
When mixing calc() and var(), we're forced to delay resolving them until
we're in StyleComputer. Previously we'd just skip over them.
This patch handles calc() in the same pass as attr(). We reparse the
calc() value after var() expansion, and then try to resolve it to a
constant value if possible. If it's not possible, we leave the calc()
where it is, and maybe layout can figure it out later.
Note that I've only implemented resolution to integer and percentage in
this commit. There are more things a calc() could resolve to, and we
should implement those as well.
We always create a Layout::InitialContainingBlock for the ICB, but in a
future where we always honor the CSS::Display everywhere, we need to
make sure everyone has the right display values.
URL had properly named replacements for protocol(), set_protocol() and
create_with_file_protocol() already. This patch removes these function
and updates all call sites to use the functions named according to the
specification.
See https://url.spec.whatwg.org/#concept-url-scheme
Instead of asking Gfx::FontDatabase for the "default font" and the
"default fixed-width font", we now proxy those requests out via
the Platform::FontPlugin. This will allow Ladybird to use other default
fonts as fallback.
This patch improves @font-face loading when there are multiple src
values in two ways:
- Invalid/empty URLs are ignored
- Fonts with unsupported file extensions are ignored
This makes us load and display the emblem font on modern Reddit,
which is pretty neat! :^)
Let's make 16px the default font size instead of 10px. This makes our
layout results match those of other engines in many more cases.
Also make the h1-h6 element styles use relative (em) font sizes, also
matching other browsers.
Instead of hard-coding the names of system fonts to use for the CSS
generic fonts (like "sans-serif", "monospace", etc.) we now call out
to a Platform::FontPlugin and ask for the generic names.