1#![allow(non_camel_case_types)]
6
7use api::{ColorU, GlyphDimensions, FontKey, FontRenderMode};
8use api::{FontInstancePlatformOptions, FontLCDFilter, FontHinting};
9use api::{FontInstanceFlags, FontTemplate, FontVariation, NativeFontHandle};
10use freetype::freetype::{FT_BBox, FT_Outline_Translate, FT_Pixel_Mode, FT_Render_Mode};
11use freetype::freetype::{FT_Done_Face, FT_Error, FT_Get_Char_Index, FT_Int32};
12use freetype::freetype::{FT_Done_FreeType, FT_Library_SetLcdFilter, FT_Pos};
13use freetype::freetype::{FT_F26Dot6, FT_Face, FT_Glyph_Format, FT_Long, FT_UInt};
14use freetype::freetype::{FT_GlyphSlot, FT_LcdFilter, FT_New_Face, FT_New_Memory_Face};
15use freetype::freetype::{FT_Init_FreeType, FT_Load_Glyph, FT_Render_Glyph};
16use freetype::freetype::{FT_Library, FT_Outline_Get_CBox, FT_Set_Char_Size, FT_Select_Size};
17use freetype::freetype::{FT_Fixed, FT_Matrix, FT_Set_Transform, FT_String, FT_ULong, FT_Vector};
18use freetype::freetype::{FT_Err_Unimplemented_Feature, FT_MulFix, FT_Outline_Embolden};
19use freetype::freetype::{FT_LOAD_COLOR, FT_LOAD_DEFAULT, FT_LOAD_FORCE_AUTOHINT};
20use freetype::freetype::{FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH, FT_LOAD_NO_AUTOHINT};
21use freetype::freetype::{FT_LOAD_NO_BITMAP, FT_LOAD_NO_HINTING};
22use freetype::freetype::{FT_FACE_FLAG_SCALABLE, FT_FACE_FLAG_FIXED_SIZES};
23use freetype::freetype::FT_FACE_FLAG_MULTIPLE_MASTERS;
24use freetype::succeeded;
25use crate::gamma_lut::{ColorLut, GammaLut};
26use crate::rasterizer::{FontInstance, GlyphFormat, GlyphKey};
27use crate::rasterizer::{GlyphRasterError, GlyphRasterResult, RasterizedGlyph};
28use crate::types::FastHashMap;
29#[cfg(any(not(target_os = "android"), feature = "dynamic_freetype"))]
30use libc::{dlsym, RTLD_DEFAULT};
31use libc::free;
32use std::{cmp, mem, ptr, slice};
33use std::cmp::max;
34use std::ffi::CString;
35use std::sync::{Arc, Condvar, Mutex, MutexGuard};
36
37#[cfg(not(target_os = "android"))]
38const FONT_GAMMA: f32 = 0.0;
39#[cfg(target_os = "android")]
40const FONT_GAMMA: f32 = 1.4;
41
42lazy_static! {
43 static ref GAMMA_LUT: GammaLut = GammaLut::new(0.0, FONT_GAMMA, FONT_GAMMA);
44}
45
46const FT_LOAD_TARGET_LIGHT: FT_UInt = 1 << 16;
51const FT_LOAD_TARGET_MONO: FT_UInt = 2 << 16;
52const FT_LOAD_TARGET_LCD: FT_UInt = 3 << 16;
53const FT_LOAD_TARGET_LCD_V: FT_UInt = 4 << 16;
54
55#[repr(C)]
56struct 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)]
66struct 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)]
73struct 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]
82pub fn unimplemented(error: FT_Error) -> bool {
83 error == FT_Err_Unimplemented_Feature as FT_Error
84}
85
86#[cfg(any(not(target_os = "android"), feature = "dynamic_freetype"))]
88macro_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#[cfg(all(target_os = "android", not(feature = "dynamic_freetype")))]
111macro_rules! ft_dyn_fn {
112 ($($proto:tt)+) => { extern "C" { fn $($proto)+; } }
113}
114
115ft_dyn_fn!(FT_Get_MM_Var(face: FT_Face, desc: *mut *mut FT_MM_Var) -> FT_Error);
116ft_dyn_fn!(FT_Done_MM_Var(library: FT_Library, desc: *mut FT_MM_Var) -> FT_Error);
117ft_dyn_fn!(FT_Set_Var_Design_Coordinates(face: FT_Face, num_vals: FT_UInt, vals: *mut FT_Fixed) -> FT_Error);
118ft_dyn_fn!(FT_Get_Var_Design_Coordinates(face: FT_Face, num_vals: FT_UInt, vals: *mut FT_Fixed) -> FT_Error);
119
120extern "C" {
121 fn FT_GlyphSlot_Embolden(slot: FT_GlyphSlot);
122}
123
124#[no_mangle]
127pub 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 unsafe { FT_GlyphSlot_Embolden(slot) };
137 return;
138 }
139
140 let face_ = unsafe { *slot_.face };
141
142 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 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
164struct CachedFont {
165 template: FontTemplate,
166 face: FT_Face,
167 mm_var: *mut FT_MM_Var,
168 variations: Vec<FontVariation>,
169}
170
171impl 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
184struct FontCache {
185 lib: FT_Library,
186 fonts: FastHashMap<FontTemplate, Arc<Mutex<CachedFont>>>,
188 lcd_filter: FontLCDFilter,
190 lcd_filter_uses: usize,
192}
193
194unsafe impl Send for CachedFont {}
198unsafe impl Send for FontCache {}
199
200impl 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 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 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
279impl Drop for FontCache {
280 fn drop(&mut self) {
281 self.fonts.clear();
282 unsafe {
283 FT_Done_FreeType(self.lib);
284 }
285 }
286}
287
288lazy_static! {
289 static ref FONT_CACHE: Mutex<FontCache> = Mutex::new(FontCache::new());
290 static ref LCD_FILTER_UNUSED: Condvar = Condvar::new();
291}
292
293pub struct FontContext {
294 fonts: FastHashMap<FontKey, Arc<Mutex<CachedFont>>>,
295}
296
297fn 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 (skew_min.min(skew_max).floor(), skew_min.max(skew_max).ceil())
302}
303
304fn skew_bitmap(
305 bitmap: &[u8],
306 width: usize,
307 height: usize,
308 left: i32,
309 top: i32,
310 skew_factor: f32,
311 vertical: bool, ) -> (Vec<u8>, usize, i32) {
313 let stride = width * 4;
314 let (skew_min, skew_max) = get_skew_bounds(top - height as i32, top, skew_factor, vertical);
316 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 let offset = (top as f32 - y as f32 - 0.5) * skew_factor - skew_min;
322 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 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 prev_px = next_px;
340 }
341 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
353fn 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
365fn 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
373fn 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
385impl 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 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 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 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 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 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 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 if font.render_mode == FontRenderMode::Subpixel {
612 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 fn get_bounding_box(
631 slot: FT_GlyphSlot,
632 font: &FontInstance,
633 glyph: &GlyphKey,
634 scale: f32,
635 ) -> FT_BBox {
636 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 if unsafe { (*slot).outline.n_contours } == 0 {
645 return cbox;
646 }
647
648 Self::pad_bounding_box(font, &mut cbox);
649
650 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 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 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 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 font.color = ColorU::new(0xFF, 0xFF, 0xFF, 0xFF);
792 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 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 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 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 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 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 if cache.lcd_filter != lcd_filter {
872 while cache.lcd_filter_uses != 0 {
875 cache = LCD_FILTER_UNUSED.wait(cache).unwrap();
876 }
877 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 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 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 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 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 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 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 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 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 })
1127 }
1128}
1129