mirror of
https://github.com/servo/servo.git
synced 2025-08-28 08:38:20 +01:00
Replace FreeTypeFaceHelpers
with a safe wrapper struct (#38634)
Testing: only safety annotations change, no tests are required. Fixes: https://github.com/servo/servo/issues/38627 --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
parent
4de9a9d100
commit
e19fade481
4 changed files with 212 additions and 167 deletions
|
@ -4,17 +4,13 @@
|
|||
|
||||
use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::os::raw::c_long;
|
||||
use std::{mem, ptr};
|
||||
|
||||
use app_units::Au;
|
||||
use euclid::default::{Point2D, Rect, Size2D};
|
||||
use freetype_sys::{
|
||||
FT_Done_Face, FT_F26Dot6, FT_FACE_FLAG_COLOR, FT_FACE_FLAG_FIXED_SIZES, FT_FACE_FLAG_SCALABLE,
|
||||
FT_Face, FT_Get_Char_Index, FT_Get_Kerning, FT_GlyphSlot, FT_Int32, FT_KERNING_DEFAULT,
|
||||
FT_LOAD_COLOR, FT_LOAD_DEFAULT, FT_LOAD_NO_HINTING, FT_Load_Glyph, FT_Long, FT_New_Face,
|
||||
FT_New_Memory_Face, FT_Pos, FT_Select_Size, FT_Set_Char_Size, FT_Size_Metrics, FT_SizeRec,
|
||||
FT_UInt, FT_ULong, FT_Vector,
|
||||
FT_F26Dot6, FT_Get_Char_Index, FT_Get_Kerning, FT_GlyphSlot, FT_KERNING_DEFAULT,
|
||||
FT_LOAD_DEFAULT, FT_LOAD_NO_HINTING, FT_Load_Glyph, FT_Size_Metrics, FT_SizeRec, FT_UInt,
|
||||
FT_ULong, FT_Vector,
|
||||
};
|
||||
use log::debug;
|
||||
use memmap2::Mmap;
|
||||
|
@ -37,13 +33,9 @@ use crate::font::{
|
|||
};
|
||||
use crate::font_template::FontTemplateDescriptor;
|
||||
use crate::glyph::GlyphId;
|
||||
use crate::platform::freetype::freetype_face::FreeTypeFace;
|
||||
use crate::system_font_service::FontIdentifier;
|
||||
|
||||
// This constant is not present in the freetype
|
||||
// bindings due to bindgen not handling the way
|
||||
// the macro is defined.
|
||||
const FT_LOAD_TARGET_LIGHT: FT_UInt = 1 << 16;
|
||||
|
||||
/// Convert FreeType-style 26.6 fixed point to an [`f64`].
|
||||
fn fixed_26_dot_6_to_float(fixed: FT_F26Dot6) -> f64 {
|
||||
fixed as f64 / 64.0
|
||||
|
@ -68,7 +60,7 @@ impl FontTableMethods for FontTable {
|
|||
#[derive(Debug)]
|
||||
#[allow(unused)]
|
||||
pub struct PlatformFont {
|
||||
face: ReentrantMutex<FT_Face>,
|
||||
face: ReentrantMutex<FreeTypeFace>,
|
||||
requested_face_size: Au,
|
||||
actual_face_size: Au,
|
||||
|
||||
|
@ -76,28 +68,6 @@ pub struct PlatformFont {
|
|||
table_provider_data: FreeTypeFaceTableProviderData,
|
||||
}
|
||||
|
||||
// FT_Face can be used in multiple threads, but from only one thread at a time.
|
||||
// It's protected with a ReentrantMutex for PlatformFont.
|
||||
// See https://freetype.org/freetype2/docs/reference/ft2-face_creation.html#ft_face.
|
||||
unsafe impl Sync for PlatformFont {}
|
||||
unsafe impl Send for PlatformFont {}
|
||||
|
||||
impl Drop for PlatformFont {
|
||||
fn drop(&mut self) {
|
||||
let face = self.face.lock();
|
||||
assert!(!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 FT_Done_Face(*face) != 0 {
|
||||
panic!("FT_Done_Face failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformFontMethods for PlatformFont {
|
||||
fn new_from_data(
|
||||
_font_identifier: FontIdentifier,
|
||||
|
@ -106,20 +76,7 @@ impl PlatformFontMethods for PlatformFont {
|
|||
) -> Result<PlatformFont, &'static str> {
|
||||
let library = FreeTypeLibraryHandle::get().lock();
|
||||
let data: &[u8] = font_data.as_ref();
|
||||
let mut face: FT_Face = ptr::null_mut();
|
||||
let result = unsafe {
|
||||
FT_New_Memory_Face(
|
||||
library.freetype_library,
|
||||
data.as_ptr(),
|
||||
data.len() as FT_Long,
|
||||
0, /* face_index */
|
||||
&mut face,
|
||||
)
|
||||
};
|
||||
|
||||
if 0 != result || face.is_null() {
|
||||
return Err("Could not create FreeType face");
|
||||
}
|
||||
let face = FreeTypeFace::new_from_memory(&library, data)?;
|
||||
|
||||
let (requested_face_size, actual_face_size) = match requested_size {
|
||||
Some(requested_size) => (requested_size, face.set_size(requested_size)?),
|
||||
|
@ -138,22 +95,10 @@ impl PlatformFontMethods for PlatformFont {
|
|||
font_identifier: LocalFontIdentifier,
|
||||
requested_size: Option<Au>,
|
||||
) -> Result<PlatformFont, &'static str> {
|
||||
let mut face: FT_Face = ptr::null_mut();
|
||||
let library = FreeTypeLibraryHandle::get().lock();
|
||||
let filename = CString::new(&*font_identifier.path).expect("filename contains NUL byte!");
|
||||
|
||||
let result = unsafe {
|
||||
FT_New_Face(
|
||||
library.freetype_library,
|
||||
filename.as_ptr(),
|
||||
font_identifier.index() as FT_Long,
|
||||
&mut face,
|
||||
)
|
||||
};
|
||||
|
||||
if 0 != result || face.is_null() {
|
||||
return Err("Could not create FreeType face");
|
||||
}
|
||||
let face = FreeTypeFace::new_from_file(&library, &filename, font_identifier.index())?;
|
||||
|
||||
let (requested_face_size, actual_face_size) = match requested_size {
|
||||
Some(requested_size) => (requested_size, face.set_size(requested_size)?),
|
||||
|
@ -210,10 +155,9 @@ impl PlatformFontMethods for PlatformFont {
|
|||
|
||||
fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
|
||||
let face = self.face.lock();
|
||||
assert!(!face.is_null());
|
||||
|
||||
unsafe {
|
||||
let idx = FT_Get_Char_Index(*face, codepoint as FT_ULong);
|
||||
let idx = FT_Get_Char_Index(face.as_ptr(), codepoint as FT_ULong);
|
||||
if idx != 0 as FT_UInt {
|
||||
Some(idx as GlyphId)
|
||||
} else {
|
||||
|
@ -228,12 +172,11 @@ impl PlatformFontMethods for PlatformFont {
|
|||
|
||||
fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> FractionalPixel {
|
||||
let face = self.face.lock();
|
||||
assert!(!face.is_null());
|
||||
|
||||
let mut delta = FT_Vector { x: 0, y: 0 };
|
||||
unsafe {
|
||||
FT_Get_Kerning(
|
||||
*face,
|
||||
face.as_ptr(),
|
||||
first_glyph,
|
||||
second_glyph,
|
||||
FT_KERNING_DEFAULT,
|
||||
|
@ -245,16 +188,15 @@ impl PlatformFontMethods for PlatformFont {
|
|||
|
||||
fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
|
||||
let face = self.face.lock();
|
||||
assert!(!face.is_null());
|
||||
|
||||
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.as_ptr(), glyph as FT_UInt, load_flags) };
|
||||
if 0 != result {
|
||||
debug!("Unable to load glyph {}. reason: {:?}", glyph, result);
|
||||
return None;
|
||||
}
|
||||
|
||||
let void_glyph = unsafe { (**face).glyph };
|
||||
let void_glyph = face.as_ref().glyph;
|
||||
let slot: FT_GlyphSlot = void_glyph;
|
||||
assert!(!slot.is_null());
|
||||
|
||||
|
@ -263,12 +205,11 @@ impl PlatformFontMethods for PlatformFont {
|
|||
}
|
||||
|
||||
fn metrics(&self) -> FontMetrics {
|
||||
let face_ptr = *self.face.lock();
|
||||
let face = unsafe { &*face_ptr };
|
||||
let face = self.face.lock();
|
||||
let font_ref = self.table_provider_data.font_ref();
|
||||
|
||||
// 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 { &*face.as_ref().size };
|
||||
let freetype_metrics: &FT_Size_Metrics = &(freetype_size).metrics;
|
||||
|
||||
let mut max_advance;
|
||||
|
@ -277,7 +218,7 @@ impl PlatformFontMethods for PlatformFont {
|
|||
let mut line_height;
|
||||
let mut y_scale = 0.0;
|
||||
let mut em_height;
|
||||
if face_ptr.scalable() {
|
||||
if face.scalable() {
|
||||
// Prefer FT_Size_Metrics::y_scale to y_ppem as y_ppem does not have subpixel accuracy.
|
||||
//
|
||||
// FT_Size_Metrics::y_scale is in 16.16 fixed point format. Its (fractional) value is a
|
||||
|
@ -287,11 +228,11 @@ impl PlatformFontMethods for PlatformFont {
|
|||
// This converts the value to a float without losing precision.
|
||||
y_scale = freetype_metrics.y_scale as f64 / 65535.0 / 64.0;
|
||||
|
||||
max_advance = (face.max_advance_width as f64) * y_scale;
|
||||
max_ascent = (face.ascender as f64) * y_scale;
|
||||
max_descent = -(face.descender as f64) * y_scale;
|
||||
line_height = (face.height as f64) * y_scale;
|
||||
em_height = (face.units_per_EM as f64) * y_scale;
|
||||
max_advance = (face.as_ref().max_advance_width as f64) * y_scale;
|
||||
max_ascent = (face.as_ref().ascender as f64) * y_scale;
|
||||
max_descent = -(face.as_ref().descender as f64) * y_scale;
|
||||
line_height = (face.as_ref().height as f64) * y_scale;
|
||||
em_height = (face.as_ref().units_per_EM as f64) * y_scale;
|
||||
} else {
|
||||
max_advance = fixed_26_dot_6_to_float(freetype_metrics.max_advance);
|
||||
max_ascent = fixed_26_dot_6_to_float(freetype_metrics.ascender);
|
||||
|
@ -307,7 +248,7 @@ impl PlatformFontMethods for PlatformFont {
|
|||
// 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
|
||||
// based on y_ppem need to be rescaled for the adjusted size.
|
||||
if face_ptr.color() {
|
||||
if face.color() {
|
||||
em_height = self.requested_face_size.to_f64_px();
|
||||
let adjust_scale = em_height / (freetype_metrics.y_ppem as f64);
|
||||
max_advance *= adjust_scale;
|
||||
|
@ -327,8 +268,8 @@ impl PlatformFontMethods for PlatformFont {
|
|||
// Convert using a formula similar to what CTFont returns for consistency.
|
||||
let leading = line_height - (max_ascent + max_descent);
|
||||
|
||||
let underline_size = face.underline_thickness as f64 * y_scale;
|
||||
let underline_offset = face.underline_position as f64 * y_scale + 0.5;
|
||||
let underline_size = face.as_ref().underline_thickness as f64 * y_scale;
|
||||
let underline_offset = face.as_ref().underline_position as f64 * y_scale + 0.5;
|
||||
|
||||
// The default values for strikeout size and offset. Use OpenType spec's suggested position
|
||||
// for Roman font as the default for offset.
|
||||
|
@ -411,16 +352,15 @@ impl PlatformFontMethods for PlatformFont {
|
|||
|
||||
fn typographic_bounds(&self, glyph_id: GlyphId) -> Rect<f32> {
|
||||
let face = self.face.lock();
|
||||
assert!(!face.is_null());
|
||||
|
||||
let load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
|
||||
let result = unsafe { FT_Load_Glyph(*face, glyph_id as FT_UInt, load_flags) };
|
||||
let result = unsafe { FT_Load_Glyph(face.as_ptr(), glyph_id as FT_UInt, load_flags) };
|
||||
if 0 != result {
|
||||
debug!("Unable to load glyph {}. reason: {:?}", glyph_id, result);
|
||||
return Rect::default();
|
||||
}
|
||||
|
||||
let metrics = unsafe { &(*(**face).glyph).metrics };
|
||||
let metrics = unsafe { &(*face.as_ref().glyph).metrics };
|
||||
|
||||
Rect::new(
|
||||
Point2D::new(
|
||||
|
@ -448,85 +388,6 @@ impl PlatformFont {
|
|||
}
|
||||
}
|
||||
|
||||
trait FreeTypeFaceHelpers {
|
||||
fn scalable(self) -> bool;
|
||||
fn color(self) -> bool;
|
||||
fn set_size(self, pt_size: Au) -> Result<Au, &'static str>;
|
||||
fn glyph_load_flags(self) -> FT_Int32;
|
||||
}
|
||||
|
||||
impl FreeTypeFaceHelpers for FT_Face {
|
||||
fn scalable(self) -> bool {
|
||||
unsafe { (*self).face_flags & FT_FACE_FLAG_SCALABLE as c_long != 0 }
|
||||
}
|
||||
|
||||
fn color(self) -> bool {
|
||||
unsafe { (*self).face_flags & FT_FACE_FLAG_COLOR as c_long != 0 }
|
||||
}
|
||||
|
||||
fn set_size(self, requested_size: Au) -> Result<Au, &'static str> {
|
||||
if self.scalable() {
|
||||
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) };
|
||||
if 0 != result {
|
||||
return Err("FT_Set_Char_Size failed");
|
||||
}
|
||||
return Ok(requested_size);
|
||||
}
|
||||
|
||||
let requested_size = (requested_size.to_f64_px() * 64.0) as FT_Pos;
|
||||
let get_size_at_index = |index| unsafe {
|
||||
(
|
||||
(*(*self).available_sizes.offset(index as isize)).x_ppem,
|
||||
(*(*self).available_sizes.offset(index as isize)).y_ppem,
|
||||
)
|
||||
};
|
||||
|
||||
let mut best_index = 0;
|
||||
let mut best_size = get_size_at_index(0);
|
||||
let mut best_dist = best_size.1 - requested_size;
|
||||
for strike_index in 1..unsafe { (*self).num_fixed_sizes } {
|
||||
let new_scale = get_size_at_index(strike_index);
|
||||
let new_distance = new_scale.1 - requested_size;
|
||||
|
||||
// Distance is positive if strike is larger than desired size,
|
||||
// or negative if smaller. If previously a found smaller strike,
|
||||
// then prefer a larger strike. Otherwise, minimize distance.
|
||||
if (best_dist < 0 && new_distance >= best_dist) || new_distance.abs() <= best_dist {
|
||||
best_dist = new_distance;
|
||||
best_size = new_scale;
|
||||
best_index = strike_index;
|
||||
}
|
||||
}
|
||||
|
||||
if 0 == unsafe { FT_Select_Size(self, best_index) } {
|
||||
Ok(Au::from_f64_px(best_size.1 as f64 / 64.0))
|
||||
} else {
|
||||
Err("FT_Select_Size failed")
|
||||
}
|
||||
}
|
||||
|
||||
fn glyph_load_flags(self) -> FT_Int32 {
|
||||
let mut load_flags = FT_LOAD_DEFAULT;
|
||||
|
||||
// Default to slight hinting, which is what most
|
||||
// Linux distros use by default, and is a better
|
||||
// default than no hinting.
|
||||
// TODO(gw): Make this configurable.
|
||||
load_flags |= FT_LOAD_TARGET_LIGHT as i32;
|
||||
|
||||
let face_flags = unsafe { (*self).face_flags };
|
||||
if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 {
|
||||
// We only set FT_LOAD_COLOR if there are bitmap strikes; COLR (color-layer) fonts
|
||||
// will be handled internally in Servo. In that case WebRender will just be asked to
|
||||
// paint individual layers.
|
||||
load_flags |= FT_LOAD_COLOR;
|
||||
}
|
||||
|
||||
load_flags as FT_Int32
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum FreeTypeFaceTableProviderData {
|
||||
Web(FontData),
|
||||
|
|
183
components/fonts/platform/freetype/freetype_face.rs
Normal file
183
components/fonts/platform/freetype/freetype_face.rs
Normal file
|
@ -0,0 +1,183 @@
|
|||
/* 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::ffi::{CStr, c_long};
|
||||
use std::ptr;
|
||||
|
||||
use app_units::Au;
|
||||
use freetype_sys::{
|
||||
FT_Done_Face, FT_F26Dot6, FT_FACE_FLAG_COLOR, FT_FACE_FLAG_FIXED_SIZES, FT_FACE_FLAG_SCALABLE,
|
||||
FT_Face, FT_FaceRec, FT_Int32, FT_LOAD_COLOR, FT_LOAD_DEFAULT, FT_Long, FT_New_Face,
|
||||
FT_New_Memory_Face, FT_Pos, FT_Select_Size, FT_Set_Char_Size, FT_UInt,
|
||||
};
|
||||
|
||||
use crate::platform::freetype::library_handle::FreeTypeLibraryHandle;
|
||||
|
||||
// This constant is not present in the freetype
|
||||
// bindings due to bindgen not handling the way
|
||||
// the macro is defined.
|
||||
const FT_LOAD_TARGET_LIGHT: FT_UInt = 1 << 16;
|
||||
|
||||
/// A safe wrapper around [FT_Face].
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FreeTypeFace {
|
||||
/// ## Safety Invariant
|
||||
/// The pointer must have been returned from [FT_New_Face] or [FT_New_Memory_Face]
|
||||
/// and must not be freed before `FreetypeFace::drop` is called.
|
||||
face: ptr::NonNull<FT_FaceRec>,
|
||||
}
|
||||
|
||||
impl FreeTypeFace {
|
||||
pub(crate) fn new_from_memory(
|
||||
library: &FreeTypeLibraryHandle,
|
||||
data: &[u8],
|
||||
) -> Result<Self, &'static str> {
|
||||
let mut face = ptr::null_mut();
|
||||
let result = unsafe {
|
||||
FT_New_Memory_Face(
|
||||
library.freetype_library,
|
||||
data.as_ptr(),
|
||||
data.len() as FT_Long,
|
||||
0,
|
||||
&mut face,
|
||||
)
|
||||
};
|
||||
|
||||
if 0 != result {
|
||||
return Err("Could not create FreeType face");
|
||||
}
|
||||
let Some(face) = ptr::NonNull::new(face) else {
|
||||
return Err("Could not create FreeType face");
|
||||
};
|
||||
|
||||
Ok(Self { face })
|
||||
}
|
||||
|
||||
pub(crate) fn new_from_file(
|
||||
library: &FreeTypeLibraryHandle,
|
||||
filename: &CStr,
|
||||
index: u32,
|
||||
) -> Result<Self, &'static str> {
|
||||
let mut face = ptr::null_mut();
|
||||
let result = unsafe {
|
||||
FT_New_Face(
|
||||
library.freetype_library,
|
||||
filename.as_ptr(),
|
||||
index as FT_Long,
|
||||
&mut face,
|
||||
)
|
||||
};
|
||||
|
||||
if 0 != result {
|
||||
return Err("Could not create FreeType face");
|
||||
}
|
||||
let Some(face) = ptr::NonNull::new(face) else {
|
||||
return Err("Could not create FreeType face");
|
||||
};
|
||||
|
||||
Ok(Self { face })
|
||||
}
|
||||
|
||||
pub(crate) fn as_ref(&self) -> &FT_FaceRec {
|
||||
unsafe { self.face.as_ref() }
|
||||
}
|
||||
|
||||
pub(crate) fn as_ptr(&self) -> FT_Face {
|
||||
self.face.as_ptr()
|
||||
}
|
||||
|
||||
/// Return true iff the font face flags contain [FT_FACE_FLAG_SCALABLE].
|
||||
pub(crate) fn scalable(&self) -> bool {
|
||||
self.as_ref().face_flags & FT_FACE_FLAG_SCALABLE as c_long != 0
|
||||
}
|
||||
|
||||
/// Return true iff the font face flags contain [FT_FACE_FLAG_COLOR].
|
||||
pub(crate) fn color(&self) -> bool {
|
||||
self.as_ref().face_flags & FT_FACE_FLAG_COLOR as c_long != 0
|
||||
}
|
||||
|
||||
/// Scale the font to the given size if it is scalable, or select the closest
|
||||
/// available size if it is not, preferring larger sizes over smaller ones.
|
||||
///
|
||||
/// Returns the selected size on success and a error message on failure
|
||||
pub(crate) fn set_size(&self, requested_size: Au) -> Result<Au, &'static str> {
|
||||
if self.scalable() {
|
||||
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.face.as_ptr(), size_in_fixed_point, 0, 72, 72) };
|
||||
if 0 != result {
|
||||
return Err("FT_Set_Char_Size failed");
|
||||
}
|
||||
return Ok(requested_size);
|
||||
}
|
||||
|
||||
let requested_size = (requested_size.to_f64_px() * 64.0) as FT_Pos;
|
||||
let get_size_at_index = |index| unsafe {
|
||||
(
|
||||
(*self.as_ref().available_sizes.offset(index as isize)).x_ppem,
|
||||
(*self.as_ref().available_sizes.offset(index as isize)).y_ppem,
|
||||
)
|
||||
};
|
||||
|
||||
let mut best_index = 0;
|
||||
let mut best_size = get_size_at_index(0);
|
||||
let mut best_dist = best_size.1 - requested_size;
|
||||
for strike_index in 1..self.as_ref().num_fixed_sizes {
|
||||
let new_scale = get_size_at_index(strike_index);
|
||||
let new_distance = new_scale.1 - requested_size;
|
||||
|
||||
// Distance is positive if strike is larger than desired size,
|
||||
// or negative if smaller. If previously a found smaller strike,
|
||||
// then prefer a larger strike. Otherwise, minimize distance.
|
||||
if (best_dist < 0 && new_distance >= best_dist) || new_distance.abs() <= best_dist {
|
||||
best_dist = new_distance;
|
||||
best_size = new_scale;
|
||||
best_index = strike_index;
|
||||
}
|
||||
}
|
||||
|
||||
if 0 == unsafe { FT_Select_Size(self.face.as_ptr(), best_index) } {
|
||||
Ok(Au::from_f64_px(best_size.1 as f64 / 64.0))
|
||||
} else {
|
||||
Err("FT_Select_Size failed")
|
||||
}
|
||||
}
|
||||
|
||||
/// Select a reasonable set of glyph loading flags for the font.
|
||||
pub(crate) fn glyph_load_flags(&self) -> FT_Int32 {
|
||||
let mut load_flags = FT_LOAD_DEFAULT;
|
||||
|
||||
// Default to slight hinting, which is what most
|
||||
// Linux distros use by default, and is a better
|
||||
// default than no hinting.
|
||||
// TODO(gw): Make this configurable.
|
||||
load_flags |= FT_LOAD_TARGET_LIGHT as i32;
|
||||
|
||||
let face_flags = self.as_ref().face_flags;
|
||||
if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 {
|
||||
// We only set FT_LOAD_COLOR if there are bitmap strikes; COLR (color-layer) fonts
|
||||
// will be handled internally in Servo. In that case WebRender will just be asked to
|
||||
// paint individual layers.
|
||||
load_flags |= FT_LOAD_COLOR;
|
||||
}
|
||||
|
||||
load_flags as FT_Int32
|
||||
}
|
||||
}
|
||||
|
||||
/// FT_Face can be used in multiple threads, but from only one thread at a time.
|
||||
/// See <https://freetype.org/freetype2/docs/reference/ft2-face_creation.html#ft_face>.
|
||||
unsafe impl Send for FreeTypeFace {}
|
||||
|
||||
impl Drop for FreeTypeFace {
|
||||
fn drop(&mut self) {
|
||||
// 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 unsafe { FT_Done_Face(self.face.as_ptr()) } != 0 {
|
||||
panic!("FT_Done_Face failed");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,12 +11,12 @@ use freetype_sys::{
|
|||
FT_Add_Default_Modules, FT_Done_Library, FT_Library, FT_Memory, FT_MemoryRec, FT_New_Library,
|
||||
};
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use parking_lot::Mutex;
|
||||
use parking_lot::ReentrantMutex;
|
||||
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();
|
||||
static FREETYPE_LIBRARY_HANDLE: OnceLock<ReentrantMutex<FreeTypeLibraryHandle>> = OnceLock::new();
|
||||
|
||||
extern "C" fn ft_alloc(_: FT_Memory, req_size: c_long) -> *mut c_void {
|
||||
unsafe {
|
||||
|
@ -90,7 +90,7 @@ impl FreeTypeLibraryHandle {
|
|||
/// > 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> {
|
||||
pub(crate) fn get() -> &'static ReentrantMutex<FreeTypeLibraryHandle> {
|
||||
FREETYPE_LIBRARY_HANDLE.get_or_init(|| {
|
||||
let freetype_memory = Box::into_raw(Box::new(FT_MemoryRec {
|
||||
user: ptr::null_mut(),
|
||||
|
@ -105,7 +105,7 @@ impl FreeTypeLibraryHandle {
|
|||
panic!("Unable to initialize FreeType library");
|
||||
}
|
||||
FT_Add_Default_Modules(freetype_library);
|
||||
Mutex::new(FreeTypeLibraryHandle {
|
||||
ReentrantMutex::new(FreeTypeLibraryHandle {
|
||||
freetype_library,
|
||||
freetype_memory,
|
||||
})
|
||||
|
|
|
@ -14,6 +14,7 @@ use style::Atom;
|
|||
use webrender_api::NativeFontHandle;
|
||||
|
||||
pub mod font;
|
||||
mod freetype_face;
|
||||
|
||||
#[cfg(all(target_os = "linux", not(target_env = "ohos"), not(ohos_mock)))]
|
||||
pub mod font_list;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue