fonts: Simplify FontContext in two ways that affect the unit test (#33541)

This is done by no longer forwarding compositor-bound messages through
SystemFontService and making `FontContext` non-generic:

- Messages from the `FontContext` to the `Compositor` no longer need to be
  forwarded through the `SystemFontService`. Instead send these messages
  directly through the script IPC channel to the `Compositor`.

- Instead of adding a mock `SystemFontServiceProxy`, simply implement a
  mock `SystemFontService` on the other side of an IPC channel in the
  `font_context` unit test. This allows making `FontContext`
  non-generic, greatly simplifying the code. The extra complexity moves
  into the unit test.

These changes necessitate adding a new kind of `FontIdentifier`,
`FontIdentifier::Mock` due to the fact that local fonts have
platform-specific identifiers. This avoids having to pretend like the
system font service can have web fonts -- which was always a bit of a
hack.

These two changes are combined into one PR because they both require
extensive and similar chages in the font_context unit test which
dependended on the details of both of them.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2024-09-25 22:15:47 +02:00 committed by GitHub
parent 1daa0b4fc7
commit ac567645a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 482 additions and 425 deletions

View file

@ -11,7 +11,7 @@ use euclid::default::{Box2D, Point2D, Rect, Size2D, Transform2D, Vector2D};
use euclid::point2; use euclid::point2;
use fonts::{ use fonts::{
ByteIndex, FontBaseline, FontContext, FontGroup, FontMetrics, FontRef, GlyphInfo, GlyphStore, ByteIndex, FontBaseline, FontContext, FontGroup, FontMetrics, FontRef, GlyphInfo, GlyphStore,
ShapingFlags, ShapingOptions, SystemFontServiceProxy, LAST_RESORT_GLYPH_ADVANCE, ShapingFlags, ShapingOptions, 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<SystemFontServiceProxy>>, font_context: Arc<FontContext>,
} }
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<SystemFontServiceProxy>>, font_context: Arc<FontContext>,
) -> 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

@ -17,7 +17,7 @@ use ipc_channel::router::ROUTER;
use log::warn; use log::warn;
use net_traits::ResourceThreads; use net_traits::ResourceThreads;
use webrender_api::ImageKey; use webrender_api::ImageKey;
use webrender_traits::ImageUpdate; use webrender_traits::{ImageUpdate, WebRenderScriptApi};
use crate::canvas_data::*; use crate::canvas_data::*;
@ -37,7 +37,7 @@ 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<SystemFontServiceProxy>>, font_context: Arc<FontContext>,
} }
impl<'a> CanvasPaintThread<'a> { impl<'a> CanvasPaintThread<'a> {
@ -46,11 +46,18 @@ impl<'a> CanvasPaintThread<'a> {
system_font_service: Arc<SystemFontServiceProxy>, system_font_service: Arc<SystemFontServiceProxy>,
resource_threads: ResourceThreads, resource_threads: ResourceThreads,
) -> CanvasPaintThread<'a> { ) -> CanvasPaintThread<'a> {
// This is only used for web fonts and currently canvas never uses web fonts.
let webrender_script_api = WebRenderScriptApi::dummy();
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(system_font_service, resource_threads)), font_context: Arc::new(FontContext::new(
system_font_service,
webrender_script_api,
resource_threads,
)),
} }
} }

View file

@ -9,6 +9,7 @@ use std::fs::{create_dir_all, File};
use std::io::Write; use std::io::Write;
use std::iter::once; use std::iter::once;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use base::cross_process_instant::CrossProcessInstant; use base::cross_process_instant::CrossProcessInstant;
@ -23,7 +24,7 @@ use embedder_traits::Cursor;
use euclid::{Point2D, Rect, Scale, Transform3D, Vector2D}; use euclid::{Point2D, Rect, Scale, Transform3D, Vector2D};
use fnv::{FnvHashMap, FnvHashSet}; use fnv::{FnvHashMap, FnvHashSet};
use image::{DynamicImage, ImageFormat}; use image::{DynamicImage, ImageFormat};
use ipc_channel::ipc; use ipc_channel::ipc::{self, IpcSharedMemory};
use libc::c_void; use libc::c_void;
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use pixels::{CorsStatus, Image, PixelFormat}; use pixels::{CorsStatus, Image, PixelFormat};
@ -43,9 +44,10 @@ use webrender_api::units::{
}; };
use webrender_api::{ use webrender_api::{
self, BuiltDisplayList, DirtyRect, DisplayListPayload, DocumentId, Epoch as WebRenderEpoch, self, BuiltDisplayList, DirtyRect, DisplayListPayload, DocumentId, Epoch as WebRenderEpoch,
ExternalScrollId, FontInstanceOptions, HitTestFlags, PipelineId as WebRenderPipelineId, ExternalScrollId, FontInstanceFlags, FontInstanceKey, FontInstanceOptions, FontKey,
PropertyBinding, ReferenceFrameKind, RenderReasons, SampledScrollOffset, ScrollLocation, HitTestFlags, PipelineId as WebRenderPipelineId, PropertyBinding, ReferenceFrameKind,
SpaceAndClipInfo, SpatialId, SpatialTreeItemKey, TransformStyle, RenderReasons, SampledScrollOffset, ScrollLocation, SpaceAndClipInfo, SpatialId,
SpatialTreeItemKey, TransformStyle,
}; };
use webrender_traits::display_list::{HitTestInfo, ScrollTree}; use webrender_traits::display_list::{HitTestInfo, ScrollTree};
use webrender_traits::{ use webrender_traits::{
@ -841,6 +843,23 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, txn); .send_transaction(self.webrender_document, txn);
}, },
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::AddFont(
data,
index,
key_sender,
)) => {
let _ = key_sender.send(self.add_font(index, data));
},
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::AddFontInstance(
font_key,
size,
flags,
sender,
)) => {
let _ = sender.send(self.add_font_instance(font_key, size, flags));
},
ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::RemoveFonts( ForwardedToCompositorMsg::Layout(ScriptToCompositorMsg::RemoveFonts(
keys, keys,
instance_keys, instance_keys,
@ -865,47 +884,24 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
.send_transaction(self.webrender_document, txn); .send_transaction(self.webrender_document, txn);
}, },
ForwardedToCompositorMsg::Font(FontToCompositorMsg::AddFontInstance( ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFontInstance(
font_key, font_key,
size, size,
flags, flags,
sender, sender,
)) => { )) => {
let key = self.webrender_api.generate_font_instance_key(); let _ = sender.send(self.add_font_instance(font_key, size, flags));
let mut transaction = Transaction::new();
let font_instance_options = FontInstanceOptions {
flags,
..Default::default()
};
transaction.add_font_instance(
key,
font_key,
size,
Some(font_instance_options),
None,
Vec::new(),
);
self.webrender_api
.send_transaction(self.webrender_document, transaction);
let _ = sender.send(key);
}, },
ForwardedToCompositorMsg::Font(FontToCompositorMsg::AddFont( ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFont(
key_sender, key_sender,
index, index,
data, data,
)) => { )) => {
let font_key = self.webrender_api.generate_font_key(); let _ = key_sender.send(self.add_font(index, data));
let mut transaction = Transaction::new();
transaction.add_raw_font(font_key, (**data).into(), index);
self.webrender_api
.send_transaction(self.webrender_document, transaction);
let _ = key_sender.send(font_key);
}, },
ForwardedToCompositorMsg::Font(FontToCompositorMsg::AddSystemFont( ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddSystemFont(
key_sender, key_sender,
native_handle, native_handle,
)) => { )) => {
@ -960,16 +956,26 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.remove_pipeline_root_layer(pipeline_id); self.remove_pipeline_root_layer(pipeline_id);
let _ = sender.send(()); let _ = sender.send(());
}, },
CompositorMsg::Forwarded(ForwardedToCompositorMsg::Font( CompositorMsg::Forwarded(ForwardedToCompositorMsg::SystemFontService(
FontToCompositorMsg::AddFontInstance(_, _, _, sender), FontToCompositorMsg::AddFontInstance(_, _, _, sender),
)) => { )) => {
let _ = sender.send(self.webrender_api.generate_font_instance_key()); let _ = sender.send(self.webrender_api.generate_font_instance_key());
}, },
CompositorMsg::Forwarded(ForwardedToCompositorMsg::Font( CompositorMsg::Forwarded(ForwardedToCompositorMsg::Layout(
ScriptToCompositorMsg::AddFontInstance(_, _, _, sender),
)) => {
let _ = sender.send(self.webrender_api.generate_font_instance_key());
},
CompositorMsg::Forwarded(ForwardedToCompositorMsg::SystemFontService(
FontToCompositorMsg::AddFont(sender, _, _), FontToCompositorMsg::AddFont(sender, _, _),
)) => { )) => {
let _ = sender.send(self.webrender_api.generate_font_key()); let _ = sender.send(self.webrender_api.generate_font_key());
}, },
CompositorMsg::Forwarded(ForwardedToCompositorMsg::Layout(
ScriptToCompositorMsg::AddFont(_, _, sender),
)) => {
let _ = sender.send(self.webrender_api.generate_font_key());
},
CompositorMsg::Forwarded(ForwardedToCompositorMsg::Canvas( CompositorMsg::Forwarded(ForwardedToCompositorMsg::Canvas(
CanvasToCompositorMsg::GenerateKey(sender), CanvasToCompositorMsg::GenerateKey(sender),
)) => { )) => {
@ -2518,4 +2524,40 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
eprintln!("Unable to write servo version for WebRender Capture: {error:?}"); eprintln!("Unable to write servo version for WebRender Capture: {error:?}");
} }
} }
fn add_font_instance(
&mut self,
font_key: FontKey,
size: f32,
flags: FontInstanceFlags,
) -> FontInstanceKey {
let instance_key = self.webrender_api.generate_font_instance_key();
let mut transaction = Transaction::new();
let font_instance_options = FontInstanceOptions {
flags,
..Default::default()
};
transaction.add_font_instance(
instance_key,
font_key,
size,
Some(font_instance_options),
None,
Vec::new(),
);
self.webrender_api
.send_transaction(self.webrender_document, transaction);
instance_key
}
fn add_font(&mut self, index: u32, data: Arc<IpcSharedMemory>) -> FontKey {
let font_key = self.webrender_api.generate_font_key();
let mut transaction = Transaction::new();
transaction.add_raw_font(font_key, (**data).into(), index);
self.webrender_api
.send_transaction(self.webrender_document, transaction);
font_key
}
} }

