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