diff options
author | Martin Robinson <mrobinson@igalia.com> | 2024-04-12 12:39:32 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-12 10:39:32 +0000 |
commit | efa0d457574f02dfbe2403f501a4626acdcb64db (patch) | |
tree | f114f9a1233a111863170b6eea10f02d11d57b37 /components | |
parent | e9591ce62f210d374463bdf1a6d956e19cca81f0 (diff) | |
download | servo-efa0d457574f02dfbe2403f501a4626acdcb64db.tar.gz servo-efa0d457574f02dfbe2403f501a4626acdcb64db.zip |
Remove `FontContextHandle` (#32038)
The `FontContextHandle` was really only used on FreeType platforms to
store the `FT_Library` handle to use for creating faces. Each
`FontContext` and `FontCacheThread` would create its own
`FontContextHandle`. This change removes this data structure in favor of
a mutex-protected shared `FontContextHandle` for an entire Servo
process. The handle is initialized using a `OnceLock` to ensure that it
only happens once and also that it stays alive for the entire process
lifetime.
In addition to greatly simplifying the code, this will make it possible
for different threads to share platform-specific `FontHandle`s, avoiding
multiple allocations for a single font.
The only downside to all of this is that memory usage of FreeType fonts
isn't measured (though the mechanism is still there). This is because
the `FontCacheThread` currently doesn't do any memory measurement.
Eventually this *will* happen though, during the font system redesign.
In exchange, this should reduce the memory usage since there is only a
single FreeType library loaded into memory now.
This is part of #32033.
Diffstat (limited to 'components')
-rw-r--r-- | components/gfx/Cargo.toml | 1 | ||||
-rw-r--r-- | components/gfx/font.rs | 2 | ||||
-rw-r--r-- | components/gfx/font_cache_thread.rs | 13 | ||||
-rw-r--r-- | components/gfx/font_context.rs | 18 | ||||
-rw-r--r-- | components/gfx/font_template.rs | 18 | ||||
-rw-r--r-- | components/gfx/platform/freetype/font.rs | 37 | ||||
-rw-r--r-- | components/gfx/platform/freetype/font_context.rs | 136 | ||||
-rw-r--r-- | components/gfx/platform/freetype/library_handle.rs | 116 | ||||
-rw-r--r-- | components/gfx/platform/macos/font.rs | 2 | ||||
-rw-r--r-- | components/gfx/platform/macos/font_context.rs | 17 | ||||
-rw-r--r-- | components/gfx/platform/mod.rs | 13 | ||||
-rw-r--r-- | components/gfx/platform/windows/font.rs | 2 | ||||
-rw-r--r-- | components/gfx/platform/windows/font_context.rs | 10 | ||||
-rw-r--r-- | components/gfx/tests/font_context.rs | 8 | ||||
-rw-r--r-- | components/gfx/tests/font_template.rs | 5 |
15 files changed, 151 insertions, 247 deletions
diff --git a/components/gfx/Cargo.toml b/components/gfx/Cargo.toml index 114e727d041..976687b953e 100644 --- a/components/gfx/Cargo.toml +++ b/components/gfx/Cargo.toml @@ -27,6 +27,7 @@ libc = { workspace = true } log = { workspace = true } malloc_size_of = { workspace = true } net_traits = { workspace = true } +parking_lot = { workspace = true } range = { path = "../range" } serde = { workspace = true } servo_arc = { workspace = true } diff --git a/components/gfx/font.rs b/components/gfx/font.rs index 6916b2e5261..f01f916d4ba 100644 --- a/components/gfx/font.rs +++ b/components/gfx/font.rs @@ -28,7 +28,6 @@ use crate::font_cache_thread::FontIdentifier; use crate::font_context::{FontContext, FontSource}; use crate::font_template::FontTemplateDescriptor; use crate::platform::font::{FontHandle, FontTable}; -use crate::platform::font_context::FontContextHandle; pub use crate::platform::font_list::fallback_font_families; use crate::platform::font_template::FontTemplateData; use crate::text::glyph::{ByteIndex, GlyphData, GlyphId, GlyphStore}; @@ -56,7 +55,6 @@ static TEXT_SHAPING_PERFORMANCE_COUNTER: AtomicUsize = AtomicUsize::new(0); pub trait FontHandleMethods: Sized { fn new_from_template( - fctx: &FontContextHandle, template: Arc<FontTemplateData>, pt_size: Option<Au>, ) -> Result<Self, &'static str>; diff --git a/components/gfx/font_cache_thread.rs b/components/gfx/font_cache_thread.rs index 5808295a4a3..a5c6a2b0974 100644 --- a/components/gfx/font_cache_thread.rs +++ b/components/gfx/font_cache_thread.rs @@ -26,7 +26,6 @@ use webrender_api::{FontInstanceKey, FontKey}; use crate::font::{FontFamilyDescriptor, FontFamilyName, FontSearchScope}; use crate::font_context::FontSource; use crate::font_template::{FontTemplate, FontTemplateDescriptor}; -use crate::platform::font_context::FontContextHandle; use crate::platform::font_list::{ for_each_available_family, for_each_variation, system_default_family, LocalFontIdentifier, SANS_SERIF_FONT_FAMILY, @@ -75,13 +74,12 @@ impl FontTemplates { pub fn find_font_for_style( &mut self, desc: &FontTemplateDescriptor, - fctx: &FontContextHandle, ) -> Option<Arc<FontTemplateData>> { // TODO(Issue #189): optimize lookup for // regular/bold/italic/bolditalic with fixed offsets and a // static decision table for fallback between these values. for template in &mut self.templates { - let maybe_template = template.data_for_descriptor(fctx, desc); + let maybe_template = template.data_for_descriptor(desc); if maybe_template.is_some() { return maybe_template; } @@ -91,8 +89,7 @@ impl FontTemplates { // TODO(#190): Do a better job. let (mut best_template_data, mut best_distance) = (None, f32::MAX); for template in &mut self.templates { - if let Some((template_data, distance)) = - template.data_for_approximate_descriptor(fctx, desc) + if let Some((template_data, distance)) = template.data_for_approximate_descriptor(desc) { if distance < best_distance { best_template_data = Some(template_data); @@ -159,7 +156,6 @@ struct FontCache { generic_fonts: HashMap<FontFamilyName, LowercaseString>, local_families: HashMap<LowercaseString, FontTemplates>, web_families: HashMap<LowercaseString, FontTemplates>, - font_context: FontContextHandle, core_resource_thread: CoreResourceThread, webrender_api: Box<dyn WebrenderApi>, webrender_fonts: HashMap<FontIdentifier, FontKey>, @@ -404,7 +400,7 @@ impl FontCache { // TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'. // if such family exists, try to match style to a font - s.find_font_for_style(template_descriptor, &self.font_context) + s.find_font_for_style(template_descriptor) } else { debug!( "FontList: Couldn't find font family with name={}", @@ -423,7 +419,7 @@ impl FontCache { if self.web_families.contains_key(&family_name) { let templates = self.web_families.get_mut(&family_name).unwrap(); - templates.find_font_for_style(template_descriptor, &self.font_context) + templates.find_font_for_style(template_descriptor) } else { None } @@ -498,7 +494,6 @@ impl FontCacheThread { generic_fonts, local_families: HashMap::new(), web_families: HashMap::new(), - font_context: FontContextHandle::default(), core_resource_thread, webrender_api, webrender_fonts: HashMap::new(), diff --git a/components/gfx/font_context.rs b/components/gfx/font_context.rs index c7f2eaef530..d316ceb50c1 100644 --- a/components/gfx/font_context.rs +++ b/components/gfx/font_context.rs @@ -12,7 +12,6 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use app_units::Au; use fnv::FnvHasher; use log::debug; -use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use servo_arc::Arc; use style::computed_values::font_variant_caps::T as FontVariantCaps; use style::properties::style_structs::Font as FontStyleStruct; @@ -24,7 +23,6 @@ use crate::font::{ use crate::font_cache_thread::FontTemplateInfo; use crate::font_template::FontTemplateDescriptor; use crate::platform::font::FontHandle; -pub use crate::platform::font_context::FontContextHandle; static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8; // Matches FireFox (see gfxFont.h) @@ -48,7 +46,6 @@ pub trait FontSource { /// required. #[derive(Debug)] pub struct FontContext<S: FontSource> { - platform_handle: FontContextHandle, font_source: S, // TODO: The font context holds a strong ref to the cached fonts @@ -66,9 +63,7 @@ pub struct FontContext<S: FontSource> { impl<S: FontSource> FontContext<S> { pub fn new(font_source: S) -> FontContext<S> { #[allow(clippy::default_constructed_unit_structs)] - let handle = FontContextHandle::default(); FontContext { - platform_handle: handle, font_source, font_cache: HashMap::new(), font_template_cache: HashMap::new(), @@ -217,11 +212,7 @@ impl<S: FontSource> FontContext<S> { descriptor: FontDescriptor, synthesized_small_caps: Option<FontRef>, ) -> Result<Font, &'static str> { - let handle = FontHandle::new_from_template( - &self.platform_handle, - info.font_template, - Some(descriptor.pt_size), - )?; + let handle = FontHandle::new_from_template(info.font_template, Some(descriptor.pt_size))?; let font_instance_key = self .font_source @@ -235,13 +226,6 @@ impl<S: FontSource> FontContext<S> { } } -impl<S: FontSource> MallocSizeOf for FontContext<S> { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - // FIXME(njn): Measure other fields eventually. - self.platform_handle.size_of(ops) - } -} - #[derive(Debug, Eq, Hash, PartialEq)] struct FontCacheKey { font_descriptor: FontDescriptor, diff --git a/components/gfx/font_template.rs b/components/gfx/font_template.rs index 00d95159632..66db059db13 100644 --- a/components/gfx/font_template.rs +++ b/components/gfx/font_template.rs @@ -15,7 +15,6 @@ use style::values::computed::font::FontWeight; use crate::font::FontHandleMethods; use crate::font_cache_thread::FontIdentifier; use crate::platform::font::FontHandle; -use crate::platform::font_context::FontContextHandle; use crate::platform::font_template::FontTemplateData; /// Describes how to select a font from a given family. This is very basic at the moment and needs @@ -130,10 +129,7 @@ impl FontTemplate { } /// Get the descriptor. Returns `None` when instantiating the data fails. - pub fn descriptor( - &mut self, - font_context: &FontContextHandle, - ) -> Option<FontTemplateDescriptor> { + pub fn descriptor(&mut self) -> Option<FontTemplateDescriptor> { // The font template data can be unloaded when nothing is referencing // it (via the Weak reference to the Arc above). However, if we have // already loaded a font, store the style information about it separately, @@ -141,7 +137,7 @@ impl FontTemplate { // without having to reload the font (unless it is an actual match). self.descriptor.or_else(|| { - if self.instantiate(font_context).is_err() { + if self.instantiate().is_err() { return None; }; @@ -155,10 +151,9 @@ impl FontTemplate { /// Get the data for creating a font if it matches a given descriptor. pub fn data_for_descriptor( &mut self, - fctx: &FontContextHandle, requested_desc: &FontTemplateDescriptor, ) -> Option<Arc<FontTemplateData>> { - self.descriptor(fctx).and_then(|descriptor| { + self.descriptor().and_then(|descriptor| { if *requested_desc == descriptor { self.data().ok() } else { @@ -171,23 +166,22 @@ impl FontTemplate { /// descriptor, if the font can be loaded. pub fn data_for_approximate_descriptor( &mut self, - font_context: &FontContextHandle, requested_descriptor: &FontTemplateDescriptor, ) -> Option<(Arc<FontTemplateData>, f32)> { - self.descriptor(font_context).and_then(|descriptor| { + self.descriptor().and_then(|descriptor| { self.data() .ok() .map(|data| (data, descriptor.distance_from(requested_descriptor))) }) } - fn instantiate(&mut self, font_context: &FontContextHandle) -> Result<(), &'static str> { + fn instantiate(&mut self) -> Result<(), &'static str> { if !self.is_valid { return Err("Invalid font template"); } let data = self.data().map_err(|_| "Could not get FontTemplate data")?; - let handle = FontHandleMethods::new_from_template(font_context, data, None); + let handle = FontHandleMethods::new_from_template(data, None); self.is_valid = handle.is_ok(); let handle: FontHandle = handle?; self.descriptor = Some(FontTemplateDescriptor::new( diff --git a/components/gfx/platform/freetype/font.rs b/components/gfx/platform/freetype/font.rs index 024b3c563e1..44e51bc218c 100644 --- a/components/gfx/platform/freetype/font.rs +++ b/components/gfx/platform/freetype/font.rs @@ -10,7 +10,7 @@ use std::{mem, ptr}; use app_units::Au; use freetype::freetype::{ FT_Done_Face, FT_F26Dot6, FT_Face, FT_FaceRec, FT_Get_Char_Index, FT_Get_Kerning, - FT_Get_Postscript_Name, FT_Get_Sfnt_Table, FT_GlyphSlot, FT_Int32, FT_Kerning_Mode, FT_Library, + FT_Get_Postscript_Name, FT_Get_Sfnt_Table, FT_GlyphSlot, FT_Int32, FT_Kerning_Mode, FT_Load_Glyph, FT_Load_Sfnt_Table, FT_Long, FT_New_Face, FT_New_Memory_Face, FT_Set_Char_Size, FT_Sfnt_Tag, FT_SizeRec, FT_Size_Metrics, FT_UInt, FT_ULong, FT_Vector, FT_STYLE_FLAG_ITALIC, }; @@ -22,12 +22,12 @@ use style::computed_values::font_weight::T as FontWeight; use style::values::computed::font::FontStyle; use super::c_str_to_string; +use super::library_handle::FreeTypeLibraryHandle; use crate::font::{ FontHandleMethods, FontMetrics, FontTableMethods, FontTableTag, FractionalPixel, GPOS, GSUB, KERN, }; use crate::font_cache_thread::FontIdentifier; -use crate::platform::font_context::FontContextHandle; use crate::platform::font_template::FontTemplateData; use crate::text::glyph::GlyphId; use crate::text::util::fixed_to_float; @@ -76,9 +76,6 @@ pub struct FontHandle { // if the font is created using FT_Memory_Face. font_data: Arc<FontTemplateData>, face: FT_Face, - // `context_handle` is unused, but here to ensure that the underlying - // FreeTypeLibraryHandle is not dropped. - context_handle: FontContextHandle, can_do_fast_shaping: bool, } @@ -86,6 +83,10 @@ impl Drop for FontHandle { fn drop(&mut self) { assert!(!self.face.is_null()); unsafe { + // The FreeType documentation says that both `FT_New_Face` and `FT_Done_Face` + // should be protected by a mutex. + // See https://freetype.org/freetype2/docs/reference/ft2-library_setup.html. + let _guard = FreeTypeLibraryHandle::get().lock(); if !succeeded(FT_Done_Face(self.face)) { panic!("FT_Done_Face failed"); } @@ -93,20 +94,17 @@ impl Drop for FontHandle { } } -fn create_face( - lib: FT_Library, - template: &FontTemplateData, - pt_size: Option<Au>, -) -> Result<FT_Face, &'static str> { +fn create_face(template: &FontTemplateData, pt_size: Option<Au>) -> Result<FT_Face, &'static str> { unsafe { let mut face: FT_Face = ptr::null_mut(); let face_index = 0 as FT_Long; + let library = FreeTypeLibraryHandle::get().lock(); let result = match template.identifier { FontIdentifier::Web(_) => { let bytes = template.bytes(); FT_New_Memory_Face( - lib, + library.freetype_library, bytes.as_ptr(), bytes.len() as FT_Long, face_index, @@ -120,7 +118,12 @@ fn create_face( // https://github.com/servo/servo/pull/20506#issuecomment-378838800 let filename = CString::new(&*local_identifier.path).expect("filename contains NUL byte!"); - FT_New_Face(lib, filename.as_ptr(), face_index, &mut face) + FT_New_Face( + library.freetype_library, + filename.as_ptr(), + face_index, + &mut face, + ) }, }; @@ -138,21 +141,13 @@ fn create_face( impl FontHandleMethods for FontHandle { fn new_from_template( - fctx: &FontContextHandle, template: Arc<FontTemplateData>, pt_size: Option<Au>, ) -> Result<FontHandle, &'static str> { - let ft_ctx: FT_Library = fctx.ctx.ctx; - if ft_ctx.is_null() { - return Err("Null FT_Library"); - } - - let face = create_face(ft_ctx, &template, pt_size)?; - + let face = create_face(&template, pt_size)?; let mut handle = FontHandle { face, font_data: template, - context_handle: fctx.clone(), can_do_fast_shaping: false, }; // TODO (#11310): Implement basic support for GPOS and GSUB. diff --git a/components/gfx/platform/freetype/font_context.rs b/components/gfx/platform/freetype/font_context.rs deleted file mode 100644 index b08ff552261..00000000000 --- a/components/gfx/platform/freetype/font_context.rs +++ /dev/null @@ -1,136 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -use std::os::raw::{c_long, c_void}; -use std::ptr; -use std::rc::Rc; - -use freetype::freetype::{ - FT_Add_Default_Modules, FT_Done_Library, FT_Library, FT_Memory, FT_MemoryRec_, FT_New_Library, -}; -use freetype::succeeded; -use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; -use servo_allocator::libc_compat::{free, malloc, realloc}; -use servo_allocator::usable_size; - -// We pass a |User| struct -- via an opaque |void*| -- to FreeType each time a new instance is -// created. FreeType passes it back to the ft_alloc/ft_realloc/ft_free callbacks. We use it to -// record the memory usage of each FreeType instance. -pub struct User { - size: usize, -} - -extern "C" fn ft_alloc(mem: FT_Memory, req_size: c_long) -> *mut c_void { - unsafe { - let ptr = malloc(req_size as usize); - let ptr = ptr as *mut c_void; // libc::c_void vs std::os::raw::c_void - let actual_size = usable_size(ptr); - let user = (*mem).user as *mut User; - (*user).size += actual_size; - ptr - } -} - -extern "C" fn ft_free(mem: FT_Memory, ptr: *mut c_void) { - unsafe { - let actual_size = usable_size(ptr); - let user = (*mem).user as *mut User; - (*user).size -= actual_size; - free(ptr as *mut _); - } -} - -extern "C" fn ft_realloc( - mem: FT_Memory, - _old_size: c_long, - new_req_size: c_long, - old_ptr: *mut c_void, -) -> *mut c_void { - unsafe { - let old_actual_size = usable_size(old_ptr); - let new_ptr = realloc(old_ptr as *mut _, new_req_size as usize); - let new_ptr = new_ptr as *mut c_void; - let new_actual_size = usable_size(new_ptr); - let user = (*mem).user as *mut User; - (*user).size += new_actual_size; - (*user).size -= old_actual_size; - new_ptr - } -} - -// A |*mut User| field in a struct triggers a "use of `#[derive]` with a raw pointer" warning from -// rustc. But using a typedef avoids this, so... -pub type UserPtr = *mut User; - -// WARNING: We need to be careful how we use this struct. See the comment about Rc<> in -// FontContextHandle. -#[derive(Clone, Debug)] -pub struct FreeTypeLibraryHandle { - pub ctx: FT_Library, - mem: FT_Memory, - user: UserPtr, -} - -impl Drop for FreeTypeLibraryHandle { - #[allow(unused)] - fn drop(&mut self) { - assert!(!self.ctx.is_null()); - unsafe { - FT_Done_Library(self.ctx); - Box::from_raw(self.mem); - Box::from_raw(self.user); - } - } -} - -impl MallocSizeOf for FreeTypeLibraryHandle { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - unsafe { - (*self.user).size + - ops.malloc_size_of(self.ctx as *const _) + - ops.malloc_size_of(self.mem as *const _) + - ops.malloc_size_of(self.user as *const _) - } - } -} - -#[derive(Clone, Debug)] -pub struct FontContextHandle { - // WARNING: FreeTypeLibraryHandle contains raw pointers, is clonable, and also implements - // `Drop`. This field needs to be Rc<> to make sure that the `drop` function is only called - // once, otherwise we'll get crashes. Yuk. - pub ctx: Rc<FreeTypeLibraryHandle>, -} - -impl MallocSizeOf for FontContextHandle { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - self.ctx.size_of(ops) - } -} - -impl Default for FontContextHandle { - fn default() -> Self { - let user = Box::into_raw(Box::new(User { size: 0 })); - let mem = Box::into_raw(Box::new(FT_MemoryRec_ { - user: user as *mut c_void, - alloc: Some(ft_alloc), - free: Some(ft_free), - realloc: Some(ft_realloc), - })); - unsafe { - let mut ctx: FT_Library = ptr::null_mut(); - - let result = FT_New_Library(mem, &mut ctx); - if !succeeded(result) { - panic!("Unable to initialize FreeType library"); - } - - FT_Add_Default_Modules(ctx); - - FontContextHandle { - ctx: Rc::new(FreeTypeLibraryHandle { ctx, mem, user }), - } - } - } -} diff --git a/components/gfx/platform/freetype/library_handle.rs b/components/gfx/platform/freetype/library_handle.rs new file mode 100644 index 00000000000..bcd8b2e4865 --- /dev/null +++ b/components/gfx/platform/freetype/library_handle.rs @@ -0,0 +1,116 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +use std::os::raw::{c_long, c_void}; +use std::ptr; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::OnceLock; + +use freetype::freetype::{ + FT_Add_Default_Modules, FT_Done_Library, FT_Library, FT_Memory, FT_MemoryRec_, FT_New_Library, +}; +use freetype::succeeded; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +use parking_lot::Mutex; +use servo_allocator::libc_compat::{free, malloc, realloc}; +use servo_allocator::usable_size; + +static FREETYPE_MEMORY_USAGE: AtomicUsize = AtomicUsize::new(0); +static FREETYPE_LIBRARY_HANDLE: OnceLock<Mutex<FreeTypeLibraryHandle>> = OnceLock::new(); + +extern "C" fn ft_alloc(_: FT_Memory, req_size: c_long) -> *mut c_void { + unsafe { + let pointer = malloc(req_size as usize); + FREETYPE_MEMORY_USAGE.fetch_add(usable_size(pointer), Ordering::Relaxed); + pointer + } +} + +extern "C" fn ft_free(_: FT_Memory, pointer: *mut c_void) { + unsafe { + FREETYPE_MEMORY_USAGE.fetch_sub(usable_size(pointer), Ordering::Relaxed); + free(pointer as *mut _); + } +} + +extern "C" fn ft_realloc( + _: FT_Memory, + _old_size: c_long, + new_req_size: c_long, + old_pointer: *mut c_void, +) -> *mut c_void { + unsafe { + FREETYPE_MEMORY_USAGE.fetch_sub(usable_size(old_pointer), Ordering::Relaxed); + let new_pointer = realloc(old_pointer, new_req_size as usize); + FREETYPE_MEMORY_USAGE.fetch_add(usable_size(new_pointer), Ordering::Relaxed); + new_pointer + } +} + +/// A FreeType library handle to be used for creating and dropping FreeType font faces. +/// It is very important that this handle lives as long as the faces themselves, which +/// is why only one of these is created for the entire execution of Servo and never +/// dropped during execution. +#[derive(Clone, Debug)] +pub(crate) struct FreeTypeLibraryHandle { + pub freetype_library: FT_Library, + freetype_memory: FT_Memory, +} + +unsafe impl Sync for FreeTypeLibraryHandle {} +unsafe impl Send for FreeTypeLibraryHandle {} + +impl Drop for FreeTypeLibraryHandle { + #[allow(unused)] + fn drop(&mut self) { + assert!(!self.freetype_library.is_null()); + unsafe { + FT_Done_Library(self.freetype_library); + Box::from_raw(self.freetype_memory); + } + } +} + +impl MallocSizeOf for FreeTypeLibraryHandle { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + unsafe { + FREETYPE_MEMORY_USAGE.load(Ordering::Relaxed) + + ops.malloc_size_of(self.freetype_library as *const _) + + ops.malloc_size_of(self.freetype_memory as *const _) + } + } +} + +impl FreeTypeLibraryHandle { + /// Get the shared FreeType library handle. This is protected by a mutex because according to + /// the FreeType documentation: + /// + /// > [Since 2.5.6] In multi-threaded applications it is easiest to use one FT_Library object per + /// > thread. In case this is too cumbersome, a single FT_Library object across threads is possible + /// > also, as long as a mutex lock is used around FT_New_Face and FT_Done_Face. + /// + /// See <https://freetype.org/freetype2/docs/reference/ft2-library_setup.html>. + pub(crate) fn get() -> &'static Mutex<FreeTypeLibraryHandle> { + FREETYPE_LIBRARY_HANDLE.get_or_init(|| { + let freetype_memory = Box::into_raw(Box::new(FT_MemoryRec_ { + user: ptr::null_mut(), + alloc: Some(ft_alloc), + free: Some(ft_free), + realloc: Some(ft_realloc), + })); + unsafe { + let mut freetype_library: FT_Library = ptr::null_mut(); + let result = FT_New_Library(freetype_memory, &mut freetype_library); + if !succeeded(result) { + panic!("Unable to initialize FreeType library"); + } + FT_Add_Default_Modules(freetype_library); + Mutex::new(FreeTypeLibraryHandle { + freetype_library, + freetype_memory, + }) + } + }) + } +} diff --git a/components/gfx/platform/macos/font.rs b/components/gfx/platform/macos/font.rs index f8088b24412..3e355c7d1ce 100644 --- a/components/gfx/platform/macos/font.rs +++ b/components/gfx/platform/macos/font.rs @@ -27,7 +27,6 @@ use crate::font::{ }; use crate::font_cache_thread::FontIdentifier; use crate::platform::font_template::FontTemplateData; -use crate::platform::macos::font_context::FontContextHandle; use crate::text::glyph::GlyphId; const KERN_PAIR_LEN: usize = 6; @@ -158,7 +157,6 @@ impl fmt::Debug for CachedKernTable { impl FontHandleMethods for FontHandle { fn new_from_template( - _fctx: &FontContextHandle, template: Arc<FontTemplateData>, pt_size: Option<Au>, ) -> Result<FontHandle, &'static str> { diff --git a/components/gfx/platform/macos/font_context.rs b/components/gfx/platform/macos/font_context.rs deleted file mode 100644 index b296ce6738b..00000000000 --- a/components/gfx/platform/macos/font_context.rs +++ /dev/null @@ -1,17 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; - -#[derive(Clone, Debug, Default)] -pub struct FontContextHandle { - // this is a placeholder until NSFontManager or whatever is bound in here. - _ctx: (), -} - -impl MallocSizeOf for FontContextHandle { - fn size_of(&self, _: &mut MallocSizeOfOps) -> usize { - 0 - } -} diff --git a/components/gfx/platform/mod.rs b/components/gfx/platform/mod.rs index cc4d28ee575..6e3d191529e 100644 --- a/components/gfx/platform/mod.rs +++ b/components/gfx/platform/mod.rs @@ -3,13 +3,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #[cfg(any(target_os = "linux", target_os = "android"))] -pub use crate::platform::freetype::{font, font_context}; -#[cfg(any(target_os = "linux", target_os = "android"))] -pub use crate::platform::freetype::{font_list, font_template}; +pub use crate::platform::freetype::{font, font_list, font_template, library_handle}; #[cfg(target_os = "macos")] -pub use crate::platform::macos::{font, font_context, font_list, font_template}; +pub use crate::platform::macos::{font, font_list, font_template}; #[cfg(target_os = "windows")] -pub use crate::platform::windows::{font, font_context, font_list, font_template}; +pub use crate::platform::windows::{font, font_list, font_template}; #[cfg(any(target_os = "linux", target_os = "android"))] mod freetype { @@ -27,7 +25,6 @@ mod freetype { } pub mod font; - pub mod font_context; #[cfg(target_os = "linux")] pub mod font_list; @@ -39,14 +36,13 @@ mod freetype { #[cfg(target_os = "android")] pub use self::android::font_list; - #[cfg(any(target_os = "linux", target_os = "android"))] pub mod font_template; + pub mod library_handle; } #[cfg(target_os = "macos")] mod macos { pub mod font; - pub mod font_context; pub mod font_list; pub mod font_template; } @@ -54,7 +50,6 @@ mod macos { #[cfg(target_os = "windows")] mod windows { pub mod font; - pub mod font_context; pub mod font_list; pub mod font_template; } diff --git a/components/gfx/platform/windows/font.rs b/components/gfx/platform/windows/font.rs index 3ec4c73ecf8..03b82022068 100644 --- a/components/gfx/platform/windows/font.rs +++ b/components/gfx/platform/windows/font.rs @@ -23,7 +23,6 @@ use crate::font::{ }; use crate::font_cache_thread::FontIdentifier; use crate::platform::font_template::FontTemplateData; -use crate::platform::windows::font_context::FontContextHandle; use crate::text::glyph::GlyphId; // 1em = 12pt = 16px, assuming 72 points per inch and 96 px per inch @@ -228,7 +227,6 @@ impl FontHandle {} impl FontHandleMethods for FontHandle { fn new_from_template( - _: &FontContextHandle, template: Arc<FontTemplateData>, pt_size: Option<Au>, ) -> Result<Self, &'static str> { diff --git a/components/gfx/platform/windows/font_context.rs b/components/gfx/platform/windows/font_context.rs deleted file mode 100644 index a67a366fc11..00000000000 --- a/components/gfx/platform/windows/font_context.rs +++ /dev/null @@ -1,10 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -use malloc_size_of::malloc_size_of_is_0; - -#[derive(Clone, Debug, Default)] -pub struct FontContextHandle; - -malloc_size_of_is_0!(FontContextHandle); diff --git a/components/gfx/tests/font_context.rs b/components/gfx/tests/font_context.rs index 3447493399d..24965e272f1 100644 --- a/components/gfx/tests/font_context.rs +++ b/components/gfx/tests/font_context.rs @@ -14,7 +14,7 @@ use gfx::font::{ fallback_font_families, FontDescriptor, FontFamilyDescriptor, FontFamilyName, FontSearchScope, }; use gfx::font_cache_thread::{FontIdentifier, FontTemplateInfo, FontTemplates}; -use gfx::font_context::{FontContext, FontContextHandle, FontSource}; +use gfx::font_context::{FontContext, FontSource}; use gfx::font_template::FontTemplateDescriptor; use servo_arc::Arc; use servo_atoms::Atom; @@ -30,7 +30,6 @@ use style::values::generics::font::LineHeight; use webrender_api::{FontInstanceKey, FontKey, IdNamespace}; struct TestFontSource { - handle: FontContextHandle, families: HashMap<String, FontTemplates>, find_font_count: Rc<Cell<isize>>, } @@ -52,7 +51,6 @@ impl TestFontSource { families.insert(fallback_font_families(None)[0].to_owned(), fallback); TestFontSource { - handle: FontContextHandle::default(), families, find_font_count: Rc::new(Cell::new(0)), } @@ -90,12 +88,10 @@ impl FontSource for TestFontSource { template_descriptor: FontTemplateDescriptor, family_descriptor: FontFamilyDescriptor, ) -> Option<FontTemplateInfo> { - let handle = &self.handle; - self.find_font_count.set(self.find_font_count.get() + 1); self.families .get_mut(family_descriptor.name()) - .and_then(|family| family.find_font_for_style(&template_descriptor, handle)) + .and_then(|family| family.find_font_for_style(&template_descriptor)) .map(|template| FontTemplateInfo { font_template: template, font_key: FontKey(IdNamespace(0), 0), diff --git a/components/gfx/tests/font_template.rs b/components/gfx/tests/font_template.rs index 1c8420bc45c..d35c3607497 100644 --- a/components/gfx/tests/font_template.rs +++ b/components/gfx/tests/font_template.rs @@ -11,7 +11,6 @@ fn test_font_template_descriptor() { use std::path::PathBuf; use gfx::font_cache_thread::FontIdentifier; - use gfx::font_context::FontContextHandle; use gfx::font_template::{FontTemplate, FontTemplateDescriptor}; use servo_url::ServoUrl; use style::values::computed::font::{FontStretch, FontStyle, FontWeight}; @@ -35,9 +34,7 @@ fn test_font_template_descriptor() { ) .unwrap(); - let context = FontContextHandle::default(); - - template.descriptor(&context).unwrap() + template.descriptor().unwrap() } assert_eq!( |