aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2024-09-26 15:44:23 +0200
committerMartin Robinson <mrobinson@igalia.com>2024-10-01 16:25:51 +0200
commitd521f5724cbaab420eba78732b8dab486c45a75a (patch)
tree4ab3ff8a4a40c095af7bdf44b6da2b85fa44dcd7
parent5ee8e2e55b9726015b0cd3d21f4f4f9b084a5b67 (diff)
downloadservo-fonts-fast-ipc-turnaround.tar.gz
servo-fonts-fast-ipc-turnaround.zip
fonts: Make `FontKey` and `FontInstanceKey` generation asynchronousfonts-fast-ipc-turnaround
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>
-rw-r--r--components/compositing/compositor.rs78
-rw-r--r--components/fonts/font.rs14
-rw-r--r--components/fonts/font_context.rs164
-rw-r--r--components/fonts/font_store.rs81
-rw-r--r--components/fonts/system_font_service.rs88
-rw-r--r--components/fonts/tests/font_context.rs6
-rw-r--r--components/layout/text.rs2
-rw-r--r--components/layout/text_run.rs3
-rw-r--r--components/layout_2020/flow/inline/mod.rs7
-rw-r--r--components/layout_2020/flow/inline/text_run.rs31
-rw-r--r--components/servo/lib.rs36
-rw-r--r--components/shared/webrender/lib.rs23
12 files changed, 317 insertions, 216 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index 4271efd75a8..e98303bc015 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -844,20 +844,20 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
},
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::AddFont(
+ font_key,
data,
index,
- key_sender,
)) => {
- let _ = key_sender.send(self.add_font(index, data));
+ self.add_font(font_key, index, data);
},
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::AddFontInstance(
+ font_instance_key,
font_key,
size,
flags,
- sender,
)) => {
- let _ = sender.send(self.add_font_instance(font_key, size, flags));
+ self.add_font_instance(font_instance_key, font_key, size, flags);
},
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::RemoveFonts(
@@ -884,33 +884,45 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, txn);
},
+ ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::GenerateKeys(
+ number_of_font_keys,
+ number_of_font_instance_keys,
+ result_sender,
+ )) => {
+ let font_keys = (0..number_of_font_keys)
+ .map(|_| self.webrender_api.generate_font_key())
+ .collect();
+ let font_instance_keys = (0..number_of_font_instance_keys)
+ .map(|_| self.webrender_api.generate_font_instance_key())
+ .collect();
+ let _ = result_sender.send((font_keys, font_instance_keys));
+ },
+
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFontInstance(
+ font_instance_key,
font_key,
size,
flags,
- sender,
)) => {
- let _ = sender.send(self.add_font_instance(font_key, size, flags));
+ self.add_font_instance(font_instance_key, font_key, size, flags);
},
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFont(
- key_sender,
+ font_key,
index,
data,
)) => {
- let _ = key_sender.send(self.add_font(index, data));
+ self.add_font(font_key, index, data);
},
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddSystemFont(
- key_sender,
+ font_key,
native_handle,
)) => {
- let font_key = self.webrender_api.generate_font_key();
let mut transaction = Transaction::new();
transaction.add_native_font(font_key, native_handle);
self.webrender_api
.send_transaction(self.webrender_document, transaction);
- let _ = key_sender.send(font_key);
},
ForwardedToCompositorMsg::Canvas(CanvasToCompositorMsg::GenerateKey(sender)) => {
@@ -956,31 +968,26 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.remove_pipeline_root_layer(pipeline_id);
let _ = sender.send(());
},
- CompositorMsg::Forwarded(ForwardedToCompositorMsg::SystemFontService(
- FontToCompositorMsg::AddFontInstance(_, _, _, sender),
- )) => {
- let _ = sender.send(self.webrender_api.generate_font_instance_key());
- },
- CompositorMsg::Forwarded(ForwardedToCompositorMsg::Layout(
- ScriptToCompositorMsg::AddFontInstance(_, _, _, sender),
- )) => {
- let _ = sender.send(self.webrender_api.generate_font_instance_key());
- },
- CompositorMsg::Forwarded(ForwardedToCompositorMsg::SystemFontService(
- FontToCompositorMsg::AddFont(sender, _, _),
- )) => {
- let _ = sender.send(self.webrender_api.generate_font_key());
- },
- CompositorMsg::Forwarded(ForwardedToCompositorMsg::Layout(
- ScriptToCompositorMsg::AddFont(_, _, sender),
- )) => {
- let _ = sender.send(self.webrender_api.generate_font_key());
- },
CompositorMsg::Forwarded(ForwardedToCompositorMsg::Canvas(
CanvasToCompositorMsg::GenerateKey(sender),
)) => {
let _ = sender.send(self.webrender_api.generate_image_key());
},
+ CompositorMsg::Forwarded(ForwardedToCompositorMsg::SystemFontService(
+ FontToCompositorMsg::GenerateKeys(
+ number_of_font_keys,
+ number_of_font_instance_keys,
+ result_sender,
+ ),
+ )) => {
+ let font_keys = (0..number_of_font_keys)
+ .map(|_| self.webrender_api.generate_font_key())
+ .collect();
+ let font_instance_keys = (0..number_of_font_instance_keys)
+ .map(|_| self.webrender_api.generate_font_instance_key())
+ .collect();
+ let _ = result_sender.send((font_keys, font_instance_keys));
+ },
CompositorMsg::GetClientWindow(sender) => {
if let Err(e) = sender.send(self.embedder_coordinates.window) {
warn!("Sending response to get client window failed ({:?}).", e);
@@ -2527,11 +2534,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
fn add_font_instance(
&mut self,
+ instance_key: FontInstanceKey,
font_key: FontKey,
size: f32,
flags: FontInstanceFlags,
- ) -> FontInstanceKey {
- let instance_key = self.webrender_api.generate_font_instance_key();
+ ) {
let mut transaction = Transaction::new();
let font_instance_options = FontInstanceOptions {
@@ -2549,15 +2556,12 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.webrender_api
.send_transaction(self.webrender_document, transaction);
- instance_key
}
- fn add_font(&mut self, index: u32, data: Arc<IpcSharedMemory>) -> FontKey {
- let font_key = self.webrender_api.generate_font_key();
+ fn add_font(&mut self, font_key: FontKey, index: u32, data: Arc<IpcSharedMemory>) {
let mut transaction = Transaction::new();
transaction.add_raw_font(font_key, (**data).into(), index);
self.webrender_api
.send_transaction(self.webrender_document, transaction);
- font_key
}
}
diff --git a/components/fonts/font.rs b/components/fonts/font.rs
index 47de63bad2c..dce89c78746 100644
--- a/components/fonts/font.rs
+++ b/components/fonts/font.rs
@@ -224,7 +224,7 @@ pub struct Font {
pub descriptor: FontDescriptor,
shaper: OnceLock<Shaper>,
cached_shape_data: RwLock<CachedShapeData>,
- pub font_key: FontInstanceKey,
+ pub font_instance_key: OnceLock<FontInstanceKey>,
/// If this is a synthesized small caps font, then this font reference is for
/// the version of the font used to replace lowercase ASCII letters. It's up
@@ -252,7 +252,9 @@ impl malloc_size_of::MallocSizeOf for Font {
self.metrics.size_of(ops) +
self.descriptor.size_of(ops) +
self.cached_shape_data.read().size_of(ops) +
- self.font_key.size_of(ops)
+ self.font_instance_key
+ .get()
+ .map_or(0, |key| key.size_of(ops))
}
}
@@ -278,7 +280,7 @@ impl Font {
descriptor,
metrics,
cached_shape_data: Default::default(),
- font_key: FontInstanceKey::default(),
+ font_instance_key: Default::default(),
synthesized_small_caps,
has_color_bitmap_or_colr_table: OnceLock::new(),
can_do_fast_shaping: OnceLock::new(),
@@ -301,6 +303,12 @@ impl Font {
self.table_for_tag(COLR).is_some()
})
}
+
+ pub fn key(&self, font_context: &FontContext) -> FontInstanceKey {
+ *self
+ .font_instance_key
+ .get_or_init(|| font_context.create_font_instance_key(self))
+ }
}
bitflags! {
diff --git a/components/fonts/font_context.rs b/components/fonts/font_context.rs
index 896007c5829..66fed552e7b 100644
--- a/components/fonts/font_context.rs
+++ b/components/fonts/font_context.rs
@@ -12,7 +12,6 @@ use app_units::Au;
use crossbeam_channel::unbounded;
use fnv::FnvHasher;
use fonts_traits::WebFontLoadFinishedCallback;
-use ipc_channel::ipc;
use log::{debug, trace};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use malloc_size_of_derive::MallocSizeOf;
@@ -36,7 +35,7 @@ use webrender_traits::{ScriptToCompositorMsg, WebRenderScriptApi};
use crate::font::{
Font, FontDescriptor, FontFamilyDescriptor, FontGroup, FontRef, FontSearchScope,
};
-use crate::font_store::{CrossThreadFontStore, CrossThreadWebRenderFontStore};
+use crate::font_store::CrossThreadFontStore;
use crate::font_template::{FontTemplate, FontTemplateRef, FontTemplateRefMethods};
use crate::platform::font::PlatformFont;
use crate::system_font_service::{CSSFontFaceDescriptors, FontIdentifier};
@@ -66,7 +65,15 @@ pub struct FontContext {
RwLock<HashMap<FontGroupCacheKey, Arc<RwLock<FontGroup>>, BuildHasherDefault<FnvHasher>>>,
web_fonts: CrossThreadFontStore,
- webrender_font_store: CrossThreadWebRenderFontStore,
+
+ /// A collection of WebRender [`FontKey`]s generated for the web fonts that this
+ /// [`FontContext`] controls.
+ webrender_font_keys: RwLock<HashMap<FontIdentifier, FontKey>>,
+
+ /// A collection of WebRender [`FontInstanceKey`]s generated for the web fonts that
+ /// this [`FontContext`] controls.
+ webrender_font_instance_keys: RwLock<HashMap<(FontKey, Au), FontInstanceKey>>,
+
have_removed_web_fonts: AtomicBool,
}
@@ -104,7 +111,8 @@ impl FontContext {
fonts: Default::default(),
resolved_font_groups: Default::default(),
web_fonts: Arc::new(RwLock::default()),
- webrender_font_store: Arc::new(RwLock::default()),
+ webrender_font_keys: RwLock::default(),
+ webrender_font_instance_keys: RwLock::default(),
have_removed_web_fonts: AtomicBool::new(false),
}
}
@@ -274,70 +282,81 @@ impl FontContext {
font_descriptor: FontDescriptor,
synthesized_small_caps: Option<FontRef>,
) -> Result<FontRef, &'static str> {
- let mut font = Font::new(
+ Ok(Arc::new(Font::new(
font_template.clone(),
font_descriptor.clone(),
self.get_font_data(&font_template.identifier()),
synthesized_small_caps,
- )?;
+ )?))
+ }
- font.font_key = match font_template.identifier() {
+ pub(crate) fn create_font_instance_key(&self, font: &Font) -> FontInstanceKey {
+ let result = match font.template.identifier() {
FontIdentifier::Local(_) | FontIdentifier::Mock(_) => {
self.system_font_service_proxy.get_system_font_instance(
- font_template.identifier(),
- font_descriptor.pt_size,
+ font.template.identifier(),
+ font.descriptor.pt_size,
font.webrender_font_instance_flags(),
)
},
- FontIdentifier::Web(_) => self.webrender_font_store.write().get_font_instance(
+ FontIdentifier::Web(_) => self.create_web_font_instance(
self,
- font_template.clone(),
- font_descriptor.pt_size,
+ font.template.clone(),
+ font.descriptor.pt_size,
font.webrender_font_instance_flags(),
),
};
-
- Ok(Arc::new(font))
+ result
}
- fn invalidate_font_groups_after_web_font_load(&self) {
- self.resolved_font_groups.write().clear();
- }
+ pub(crate) fn create_web_font_instance(
+ &self,
+ font_context: &FontContext,
+ font_template: FontTemplateRef,
+ pt_size: Au,
+ flags: FontInstanceFlags,
+ ) -> FontInstanceKey {
+ let identifier = font_template.identifier().clone();
+ let font_data = font_context.get_font_data(&identifier);
+ let font_key = *self
+ .webrender_font_keys
+ .write()
+ .entry(identifier.clone())
+ .or_insert_with(|| {
+ let font_key = self.system_font_service_proxy.generate_font_key();
+ let _ = self
+ .webrender_api
+ .lock()
+ .sender()
+ .send(ScriptToCompositorMsg::AddFont(
+ font_key,
+ font_data.as_ipc_shared_memory(),
+ identifier.index(),
+ ));
+ font_key
+ });
- pub(crate) fn get_web_font(&self, data: Arc<FontData>, index: u32) -> FontKey {
- let (result_sender, result_receiver) =
- ipc::channel().expect("failed to create IPC channel");
- let _ = self
- .webrender_api
- .lock()
- .sender()
- .send(ScriptToCompositorMsg::AddFont(
- data.as_ipc_shared_memory(),
- index,
- result_sender,
- ));
- result_receiver.recv().unwrap()
+ let key = *self
+ .webrender_font_instance_keys
+ .write()
+ .entry((font_key, pt_size))
+ .or_insert_with(|| {
+ let font_instance_key = self.system_font_service_proxy.generate_font_instance_key();
+ let _ = self.webrender_api.lock().sender().send(
+ ScriptToCompositorMsg::AddFontInstance(
+ font_instance_key,
+ font_key,
+ pt_size.to_f32_px(),
+ flags,
+ ),
+ );
+ font_instance_key
+ });
+ key
}
- pub(crate) fn get_web_font_instance(
- &self,
- font_key: FontKey,
- font_size: f32,
- font_flags: FontInstanceFlags,
- ) -> FontInstanceKey {
- let (result_sender, result_receiver) =
- ipc::channel().expect("failed to create IPC channel");
- let _ = self
- .webrender_api
- .lock()
- .sender()
- .send(ScriptToCompositorMsg::AddFontInstance(
- font_key,
- font_size,
- font_flags,
- result_sender,
- ));
- result_receiver.recv().unwrap()
+ fn invalidate_font_groups_after_web_font_load(&self) {
+ self.resolved_font_groups.write().clear();
}
}
@@ -538,9 +557,16 @@ impl FontContextWebFontMethods for Arc<FontContext> {
all: bool,
) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
if all {
- let mut webrender_font_store = self.webrender_font_store.write();
+ let mut webrender_font_keys = self.webrender_font_keys.write();
+ let mut webrender_font_instance_keys = self.webrender_font_instance_keys.write();
self.have_removed_web_fonts.store(false, Ordering::Relaxed);
- return webrender_font_store.remove_all_fonts();
+ return (
+ webrender_font_keys.drain().map(|(_, key)| key).collect(),
+ webrender_font_instance_keys
+ .drain()
+ .map(|(_, key)| key)
+ .collect(),
+ );
}
if !self.have_removed_web_fonts.load(Ordering::Relaxed) {
@@ -551,13 +577,11 @@ impl FontContextWebFontMethods for Arc<FontContext> {
let mut web_fonts = self.web_fonts.write();
let _fonts = self.fonts.write();
let _font_groups = self.resolved_font_groups.write();
- let mut webrender_font_store = self.webrender_font_store.write();
+ let mut webrender_font_keys = self.webrender_font_keys.write();
+ let mut webrender_font_instance_keys = self.webrender_font_instance_keys.write();
- let mut unused_identifiers: HashSet<FontIdentifier> = webrender_font_store
- .webrender_font_key_map
- .keys()
- .cloned()
- .collect();
+ let mut unused_identifiers: HashSet<FontIdentifier> =
+ webrender_font_keys.keys().cloned().collect();
for templates in web_fonts.families.values() {
templates.for_all_identifiers(|identifier| {
unused_identifiers.remove(identifier);
@@ -567,7 +591,31 @@ impl FontContextWebFontMethods for Arc<FontContext> {
web_fonts.remove_all_font_data_for_identifiers(&unused_identifiers);
self.have_removed_web_fonts.store(false, Ordering::Relaxed);
- webrender_font_store.remove_all_fonts_for_identifiers(&unused_identifiers)
+
+ let mut removed_keys: HashSet<FontKey> = HashSet::new();
+ webrender_font_keys.retain(|identifier, font_key| {
+ if unused_identifiers.contains(identifier) {
+ removed_keys.insert(*font_key);
+ false
+ } else {
+ true
+ }
+ });
+
+ let mut removed_instance_keys: HashSet<FontInstanceKey> = HashSet::new();
+ webrender_font_instance_keys.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(),
+ )
}
}
diff --git a/components/fonts/font_store.rs b/components/fonts/font_store.rs
index aad3c3e89a8..d0a79456ef6 100644
--- a/components/fonts/font_store.rs
+++ b/components/fonts/font_store.rs
@@ -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
diff --git a/components/fonts/system_font_service.rs b/components/fonts/system_font_service.rs
index e1070b49021..36130c5ed8b 100644
--- a/components/fonts/system_font_service.rs
+++ b/components/fonts/system_font_service.rs
@@ -74,6 +74,8 @@ pub enum SystemFontServiceMessage {
FontInstanceFlags,
IpcSender<FontInstanceKey>,
),
+ GetFontKey(IpcSender<FontKey>),
+ GetFontInstanceKey(IpcSender<FontInstanceKey>),
Exit(IpcSender<()>),
Ping,
}
@@ -99,6 +101,18 @@ pub struct SystemFontService {
webrender_fonts: HashMap<FontIdentifier, FontKey>,
font_instances: HashMap<(FontKey, Au), FontInstanceKey>,
generic_fonts: ResolvedGenericFontFamilies,
+
+ /// This is an optimization that allows the [`SystemFontService`] to send font data to
+ /// the compositor asynchronously for creating WebRender fonts, while immediately
+ /// returning a font key for that data. Once the free keys are exhausted, the
+ /// [`SystemFontService`] will fetch a new batch.
+ free_font_keys: Vec<FontKey>,
+
+ /// This is an optimization that allows the [`SystemFontService`] to create WebRender font
+ /// instances in the compositor asynchronously, while immediately returning a font
+ /// instance key for the instance. Once the free keys are exhausted, the
+ /// [`SystemFontService`] will fetch a new batch.
+ free_font_instance_keys: Vec<FontInstanceKey>,
}
#[derive(Clone, Deserialize, Serialize)]
@@ -129,6 +143,8 @@ impl SystemFontService {
webrender_fonts: HashMap::new(),
font_instances: HashMap::new(),
generic_fonts: Default::default(),
+ free_font_keys: Default::default(),
+ free_font_instance_keys: Default::default(),
};
cache.refresh_local_families();
@@ -158,6 +174,14 @@ impl SystemFontService {
SystemFontServiceMessage::GetFontInstance(identifier, pt_size, flags, result) => {
let _ = result.send(self.get_font_instance(identifier, pt_size, flags));
},
+ SystemFontServiceMessage::GetFontKey(result_sender) => {
+ self.fetch_new_keys();
+ let _ = result_sender.send(self.free_font_keys.pop().unwrap());
+ },
+ SystemFontServiceMessage::GetFontInstanceKey(result_sender) => {
+ self.fetch_new_keys();
+ let _ = result_sender.send(self.free_font_instance_keys.pop().unwrap());
+ },
SystemFontServiceMessage::Ping => (),
SystemFontServiceMessage::Exit(result) => {
let _ = result.send(());
@@ -167,6 +191,22 @@ impl SystemFontService {
}
}
+ fn fetch_new_keys(&mut self) {
+ if !self.free_font_keys.is_empty() && !self.free_font_instance_keys.is_empty() {
+ return;
+ }
+
+ const FREE_FONT_KEYS_BATCH_SIZE: usize = 20;
+ const FREE_FONT_INSTANCE_KEYS_BATCH_SIZE: usize = 20;
+ let (mut new_font_keys, mut new_font_instance_keys) = self.webrender_api.fetch_font_keys(
+ FREE_FONT_KEYS_BATCH_SIZE - self.free_font_keys.len(),
+ FREE_FONT_INSTANCE_KEYS_BATCH_SIZE - self.free_font_instance_keys.len(),
+ );
+ self.free_font_keys.append(&mut new_font_keys);
+ self.free_font_instance_keys
+ .append(&mut new_font_instance_keys);
+ }
+
fn get_font_templates(
&mut self,
font_descriptor: Option<FontDescriptor>,
@@ -239,6 +279,8 @@ impl SystemFontService {
pt_size: Au,
flags: FontInstanceFlags,
) -> FontInstanceKey {
+ self.fetch_new_keys();
+
let webrender_font_api = &self.webrender_api;
let webrender_fonts = &mut self.webrender_fonts;
let font_data = self.local_families.get_or_initialize_font_data(&identifier);
@@ -246,6 +288,7 @@ impl SystemFontService {
let font_key = *webrender_fonts
.entry(identifier.clone())
.or_insert_with(|| {
+ let font_key = self.free_font_keys.pop().unwrap();
// CoreText cannot reliably create CoreTextFonts for system fonts stored
// as part of TTC files, so on CoreText platforms, create a system font in
// WebRender using the LocalFontIdentifier. This has the downside of
@@ -253,18 +296,31 @@ impl SystemFontService {
// this for those platforms.
#[cfg(target_os = "macos")]
if let FontIdentifier::Local(local_font_identifier) = identifier {
- return webrender_font_api
- .add_system_font(local_font_identifier.native_font_handle());
+ webrender_font_api
+ .add_system_font(font_key, local_font_identifier.native_font_handle());
+ return font_key;
}
- webrender_font_api.add_font(font_data.as_ipc_shared_memory(), identifier.index())
+ webrender_font_api.add_font(
+ font_key,
+ font_data.as_ipc_shared_memory(),
+ identifier.index(),
+ );
+ font_key
});
*self
.font_instances
.entry((font_key, pt_size))
.or_insert_with(|| {
- webrender_font_api.add_font_instance(font_key, pt_size.to_f32_px(), flags)
+ let font_instance_key = self.free_font_instance_keys.pop().unwrap();
+ webrender_font_api.add_font_instance(
+ font_instance_key,
+ font_key,
+ pt_size.to_f32_px(),
+ flags,
+ );
+ font_instance_key
})
}
@@ -514,6 +570,30 @@ impl SystemFontServiceProxy {
pub(crate) fn get_font_data(&self, identifier: &FontIdentifier) -> Option<Arc<FontData>> {
self.data_cache.read().get(identifier).cloned()
}
+
+ pub(crate) fn generate_font_key(&self) -> FontKey {
+ let (result_sender, result_receiver) =
+ ipc::channel().expect("failed to create IPC channel");
+ self.sender
+ .lock()
+ .send(SystemFontServiceMessage::GetFontKey(result_sender))
+ .expect("failed to send message to system font service");
+ result_receiver
+ .recv()
+ .expect("Failed to communicate with system font service.")
+ }
+
+ pub(crate) fn generate_font_instance_key(&self) -> FontInstanceKey {
+ let (result_sender, result_receiver) =
+ ipc::channel().expect("failed to create IPC channel");
+ self.sender
+ .lock()
+ .send(SystemFontServiceMessage::GetFontInstanceKey(result_sender))
+ .expect("failed to send message to system font service");
+ result_receiver
+ .recv()
+ .expect("Failed to communicate with system font service.")
+ }
}
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
diff --git a/components/fonts/tests/font_context.rs b/components/fonts/tests/font_context.rs
index de706451569..036bcde7aec 100644
--- a/components/fonts/tests/font_context.rs
+++ b/components/fonts/tests/font_context.rs
@@ -32,7 +32,7 @@ use style::values::computed::font::{
use style::values::computed::{FontLanguageOverride, XLang};
use style::values::generics::font::LineHeight;
use style::ArcSlice;
-use webrender_api::{FontInstanceKey, IdNamespace};
+use webrender_api::{FontInstanceKey, FontKey, IdNamespace};
use webrender_traits::WebRenderScriptApi;
struct TestContext {
@@ -125,9 +125,13 @@ impl MockSystemFontService {
template_data,
});
},
+ SystemFontServiceMessage::GetFontInstanceKey(result_sender) |
SystemFontServiceMessage::GetFontInstance(_, _, _, result_sender) => {
let _ = result_sender.send(FontInstanceKey(IdNamespace(0), 0));
},
+ SystemFontServiceMessage::GetFontKey(result_sender) => {
+ let _ = result_sender.send(FontKey(IdNamespace(0), 0));
+ },
SystemFontServiceMessage::Exit(result_sender) => {
let _ = result_sender.send(());
break;
diff --git a/components/layout/text.rs b/components/layout/text.rs
index fa75753a47d..01c8fee6325 100644
--- a/components/layout/text.rs
+++ b/components/layout/text.rs
@@ -378,8 +378,10 @@ impl TextRunScanner {
},
};
+ let font_instance_key = font.key(font_context);
let (run, break_at_zero) = TextRun::new(
font,
+ font_instance_key,
run_info.text,
&options,
run_info.bidi_level,
diff --git a/components/layout/text_run.rs b/components/layout/text_run.rs
index 0810512ab9b..9bddc5078b8 100644
--- a/components/layout/text_run.rs
+++ b/components/layout/text_run.rs
@@ -160,6 +160,7 @@ impl<'a> TextRun {
/// Constructs a new text run. Also returns if there is a line break at the beginning
pub fn new(
font: FontRef,
+ font_key: FontInstanceKey,
text: String,
options: &ShapingOptions,
bidi_level: bidi::Level,
@@ -171,7 +172,7 @@ impl<'a> TextRun {
TextRun {
text: Arc::new(text),
font_metrics: font.metrics.clone(),
- font_key: font.font_key,
+ font_key,
pt_size: font.descriptor.pt_size,
glyphs: Arc::new(glyphs),
bidi_level,
diff --git a/components/layout_2020/flow/inline/mod.rs b/components/layout_2020/flow/inline/mod.rs
index 56d17bd54b9..8a2c47ef282 100644
--- a/components/layout_2020/flow/inline/mod.rs
+++ b/components/layout_2020/flow/inline/mod.rs
@@ -1528,8 +1528,11 @@ impl InlineFormattingContext {
&inline_box.style,
&layout_context.font_context,
) {
- inline_box.default_font_index =
- Some(add_or_get_font(&font, &mut font_metrics));
+ inline_box.default_font_index = Some(add_or_get_font(
+ &font,
+ &mut font_metrics,
+ &layout_context.font_context,
+ ));
}
},
InlineItem::Atomic(_, index_in_text, bidi_level) => {
diff --git a/components/layout_2020/flow/inline/text_run.rs b/components/layout_2020/flow/inline/text_run.rs
index d5438a103e1..76ec3032d0e 100644
--- a/components/layout_2020/flow/inline/text_run.rs
+++ b/components/layout_2020/flow/inline/text_run.rs
@@ -109,6 +109,7 @@ impl TextRunSegment {
script: Script,
bidi_level: Level,
fonts: &[FontKeyAndMetrics],
+ font_context: &FontContext,
) -> bool {
fn is_specific(script: Script) -> bool {
script != Script::Common && script != Script::Inherited
@@ -119,7 +120,7 @@ impl TextRunSegment {
}
let current_font_key_and_metrics = &fonts[self.font_index];
- if new_font.font_key != current_font_key_and_metrics.key ||
+ if new_font.key(font_context) != current_font_key_and_metrics.key ||
new_font.descriptor.pt_size != current_font_key_and_metrics.pt_size
{
return false;
@@ -440,15 +441,18 @@ impl TextRun {
let script = Script::from(character);
let bidi_level = bidi_info.levels[current_byte_index];
if let Some(current) = current.as_mut() {
- if current
- .0
- .update_if_compatible(&font, script, bidi_level, font_cache)
- {
+ if current.0.update_if_compatible(
+ &font,
+ script,
+ bidi_level,
+ font_cache,
+ font_context,
+ ) {
continue;
}
}
- let font_index = add_or_get_font(&font, font_cache);
+ let font_index = add_or_get_font(&font, font_cache, font_context);
// Add the new segment and finish the existing one, if we had one. If the first
// characters in the run were control characters we may be creating the first
@@ -473,7 +477,7 @@ impl TextRun {
// of those cases, just use the first font.
if current.is_none() {
current = font_group.write().first(font_context).map(|font| {
- let font_index = add_or_get_font(&font, font_cache);
+ let font_index = add_or_get_font(&font, font_cache, font_context);
(
TextRunSegment::new(
font_index,
@@ -539,15 +543,22 @@ fn char_does_not_change_font(character: char) -> bool {
class == XI_LINE_BREAKING_CLASS_ZWJ
}
-pub(super) fn add_or_get_font(font: &FontRef, ifc_fonts: &mut Vec<FontKeyAndMetrics>) -> usize {
+pub(super) fn add_or_get_font(
+ font: &FontRef,
+ ifc_fonts: &mut Vec<FontKeyAndMetrics>,
+ font_context: &FontContext,
+) -> usize {
+ let font_instance_key = font.key(font_context);
for (index, ifc_font_info) in ifc_fonts.iter().enumerate() {
- if ifc_font_info.key == font.font_key && ifc_font_info.pt_size == font.descriptor.pt_size {
+ if ifc_font_info.key == font_instance_key &&
+ ifc_font_info.pt_size == font.descriptor.pt_size
+ {
return index;
}
}
ifc_fonts.push(FontKeyAndMetrics {
metrics: font.metrics.clone(),
- key: font.font_key,
+ key: font_instance_key,
pt_size: font.descriptor.pt_size,
});
ifc_fonts.len() - 1
diff --git a/components/servo/lib.rs b/components/servo/lib.rs
index 7c44981600d..ff5a1e54efd 100644
--- a/components/servo/lib.rs
+++ b/components/servo/lib.rs
@@ -1096,34 +1096,48 @@ struct WebRenderFontApiCompositorProxy(CompositorProxy);
impl WebRenderFontApi for WebRenderFontApiCompositorProxy {
fn add_font_instance(
&self,
+ font_instance_key: FontInstanceKey,
font_key: FontKey,
size: f32,
flags: FontInstanceFlags,
- ) -> FontInstanceKey {
- let (sender, receiver) = unbounded();
+ ) {
self.0.send(CompositorMsg::Forwarded(
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFontInstance(
- font_key, size, flags, sender,
+ font_instance_key,
+ font_key,
+ size,
+ flags,
)),
));
- receiver.recv().unwrap()
}
- fn add_font(&self, data: Arc<IpcSharedMemory>, index: u32) -> FontKey {
- let (sender, receiver) = unbounded();
+ fn add_font(&self, font_key: FontKey, data: Arc<IpcSharedMemory>, index: u32) {
self.0.send(CompositorMsg::Forwarded(
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFont(
- sender, index, data,
+ font_key, index, data,
)),
));
- receiver.recv().unwrap()
}
- fn add_system_font(&self, handle: NativeFontHandle) -> FontKey {
- let (sender, receiver) = unbounded();
+ fn add_system_font(&self, font_key: FontKey, handle: NativeFontHandle) {
self.0.send(CompositorMsg::Forwarded(
ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddSystemFont(
- sender, handle,
+ font_key, handle,
+ )),
+ ));
+ }
+
+ fn fetch_font_keys(
+ &self,
+ number_of_font_keys: usize,
+ number_of_font_instance_keys: usize,
+ ) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
+ let (sender, receiver) = unbounded();
+ self.0.send(CompositorMsg::Forwarded(
+ ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::GenerateKeys(
+ number_of_font_keys,
+ number_of_font_instance_keys,
+ sender,
)),
));
receiver.recv().unwrap()
diff --git a/components/shared/webrender/lib.rs b/components/shared/webrender/lib.rs
index accb73df316..58580175e7d 100644
--- a/components/shared/webrender/lib.rs
+++ b/components/shared/webrender/lib.rs
@@ -186,12 +186,18 @@ impl ExternalImageHandler for WebrenderExternalImageHandlers {
pub trait WebRenderFontApi {
fn add_font_instance(
&self,
+ font_instance_key: FontInstanceKey,
font_key: FontKey,
size: f32,
flags: FontInstanceFlags,
- ) -> FontInstanceKey;
- fn add_font(&self, data: Arc<IpcSharedMemory>, index: u32) -> FontKey;
- fn add_system_font(&self, handle: NativeFontHandle) -> FontKey;
+ );
+ fn add_font(&self, font_key: FontKey, data: Arc<IpcSharedMemory>, index: u32);
+ fn add_system_font(&self, font_key: FontKey, handle: NativeFontHandle);
+ fn fetch_font_keys(
+ &self,
+ number_of_font_keys: usize,
+ number_of_font_instance_keys: usize,
+ ) -> (Vec<FontKey>, Vec<FontInstanceKey>);
}
pub enum CanvasToCompositorMsg {
@@ -200,9 +206,10 @@ pub enum CanvasToCompositorMsg {
}
pub enum FontToCompositorMsg {
- AddFontInstance(FontKey, f32, FontInstanceFlags, Sender<FontInstanceKey>),
- AddFont(Sender<FontKey>, u32, Arc<IpcSharedMemory>),
- AddSystemFont(Sender<FontKey>, NativeFontHandle),
+ GenerateKeys(usize, usize, Sender<(Vec<FontKey>, Vec<FontInstanceKey>)>),
+ AddFontInstance(FontInstanceKey, FontKey, f32, FontInstanceFlags),
+ AddFont(FontKey, u32, Arc<IpcSharedMemory>),
+ AddSystemFont(FontKey, NativeFontHandle),
}
#[derive(Deserialize, Serialize)]
@@ -242,8 +249,8 @@ pub enum ScriptToCompositorMsg {
UpdateImages(Vec<SerializedImageUpdate>),
/// Remove the given font resources from our WebRender instance.
RemoveFonts(Vec<FontKey>, Vec<FontInstanceKey>),
- AddFontInstance(FontKey, f32, FontInstanceFlags, IpcSender<FontInstanceKey>),
- AddFont(Arc<IpcSharedMemory>, u32, IpcSender<FontKey>),
+ AddFontInstance(FontInstanceKey, FontKey, f32, FontInstanceFlags),
+ AddFont(FontKey, Arc<IpcSharedMemory>, u32),
}
/// A mechanism to send messages from networking to the WebRender instance.