fonts: Make FontKey and FontInstanceKey generation asynchronous (#33600)

Instead of a blocking a layout thread on the generation of WebRender
`FontKey`s and `FontInstanceKey`s, generate the keys ahead of time and
send the font data to WebRender asynchronously. This has the benefit of
allowing use of the font much more quickly in layout, though blocking
display list sending itself on the font data upload.

In order to make this work for web fonts, `FontContext` now asks the
`SystemFontService` for a `FontKey`s and `FontInstanceKey`s for new web
fonts. This should happen much more quickly as the `SystemFontService`
is only blocking in order to load system fonts into memory now. In
practice this still drops layout thread blocking to fractions of a
millisecond instead of multiple milliseconds as before.

In addition, ensure that we don't send font data or generate keys for
fonts that are used in layout but never added to display lists. This
should help to reduce memory usage and increase performance.

Performance of this change was verified by putting a microbenchmark
around `FontContext::create_font` which is what triggered font key
generation.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2024-10-01 17:31:26 +02:00 committed by GitHub
parent 05ecb8eddb
commit abad89a49c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 302 additions and 216 deletions

View file

@ -5,7 +5,6 @@
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, OnceLock};
use app_units::Au;
use atomic_refcell::AtomicRefCell;
use ipc_channel::ipc::IpcSharedMemory;
use log::warn;
@ -13,13 +12,11 @@ use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use style::stylesheets::DocumentStyleSheet;
use style::values::computed::{FontStyle, FontWeight};
use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey};
use crate::font::FontDescriptor;
use crate::font_context::WebFontDownloadState;
use crate::font_template::{FontTemplate, FontTemplateRef, FontTemplateRefMethods, IsOblique};
use crate::system_font_service::{FontIdentifier, LowercaseFontFamilyName};
use crate::FontContext;
/// A data structure to store data for fonts. If sent across IPC channels and only a
/// [`IpcSharedMemory`] handle is sent, avoiding the overhead of serialization and
@ -186,84 +183,6 @@ impl FontStore {
}
}
#[derive(Default)]
pub struct WebRenderFontStore {
pub(crate) webrender_font_key_map: HashMap<FontIdentifier, FontKey>,
pub(crate) webrender_font_instance_map: HashMap<(FontKey, Au), FontInstanceKey>,
}
pub(crate) type CrossThreadWebRenderFontStore = Arc<RwLock<WebRenderFontStore>>;
impl WebRenderFontStore {
pub(crate) fn get_font_instance(
&mut self,
font_context: &FontContext,
font_template: FontTemplateRef,
pt_size: Au,
flags: FontInstanceFlags,
) -> FontInstanceKey {
let webrender_font_key_map = &mut self.webrender_font_key_map;
let identifier = font_template.identifier().clone();
let font_key = *webrender_font_key_map
.entry(identifier.clone())
.or_insert_with(|| {
let data = font_context.get_font_data(&identifier);
font_context.get_web_font(data, identifier.index())
});
*self
.webrender_font_instance_map
.entry((font_key, pt_size))
.or_insert_with(|| {
font_context.get_web_font_instance(font_key, pt_size.to_f32_px(), flags)
})
}
pub(crate) fn remove_all_fonts(&mut self) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
(
self.webrender_font_key_map
.drain()
.map(|(_, key)| key)
.collect(),
self.webrender_font_instance_map
.drain()
.map(|(_, key)| key)
.collect(),
)
}
pub(crate) fn remove_all_fonts_for_identifiers(
&mut self,
identifiers: &HashSet<FontIdentifier>,
) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
let mut removed_keys: HashSet<FontKey> = HashSet::new();
self.webrender_font_key_map.retain(|identifier, font_key| {
if identifiers.contains(identifier) {
removed_keys.insert(*font_key);
false
} else {
true
}
});
let mut removed_instance_keys: HashSet<FontInstanceKey> = HashSet::new();
self.webrender_font_instance_map
.retain(|(font_key, _), instance_key| {
if removed_keys.contains(font_key) {
removed_instance_keys.insert(*instance_key);
false
} else {
true
}
});
(
removed_keys.into_iter().collect(),
removed_instance_keys.into_iter().collect(),
)
}
}
/// A struct that represents the available templates in a "simple family." A simple family
/// is one that contains <= 4 available faces: regular, bold, italic, and bold italic. Having
/// this simple family abstraction makes font matching much faster for families that don't