fonts/platform/freetype/
freetype_face.rs1use std::ffi::c_long;
6use std::fmt::Debug;
7use std::ptr;
8
9use app_units::Au;
10use fonts_traits::FontData;
11use freetype_sys::{
12 FT_Done_Face, FT_Done_MM_Var, FT_F26Dot6, FT_FACE_FLAG_COLOR, FT_FACE_FLAG_FIXED_SIZES,
13 FT_FACE_FLAG_SCALABLE, FT_Face, FT_FaceRec, FT_Fixed, FT_Get_MM_Var, FT_HAS_MULTIPLE_MASTERS,
14 FT_Int32, FT_LOAD_COLOR, FT_LOAD_DEFAULT, FT_LOAD_TARGET_LIGHT, FT_Long, FT_MM_Var,
15 FT_New_Memory_Face, FT_Pos, FT_Select_Size, FT_Set_Char_Size, FT_Set_Var_Design_Coordinates,
16 FTErrorMethods,
17};
18use memmap2::Mmap;
19use servo_arc::Arc;
20use webrender_api::FontVariation;
21
22use crate::platform::freetype::library_handle::FreeTypeLibraryHandle;
23
24#[derive(Debug)]
26pub(crate) struct FreeTypeFace {
27 face: ptr::NonNull<FT_FaceRec>,
31 _data: FontBackingStore,
32}
33
34pub(crate) enum FontBackingStore {
35 Web(FontData),
36 Local(Arc<Mmap>),
38}
39
40impl AsRef<[u8]> for FontBackingStore {
41 fn as_ref(&self) -> &[u8] {
42 match self {
43 Self::Web(font_data) => font_data.as_ref(),
44 Self::Local(mmap) => mmap.as_ref(),
45 }
46 }
47}
48
49impl Debug for FontBackingStore {
50 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
51 f.debug_struct("FontBackingStore")
52 .field("len", &self.as_ref().len())
53 .finish()
54 }
55}
56
57impl FreeTypeFace {
58 pub(crate) fn new_from_memory(
59 library: &FreeTypeLibraryHandle,
60 font_backing_store: FontBackingStore,
61 face_index: u32,
62 ) -> Result<Self, &'static str> {
63 let mut face = ptr::null_mut();
64 let data = font_backing_store.as_ref();
65 let result = unsafe {
69 FT_New_Memory_Face(
70 library.freetype_library,
71 data.as_ptr(),
72 data.len() as FT_Long,
73 face_index as FT_Long,
74 &mut face,
75 )
76 };
77
78 if 0 != result {
79 return Err("Could not create FreeType face");
80 }
81 let Some(face) = ptr::NonNull::new(face) else {
82 return Err("Could not create FreeType face");
83 };
84
85 Ok(Self {
86 face,
87 _data: font_backing_store,
88 })
89 }
90
91 pub(crate) fn as_ref(&self) -> &FT_FaceRec {
92 unsafe { self.face.as_ref() }
93 }
94
95 pub(crate) fn as_ptr(&self) -> FT_Face {
96 self.face.as_ptr()
97 }
98
99 pub(crate) fn scalable(&self) -> bool {
101 self.as_ref().face_flags & FT_FACE_FLAG_SCALABLE as c_long != 0
102 }
103
104 pub(crate) fn color(&self) -> bool {
106 self.as_ref().face_flags & FT_FACE_FLAG_COLOR as c_long != 0
107 }
108
109 pub(crate) fn set_size(&self, requested_size: Au) -> Result<Au, &'static str> {
114 if self.scalable() {
115 let size_in_fixed_point = (requested_size.to_f64_px() * 64.0 + 0.5) as FT_F26Dot6;
116 let result =
117 unsafe { FT_Set_Char_Size(self.face.as_ptr(), size_in_fixed_point, 0, 72, 72) };
118 if 0 != result {
119 return Err("FT_Set_Char_Size failed");
120 }
121 return Ok(requested_size);
122 }
123
124 let face = self.as_ref();
125 if face.num_fixed_sizes <= 0 || face.available_sizes.is_null() {
126 return Err("No fixed sizes available");
127 }
128
129 let requested_size = (requested_size.to_f64_px() * 64.0) as FT_Pos;
130 let get_size_at_index = |index| {
131 assert!(index < face.num_fixed_sizes);
132 unsafe {
134 (
135 (*face.available_sizes.offset(index as isize)).x_ppem,
136 (*face.available_sizes.offset(index as isize)).y_ppem,
137 )
138 }
139 };
140
141 let mut best_index = 0;
142 let mut best_size = get_size_at_index(0);
143 let mut best_dist = best_size.1 - requested_size;
144 for strike_index in 1..face.num_fixed_sizes {
145 let new_scale = get_size_at_index(strike_index);
146 let new_distance = new_scale.1 - requested_size;
147
148 if (best_dist < 0 && new_distance >= best_dist) || new_distance.abs() <= best_dist {
152 best_dist = new_distance;
153 best_size = new_scale;
154 best_index = strike_index;
155 }
156 }
157
158 if 0 == unsafe { FT_Select_Size(self.face.as_ptr(), best_index) } {
159 Ok(Au::from_f64_px(best_size.1 as f64 / 64.0))
160 } else {
161 Err("FT_Select_Size failed")
162 }
163 }
164
165 pub(crate) fn glyph_load_flags(&self) -> FT_Int32 {
167 let mut load_flags = FT_LOAD_DEFAULT;
168
169 load_flags |= FT_LOAD_TARGET_LIGHT;
174
175 let face_flags = self.as_ref().face_flags;
176 if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 {
177 load_flags |= FT_LOAD_COLOR;
181 }
182
183 load_flags as FT_Int32
184 }
185
186 pub(crate) fn set_variations_for_font(
192 &self,
193 variations: &[FontVariation],
194 library: &FreeTypeLibraryHandle,
195 ) -> Result<Vec<FontVariation>, &'static str> {
196 if !unsafe { FT_HAS_MULTIPLE_MASTERS(self.as_ptr()) } ||
197 variations.is_empty() ||
198 !servo_config::pref!(layout_variable_fonts_enabled)
199 {
200 return Ok(vec![]);
202 }
203
204 let mut mm_var: *mut FT_MM_Var = ptr::null_mut();
206 let result = unsafe { FT_Get_MM_Var(self.as_ptr(), &mut mm_var as *mut _) };
207 if !result.succeeded() {
208 return Err("Failed to query font variations");
209 }
210
211 let num_axis = unsafe { (*mm_var).num_axis } as usize;
214 let mut normalized_axis_values = Vec::with_capacity(variations.len());
215 let mut coords = vec![0; num_axis];
216 for (index, coord) in coords.iter_mut().enumerate() {
217 let axis_data = unsafe { &*(*mm_var).axis.add(index) };
218 let Some(variation) = variations
219 .iter()
220 .find(|variation| variation.tag == axis_data.tag as u32)
221 else {
222 *coord = axis_data.def;
223 continue;
224 };
225
226 let shift_factor = 16.0_f32.exp2();
228 let min_value = axis_data.minimum as f32 / shift_factor;
229 let max_value = axis_data.maximum as f32 / shift_factor;
230 normalized_axis_values.push(FontVariation {
231 tag: variation.tag,
232 value: variation.value.min(max_value).max(min_value),
233 });
234
235 *coord = (variation.value * shift_factor) as FT_Fixed;
236 }
237
238 unsafe {
240 FT_Done_MM_Var(library.freetype_library, mm_var);
241 }
242
243 let result = unsafe {
245 FT_Set_Var_Design_Coordinates(self.as_ptr(), coords.len() as u32, coords.as_ptr())
246 };
247 if !result.succeeded() {
248 return Err("Could not set variations for font face");
249 }
250
251 Ok(normalized_axis_values)
252 }
253}
254
255unsafe impl Send for FreeTypeFace {}
258
259impl Drop for FreeTypeFace {
260 fn drop(&mut self) {
261 let result_code = {
265 let _guard = FreeTypeLibraryHandle::get().lock();
266 unsafe { FT_Done_Face(self.face.as_ptr()) }
269 };
270 if result_code != 0 {
271 log::error!("FT_Done_Face failed: {result_code}");
272 }
273 }
274}