Previously, FontFace objects created via the JS and added to
`document.fonts` were stored in the FontFaceSet but never participated
in font matching during style resolution. We now store both
CSS-connected and JS-created font faces in a unified map on
`FontComputer`, keyed by family name, and include them all as
candidates in the font matching algorithm.
Some at-rules (i.e. `@function`) require us to support custom
descriptors (e.g. `--foo`).
We do this by adding `DescriptorID::Custom` and using a new
`DescriptorNameAndID` class in a bunch of places where we previously
just used `DescriptorID`
Filter out unsupported @font-face sources (e.g. .eot files, or sources
with an explicit unsupported format() hint) when populating the
FontFace's URL list, rather than fetching and attempting to decode them.
This matches the behavior of Blink and WebKit, which both reject .eot
URLs by filename when no format() hint is present, to avoid conflicts
with old WinIE-style @font-face rules.
Previously, we would fetch .eot files over the network, fail to decode
them, and then reject the font load promise, leading to a flood of
"NetworkError: Failed to load font" messages in the console.
As FontFaces are added or removed from a FontFaceSet, and as they load
or fail, the FontFaceSet moves them between a few different lists, and
updates its loading/loaded status. In the spec, this is how the
FontFaceSet.[[ReadyPromise]] gets fulfilled: When the document has
finished loading and FontFaceSet.[[LoadingFonts]] is empty, it resolves
the promise.
To support this, FontFace now keeps a set of FontFaceSets that it is
contained in.
This lets us remove the non-spec resolve_ready_promise() call in
EventLoop which was sometimes triggering before any fonts had attempted
to load.
As noted, there's a spec issue with the ready promise: If nothing
modifies the document's fonts, then it would never resolve. My ad-hoc
fix is to also switch the FontFaceSet to the loaded state if it is
empty, which appears to solve the issues but is not ideal.
The spec requires us to follow the steps in FontFace::load() whenever a
font is loaded. The simplest way to do so, is to make that the only way
we load fonts. :^)
To support this, FontFace::load() uses its connected CSSFontFaceRule's
ParsedFontFace if it's available.
The 1 regression in generic-family-keywords-003.html seems to be a false
positive: we don't support the system-ui font keyword.
Remove 11 heavy includes from Document.h that were only needed for
pointer/reference types (already forward-declared in Forward.h), and
extract the nested ViewportClient interface to a standalone header.
This reduces Document.h's recompilation cascade from ~1228 files to
~717 files (42% reduction). Headers like BrowsingContext.h that were
previously transitively included see even larger improvements (from
~1228 down to ~73 dependents).
Previously we would just set the attributes to the serialized
descriptors, even if they were the empty string.
We now apply defaults when we have empty descriptors and apply parsing
logic from the various `set_*` methods (only applicable to `font-family`
so far where we now extract the value from either a string or a
custom-ident)
Fixes an issue in some css/css-shapes WPT tests where we weren't
properly matching fonts.
Previously we would always try to load the font URL relative to the
document's base URL. This commit means that for CSS-connected
`FontFace`s we now try to load relative to the URL of the stylesheet
that contains the associated `CSSFontFaceRule`
The spec states that updates to descriptors in a `@font-face` rule
should be reflected in the connected `FontFace`'s attributes.
Previously this was achieved by directly accessing those descriptors
when calling the attribute getters, but this has a couple of issues:
a) The changes are only reflected if we use the accessors (i.e.
`FontFace::family()` rather than `FontFace::m_family`) which isn't
the case everywhere
b) The changes aren't persisted after the `FontFace` is disconnected
from it's `CSSFontFaceRule`
To fix these issues we now reparse and store the `FontFace`'s attributes
whenever the `CSSFontFaceRule`'s descriptors change.
Font computation and loading is distinct enough from style computation
that it makes more sense to have this in it's own class.
This will be useful later when we move the font loading process to
`ComputedProperties` in order to respect animated values.
This reverts 0e3487b9ab.
Back when I made that change, I thought we could make our StyleValue
classes match the typed-om definitions directly. However, they have
different requirements. Typed-om types need to be mutable and GCed,
whereas StyleValues are immutable and ideally wouldn't require a JS VM.
While I was already making such a cataclysmic change, I've moved it into
the StyleValues directory, because it *not* being there has bothered me
for a long time. 😅
This allows them to keep style sheets alive while loading fonts for
them. Fixes some GC crashes seen on the WPT WOFF2 tests after
66a19b8550 stopped FetchRecord leaks from
keeping various other things alive.
Based very scientifically on what's listed here:
https://harfbuzz.github.io/what-does-harfbuzz-do.html
I've moved the code into LibGfx because including a HarfBuzz header
directly from LibWeb is a little unpleasant. But the Gfx::FontTech enum
follows the CSS definitions for font features for simplicity.
TrueType collections are supported. SVG and Embedded OpenType are not,
but they're not widely supported by other browsers so that's fine.
Most of the features are completely supported by HarfBuzz, so we can
just return true. Graphite support is optional (and it appears we use a
build of HarfBuzz without it) but there's a define we can check.
Incremental Font Transfer is a whole separate thing that we definitely
don't support yet.
ParsedFontFace and FontLoader now both keep track of which
CSSStyleSheet (if any) was the source of the font-face, so the URLs can
be completed correctly.
Convert FontLoader to use fetch_a_style_resource(). ResourceLoader used
to keep its downloaded data around for us, but fetch doesn't, so we use
Gfx::Typeface::try_load_from_temporary_memory() so that the font has a
permanent copy of that data.
Typeface::try_load_from_externally_owned_memory() relies on that
external owner keeping the memory around. However, neither WOFF nor
WOFF2 do so - they both create separate ByteBuffers to hold the TTF
data. So, rename them to make it clearer that they don't have any
requirements on the byte owner.
Before this change, we were going through the chain of base classes for
each IDL interface object and having them set the prototype to their
prototype.
Instead of doing that, reorder things so that we set the right prototype
immediately in Foo::initialize(), and then don't bother in all the base
class overrides.
This knocks off a ~1% profile item on Speedometer 3.
This also rearranges the code to follow the spec better: We create an
empty FontFace first and then fill it in, instead of creating it
fully-formed at the end.
Both `@supports` and `@font-face` need this. There may be some automatic
way of querying whether our renderer supports these, but I couldn't
figure it out, so here's a basic hard-coded list. I think the font-tech
list has false negatives, as I don't know enough about fonts to
determine what we support accurately.
This is not really a context, but more of a set of parameters for
creating a Parser. So, treat it as such: Rename it to ParsingParams,
and store its values and methods directly in the Parser instead of
keeping the ParsingContext around.
This has a nice side-effect of not including DOM/Document.h everywhere
that needs a Parser.
Resulting in a massive rename across almost everywhere! Alongside the
namespace change, we now have the following names:
* JS::NonnullGCPtr -> GC::Ref
* JS::GCPtr -> GC::Ptr
* JS::HeapFunction -> GC::Function
* JS::CellImpl -> GC::Cell
* JS::Handle -> GC::Root
The main motivation behind this is to remove JS specifics of the Realm
from the implementation of the Heap.
As a side effect of this change, this is a bit nicer to read than the
previous approach, and in my opinion, also makes it a little more clear
that this method is specific to a JavaScript Realm.