mirror of
https://github.com/servo/servo.git
synced 2025-08-15 02:15:33 +01:00
fonts: Use IpcSharedMemory
to send font data (#33530)
This changes modifes the way that font data is sent over IPC channels. Instead of serializing the data or sending it via IPC byte senders, font data is copied into shared memory and a copy of the handle is sent over the channel. There is also the idea of sending the file handle of the on disk data of system fonts. This could be implemented as a further followup once there is an abstraction in `ipc-channel` over file handles. To accomplish this, a `FontData` abstraction is added, which also allows caching an in-memory shared `Arc<Vec<u8>>` version of the data (neeeded by some APIs). This could also be a place for caching font tables in the future. Finally, the `FontCacheThread` is renamed to the `SystemFontService` while the proxy for this is now named `SystemFontServiceProxy`. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
This commit is contained in:
parent
2c6d9a190f
commit
ade902207f
26 changed files with 601 additions and 544 deletions
|
@ -3,25 +3,72 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
|
||||
use app_units::Au;
|
||||
use atomic_refcell::AtomicRefCell;
|
||||
use ipc_channel::ipc::IpcSharedMemory;
|
||||
use log::warn;
|
||||
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_cache_thread::{FontIdentifier, FontSource, LowercaseFontFamilyName};
|
||||
use crate::font_context::WebFontDownloadState;
|
||||
use crate::font_template::{FontTemplate, FontTemplateRef, FontTemplateRefMethods, IsOblique};
|
||||
use crate::system_font_service::{
|
||||
FontIdentifier, LowercaseFontFamilyName, SystemFontServiceProxyTrait,
|
||||
};
|
||||
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
|
||||
/// deserialization. In addition, if a shared handle to data is requested
|
||||
/// (`Arc<Vec<u8>>`), the data is lazily copied out of shared memory once per
|
||||
/// [`FontData`].
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct FontData {
|
||||
/// The data of this font in shared memory. Suitable for sending across IPC channels.
|
||||
shared_memory: Arc<IpcSharedMemory>,
|
||||
/// A lazily-initialized copy of the data behind an [`Arc`] which can be used when
|
||||
/// passing it to various APIs.
|
||||
#[serde(skip)]
|
||||
arc: OnceLock<Arc<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl FontData {
|
||||
pub fn from_bytes(data: Vec<u8>) -> FontData {
|
||||
FontData {
|
||||
shared_memory: Arc::new(IpcSharedMemory::from_bytes(&data)),
|
||||
arc: Arc::new(data).into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a non-shared memory `Arc` view of this data. This may copy the data once
|
||||
/// per [`FontData`], but subsequent calls will return the same shared view.
|
||||
pub fn as_arc(&self) -> &Arc<Vec<u8>> {
|
||||
self.arc
|
||||
.get_or_init(|| Arc::new((**self.shared_memory).into()))
|
||||
}
|
||||
|
||||
/// Return a the [`IpcSharedMemory`] view of this data suitable for sending directly across
|
||||
/// an IPC channel if necessary. An `Arc` is returned to avoid the overhead of copying the
|
||||
/// platform-specific shared memory handle.
|
||||
pub(crate) fn as_ipc_shared_memory(&self) -> Arc<IpcSharedMemory> {
|
||||
self.shared_memory.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FontStore {
|
||||
pub(crate) families: HashMap<LowercaseFontFamilyName, FontTemplates>,
|
||||
web_fonts_loading: Vec<(DocumentStyleSheet, usize)>,
|
||||
/// The data for each [`FontIdentifier`]. This data might be used by
|
||||
/// more than one [`FontTemplate`] as each identifier refers to a URL
|
||||
/// or font that can contain more than a single font.
|
||||
font_data: HashMap<FontIdentifier, Arc<FontData>>,
|
||||
}
|
||||
pub(crate) type CrossThreadFontStore = Arc<RwLock<FontStore>>;
|
||||
|
||||
|
@ -78,28 +125,67 @@ impl FontStore {
|
|||
/// Handle a web font load finishing, adding the new font to the [`FontStore`]. If the web font
|
||||
/// load was canceled (for instance, if the stylesheet was removed), then do nothing and return
|
||||
/// false.
|
||||
///
|
||||
/// In addition pass newly loaded data for this font. Add this data the cached [`FontData`] store
|
||||
/// inside this [`FontStore`].
|
||||
pub(crate) fn handle_web_font_loaded(
|
||||
&mut self,
|
||||
state: &WebFontDownloadState,
|
||||
new_template: FontTemplate,
|
||||
data: Arc<FontData>,
|
||||
) -> bool {
|
||||
// Abort processing this web font if the originating stylesheet was removed.
|
||||
if self.font_load_cancelled_for_stylesheet(&state.stylesheet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let family_name = state.css_font_face_descriptors.family_name.clone();
|
||||
self.families
|
||||
.entry(family_name)
|
||||
.or_default()
|
||||
.add_template(new_template);
|
||||
self.add_template_and_data(family_name, new_template, data);
|
||||
self.remove_one_web_font_loading_for_stylesheet(&state.stylesheet);
|
||||
true
|
||||
}
|
||||
|
||||
pub(crate) fn add_template_and_data(
|
||||
&mut self,
|
||||
family_name: LowercaseFontFamilyName,
|
||||
new_template: FontTemplate,
|
||||
data: Arc<FontData>,
|
||||
) {
|
||||
self.font_data.insert(new_template.identifier.clone(), data);
|
||||
self.families
|
||||
.entry(family_name)
|
||||
.or_default()
|
||||
.add_template(new_template);
|
||||
}
|
||||
|
||||
pub(crate) fn number_of_fonts_still_loading(&self) -> usize {
|
||||
self.web_fonts_loading.iter().map(|(_, count)| count).sum()
|
||||
}
|
||||
|
||||
pub(crate) fn get_or_initialize_font_data(
|
||||
&mut self,
|
||||
identifier: &FontIdentifier,
|
||||
) -> &Arc<FontData> {
|
||||
self.font_data
|
||||
.entry(identifier.clone())
|
||||
.or_insert_with(|| match identifier {
|
||||
FontIdentifier::Local(local_identifier) => {
|
||||
Arc::new(FontData::from_bytes(local_identifier.read_data_from_file()))
|
||||
},
|
||||
FontIdentifier::Web(_) => unreachable!("Web fonts should always have data."),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_font_data(&self, identifier: &FontIdentifier) -> Option<Arc<FontData>> {
|
||||
self.font_data.get(identifier).cloned()
|
||||
}
|
||||
|
||||
pub(crate) fn remove_all_font_data_for_identifiers(
|
||||
&mut self,
|
||||
identifiers: &HashSet<FontIdentifier>,
|
||||
) {
|
||||
self.font_data
|
||||
.retain(|font_identifier, _| identifiers.contains(font_identifier));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -110,26 +196,32 @@ pub struct WebRenderFontStore {
|
|||
pub(crate) type CrossThreadWebRenderFontStore = Arc<RwLock<WebRenderFontStore>>;
|
||||
|
||||
impl WebRenderFontStore {
|
||||
pub(crate) fn get_font_instance<FCT: FontSource>(
|
||||
pub(crate) fn get_font_instance<Proxy: SystemFontServiceProxyTrait>(
|
||||
&mut self,
|
||||
font_cache_thread: &FCT,
|
||||
font_context: &FontContext<Proxy>,
|
||||
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(|| {
|
||||
font_cache_thread.get_web_font(font_template.data(), identifier.index())
|
||||
let data = font_context.get_font_data(&identifier);
|
||||
font_context
|
||||
.system_font_service_proxy
|
||||
.get_web_font(data, identifier.index())
|
||||
});
|
||||
|
||||
*self
|
||||
.webrender_font_instance_map
|
||||
.entry((font_key, pt_size))
|
||||
.or_insert_with(|| {
|
||||
font_cache_thread.get_web_font_instance(font_key, pt_size.to_f32_px(), flags)
|
||||
font_context
|
||||
.system_font_service_proxy
|
||||
.get_web_font_instance(font_key, pt_size.to_f32_px(), flags)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -148,7 +240,7 @@ impl WebRenderFontStore {
|
|||
|
||||
pub(crate) fn remove_all_fonts_for_identifiers(
|
||||
&mut self,
|
||||
identifiers: HashSet<FontIdentifier>,
|
||||
identifiers: &HashSet<FontIdentifier>,
|
||||
) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
|
||||
let mut removed_keys: HashSet<FontKey> = HashSet::new();
|
||||
self.webrender_font_key_map.retain(|identifier, font_key| {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue