1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use api::{ColorU, GlyphDimensions, FontKey, FontRenderMode};
6 use api::{FontInstancePlatformOptions, FontLCDFilter, FontHinting};
7 use api::{FontInstanceFlags, FontVariation, NativeFontHandle};
8 use freetype::freetype::{FT_BBox, FT_Outline_Translate, FT_Pixel_Mode, FT_Render_Mode};
9 use freetype::freetype::{FT_Done_Face, FT_Error, FT_Get_Char_Index, FT_Int32};
10 use freetype::freetype::{FT_Done_FreeType, FT_Library_SetLcdFilter, FT_Pos};
11 use freetype::freetype::{FT_F26Dot6, FT_Face, FT_Glyph_Format, FT_Long, FT_UInt};
12 use freetype::freetype::{FT_GlyphSlot, FT_LcdFilter, FT_New_Face, FT_New_Memory_Face};
13 use freetype::freetype::{FT_Init_FreeType, FT_Load_Glyph, FT_Render_Glyph};
14 use freetype::freetype::{FT_Library, FT_Outline_Get_CBox, FT_Set_Char_Size, FT_Select_Size};
15 use freetype::freetype::{FT_Fixed, FT_Matrix, FT_Set_Transform, FT_String, FT_ULong, FT_Vector};
16 use freetype::freetype::{FT_Err_Unimplemented_Feature, FT_MulFix, FT_Outline_Embolden};
17 use freetype::freetype::{FT_LOAD_COLOR, FT_LOAD_DEFAULT, FT_LOAD_FORCE_AUTOHINT};
18 use freetype::freetype::{FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH, FT_LOAD_NO_AUTOHINT};
19 use freetype::freetype::{FT_LOAD_NO_BITMAP, FT_LOAD_NO_HINTING};
20 use freetype::freetype::{FT_FACE_FLAG_SCALABLE, FT_FACE_FLAG_FIXED_SIZES};
21 use freetype::freetype::{FT_FACE_FLAG_MULTIPLE_MASTERS};
22 use freetype::succeeded;
23 use crate::glyph_rasterizer::{FontInstance, GlyphFormat, GlyphKey};
24 use crate::glyph_rasterizer::{GlyphRasterError, GlyphRasterResult, RasterizedGlyph};
25 use crate::internal_types::{FastHashMap, ResourceCacheError};
26 #[cfg(any(not(target_os = "android"), feature = "no_static_freetype"))]
27 use libc::{dlsym, RTLD_DEFAULT};
28 use libc::free;
29 use std::{cmp, mem, ptr, slice};
30 use std::cmp::max;
31 use std::collections::hash_map::Entry;
32 use std::ffi::CString;
33 use std::sync::Arc;
34 
35 // These constants are not present in the freetype
36 // bindings due to bindgen not handling the way
37 // the macros are defined.
38 //const FT_LOAD_TARGET_NORMAL: FT_UInt = 0 << 16;
39 const FT_LOAD_TARGET_LIGHT: FT_UInt  = 1 << 16;
40 const FT_LOAD_TARGET_MONO: FT_UInt   = 2 << 16;
41 const FT_LOAD_TARGET_LCD: FT_UInt    = 3 << 16;
42 const FT_LOAD_TARGET_LCD_V: FT_UInt  = 4 << 16;
43 
44 #[repr(C)]
45 struct FT_Var_Axis {
46     pub name: *mut FT_String,
47     pub minimum: FT_Fixed,
48     pub def: FT_Fixed,
49     pub maximum: FT_Fixed,
50     pub tag: FT_ULong,
51     pub strid: FT_UInt,
52 }
53 
54 #[repr(C)]
55 struct FT_Var_Named_Style {
56     pub coords: *mut FT_Fixed,
57     pub strid: FT_UInt,
58     pub psid: FT_UInt,
59 }
60 
61 #[repr(C)]
62 struct FT_MM_Var {
63     pub num_axis: FT_UInt,
64     pub num_designs: FT_UInt,
65     pub num_namedstyles: FT_UInt,
66     pub axis: *mut FT_Var_Axis,
67     pub namedstyle: *mut FT_Var_Named_Style,
68 }
69 
70 #[inline]
unimplemented(error: FT_Error) -> bool71 pub fn unimplemented(error: FT_Error) -> bool {
72     error == FT_Err_Unimplemented_Feature as FT_Error
73 }
74 
75 // Use dlsym to check for symbols. If not available. just return an unimplemented error.
76 #[cfg(any(not(target_os = "android"), feature = "no_static_freetype"))]
77 macro_rules! ft_dyn_fn {
78     ($func_name:ident($($arg_name:ident:$arg_type:ty),*) -> FT_Error) => {
79         #[allow(non_snake_case)]
80         unsafe fn $func_name($($arg_name:$arg_type),*) -> FT_Error {
81             extern "C" fn unimpl_func($(_:$arg_type),*) -> FT_Error {
82                 FT_Err_Unimplemented_Feature as FT_Error
83             }
84             lazy_static! {
85                 static ref FUNC: unsafe extern "C" fn($($arg_type),*) -> FT_Error = {
86                     unsafe {
87                         let cname = CString::new(stringify!($func_name)).unwrap();
88                         let ptr = dlsym(RTLD_DEFAULT, cname.as_ptr());
89                         if !ptr.is_null() { mem::transmute(ptr) } else { unimpl_func }
90                     }
91                 };
92             }
93             (*FUNC)($($arg_name),*)
94         }
95     }
96 }
97 
98 // On Android, just statically link in the symbols...
99 #[cfg(all(target_os = "android", not(feature = "no_static_freetype")))]
100 macro_rules! ft_dyn_fn {
101     ($($proto:tt)+) => { extern "C" { fn $($proto)+; } }
102 }
103 
104 ft_dyn_fn!(FT_Get_MM_Var(face: FT_Face, desc: *mut *mut FT_MM_Var) -> FT_Error);
105 ft_dyn_fn!(FT_Done_MM_Var(library: FT_Library, desc: *mut FT_MM_Var) -> FT_Error);
106 ft_dyn_fn!(FT_Set_Var_Design_Coordinates(face: FT_Face, num_vals: FT_UInt, vals: *mut FT_Fixed) -> FT_Error);
107 ft_dyn_fn!(FT_Get_Var_Design_Coordinates(face: FT_Face, num_vals: FT_UInt, vals: *mut FT_Fixed) -> FT_Error);
108 
109 extern "C" {
FT_GlyphSlot_Embolden(slot: FT_GlyphSlot)110     fn FT_GlyphSlot_Embolden(slot: FT_GlyphSlot);
111 }
112 
113 // Custom version of FT_GlyphSlot_Embolden to be less aggressive with outline
114 // fonts than the default implementation in FreeType.
115 #[no_mangle]
mozilla_glyphslot_embolden_less(slot: FT_GlyphSlot)116 pub extern "C" fn mozilla_glyphslot_embolden_less(slot: FT_GlyphSlot) {
117     if slot.is_null() {
118         return;
119     }
120 
121     let slot_ = unsafe { &mut *slot };
122     let format = slot_.format;
123     if format != FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE {
124         // For non-outline glyphs, just fall back to FreeType's function.
125         unsafe { FT_GlyphSlot_Embolden(slot) };
126         return;
127     }
128 
129     let face_ = unsafe { *slot_.face };
130 
131     // FT_GlyphSlot_Embolden uses a divisor of 24 here; we'll be only half as
132     // bold.
133     let size_ = unsafe { *face_.size };
134     let strength =
135         unsafe { FT_MulFix(face_.units_per_EM as FT_Long,
136                            size_.metrics.y_scale) / 48 };
137     unsafe { FT_Outline_Embolden(&mut slot_.outline, strength) };
138 
139     // Adjust metrics to suit the fattened glyph.
140     if slot_.advance.x != 0 {
141         slot_.advance.x += strength;
142     }
143     if slot_.advance.y != 0 {
144         slot_.advance.y += strength;
145     }
146     slot_.metrics.width += strength;
147     slot_.metrics.height += strength;
148     slot_.metrics.horiAdvance += strength;
149     slot_.metrics.vertAdvance += strength;
150     slot_.metrics.horiBearingY += strength;
151 }
152 
153 enum FontFile {
154     Pathname(CString),
155     Data(Arc<Vec<u8>>),
156 }
157 
158 struct FontFace {
159     // Raw byte data has to live until the font is deleted, according to
160     // https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_New_Memory_Face
161     file: FontFile,
162     index: u32,
163     face: FT_Face,
164     mm_var: *mut FT_MM_Var,
165 }
166 
167 impl Drop for FontFace {
drop(&mut self)168     fn drop(&mut self) {
169         unsafe {
170             if !self.mm_var.is_null() &&
171                unimplemented(FT_Done_MM_Var((*(*self.face).glyph).library, self.mm_var)) {
172                 free(self.mm_var as _);
173             }
174 
175             FT_Done_Face(self.face);
176         }
177     }
178 }
179 
180 struct VariationFace(FT_Face);
181 
182 impl Drop for VariationFace {
drop(&mut self)183     fn drop(&mut self) {
184         unsafe { FT_Done_Face(self.0) };
185     }
186 }
187 
new_ft_face(font_key: &FontKey, lib: FT_Library, file: &FontFile, index: u32) -> Result<FT_Face, FT_Error>188 fn new_ft_face(font_key: &FontKey, lib: FT_Library, file: &FontFile, index: u32) -> Result<FT_Face, FT_Error> {
189     unsafe {
190         let mut face: FT_Face = ptr::null_mut();
191         let result = match file {
192             FontFile::Pathname(ref cstr) => FT_New_Face(
193                 lib,
194                 cstr.as_ptr(),
195                 index as FT_Long,
196                 &mut face,
197             ),
198             FontFile::Data(ref bytes) => FT_New_Memory_Face(
199                 lib,
200                 bytes.as_ptr(),
201                 bytes.len() as FT_Long,
202                 index as FT_Long,
203                 &mut face,
204             ),
205         };
206         if succeeded(result) && !face.is_null() {
207             Ok(face)
208         } else {
209             warn!("WARN: webrender failed to load font");
210             debug!("font={:?}, result={:?}", font_key, result);
211             Err(result)
212         }
213     }
214 }
215 
216 pub struct FontContext {
217     lib: FT_Library,
218     faces: FastHashMap<FontKey, FontFace>,
219     variations: FastHashMap<(FontKey, Vec<FontVariation>), VariationFace>,
220     lcd_extra_pixels: i64,
221 }
222 
223 // FreeType resources are safe to move between threads as long as they
224 // are not concurrently accessed. In our case, everything is hidden inside
225 // a given FontContext so it is safe to move the latter between threads.
226 unsafe impl Send for FontContext {}
227 
get_skew_bounds(bottom: i32, top: i32, skew_factor: f32, _vertical: bool) -> (f32, f32)228 fn get_skew_bounds(bottom: i32, top: i32, skew_factor: f32, _vertical: bool) -> (f32, f32) {
229     let skew_min = (bottom as f32 + 0.5) * skew_factor;
230     let skew_max = (top as f32 - 0.5) * skew_factor;
231     // Negative skew factor may switch the sense of skew_min and skew_max.
232     (skew_min.min(skew_max).floor(), skew_min.max(skew_max).ceil())
233 }
234 
skew_bitmap( bitmap: &[u8], width: usize, height: usize, left: i32, top: i32, skew_factor: f32, vertical: bool, ) -> (Vec<u8>, usize, i32)235 fn skew_bitmap(
236     bitmap: &[u8],
237     width: usize,
238     height: usize,
239     left: i32,
240     top: i32,
241     skew_factor: f32,
242     vertical: bool, // TODO: vertical skew not yet implemented!
243 ) -> (Vec<u8>, usize, i32) {
244     let stride = width * 4;
245     // Calculate the skewed horizontal offsets of the bottom and top of the glyph.
246     let (skew_min, skew_max) = get_skew_bounds(top - height as i32, top, skew_factor, vertical);
247     // Allocate enough extra width for the min/max skew offsets.
248     let skew_width = width + (skew_max - skew_min) as usize;
249     let mut skew_buffer = vec![0u8; skew_width * height * 4];
250     for y in 0 .. height {
251         // Calculate a skew offset at the vertical center of the current row.
252         let offset = (top as f32 - y as f32 - 0.5) * skew_factor - skew_min;
253         // Get a blend factor in 0..256 constant across all pixels in the row.
254         let blend = (offset.fract() * 256.0) as u32;
255         let src_row = y * stride;
256         let dest_row = (y * skew_width + offset.floor() as usize) * 4;
257         let mut prev_px = [0u32; 4];
258         for (src, dest) in
259             bitmap[src_row .. src_row + stride].chunks(4).zip(
260                 skew_buffer[dest_row .. dest_row + stride].chunks_mut(4)
261             ) {
262             let px = [src[0] as u32, src[1] as u32, src[2] as u32, src[3] as u32];
263             // Blend current pixel with previous pixel based on blend factor.
264             let next_px = [px[0] * blend, px[1] * blend, px[2] * blend, px[3] * blend];
265             dest[0] = ((((px[0] << 8) - next_px[0]) + prev_px[0] + 128) >> 8) as u8;
266             dest[1] = ((((px[1] << 8) - next_px[1]) + prev_px[1] + 128) >> 8) as u8;
267             dest[2] = ((((px[2] << 8) - next_px[2]) + prev_px[2] + 128) >> 8) as u8;
268             dest[3] = ((((px[3] << 8) - next_px[3]) + prev_px[3] + 128) >> 8) as u8;
269             // Save the remainder for blending onto the next pixel.
270             prev_px = next_px;
271         }
272         // If the skew misaligns the final pixel, write out the remainder.
273         if blend > 0 {
274             let dest = &mut skew_buffer[dest_row + stride .. dest_row + stride + 4];
275             dest[0] = ((prev_px[0] + 128) >> 8) as u8;
276             dest[1] = ((prev_px[1] + 128) >> 8) as u8;
277             dest[2] = ((prev_px[2] + 128) >> 8) as u8;
278             dest[3] = ((prev_px[3] + 128) >> 8) as u8;
279         }
280     }
281     (skew_buffer, skew_width, left + skew_min as i32)
282 }
283 
transpose_bitmap(bitmap: &[u8], width: usize, height: usize) -> Vec<u8>284 fn transpose_bitmap(bitmap: &[u8], width: usize, height: usize) -> Vec<u8> {
285     let mut transposed = vec![0u8; width * height * 4];
286     for (y, row) in bitmap.chunks(width * 4).enumerate() {
287         let mut offset = y * 4;
288         for src in row.chunks(4) {
289             transposed[offset .. offset + 4].copy_from_slice(src);
290             offset += height * 4;
291         }
292     }
293     transposed
294 }
295 
flip_bitmap_x(bitmap: &mut [u8], width: usize, height: usize)296 fn flip_bitmap_x(bitmap: &mut [u8], width: usize, height: usize) {
297     assert!(bitmap.len() == width * height * 4);
298     let pixels = unsafe { slice::from_raw_parts_mut(bitmap.as_mut_ptr() as *mut u32, width * height) };
299     for row in pixels.chunks_mut(width) {
300         row.reverse();
301     }
302 }
303 
flip_bitmap_y(bitmap: &mut [u8], width: usize, height: usize)304 fn flip_bitmap_y(bitmap: &mut [u8], width: usize, height: usize) {
305     assert!(bitmap.len() == width * height * 4);
306     let pixels = unsafe { slice::from_raw_parts_mut(bitmap.as_mut_ptr() as *mut u32, width * height) };
307     for y in 0 .. height / 2 {
308         let low_row = y * width;
309         let high_row = (height - 1 - y) * width;
310         for x in 0 .. width {
311             pixels.swap(low_row + x, high_row + x);
312         }
313     }
314 }
315 
316 impl FontContext {
new() -> Result<FontContext, ResourceCacheError>317     pub fn new() -> Result<FontContext, ResourceCacheError> {
318         let mut lib: FT_Library = ptr::null_mut();
319 
320         // Using an LCD filter may add one full pixel to each side if support is built in.
321         // As of FreeType 2.8.1, an LCD filter is always used regardless of settings
322         // if support for the patent-encumbered LCD filter algorithms is not built in.
323         // Thus, the only reasonable way to guess padding is to unconditonally add it if
324         // subpixel AA is used.
325         let lcd_extra_pixels = 1;
326 
327         let result = unsafe {
328             FT_Init_FreeType(&mut lib)
329         };
330 
331         if succeeded(result) {
332             Ok(FontContext {
333                 lib,
334                 faces: FastHashMap::default(),
335                 variations: FastHashMap::default(),
336                 lcd_extra_pixels,
337             })
338         } else {
339             // TODO(gw): Provide detailed error values.
340             // Once this panic has been here for a while with no issues we should get rid of
341             // ResourceCacheError as this was the only place that could fail previously.
342             panic!("Failed to initialize FreeType - {}", result)
343         }
344     }
345 
has_font(&self, font_key: &FontKey) -> bool346     pub fn has_font(&self, font_key: &FontKey) -> bool {
347         self.faces.contains_key(font_key)
348     }
349 
add_raw_font(&mut self, font_key: &FontKey, bytes: Arc<Vec<u8>>, index: u32)350     pub fn add_raw_font(&mut self, font_key: &FontKey, bytes: Arc<Vec<u8>>, index: u32) {
351         if !self.faces.contains_key(font_key) {
352             let len = bytes.len();
353             let file = FontFile::Data(bytes);
354             if let Ok(face) = new_ft_face(font_key, self.lib, &file, index) {
355                 self.faces.insert(*font_key, FontFace { file, index, face, mm_var: ptr::null_mut() });
356             } else {
357                 panic!("adding raw font failed: {} bytes", len);
358             }
359         }
360     }
361 
add_native_font(&mut self, font_key: &FontKey, native_font_handle: NativeFontHandle)362     pub fn add_native_font(&mut self, font_key: &FontKey, native_font_handle: NativeFontHandle) {
363         if !self.faces.contains_key(font_key) {
364             let str = native_font_handle.path.as_os_str().to_str().unwrap();
365             let cstr = CString::new(str).unwrap();
366             let file = FontFile::Pathname(cstr);
367             let index = native_font_handle.index;
368             match new_ft_face(font_key, self.lib, &file, index) {
369                 Ok(face) => self.faces.insert(*font_key, FontFace { file, index, face, mm_var: ptr::null_mut() }),
370                 Err(result) => panic!("adding native font failed: file={} err={:?}", str, result),
371             };
372         }
373     }
374 
delete_font(&mut self, font_key: &FontKey)375     pub fn delete_font(&mut self, font_key: &FontKey) {
376         if self.faces.remove(font_key).is_some() {
377             self.variations.retain(|k, _| k.0 != *font_key);
378         }
379     }
380 
delete_font_instance(&mut self, instance: &FontInstance)381     pub fn delete_font_instance(&mut self, instance: &FontInstance) {
382         // Ensure we don't keep around excessive amounts of stale variations.
383         if !instance.variations.is_empty() {
384             self.variations.remove(&(instance.font_key, instance.variations.clone()));
385         }
386     }
387 
get_ft_face(&mut self, font: &FontInstance) -> Option<FT_Face>388     fn get_ft_face(&mut self, font: &FontInstance) -> Option<FT_Face> {
389         if font.variations.is_empty() {
390             return Some(self.faces.get(&font.font_key)?.face);
391         }
392         match self.variations.entry((font.font_key, font.variations.clone())) {
393             Entry::Occupied(entry) => Some(entry.get().0),
394             Entry::Vacant(entry) => unsafe {
395                 let normal_face = self.faces.get_mut(&font.font_key)?;
396                 if ((*normal_face.face).face_flags & (FT_FACE_FLAG_MULTIPLE_MASTERS as FT_Long)) == 0 {
397                     return Some(normal_face.face);
398                 }
399                 // Clone a new FT face and attempt to set the variation values on it.
400                 // Leave unspecified values at the defaults.
401                 let var_face = new_ft_face(&font.font_key, self.lib, &normal_face.file, normal_face.index).ok()?;
402                 if !normal_face.mm_var.is_null() ||
403                    succeeded(FT_Get_MM_Var(normal_face.face, &mut normal_face.mm_var)) {
404                     let mm_var = normal_face.mm_var;
405                     let num_axis = (*mm_var).num_axis;
406                     let mut coords: Vec<FT_Fixed> = Vec::with_capacity(num_axis as usize);
407 
408                     // Calling this before FT_Set_Var_Design_Coordinates avoids a bug with font variations
409                     // not initialized properly in the font face, even if we ignore the result.
410                     // See bug 1647035.
411                     let mut tmp = [0; 16];
412                     let res = FT_Get_Var_Design_Coordinates(
413                         normal_face.face,
414                         num_axis.min(16),
415                         tmp.as_mut_ptr()
416                     );
417                     debug_assert!(succeeded(res));
418 
419 
420                     for i in 0 .. num_axis {
421                         let axis = (*mm_var).axis.offset(i as isize);
422                         let mut value = (*axis).def;
423                         for var in &font.variations {
424                             if var.tag as FT_ULong == (*axis).tag {
425                                 value = (var.value * 65536.0 + 0.5) as FT_Fixed;
426                                 value = cmp::min(value, (*axis).maximum);
427                                 value = cmp::max(value, (*axis).minimum);
428                                 break;
429                             }
430                         }
431                         coords.push(value);
432                     }
433                     let res = FT_Set_Var_Design_Coordinates(var_face, num_axis, coords.as_mut_ptr());
434                     debug_assert!(succeeded(res));
435                 }
436                 entry.insert(VariationFace(var_face));
437                 Some(var_face)
438             }
439         }
440     }
441 
load_glyph(&mut self, font: &FontInstance, glyph: &GlyphKey) -> Option<(FT_GlyphSlot, f32)>442     fn load_glyph(&mut self, font: &FontInstance, glyph: &GlyphKey) -> Option<(FT_GlyphSlot, f32)> {
443         let face = self.get_ft_face(font)?;
444 
445         let mut load_flags = FT_LOAD_DEFAULT;
446         let FontInstancePlatformOptions { mut hinting, .. } = font.platform_options.unwrap_or_default();
447         // Disable hinting if there is a non-axis-aligned transform.
448         if font.synthetic_italics.is_enabled() ||
449            ((font.transform.scale_x != 0.0 || font.transform.scale_y != 0.0) &&
450             (font.transform.skew_x != 0.0 || font.transform.skew_y != 0.0)) {
451             hinting = FontHinting::None;
452         }
453         match (hinting, font.render_mode) {
454             (FontHinting::None, _) => load_flags |= FT_LOAD_NO_HINTING,
455             (FontHinting::Mono, _) => load_flags = FT_LOAD_TARGET_MONO,
456             (FontHinting::Light, _) => load_flags = FT_LOAD_TARGET_LIGHT,
457             (FontHinting::LCD, FontRenderMode::Subpixel) => {
458                 load_flags = if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
459                     FT_LOAD_TARGET_LCD_V
460                 } else {
461                     FT_LOAD_TARGET_LCD
462                 };
463                 if font.flags.contains(FontInstanceFlags::FORCE_AUTOHINT) {
464                     load_flags |= FT_LOAD_FORCE_AUTOHINT;
465                 }
466             }
467             _ => {
468                 if font.flags.contains(FontInstanceFlags::FORCE_AUTOHINT) {
469                     load_flags |= FT_LOAD_FORCE_AUTOHINT;
470                 }
471             }
472         }
473 
474         if font.flags.contains(FontInstanceFlags::NO_AUTOHINT) {
475             load_flags |= FT_LOAD_NO_AUTOHINT;
476         }
477         if !font.flags.contains(FontInstanceFlags::EMBEDDED_BITMAPS) {
478             load_flags |= FT_LOAD_NO_BITMAP;
479         }
480 
481         let face_flags = unsafe { (*face).face_flags };
482         if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 {
483           // We only set FT_LOAD_COLOR if there are bitmap strikes;
484           // COLR (color-layer) fonts are handled internally by Gecko, and
485           // WebRender is just asked to paint individual layers.
486           load_flags |= FT_LOAD_COLOR;
487         }
488 
489         load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
490 
491         let (x_scale, y_scale) = font.transform.compute_scale().unwrap_or((1.0, 1.0));
492         let req_size = font.size.to_f64_px();
493 
494         let mut result = if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 &&
495                             (face_flags & (FT_FACE_FLAG_SCALABLE as FT_Long)) == 0 &&
496                             (load_flags & FT_LOAD_NO_BITMAP) == 0 {
497             unsafe { FT_Set_Transform(face, ptr::null_mut(), ptr::null_mut()) };
498             self.choose_bitmap_size(face, req_size * y_scale)
499         } else {
500             let mut shape = font.transform.invert_scale(x_scale, y_scale);
501             if font.flags.contains(FontInstanceFlags::FLIP_X) {
502                 shape = shape.flip_x();
503             }
504             if font.flags.contains(FontInstanceFlags::FLIP_Y) {
505                 shape = shape.flip_y();
506             }
507             if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
508                 shape = shape.swap_xy();
509             }
510             let (mut tx, mut ty) = (0.0, 0.0);
511             if font.synthetic_italics.is_enabled() {
512                 let (shape_, (tx_, ty_)) = font.synthesize_italics(shape, y_scale * req_size);
513                 shape = shape_;
514                 tx = tx_;
515                 ty = ty_;
516             };
517             let mut ft_shape = FT_Matrix {
518                 xx: (shape.scale_x * 65536.0) as FT_Fixed,
519                 xy: (shape.skew_x * -65536.0) as FT_Fixed,
520                 yx: (shape.skew_y * -65536.0) as FT_Fixed,
521                 yy: (shape.scale_y * 65536.0) as FT_Fixed,
522             };
523             // The delta vector for FT_Set_Transform is in units of 1/64 pixel.
524             let mut ft_delta = FT_Vector {
525                 x: (tx * 64.0) as FT_F26Dot6,
526                 y: (ty * -64.0) as FT_F26Dot6,
527             };
528             unsafe {
529                 FT_Set_Transform(face, &mut ft_shape, &mut ft_delta);
530                 FT_Set_Char_Size(
531                     face,
532                     (req_size * x_scale * 64.0 + 0.5) as FT_F26Dot6,
533                     (req_size * y_scale * 64.0 + 0.5) as FT_F26Dot6,
534                     0,
535                     0,
536                 )
537             }
538         };
539 
540         if !succeeded(result) {
541             error!("Unable to set glyph size and transform: {}", result);
542             //let raw_error = unsafe { FT_Error_String(result) };
543             //if !raw_error.is_ptr() {
544             //    error!("\tcode {:?}", CStr::from_ptr(raw_error));
545             //}
546             debug!(
547                 "\t[{}] for size {:?} and scale {:?} from font {:?}",
548                 glyph.index(),
549                 req_size,
550                 (x_scale, y_scale),
551                 font.font_key,
552             );
553             return None;
554         }
555 
556         result = unsafe { FT_Load_Glyph(face, glyph.index() as FT_UInt, load_flags as FT_Int32) };
557         if !succeeded(result) {
558             error!("Unable to load glyph: {}", result);
559             //let raw_error = unsafe { FT_Error_String(result) };
560             //if !raw_error.is_ptr() {
561             //    error!("\tcode {:?}", CStr::from_ptr(raw_error));
562             //}
563             debug!(
564                 "\t[{}] with flags {:?} from font {:?}",
565                 glyph.index(),
566                 load_flags,
567                 font.font_key,
568             );
569             return None;
570         }
571 
572         let slot = unsafe { (*face).glyph };
573         assert!(slot != ptr::null_mut());
574 
575         if font.flags.contains(FontInstanceFlags::SYNTHETIC_BOLD) {
576             mozilla_glyphslot_embolden_less(slot);
577         }
578 
579         let format = unsafe { (*slot).format };
580         match format {
581             FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
582                 let bitmap_size = unsafe { (*(*(*slot).face).size).metrics.y_ppem };
583                 Some((slot, req_size as f32 / bitmap_size as f32))
584             }
585             FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => Some((slot, 1.0)),
586             _ => {
587                 error!("Unsupported format");
588                 debug!("format={:?}", format);
589                 None
590             }
591         }
592     }
593 
pad_bounding_box(&self, font: &FontInstance, cbox: &mut FT_BBox)594     fn pad_bounding_box(&self, font: &FontInstance, cbox: &mut FT_BBox) {
595         // Apply extra pixel of padding for subpixel AA, due to the filter.
596         if font.render_mode == FontRenderMode::Subpixel {
597             let padding = (self.lcd_extra_pixels * 64) as FT_Pos;
598             if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
599                 cbox.yMin -= padding;
600                 cbox.yMax += padding;
601             } else {
602                 cbox.xMin -= padding;
603                 cbox.xMax += padding;
604             }
605         }
606     }
607 
608     // Get the bounding box for a glyph, accounting for sub-pixel positioning.
get_bounding_box( &self, slot: FT_GlyphSlot, font: &FontInstance, glyph: &GlyphKey, scale: f32, ) -> FT_BBox609     fn get_bounding_box(
610         &self,
611         slot: FT_GlyphSlot,
612         font: &FontInstance,
613         glyph: &GlyphKey,
614         scale: f32,
615     ) -> FT_BBox {
616         // Get the estimated bounding box from FT (control points).
617         let mut cbox = FT_BBox { xMin: 0, yMin: 0, xMax: 0, yMax: 0 };
618 
619         unsafe {
620             FT_Outline_Get_CBox(&(*slot).outline, &mut cbox);
621         }
622 
623         // For spaces and other non-printable characters, early out.
624         if unsafe { (*slot).outline.n_contours } == 0 {
625             return cbox;
626         }
627 
628         self.pad_bounding_box(font, &mut cbox);
629 
630         // Offset the bounding box by subpixel positioning.
631         // Convert to 26.6 fixed point format for FT.
632         let (dx, dy) = font.get_subpx_offset(glyph);
633         let (dx, dy) = (
634             (dx / scale as f64 * 64.0 + 0.5) as FT_Pos,
635             -(dy / scale as f64 * 64.0 + 0.5) as FT_Pos,
636         );
637         cbox.xMin += dx;
638         cbox.xMax += dx;
639         cbox.yMin += dy;
640         cbox.yMax += dy;
641 
642         // Outset the box to device pixel boundaries
643         cbox.xMin &= !63;
644         cbox.yMin &= !63;
645         cbox.xMax = (cbox.xMax + 63) & !63;
646         cbox.yMax = (cbox.yMax + 63) & !63;
647 
648         cbox
649     }
650 
get_glyph_dimensions_impl( &self, slot: FT_GlyphSlot, font: &FontInstance, glyph: &GlyphKey, scale: f32, use_transform: bool, ) -> Option<GlyphDimensions>651     fn get_glyph_dimensions_impl(
652         &self,
653         slot: FT_GlyphSlot,
654         font: &FontInstance,
655         glyph: &GlyphKey,
656         scale: f32,
657         use_transform: bool,
658     ) -> Option<GlyphDimensions> {
659         let format = unsafe { (*slot).format };
660         let (mut left, mut top, mut width, mut height) = match format {
661             FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
662                 unsafe { (
663                     (*slot).bitmap_left as i32,
664                     (*slot).bitmap_top as i32,
665                     (*slot).bitmap.width as i32,
666                     (*slot).bitmap.rows as i32,
667                 ) }
668             }
669             FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
670                 let cbox = self.get_bounding_box(slot, font, glyph, scale);
671                 (
672                     (cbox.xMin >> 6) as i32,
673                     (cbox.yMax >> 6) as i32,
674                     ((cbox.xMax - cbox.xMin) >> 6) as i32,
675                     ((cbox.yMax - cbox.yMin) >> 6) as i32,
676                 )
677             }
678             _ => return None,
679         };
680         let mut advance = unsafe { (*slot).metrics.horiAdvance as f32 / 64.0 };
681         if use_transform {
682             if scale != 1.0 {
683                 let x0 = left as f32 * scale;
684                 let x1 = width as f32 * scale + x0;
685                 let y1 = top as f32 * scale;
686                 let y0 = y1 - height as f32 * scale;
687                 left = x0.round() as i32;
688                 top = y1.round() as i32;
689                 width = (x1.ceil() - x0.floor()) as i32;
690                 height = (y1.ceil() - y0.floor()) as i32;
691                 advance *= scale;
692             }
693             // An outline glyph's cbox would have already been transformed inside FT_Load_Glyph,
694             // so only handle bitmap glyphs which are not handled by FT_Load_Glyph.
695             if format == FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP {
696                 if font.synthetic_italics.is_enabled() {
697                     let (skew_min, skew_max) = get_skew_bounds(
698                         top - height as i32,
699                         top,
700                         font.synthetic_italics.to_skew(),
701                         font.flags.contains(FontInstanceFlags::VERTICAL),
702                     );
703                     left += skew_min as i32;
704                     width += (skew_max - skew_min) as i32;
705                 }
706                 if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
707                     mem::swap(&mut width, &mut height);
708                     mem::swap(&mut left, &mut top);
709                     left -= width as i32;
710                     top += height as i32;
711                 }
712                 if font.flags.contains(FontInstanceFlags::FLIP_X) {
713                     left = -(left + width as i32);
714                 }
715                 if font.flags.contains(FontInstanceFlags::FLIP_Y) {
716                     top = -(top - height as i32);
717                 }
718             }
719         }
720         Some(GlyphDimensions {
721             left,
722             top,
723             width,
724             height,
725             advance,
726         })
727     }
728 
get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32>729     pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
730         let face = self.faces.get(&font_key)?.face;
731         unsafe {
732             let idx = FT_Get_Char_Index(face, ch as _);
733             if idx != 0 {
734                 Some(idx)
735             } else {
736                 None
737             }
738         }
739     }
740 
get_glyph_dimensions( &mut self, font: &FontInstance, key: &GlyphKey, ) -> Option<GlyphDimensions>741     pub fn get_glyph_dimensions(
742         &mut self,
743         font: &FontInstance,
744         key: &GlyphKey,
745     ) -> Option<GlyphDimensions> {
746         let slot = self.load_glyph(font, key);
747         slot.and_then(|(slot, scale)| self.get_glyph_dimensions_impl(slot, &font, key, scale, true))
748     }
749 
choose_bitmap_size(&self, face: FT_Face, requested_size: f64) -> FT_Error750     fn choose_bitmap_size(&self, face: FT_Face, requested_size: f64) -> FT_Error {
751         let mut best_dist = unsafe { *(*face).available_sizes.offset(0) }.y_ppem as f64 / 64.0 - requested_size;
752         let mut best_size = 0;
753         let num_fixed_sizes = unsafe { (*face).num_fixed_sizes };
754         for i in 1 .. num_fixed_sizes {
755             // Distance is positive if strike is larger than desired size,
756             // or negative if smaller. If previously a found smaller strike,
757             // then prefer a larger strike. Otherwise, minimize distance.
758             let dist = unsafe { *(*face).available_sizes.offset(i as isize) }.y_ppem as f64 / 64.0 - requested_size;
759             if (best_dist < 0.0 && dist >= best_dist) || dist.abs() <= best_dist {
760                 best_dist = dist;
761                 best_size = i;
762             }
763         }
764         unsafe { FT_Select_Size(face, best_size) }
765     }
766 
prepare_font(font: &mut FontInstance)767     pub fn prepare_font(font: &mut FontInstance) {
768         match font.render_mode {
769             FontRenderMode::Mono => {
770                 // In mono mode the color of the font is irrelevant.
771                 font.color = ColorU::new(0xFF, 0xFF, 0xFF, 0xFF);
772                 // Subpixel positioning is disabled in mono mode.
773                 font.disable_subpixel_position();
774             }
775             FontRenderMode::Alpha | FontRenderMode::Subpixel => {
776                 // We don't do any preblending with FreeType currently, so the color is not used.
777                 font.color = ColorU::new(0xFF, 0xFF, 0xFF, 0xFF);
778             }
779         }
780     }
781 
rasterize_glyph_outline( &mut self, slot: FT_GlyphSlot, font: &FontInstance, key: &GlyphKey, scale: f32, ) -> bool782     fn rasterize_glyph_outline(
783         &mut self,
784         slot: FT_GlyphSlot,
785         font: &FontInstance,
786         key: &GlyphKey,
787         scale: f32,
788     ) -> bool {
789         // Get the subpixel offsets in FT 26.6 format.
790         let (dx, dy) = font.get_subpx_offset(key);
791         let (dx, dy) = (
792             (dx / scale as f64 * 64.0 + 0.5) as FT_Pos,
793             -(dy / scale as f64 * 64.0 + 0.5) as FT_Pos,
794         );
795 
796         // Move the outline curves to be at the origin, taking
797         // into account the subpixel positioning.
798         unsafe {
799             let outline = &(*slot).outline;
800             let mut cbox = FT_BBox { xMin: 0, yMin: 0, xMax: 0, yMax: 0 };
801             FT_Outline_Get_CBox(outline, &mut cbox);
802             self.pad_bounding_box(font, &mut cbox);
803             FT_Outline_Translate(
804                 outline,
805                 dx - ((cbox.xMin + dx) & !63),
806                 dy - ((cbox.yMin + dy) & !63),
807             );
808         }
809 
810         if font.render_mode == FontRenderMode::Subpixel {
811             let FontInstancePlatformOptions { lcd_filter, .. } = font.platform_options.unwrap_or_default();
812             let filter = match lcd_filter {
813                 FontLCDFilter::None => FT_LcdFilter::FT_LCD_FILTER_NONE,
814                 FontLCDFilter::Default => FT_LcdFilter::FT_LCD_FILTER_DEFAULT,
815                 FontLCDFilter::Light => FT_LcdFilter::FT_LCD_FILTER_LIGHT,
816                 FontLCDFilter::Legacy => FT_LcdFilter::FT_LCD_FILTER_LEGACY,
817             };
818             unsafe { FT_Library_SetLcdFilter(self.lib, filter) };
819         }
820         let render_mode = match font.render_mode {
821             FontRenderMode::Mono => FT_Render_Mode::FT_RENDER_MODE_MONO,
822             FontRenderMode::Alpha => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
823             FontRenderMode::Subpixel => if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
824                 FT_Render_Mode::FT_RENDER_MODE_LCD_V
825             } else {
826                 FT_Render_Mode::FT_RENDER_MODE_LCD
827             },
828         };
829         let result = unsafe { FT_Render_Glyph(slot, render_mode) };
830         if !succeeded(result) {
831             error!("Unable to rasterize");
832             debug!(
833                 "{:?} with {:?}, {:?}",
834                 key,
835                 render_mode,
836                 result
837             );
838             false
839         } else {
840             true
841         }
842     }
843 
rasterize_glyph(&mut self, font: &FontInstance, key: &GlyphKey) -> GlyphRasterResult844     pub fn rasterize_glyph(&mut self, font: &FontInstance, key: &GlyphKey) -> GlyphRasterResult {
845         let (slot, scale) = self.load_glyph(font, key).ok_or(GlyphRasterError::LoadFailed)?;
846 
847         // Get dimensions of the glyph, to see if we need to rasterize it.
848         // Don't apply scaling to the dimensions, as the glyph cache needs to know the actual
849         // footprint of the glyph.
850         let dimensions = self.get_glyph_dimensions_impl(slot, font, key, scale, false)
851                              .ok_or(GlyphRasterError::LoadFailed)?;
852         let GlyphDimensions { mut left, mut top, width, height, .. } = dimensions;
853 
854         // For spaces and other non-printable characters, early out.
855         if width == 0 || height == 0 {
856             return Err(GlyphRasterError::LoadFailed);
857         }
858 
859         let format = unsafe { (*slot).format };
860         match format {
861             FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {}
862             FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
863                 if !self.rasterize_glyph_outline(slot, font, key, scale) {
864                     return Err(GlyphRasterError::LoadFailed);
865                 }
866             }
867             _ => {
868                 error!("Unsupported format");
869                 debug!("format={:?}", format);
870                 return Err(GlyphRasterError::LoadFailed);
871             }
872         };
873 
874         debug!(
875             "Rasterizing {:?} as {:?} with dimensions {:?}",
876             key,
877             font.render_mode,
878             dimensions
879         );
880 
881         let bitmap = unsafe { &(*slot).bitmap };
882         let pixel_mode = unsafe { mem::transmute(bitmap.pixel_mode as u32) };
883         let (mut actual_width, mut actual_height) = match pixel_mode {
884             FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
885                 assert!(bitmap.width % 3 == 0);
886                 ((bitmap.width / 3) as usize, bitmap.rows as usize)
887             }
888             FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V => {
889                 assert!(bitmap.rows % 3 == 0);
890                 (bitmap.width as usize, (bitmap.rows / 3) as usize)
891             }
892             FT_Pixel_Mode::FT_PIXEL_MODE_MONO |
893             FT_Pixel_Mode::FT_PIXEL_MODE_GRAY |
894             FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
895                 (bitmap.width as usize, bitmap.rows as usize)
896             }
897             _ => panic!("Unsupported mode"),
898         };
899 
900         // If we need padding, we will need to expand the buffer size.
901         let (buffer_width, buffer_height, padding) = if font.use_texture_padding() {
902             (actual_width + 2, actual_height + 2, 1)
903         } else {
904             (actual_width, actual_height, 0)
905         };
906 
907         let mut final_buffer = vec![0u8; buffer_width * buffer_height * 4];
908 
909         // Extract the final glyph from FT format into BGRA8 format, which is
910         // what WR expects.
911         let subpixel_bgr = font.flags.contains(FontInstanceFlags::SUBPIXEL_BGR);
912         let mut src_row = bitmap.buffer;
913         let mut dest = 4 * padding * (padding + buffer_width);
914         let actual_end = final_buffer.len() - 4 * padding * (buffer_width + 1);
915         while dest < actual_end {
916             let mut src = src_row;
917             let row_end = dest + actual_width * 4;
918             match pixel_mode {
919                 FT_Pixel_Mode::FT_PIXEL_MODE_MONO => {
920                     while dest < row_end {
921                         // Cast the byte to signed so that we can left shift each bit into
922                         // the top bit, then right shift to fill out the bits with 0s or 1s.
923                         let mut byte: i8 = unsafe { *src as i8 };
924                         src = unsafe { src.offset(1) };
925                         let byte_end = cmp::min(row_end, dest + 8 * 4);
926                         while dest < byte_end {
927                             let alpha = (byte >> 7) as u8;
928                             final_buffer[dest + 0] = alpha;
929                             final_buffer[dest + 1] = alpha;
930                             final_buffer[dest + 2] = alpha;
931                             final_buffer[dest + 3] = alpha;
932                             dest += 4;
933                             byte <<= 1;
934                         }
935                     }
936                 }
937                 FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => {
938                     while dest < row_end {
939                         let alpha = unsafe { *src };
940                         final_buffer[dest + 0] = alpha;
941                         final_buffer[dest + 1] = alpha;
942                         final_buffer[dest + 2] = alpha;
943                         final_buffer[dest + 3] = alpha;
944                         src = unsafe { src.offset(1) };
945                         dest += 4;
946                     }
947                 }
948                 FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
949                     while dest < row_end {
950                         let (mut r, g, mut b) = unsafe { (*src, *src.offset(1), *src.offset(2)) };
951                         if subpixel_bgr {
952                             mem::swap(&mut r, &mut b);
953                         }
954                         final_buffer[dest + 0] = b;
955                         final_buffer[dest + 1] = g;
956                         final_buffer[dest + 2] = r;
957                         final_buffer[dest + 3] = max(max(b, g), r);
958                         src = unsafe { src.offset(3) };
959                         dest += 4;
960                     }
961                 }
962                 FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V => {
963                     while dest < row_end {
964                         let (mut r, g, mut b) =
965                             unsafe { (*src, *src.offset(bitmap.pitch as isize), *src.offset((2 * bitmap.pitch) as isize)) };
966                         if subpixel_bgr {
967                             mem::swap(&mut r, &mut b);
968                         }
969                         final_buffer[dest + 0] = b;
970                         final_buffer[dest + 1] = g;
971                         final_buffer[dest + 2] = r;
972                         final_buffer[dest + 3] = max(max(b, g), r);
973                         src = unsafe { src.offset(1) };
974                         dest += 4;
975                     }
976                     src_row = unsafe { src_row.offset((2 * bitmap.pitch) as isize) };
977                 }
978                 FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
979                     // The source is premultiplied BGRA data.
980                     let dest_slice = &mut final_buffer[dest .. row_end];
981                     let src_slice = unsafe { slice::from_raw_parts(src, dest_slice.len()) };
982                     dest_slice.copy_from_slice(src_slice);
983                 }
984                 _ => panic!("Unsupported mode"),
985             }
986             src_row = unsafe { src_row.offset(bitmap.pitch as isize) };
987             dest = row_end + 8 * padding;
988         }
989 
990         if font.use_texture_padding() {
991             left -= padding as i32;
992             top += padding as i32;
993             actual_width = buffer_width;
994             actual_height = buffer_height;
995         }
996 
997         match format {
998             FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
999                 if font.synthetic_italics.is_enabled() {
1000                     let (skew_buffer, skew_width, skew_left) = skew_bitmap(
1001                         &final_buffer,
1002                         actual_width,
1003                         actual_height,
1004                         left,
1005                         top,
1006                         font.synthetic_italics.to_skew(),
1007                         font.flags.contains(FontInstanceFlags::VERTICAL),
1008                     );
1009                     final_buffer = skew_buffer;
1010                     actual_width = skew_width;
1011                     left = skew_left;
1012                 }
1013                 if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
1014                     final_buffer = transpose_bitmap(&final_buffer, actual_width, actual_height);
1015                     mem::swap(&mut actual_width, &mut actual_height);
1016                     mem::swap(&mut left, &mut top);
1017                     left -= actual_width as i32;
1018                     top += actual_height as i32;
1019                 }
1020                 if font.flags.contains(FontInstanceFlags::FLIP_X) {
1021                     flip_bitmap_x(&mut final_buffer, actual_width, actual_height);
1022                     left = -(left + actual_width as i32);
1023                 }
1024                 if font.flags.contains(FontInstanceFlags::FLIP_Y) {
1025                     flip_bitmap_y(&mut final_buffer, actual_width, actual_height);
1026                     top = -(top - actual_height as i32);
1027                 }
1028             }
1029             FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
1030                 unsafe {
1031                     left += (*slot).bitmap_left;
1032                     top += (*slot).bitmap_top - height as i32;
1033                 }
1034             }
1035             _ => {}
1036         }
1037 
1038         let glyph_format = match (pixel_mode, format) {
1039             (FT_Pixel_Mode::FT_PIXEL_MODE_LCD, _) |
1040             (FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V, _) => font.get_subpixel_glyph_format(),
1041             (FT_Pixel_Mode::FT_PIXEL_MODE_BGRA, _) => GlyphFormat::ColorBitmap,
1042             (_, FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP) => GlyphFormat::Bitmap,
1043             _ => font.get_alpha_glyph_format(),
1044         };
1045 
1046         Ok(RasterizedGlyph {
1047             left: left as f32,
1048             top: top as f32,
1049             width: actual_width as i32,
1050             height: actual_height as i32,
1051             scale,
1052             format: glyph_format,
1053             bytes: final_buffer,
1054         })
1055     }
1056 }
1057 
1058 impl Drop for FontContext {
drop(&mut self)1059     fn drop(&mut self) {
1060         self.variations.clear();
1061         self.faces.clear();
1062         unsafe {
1063             FT_Done_FreeType(self.lib);
1064         }
1065     }
1066 }
1067