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:
Martin Robinson 2024-09-25 09:31:55 +02:00 committed by GitHub
parent 2c6d9a190f
commit ade902207f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 601 additions and 544 deletions

View file

@ -10,8 +10,8 @@ use canvas_traits::canvas::*;
use euclid::default::{Box2D, Point2D, Rect, Size2D, Transform2D, Vector2D}; use euclid::default::{Box2D, Point2D, Rect, Size2D, Transform2D, Vector2D};
use euclid::point2; use euclid::point2;
use fonts::{ use fonts::{
ByteIndex, FontBaseline, FontCacheThread, FontContext, FontGroup, FontMetrics, FontRef, ByteIndex, FontBaseline, FontContext, FontGroup, FontMetrics, FontRef, GlyphInfo, GlyphStore,
GlyphInfo, GlyphStore, ShapingFlags, ShapingOptions, LAST_RESORT_GLYPH_ADVANCE, ShapingFlags, ShapingOptions, SystemFontServiceProxy, LAST_RESORT_GLYPH_ADVANCE,
}; };
use ipc_channel::ipc::{IpcSender, IpcSharedMemory}; use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
use log::{debug, warn}; use log::{debug, warn};
@ -434,7 +434,7 @@ pub struct CanvasData<'a> {
old_image_key: Option<ImageKey>, old_image_key: Option<ImageKey>,
/// An old webrender image key that can be deleted when the current epoch ends. /// An old webrender image key that can be deleted when the current epoch ends.
very_old_image_key: Option<ImageKey>, very_old_image_key: Option<ImageKey>,
font_context: Arc<FontContext<FontCacheThread>>, font_context: Arc<FontContext<SystemFontServiceProxy>>,
} }
fn create_backend() -> Box<dyn Backend> { fn create_backend() -> Box<dyn Backend> {
@ -446,7 +446,7 @@ impl<'a> CanvasData<'a> {
size: Size2D<u64>, size: Size2D<u64>,
webrender_api: Box<dyn WebrenderApi>, webrender_api: Box<dyn WebrenderApi>,
antialias: AntialiasMode, antialias: AntialiasMode,
font_context: Arc<FontContext<FontCacheThread>>, font_context: Arc<FontContext<SystemFontServiceProxy>>,
) -> CanvasData<'a> { ) -> CanvasData<'a> {
let backend = create_backend(); let backend = create_backend();
let draw_target = backend.create_drawtarget(size); let draw_target = backend.create_drawtarget(size);

View file

@ -11,7 +11,7 @@ use canvas_traits::canvas::*;
use canvas_traits::ConstellationCanvasMsg; use canvas_traits::ConstellationCanvasMsg;
use crossbeam_channel::{select, unbounded, Sender}; use crossbeam_channel::{select, unbounded, Sender};
use euclid::default::Size2D; use euclid::default::Size2D;
use fonts::{FontCacheThread, FontContext}; use fonts::{FontContext, SystemFontServiceProxy};
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use log::warn; use log::warn;
@ -37,20 +37,20 @@ pub struct CanvasPaintThread<'a> {
canvases: HashMap<CanvasId, CanvasData<'a>>, canvases: HashMap<CanvasId, CanvasData<'a>>,
next_canvas_id: CanvasId, next_canvas_id: CanvasId,
webrender_api: Box<dyn WebrenderApi>, webrender_api: Box<dyn WebrenderApi>,
font_context: Arc<FontContext<FontCacheThread>>, font_context: Arc<FontContext<SystemFontServiceProxy>>,
} }
impl<'a> CanvasPaintThread<'a> { impl<'a> CanvasPaintThread<'a> {
fn new( fn new(
webrender_api: Box<dyn WebrenderApi>, webrender_api: Box<dyn WebrenderApi>,
font_cache_thread: FontCacheThread, system_font_service: Arc<SystemFontServiceProxy>,
resource_threads: ResourceThreads, resource_threads: ResourceThreads,
) -> CanvasPaintThread<'a> { ) -> CanvasPaintThread<'a> {
CanvasPaintThread { CanvasPaintThread {
canvases: HashMap::new(), canvases: HashMap::new(),
next_canvas_id: CanvasId(0), next_canvas_id: CanvasId(0),
webrender_api, webrender_api,
font_context: Arc::new(FontContext::new(font_cache_thread, resource_threads)), font_context: Arc::new(FontContext::new(system_font_service, resource_threads)),
} }
} }
@ -58,7 +58,7 @@ impl<'a> CanvasPaintThread<'a> {
/// communicate with it. /// communicate with it.
pub fn start( pub fn start(
webrender_api: Box<dyn WebrenderApi + Send>, webrender_api: Box<dyn WebrenderApi + Send>,
font_cache_thread: FontCacheThread, system_font_service: Arc<SystemFontServiceProxy>,
resource_threads: ResourceThreads, resource_threads: ResourceThreads,
) -> (Sender<ConstellationCanvasMsg>, IpcSender<CanvasMsg>) { ) -> (Sender<ConstellationCanvasMsg>, IpcSender<CanvasMsg>) {
let (ipc_sender, ipc_receiver) = ipc::channel::<CanvasMsg>().unwrap(); let (ipc_sender, ipc_receiver) = ipc::channel::<CanvasMsg>().unwrap();
@ -68,7 +68,7 @@ impl<'a> CanvasPaintThread<'a> {
.name("Canvas".to_owned()) .name("Canvas".to_owned())
.spawn(move || { .spawn(move || {
let mut canvas_paint_thread = CanvasPaintThread::new( let mut canvas_paint_thread = CanvasPaintThread::new(
webrender_api, font_cache_thread, resource_threads); webrender_api, system_font_service, resource_threads);
loop { loop {
select! { select! {
recv(msg_receiver) -> msg => { recv(msg_receiver) -> msg => {

View file

@ -555,7 +555,9 @@ impl GenericDrawTarget for raqote::DrawTarget {
SHARED_FONT_CACHE.with(|font_cache| { SHARED_FONT_CACHE.with(|font_cache| {
let identifier = template.identifier(); let identifier = template.identifier();
if !font_cache.borrow().contains_key(&identifier) { if !font_cache.borrow().contains_key(&identifier) {
let Ok(font) = Font::from_bytes(template.data(), identifier.index()) else { let Ok(font) =
Font::from_bytes(run.font.data.as_arc().clone(), identifier.index())
else {
return; return;
}; };
font_cache.borrow_mut().insert(identifier.clone(), font); font_cache.borrow_mut().insert(identifier.clone(), font);

View file

@ -895,12 +895,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
ForwardedToCompositorMsg::Font(FontToCompositorMsg::AddFont( ForwardedToCompositorMsg::Font(FontToCompositorMsg::AddFont(
key_sender, key_sender,
index, index,
bytes_receiver, data,
)) => { )) => {
let font_key = self.webrender_api.generate_font_key(); let font_key = self.webrender_api.generate_font_key();
let mut transaction = Transaction::new(); let mut transaction = Transaction::new();
let bytes = bytes_receiver.recv().unwrap_or_default(); transaction.add_raw_font(font_key, (**data).into(), index);
transaction.add_raw_font(font_key, bytes, index);
self.webrender_api self.webrender_api
.send_transaction(self.webrender_document, transaction); .send_transaction(self.webrender_document, transaction);
let _ = key_sender.send(font_key); let _ = key_sender.send(font_key);

View file

@ -121,7 +121,7 @@ use embedder_traits::{
}; };
use euclid::default::Size2D as UntypedSize2D; use euclid::default::Size2D as UntypedSize2D;
use euclid::Size2D; use euclid::Size2D;
use fonts::FontCacheThread; use fonts::SystemFontServiceProxy;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use ipc_channel::Error as IpcError; use ipc_channel::Error as IpcError;
@ -346,7 +346,7 @@ pub struct Constellation<STF, SWF> {
/// A channel for the constellation to send messages to the font /// A channel for the constellation to send messages to the font
/// cache thread. /// cache thread.
font_cache_thread: FontCacheThread, system_font_service: Arc<SystemFontServiceProxy>,
/// A channel for the constellation to send messages to the /// A channel for the constellation to send messages to the
/// devtools thread. /// devtools thread.
@ -515,8 +515,8 @@ pub struct InitialConstellationState {
/// A channel to the bluetooth thread. /// A channel to the bluetooth thread.
pub bluetooth_thread: IpcSender<BluetoothRequest>, pub bluetooth_thread: IpcSender<BluetoothRequest>,
/// A channel to the font cache thread. /// A proxy to the `SystemFontService` which manages the list of system fonts.
pub font_cache_thread: FontCacheThread, pub system_font_service: Arc<SystemFontServiceProxy>,
/// A channel to the resource thread. /// A channel to the resource thread.
pub public_resource_threads: ResourceThreads, pub public_resource_threads: ResourceThreads,
@ -762,7 +762,7 @@ where
bluetooth_ipc_sender: state.bluetooth_thread, bluetooth_ipc_sender: state.bluetooth_thread,
public_resource_threads: state.public_resource_threads, public_resource_threads: state.public_resource_threads,
private_resource_threads: state.private_resource_threads, private_resource_threads: state.private_resource_threads,
font_cache_thread: state.font_cache_thread, system_font_service: state.system_font_service,
sw_managers: Default::default(), sw_managers: Default::default(),
swmanager_receiver, swmanager_receiver,
swmanager_ipc_sender, swmanager_ipc_sender,
@ -1042,7 +1042,7 @@ where
devtools_sender: self.devtools_sender.clone(), devtools_sender: self.devtools_sender.clone(),
bluetooth_thread: self.bluetooth_ipc_sender.clone(), bluetooth_thread: self.bluetooth_ipc_sender.clone(),
swmanager_thread: self.swmanager_ipc_sender.clone(), swmanager_thread: self.swmanager_ipc_sender.clone(),
font_cache_thread: self.font_cache_thread.clone(), system_font_service: self.system_font_service.clone(),
resource_threads, resource_threads,
time_profiler_chan: self.time_profiler_chan.clone(), time_profiler_chan: self.time_profiler_chan.clone(),
mem_profiler_chan: self.mem_profiler_chan.clone(), mem_profiler_chan: self.mem_profiler_chan.clone(),
@ -2760,8 +2760,8 @@ where
} }
} }
debug!("Exiting font cache thread."); debug!("Exiting the system font service thread.");
self.font_cache_thread.exit(); self.system_font_service.exit();
// Receive exit signals from threads. // Receive exit signals from threads.
if let Err(e) = core_ipc_receiver.recv() { if let Err(e) = core_ipc_receiver.recv() {

View file

@ -21,7 +21,7 @@ use canvas_traits::webgl::WebGLPipeline;
use compositing_traits::{CompositionPipeline, CompositorMsg, CompositorProxy}; use compositing_traits::{CompositionPipeline, CompositorMsg, CompositorProxy};
use crossbeam_channel::{unbounded, Sender}; use crossbeam_channel::{unbounded, Sender};
use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg}; use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg};
use fonts::FontCacheThread; use fonts::{SystemFontServiceProxy, SystemFontServiceProxySender};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use ipc_channel::Error; use ipc_channel::Error;
@ -153,8 +153,8 @@ pub struct InitialPipelineState {
/// A channel to the service worker manager thread /// A channel to the service worker manager thread
pub swmanager_thread: IpcSender<SWManagerMsg>, pub swmanager_thread: IpcSender<SWManagerMsg>,
/// A channel to the font cache thread. /// A proxy to the system font service, responsible for managing the list of system fonts.
pub font_cache_thread: FontCacheThread, pub system_font_service: Arc<SystemFontServiceProxy>,
/// Channels to the resource-related threads. /// Channels to the resource-related threads.
pub resource_threads: ResourceThreads, pub resource_threads: ResourceThreads,
@ -281,7 +281,7 @@ impl Pipeline {
devtools_ipc_sender: script_to_devtools_ipc_sender, devtools_ipc_sender: script_to_devtools_ipc_sender,
bluetooth_thread: state.bluetooth_thread, bluetooth_thread: state.bluetooth_thread,
swmanager_thread: state.swmanager_thread, swmanager_thread: state.swmanager_thread,
font_cache_thread: state.font_cache_thread, system_font_service: state.system_font_service.to_sender(),
resource_threads: state.resource_threads, resource_threads: state.resource_threads,
time_profiler_chan: state.time_profiler_chan, time_profiler_chan: state.time_profiler_chan,
mem_profiler_chan: state.mem_profiler_chan, mem_profiler_chan: state.mem_profiler_chan,
@ -487,7 +487,7 @@ pub struct UnprivilegedPipelineContent {
devtools_ipc_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>, devtools_ipc_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
bluetooth_thread: IpcSender<BluetoothRequest>, bluetooth_thread: IpcSender<BluetoothRequest>,
swmanager_thread: IpcSender<SWManagerMsg>, swmanager_thread: IpcSender<SWManagerMsg>,
font_cache_thread: FontCacheThread, system_font_service: SystemFontServiceProxySender,
resource_threads: ResourceThreads, resource_threads: ResourceThreads,
time_profiler_chan: time::ProfilerChan, time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: profile_mem::ProfilerChan, mem_profiler_chan: profile_mem::ProfilerChan,
@ -550,7 +550,7 @@ impl UnprivilegedPipelineContent {
inherited_secure_context: self.load_data.inherited_secure_context, inherited_secure_context: self.load_data.inherited_secure_context,
}, },
layout_factory, layout_factory,
self.font_cache_thread.clone(), Arc::new(self.system_font_service.to_proxy()),
self.load_data.clone(), self.load_data.clone(),
self.user_agent, self.user_agent,
); );

View file

@ -27,14 +27,14 @@ use style::values::computed::{FontStretch, FontStyle, FontWeight};
use unicode_script::Script; use unicode_script::Script;
use webrender_api::{FontInstanceFlags, FontInstanceKey}; use webrender_api::{FontInstanceFlags, FontInstanceKey};
use crate::font_cache_thread::{FontIdentifier, FontSource};
use crate::font_context::FontContext; use crate::font_context::FontContext;
use crate::font_template::{FontTemplateDescriptor, FontTemplateRef, FontTemplateRefMethods}; use crate::font_template::{FontTemplateDescriptor, FontTemplateRef, FontTemplateRefMethods};
use crate::platform::font::{FontTable, PlatformFont}; use crate::platform::font::{FontTable, PlatformFont};
pub use crate::platform::font_list::fallback_font_families; pub use crate::platform::font_list::fallback_font_families;
use crate::system_font_service::{FontIdentifier, SystemFontServiceProxyTrait};
use crate::{ use crate::{
ByteIndex, EmojiPresentationPreference, FallbackFontSelectionOptions, GlyphData, GlyphId, ByteIndex, EmojiPresentationPreference, FallbackFontSelectionOptions, FontData, GlyphData,
GlyphStore, Shaper, GlyphId, GlyphStore, Shaper,
}; };
#[macro_export] #[macro_export]
@ -66,11 +66,13 @@ pub trait PlatformFontMethods: Sized {
fn new_from_template( fn new_from_template(
template: FontTemplateRef, template: FontTemplateRef,
pt_size: Option<Au>, pt_size: Option<Au>,
data: &Arc<Vec<u8>>,
) -> Result<PlatformFont, &'static str> { ) -> Result<PlatformFont, &'static str> {
let data = template.data(); let template = template.borrow();
let face_index = template.identifier().index(); let face_index = template.identifier().index();
let font_identifier = template.borrow().identifier.clone(); let font_identifier = template.identifier.clone();
Self::new_from_data(font_identifier, data, face_index, pt_size) Self::new_from_data(font_identifier, data.clone(), face_index, pt_size)
} }
fn new_from_data( fn new_from_data(
@ -218,6 +220,7 @@ impl malloc_size_of::MallocSizeOf for CachedShapeData {
#[derive(Debug)] #[derive(Debug)]
pub struct Font { pub struct Font {
pub handle: PlatformFont, pub handle: PlatformFont,
pub data: Arc<FontData>,
pub template: FontTemplateRef, pub template: FontTemplateRef,
pub metrics: FontMetrics, pub metrics: FontMetrics,
pub descriptor: FontDescriptor, pub descriptor: FontDescriptor,
@ -251,13 +254,19 @@ impl Font {
pub fn new( pub fn new(
template: FontTemplateRef, template: FontTemplateRef,
descriptor: FontDescriptor, descriptor: FontDescriptor,
data: Arc<FontData>,
synthesized_small_caps: Option<FontRef>, synthesized_small_caps: Option<FontRef>,
) -> Result<Font, &'static str> { ) -> Result<Font, &'static str> {
let handle = PlatformFont::new_from_template(template.clone(), Some(descriptor.pt_size))?; let handle = PlatformFont::new_from_template(
template.clone(),
Some(descriptor.pt_size),
data.as_arc(),
)?;
let metrics = handle.metrics(); let metrics = handle.metrics();
Ok(Font { Ok(Font {
handle, handle,
data,
template, template,
shaper: OnceLock::new(), shaper: OnceLock::new(),
descriptor, descriptor,
@ -526,7 +535,7 @@ impl FontGroup {
/// `codepoint`. If no such font is found, returns the first available font or fallback font /// `codepoint`. If no such font is found, returns the first available font or fallback font
/// (which will cause a "glyph not found" character to be rendered). If no font at all can be /// (which will cause a "glyph not found" character to be rendered). If no font at all can be
/// found, returns None. /// found, returns None.
pub fn find_by_codepoint<S: FontSource>( pub fn find_by_codepoint<S: SystemFontServiceProxyTrait>(
&mut self, &mut self,
font_context: &FontContext<S>, font_context: &FontContext<S>,
codepoint: char, codepoint: char,
@ -598,7 +607,10 @@ impl FontGroup {
} }
/// Find the first available font in the group, or the first available fallback font. /// Find the first available font in the group, or the first available fallback font.
pub fn first<S: FontSource>(&mut self, font_context: &FontContext<S>) -> Option<FontRef> { pub fn first<S: SystemFontServiceProxyTrait>(
&mut self,
font_context: &FontContext<S>,
) -> Option<FontRef> {
// From https://drafts.csswg.org/css-fonts/#first-available-font: // From https://drafts.csswg.org/css-fonts/#first-available-font:
// > The first available font, used for example in the definition of font-relative lengths // > The first available font, used for example in the definition of font-relative lengths
// > such as ex or in the definition of the line-height property, is defined to be the first // > such as ex or in the definition of the line-height property, is defined to be the first
@ -629,7 +641,7 @@ impl FontGroup {
font_predicate: FontPredicate, font_predicate: FontPredicate,
) -> Option<FontRef> ) -> Option<FontRef>
where where
S: FontSource, S: SystemFontServiceProxyTrait,
TemplatePredicate: Fn(FontTemplateRef) -> bool, TemplatePredicate: Fn(FontTemplateRef) -> bool,
FontPredicate: Fn(&FontRef) -> bool, FontPredicate: Fn(&FontRef) -> bool,
{ {
@ -659,7 +671,7 @@ impl FontGroup {
font_predicate: FontPredicate, font_predicate: FontPredicate,
) -> Option<FontRef> ) -> Option<FontRef>
where where
S: FontSource, S: SystemFontServiceProxyTrait,
TemplatePredicate: Fn(FontTemplateRef) -> bool, TemplatePredicate: Fn(FontTemplateRef) -> bool,
FontPredicate: Fn(&FontRef) -> bool, FontPredicate: Fn(&FontRef) -> bool,
{ {
@ -731,7 +743,7 @@ impl FontGroupFamily {
font_predicate: &FontPredicate, font_predicate: &FontPredicate,
) -> Option<FontRef> ) -> Option<FontRef>
where where
S: FontSource, S: SystemFontServiceProxyTrait,
TemplatePredicate: Fn(FontTemplateRef) -> bool, TemplatePredicate: Fn(FontTemplateRef) -> bool,
FontPredicate: Fn(&FontRef) -> bool, FontPredicate: Fn(&FontRef) -> bool,
{ {
@ -754,7 +766,7 @@ impl FontGroupFamily {
.next() .next()
} }
fn members<S: FontSource>( fn members<S: SystemFontServiceProxyTrait>(
&mut self, &mut self,
font_descriptor: &FontDescriptor, font_descriptor: &FontDescriptor,
font_context: &FontContext<S>, font_context: &FontContext<S>,
@ -883,6 +895,8 @@ pub(crate) fn map_platform_values_to_style_values(mapping: &[(f64, f64)], value:
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::FontData;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
#[test] #[test]
fn test_shape_text_fast() { fn test_shape_text_fast() {
@ -917,14 +931,16 @@ mod test {
let identifier = FontIdentifier::Web(ServoUrl::from_file_path(path.clone()).unwrap()); let identifier = FontIdentifier::Web(ServoUrl::from_file_path(path.clone()).unwrap());
let file = File::open(path).unwrap(); let file = File::open(path).unwrap();
let data: Arc<Vec<u8>> = Arc::new(file.bytes().map(|b| b.unwrap()).collect()); let data = Arc::new(FontData::from_bytes(
file.bytes().map(|b| b.unwrap()).collect(),
));
let platform_font = let platform_font =
PlatformFont::new_from_data(identifier.clone(), data.clone(), 0, None).unwrap(); PlatformFont::new_from_data(identifier.clone(), data.as_arc().clone(), 0, None)
.unwrap();
let template = FontTemplate { let template = FontTemplate {
identifier, identifier,
descriptor: platform_font.descriptor(), descriptor: platform_font.descriptor(),
data: Some(data),
stylesheet: None, stylesheet: None,
}; };
let descriptor = FontDescriptor { let descriptor = FontDescriptor {
@ -937,6 +953,7 @@ mod test {
let font = Font::new( let font = Font::new(
Arc::new(atomic_refcell::AtomicRefCell::new(template)), Arc::new(atomic_refcell::AtomicRefCell::new(template)),
descriptor, descriptor,
data,
None, None,
) )
.unwrap(); .unwrap();

View file

@ -19,6 +19,7 @@ use net_traits::request::{Destination, Referrer, RequestBuilder};
use net_traits::{fetch_async, CoreResourceThread, FetchResponseMsg, ResourceThreads}; use net_traits::{fetch_async, CoreResourceThread, FetchResponseMsg, ResourceThreads};
use parking_lot::{Mutex, ReentrantMutex, RwLock}; use parking_lot::{Mutex, ReentrantMutex, RwLock};
use servo_arc::Arc as ServoArc; use servo_arc::Arc as ServoArc;
use servo_url::ServoUrl;
use style::computed_values::font_variant_caps::T as FontVariantCaps; use style::computed_values::font_variant_caps::T as FontVariantCaps;
use style::font_face::{FontFaceSourceFormat, FontFaceSourceFormatKeyword, Source, UrlSource}; use style::font_face::{FontFaceSourceFormat, FontFaceSourceFormatKeyword, Source, UrlSource};
use style::media_queries::Device; use style::media_queries::Device;
@ -33,39 +34,67 @@ use webrender_api::{FontInstanceKey, FontKey};
use crate::font::{ use crate::font::{
Font, FontDescriptor, FontFamilyDescriptor, FontGroup, FontRef, FontSearchScope, Font, FontDescriptor, FontFamilyDescriptor, FontGroup, FontRef, FontSearchScope,
}; };
use crate::font_cache_thread::{CSSFontFaceDescriptors, FontIdentifier, FontSource};
use crate::font_store::{CrossThreadFontStore, CrossThreadWebRenderFontStore}; use crate::font_store::{CrossThreadFontStore, CrossThreadWebRenderFontStore};
use crate::font_template::{FontTemplate, FontTemplateRef, FontTemplateRefMethods}; use crate::font_template::{FontTemplate, FontTemplateRef, FontTemplateRefMethods};
use crate::LowercaseFontFamilyName; use crate::platform::font::PlatformFont;
use crate::system_font_service::{
CSSFontFaceDescriptors, FontIdentifier, SystemFontServiceProxyTrait,
};
use crate::{FontData, LowercaseFontFamilyName, PlatformFontMethods};
static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8; // Matches FireFox (see gfxFont.h) static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8; // Matches FireFox (see gfxFont.h)
/// The FontContext represents the per-thread/thread state necessary for /// The FontContext represents the per-thread/thread state necessary for
/// working with fonts. It is the public API used by the layout and /// working with fonts. It is the public API used by the layout and
/// paint code. It talks directly to the font cache thread where /// paint code. It talks directly to the system font service where
/// required. /// required.
pub struct FontContext<S: FontSource> { pub struct FontContext<Proxy: SystemFontServiceProxyTrait> {
font_source: ReentrantMutex<S>, pub(crate) system_font_service_proxy: Arc<Proxy>,
resource_threads: ReentrantMutex<CoreResourceThread>, resource_threads: ReentrantMutex<CoreResourceThread>,
cache: CachingFontSource<S>,
/// The actual instances of fonts ie a [`FontTemplate`] combined with a size and
/// other font properties, along with the font data and a platform font instance.
fonts: RwLock<HashMap<FontCacheKey, Option<FontRef>>>,
/// A caching map between the specification of a font in CSS style and
/// resolved [`FontGroup`] which contains information about all fonts that
/// can be selected with that style.
resolved_font_groups:
RwLock<HashMap<FontGroupCacheKey, Arc<RwLock<FontGroup>>, BuildHasherDefault<FnvHasher>>>,
web_fonts: CrossThreadFontStore, web_fonts: CrossThreadFontStore,
webrender_font_store: CrossThreadWebRenderFontStore, webrender_font_store: CrossThreadWebRenderFontStore,
have_removed_web_fonts: AtomicBool, have_removed_web_fonts: AtomicBool,
} }
impl<S: FontSource> MallocSizeOf for FontContext<S> { impl<S: SystemFontServiceProxyTrait> MallocSizeOf for FontContext<S> {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.cache.size_of(ops) let font_cache_size = self
.fonts
.read()
.iter()
.map(|(key, font)| {
key.size_of(ops) + font.as_ref().map_or(0, |font| (*font).size_of(ops))
})
.sum::<usize>();
let font_group_cache_size = self
.resolved_font_groups
.read()
.iter()
.map(|(key, font_group)| key.size_of(ops) + (*font_group.read()).size_of(ops))
.sum::<usize>();
font_cache_size + font_group_cache_size
} }
} }
impl<S: FontSource> FontContext<S> { impl<Proxy: SystemFontServiceProxyTrait> FontContext<Proxy> {
pub fn new(font_source: S, resource_threads: ResourceThreads) -> FontContext<S> { pub fn new(system_font_service_proxy: Arc<Proxy>, resource_threads: ResourceThreads) -> Self {
#[allow(clippy::default_constructed_unit_structs)] #[allow(clippy::default_constructed_unit_structs)]
FontContext { Self {
font_source: ReentrantMutex::new(font_source.clone()), system_font_service_proxy,
resource_threads: ReentrantMutex::new(resource_threads.core_thread), resource_threads: ReentrantMutex::new(resource_threads.core_thread),
cache: CachingFontSource::new(font_source), fonts: Default::default(),
resolved_font_groups: Default::default(),
web_fonts: Arc::new(RwLock::default()), web_fonts: Arc::new(RwLock::default()),
webrender_font_store: Arc::new(RwLock::default()), webrender_font_store: Arc::new(RwLock::default()),
have_removed_web_fonts: AtomicBool::new(false), have_removed_web_fonts: AtomicBool::new(false),
@ -76,6 +105,14 @@ impl<S: FontSource> FontContext<S> {
self.web_fonts.read().number_of_fonts_still_loading() self.web_fonts.read().number_of_fonts_still_loading()
} }
pub(crate) fn get_font_data(&self, identifier: &FontIdentifier) -> Arc<FontData> {
self.web_fonts
.read()
.get_font_data(identifier)
.or_else(|| self.system_font_service_proxy.get_font_data(identifier))
.expect("Could not find font data")
}
/// Handle the situation where a web font finishes loading, specifying if the load suceeded or failed. /// Handle the situation where a web font finishes loading, specifying if the load suceeded or failed.
fn handle_web_font_load_finished( fn handle_web_font_load_finished(
&self, &self,
@ -83,7 +120,7 @@ impl<S: FontSource> FontContext<S> {
succeeded: bool, succeeded: bool,
) { ) {
if succeeded { if succeeded {
self.cache.invalidate_after_web_font_load(); self.invalidate_font_groups_after_web_font_load();
} }
finished_callback(succeeded); finished_callback(succeeded);
} }
@ -103,7 +140,19 @@ impl<S: FontSource> FontContext<S> {
style: ServoArc<FontStyleStruct>, style: ServoArc<FontStyleStruct>,
size: Au, size: Au,
) -> Arc<RwLock<FontGroup>> { ) -> Arc<RwLock<FontGroup>> {
self.cache.font_group_with_size(style, size) let cache_key = FontGroupCacheKey { size, style };
if let Some(font_group) = self.resolved_font_groups.read().get(&cache_key) {
return font_group.clone();
}
let mut descriptor = FontDescriptor::from(&*cache_key.style);
descriptor.pt_size = size;
let font_group = Arc::new(RwLock::new(FontGroup::new(&cache_key.style, descriptor)));
self.resolved_font_groups
.write()
.insert(cache_key, font_group.clone());
font_group
} }
/// Returns a font matching the parameters. Fonts are cached, so repeated calls will return a /// Returns a font matching the parameters. Fonts are cached, so repeated calls will return a
@ -148,7 +197,7 @@ impl<S: FontSource> FontContext<S> {
font_descriptor: font_descriptor.clone(), font_descriptor: font_descriptor.clone(),
}; };
if let Some(font) = self.cache.fonts.read().get(&cache_key).cloned() { if let Some(font) = self.fonts.read().get(&cache_key).cloned() {
return font; return font;
} }
@ -166,7 +215,7 @@ impl<S: FontSource> FontContext<S> {
synthesized_small_caps_font, synthesized_small_caps_font,
) )
.ok(); .ok();
self.cache.fonts.write().insert(cache_key, font.clone()); self.fonts.write().insert(cache_key, font.clone());
font font
} }
@ -192,7 +241,7 @@ impl<S: FontSource> FontContext<S> {
} }
/// Try to find matching templates in this [`FontContext`], first looking in the list of web fonts and /// Try to find matching templates in this [`FontContext`], first looking in the list of web fonts and
/// falling back to asking the [`super::FontCacheThread`] for a matching system font. /// falling back to asking the [`super::SystemFontService`] for a matching system font.
pub fn matching_templates( pub fn matching_templates(
&self, &self,
descriptor_to_match: &FontDescriptor, descriptor_to_match: &FontDescriptor,
@ -200,8 +249,10 @@ impl<S: FontSource> FontContext<S> {
) -> Vec<FontTemplateRef> { ) -> Vec<FontTemplateRef> {
self.matching_web_font_templates(descriptor_to_match, family_descriptor) self.matching_web_font_templates(descriptor_to_match, family_descriptor)
.unwrap_or_else(|| { .unwrap_or_else(|| {
self.cache self.system_font_service_proxy.find_matching_font_templates(
.matching_templates(descriptor_to_match, family_descriptor) Some(descriptor_to_match),
&family_descriptor.family,
)
}) })
} }
@ -216,18 +267,18 @@ impl<S: FontSource> FontContext<S> {
let mut font = Font::new( let mut font = Font::new(
font_template.clone(), font_template.clone(),
font_descriptor.clone(), font_descriptor.clone(),
self.get_font_data(&font_template.identifier()),
synthesized_small_caps, synthesized_small_caps,
)?; )?;
let font_source = self.font_source.lock();
font.font_key = match font_template.identifier() { font.font_key = match font_template.identifier() {
FontIdentifier::Local(_) => font_source.get_system_font_instance( FontIdentifier::Local(_) => self.system_font_service_proxy.get_system_font_instance(
font_template.identifier(), font_template.identifier(),
font_descriptor.pt_size, font_descriptor.pt_size,
font.webrender_font_instance_flags(), font.webrender_font_instance_flags(),
), ),
FontIdentifier::Web(_) => self.webrender_font_store.write().get_font_instance( FontIdentifier::Web(_) => self.webrender_font_store.write().get_font_instance(
&*font_source, self,
font_template.clone(), font_template.clone(),
font_descriptor.pt_size, font_descriptor.pt_size,
font.webrender_font_instance_flags(), font.webrender_font_instance_flags(),
@ -236,6 +287,10 @@ impl<S: FontSource> FontContext<S> {
Ok(Arc::new(font)) Ok(Arc::new(font))
} }
fn invalidate_font_groups_after_web_font_load(&self) {
self.resolved_font_groups.write().clear();
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -263,7 +318,7 @@ pub trait FontContextWebFontMethods {
-> (Vec<FontKey>, Vec<FontInstanceKey>); -> (Vec<FontKey>, Vec<FontInstanceKey>);
} }
impl<S: FontSource + Send + 'static> FontContextWebFontMethods for Arc<FontContext<S>> { impl<S: SystemFontServiceProxyTrait + 'static> FontContextWebFontMethods for Arc<FontContext<S>> {
fn add_all_web_fonts_from_stylesheet( fn add_all_web_fonts_from_stylesheet(
&self, &self,
stylesheet: &DocumentStyleSheet, stylesheet: &DocumentStyleSheet,
@ -325,8 +380,7 @@ impl<S: FontSource + Send + 'static> FontContextWebFontMethods for Arc<FontConte
name: family_name.name.clone(), name: family_name.name.clone(),
syntax: FontFamilyNameSyntax::Quoted, syntax: FontFamilyNameSyntax::Quoted,
}); });
self.font_source self.system_font_service_proxy
.lock()
.find_matching_font_templates(None, &family) .find_matching_font_templates(None, &family)
.first() .first()
.cloned() .cloned()
@ -373,24 +427,27 @@ impl<S: FontSource + Send + 'static> FontContextWebFontMethods for Arc<FontConte
RemoteWebFontDownloader::download(url_source, this, web_font_family_name, state) RemoteWebFontDownloader::download(url_source, this, web_font_family_name, state)
}, },
Source::Local(ref local_family_name) => { Source::Local(ref local_family_name) => {
if let Some(new_template) = state if let Some((new_template, font_data)) = state
.local_fonts .local_fonts
.get(&local_family_name.name) .get(&local_family_name.name)
.cloned() .cloned()
.flatten() .flatten()
.and_then(|local_template| { .and_then(|local_template| {
FontTemplate::new_for_local_web_font( let template = FontTemplate::new_for_local_web_font(
local_template, local_template.clone(),
&state.css_font_face_descriptors, &state.css_font_face_descriptors,
state.stylesheet.clone(), state.stylesheet.clone(),
) )
.ok() .ok()?;
let font_data = self.get_font_data(&local_template.identifier());
Some((template, font_data))
}) })
{ {
let not_cancelled = self let not_cancelled = self.web_fonts.write().handle_web_font_loaded(
.web_fonts &state,
.write() new_template,
.handle_web_font_loaded(&state, new_template); font_data,
);
self.handle_web_font_load_finished(&state.finished_callback, not_cancelled); self.handle_web_font_load_finished(&state.finished_callback, not_cancelled);
} else { } else {
this.process_next_web_font_source(state); this.process_next_web_font_source(state);
@ -401,8 +458,8 @@ impl<S: FontSource + Send + 'static> FontContextWebFontMethods for Arc<FontConte
fn remove_all_web_fonts_from_stylesheet(&self, stylesheet: &DocumentStyleSheet) { fn remove_all_web_fonts_from_stylesheet(&self, stylesheet: &DocumentStyleSheet) {
let mut web_fonts = self.web_fonts.write(); let mut web_fonts = self.web_fonts.write();
let mut fonts = self.cache.fonts.write(); let mut fonts = self.fonts.write();
let mut font_groups = self.cache.resolved_font_groups.write(); let mut font_groups = self.resolved_font_groups.write();
// Cancel any currently in-progress web font loads. // Cancel any currently in-progress web font loads.
web_fonts.handle_stylesheet_removed(stylesheet); web_fonts.handle_stylesheet_removed(stylesheet);
@ -443,9 +500,9 @@ impl<S: FontSource + Send + 'static> FontContextWebFontMethods for Arc<FontConte
} }
// Lock everything to prevent adding new fonts while we are cleaning up the old ones. // Lock everything to prevent adding new fonts while we are cleaning up the old ones.
let web_fonts = self.web_fonts.write(); let mut web_fonts = self.web_fonts.write();
let _fonts = self.cache.fonts.write(); let _fonts = self.fonts.write();
let _font_groups = self.cache.resolved_font_groups.write(); let _font_groups = self.resolved_font_groups.write();
let mut webrender_font_store = self.webrender_font_store.write(); let mut webrender_font_store = self.webrender_font_store.write();
let mut unused_identifiers: HashSet<FontIdentifier> = webrender_font_store let mut unused_identifiers: HashSet<FontIdentifier> = webrender_font_store
@ -459,13 +516,15 @@ impl<S: FontSource + Send + 'static> FontContextWebFontMethods for Arc<FontConte
}); });
} }
web_fonts.remove_all_font_data_for_identifiers(&unused_identifiers);
self.have_removed_web_fonts.store(false, Ordering::Relaxed); self.have_removed_web_fonts.store(false, Ordering::Relaxed);
webrender_font_store.remove_all_fonts_for_identifiers(unused_identifiers) webrender_font_store.remove_all_fonts_for_identifiers(&unused_identifiers)
} }
} }
struct RemoteWebFontDownloader<FCT: FontSource> { struct RemoteWebFontDownloader<Proxy: SystemFontServiceProxyTrait> {
font_context: Arc<FontContext<FCT>>, font_context: Arc<FontContext<Proxy>>,
url: ServoArc<Url>, url: ServoArc<Url>,
web_font_family_name: LowercaseFontFamilyName, web_font_family_name: LowercaseFontFamilyName,
response_valid: Mutex<bool>, response_valid: Mutex<bool>,
@ -478,10 +537,10 @@ enum DownloaderResponseResult {
Failure, Failure,
} }
impl<FCT: FontSource + Send + 'static> RemoteWebFontDownloader<FCT> { impl<Proxy: SystemFontServiceProxyTrait + 'static> RemoteWebFontDownloader<Proxy> {
fn download( fn download(
url_source: UrlSource, url_source: UrlSource,
font_context: Arc<FontContext<FCT>>, font_context: Arc<FontContext<Proxy>>,
web_font_family_name: LowercaseFontFamilyName, web_font_family_name: LowercaseFontFamilyName,
state: WebFontDownloadState, state: WebFontDownloadState,
) { ) {
@ -548,7 +607,7 @@ impl<FCT: FontSource + Send + 'static> RemoteWebFontDownloader<FCT> {
); );
let font_data = match fontsan::process(&font_data) { let font_data = match fontsan::process(&font_data) {
Ok(bytes) => bytes, Ok(bytes) => Arc::new(FontData::from_bytes(bytes)),
Err(error) => { Err(error) => {
debug!( debug!(
"Sanitiser rejected web font: family={} url={:?} with {error:?}", "Sanitiser rejected web font: family={} url={:?} with {error:?}",
@ -558,20 +617,28 @@ impl<FCT: FontSource + Send + 'static> RemoteWebFontDownloader<FCT> {
}, },
}; };
let Ok(new_template) = FontTemplate::new_for_remote_web_font( let url: ServoUrl = self.url.clone().into();
self.url.clone().into(), let identifier = FontIdentifier::Web(url.clone());
Arc::new(font_data), let Ok(handle) =
&state.css_font_face_descriptors, PlatformFont::new_from_data(identifier, font_data.as_arc().clone(), 0, None)
Some(state.stylesheet.clone()), else {
) else { return false;
};
let mut descriptor = handle.descriptor();
descriptor
.override_values_with_css_font_template_descriptors(&state.css_font_face_descriptors);
let Ok(new_template) =
FontTemplate::new_for_remote_web_font(url, descriptor, Some(state.stylesheet.clone()))
else {
return false; return false;
}; };
let not_cancelled = self let not_cancelled = self.font_context.web_fonts.write().handle_web_font_loaded(
.font_context state,
.web_fonts new_template,
.write() font_data,
.handle_web_font_loaded(state, new_template); );
self.font_context self.font_context
.handle_web_font_load_finished(&state.finished_callback, not_cancelled); .handle_web_font_load_finished(&state.finished_callback, not_cancelled);
@ -623,121 +690,12 @@ impl<FCT: FontSource + Send + 'static> RemoteWebFontDownloader<FCT> {
} }
} }
#[derive(Default)]
pub struct CachingFontSource<FCT: FontSource> {
font_cache_thread: ReentrantMutex<FCT>,
fonts: RwLock<HashMap<FontCacheKey, Option<FontRef>>>,
templates: RwLock<HashMap<FontTemplateCacheKey, Vec<FontTemplateRef>>>,
resolved_font_groups:
RwLock<HashMap<FontGroupCacheKey, Arc<RwLock<FontGroup>>, BuildHasherDefault<FnvHasher>>>,
}
impl<FCT: FontSource> CachingFontSource<FCT> {
fn new(font_cache_thread: FCT) -> Self {
Self {
font_cache_thread: ReentrantMutex::new(font_cache_thread),
fonts: Default::default(),
templates: Default::default(),
resolved_font_groups: Default::default(),
}
}
fn invalidate_after_web_font_load(&self) {
self.resolved_font_groups.write().clear();
}
pub fn matching_templates(
&self,
descriptor_to_match: &FontDescriptor,
family_descriptor: &FontFamilyDescriptor,
) -> Vec<FontTemplateRef> {
let cache_key = FontTemplateCacheKey {
font_descriptor: descriptor_to_match.clone(),
family_descriptor: family_descriptor.clone(),
};
if let Some(templates) = self.templates.read().get(&cache_key).cloned() {
return templates;
}
debug!(
"CachingFontSource: cache miss for template_descriptor={:?} family_descriptor={:?}",
descriptor_to_match, family_descriptor
);
let templates = self
.font_cache_thread
.lock()
.find_matching_font_templates(Some(descriptor_to_match), &family_descriptor.family);
self.templates.write().insert(cache_key, templates.clone());
templates
}
pub fn font_group_with_size(
&self,
style: ServoArc<FontStyleStruct>,
size: Au,
) -> Arc<RwLock<FontGroup>> {
let cache_key = FontGroupCacheKey { size, style };
if let Some(font_group) = self.resolved_font_groups.read().get(&cache_key) {
return font_group.clone();
}
let mut descriptor = FontDescriptor::from(&*cache_key.style);
descriptor.pt_size = size;
let font_group = Arc::new(RwLock::new(FontGroup::new(&cache_key.style, descriptor)));
self.resolved_font_groups
.write()
.insert(cache_key, font_group.clone());
font_group
}
}
impl<FCT: FontSource> MallocSizeOf for CachingFontSource<FCT> {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
let font_cache_size = self
.fonts
.read()
.iter()
.map(|(key, font)| {
key.size_of(ops) + font.as_ref().map_or(0, |font| (*font).size_of(ops))
})
.sum::<usize>();
let font_template_cache_size = self
.templates
.read()
.iter()
.map(|(key, templates)| {
let templates_size = templates
.iter()
.map(|template| template.borrow().size_of(ops))
.sum::<usize>();
key.size_of(ops) + templates_size
})
.sum::<usize>();
let font_group_cache_size = self
.resolved_font_groups
.read()
.iter()
.map(|(key, font_group)| key.size_of(ops) + (*font_group.read()).size_of(ops))
.sum::<usize>();
font_cache_size + font_template_cache_size + font_group_cache_size
}
}
#[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)] #[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)]
struct FontCacheKey { struct FontCacheKey {
font_identifier: FontIdentifier, font_identifier: FontIdentifier,
font_descriptor: FontDescriptor, font_descriptor: FontDescriptor,
} }
#[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)]
struct FontTemplateCacheKey {
font_descriptor: FontDescriptor,
family_descriptor: FontFamilyDescriptor,
}
#[derive(Debug, MallocSizeOf)] #[derive(Debug, MallocSizeOf)]
struct FontGroupCacheKey { struct FontGroupCacheKey {
#[ignore_malloc_size_of = "This is also stored as part of styling."] #[ignore_malloc_size_of = "This is also stored as part of styling."]

View file

@ -3,25 +3,72 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::sync::Arc; use std::sync::{Arc, OnceLock};
use app_units::Au; use app_units::Au;
use atomic_refcell::AtomicRefCell; use atomic_refcell::AtomicRefCell;
use ipc_channel::ipc::IpcSharedMemory;
use log::warn; use log::warn;
use parking_lot::RwLock; use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use style::stylesheets::DocumentStyleSheet; use style::stylesheets::DocumentStyleSheet;
use style::values::computed::{FontStyle, FontWeight}; use style::values::computed::{FontStyle, FontWeight};
use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey}; use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey};
use crate::font::FontDescriptor; use crate::font::FontDescriptor;
use crate::font_cache_thread::{FontIdentifier, FontSource, LowercaseFontFamilyName};
use crate::font_context::WebFontDownloadState; use crate::font_context::WebFontDownloadState;
use crate::font_template::{FontTemplate, FontTemplateRef, FontTemplateRefMethods, IsOblique}; 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)] #[derive(Default)]
pub struct FontStore { pub struct FontStore {
pub(crate) families: HashMap<LowercaseFontFamilyName, FontTemplates>, pub(crate) families: HashMap<LowercaseFontFamilyName, FontTemplates>,
web_fonts_loading: Vec<(DocumentStyleSheet, usize)>, 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>>; 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 /// 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 /// load was canceled (for instance, if the stylesheet was removed), then do nothing and return
/// false. /// 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( pub(crate) fn handle_web_font_loaded(
&mut self, &mut self,
state: &WebFontDownloadState, state: &WebFontDownloadState,
new_template: FontTemplate, new_template: FontTemplate,
data: Arc<FontData>,
) -> bool { ) -> bool {
// Abort processing this web font if the originating stylesheet was removed. // Abort processing this web font if the originating stylesheet was removed.
if self.font_load_cancelled_for_stylesheet(&state.stylesheet) { if self.font_load_cancelled_for_stylesheet(&state.stylesheet) {
return false; return false;
} }
let family_name = state.css_font_face_descriptors.family_name.clone(); let family_name = state.css_font_face_descriptors.family_name.clone();
self.families self.add_template_and_data(family_name, new_template, data);
.entry(family_name)
.or_default()
.add_template(new_template);
self.remove_one_web_font_loading_for_stylesheet(&state.stylesheet); self.remove_one_web_font_loading_for_stylesheet(&state.stylesheet);
true 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 { pub(crate) fn number_of_fonts_still_loading(&self) -> usize {
self.web_fonts_loading.iter().map(|(_, count)| count).sum() 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)] #[derive(Default)]
@ -110,26 +196,32 @@ pub struct WebRenderFontStore {
pub(crate) type CrossThreadWebRenderFontStore = Arc<RwLock<WebRenderFontStore>>; pub(crate) type CrossThreadWebRenderFontStore = Arc<RwLock<WebRenderFontStore>>;
impl WebRenderFontStore { impl WebRenderFontStore {
pub(crate) fn get_font_instance<FCT: FontSource>( pub(crate) fn get_font_instance<Proxy: SystemFontServiceProxyTrait>(
&mut self, &mut self,
font_cache_thread: &FCT, font_context: &FontContext<Proxy>,
font_template: FontTemplateRef, font_template: FontTemplateRef,
pt_size: Au, pt_size: Au,
flags: FontInstanceFlags, flags: FontInstanceFlags,
) -> FontInstanceKey { ) -> FontInstanceKey {
let webrender_font_key_map = &mut self.webrender_font_key_map; let webrender_font_key_map = &mut self.webrender_font_key_map;
let identifier = font_template.identifier().clone(); let identifier = font_template.identifier().clone();
let font_key = *webrender_font_key_map let font_key = *webrender_font_key_map
.entry(identifier.clone()) .entry(identifier.clone())
.or_insert_with(|| { .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 *self
.webrender_font_instance_map .webrender_font_instance_map
.entry((font_key, pt_size)) .entry((font_key, pt_size))
.or_insert_with(|| { .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( pub(crate) fn remove_all_fonts_for_identifiers(
&mut self, &mut self,
identifiers: HashSet<FontIdentifier>, identifiers: &HashSet<FontIdentifier>,
) -> (Vec<FontKey>, Vec<FontInstanceKey>) { ) -> (Vec<FontKey>, Vec<FontInstanceKey>) {
let mut removed_keys: HashSet<FontKey> = HashSet::new(); let mut removed_keys: HashSet<FontKey> = HashSet::new();
self.webrender_font_key_map.retain(|identifier, font_key| { self.webrender_font_key_map.retain(|identifier, font_key| {

View file

@ -15,12 +15,11 @@ use style::computed_values::font_style::T as FontStyle;
use style::stylesheets::DocumentStyleSheet; use style::stylesheets::DocumentStyleSheet;
use style::values::computed::font::FontWeight; use style::values::computed::font::FontWeight;
use crate::font::{FontDescriptor, PlatformFontMethods}; use crate::font::FontDescriptor;
use crate::font_cache_thread::{ use crate::platform::font_list::LocalFontIdentifier;
use crate::system_font_service::{
CSSFontFaceDescriptors, ComputedFontStyleDescriptor, FontIdentifier, CSSFontFaceDescriptors, ComputedFontStyleDescriptor, FontIdentifier,
}; };
use crate::platform::font::PlatformFont;
use crate::platform::font_list::LocalFontIdentifier;
/// A reference to a [`FontTemplate`] with shared ownership and mutability. /// A reference to a [`FontTemplate`] with shared ownership and mutability.
pub type FontTemplateRef = Arc<AtomicRefCell<FontTemplate>>; pub type FontTemplateRef = Arc<AtomicRefCell<FontTemplate>>;
@ -109,7 +108,7 @@ impl FontTemplateDescriptor {
self.stretch.1 >= descriptor_to_match.stretch self.stretch.1 >= descriptor_to_match.stretch
} }
fn override_values_with_css_font_template_descriptors( pub(crate) fn override_values_with_css_font_template_descriptors(
&mut self, &mut self,
css_font_template_descriptors: &CSSFontFaceDescriptors, css_font_template_descriptors: &CSSFontFaceDescriptors,
) { ) {
@ -137,27 +136,20 @@ impl FontTemplateDescriptor {
/// This describes all the information needed to create /// This describes all the information needed to create
/// font instance handles. It contains a unique /// font instance handles. It contains a unique
/// FontTemplateData structure that is platform specific. /// FontTemplateData structure that is platform specific.
#[derive(Clone)] #[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
pub struct FontTemplate { pub struct FontTemplate {
pub identifier: FontIdentifier, pub identifier: FontIdentifier,
pub descriptor: FontTemplateDescriptor, pub descriptor: FontTemplateDescriptor,
/// The data to use for this [`FontTemplate`]. For web fonts, this is always filled, but
/// for local fonts, this is loaded only lazily in layout.
pub data: Option<Arc<Vec<u8>>>,
/// If this font is a web font, this is a reference to the stylesheet that /// If this font is a web font, this is a reference to the stylesheet that
/// created it. This will be used to remove this font from caches, when the /// created it. This will be used to remove this font from caches, when the
/// stylesheet is removed. /// stylesheet is removed.
///
/// This is not serialized, as it's only useful in the [`super::FontContext`]
/// that it is created in.
#[serde(skip)]
pub stylesheet: Option<DocumentStyleSheet>, pub stylesheet: Option<DocumentStyleSheet>,
} }
impl malloc_size_of::MallocSizeOf for FontTemplate {
fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
self.identifier.size_of(ops) +
self.descriptor.size_of(ops) +
self.data.as_ref().map_or(0, |data| (*data).size_of(ops))
}
}
impl Debug for FontTemplate { impl Debug for FontTemplate {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
self.identifier.fmt(f) self.identifier.fmt(f)
@ -176,7 +168,6 @@ impl FontTemplate {
FontTemplate { FontTemplate {
identifier: FontIdentifier::Local(identifier), identifier: FontIdentifier::Local(identifier),
descriptor, descriptor,
data: None,
stylesheet: None, stylesheet: None,
} }
} }
@ -184,22 +175,12 @@ impl FontTemplate {
/// Create a new [`FontTemplate`] for a `@font-family` with a `url(...)` `src` font. /// Create a new [`FontTemplate`] for a `@font-family` with a `url(...)` `src` font.
pub fn new_for_remote_web_font( pub fn new_for_remote_web_font(
url: ServoUrl, url: ServoUrl,
data: Arc<Vec<u8>>, descriptor: FontTemplateDescriptor,
css_font_template_descriptors: &CSSFontFaceDescriptors,
stylesheet: Option<DocumentStyleSheet>, stylesheet: Option<DocumentStyleSheet>,
) -> Result<FontTemplate, &'static str> { ) -> Result<FontTemplate, &'static str> {
let identifier = FontIdentifier::Web(url.clone());
let Ok(handle) = PlatformFont::new_from_data(identifier, data.clone(), 0, None) else {
return Err("Could not initialize platform font data for: {url:?}");
};
let mut descriptor = handle.descriptor();
descriptor
.override_values_with_css_font_template_descriptors(css_font_template_descriptors);
Ok(FontTemplate { Ok(FontTemplate {
identifier: FontIdentifier::Web(url), identifier: FontIdentifier::Web(url),
descriptor, descriptor,
data: Some(data),
stylesheet, stylesheet,
}) })
} }
@ -223,19 +204,9 @@ impl FontTemplate {
pub fn identifier(&self) -> &FontIdentifier { pub fn identifier(&self) -> &FontIdentifier {
&self.identifier &self.identifier
} }
/// Returns a reference to the bytes in this font if they are in memory.
/// This function never performs disk I/O.
pub fn data_if_in_memory(&self) -> Option<Arc<Vec<u8>>> {
self.data.clone()
}
} }
pub trait FontTemplateRefMethods { pub trait FontTemplateRefMethods {
/// Returns a reference to the data in this font. This may be a hugely expensive
/// operation (depending on the platform) which performs synchronous disk I/O
/// and should never be done lightly.
fn data(&self) -> Arc<Vec<u8>>;
/// Get the descriptor. /// Get the descriptor.
fn descriptor(&self) -> FontTemplateDescriptor; fn descriptor(&self) -> FontTemplateDescriptor;
/// Get the [`FontIdentifier`] for this template. /// Get the [`FontIdentifier`] for this template.
@ -267,24 +238,6 @@ impl FontTemplateRefMethods for FontTemplateRef {
self.descriptor().distance_from(descriptor_to_match) self.descriptor().distance_from(descriptor_to_match)
} }
fn data(&self) -> Arc<Vec<u8>> {
if let Some(data) = self.borrow().data.clone() {
return data;
}
let mut template = self.borrow_mut();
let identifier = template.identifier.clone();
template
.data
.get_or_insert_with(|| match identifier {
FontIdentifier::Local(local_identifier) => {
Arc::new(local_identifier.read_data_from_file())
},
FontIdentifier::Web(_) => unreachable!("Web fonts should always have data."),
})
.clone()
}
fn char_in_unicode_range(&self, character: char) -> bool { fn char_in_unicode_range(&self, character: char) -> bool {
let character = character as u32; let character = character as u32;
self.borrow() self.borrow()

View file

@ -5,7 +5,6 @@
#![deny(unsafe_code)] #![deny(unsafe_code)]
mod font; mod font;
mod font_cache_thread;
mod font_context; mod font_context;
mod font_store; mod font_store;
mod font_template; mod font_template;
@ -13,14 +12,15 @@ mod glyph;
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub mod platform; pub mod platform;
mod shaper; mod shaper;
mod system_font_service;
pub use font::*; pub use font::*;
pub use font_cache_thread::*;
pub use font_context::*; pub use font_context::*;
pub use font_store::*; pub use font_store::*;
pub use font_template::*; pub use font_template::*;
pub use glyph::*; pub use glyph::*;
pub use shaper::*; pub use shaper::*;
pub use system_font_service::*;
use unicode_properties::{emoji, EmojiStatus, UnicodeEmoji}; use unicode_properties::{emoji, EmojiStatus, UnicodeEmoji};
/// Whether or not font fallback selection prefers the emoji or text representation /// Whether or not font fallback selection prefers the emoji or text representation

View file

@ -452,7 +452,7 @@ impl FontList {
} }
} }
// Functions used by FontCacheThread // Functions used by SystemFontSerivce
pub fn for_each_available_family<F>(mut callback: F) pub fn for_each_available_family<F>(mut callback: F)
where where
F: FnMut(String), F: FnMut(String),

View file

@ -29,9 +29,9 @@ use crate::font::{
FontMetrics, FontTableMethods, FontTableTag, FractionalPixel, PlatformFontMethods, GPOS, GSUB, FontMetrics, FontTableMethods, FontTableTag, FractionalPixel, PlatformFontMethods, GPOS, GSUB,
KERN, KERN,
}; };
use crate::font_cache_thread::FontIdentifier;
use crate::font_template::FontTemplateDescriptor; use crate::font_template::FontTemplateDescriptor;
use crate::glyph::GlyphId; use crate::glyph::GlyphId;
use crate::system_font_service::FontIdentifier;
// This constant is not present in the freetype // This constant is not present in the freetype
// bindings due to bindgen not handling the way // bindings due to bindgen not handling the way

View file

@ -453,7 +453,7 @@ impl FontList {
} }
} }
// Functions used by FontCacheThread // Functions used by SystemFontService
pub fn for_each_available_family<F>(mut callback: F) pub fn for_each_available_family<F>(mut callback: F)
where where
F: FnMut(String), F: FnMut(String),

View file

@ -16,7 +16,7 @@ use core_text::font::CTFont;
use core_text::font_descriptor::kCTFontURLAttribute; use core_text::font_descriptor::kCTFontURLAttribute;
use parking_lot::RwLock; use parking_lot::RwLock;
use crate::font_cache_thread::FontIdentifier; use crate::system_font_service::FontIdentifier;
/// A cache of `CTFont` to avoid having to create `CTFont` instances over and over. It is /// A cache of `CTFont` to avoid having to create `CTFont` instances over and over. It is
/// always possible to create a `CTFont` using a `FontTemplate` even if it isn't in this /// always possible to create a `CTFont` using a `FontTemplate` even if it isn't in this

View file

@ -11,9 +11,10 @@ use std::{fmt, thread};
use app_units::Au; use app_units::Au;
use atomic_refcell::AtomicRefCell; use atomic_refcell::AtomicRefCell;
use ipc_channel::ipc::{self, IpcBytesReceiver, IpcBytesSender, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use log::debug; use log::debug;
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
use parking_lot::{ReentrantMutex, RwLock};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use servo_config::pref; use servo_config::pref;
use servo_url::ServoUrl; use servo_url::ServoUrl;
@ -29,13 +30,12 @@ use webrender_traits::WebRenderFontApi;
use crate::font::FontDescriptor; use crate::font::FontDescriptor;
use crate::font_store::FontStore; use crate::font_store::FontStore;
use crate::font_template::{ use crate::font_template::{FontTemplate, FontTemplateRef};
FontTemplate, FontTemplateDescriptor, FontTemplateRef, FontTemplateRefMethods,
};
use crate::platform::font_list::{ use crate::platform::font_list::{
default_system_generic_font_family, for_each_available_family, for_each_variation, default_system_generic_font_family, for_each_available_family, for_each_variation,
LocalFontIdentifier, LocalFontIdentifier,
}; };
use crate::FontData;
#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] #[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub enum FontIdentifier { pub enum FontIdentifier {
@ -53,19 +53,18 @@ impl FontIdentifier {
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct SerializedFontTemplate { pub struct FontTemplateRequestResult {
identifier: FontIdentifier, templates: Vec<FontTemplate>,
descriptor: FontTemplateDescriptor, template_data: Vec<(FontIdentifier, Arc<FontData>)>,
bytes_receiver: ipc_channel::ipc::IpcBytesReceiver,
} }
/// Commands that the FontContext sends to the font cache thread. /// Commands that the `FontContext` sends to the `SystemFontService`.
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub enum Command { pub enum Command {
GetFontTemplates( GetFontTemplates(
Option<FontDescriptor>, Option<FontDescriptor>,
SingleFontFamily, SingleFontFamily,
IpcSender<Vec<SerializedFontTemplate>>, IpcSender<FontTemplateRequestResult>,
), ),
GetFontInstance( GetFontInstance(
FontIdentifier, FontIdentifier,
@ -73,7 +72,7 @@ pub enum Command {
FontInstanceFlags, FontInstanceFlags,
IpcSender<FontInstanceKey>, IpcSender<FontInstanceKey>,
), ),
GetWebFont(IpcBytesReceiver, u32, IpcSender<FontKey>), GetWebFont(Arc<FontData>, u32, IpcSender<FontKey>),
GetWebFontInstance(FontKey, f32, FontInstanceFlags, IpcSender<FontInstanceKey>), GetWebFontInstance(FontKey, f32, FontInstanceFlags, IpcSender<FontInstanceKey>),
Exit(IpcSender<()>), Exit(IpcSender<()>),
Ping, Ping,
@ -90,11 +89,11 @@ struct ResolvedGenericFontFamilies {
system_ui: OnceCell<LowercaseFontFamilyName>, system_ui: OnceCell<LowercaseFontFamilyName>,
} }
/// The font cache thread itself. It maintains a list of reference counted /// The system font service. There is one of these for every Servo instance. This is a thread,
/// font templates that are currently in use. /// responsible for reading the list of system fonts, handling requests to match against
struct FontCache { /// them, and ensuring that only one copy of system font data is loaded at a time.
pub struct SystemFontService {
port: IpcReceiver<Command>, port: IpcReceiver<Command>,
font_data: HashMap<FontIdentifier, Arc<Vec<u8>>>,
local_families: FontStore, local_families: FontStore,
webrender_api: Box<dyn WebRenderFontApi>, webrender_api: Box<dyn WebRenderFontApi>,
webrender_fonts: HashMap<FontIdentifier, FontKey>, webrender_fonts: HashMap<FontIdentifier, FontKey>,
@ -102,68 +101,62 @@ struct FontCache {
generic_fonts: ResolvedGenericFontFamilies, generic_fonts: ResolvedGenericFontFamilies,
} }
impl FontCache { #[derive(Clone, Deserialize, Serialize)]
pub struct SystemFontServiceProxySender(IpcSender<Command>);
impl SystemFontServiceProxySender {
pub fn to_proxy(&self) -> SystemFontServiceProxy {
SystemFontServiceProxy {
sender: ReentrantMutex::new(self.0.clone()),
templates: Default::default(),
data_cache: Default::default(),
}
}
}
impl SystemFontService {
pub fn spawn(webrender_api: Box<dyn WebRenderFontApi + Send>) -> SystemFontServiceProxySender {
let (sender, receiver) = ipc::channel().unwrap();
thread::Builder::new()
.name("SystemFontService".to_owned())
.spawn(move || {
#[allow(clippy::default_constructed_unit_structs)]
let mut cache = SystemFontService {
port: receiver,
local_families: Default::default(),
webrender_api,
webrender_fonts: HashMap::new(),
font_instances: HashMap::new(),
generic_fonts: Default::default(),
};
cache.refresh_local_families();
cache.run();
})
.expect("Thread spawning failed");
SystemFontServiceProxySender(sender)
}
#[tracing::instrument(skip(self), fields(servo_profiling = true))] #[tracing::instrument(skip(self), fields(servo_profiling = true))]
fn run(&mut self) { fn run(&mut self) {
loop { loop {
let msg = self.port.recv().unwrap(); let msg = self.port.recv().unwrap();
match msg { match msg {
Command::GetFontTemplates(descriptor_to_match, font_family, result) => { Command::GetFontTemplates(font_descriptor, font_family, result_sender) => {
let span = span!( let span = span!(Level::TRACE, "GetFontTemplates", servo_profiling = true);
Level::TRACE,
"Command::GetFontTemplates",
servo_profiling = true
);
let _span = span.enter(); let _span = span.enter();
let templates = let _ =
self.find_font_templates(descriptor_to_match.as_ref(), &font_family); result_sender.send(self.get_font_templates(font_descriptor, font_family));
debug!("Found templates for descriptor {descriptor_to_match:?}: ");
debug!(" {templates:?}");
let (serialized_templates, senders): (
Vec<SerializedFontTemplate>,
Vec<(FontTemplateRef, IpcBytesSender)>,
) = templates
.into_iter()
.map(|template| {
let (bytes_sender, bytes_receiver) =
ipc::bytes_channel().expect("failed to create IPC channel");
(
SerializedFontTemplate {
identifier: template.identifier().clone(),
descriptor: template.descriptor().clone(),
bytes_receiver,
},
(template.clone(), bytes_sender),
)
})
.unzip();
let _ = result.send(serialized_templates);
// NB: This will load the font into memory if it hasn't been loaded already.
for (font_template, bytes_sender) in senders.iter() {
let identifier = font_template.identifier();
let data = self
.font_data
.entry(identifier)
.or_insert_with(|| font_template.data());
let span = span!(
Level::TRACE,
"GetFontTemplates send",
servo_profiling = true
);
let _span = span.enter();
let _ = bytes_sender.send(data);
}
}, },
Command::GetFontInstance(identifier, pt_size, flags, result) => { Command::GetFontInstance(identifier, pt_size, flags, result) => {
let _ = result.send(self.get_font_instance(identifier, pt_size, flags)); let _ = result.send(self.get_font_instance(identifier, pt_size, flags));
}, },
Command::GetWebFont(bytes_receiver, font_index, result_sender) => { Command::GetWebFont(data, font_index, result_sender) => {
self.webrender_api.forward_add_font_message( self.webrender_api.forward_add_font_message(
bytes_receiver, data.as_ipc_shared_memory(),
font_index, font_index,
result_sender, result_sender,
); );
@ -190,6 +183,38 @@ impl FontCache {
} }
} }
fn get_font_templates(
&mut self,
font_descriptor: Option<FontDescriptor>,
font_family: SingleFontFamily,
) -> FontTemplateRequestResult {
let templates = self.find_font_templates(font_descriptor.as_ref(), &font_family);
let templates: Vec<_> = templates
.into_iter()
.map(|template| template.borrow().clone())
.collect();
// The `FontData` for all templates is also sent along with the `FontTemplate`s. This is to ensure that
// the data is not read from disk in each content process. The data is loaded once here in the system
// font service and each process gets another handle to the `IpcSharedMemory` view of that data.
let template_data = templates
.iter()
.map(|template| {
let identifier = template.identifier.clone();
let data = self
.local_families
.get_or_initialize_font_data(&identifier)
.clone();
(identifier, data)
})
.collect();
FontTemplateRequestResult {
templates,
template_data,
}
}
fn refresh_local_families(&mut self) { fn refresh_local_families(&mut self) {
self.local_families.clear(); self.local_families.clear();
for_each_available_family(|family_name| { for_each_available_family(|family_name| {
@ -232,11 +257,7 @@ impl FontCache {
) -> FontInstanceKey { ) -> FontInstanceKey {
let webrender_font_api = &self.webrender_api; let webrender_font_api = &self.webrender_api;
let webrender_fonts = &mut self.webrender_fonts; let webrender_fonts = &mut self.webrender_fonts;
let font_data = self let font_data = self.local_families.get_or_initialize_font_data(&identifier);
.font_data
.get(&identifier)
.expect("Got unexpected FontIdentifier")
.clone();
let font_key = *webrender_fonts let font_key = *webrender_fonts
.entry(identifier.clone()) .entry(identifier.clone())
@ -252,7 +273,7 @@ impl FontCache {
.add_system_font(local_font_identifier.native_font_handle()); .add_system_font(local_font_identifier.native_font_handle());
} }
webrender_font_api.add_font(font_data, identifier.index()) webrender_font_api.add_font(font_data.as_ipc_shared_memory(), identifier.index())
}); });
*self *self
@ -304,7 +325,8 @@ impl FontCache {
} }
} }
pub trait FontSource: Clone { /// A trait for accessing the [`SystemFontServiceProxy`] necessary for unit testing.
pub trait SystemFontServiceProxyTrait: Send + Sync {
fn find_matching_font_templates( fn find_matching_font_templates(
&self, &self,
descriptor_to_match: Option<&FontDescriptor>, descriptor_to_match: Option<&FontDescriptor>,
@ -316,20 +338,29 @@ pub trait FontSource: Clone {
size: Au, size: Au,
flags: FontInstanceFlags, flags: FontInstanceFlags,
) -> FontInstanceKey; ) -> FontInstanceKey;
fn get_web_font(&self, data: Arc<Vec<u8>>, index: u32) -> FontKey; fn get_web_font(&self, data: Arc<FontData>, index: u32) -> FontKey;
fn get_web_font_instance( fn get_web_font_instance(
&self, &self,
font_key: FontKey, font_key: FontKey,
size: f32, size: f32,
flags: FontInstanceFlags, flags: FontInstanceFlags,
) -> FontInstanceKey; ) -> FontInstanceKey;
fn get_font_data(&self, identifier: &FontIdentifier) -> Option<Arc<FontData>>;
} }
/// The public interface to the font cache thread, used by per-thread `FontContext` instances (via #[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)]
/// the `FontSource` trait), and also by layout. struct FontTemplateCacheKey {
#[derive(Clone, Debug, Deserialize, Serialize)] font_descriptor: Option<FontDescriptor>,
pub struct FontCacheThread { family_descriptor: SingleFontFamily,
chan: IpcSender<Command>, }
/// The public interface to the [`SystemFontService`], used by per-Document `FontContext`
/// instances (via [`SystemFontServiceProxyTrait`]).
#[derive(Debug)]
pub struct SystemFontServiceProxy {
sender: ReentrantMutex<IpcSender<Command>>,
templates: RwLock<HashMap<FontTemplateCacheKey, Vec<FontTemplateRef>>>,
data_cache: RwLock<HashMap<FontIdentifier, Arc<FontData>>>,
} }
/// A version of `FontStyle` from Stylo that is serializable. Normally this is not /// A version of `FontStyle` from Stylo that is serializable. Normally this is not
@ -417,44 +448,24 @@ impl From<&FontFaceRuleData> for CSSFontFaceDescriptors {
} }
} }
impl FontCacheThread { impl SystemFontServiceProxy {
pub fn new(webrender_api: Box<dyn WebRenderFontApi + Send>) -> FontCacheThread {
let (chan, port) = ipc::channel().unwrap();
thread::Builder::new()
.name("FontCache".to_owned())
.spawn(move || {
#[allow(clippy::default_constructed_unit_structs)]
let mut cache = FontCache {
port,
font_data: HashMap::new(),
local_families: Default::default(),
webrender_api,
webrender_fonts: HashMap::new(),
font_instances: HashMap::new(),
generic_fonts: Default::default(),
};
cache.refresh_local_families();
cache.run();
})
.expect("Thread spawning failed");
FontCacheThread { chan }
}
pub fn exit(&self) { pub fn exit(&self) {
let (response_chan, response_port) = ipc::channel().unwrap(); let (response_chan, response_port) = ipc::channel().unwrap();
self.chan self.sender
.lock()
.send(Command::Exit(response_chan)) .send(Command::Exit(response_chan))
.expect("Couldn't send FontCacheThread exit message"); .expect("Couldn't send SystemFontService exit message");
response_port response_port
.recv() .recv()
.expect("Couldn't receive FontCacheThread reply"); .expect("Couldn't receive SystemFontService reply");
}
pub fn to_sender(&self) -> SystemFontServiceProxySender {
SystemFontServiceProxySender(self.sender.lock().clone())
} }
} }
impl FontSource for FontCacheThread { impl SystemFontServiceProxyTrait for SystemFontServiceProxy {
fn get_system_font_instance( fn get_system_font_instance(
&self, &self,
identifier: FontIdentifier, identifier: FontIdentifier,
@ -462,23 +473,24 @@ impl FontSource for FontCacheThread {
flags: FontInstanceFlags, flags: FontInstanceFlags,
) -> FontInstanceKey { ) -> FontInstanceKey {
let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel"); let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel");
self.chan self.sender
.lock()
.send(Command::GetFontInstance( .send(Command::GetFontInstance(
identifier, identifier,
size, size,
flags, flags,
response_chan, response_chan,
)) ))
.expect("failed to send message to font cache thread"); .expect("failed to send message to system font service");
let instance_key = response_port.recv(); let instance_key = response_port.recv();
if instance_key.is_err() { if instance_key.is_err() {
let font_thread_has_closed = self.chan.send(Command::Ping).is_err(); let font_thread_has_closed = self.sender.lock().send(Command::Ping).is_err();
assert!( assert!(
font_thread_has_closed, font_thread_has_closed,
"Failed to receive a response from live font cache" "Failed to receive a response from live font cache"
); );
panic!("Font cache thread has already exited."); panic!("SystemFontService has already exited.");
} }
instance_key.unwrap() instance_key.unwrap()
} }
@ -486,51 +498,59 @@ impl FontSource for FontCacheThread {
fn find_matching_font_templates( fn find_matching_font_templates(
&self, &self,
descriptor_to_match: Option<&FontDescriptor>, descriptor_to_match: Option<&FontDescriptor>,
font_family: &SingleFontFamily, family_descriptor: &SingleFontFamily,
) -> Vec<FontTemplateRef> { ) -> Vec<FontTemplateRef> {
let cache_key = FontTemplateCacheKey {
font_descriptor: descriptor_to_match.cloned(),
family_descriptor: family_descriptor.clone(),
};
if let Some(templates) = self.templates.read().get(&cache_key).cloned() {
return templates;
}
debug!(
"SystemFontServiceProxy: cache miss for template_descriptor={:?} family_descriptor={:?}",
descriptor_to_match, family_descriptor
);
let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel"); let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel");
self.chan self.sender
.lock()
.send(Command::GetFontTemplates( .send(Command::GetFontTemplates(
descriptor_to_match.cloned(), descriptor_to_match.cloned(),
font_family.clone(), family_descriptor.clone(),
response_chan, response_chan,
)) ))
.expect("failed to send message to font cache thread"); .expect("failed to send message to system font service");
let reply = response_port.recv(); let reply = response_port.recv();
if reply.is_err() { let Ok(reply) = reply else {
let font_thread_has_closed = self.chan.send(Command::Ping).is_err(); let font_thread_has_closed = self.sender.lock().send(Command::Ping).is_err();
assert!( assert!(
font_thread_has_closed, font_thread_has_closed,
"Failed to receive a response from live font cache" "Failed to receive a response from live font cache"
); );
panic!("Font cache thread has already exited."); panic!("SystemFontService has already exited.");
} };
reply let templates: Vec<_> = reply
.unwrap() .templates
.into_iter() .into_iter()
.map(|serialized_font_template| { .map(AtomicRefCell::new)
let font_data = serialized_font_template.bytes_receiver.recv().ok(); .map(Arc::new)
Arc::new(AtomicRefCell::new(FontTemplate { .collect();
identifier: serialized_font_template.identifier, self.data_cache.write().extend(reply.template_data);
descriptor: serialized_font_template.descriptor.clone(),
data: font_data.map(Arc::new), templates
stylesheet: None,
}))
})
.collect()
} }
fn get_web_font(&self, data: Arc<Vec<u8>>, index: u32) -> FontKey { fn get_web_font(&self, data: Arc<FontData>, index: u32) -> FontKey {
let (result_sender, result_receiver) = let (result_sender, result_receiver) =
ipc::channel().expect("failed to create IPC channel"); ipc::channel().expect("failed to create IPC channel");
let (bytes_sender, bytes_receiver) =
ipc::bytes_channel().expect("failed to create IPC channel");
let _ = self let _ = self
.chan .sender
.send(Command::GetWebFont(bytes_receiver, index, result_sender)); .lock()
let _ = bytes_sender.send(&data); .send(Command::GetWebFont(data, index, result_sender));
result_receiver.recv().unwrap() result_receiver.recv().unwrap()
} }
@ -542,7 +562,7 @@ impl FontSource for FontCacheThread {
) -> FontInstanceKey { ) -> FontInstanceKey {
let (result_sender, result_receiver) = let (result_sender, result_receiver) =
ipc::channel().expect("failed to create IPC channel"); ipc::channel().expect("failed to create IPC channel");
let _ = self.chan.send(Command::GetWebFontInstance( let _ = self.sender.lock().send(Command::GetWebFontInstance(
font_key, font_key,
font_size, font_size,
font_flags, font_flags,
@ -550,6 +570,10 @@ impl FontSource for FontCacheThread {
)); ));
result_receiver.recv().unwrap() result_receiver.recv().unwrap()
} }
fn get_font_data(&self, identifier: &FontIdentifier) -> Option<Arc<FontData>> {
self.data_cache.read().get(identifier).cloned()
}
} }
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]

View file

@ -2,22 +2,24 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::{Cell, RefCell};
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::sync::atomic::{AtomicI32, Ordering};
use std::sync::Arc;
use app_units::Au; use app_units::Au;
use fonts::platform::font::PlatformFont;
use fonts::{ use fonts::{
fallback_font_families, CSSFontFaceDescriptors, FallbackFontSelectionOptions, FontContext, fallback_font_families, FallbackFontSelectionOptions, FontContext, FontData, FontDescriptor,
FontDescriptor, FontFamilyDescriptor, FontIdentifier, FontSearchScope, FontSource, FontFamilyDescriptor, FontIdentifier, FontSearchScope, FontTemplate, FontTemplateRef,
FontTemplate, FontTemplateRef, FontTemplates, FontTemplates, PlatformFontMethods, SystemFontServiceProxyTrait,
}; };
use ipc_channel::ipc; use ipc_channel::ipc;
use net_traits::ResourceThreads; use net_traits::ResourceThreads;
use servo_arc::Arc; use parking_lot::Mutex;
use servo_arc::Arc as ServoArc;
use servo_atoms::Atom; use servo_atoms::Atom;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use style::properties::longhands::font_variant_caps::computed_value::T as FontVariantCaps; use style::properties::longhands::font_variant_caps::computed_value::T as FontVariantCaps;
@ -31,35 +33,40 @@ use style::values::generics::font::LineHeight;
use style::ArcSlice; use style::ArcSlice;
use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey, IdNamespace}; use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey, IdNamespace};
#[derive(Clone)]
struct MockFontCacheThread { struct MockFontCacheThread {
families: RefCell<HashMap<String, FontTemplates>>, families: Mutex<HashMap<String, FontTemplates>>,
find_font_count: Rc<Cell<isize>>, data: Mutex<HashMap<FontIdentifier, Arc<FontData>>>,
find_font_count: AtomicI32,
} }
impl MockFontCacheThread { impl MockFontCacheThread {
fn new() -> MockFontCacheThread { fn new() -> Self {
let proxy = Self {
families: Default::default(),
data: Default::default(),
find_font_count: AtomicI32::new(0),
};
let mut csstest_ascii = FontTemplates::default(); let mut csstest_ascii = FontTemplates::default();
Self::add_face(&mut csstest_ascii, "csstest-ascii"); proxy.add_face(&mut csstest_ascii, "csstest-ascii");
let mut csstest_basic = FontTemplates::default(); let mut csstest_basic = FontTemplates::default();
Self::add_face(&mut csstest_basic, "csstest-basic-regular"); proxy.add_face(&mut csstest_basic, "csstest-basic-regular");
let mut fallback = FontTemplates::default(); let mut fallback = FontTemplates::default();
Self::add_face(&mut fallback, "csstest-basic-regular"); proxy.add_face(&mut fallback, "csstest-basic-regular");
let mut families = HashMap::new(); {
families.insert("CSSTest ASCII".to_owned(), csstest_ascii); let mut families = proxy.families.lock();
families.insert("CSSTest Basic".to_owned(), csstest_basic); families.insert("CSSTest ASCII".to_owned(), csstest_ascii);
families.insert( families.insert("CSSTest Basic".to_owned(), csstest_basic);
fallback_font_families(FallbackFontSelectionOptions::default())[0].to_owned(), families.insert(
fallback, fallback_font_families(FallbackFontSelectionOptions::default())[0].to_owned(),
); fallback,
);
MockFontCacheThread {
families: RefCell::new(families),
find_font_count: Rc::new(Cell::new(0)),
} }
proxy
} }
fn identifier_for_font_name(name: &str) -> FontIdentifier { fn identifier_for_font_name(name: &str) -> FontIdentifier {
@ -74,39 +81,44 @@ impl MockFontCacheThread {
ServoUrl::from_file_path(path).unwrap() ServoUrl::from_file_path(path).unwrap()
} }
fn add_face(family: &mut FontTemplates, name: &str) { fn add_face(&self, family: &mut FontTemplates, name: &str) {
let mut path: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests", "support", "CSSTest"] let mut path: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests", "support", "CSSTest"]
.iter() .iter()
.collect(); .collect();
path.push(format!("{}.ttf", name)); path.push(format!("{}.ttf", name));
let file = File::open(path).unwrap(); let file = File::open(path).unwrap();
let data: Vec<u8> = file.bytes().map(|b| b.unwrap()).collect(); let data = Arc::new(FontData::from_bytes(
family.add_template( file.bytes().map(|b| b.unwrap()).collect(),
FontTemplate::new_for_remote_web_font( ));
Self::url_for_font_name(name),
std::sync::Arc::new(data), let url = Self::url_for_font_name(name);
&CSSFontFaceDescriptors::new(name), let identifier = FontIdentifier::Web(url.clone());
None, let handle =
) PlatformFont::new_from_data(identifier.clone(), data.as_arc().clone(), 0, None)
.unwrap(), .expect("Could not load test font");
); let template =
FontTemplate::new_for_remote_web_font(url, handle.descriptor(), None).unwrap();
family.add_template(template);
self.data.lock().insert(identifier, data);
} }
} }
impl FontSource for MockFontCacheThread { impl SystemFontServiceProxyTrait for MockFontCacheThread {
fn find_matching_font_templates( fn find_matching_font_templates(
&self, &self,
descriptor_to_match: Option<&FontDescriptor>, descriptor_to_match: Option<&FontDescriptor>,
font_family: &SingleFontFamily, font_family: &SingleFontFamily,
) -> Vec<FontTemplateRef> { ) -> Vec<FontTemplateRef> {
self.find_font_count.set(self.find_font_count.get() + 1); self.find_font_count.fetch_add(1, Ordering::Relaxed);
let SingleFontFamily::FamilyName(family_name) = font_family else { let SingleFontFamily::FamilyName(family_name) = font_family else {
return Vec::new(); return Vec::new();
}; };
self.families self.families
.borrow_mut() .lock()
.get_mut(&*family_name.name) .get_mut(&*family_name.name)
.map(|family| family.find_for_descriptor(descriptor_to_match)) .map(|family| family.find_for_descriptor(descriptor_to_match))
.unwrap_or_default() .unwrap_or_default()
@ -114,25 +126,29 @@ impl FontSource for MockFontCacheThread {
fn get_system_font_instance( fn get_system_font_instance(
&self, &self,
_: FontIdentifier, _font_identifier: FontIdentifier,
_: Au, _size: Au,
_: FontInstanceFlags, _flags: FontInstanceFlags,
) -> FontInstanceKey { ) -> FontInstanceKey {
FontInstanceKey(IdNamespace(0), 0) FontInstanceKey(IdNamespace(0), 0)
} }
fn get_web_font(&self, _: std::sync::Arc<Vec<u8>>, _: u32) -> webrender_api::FontKey { fn get_web_font(&self, _data: Arc<fonts::FontData>, _index: u32) -> FontKey {
FontKey(IdNamespace(0), 0) FontKey(IdNamespace(0), 0)
} }
fn get_web_font_instance( fn get_web_font_instance(
&self, &self,
_: webrender_api::FontKey, _font_key: FontKey,
_: f32, _size: f32,
_: FontInstanceFlags, _flags: FontInstanceFlags,
) -> FontInstanceKey { ) -> FontInstanceKey {
FontInstanceKey(IdNamespace(0), 0) FontInstanceKey(IdNamespace(0), 0)
} }
fn get_font_data(&self, identifier: &FontIdentifier) -> Option<Arc<fonts::FontData>> {
self.data.lock().get(identifier).cloned()
}
} }
fn style() -> FontStyleStruct { fn style() -> FontStyleStruct {
@ -177,7 +193,7 @@ fn mock_resource_threads() -> ResourceThreads {
#[test] #[test]
fn test_font_group_is_cached_by_style() { fn test_font_group_is_cached_by_style() {
let source = MockFontCacheThread::new(); let source = Arc::new(MockFontCacheThread::new());
let context = FontContext::new(source, mock_resource_threads()); let context = FontContext::new(source, mock_resource_threads());
let style1 = style(); let style1 = style();
@ -187,16 +203,16 @@ fn test_font_group_is_cached_by_style() {
assert!( assert!(
std::ptr::eq( std::ptr::eq(
&*context.font_group(Arc::new(style1.clone())).read(), &*context.font_group(ServoArc::new(style1.clone())).read(),
&*context.font_group(Arc::new(style1.clone())).read() &*context.font_group(ServoArc::new(style1.clone())).read()
), ),
"the same font group should be returned for two styles with the same hash" "the same font group should be returned for two styles with the same hash"
); );
assert!( assert!(
!std::ptr::eq( !std::ptr::eq(
&*context.font_group(Arc::new(style1.clone())).read(), &*context.font_group(ServoArc::new(style1.clone())).read(),
&*context.font_group(Arc::new(style2.clone())).read() &*context.font_group(ServoArc::new(style2.clone())).read()
), ),
"different font groups should be returned for two styles with different hashes" "different font groups should be returned for two styles with different hashes"
) )
@ -204,14 +220,13 @@ fn test_font_group_is_cached_by_style() {
#[test] #[test]
fn test_font_group_find_by_codepoint() { fn test_font_group_find_by_codepoint() {
let source = MockFontCacheThread::new(); let source = Arc::new(MockFontCacheThread::new());
let count = source.find_font_count.clone(); let mut context = FontContext::new(source.clone(), mock_resource_threads());
let mut context = FontContext::new(source, mock_resource_threads());
let mut style = style(); let mut style = style();
style.set_font_family(font_family(vec!["CSSTest ASCII", "CSSTest Basic"])); style.set_font_family(font_family(vec!["CSSTest ASCII", "CSSTest Basic"]));
let group = context.font_group(Arc::new(style)); let group = context.font_group(ServoArc::new(style));
let font = group let font = group
.write() .write()
@ -222,7 +237,7 @@ fn test_font_group_find_by_codepoint() {
MockFontCacheThread::identifier_for_font_name("csstest-ascii") MockFontCacheThread::identifier_for_font_name("csstest-ascii")
); );
assert_eq!( assert_eq!(
count.get(), source.find_font_count.fetch_add(0, Ordering::Relaxed),
1, 1,
"only the first font in the list should have been loaded" "only the first font in the list should have been loaded"
); );
@ -236,7 +251,7 @@ fn test_font_group_find_by_codepoint() {
MockFontCacheThread::identifier_for_font_name("csstest-ascii") MockFontCacheThread::identifier_for_font_name("csstest-ascii")
); );
assert_eq!( assert_eq!(
count.get(), source.find_font_count.fetch_add(0, Ordering::Relaxed),
1, 1,
"we shouldn't load the same font a second time" "we shouldn't load the same font a second time"
); );
@ -249,18 +264,22 @@ fn test_font_group_find_by_codepoint() {
font.identifier(), font.identifier(),
MockFontCacheThread::identifier_for_font_name("csstest-basic-regular") MockFontCacheThread::identifier_for_font_name("csstest-basic-regular")
); );
assert_eq!(count.get(), 2, "both fonts should now have been loaded"); assert_eq!(
source.find_font_count.fetch_add(0, Ordering::Relaxed),
2,
"both fonts should now have been loaded"
);
} }
#[test] #[test]
fn test_font_fallback() { fn test_font_fallback() {
let source = MockFontCacheThread::new(); let source = Arc::new(MockFontCacheThread::new());
let mut context = FontContext::new(source, mock_resource_threads()); let mut context = FontContext::new(source, mock_resource_threads());
let mut style = style(); let mut style = style();
style.set_font_family(font_family(vec!["CSSTest ASCII"])); style.set_font_family(font_family(vec!["CSSTest ASCII"]));
let group = context.font_group(Arc::new(style)); let group = context.font_group(ServoArc::new(style));
let font = group let font = group
.write() .write()
@ -285,9 +304,8 @@ fn test_font_fallback() {
#[test] #[test]
fn test_font_template_is_cached() { fn test_font_template_is_cached() {
let source = MockFontCacheThread::new(); let source = Arc::new(MockFontCacheThread::new());
let count = source.find_font_count.clone(); let context = FontContext::new(source.clone(), mock_resource_threads());
let context = FontContext::new(source, mock_resource_threads());
let mut font_descriptor = FontDescriptor { let mut font_descriptor = FontDescriptor {
weight: FontWeight::normal(), weight: FontWeight::normal(),
@ -320,7 +338,7 @@ fn test_font_template_is_cached() {
); );
assert_eq!( assert_eq!(
count.get(), source.find_font_count.fetch_add(0, Ordering::Relaxed),
1, 1,
"we should only have fetched the template data from the cache thread once" "we should only have fetched the template data from the cache thread once"
); );

View file

@ -11,7 +11,7 @@ use std::thread;
use base::id::PipelineId; use base::id::PipelineId;
use fnv::FnvHasher; use fnv::FnvHasher;
use fonts::{FontCacheThread, FontContext}; use fonts::{FontContext, SystemFontServiceProxy};
use net_traits::image_cache::{ use net_traits::image_cache::{
ImageCache, ImageCacheResult, ImageOrMetadataAvailable, UsePlaceholder, ImageCache, ImageCacheResult, ImageOrMetadataAvailable, UsePlaceholder,
}; };
@ -24,7 +24,7 @@ use style::context::{RegisteredSpeculativePainter, SharedStyleContext};
use crate::display_list::items::{OpaqueNode, WebRenderImageInfo}; use crate::display_list::items::{OpaqueNode, WebRenderImageInfo};
pub type LayoutFontContext = FontContext<FontCacheThread>; pub type LayoutFontContext = FontContext<SystemFontServiceProxy>;
type WebrenderImageCache = type WebrenderImageCache =
HashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo, BuildHasherDefault<FnvHasher>>; HashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo, BuildHasherDefault<FnvHasher>>;
@ -44,7 +44,7 @@ pub struct LayoutContext<'a> {
pub image_cache: Arc<dyn ImageCache>, pub image_cache: Arc<dyn ImageCache>,
/// A FontContext to be used during layout. /// A FontContext to be used during layout.
pub font_context: Arc<FontContext<FontCacheThread>>, pub font_context: Arc<FontContext<SystemFontServiceProxy>>,
/// A cache of WebRender image info. /// A cache of WebRender image info.
pub webrender_image_cache: Arc<RwLock<WebrenderImageCache>>, pub webrender_image_cache: Arc<RwLock<WebrenderImageCache>>,

View file

@ -6,7 +6,7 @@ use std::sync::Arc;
use base::id::PipelineId; use base::id::PipelineId;
use fnv::FnvHashMap; use fnv::FnvHashMap;
use fonts::{FontCacheThread, FontContext}; use fonts::{FontContext, SystemFontServiceProxy};
use net_traits::image_cache::{ use net_traits::image_cache::{
ImageCache, ImageCacheResult, ImageOrMetadataAvailable, UsePlaceholder, ImageCache, ImageCacheResult, ImageOrMetadataAvailable, UsePlaceholder,
}; };
@ -27,7 +27,7 @@ pub struct LayoutContext<'a> {
pub style_context: SharedStyleContext<'a>, pub style_context: SharedStyleContext<'a>,
/// A FontContext to be used during layout. /// A FontContext to be used during layout.
pub font_context: Arc<FontContext<FontCacheThread>>, pub font_context: Arc<FontContext<SystemFontServiceProxy>>,
/// Reference to the script thread image cache. /// Reference to the script thread image cache.
pub image_cache: Arc<dyn ImageCache>, pub image_cache: Arc<dyn ImageCache>,

View file

@ -8,7 +8,7 @@ use std::ops::Range;
use app_units::Au; use app_units::Au;
use base::text::is_bidi_control; use base::text::is_bidi_control;
use fonts::{ use fonts::{
FontCacheThread, FontContext, FontRef, GlyphRun, ShapingFlags, ShapingOptions, FontContext, FontRef, GlyphRun, ShapingFlags, ShapingOptions, SystemFontServiceProxy,
LAST_RESORT_GLYPH_ADVANCE, LAST_RESORT_GLYPH_ADVANCE,
}; };
use fonts_traits::ByteIndex; use fonts_traits::ByteIndex;
@ -342,7 +342,7 @@ impl TextRun {
pub(super) fn segment_and_shape( pub(super) fn segment_and_shape(
&mut self, &mut self,
formatting_context_text: &str, formatting_context_text: &str,
font_context: &FontContext<FontCacheThread>, font_context: &FontContext<SystemFontServiceProxy>,
linebreaker: &mut LineBreaker, linebreaker: &mut LineBreaker,
font_cache: &mut Vec<FontKeyAndMetrics>, font_cache: &mut Vec<FontKeyAndMetrics>,
bidi_info: &BidiInfo, bidi_info: &BidiInfo,
@ -410,7 +410,7 @@ impl TextRun {
fn segment_text_by_font( fn segment_text_by_font(
&mut self, &mut self,
formatting_context_text: &str, formatting_context_text: &str,
font_context: &FontContext<FontCacheThread>, font_context: &FontContext<SystemFontServiceProxy>,
font_cache: &mut Vec<FontKeyAndMetrics>, font_cache: &mut Vec<FontKeyAndMetrics>,
bidi_info: &BidiInfo, bidi_info: &BidiInfo,
) -> Vec<(TextRunSegment, FontRef)> { ) -> Vec<(TextRunSegment, FontRef)> {
@ -556,7 +556,7 @@ pub(super) fn add_or_get_font(font: &FontRef, ifc_fonts: &mut Vec<FontKeyAndMetr
pub(super) fn get_font_for_first_font_for_style( pub(super) fn get_font_for_first_font_for_style(
style: &ComputedValues, style: &ComputedValues,
font_context: &FontContext<FontCacheThread>, font_context: &FontContext<SystemFontServiceProxy>,
) -> Option<FontRef> { ) -> Option<FontRef> {
let font = font_context let font = font_context
.font_group(style.clone_font()) .font_group(style.clone_font())

View file

@ -23,8 +23,8 @@ use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as
use euclid::{Point2D, Rect, Scale, Size2D}; use euclid::{Point2D, Rect, Scale, Size2D};
use fnv::FnvHashMap; use fnv::FnvHashMap;
use fonts::{ use fonts::{
get_and_reset_text_shaping_performance_counter, FontCacheThread, FontContext, get_and_reset_text_shaping_performance_counter, FontContext, FontContextWebFontMethods,
FontContextWebFontMethods, SystemFontServiceProxy,
}; };
use fonts_traits::WebFontLoadFinishedCallback; use fonts_traits::WebFontLoadFinishedCallback;
use fxhash::{FxHashMap, FxHashSet}; use fxhash::{FxHashMap, FxHashSet};
@ -133,10 +133,10 @@ pub struct LayoutThread {
/// Reference to the script thread image cache. /// Reference to the script thread image cache.
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
/// A FontContext tFontCacheThreadImplg layout. /// A per-layout FontContext managing font access.
font_context: Arc<FontContext<FontCacheThread>>, font_context: Arc<FontContext<SystemFontServiceProxy>>,
/// Is this the first reflow iFontCacheThreadImplread? /// Is this the first reflow in this layout?
first_reflow: Cell<bool>, first_reflow: Cell<bool>,
/// Flag to indicate whether to use parallel operations /// Flag to indicate whether to use parallel operations
@ -199,7 +199,7 @@ impl LayoutFactory for LayoutFactoryImpl {
config.script_chan, config.script_chan,
config.image_cache, config.image_cache,
config.resource_threads, config.resource_threads,
config.font_cache_thread, config.system_font_service,
config.time_profiler_chan, config.time_profiler_chan,
config.webrender_api_sender, config.webrender_api_sender,
config.paint_time_metrics, config.paint_time_metrics,
@ -560,7 +560,7 @@ impl LayoutThread {
script_chan: IpcSender<ConstellationControlMsg>, script_chan: IpcSender<ConstellationControlMsg>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
resource_threads: ResourceThreads, resource_threads: ResourceThreads,
font_cache_thread: FontCacheThread, system_font_service: Arc<SystemFontServiceProxy>,
time_profiler_chan: profile_time::ProfilerChan, time_profiler_chan: profile_time::ProfilerChan,
webrender_api: WebRenderScriptApi, webrender_api: WebRenderScriptApi,
paint_time_metrics: PaintTimeMetrics, paint_time_metrics: PaintTimeMetrics,
@ -577,7 +577,7 @@ impl LayoutThread {
keyword_info: KeywordInfo::medium(), keyword_info: KeywordInfo::medium(),
}; };
let font_context = Arc::new(FontContext::new(font_cache_thread, resource_threads)); let font_context = Arc::new(FontContext::new(system_font_service, resource_threads));
let device = Device::new( let device = Device::new(
MediaType::screen(), MediaType::screen(),
QuirksMode::NoQuirks, QuirksMode::NoQuirks,

View file

@ -23,7 +23,7 @@ use embedder_traits::resources::{self, Resource};
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D}; use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D};
use euclid::{Point2D, Scale, Size2D, Vector2D}; use euclid::{Point2D, Scale, Size2D, Vector2D};
use fnv::FnvHashMap; use fnv::FnvHashMap;
use fonts::{FontCacheThread, FontContext, FontContextWebFontMethods}; use fonts::{FontContext, FontContextWebFontMethods, SystemFontServiceProxy};
use fonts_traits::WebFontLoadFinishedCallback; use fonts_traits::WebFontLoadFinishedCallback;
use fxhash::FxHashMap; use fxhash::FxHashMap;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
@ -121,7 +121,7 @@ pub struct LayoutThread {
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
/// A FontContext to be used during layout. /// A FontContext to be used during layout.
font_context: Arc<FontContext<FontCacheThread>>, font_context: Arc<FontContext<SystemFontServiceProxy>>,
/// Is this the first reflow in this LayoutThread? /// Is this the first reflow in this LayoutThread?
first_reflow: Cell<bool>, first_reflow: Cell<bool>,
@ -177,7 +177,7 @@ impl LayoutFactory for LayoutFactoryImpl {
config.script_chan, config.script_chan,
config.image_cache, config.image_cache,
config.resource_threads, config.resource_threads,
config.font_cache_thread, config.system_font_service,
config.time_profiler_chan, config.time_profiler_chan,
config.webrender_api_sender, config.webrender_api_sender,
config.paint_time_metrics, config.paint_time_metrics,
@ -502,7 +502,7 @@ impl LayoutThread {
script_chan: IpcSender<ConstellationControlMsg>, script_chan: IpcSender<ConstellationControlMsg>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
resource_threads: ResourceThreads, resource_threads: ResourceThreads,
font_cache_thread: FontCacheThread, system_font_service: Arc<SystemFontServiceProxy>,
time_profiler_chan: profile_time::ProfilerChan, time_profiler_chan: profile_time::ProfilerChan,
webrender_api_sender: WebRenderScriptApi, webrender_api_sender: WebRenderScriptApi,
paint_time_metrics: PaintTimeMetrics, paint_time_metrics: PaintTimeMetrics,
@ -521,7 +521,7 @@ impl LayoutThread {
// The device pixel ratio is incorrect (it does not have the hidpi value), // The device pixel ratio is incorrect (it does not have the hidpi value),
// but it will be set correctly when the initial reflow takes place. // but it will be set correctly when the initial reflow takes place.
let font_context = Arc::new(FontContext::new(font_cache_thread, resource_threads)); let font_context = Arc::new(FontContext::new(system_font_service, resource_threads));
let device = Device::new( let device = Device::new(
MediaType::screen(), MediaType::screen(),
QuirksMode::NoQuirks, QuirksMode::NoQuirks,
@ -1227,7 +1227,7 @@ impl RegisteredSpeculativePainters for RegisteredPaintersImpl {
} }
} }
struct LayoutFontMetricsProvider(Arc<FontContext<FontCacheThread>>); struct LayoutFontMetricsProvider(Arc<FontContext<SystemFontServiceProxy>>);
impl FontMetricsProvider for LayoutFontMetricsProvider { impl FontMetricsProvider for LayoutFontMetricsProvider {
fn query_font_metrics( fn query_font_metrics(

View file

@ -48,7 +48,7 @@ use devtools_traits::{
}; };
use embedder_traits::EmbedderMsg; use embedder_traits::EmbedderMsg;
use euclid::default::{Point2D, Rect}; use euclid::default::{Point2D, Rect};
use fonts::FontCacheThread; use fonts::SystemFontServiceProxy;
use headers::{HeaderMapExt, LastModified, ReferrerPolicy as ReferrerPolicyHeader}; use headers::{HeaderMapExt, LastModified, ReferrerPolicy as ReferrerPolicyHeader};
use html5ever::{local_name, namespace_url, ns}; use html5ever::{local_name, namespace_url, ns};
use hyper_serde::Serde; use hyper_serde::Serde;
@ -593,9 +593,9 @@ pub struct ScriptThread {
#[no_trace] #[no_trace]
layout_to_constellation_chan: IpcSender<LayoutMsg>, layout_to_constellation_chan: IpcSender<LayoutMsg>,
/// The font cache thread to use for layout that happens in this [`ScriptThread`]. /// A proxy to the `SystemFontService` to use for accessing system font lists.
#[no_trace] #[no_trace]
font_cache_thread: FontCacheThread, system_font_service: Arc<SystemFontServiceProxy>,
/// The port on which we receive messages from the image cache /// The port on which we receive messages from the image cache
#[no_trace] #[no_trace]
@ -786,7 +786,7 @@ impl ScriptThreadFactory for ScriptThread {
fn create( fn create(
state: InitialScriptState, state: InitialScriptState,
layout_factory: Arc<dyn LayoutFactory>, layout_factory: Arc<dyn LayoutFactory>,
font_cache_thread: FontCacheThread, system_font_service: Arc<SystemFontServiceProxy>,
load_data: LoadData, load_data: LoadData,
user_agent: Cow<'static, str>, user_agent: Cow<'static, str>,
) { ) {
@ -813,7 +813,7 @@ impl ScriptThreadFactory for ScriptThread {
script_port, script_port,
script_chan.clone(), script_chan.clone(),
layout_factory, layout_factory,
font_cache_thread, system_font_service,
user_agent, user_agent,
); );
@ -1282,7 +1282,7 @@ impl ScriptThread {
port: Receiver<MainThreadScriptMsg>, port: Receiver<MainThreadScriptMsg>,
chan: Sender<MainThreadScriptMsg>, chan: Sender<MainThreadScriptMsg>,
layout_factory: Arc<dyn LayoutFactory>, layout_factory: Arc<dyn LayoutFactory>,
font_cache_thread: FontCacheThread, system_font_service: Arc<SystemFontServiceProxy>,
user_agent: Cow<'static, str>, user_agent: Cow<'static, str>,
) -> ScriptThread { ) -> ScriptThread {
let opts = opts::get(); let opts = opts::get();
@ -1387,7 +1387,7 @@ impl ScriptThread {
mutation_observers: Default::default(), mutation_observers: Default::default(),
layout_to_constellation_chan: state.layout_to_constellation_chan, layout_to_constellation_chan: state.layout_to_constellation_chan,
font_cache_thread, system_font_service,
webgl_chan: state.webgl_chan, webgl_chan: state.webgl_chan,
webxr_registry: state.webxr_registry, webxr_registry: state.webxr_registry,
@ -3657,7 +3657,7 @@ impl ScriptThread {
constellation_chan: self.layout_to_constellation_chan.clone(), constellation_chan: self.layout_to_constellation_chan.clone(),
script_chan: self.control_chan.clone(), script_chan: self.control_chan.clone(),
image_cache: self.image_cache.clone(), image_cache: self.image_cache.clone(),
font_cache_thread: self.font_cache_thread.clone(), system_font_service: self.system_font_service.clone(),
resource_threads: self.resource_threads.clone(), resource_threads: self.resource_threads.clone(),
time_profiler_chan: self.time_profiler_chan.clone(), time_profiler_chan: self.time_profiler_chan.clone(),
webrender_api_sender: self.webrender_api_sender.clone(), webrender_api_sender: self.webrender_api_sender.clone(),

View file

@ -54,7 +54,7 @@ use crossbeam_channel::{unbounded, Sender};
use embedder_traits::{EmbedderMsg, EmbedderProxy, EmbedderReceiver, EventLoopWaker}; use embedder_traits::{EmbedderMsg, EmbedderProxy, EmbedderReceiver, EventLoopWaker};
use env_logger::Builder as EnvLoggerBuilder; use env_logger::Builder as EnvLoggerBuilder;
use euclid::Scale; use euclid::Scale;
use fonts::FontCacheThread; use fonts::SystemFontService;
#[cfg(all( #[cfg(all(
not(target_os = "windows"), not(target_os = "windows"),
not(target_os = "ios"), not(target_os = "ios"),
@ -66,7 +66,7 @@ use fonts::FontCacheThread;
use gaol::sandbox::{ChildSandbox, ChildSandboxMethods}; use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
pub use gleam::gl; pub use gleam::gl;
use gleam::gl::RENDERER; use gleam::gl::RENDERER;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
#[cfg(feature = "layout_2013")] #[cfg(feature = "layout_2013")]
pub use layout_thread_2013; pub use layout_thread_2013;
use log::{error, trace, warn, Log, Metadata, Record}; use log::{error, trace, warn, Log, Metadata, Record};
@ -89,7 +89,6 @@ use surfman::platform::generic::multi::context::NativeContext as LinuxNativeCont
use surfman::{GLApi, GLVersion}; use surfman::{GLApi, GLVersion};
#[cfg(all(target_os = "linux", not(target_env = "ohos")))] #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
use surfman::{NativeConnection, NativeContext}; use surfman::{NativeConnection, NativeContext};
use tracing::{span, Level};
use webgpu::swapchain::WGPUImageMap; use webgpu::swapchain::WGPUImageMap;
use webrender::{RenderApiSender, ShaderPrecacheFlags, UploadMethod, ONE_TIME_USAGE_HINT}; use webrender::{RenderApiSender, ShaderPrecacheFlags, UploadMethod, ONE_TIME_USAGE_HINT};
use webrender_api::{ use webrender_api::{
@ -1040,13 +1039,16 @@ fn create_constellation(
Arc::new(protocols), Arc::new(protocols),
); );
let font_cache_thread = FontCacheThread::new(Box::new(WebRenderFontApiCompositorProxy( let system_font_service = Arc::new(
compositor_proxy.clone(), SystemFontService::spawn(Box::new(WebRenderFontApiCompositorProxy(
))); compositor_proxy.clone(),
)))
.to_proxy(),
);
let (canvas_create_sender, canvas_ipc_sender) = CanvasPaintThread::start( let (canvas_create_sender, canvas_ipc_sender) = CanvasPaintThread::start(
Box::new(CanvasWebrenderApi(compositor_proxy.clone())), Box::new(CanvasWebrenderApi(compositor_proxy.clone())),
font_cache_thread.clone(), system_font_service.clone(),
public_resource_threads.clone(), public_resource_threads.clone(),
); );
@ -1055,7 +1057,7 @@ fn create_constellation(
embedder_proxy, embedder_proxy,
devtools_sender, devtools_sender,
bluetooth_thread, bluetooth_thread,
font_cache_thread, system_font_service,
public_resource_threads, public_resource_threads,
private_resource_threads, private_resource_threads,
time_profiler_chan, time_profiler_chan,
@ -1106,20 +1108,12 @@ impl WebRenderFontApi for WebRenderFontApiCompositorProxy {
receiver.recv().unwrap() receiver.recv().unwrap()
} }
#[tracing::instrument(skip(self), fields(servo_profiling = true))] fn add_font(&self, data: Arc<IpcSharedMemory>, index: u32) -> FontKey {
fn add_font(&self, data: Arc<Vec<u8>>, index: u32) -> FontKey {
let (sender, receiver) = unbounded(); let (sender, receiver) = unbounded();
let (bytes_sender, bytes_receiver) =
ipc::bytes_channel().expect("failed to create IPC channel");
self.0 self.0
.send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Font( .send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Font(
FontToCompositorMsg::AddFont(sender, index, bytes_receiver), FontToCompositorMsg::AddFont(sender, index, data),
))); )));
{
let span = span!(Level::TRACE, "add_font send", servo_profiling = true);
let _span = span.enter();
let _ = bytes_sender.send(&data);
}
receiver.recv().unwrap() receiver.recv().unwrap()
} }
@ -1134,14 +1128,14 @@ impl WebRenderFontApi for WebRenderFontApiCompositorProxy {
fn forward_add_font_message( fn forward_add_font_message(
&self, &self,
bytes_receiver: ipc::IpcBytesReceiver, data: Arc<IpcSharedMemory>,
font_index: u32, font_index: u32,
result_sender: IpcSender<FontKey>, result_sender: IpcSender<FontKey>,
) { ) {
let (sender, receiver) = unbounded(); let (sender, receiver) = unbounded();
self.0 self.0
.send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Font( .send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Font(
FontToCompositorMsg::AddFont(sender, font_index, bytes_receiver), FontToCompositorMsg::AddFont(sender, font_index, data),
))); )));
let _ = result_sender.send(receiver.recv().unwrap()); let _ = result_sender.send(receiver.recv().unwrap());
} }

View file

@ -24,7 +24,7 @@ use canvas_traits::canvas::{CanvasId, CanvasMsg};
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use euclid::default::{Point2D, Rect}; use euclid::default::{Point2D, Rect};
use euclid::Size2D; use euclid::Size2D;
use fonts::FontCacheThread; use fonts::SystemFontServiceProxy;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use libc::c_void; use libc::c_void;
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
@ -175,7 +175,7 @@ pub struct LayoutConfig {
pub script_chan: IpcSender<ConstellationControlMsg>, pub script_chan: IpcSender<ConstellationControlMsg>,
pub image_cache: Arc<dyn ImageCache>, pub image_cache: Arc<dyn ImageCache>,
pub resource_threads: ResourceThreads, pub resource_threads: ResourceThreads,
pub font_cache_thread: FontCacheThread, pub system_font_service: Arc<SystemFontServiceProxy>,
pub time_profiler_chan: time::ProfilerChan, pub time_profiler_chan: time::ProfilerChan,
pub webrender_api_sender: WebRenderScriptApi, pub webrender_api_sender: WebRenderScriptApi,
pub paint_time_metrics: PaintTimeMetrics, pub paint_time_metrics: PaintTimeMetrics,
@ -281,7 +281,7 @@ pub trait ScriptThreadFactory {
fn create( fn create(
state: InitialScriptState, state: InitialScriptState,
layout_factory: Arc<dyn LayoutFactory>, layout_factory: Arc<dyn LayoutFactory>,
font_cache_thread: FontCacheThread, system_font_service: Arc<SystemFontServiceProxy>,
load_data: LoadData, load_data: LoadData,
user_agent: Cow<'static, str>, user_agent: Cow<'static, str>,
); );

View file

@ -15,7 +15,7 @@ use crossbeam_channel::Sender;
use display_list::{CompositorDisplayListInfo, ScrollTreeNodeId}; use display_list::{CompositorDisplayListInfo, ScrollTreeNodeId};
use embedder_traits::Cursor; use embedder_traits::Cursor;
use euclid::default::Size2D; use euclid::default::Size2D;
use ipc_channel::ipc::{self, IpcBytesReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
use libc::c_void; use libc::c_void;
use log::warn; use log::warn;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -190,14 +190,14 @@ pub trait WebRenderFontApi {
size: f32, size: f32,
flags: FontInstanceFlags, flags: FontInstanceFlags,
) -> FontInstanceKey; ) -> FontInstanceKey;
fn add_font(&self, data: Arc<Vec<u8>>, index: u32) -> FontKey; fn add_font(&self, data: Arc<IpcSharedMemory>, index: u32) -> FontKey;
fn add_system_font(&self, handle: NativeFontHandle) -> FontKey; fn add_system_font(&self, handle: NativeFontHandle) -> FontKey;
/// Forward a `AddFont` message, sending it on to the compositor. This is used to get WebRender /// Forward a `AddFont` message, sending it on to the compositor. This is used to get WebRender
/// [`FontKey`]s for web fonts in the per-layout `FontContext`. /// [`FontKey`]s for web fonts in the per-layout `FontContext`.
fn forward_add_font_message( fn forward_add_font_message(
&self, &self,
bytes_receiver: IpcBytesReceiver, data: Arc<IpcSharedMemory>,
font_index: u32, font_index: u32,
result_sender: IpcSender<FontKey>, result_sender: IpcSender<FontKey>,
); );
@ -219,7 +219,7 @@ pub enum CanvasToCompositorMsg {
pub enum FontToCompositorMsg { pub enum FontToCompositorMsg {
AddFontInstance(FontKey, f32, FontInstanceFlags, Sender<FontInstanceKey>), AddFontInstance(FontKey, f32, FontInstanceFlags, Sender<FontInstanceKey>),
AddFont(Sender<FontKey>, u32, IpcBytesReceiver), AddFont(Sender<FontKey>, u32, Arc<IpcSharedMemory>),
AddSystemFont(Sender<FontKey>, NativeFontHandle), AddSystemFont(Sender<FontKey>, NativeFontHandle),
} }