View file

@ -31,7 +31,7 @@ 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::system_font_service::FontIdentifier;
use crate::{ use crate::{
ByteIndex, EmojiPresentationPreference, FallbackFontSelectionOptions, FontData, GlyphData, ByteIndex, EmojiPresentationPreference, FallbackFontSelectionOptions, FontData, GlyphData,
GlyphId, GlyphStore, Shaper, GlyphId, GlyphStore, Shaper,
@ -550,9 +550,9 @@ 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: SystemFontServiceProxyTrait>( pub fn find_by_codepoint(
&mut self, &mut self,
font_context: &FontContext<S>, font_context: &FontContext,
codepoint: char, codepoint: char,
next_codepoint: Option<char>, next_codepoint: Option<char>,
) -> Option<FontRef> { ) -> Option<FontRef> {
@ -622,10 +622,7 @@ 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: SystemFontServiceProxyTrait>( pub fn first(&mut self, font_context: &FontContext) -> Option<FontRef> {
&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
@ -649,14 +646,13 @@ impl FontGroup {
/// Attempts to find a font which matches the given `template_predicate` and `font_predicate`. /// Attempts to find a font which matches the given `template_predicate` and `font_predicate`.
/// This method mutates because we may need to load new font data in the process of finding /// This method mutates because we may need to load new font data in the process of finding
/// a suitable font. /// a suitable font.
fn find<S, TemplatePredicate, FontPredicate>( fn find<TemplatePredicate, FontPredicate>(
&mut self, &mut self,
font_context: &FontContext<S>, font_context: &FontContext,
template_predicate: TemplatePredicate, template_predicate: TemplatePredicate,
font_predicate: FontPredicate, font_predicate: FontPredicate,
) -> Option<FontRef> ) -> Option<FontRef>
where where
S: SystemFontServiceProxyTrait,
TemplatePredicate: Fn(FontTemplateRef) -> bool, TemplatePredicate: Fn(FontTemplateRef) -> bool,
FontPredicate: Fn(&FontRef) -> bool, FontPredicate: Fn(&FontRef) -> bool,
{ {
@ -678,15 +674,14 @@ impl FontGroup {
/// `font_predicate`. The default family (i.e. "serif") will be tried first, followed by /// `font_predicate`. The default family (i.e. "serif") will be tried first, followed by
/// platform-specific family names. If a `codepoint` is provided, then its Unicode block may be /// platform-specific family names. If a `codepoint` is provided, then its Unicode block may be
/// used to refine the list of family names which will be tried. /// used to refine the list of family names which will be tried.
fn find_fallback<S, TemplatePredicate, FontPredicate>( fn find_fallback<TemplatePredicate, FontPredicate>(
&mut self, &mut self,
font_context: &FontContext<S>, font_context: &FontContext,
options: FallbackFontSelectionOptions, options: FallbackFontSelectionOptions,
template_predicate: TemplatePredicate, template_predicate: TemplatePredicate,
font_predicate: FontPredicate, font_predicate: FontPredicate,
) -> Option<FontRef> ) -> Option<FontRef>
where where
S: SystemFontServiceProxyTrait,
TemplatePredicate: Fn(FontTemplateRef) -> bool, TemplatePredicate: Fn(FontTemplateRef) -> bool,
FontPredicate: Fn(&FontRef) -> bool, FontPredicate: Fn(&FontRef) -> bool,
{ {
@ -750,15 +745,14 @@ impl FontGroupFamily {
} }
} }
fn find<S, TemplatePredicate, FontPredicate>( fn find<TemplatePredicate, FontPredicate>(
&mut self, &mut self,
font_descriptor: &FontDescriptor, font_descriptor: &FontDescriptor,
font_context: &FontContext<S>, font_context: &FontContext,
template_predicate: &TemplatePredicate, template_predicate: &TemplatePredicate,
font_predicate: &FontPredicate, font_predicate: &FontPredicate,
) -> Option<FontRef> ) -> Option<FontRef>
where where
S: SystemFontServiceProxyTrait,
TemplatePredicate: Fn(FontTemplateRef) -> bool, TemplatePredicate: Fn(FontTemplateRef) -> bool,
FontPredicate: Fn(&FontRef) -> bool, FontPredicate: Fn(&FontRef) -> bool,
{ {
@ -781,10 +775,10 @@ impl FontGroupFamily {
.next() .next()
} }
fn members<S: SystemFontServiceProxyTrait>( fn members(
&mut self, &mut self,
font_descriptor: &FontDescriptor, font_descriptor: &FontDescriptor,
font_context: &FontContext<S>, font_context: &FontContext,
) -> impl Iterator<Item = &mut FontGroupFamilyMember> { ) -> impl Iterator<Item = &mut FontGroupFamilyMember> {
let family_descriptor = &self.family_descriptor; let family_descriptor = &self.family_descriptor;
let members = self.members.get_or_insert_with(|| { let members = self.members.get_or_insert_with(|| {

View file

@ -12,6 +12,7 @@ use app_units::Au;
use crossbeam_channel::unbounded; use crossbeam_channel::unbounded;
use fnv::FnvHasher; use fnv::FnvHasher;
use fonts_traits::WebFontLoadFinishedCallback; use fonts_traits::WebFontLoadFinishedCallback;
use ipc_channel::ipc;
use log::{debug, trace}; use log::{debug, trace};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
@ -29,7 +30,8 @@ use style::stylesheets::{CssRule, DocumentStyleSheet, FontFaceRule, StylesheetIn
use style::values::computed::font::{FamilyName, FontFamilyNameSyntax, SingleFontFamily}; use style::values::computed::font::{FamilyName, FontFamilyNameSyntax, SingleFontFamily};
use style::Atom; use style::Atom;
use url::Url; use url::Url;
use webrender_api::{FontInstanceKey, FontKey}; use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey};
use webrender_traits::{ScriptToCompositorMsg, WebRenderScriptApi};
use crate::font::{ use crate::font::{
Font, FontDescriptor, FontFamilyDescriptor, FontGroup, FontRef, FontSearchScope, Font, FontDescriptor, FontFamilyDescriptor, FontGroup, FontRef, FontSearchScope,
@ -37,10 +39,8 @@ use crate::font::{
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::platform::font::PlatformFont; use crate::platform::font::PlatformFont;
use crate::system_font_service::{ use crate::system_font_service::{CSSFontFaceDescriptors, FontIdentifier};
CSSFontFaceDescriptors, FontIdentifier, SystemFontServiceProxyTrait, use crate::{FontData, LowercaseFontFamilyName, PlatformFontMethods, SystemFontServiceProxy};
};
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)
@ -48,10 +48,13 @@ static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8; // Matches FireFox (see gfxFont.h)
/// 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 system font service where /// paint code. It talks directly to the system font service where
/// required. /// required.
pub struct FontContext<Proxy: SystemFontServiceProxyTrait> { pub struct FontContext {
pub(crate) system_font_service_proxy: Arc<Proxy>, pub(crate) system_font_service_proxy: Arc<SystemFontServiceProxy>,
resource_threads: ReentrantMutex<CoreResourceThread>, resource_threads: ReentrantMutex<CoreResourceThread>,
/// A sender that can send messages and receive replies from the compositor.
webrender_api: ReentrantMutex<WebRenderScriptApi>,
/// The actual instances of fonts ie a [`FontTemplate`] combined with a size and /// 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. /// other font properties, along with the font data and a platform font instance.
fonts: RwLock<HashMap<FontCacheKey, Option<FontRef>>>, fonts: RwLock<HashMap<FontCacheKey, Option<FontRef>>>,
@ -67,7 +70,7 @@ pub struct FontContext<Proxy: SystemFontServiceProxyTrait> {
have_removed_web_fonts: AtomicBool, have_removed_web_fonts: AtomicBool,
} }
impl<S: SystemFontServiceProxyTrait> MallocSizeOf for FontContext<S> { impl MallocSizeOf for FontContext {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
let font_cache_size = self let font_cache_size = self
.fonts .fonts
@ -87,12 +90,17 @@ impl<S: SystemFontServiceProxyTrait> MallocSizeOf for FontContext<S> {
} }
} }
impl<Proxy: SystemFontServiceProxyTrait> FontContext<Proxy> { impl FontContext {
pub fn new(system_font_service_proxy: Arc<Proxy>, resource_threads: ResourceThreads) -> Self { pub fn new(
system_font_service_proxy: Arc<SystemFontServiceProxy>,
webrender_api: WebRenderScriptApi,
resource_threads: ResourceThreads,
) -> Self {
#[allow(clippy::default_constructed_unit_structs)] #[allow(clippy::default_constructed_unit_structs)]
Self { Self {
system_font_service_proxy, system_font_service_proxy,
resource_threads: ReentrantMutex::new(resource_threads.core_thread), resource_threads: ReentrantMutex::new(resource_threads.core_thread),
webrender_api: ReentrantMutex::new(webrender_api),
fonts: Default::default(), fonts: Default::default(),
resolved_font_groups: Default::default(), resolved_font_groups: Default::default(),
web_fonts: Arc::new(RwLock::default()), web_fonts: Arc::new(RwLock::default()),
@ -106,10 +114,12 @@ impl<Proxy: SystemFontServiceProxyTrait> FontContext<Proxy> {
} }
pub(crate) fn get_font_data(&self, identifier: &FontIdentifier) -> Arc<FontData> { pub(crate) fn get_font_data(&self, identifier: &FontIdentifier) -> Arc<FontData> {
self.web_fonts match identifier {
.read() FontIdentifier::Web(_) => self.web_fonts.read().get_font_data(identifier),
.get_font_data(identifier) FontIdentifier::Local(_) | FontIdentifier::Mock(_) => {
.or_else(|| self.system_font_service_proxy.get_font_data(identifier)) self.system_font_service_proxy.get_font_data(identifier)
},
}
.expect("Could not find font data") .expect("Could not find font data")
} }
@ -272,11 +282,13 @@ impl<Proxy: SystemFontServiceProxyTrait> FontContext<Proxy> {
)?; )?;
font.font_key = match font_template.identifier() { font.font_key = match font_template.identifier() {
FontIdentifier::Local(_) => self.system_font_service_proxy.get_system_font_instance( FontIdentifier::Local(_) | FontIdentifier::Mock(_) => {
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(
self, self,
font_template.clone(), font_template.clone(),
@ -291,6 +303,42 @@ impl<Proxy: SystemFontServiceProxyTrait> FontContext<Proxy> {
fn invalidate_font_groups_after_web_font_load(&self) { fn invalidate_font_groups_after_web_font_load(&self) {
self.resolved_font_groups.write().clear(); self.resolved_font_groups.write().clear();
} }
pub(crate) fn get_web_font(&self, data: Arc<FontData>, index: u32) -> FontKey {
let (result_sender, result_receiver) =
ipc::channel().expect("failed to create IPC channel");
let _ = self
.webrender_api
.lock()
.sender()
.send(ScriptToCompositorMsg::AddFont(
data.as_ipc_shared_memory(),
index,
result_sender,
));
result_receiver.recv().unwrap()
}
pub(crate) fn get_web_font_instance(
&self,
font_key: FontKey,
font_size: f32,
font_flags: FontInstanceFlags,
) -> FontInstanceKey {
let (result_sender, result_receiver) =
ipc::channel().expect("failed to create IPC channel");
let _ = self
.webrender_api
.lock()
.sender()
.send(ScriptToCompositorMsg::AddFontInstance(
font_key,
font_size,
font_flags,
result_sender,
));
result_receiver.recv().unwrap()
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -318,7 +366,7 @@ pub trait FontContextWebFontMethods {
-> (Vec<FontKey>, Vec<FontInstanceKey>); -> (Vec<FontKey>, Vec<FontInstanceKey>);
} }
impl<S: SystemFontServiceProxyTrait + 'static> FontContextWebFontMethods for Arc<FontContext<S>> { impl FontContextWebFontMethods for Arc<FontContext> {
fn add_all_web_fonts_from_stylesheet( fn add_all_web_fonts_from_stylesheet(
&self, &self,
stylesheet: &DocumentStyleSheet, stylesheet: &DocumentStyleSheet,
@ -523,8 +571,8 @@ impl<S: SystemFontServiceProxyTrait + 'static> FontContextWebFontMethods for Arc
} }
} }
struct RemoteWebFontDownloader<Proxy: SystemFontServiceProxyTrait> { struct RemoteWebFontDownloader {
font_context: Arc<FontContext<Proxy>>, font_context: Arc<FontContext>,
url: ServoArc<Url>, url: ServoArc<Url>,
web_font_family_name: LowercaseFontFamilyName, web_font_family_name: LowercaseFontFamilyName,
response_valid: Mutex<bool>, response_valid: Mutex<bool>,
@ -537,10 +585,10 @@ enum DownloaderResponseResult {
Failure, Failure,
} }
impl<Proxy: SystemFontServiceProxyTrait + 'static> RemoteWebFontDownloader<Proxy> { impl RemoteWebFontDownloader {
fn download( fn download(
url_source: UrlSource, url_source: UrlSource,
font_context: Arc<FontContext<Proxy>>, font_context: Arc<FontContext>,
web_font_family_name: LowercaseFontFamilyName, web_font_family_name: LowercaseFontFamilyName,
state: WebFontDownloadState, state: WebFontDownloadState,
) { ) {
@ -628,12 +676,11 @@ impl<Proxy: SystemFontServiceProxyTrait + 'static> RemoteWebFontDownloader<Proxy
descriptor descriptor
.override_values_with_css_font_template_descriptors(&state.css_font_face_descriptors); .override_values_with_css_font_template_descriptors(&state.css_font_face_descriptors);
let Ok(new_template) = let new_template = FontTemplate::new(
FontTemplate::new_for_remote_web_font(url, descriptor, Some(state.stylesheet.clone())) FontIdentifier::Web(url),
else { descriptor,
return false; Some(state.stylesheet.clone()),
}; );
let not_cancelled = self.font_context.web_fonts.write().handle_web_font_loaded( let not_cancelled = self.font_context.web_fonts.write().handle_web_font_loaded(
state, state,
new_template, new_template,

View file

@ -18,9 +18,7 @@ use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey};
use crate::font::FontDescriptor; use crate::font::FontDescriptor;
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::{ use crate::system_font_service::{FontIdentifier, LowercaseFontFamilyName};
FontIdentifier, LowercaseFontFamilyName, SystemFontServiceProxyTrait,
};
use crate::FontContext; use crate::FontContext;
/// A data structure to store data for fonts. If sent across IPC channels and only a /// A data structure to store data for fonts. If sent across IPC channels and only a
@ -171,7 +169,7 @@ impl FontStore {
FontIdentifier::Local(local_identifier) => { FontIdentifier::Local(local_identifier) => {
Arc::new(FontData::from_bytes(local_identifier.read_data_from_file())) Arc::new(FontData::from_bytes(local_identifier.read_data_from_file()))
}, },
FontIdentifier::Web(_) => unreachable!("Web fonts should always have data."), _ => unreachable!("Web and mock fonts should always have data."),
}) })
} }
@ -196,9 +194,9 @@ 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<Proxy: SystemFontServiceProxyTrait>( pub(crate) fn get_font_instance(
&mut self, &mut self,
font_context: &FontContext<Proxy>, font_context: &FontContext,
font_template: FontTemplateRef, font_template: FontTemplateRef,
pt_size: Au, pt_size: Au,
flags: FontInstanceFlags, flags: FontInstanceFlags,
@ -210,18 +208,14 @@ impl WebRenderFontStore {
.entry(identifier.clone()) .entry(identifier.clone())
.or_insert_with(|| { .or_insert_with(|| {
let data = font_context.get_font_data(&identifier); let data = font_context.get_font_data(&identifier);
font_context font_context.get_web_font(data, identifier.index())
.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_context font_context.get_web_font_instance(font_key, pt_size.to_f32_px(), flags)
.system_font_service_proxy
.get_web_font_instance(font_key, pt_size.to_f32_px(), flags)
}) })
} }

View file

@ -9,14 +9,12 @@ use std::sync::Arc;
use atomic_refcell::AtomicRefCell; use atomic_refcell::AtomicRefCell;
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use servo_url::ServoUrl;
use style::computed_values::font_stretch::T as FontStretch; use style::computed_values::font_stretch::T as FontStretch;
use style::computed_values::font_style::T as FontStyle; 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; use crate::font::FontDescriptor;
use crate::platform::font_list::LocalFontIdentifier;
use crate::system_font_service::{ use crate::system_font_service::{
CSSFontFaceDescriptors, ComputedFontStyleDescriptor, FontIdentifier, CSSFontFaceDescriptors, ComputedFontStyleDescriptor, FontIdentifier,
}; };
@ -160,29 +158,17 @@ impl Debug for FontTemplate {
/// is common, regardless of the number of instances of /// is common, regardless of the number of instances of
/// this font handle per thread. /// this font handle per thread.
impl FontTemplate { impl FontTemplate {
/// Create a new [`FontTemplate`] for a system font installed locally. /// Create a new [`FontTemplate`].
pub fn new_for_local_font( pub fn new(
identifier: LocalFontIdentifier, identifier: FontIdentifier,
descriptor: FontTemplateDescriptor,
) -> FontTemplate {
FontTemplate {
identifier: FontIdentifier::Local(identifier),
descriptor,
stylesheet: None,
}
}
/// Create a new [`FontTemplate`] for a `@font-family` with a `url(...)` `src` font.
pub fn new_for_remote_web_font(
url: ServoUrl,
descriptor: FontTemplateDescriptor, descriptor: FontTemplateDescriptor,
stylesheet: Option<DocumentStyleSheet>, stylesheet: Option<DocumentStyleSheet>,
) -> Result<FontTemplate, &'static str> { ) -> FontTemplate {
Ok(FontTemplate { FontTemplate {
identifier: FontIdentifier::Web(url), identifier,
descriptor, descriptor,
stylesheet, stylesheet,
}) }
} }
/// Create a new [`FontTemplate`] for a `@font-family` with a `local(...)` `src`. This takes in /// Create a new [`FontTemplate`] for a `@font-family` with a `local(...)` `src`. This takes in

View file

@ -19,7 +19,8 @@ use style::Atom;
use super::xml::{Attribute, Node}; use super::xml::{Attribute, Node};
use crate::{ use crate::{
FallbackFontSelectionOptions, FontTemplate, FontTemplateDescriptor, LowercaseFontFamilyName, FallbackFontSelectionOptions, FontIdentifier, FontTemplate, FontTemplateDescriptor,
LowercaseFontFamilyName,
}; };
static FONT_LIST: LazyLock<FontList> = LazyLock::new(|| FontList::new()); static FONT_LIST: LazyLock<FontList> = LazyLock::new(|| FontList::new());
@ -491,9 +492,10 @@ where
None => StyleFontStyle::NORMAL, None => StyleFontStyle::NORMAL,
}; };
let descriptor = FontTemplateDescriptor::new(weight, stretch, style); let descriptor = FontTemplateDescriptor::new(weight, stretch, style);
callback(FontTemplate::new_for_local_font( callback(FontTemplate::new(
local_font_identifier, FontIdentifier::Local(local_font_identifier),
descriptor, descriptor,
None,
)); ));
}; };

View file

@ -36,7 +36,10 @@ use super::c_str_to_string;
use crate::font::map_platform_values_to_style_values; use crate::font::map_platform_values_to_style_values;
use crate::font_template::{FontTemplate, FontTemplateDescriptor}; use crate::font_template::{FontTemplate, FontTemplateDescriptor};
use crate::platform::add_noto_fallback_families; use crate::platform::add_noto_fallback_families;
use crate::{EmojiPresentationPreference, FallbackFontSelectionOptions, LowercaseFontFamilyName}; use crate::{
EmojiPresentationPreference, FallbackFontSelectionOptions, FontIdentifier,
LowercaseFontFamilyName,
};
/// An identifier for a local font on systems using Freetype. /// An identifier for a local font on systems using Freetype.
#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] #[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
@ -155,9 +158,10 @@ where
}; };
let descriptor = FontTemplateDescriptor::new(weight, stretch, style); let descriptor = FontTemplateDescriptor::new(weight, stretch, style);
callback(FontTemplate::new_for_local_font( callback(FontTemplate::new(
local_font_identifier, FontIdentifier::Local(local_font_identifier),
descriptor, descriptor,
None,
)) ))
} }

View file

@ -22,7 +22,7 @@ use style::Atom;
use unicode_script::Script; use unicode_script::Script;
use crate::{ use crate::{
EmojiPresentationPreference, FallbackFontSelectionOptions, FontTemplate, EmojiPresentationPreference, FallbackFontSelectionOptions, FontIdentifier, FontTemplate,
FontTemplateDescriptor, LowercaseFontFamilyName, FontTemplateDescriptor, LowercaseFontFamilyName,
}; };
@ -492,9 +492,10 @@ where
None => StyleFontStyle::NORMAL, None => StyleFontStyle::NORMAL,
}; };
let descriptor = FontTemplateDescriptor::new(weight, stretch, style); let descriptor = FontTemplateDescriptor::new(weight, stretch, style);
callback(FontTemplate::new_for_local_font( callback(FontTemplate::new(
local_font_identifier, FontIdentifier::Local(local_font_identifier),
descriptor, descriptor,
None,
)); ));
}; };

View file

@ -86,7 +86,7 @@ impl CoreTextFontCache {
core_text::font::new_from_descriptor(&descriptor, clamped_pt_size) core_text::font::new_from_descriptor(&descriptor, clamped_pt_size)
}, },
FontIdentifier::Web(_) => { FontIdentifier::Web(_) | FontIdentifier::Mock(_) => {
let provider = CGDataProvider::from_buffer(data); let provider = CGDataProvider::from_buffer(data);
let cgfont = CGFont::from_data_provider(provider).ok()?; let cgfont = CGFont::from_data_provider(provider).ok()?;
core_text::font::new_from_CGFont(&cgfont, clamped_pt_size) core_text::font::new_from_CGFont(&cgfont, clamped_pt_size)

View file

@ -18,7 +18,7 @@ use webrender_api::NativeFontHandle;
use crate::platform::add_noto_fallback_families; use crate::platform::add_noto_fallback_families;
use crate::platform::font::CoreTextFontTraitsMapping; use crate::platform::font::CoreTextFontTraitsMapping;
use crate::{ use crate::{
EmojiPresentationPreference, FallbackFontSelectionOptions, FontTemplate, EmojiPresentationPreference, FallbackFontSelectionOptions, FontIdentifier, FontTemplate,
FontTemplateDescriptor, LowercaseFontFamilyName, FontTemplateDescriptor, LowercaseFontFamilyName,
}; };
@ -85,7 +85,11 @@ where
postscript_name: Atom::from(family_descriptor.font_name()), postscript_name: Atom::from(family_descriptor.font_name()),
path: Atom::from(path), path: Atom::from(path),
}; };
callback(FontTemplate::new_for_local_font(identifier, descriptor)); callback(FontTemplate::new(
FontIdentifier::Local(identifier),
descriptor,
None,
));
} }
} }
} }

View file

@ -14,7 +14,7 @@ use style::values::computed::{FontStyle as StyleFontStyle, FontWeight as StyleFo
use style::values::specified::font::FontStretchKeyword; use style::values::specified::font::FontStretchKeyword;
use crate::{ use crate::{
EmojiPresentationPreference, FallbackFontSelectionOptions, FontTemplate, EmojiPresentationPreference, FallbackFontSelectionOptions, FontIdentifier, FontTemplate,
FontTemplateDescriptor, LowercaseFontFamilyName, FontTemplateDescriptor, LowercaseFontFamilyName,
}; };
@ -78,9 +78,10 @@ where
let local_font_identifier = LocalFontIdentifier { let local_font_identifier = LocalFontIdentifier {
font_descriptor: Arc::new(font.to_descriptor()), font_descriptor: Arc::new(font.to_descriptor()),
}; };
callback(FontTemplate::new_for_local_font( callback(FontTemplate::new(
local_font_identifier, FontIdentifier::Local(local_font_identifier),
template_descriptor, template_descriptor,
None,
)) ))
} }
} }

View file

@ -24,6 +24,7 @@ use style::values::computed::font::{
}; };
use style::values::computed::{FontStretch, FontWeight}; use style::values::computed::{FontStretch, FontWeight};
use style::values::specified::FontStretch as SpecifiedFontStretch; use style::values::specified::FontStretch as SpecifiedFontStretch;
use style::Atom;
use tracing::{span, Level}; use tracing::{span, Level};
use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey}; use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey};
use webrender_traits::WebRenderFontApi; use webrender_traits::WebRenderFontApi;
@ -41,26 +42,27 @@ use crate::FontData;
pub enum FontIdentifier { pub enum FontIdentifier {
Local(LocalFontIdentifier), Local(LocalFontIdentifier),
Web(ServoUrl), Web(ServoUrl),
Mock(Atom),
} }
impl FontIdentifier { impl FontIdentifier {
pub fn index(&self) -> u32 { pub fn index(&self) -> u32 {
match *self { match *self {
Self::Local(ref local_font_identifier) => local_font_identifier.index(), Self::Local(ref local_font_identifier) => local_font_identifier.index(),
Self::Web(_) => 0, Self::Web(_) | Self::Mock(_) => 0,
} }
} }
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Default, Deserialize, Serialize)]
pub struct FontTemplateRequestResult { pub struct FontTemplateRequestResult {
templates: Vec<FontTemplate>, pub templates: Vec<FontTemplate>,
template_data: Vec<(FontIdentifier, Arc<FontData>)>, pub template_data: Vec<(FontIdentifier, Arc<FontData>)>,
} }
/// Commands that the `FontContext` sends to the `SystemFontService`. /// Commands that the `FontContext` sends to the `SystemFontService`.
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub enum Command { pub enum SystemFontServiceMessage {
GetFontTemplates( GetFontTemplates(
Option<FontDescriptor>, Option<FontDescriptor>,
SingleFontFamily, SingleFontFamily,
@ -72,8 +74,6 @@ pub enum Command {
FontInstanceFlags, FontInstanceFlags,
IpcSender<FontInstanceKey>, IpcSender<FontInstanceKey>,
), ),
GetWebFont(Arc<FontData>, u32, IpcSender<FontKey>),
GetWebFontInstance(FontKey, f32, FontInstanceFlags, IpcSender<FontInstanceKey>),
Exit(IpcSender<()>), Exit(IpcSender<()>),
Ping, Ping,
} }
@ -93,7 +93,7 @@ struct ResolvedGenericFontFamilies {
/// responsible for reading the list of system fonts, handling requests to match against /// responsible for reading the list of system fonts, handling requests to match against
/// them, and ensuring that only one copy of system font data is loaded at a time. /// them, and ensuring that only one copy of system font data is loaded at a time.
pub struct SystemFontService { pub struct SystemFontService {
port: IpcReceiver<Command>, port: IpcReceiver<SystemFontServiceMessage>,
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,7 +102,7 @@ pub struct SystemFontService {
} }
#[derive(Clone, Deserialize, Serialize)] #[derive(Clone, Deserialize, Serialize)]
pub struct SystemFontServiceProxySender(IpcSender<Command>); pub struct SystemFontServiceProxySender(pub IpcSender<SystemFontServiceMessage>);
impl SystemFontServiceProxySender { impl SystemFontServiceProxySender {
pub fn to_proxy(&self) -> SystemFontServiceProxy { pub fn to_proxy(&self) -> SystemFontServiceProxy {
@ -145,37 +145,21 @@ impl SystemFontService {
let msg = self.port.recv().unwrap(); let msg = self.port.recv().unwrap();
match msg { match msg {
Command::GetFontTemplates(font_descriptor, font_family, result_sender) => { SystemFontServiceMessage::GetFontTemplates(
font_descriptor,
font_family,
result_sender,
) => {
let span = span!(Level::TRACE, "GetFontTemplates", servo_profiling = true); let span = span!(Level::TRACE, "GetFontTemplates", servo_profiling = true);
let _span = span.enter(); let _span = span.enter();
let _ = let _ =
result_sender.send(self.get_font_templates(font_descriptor, font_family)); result_sender.send(self.get_font_templates(font_descriptor, font_family));
}, },
Command::GetFontInstance(identifier, pt_size, flags, result) => { SystemFontServiceMessage::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(data, font_index, result_sender) => { SystemFontServiceMessage::Ping => (),
self.webrender_api.forward_add_font_message( SystemFontServiceMessage::Exit(result) => {
data.as_ipc_shared_memory(),
font_index,
result_sender,
);
},
Command::GetWebFontInstance(
font_key,
font_size,
font_instance_flags,
result_sender,
) => {
self.webrender_api.forward_add_font_instance_message(
font_key,
font_size,
font_instance_flags,
result_sender,
);
},
Command::Ping => (),
Command::Exit(result) => {
let _ = result.send(()); let _ = result.send(());
break; break;
}, },
@ -325,40 +309,17 @@ impl SystemFontService {
} }
} }
/// A trait for accessing the [`SystemFontServiceProxy`] necessary for unit testing.
pub trait SystemFontServiceProxyTrait: Send + Sync {
fn find_matching_font_templates(
&self,
descriptor_to_match: Option<&FontDescriptor>,
font_family_name: &SingleFontFamily,
) -> Vec<FontTemplateRef>;
fn get_system_font_instance(
&self,
font_identifier: FontIdentifier,
size: Au,
flags: FontInstanceFlags,
) -> FontInstanceKey;
fn get_web_font(&self, data: Arc<FontData>, index: u32) -> FontKey;
fn get_web_font_instance(
&self,
font_key: FontKey,
size: f32,
flags: FontInstanceFlags,
) -> FontInstanceKey;
fn get_font_data(&self, identifier: &FontIdentifier) -> Option<Arc<FontData>>;
}
#[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)] #[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)]
struct FontTemplateCacheKey { struct FontTemplateCacheKey {
font_descriptor: Option<FontDescriptor>, font_descriptor: Option<FontDescriptor>,
family_descriptor: SingleFontFamily, family_descriptor: SingleFontFamily,
} }
/// The public interface to the [`SystemFontService`], used by per-Document `FontContext` /// The public interface to the [`SystemFontService`], used by per-Document
/// instances (via [`SystemFontServiceProxyTrait`]). /// `FontContext` instances.
#[derive(Debug)] #[derive(Debug)]
pub struct SystemFontServiceProxy { pub struct SystemFontServiceProxy {
sender: ReentrantMutex<IpcSender<Command>>, sender: ReentrantMutex<IpcSender<SystemFontServiceMessage>>,
templates: RwLock<HashMap<FontTemplateCacheKey, Vec<FontTemplateRef>>>, templates: RwLock<HashMap<FontTemplateCacheKey, Vec<FontTemplateRef>>>,
data_cache: RwLock<HashMap<FontIdentifier, Arc<FontData>>>, data_cache: RwLock<HashMap<FontIdentifier, Arc<FontData>>>,
} }
@ -453,7 +414,7 @@ impl SystemFontServiceProxy {
let (response_chan, response_port) = ipc::channel().unwrap(); let (response_chan, response_port) = ipc::channel().unwrap();
self.sender self.sender
.lock() .lock()
.send(Command::Exit(response_chan)) .send(SystemFontServiceMessage::Exit(response_chan))
.expect("Couldn't send SystemFontService exit message"); .expect("Couldn't send SystemFontService exit message");
response_port response_port
.recv() .recv()
@ -463,10 +424,8 @@ impl SystemFontServiceProxy {
pub fn to_sender(&self) -> SystemFontServiceProxySender { pub fn to_sender(&self) -> SystemFontServiceProxySender {
SystemFontServiceProxySender(self.sender.lock().clone()) SystemFontServiceProxySender(self.sender.lock().clone())
} }
}
impl SystemFontServiceProxyTrait for SystemFontServiceProxy { pub(crate) fn get_system_font_instance(
fn get_system_font_instance(
&self, &self,
identifier: FontIdentifier, identifier: FontIdentifier,
size: Au, size: Au,
@ -475,7 +434,7 @@ impl SystemFontServiceProxyTrait for SystemFontServiceProxy {
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.sender self.sender
.lock() .lock()
.send(Command::GetFontInstance( .send(SystemFontServiceMessage::GetFontInstance(
identifier, identifier,
size, size,
flags, flags,
@ -485,7 +444,11 @@ impl SystemFontServiceProxyTrait for SystemFontServiceProxy {
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.sender.lock().send(Command::Ping).is_err(); let font_thread_has_closed = self
.sender
.lock()
.send(SystemFontServiceMessage::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"
@ -495,7 +458,7 @@ impl SystemFontServiceProxyTrait for SystemFontServiceProxy {
instance_key.unwrap() instance_key.unwrap()
} }
fn find_matching_font_templates( pub(crate) fn find_matching_font_templates(
&self, &self,
descriptor_to_match: Option<&FontDescriptor>, descriptor_to_match: Option<&FontDescriptor>,
family_descriptor: &SingleFontFamily, family_descriptor: &SingleFontFamily,
@ -516,7 +479,7 @@ impl SystemFontServiceProxyTrait for SystemFontServiceProxy {
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.sender self.sender
.lock() .lock()
.send(Command::GetFontTemplates( .send(SystemFontServiceMessage::GetFontTemplates(
descriptor_to_match.cloned(), descriptor_to_match.cloned(),
family_descriptor.clone(), family_descriptor.clone(),
response_chan, response_chan,
@ -525,7 +488,11 @@ impl SystemFontServiceProxyTrait for SystemFontServiceProxy {
let reply = response_port.recv(); let reply = response_port.recv();
let Ok(reply) = reply else { let Ok(reply) = reply else {
let font_thread_has_closed = self.sender.lock().send(Command::Ping).is_err(); let font_thread_has_closed = self
.sender
.lock()
.send(SystemFontServiceMessage::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"
@ -544,34 +511,7 @@ impl SystemFontServiceProxyTrait for SystemFontServiceProxy {
templates templates
} }
fn get_web_font(&self, data: Arc<FontData>, index: u32) -> FontKey { pub(crate) fn get_font_data(&self, identifier: &FontIdentifier) -> Option<Arc<FontData>> {
let (result_sender, result_receiver) =
ipc::channel().expect("failed to create IPC channel");
let _ = self
.sender
.lock()
.send(Command::GetWebFont(data, index, result_sender));
result_receiver.recv().unwrap()
}
fn get_web_font_instance(
&self,
font_key: FontKey,
font_size: f32,
font_flags: FontInstanceFlags,
) -> FontInstanceKey {
let (result_sender, result_receiver) =
ipc::channel().expect("failed to create IPC channel");
let _ = self.sender.lock().send(Command::GetWebFontInstance(
font_key,
font_size,
font_flags,
result_sender,
));
result_receiver.recv().unwrap()
}
fn get_font_data(&self, identifier: &FontIdentifier) -> Option<Arc<FontData>> {
self.data_cache.read().get(identifier).cloned() self.data_cache.read().get(identifier).cloned()
} }
} }

View file

@ -8,20 +8,21 @@ use std::io::prelude::*;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::atomic::{AtomicI32, Ordering}; use std::sync::atomic::{AtomicI32, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::thread;
use app_units::Au; use app_units::Au;
use fonts::platform::font::PlatformFont; use fonts::platform::font::PlatformFont;
use fonts::{ use fonts::{
fallback_font_families, FallbackFontSelectionOptions, FontContext, FontData, FontDescriptor, fallback_font_families, FallbackFontSelectionOptions, FontContext, FontData, FontDescriptor,
FontFamilyDescriptor, FontIdentifier, FontSearchScope, FontTemplate, FontTemplateRef, FontFamilyDescriptor, FontIdentifier, FontSearchScope, FontTemplate, FontTemplateRequestResult,
FontTemplates, PlatformFontMethods, SystemFontServiceProxyTrait, FontTemplates, PlatformFontMethods, SystemFontServiceMessage, SystemFontServiceProxy,
SystemFontServiceProxySender,
}; };
use ipc_channel::ipc; use ipc_channel::ipc::{self, IpcReceiver};
use net_traits::ResourceThreads; use net_traits::ResourceThreads;
use parking_lot::Mutex; use parking_lot::Mutex;
use servo_arc::Arc as ServoArc; use servo_arc::Arc as ServoArc;
use servo_atoms::Atom; use servo_atoms::Atom;
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;
use style::properties::style_structs::Font as FontStyleStruct; use style::properties::style_structs::Font as FontStyleStruct;
use style::values::computed::font::{ use style::values::computed::font::{
@ -31,15 +32,111 @@ use style::values::computed::font::{
use style::values::computed::{FontLanguageOverride, XLang}; use style::values::computed::{FontLanguageOverride, XLang};
use style::values::generics::font::LineHeight; use style::values::generics::font::LineHeight;
use style::ArcSlice; use style::ArcSlice;
use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey, IdNamespace}; use webrender_api::{FontInstanceKey, IdNamespace};
use webrender_traits::WebRenderScriptApi;
struct MockFontCacheThread { struct TestContext {
context: FontContext,
system_font_service: Arc<MockSystemFontService>,
system_font_service_proxy: SystemFontServiceProxy,
}
impl TestContext {
fn new() -> TestContext {
let (system_font_service, system_font_service_proxy) = MockSystemFontService::spawn();
let (core_sender, _) = ipc::channel().unwrap();
let (storage_sender, _) = ipc::channel().unwrap();
let mock_resource_threads = ResourceThreads::new(core_sender, storage_sender);
let mock_webrender_api = WebRenderScriptApi::dummy();
let proxy_clone = Arc::new(system_font_service_proxy.to_sender().to_proxy());
Self {
context: FontContext::new(proxy_clone, mock_webrender_api, mock_resource_threads),
system_font_service,
system_font_service_proxy,
}
}
}
impl Drop for TestContext {
fn drop(&mut self) {
self.system_font_service_proxy.exit();
}
}
struct MockSystemFontService {
families: Mutex<HashMap<String, FontTemplates>>, families: Mutex<HashMap<String, FontTemplates>>,
data: Mutex<HashMap<FontIdentifier, Arc<FontData>>>, data: Mutex<HashMap<FontIdentifier, Arc<FontData>>>,
find_font_count: AtomicI32, find_font_count: AtomicI32,
} }
impl MockFontCacheThread { impl MockSystemFontService {
pub fn spawn() -> (Arc<MockSystemFontService>, SystemFontServiceProxy) {
let (sender, receiver) = ipc::channel().unwrap();
let system_font_service = Arc::new(Self::new());
let system_font_service_clone = system_font_service.clone();
thread::Builder::new()
.name("MockSystemFontService".to_owned())
.spawn(move || system_font_service_clone.run(receiver))
.expect("Thread spawning failed");
(
system_font_service,
SystemFontServiceProxySender(sender).to_proxy(),
)
}
fn run(&self, receiver: IpcReceiver<SystemFontServiceMessage>) {
loop {
match receiver.recv().unwrap() {
SystemFontServiceMessage::GetFontTemplates(
descriptor_to_match,
font_family,
result_sender,
) => {
self.find_font_count.fetch_add(1, Ordering::Relaxed);
let SingleFontFamily::FamilyName(family_name) = font_family else {
let _ = result_sender.send(FontTemplateRequestResult::default());
continue;
};
let templates: Vec<_> = self
.families
.lock()
.get_mut(&*family_name.name)
.map(|family| family.find_for_descriptor(descriptor_to_match.as_ref()))
.unwrap()
.into_iter()
.map(|template| template.borrow().clone())
.collect();
let template_data = templates
.iter()
.map(|template| {
let identifier = template.identifier().clone();
let data = self.data.lock().get(&identifier).unwrap().clone();
(identifier, data)
})
.collect();
let _ = result_sender.send(FontTemplateRequestResult {
templates,
template_data,
});
},
SystemFontServiceMessage::GetFontInstance(_, _, _, result_sender) => {
let _ = result_sender.send(FontInstanceKey(IdNamespace(0), 0));
},
SystemFontServiceMessage::Exit(result_sender) => {
let _ = result_sender.send(());
break;
},
SystemFontServiceMessage::Ping => {},
}
}
}
fn new() -> Self { fn new() -> Self {
let proxy = Self { let proxy = Self {
families: Default::default(), families: Default::default(),
@ -69,18 +166,6 @@ impl MockFontCacheThread {
proxy proxy
} }
fn identifier_for_font_name(name: &str) -> FontIdentifier {
FontIdentifier::Web(Self::url_for_font_name(name))
}
fn url_for_font_name(name: &str) -> ServoUrl {
let mut path: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests", "support", "CSSTest"]
.iter()
.collect();
path.push(format!("{}.ttf", name));
ServoUrl::from_file_path(path).unwrap()
}
fn add_face(&self, 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()
@ -92,65 +177,20 @@ impl MockFontCacheThread {
file.bytes().map(|b| b.unwrap()).collect(), file.bytes().map(|b| b.unwrap()).collect(),
)); ));
let url = Self::url_for_font_name(name); let identifier = FontIdentifier::Mock(name.into());
let identifier = FontIdentifier::Web(url.clone());
let handle = let handle =
PlatformFont::new_from_data(identifier.clone(), data.as_arc().clone(), 0, None) PlatformFont::new_from_data(identifier.clone(), data.as_arc().clone(), 0, None)
.expect("Could not load test font"); .expect("Could not load test font");
let template = family.add_template(FontTemplate::new(
FontTemplate::new_for_remote_web_font(url, handle.descriptor(), None).unwrap(); identifier.clone(),
family.add_template(template); handle.descriptor(),
None,
));
self.data.lock().insert(identifier, data); self.data.lock().insert(identifier, data);
} }
} }
impl SystemFontServiceProxyTrait for MockFontCacheThread {
fn find_matching_font_templates(
&self,
descriptor_to_match: Option<&FontDescriptor>,
font_family: &SingleFontFamily,
) -> Vec<FontTemplateRef> {
self.find_font_count.fetch_add(1, Ordering::Relaxed);
let SingleFontFamily::FamilyName(family_name) = font_family else {
return Vec::new();
};
self.families
.lock()
.get_mut(&*family_name.name)
.map(|family| family.find_for_descriptor(descriptor_to_match))
.unwrap_or_default()
}
fn get_system_font_instance(
&self,
_font_identifier: FontIdentifier,
_size: Au,
_flags: FontInstanceFlags,
) -> FontInstanceKey {
FontInstanceKey(IdNamespace(0), 0)
}
fn get_web_font(&self, _data: Arc<fonts::FontData>, _index: u32) -> FontKey {
FontKey(IdNamespace(0), 0)
}
fn get_web_font_instance(
&self,
_font_key: FontKey,
_size: f32,
_flags: FontInstanceFlags,
) -> FontInstanceKey {
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 {
let mut style = FontStyleStruct { let mut style = FontStyleStruct {
font_family: FontFamily::serif(), font_family: FontFamily::serif(),
@ -185,16 +225,9 @@ fn font_family(names: Vec<&str>) -> FontFamily {
} }
} }
fn mock_resource_threads() -> ResourceThreads {
let (core_sender, _) = ipc::channel().unwrap();
let (storage_sender, _) = ipc::channel().unwrap();
ResourceThreads::new(core_sender, storage_sender)
}
#[test] #[test]
fn test_font_group_is_cached_by_style() { fn test_font_group_is_cached_by_style() {
let source = Arc::new(MockFontCacheThread::new()); let context = TestContext::new();
let context = FontContext::new(source, mock_resource_threads());
let style1 = style(); let style1 = style();
@ -203,16 +236,28 @@ fn test_font_group_is_cached_by_style() {
assert!( assert!(
std::ptr::eq( std::ptr::eq(
&*context.font_group(ServoArc::new(style1.clone())).read(), &*context
&*context.font_group(ServoArc::new(style1.clone())).read() .context
.font_group(ServoArc::new(style1.clone()))
.read(),
&*context
.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(ServoArc::new(style1.clone())).read(), &*context
&*context.font_group(ServoArc::new(style2.clone())).read() .context
.font_group(ServoArc::new(style1.clone()))
.read(),
&*context
.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"
) )
@ -220,52 +265,60 @@ 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 = Arc::new(MockFontCacheThread::new()); let mut context = TestContext::new();
let mut context = FontContext::new(source.clone(), 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(ServoArc::new(style)); let group = context.context.font_group(ServoArc::new(style));
let font = group let font = group
.write() .write()
.find_by_codepoint(&mut context, 'a', None) .find_by_codepoint(&mut context.context, 'a', None)
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
font.identifier(), font.identifier(),
MockFontCacheThread::identifier_for_font_name("csstest-ascii") FontIdentifier::Mock("csstest-ascii".into())
); );
assert_eq!( assert_eq!(
source.find_font_count.fetch_add(0, Ordering::Relaxed), context
.system_font_service
.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"
); );
let font = group let font = group
.write() .write()
.find_by_codepoint(&mut context, 'a', None) .find_by_codepoint(&mut context.context, 'a', None)
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
font.identifier(), font.identifier(),
MockFontCacheThread::identifier_for_font_name("csstest-ascii") FontIdentifier::Mock("csstest-ascii".into())
); );
assert_eq!( assert_eq!(
source.find_font_count.fetch_add(0, Ordering::Relaxed), context
.system_font_service
.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"
); );
let font = group let font = group
.write() .write()
.find_by_codepoint(&mut context, 'á', None) .find_by_codepoint(&mut context.context, 'á', None)
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
font.identifier(), font.identifier(),
MockFontCacheThread::identifier_for_font_name("csstest-basic-regular") FontIdentifier::Mock("csstest-basic-regular".into())
); );
assert_eq!( assert_eq!(
source.find_font_count.fetch_add(0, Ordering::Relaxed), context
.system_font_service
.find_font_count
.fetch_add(0, Ordering::Relaxed),
2, 2,
"both fonts should now have been loaded" "both fonts should now have been loaded"
); );
@ -273,39 +326,37 @@ fn test_font_group_find_by_codepoint() {
#[test] #[test]
fn test_font_fallback() { fn test_font_fallback() {
let source = Arc::new(MockFontCacheThread::new()); let mut context = TestContext::new();
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(ServoArc::new(style)); let group = context.context.font_group(ServoArc::new(style));
let font = group let font = group
.write() .write()
.find_by_codepoint(&mut context, 'a', None) .find_by_codepoint(&mut context.context, 'a', None)
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
font.identifier(), font.identifier(),
MockFontCacheThread::identifier_for_font_name("csstest-ascii"), FontIdentifier::Mock("csstest-ascii".into()),
"a family in the group should be used if there is a matching glyph" "a family in the group should be used if there is a matching glyph"
); );
let font = group let font = group
.write() .write()
.find_by_codepoint(&mut context, 'á', None) .find_by_codepoint(&mut context.context, 'á', None)
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
font.identifier(), font.identifier(),
MockFontCacheThread::identifier_for_font_name("csstest-basic-regular"), FontIdentifier::Mock("csstest-basic-regular".into()),
"a fallback font should be used if there is no matching glyph in the group" "a fallback font should be used if there is no matching glyph in the group"
); );
} }
#[test] #[test]
fn test_font_template_is_cached() { fn test_font_template_is_cached() {
let source = Arc::new(MockFontCacheThread::new()); let context = TestContext::new();
let context = FontContext::new(source.clone(), mock_resource_threads());
let mut font_descriptor = FontDescriptor { let mut font_descriptor = FontDescriptor {
weight: FontWeight::normal(), weight: FontWeight::normal(),
@ -321,14 +372,19 @@ fn test_font_template_is_cached() {
}); });
let family_descriptor = FontFamilyDescriptor::new(family, FontSearchScope::Any); let family_descriptor = FontFamilyDescriptor::new(family, FontSearchScope::Any);
let font_template = context.matching_templates(&font_descriptor, &family_descriptor)[0].clone(); let font_template = context
.context
.matching_templates(&font_descriptor, &family_descriptor)[0]
.clone();
let font1 = context let font1 = context
.context
.font(font_template.clone(), &font_descriptor) .font(font_template.clone(), &font_descriptor)
.unwrap(); .unwrap();
font_descriptor.pt_size = Au(20); font_descriptor.pt_size = Au(20);
let font2 = context let font2 = context
.context
.font(font_template.clone(), &font_descriptor) .font(font_template.clone(), &font_descriptor)
.unwrap(); .unwrap();
@ -338,7 +394,10 @@ fn test_font_template_is_cached() {
); );
assert_eq!( assert_eq!(
source.find_font_count.fetch_add(0, Ordering::Relaxed), context
.system_font_service
.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::{FontContext, SystemFontServiceProxy}; use fonts::FontContext;
use net_traits::image_cache::{ use net_traits::image_cache::{
ImageCache, ImageCacheResult, ImageOrMetadataAvailable, UsePlaceholder, ImageCache, ImageCacheResult, ImageOrMetadataAvailable, UsePlaceholder,
}; };
@ -24,8 +24,6 @@ use style::context::{RegisteredSpeculativePainter, SharedStyleContext};
use crate::display_list::items::{OpaqueNode, WebRenderImageInfo}; use crate::display_list::items::{OpaqueNode, WebRenderImageInfo};
pub type LayoutFontContext = FontContext<SystemFontServiceProxy>;
type WebrenderImageCache = type WebrenderImageCache =
HashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo, BuildHasherDefault<FnvHasher>>; HashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo, BuildHasherDefault<FnvHasher>>;
@ -44,7 +42,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<SystemFontServiceProxy>>, pub font_context: Arc<FontContext>,
/// 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

@ -11,7 +11,7 @@ use app_units::{Au, MIN_AU};
use base::print_tree::PrintTree; use base::print_tree::PrintTree;
use bitflags::bitflags; use bitflags::bitflags;
use euclid::default::{Point2D, Rect, Size2D}; use euclid::default::{Point2D, Rect, Size2D};
use fonts::FontMetrics; use fonts::{FontContext, FontMetrics};
use log::debug; use log::debug;
use range::{int_range_index, Range, RangeIndex}; use range::{int_range_index, Range, RangeIndex};
use script_layout_interface::wrapper_traits::PseudoElementType; use script_layout_interface::wrapper_traits::PseudoElementType;
@ -33,7 +33,7 @@ use style::values::specified::text::TextOverflowSide;
use unicode_bidi as bidi; use unicode_bidi as bidi;
use crate::block::AbsoluteAssignBSizesTraversal; use crate::block::AbsoluteAssignBSizesTraversal;
use crate::context::{LayoutContext, LayoutFontContext}; use crate::context::LayoutContext;
use crate::display_list::items::{DisplayListSection, OpaqueNode}; use crate::display_list::items::{DisplayListSection, OpaqueNode};
use crate::display_list::{ use crate::display_list::{
BorderPaintingMode, DisplayListBuildState, StackingContextCollectionState, BorderPaintingMode, DisplayListBuildState, StackingContextCollectionState,
@ -1239,7 +1239,7 @@ impl InlineFlow {
/// `style` is the style of the block. /// `style` is the style of the block.
pub fn minimum_line_metrics( pub fn minimum_line_metrics(
&self, &self,
font_context: &LayoutFontContext, font_context: &FontContext,
style: &ComputedValues, style: &ComputedValues,
) -> LineMetrics { ) -> LineMetrics {
InlineFlow::minimum_line_metrics_for_fragments( InlineFlow::minimum_line_metrics_for_fragments(
@ -1255,7 +1255,7 @@ impl InlineFlow {
/// `style` is the style of the block that these fragments belong to. /// `style` is the style of the block that these fragments belong to.
pub fn minimum_line_metrics_for_fragments( pub fn minimum_line_metrics_for_fragments(
fragments: &[Fragment], fragments: &[Fragment],
font_context: &LayoutFontContext, font_context: &FontContext,
style: &ComputedValues, style: &ComputedValues,
) -> LineMetrics { ) -> LineMetrics {
// As a special case, if this flow contains only hypothetical fragments, then the entire // As a special case, if this flow contains only hypothetical fragments, then the entire

View file

@ -11,7 +11,7 @@ use std::sync::Arc;
use app_units::Au; use app_units::Au;
use base::text::is_bidi_control; use base::text::is_bidi_control;
use fonts::{ use fonts::{
self, ByteIndex, FontIdentifier, FontMetrics, FontRef, RunMetrics, ShapingFlags, self, ByteIndex, FontContext, FontIdentifier, FontMetrics, FontRef, RunMetrics, ShapingFlags,
ShapingOptions, LAST_RESORT_GLYPH_ADVANCE, ShapingOptions, LAST_RESORT_GLYPH_ADVANCE,
}; };
use log::{debug, warn}; use log::{debug, warn};
@ -28,7 +28,6 @@ use unicode_bidi as bidi;
use unicode_script::Script; use unicode_script::Script;
use xi_unicode::LineBreakLeafIter; use xi_unicode::LineBreakLeafIter;
use crate::context::LayoutFontContext;
use crate::fragment::{ use crate::fragment::{
Fragment, ScannedTextFlags, ScannedTextFragmentInfo, SpecificFragmentInfo, Fragment, ScannedTextFlags, ScannedTextFragmentInfo, SpecificFragmentInfo,
UnscannedTextFragmentInfo, UnscannedTextFragmentInfo,
@ -71,7 +70,7 @@ impl TextRunScanner {
pub fn scan_for_runs( pub fn scan_for_runs(
&mut self, &mut self,
font_context: &LayoutFontContext, font_context: &FontContext,
mut fragments: LinkedList<Fragment>, mut fragments: LinkedList<Fragment>,
) -> InlineFragments { ) -> InlineFragments {
debug!( debug!(
@ -151,7 +150,7 @@ impl TextRunScanner {
/// be adjusted. /// be adjusted.
fn flush_clump_to_list( fn flush_clump_to_list(
&mut self, &mut self,
font_context: &LayoutFontContext, font_context: &FontContext,
out_fragments: &mut Vec<Fragment>, out_fragments: &mut Vec<Fragment>,
paragraph_bytes_processed: &mut usize, paragraph_bytes_processed: &mut usize,
bidi_levels: Option<&[bidi::Level]>, bidi_levels: Option<&[bidi::Level]>,
@ -538,7 +537,7 @@ fn bounding_box_for_run_metrics(
/// Panics if no font can be found for the given font style. /// Panics if no font can be found for the given font style.
#[inline] #[inline]
pub fn font_metrics_for_style( pub fn font_metrics_for_style(
font_context: &LayoutFontContext, font_context: &FontContext,
style: crate::ServoArc<FontStyleStruct>, style: crate::ServoArc<FontStyleStruct>,
) -> FontMetrics { ) -> FontMetrics {
let font_group = font_context.font_group(style); let font_group = font_context.font_group(style);

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::{FontContext, SystemFontServiceProxy}; use fonts::FontContext;
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<SystemFontServiceProxy>>, pub font_context: Arc<FontContext>,
/// 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,8 +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::{
FontContext, FontRef, GlyphRun, ShapingFlags, ShapingOptions, SystemFontServiceProxy, FontContext, FontRef, GlyphRun, ShapingFlags, ShapingOptions, LAST_RESORT_GLYPH_ADVANCE,
LAST_RESORT_GLYPH_ADVANCE,
}; };
use fonts_traits::ByteIndex; use fonts_traits::ByteIndex;
use log::warn; use log::warn;
@ -342,7 +341,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<SystemFontServiceProxy>, font_context: &FontContext,
linebreaker: &mut LineBreaker, linebreaker: &mut LineBreaker,
font_cache: &mut Vec<FontKeyAndMetrics>, font_cache: &mut Vec<FontKeyAndMetrics>,
bidi_info: &BidiInfo, bidi_info: &BidiInfo,
@ -410,7 +409,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<SystemFontServiceProxy>, font_context: &FontContext,
font_cache: &mut Vec<FontKeyAndMetrics>, font_cache: &mut Vec<FontKeyAndMetrics>,
bidi_info: &BidiInfo, bidi_info: &BidiInfo,
) -> Vec<(TextRunSegment, FontRef)> { ) -> Vec<(TextRunSegment, FontRef)> {
@ -556,7 +555,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<SystemFontServiceProxy>, font_context: &FontContext,
) -> Option<FontRef> { ) -> Option<FontRef> {
let font = font_context let font = font_context
.font_group(style.clone_font()) .font_group(style.clone_font())

View file

@ -134,7 +134,7 @@ pub struct LayoutThread {
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
/// A per-layout FontContext managing font access. /// A per-layout FontContext managing font access.
font_context: Arc<FontContext<SystemFontServiceProxy>>, font_context: Arc<FontContext>,
/// Is this the first reflow in this layout? /// Is this the first reflow in this layout?
first_reflow: Cell<bool>, first_reflow: Cell<bool>,
@ -577,7 +577,11 @@ impl LayoutThread {
keyword_info: KeywordInfo::medium(), keyword_info: KeywordInfo::medium(),
}; };
let font_context = Arc::new(FontContext::new(system_font_service, resource_threads)); let font_context = Arc::new(FontContext::new(
system_font_service,
webrender_api.clone(),
resource_threads,
));
let device = Device::new( let device = Device::new(
MediaType::screen(), MediaType::screen(),
QuirksMode::NoQuirks, QuirksMode::NoQuirks,

View file

@ -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<SystemFontServiceProxy>>, font_context: Arc<FontContext>,
/// Is this the first reflow in this LayoutThread? /// Is this the first reflow in this LayoutThread?
first_reflow: Cell<bool>, first_reflow: Cell<bool>,
@ -521,7 +521,11 @@ 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(system_font_service, resource_threads)); let font_context = Arc::new(FontContext::new(
system_font_service,
webrender_api_sender.clone(),
resource_threads,
));
let device = Device::new( let device = Device::new(
MediaType::screen(), MediaType::screen(),
QuirksMode::NoQuirks, QuirksMode::NoQuirks,
@ -1227,7 +1231,7 @@ impl RegisteredSpeculativePainters for RegisteredPaintersImpl {
} }
} }
struct LayoutFontMetricsProvider(Arc<FontContext<SystemFontServiceProxy>>); struct LayoutFontMetricsProvider(Arc<FontContext>);
impl FontMetricsProvider for LayoutFontMetricsProvider { impl FontMetricsProvider for LayoutFontMetricsProvider {
fn query_font_metrics( fn query_font_metrics(

View file

@ -1101,59 +1101,33 @@ impl WebRenderFontApi for WebRenderFontApiCompositorProxy {
flags: FontInstanceFlags, flags: FontInstanceFlags,
) -> FontInstanceKey { ) -> FontInstanceKey {
let (sender, receiver) = unbounded(); let (sender, receiver) = unbounded();
self.0 self.0.send(CompositorMsg::Forwarded(
.send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Font( ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFontInstance(
FontToCompositorMsg::AddFontInstance(font_key, size, flags, sender), font_key, size, flags, sender,
))); )),
));
receiver.recv().unwrap() receiver.recv().unwrap()
} }
fn add_font(&self, data: Arc<IpcSharedMemory>, index: u32) -> FontKey { fn add_font(&self, data: Arc<IpcSharedMemory>, index: u32) -> FontKey {
let (sender, receiver) = unbounded(); let (sender, receiver) = unbounded();
self.0 self.0.send(CompositorMsg::Forwarded(
.send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Font( ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddFont(
FontToCompositorMsg::AddFont(sender, index, data), sender, index, data,
))); )),
));
receiver.recv().unwrap() receiver.recv().unwrap()
} }
fn add_system_font(&self, handle: NativeFontHandle) -> FontKey { fn add_system_font(&self, handle: NativeFontHandle) -> FontKey {
let (sender, receiver) = unbounded(); let (sender, receiver) = unbounded();
self.0 self.0.send(CompositorMsg::Forwarded(
.send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Font( ForwardedToCompositorMsg::SystemFontService(FontToCompositorMsg::AddSystemFont(
FontToCompositorMsg::AddSystemFont(sender, handle), sender, handle,
))); )),
));
receiver.recv().unwrap() receiver.recv().unwrap()
} }
fn forward_add_font_message(
&self,
data: Arc<IpcSharedMemory>,
font_index: u32,
result_sender: IpcSender<FontKey>,
) {
let (sender, receiver) = unbounded();
self.0
.send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Font(
FontToCompositorMsg::AddFont(sender, font_index, data),
)));
let _ = result_sender.send(receiver.recv().unwrap());
}
fn forward_add_font_instance_message(
&self,
font_key: FontKey,
size: f32,
flags: FontInstanceFlags,
result_sender: IpcSender<FontInstanceKey>,
) {
let (sender, receiver) = unbounded();
self.0
.send(CompositorMsg::Forwarded(ForwardedToCompositorMsg::Font(
FontToCompositorMsg::AddFontInstance(font_key, size, flags, sender),
)));
let _ = result_sender.send(receiver.recv().unwrap());
}
} }
#[derive(Clone)] #[derive(Clone)]

View file

@ -141,7 +141,7 @@ pub struct CompositionPipeline {
pub enum ForwardedToCompositorMsg { pub enum ForwardedToCompositorMsg {
Layout(ScriptToCompositorMsg), Layout(ScriptToCompositorMsg),
Net(NetToCompositorMsg), Net(NetToCompositorMsg),
Font(FontToCompositorMsg), SystemFontService(FontToCompositorMsg),
Canvas(CanvasToCompositorMsg), Canvas(CanvasToCompositorMsg),
} }
@ -150,7 +150,9 @@ impl Debug for ForwardedToCompositorMsg {
match self { match self {
ForwardedToCompositorMsg::Layout(_) => write!(f, "Layout(ScriptToCompositorMsg)"), ForwardedToCompositorMsg::Layout(_) => write!(f, "Layout(ScriptToCompositorMsg)"),
ForwardedToCompositorMsg::Net(_) => write!(f, "Net(NetToCompositorMsg)"), ForwardedToCompositorMsg::Net(_) => write!(f, "Net(NetToCompositorMsg)"),
ForwardedToCompositorMsg::Font(_) => write!(f, "Font(FontToCompositorMsg)"), ForwardedToCompositorMsg::SystemFontService(_) => {
write!(f, "SystemFontService(FontToCompositorMsg)")
},
ForwardedToCompositorMsg::Canvas(_) => write!(f, "Canvas(CanvasToCompositorMsg)"), ForwardedToCompositorMsg::Canvas(_) => write!(f, "Canvas(CanvasToCompositorMsg)"),
} }
} }

View file

@ -192,24 +192,6 @@ pub trait WebRenderFontApi {
) -> FontInstanceKey; ) -> FontInstanceKey;
fn add_font(&self, data: Arc<IpcSharedMemory>, 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
/// [`FontKey`]s for web fonts in the per-layout `FontContext`.
fn forward_add_font_message(
&self,
data: Arc<IpcSharedMemory>,
font_index: u32,
result_sender: IpcSender<FontKey>,
);
/// Forward a `AddFontInstance` message, sending it on to the compositor. This is used to get
/// WebRender [`FontInstanceKey`]s for web fonts in the per-layout `FontContext`.
fn forward_add_font_instance_message(
&self,
font_key: FontKey,
size: f32,
flags: FontInstanceFlags,
result_receiver: IpcSender<FontInstanceKey>,
);
} }
pub enum CanvasToCompositorMsg { pub enum CanvasToCompositorMsg {
@ -260,6 +242,8 @@ pub enum ScriptToCompositorMsg {
UpdateImages(Vec<SerializedImageUpdate>), UpdateImages(Vec<SerializedImageUpdate>),
/// Remove the given font resources from our WebRender instance. /// Remove the given font resources from our WebRender instance.
RemoveFonts(Vec<FontKey>, Vec<FontInstanceKey>), RemoveFonts(Vec<FontKey>, Vec<FontInstanceKey>),
AddFontInstance(FontKey, f32, FontInstanceFlags, IpcSender<FontInstanceKey>),
AddFont(Arc<IpcSharedMemory>, u32, IpcSender<FontKey>),
} }
/// A mechanism to send messages from networking to the WebRender instance. /// A mechanism to send messages from networking to the WebRender instance.
@ -294,11 +278,23 @@ impl WebRenderNetApi {
pub struct WebRenderScriptApi(IpcSender<ScriptToCompositorMsg>); pub struct WebRenderScriptApi(IpcSender<ScriptToCompositorMsg>);
impl WebRenderScriptApi { impl WebRenderScriptApi {
/// Create a new WebrenderIpcSender object that wraps the provided channel sender. /// Create a new [`WebRenderScriptApi`] object that wraps the provided channel sender.
pub fn new(sender: IpcSender<ScriptToCompositorMsg>) -> Self { pub fn new(sender: IpcSender<ScriptToCompositorMsg>) -> Self {
Self(sender) Self(sender)
} }
/// Create a new [`WebRenderScriptApi`] object that does not have a listener on the
/// other end.
pub fn dummy() -> Self {
let (sender, _) = ipc::channel().unwrap();
Self::new(sender)
}
/// Get the sender for this proxy.
pub fn sender(&self) -> &IpcSender<ScriptToCompositorMsg> {
&self.0
}
/// Inform WebRender of the existence of this pipeline. /// Inform WebRender of the existence of this pipeline.
pub fn send_initial_transaction(&self, pipeline: WebRenderPipelineId) { pub fn send_initial_transaction(&self, pipeline: WebRenderPipelineId) {
if let Err(e) = self if let Err(e) = self