tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

font.rs (45646B)


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