The `FontContextHandle` was really only used on FreeType platforms to
store the `FT_Library` handle to use for creating faces. Each
`FontContext` and `FontCacheThread` would create its own
`FontContextHandle`. This change removes this data structure in favor of
a mutex-protected shared `FontContextHandle` for an entire Servo
process. The handle is initialized using a `OnceLock` to ensure that it
only happens once and also that it stays alive for the entire process
lifetime.
In addition to greatly simplifying the code, this will make it possible
for different threads to share platform-specific `FontHandle`s, avoiding
multiple allocations for a single font.
The only downside to all of this is that memory usage of FreeType fonts
isn't measured (though the mechanism is still there). This is because
the `FontCacheThread` currently doesn't do any memory measurement.
Eventually this *will* happen though, during the font system redesign.
In exchange, this should reduce the memory usage since there is only a
single FreeType library loaded into memory now.
This is part of #32033.
This change also makes two fixes that are necessary to get WOFF2 fonts
working:
1. It adds support for loading web fonts from stylesheets included via
@import rules.
2. It ensure that when web fonts are loaded synchronusly they invalidate
the font cache. This led to incorrect font rendering when running
tests before.
Fixes#31598.
Instead of using a simple `Atom` to identify a local font, use a data
structure. This allows us to carry more information necessary to
identify a local font (such as a path on MacOS). We need this for the
new version of WebRender, as fonts on MacOS now require a path.
This has a lot of benefits:
1. We can avoid loading fonts without paths on MacOS, which should
avoid a lot of problems with flakiness and ensure we always load the
same font for a given identifier.
2. This clarifies the difference between web fonts and local fonts,
though there is more work to do here.
3. This avoid a *lot* of font shenanigans, such as trying to work
backwards from the name of the font to the path of the font we
actually matched. In general, we can remove a lot of code trying to
accomplish these shenanigans.
4. Getting the font bytes always returns an `Arc` now avoiding an extra
full font copy in the case of Canvas.
Instead of letting Stylo filter `@font-face` rules, handle this
filtering in Servo. It doesn't make sense that Stylo knows about what
fonts Servo supports. This also cleans up a bit the way that this is
handled, giving an entire stylesheet of rules to the font cache to
process instead of letting each layout thread walk the rules. This
brings more of the font-related code into the FontCacheThread itself.
This is the first step toward adding WOFF2 support and fixing various
web font related bugs.
* clippy: fix warnings in components/gfx
* refactor: switched the order of impl so that its intent is clearer
* fix: add font context default in other platforms
In order for stylo to be a separate crate, it needs to depend on less
things from Servo. This change makes it so that stylo no longer depends
on servo_url.
The Linux kernel imposes a 15-byte limit on thread names[1]. This means
information that does not fit in this limit, e.g., the pipeline ID of
layout and script threads, is lost in a debugger and profiler (see the
first column of the table below).
This commit shortens the thread names used in Servo to maximize the
amount of information conveyed. It also rectifies some inconsistencies
in the names.
| Before | After |
|-------------------|-------------------|
| `BluetoothThread` | `Bluetooth` |
| `CanvasThread` | `Canvas` |
| `display alert d` | `AlertDialog` |
| `FontCacheThread` | `FontCache` |
| `GLPlayerThread` | `GLPlayer` |
| `HTML Parser` | `Parse:www.examp` |
| `LayoutThread Pi` | `Layout(1,1)` |
| `Memory profiler` | `MemoryProfiler` |
| `Memory profiler` | `MemoryProfTimer` |
| `OfflineAudioCon` | `OfflineACResolv` |
| `PullTimelineMar` | `PullTimelineDat` |
| `ScriptThread Pi` | `Script(1,1)` |
| `WebWorker for h` | `WW:www.example.` |
| `ServiceWorker f` | `SW:www.example.` |
| `ServiceWorkerMa` | `SvcWorkerManage` |
| `Time profiler t` | `TimeProfTimer` |
| `Time profiler` | `TimeProfiler` |
| `WebGL thread` | `WebGL` |
| `Choose a device` | `DevicePicker` |
| `Pick a file` | `FilePicker` |
| `Pick files` | `FilePicker` |
[1]: https://stackoverflow.com/questions/5026531/thread-name-longer-than-15-chars
Before this change, if we needed to create a Font which we've already
created, but at a new size, then we'd fetch the FontTemplateInfo again.
If the bytes of the font are held in memory, then this could be
expensive as we need to pass those bytes over IPC.
Prior to this change, if none of the fonts specified in CSS contained a
glyph for a codepoint, we tried only one fallback font. If that font
didn't contain the glyph, we'd give up.
With this change, we try multiple fonts in turn. The font names we try
differ across each platform, and based on the codepoint we're trying to
match. The current implementation is heavily inspired by the analogous
code in Gecko, but I've used to ucd lib to make it more readable,
whereas Gecko matches raw unicode ranges.
This fixes some of the issues reported in #17267, although colour emoji
support is not implemented.
== Notes on changes to WPT metadata ==
=== css/css-text/i18n/css3-text-line-break-opclns-* ===
A bunch of these have started failing on macos when they previously
passed.
These tests check that the browser automatically inserts line breaks
near certain characters that are classified as "opening and closing
punctuation". The idea is that if we have e.g. an opening parenthesis,
it does not make sense for it to appear at the end of a line box; it
should "stick" to the next character and go into the next line box.
Before this change, a lot of these codepoints rendered as a missing
glyph on Mac and Linux. In some cases, that meant that the test was
passing.
After this change, a bunch of these codepoints are now rendering glyphs
on Mac (but not Linux). In some cases, the test should continue to pass
where it previously did when rendering with the missing glyph.
However, it seems this has also exposed a layout bug. The "ref" div in
these tests contains a <br> element, and it seems that this, combined
with these punctuation characters, makes the spacing between glyphs ever
so slightly different to the "test" div. (Speculation: might be
something to do with shaping?)
Therefore I've had to mark a bunch of these tests failing on mac.
=== css/css-text/i18n/css3-text-line-break-baspglwj-* ===
Some of these previously passed on Mac due to a missing glyph. Now that
we're rendering the correct glyph, they are failing.
=== css/css-text/word-break/word-break-normal-bo-000.html ===
The characters now render correctly on Mac, and the test is passing. But
we do not find a suitable fallback font on Linux, so it is still failing
on that platform.
=== css/css-text/word-break/word-break-break-all-007.html ===
This was previously passing on Mac, but only because missing character
glyphs were rendered. Now that a fallback font is able to be found, it
(correctly) fails.
=== mozilla/tests/css/font_fallback_* ===
These are new tests added in this commit. 01 and 02 are marked failing
on Linux because the builders don't have the appropriate fonts installed
(that will be a follow-up).
Fix build errors from rebase
FontTemplateDescriptor can no longer just derive(Hash). We need to
implement it on each component part, because the components now
generally wrap floats, which do not impl Hash because of NaN. However in
this case we know that we won't have a NaN, so it is safe to manually
impl Hash.
Unfortunately, this required quite a bit of changes to the non-test
code. That's because FontContext depends on a FontCacheThread, which in
turn depends on a CoreResourceThread and therefore lots of other data
structures.
It seemed like it would be very difficult to instantiate a FontContext
as it was, and even if we could it seems like overkill to have all these
data structures present for a relatively focused test.
Therefore, I created a FontSource trait which represents the interface
which FontContext uses to talk to FontCacheThread. FontCacheThread then
implements FontSource. Then, in the test, we can create a dummy
implementation of FontSource rather than using FontCacheThread.
This actually has the advantage that we can make our dummy
implementation behave in certain specific way which are useful for
testing, for example it can count the number of times
find_font_template() is called, which helps us verify that
caching/lazy-loading is working as intended.
WR now has a concept of font templates and font instances. This
makes the WR font interfaces closer to Cairo and Gecko, and also
makes some future performance optimizations possible.
A font template is the font family, and data backing the font.
A font instance is a reference to a font template and per-instance
options, such as font size, anti-aliasing settings etc.
To update Servo in a minimally invasive way, I added a new font
cache call, that creates a font instance. This means that when
a font is created, and doesn't exist in the cache there are now
two calls to the font cache thread. We could refactor the font
cache to make this work in one call, which we should do in the
future. However, refactoring the font cache is a large chunk of
work by itself. The extra call is only when a font doesn't already
exist in the font context cache, so it should have minimal
performance impact.
Properly set origin of fetch requests
<!-- Please describe your changes on the following line: -->
These changes aim to fix#15247
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix#15247 (github issue number if applicable).
<!-- Either: -->
- [ ] There are tests for these changes
- [x] These changes do not require tests because cors is already tested with different origins
These changes require changes in tests, but I need help with that (see comments below).
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16508)
<!-- Reviewable:end -->