fonts: Depend directly on freetype-sys (#32318)

Instead of depending on `rust-freetype`, depend directly on
`freetype-sys` which is a transitive dependency. This provides almost
everything we need (apart from one function call). This will help us
eliminate one crate in the dependency chain.
This commit is contained in:
Martin Robinson 2024-05-21 12:47:15 +02:00 committed by GitHub
parent 1bcb4787d2
commit 67e556e3be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 40 additions and 47 deletions

2
Cargo.lock generated
View file

@ -2027,7 +2027,7 @@ dependencies = [
"euclid", "euclid",
"fnv", "fnv",
"fontsan", "fontsan",
"freetype", "freetype-sys",
"gfx_traits", "gfx_traits",
"harfbuzz-sys", "harfbuzz-sys",
"ipc-channel", "ipc-channel",

View file

@ -37,6 +37,7 @@ encoding_rs = "0.8"
env_logger = "0.10" env_logger = "0.10"
euclid = "0.22" euclid = "0.22"
fnv = "1.0" fnv = "1.0"
freetype-sys = "0.20"
fxhash = "0.2" fxhash = "0.2"
getopts = "0.2.11" getopts = "0.2.11"
gfx_traits = { path = "components/shared/gfx" } gfx_traits = { path = "components/shared/gfx" }

View file

@ -56,7 +56,7 @@ core-text = "20.1"
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
harfbuzz-sys = { version = "0.6", features = ["bundled"] } harfbuzz-sys = { version = "0.6", features = ["bundled"] }
freetype = "0.7" freetype-sys = { workspace = true }
servo_allocator = { path = "../allocator" } servo_allocator = { path = "../allocator" }
[target.'cfg(all(target_os = "linux", not(target_env = "ohos")))'.dependencies] [target.'cfg(all(target_os = "linux", not(target_env = "ohos")))'.dependencies]

View file

@ -8,16 +8,14 @@ use std::sync::Arc;
use std::{mem, ptr}; use std::{mem, ptr};
use app_units::Au; use app_units::Au;
use freetype::freetype::{ use freetype_sys::{
FT_Done_Face, FT_F26Dot6, FT_Face, FT_Fixed, FT_Get_Char_Index, FT_Get_Kerning, ft_sfnt_head, ft_sfnt_os2, FT_Byte, FT_Done_Face, FT_Error, FT_F26Dot6, FT_Face, FT_Fixed,
FT_Get_Sfnt_Table, FT_GlyphSlot, FT_Int32, FT_Kerning_Mode, FT_Load_Glyph, FT_Load_Sfnt_Table, FT_Get_Char_Index, FT_Get_Kerning, FT_Get_Sfnt_Table, FT_GlyphSlot, FT_Int32, FT_Load_Glyph,
FT_Long, FT_MulFix, FT_New_Memory_Face, FT_Pos, FT_Select_Size, FT_Set_Char_Size, FT_Sfnt_Tag, FT_Long, FT_MulFix, FT_New_Memory_Face, FT_Pos, FT_Select_Size, FT_Set_Char_Size, FT_Short,
FT_Short, FT_SizeRec, FT_Size_Metrics, FT_UInt, FT_ULong, FT_UShort, FT_Vector, FT_SizeRec, FT_Size_Metrics, FT_UInt, FT_ULong, FT_UShort, FT_Vector, FT_FACE_FLAG_COLOR,
FT_FACE_FLAG_COLOR, FT_FACE_FLAG_FIXED_SIZES, FT_FACE_FLAG_SCALABLE, FT_LOAD_COLOR, FT_FACE_FLAG_FIXED_SIZES, FT_FACE_FLAG_SCALABLE, FT_KERNING_DEFAULT, FT_LOAD_COLOR,
FT_LOAD_DEFAULT, FT_STYLE_FLAG_ITALIC, FT_LOAD_DEFAULT, FT_STYLE_FLAG_ITALIC, TT_OS2,
}; };
use freetype::succeeded;
use freetype::tt_os2::TT_OS2;
use log::debug; use log::debug;
use parking_lot::ReentrantMutex; use parking_lot::ReentrantMutex;
use style::computed_values::font_stretch::T as FontStretch; use style::computed_values::font_stretch::T as FontStretch;
@ -95,7 +93,7 @@ impl Drop for PlatformFont {
// should be protected by a mutex. // should be protected by a mutex.
// See https://freetype.org/freetype2/docs/reference/ft2-library_setup.html. // See https://freetype.org/freetype2/docs/reference/ft2-library_setup.html.
let _guard = FreeTypeLibraryHandle::get().lock(); let _guard = FreeTypeLibraryHandle::get().lock();
if !succeeded(FT_Done_Face(*face)) { if FT_Done_Face(*face) != 0 {
panic!("FT_Done_Face failed"); panic!("FT_Done_Face failed");
} }
} }
@ -117,7 +115,7 @@ fn create_face(data: Arc<Vec<u8>>, face_index: u32) -> Result<FT_Face, &'static
&mut face, &mut face,
); );
if !succeeded(result) || face.is_null() { if 0 != result || face.is_null() {
return Err("Could not create FreeType face"); return Err("Could not create FreeType face");
} }
@ -211,7 +209,7 @@ impl PlatformFontMethods for PlatformFont {
*face, *face,
first_glyph, first_glyph,
second_glyph, second_glyph,
FT_Kerning_Mode::FT_KERNING_DEFAULT as FT_UInt, FT_KERNING_DEFAULT,
&mut delta, &mut delta,
); );
} }
@ -228,7 +226,7 @@ impl PlatformFontMethods for PlatformFont {
let load_flags = face.glyph_load_flags(); let load_flags = face.glyph_load_flags();
let result = unsafe { FT_Load_Glyph(*face, glyph as FT_UInt, load_flags) }; let result = unsafe { FT_Load_Glyph(*face, glyph as FT_UInt, load_flags) };
if !succeeded(result) { if 0 != result {
debug!("Unable to load glyph {}. reason: {:?}", glyph, result); debug!("Unable to load glyph {}. reason: {:?}", glyph, result);
return None; return None;
} }
@ -243,7 +241,7 @@ impl PlatformFontMethods for PlatformFont {
fn metrics(&self) -> FontMetrics { fn metrics(&self) -> FontMetrics {
let face_ptr = *self.face.lock(); let face_ptr = *self.face.lock();
let face = unsafe { *face_ptr }; let face = unsafe { &*face_ptr };
// face.size is a *c_void in the bindings, presumably to avoid recursive structural types // face.size is a *c_void in the bindings, presumably to avoid recursive structural types
let freetype_size: &FT_SizeRec = unsafe { mem::transmute(&(*face.size)) }; let freetype_size: &FT_SizeRec = unsafe { mem::transmute(&(*face.size)) };
@ -281,8 +279,7 @@ impl PlatformFontMethods for PlatformFont {
// scalable outlines". If it's an sfnt, we can get units_per_EM from the 'head' table // scalable outlines". If it's an sfnt, we can get units_per_EM from the 'head' table
// instead; otherwise, we don't have a unitsPerEm value so we can't compute y_scale and // instead; otherwise, we don't have a unitsPerEm value so we can't compute y_scale and
// x_scale. // x_scale.
let head = let head = unsafe { FT_Get_Sfnt_Table(face_ptr, ft_sfnt_head) as *mut TtHeader };
unsafe { FT_Get_Sfnt_Table(face_ptr, FT_Sfnt_Tag::FT_SFNT_HEAD) as *mut TtHeader };
if !head.is_null() && unsafe { (*head).table_version != 0xffff } { if !head.is_null() && unsafe { (*head).table_version != 0xffff } {
// Bug 1267909 - Even if the font is not explicitly scalable, if the face has color // Bug 1267909 - Even if the font is not explicitly scalable, if the face has color
// bitmaps, it should be treated as scalable and scaled to the desired size. Metrics // bitmaps, it should be treated as scalable and scaled to the desired size. Metrics
@ -381,18 +378,12 @@ impl PlatformFontMethods for PlatformFont {
unsafe { unsafe {
// Get the length // Get the length
let mut len = 0; let mut len = 0;
if !succeeded(FT_Load_Sfnt_Table(*face, tag, 0, ptr::null_mut(), &mut len)) { if 0 != FT_Load_Sfnt_Table(*face, tag, 0, ptr::null_mut(), &mut len) {
return None; return None;
} }
// Get the bytes // Get the bytes
let mut buf = vec![0u8; len as usize]; let mut buf = vec![0u8; len as usize];
if !succeeded(FT_Load_Sfnt_Table( if 0 != FT_Load_Sfnt_Table(*face, tag, 0, buf.as_mut_ptr(), &mut len) {
*face,
tag,
0,
buf.as_mut_ptr(),
&mut len,
)) {
return None; return None;
} }
Some(FontTable { buffer: buf }) Some(FontTable { buffer: buf })
@ -438,7 +429,7 @@ impl FreeTypeFaceHelpers for FT_Face {
if self.scalable() { if self.scalable() {
let size_in_fixed_point = (requested_size.to_f64_px() * 64.0 + 0.5) as FT_F26Dot6; let size_in_fixed_point = (requested_size.to_f64_px() * 64.0 + 0.5) as FT_F26Dot6;
let result = unsafe { FT_Set_Char_Size(self, size_in_fixed_point, 0, 72, 72) }; let result = unsafe { FT_Set_Char_Size(self, size_in_fixed_point, 0, 72, 72) };
if !succeeded(result) { if 0 != result {
return Err("FT_Set_Char_Size failed"); return Err("FT_Set_Char_Size failed");
} }
return Ok(requested_size); return Ok(requested_size);
@ -469,7 +460,7 @@ impl FreeTypeFaceHelpers for FT_Face {
} }
} }
if succeeded(unsafe { FT_Select_Size(self, best_index) }) { if 0 == unsafe { FT_Select_Size(self, best_index) } {
Ok(Au::from_f64_px(best_size.1 as f64 / 64.0)) Ok(Au::from_f64_px(best_size.1 as f64 / 64.0))
} else { } else {
Err("FT_Select_Size failed") Err("FT_Select_Size failed")
@ -483,7 +474,7 @@ impl FreeTypeFaceHelpers for FT_Face {
// Linux distros use by default, and is a better // Linux distros use by default, and is a better
// default than no hinting. // default than no hinting.
// TODO(gw): Make this configurable. // TODO(gw): Make this configurable.
load_flags |= FT_LOAD_TARGET_LIGHT; load_flags |= FT_LOAD_TARGET_LIGHT as i32;
let face_flags = unsafe { (*self).face_flags }; let face_flags = unsafe { (*self).face_flags };
if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 { if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 {
@ -497,20 +488,12 @@ impl FreeTypeFaceHelpers for FT_Face {
} }
fn has_table(self, tag: FontTableTag) -> bool { fn has_table(self, tag: FontTableTag) -> bool {
unsafe { unsafe { 0 == FT_Load_Sfnt_Table(self, tag as FT_ULong, 0, ptr::null_mut(), &mut 0) }
succeeded(FT_Load_Sfnt_Table(
self,
tag as FT_ULong,
0,
ptr::null_mut(),
&mut 0,
))
}
} }
fn os2_table(self) -> Option<OS2Table> { fn os2_table(self) -> Option<OS2Table> {
unsafe { unsafe {
let os2 = FT_Get_Sfnt_Table(self, FT_Sfnt_Tag::FT_SFNT_OS2) as *mut TT_OS2; let os2 = FT_Get_Sfnt_Table(self, ft_sfnt_os2) as *mut TT_OS2;
let valid = !os2.is_null() && (*os2).version != 0xffff; let valid = !os2.is_null() && (*os2).version != 0xffff;
if !valid { if !valid {
@ -555,3 +538,13 @@ struct TtHeader {
index_to_loc_format: FT_Short, index_to_loc_format: FT_Short,
glyph_data_format: FT_Short, glyph_data_format: FT_Short,
} }
extern "C" {
fn FT_Load_Sfnt_Table(
face: FT_Face,
tag: FT_ULong,
offset: FT_Long,
buffer: *mut FT_Byte,
length: *mut FT_ULong,
) -> FT_Error;
}

View file

@ -7,10 +7,9 @@ use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::OnceLock; use std::sync::OnceLock;
use freetype::freetype::{ use freetype_sys::{
FT_Add_Default_Modules, FT_Done_Library, FT_Library, FT_Memory, FT_MemoryRec_, FT_New_Library, 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 malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use parking_lot::Mutex; use parking_lot::Mutex;
use servo_allocator::libc_compat::{free, malloc, realloc}; use servo_allocator::libc_compat::{free, malloc, realloc};
@ -93,16 +92,16 @@ impl FreeTypeLibraryHandle {
/// See <https://freetype.org/freetype2/docs/reference/ft2-library_setup.html>. /// See <https://freetype.org/freetype2/docs/reference/ft2-library_setup.html>.
pub(crate) fn get() -> &'static Mutex<FreeTypeLibraryHandle> { pub(crate) fn get() -> &'static Mutex<FreeTypeLibraryHandle> {
FREETYPE_LIBRARY_HANDLE.get_or_init(|| { FREETYPE_LIBRARY_HANDLE.get_or_init(|| {
let freetype_memory = Box::into_raw(Box::new(FT_MemoryRec_ { let freetype_memory = Box::into_raw(Box::new(FT_MemoryRec {
user: ptr::null_mut(), user: ptr::null_mut(),
alloc: Some(ft_alloc), alloc: ft_alloc,
free: Some(ft_free), free: ft_free,
realloc: Some(ft_realloc), realloc: ft_realloc,
})); }));
unsafe { unsafe {
let mut freetype_library: FT_Library = ptr::null_mut(); let mut freetype_library: FT_Library = ptr::null_mut();
let result = FT_New_Library(freetype_memory, &mut freetype_library); let result = FT_New_Library(freetype_memory, &mut freetype_library);
if !succeeded(result) { if 0 != result {
panic!("Unable to initialize FreeType library"); panic!("Unable to initialize FreeType library");
} }
FT_Add_Default_Modules(freetype_library); FT_Add_Default_Modules(freetype_library);