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 }