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
38const FT_LOAD_TARGET_LIGHT: FT_UInt = 1 << 16;
43const FT_LOAD_TARGET_MONO: FT_UInt = 2 << 16;
44const FT_LOAD_TARGET_LCD: FT_UInt = 3 << 16;
45const FT_LOAD_TARGET_LCD_V: FT_UInt = 4 << 16;
46
47#[repr(C)]
48struct FT_Var_Axis {
49 pub name: *mut FT_String,
50 pub minimum: FT_Fixed,
51 pub def: FT_Fixed,
52 pub maximum: FT_Fixed,
53 pub tag: FT_ULong,
54 pub strid: FT_UInt,
55}
56
57#[repr(C)]
58struct FT_Var_Named_Style {
59 pub coords: *mut FT_Fixed,
60 pub strid: FT_UInt,
61 pub psid: FT_UInt,
62}
63
64#[repr(C)]
65struct FT_MM_Var {
66 pub num_axis: FT_UInt,
67 pub num_designs: FT_UInt,
68 pub num_namedstyles: FT_UInt,
69 pub axis: *mut FT_Var_Axis,
70 pub namedstyle: *mut FT_Var_Named_Style,
71}
72
73#[inline]
74pub fn unimplemented(error: FT_Error) -> bool {
75 error == FT_Err_Unimplemented_Feature as FT_Error
76}
77
78#[cfg(any(not(target_os = "android"), feature = "dynamic_freetype"))]
80macro_rules! ft_dyn_fn {
81 ($func_name:ident($($arg_name:ident:$arg_type:ty),*) -> FT_Error) => {
82 #[allow(non_snake_case)]
83 unsafe fn $func_name($($arg_name:$arg_type),*) -> FT_Error {
84 extern "C" fn unimpl_func($(_:$arg_type),*) -> FT_Error {
85 FT_Err_Unimplemented_Feature as FT_Error
86 }
87 lazy_static! {
88 static ref FUNC: unsafe extern "C" fn($($arg_type),*) -> FT_Error = {
89 unsafe {
90 let cname = CString::new(stringify!($func_name)).unwrap();
91 let ptr = dlsym(RTLD_DEFAULT, cname.as_ptr());
92 if !ptr.is_null() { mem::transmute(ptr) } else { unimpl_func }
93 }
94 };
95 }
96 (*FUNC)($($arg_name),*)
97 }
98 }
99}
100
101#[cfg(all(target_os = "android", not(feature = "dynamic_freetype")))]
103macro_rules! ft_dyn_fn {
104 ($($proto:tt)+) => { extern "C" { fn $($proto)+; } }
105}
106
107ft_dyn_fn!(FT_Get_MM_Var(face: FT_Face, desc: *mut *mut FT_MM_Var) -> FT_Error);
108ft_dyn_fn!(FT_Done_MM_Var(library: FT_Library, desc: *mut FT_MM_Var) -> FT_Error);
109ft_dyn_fn!(FT_Set_Var_Design_Coordinates(face: FT_Face, num_vals: FT_UInt, vals: *mut FT_Fixed) -> FT_Error);
110ft_dyn_fn!(FT_Get_Var_Design_Coordinates(face: FT_Face, num_vals: FT_UInt, vals: *mut FT_Fixed) -> FT_Error);
111
112extern "C" {
113 fn FT_GlyphSlot_Embolden(slot: FT_GlyphSlot);
114}
115
116#[no_mangle]
119pub extern "C" fn mozilla_glyphslot_embolden_less(slot: FT_GlyphSlot) {
120 if slot.is_null() {
121 return;
122 }
123
124 let slot_ = unsafe { &mut *slot };
125 let format = slot_.format;
126 if format != FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE {
127 unsafe { FT_GlyphSlot_Embolden(slot) };
129 return;
130 }
131
132 let face_ = unsafe { *slot_.face };
133
134 let size_ = unsafe { *face_.size };
137 let strength =
138 unsafe { FT_MulFix(face_.units_per_EM as FT_Long,
139 size_.metrics.y_scale) / 48 };
140 unsafe { FT_Outline_Embolden(&mut slot_.outline, strength) };
141
142 if slot_.advance.x != 0 {
144 slot_.advance.x += strength;
145 }
146 if slot_.advance.y != 0 {
147 slot_.advance.y += strength;
148 }
149 slot_.metrics.width += strength;
150 slot_.metrics.height += strength;
151 slot_.metrics.horiAdvance += strength;
152 slot_.metrics.vertAdvance += strength;
153 slot_.metrics.horiBearingY += strength;
154}
155
156struct CachedFont {
157 template: FontTemplate,
158 face: FT_Face,
159 mm_var: *mut FT_MM_Var,
160 variations: Vec<FontVariation>,
161}
162
163impl Drop for CachedFont {
164 fn drop(&mut self) {
165 unsafe {
166 if !self.mm_var.is_null() &&
167 unimplemented(FT_Done_MM_Var((*(*self.face).glyph).library, self.mm_var)) {
168 free(self.mm_var as _);
169 }
170
171 FT_Done_Face(self.face);
172 }
173 }
174}
175
176struct FontCache {
177 lib: FT_Library,
178 fonts: FastHashMap<FontTemplate, Arc<Mutex<CachedFont>>>,
180 lcd_filter: FontLCDFilter,
182 lcd_filter_uses: usize,
184}
185
186unsafe impl Send for CachedFont {}
190unsafe impl Send for FontCache {}
191
192impl FontCache {
193 fn new() -> Self {
194 let mut lib: FT_Library = ptr::null_mut();
195 let result = unsafe { FT_Init_FreeType(&mut lib) };
196 if succeeded(result) {
197 unsafe { FT_Library_SetLcdFilter(lib, FT_LcdFilter::FT_LCD_FILTER_DEFAULT) };
199 } else {
200 panic!("Failed to initialize FreeType - {}", result)
201 }
202
203 FontCache {
204 lib,
205 fonts: FastHashMap::default(),
206 lcd_filter: FontLCDFilter::Default,
207 lcd_filter_uses: 0,
208 }
209 }
210
211 fn add_font(&mut self, template: FontTemplate) -> Result<Arc<Mutex<CachedFont>>, FT_Error> {
212 if let Some(cached) = self.fonts.get(&template) {
213 return Ok(cached.clone());
214 }
215 unsafe {
216 let mut face: FT_Face = ptr::null_mut();
217 let result = match template {
218 FontTemplate::Raw(ref bytes, index) => {
219 FT_New_Memory_Face(
220 self.lib,
221 bytes.as_ptr(),
222 bytes.len() as FT_Long,
223 index as FT_Long,
224 &mut face,
225 )
226 }
227 FontTemplate::Native(NativeFontHandle { ref path, index }) => {
228 let str = path.as_os_str().to_str().unwrap();
229 let cstr = CString::new(str).unwrap();
230 FT_New_Face(
231 self.lib,
232 cstr.as_ptr(),
233 index as FT_Long,
234 &mut face,
235 )
236 }
237 };
238 if !succeeded(result) || face.is_null() {
239 return Err(result);
240 }
241 let mut mm_var = ptr::null_mut();
242 if ((*face).face_flags & (FT_FACE_FLAG_MULTIPLE_MASTERS as FT_Long)) != 0 &&
243 succeeded(FT_Get_MM_Var(face, &mut mm_var)) {
244 let mut tmp = [0; 16];
248 let res = FT_Get_Var_Design_Coordinates(
249 face,
250 (*mm_var).num_axis.min(16),
251 tmp.as_mut_ptr()
252 );
253 debug_assert!(succeeded(res));
254 }
255 let cached = Arc::new(Mutex::new(CachedFont {
256 template: template.clone(),
257 face,
258 mm_var,
259 variations: Vec::new(),
260 }));
261 self.fonts.insert(template, cached.clone());
262 Ok(cached)
263 }
264 }
265
266 fn delete_font(&mut self, cached: Arc<Mutex<CachedFont>>) {
267 self.fonts.remove(&cached.lock().unwrap().template);
268 }
269}
270
271impl Drop for FontCache {
272 fn drop(&mut self) {
273 self.fonts.clear();
274 unsafe {
275 FT_Done_FreeType(self.lib);
276 }
277 }
278}
279
280lazy_static! {
281 static ref FONT_CACHE: Mutex<FontCache> = Mutex::new(FontCache::new());
282 static ref LCD_FILTER_UNUSED: Condvar = Condvar::new();
283}
284
285pub struct FontContext {
286 fonts: FastHashMap<FontKey, Arc<Mutex<CachedFont>>>,
287 gamma_luts: FastHashMap<(i16, i16), GammaLut>,
288}
289
290fn get_skew_bounds(bottom: i32, top: i32, skew_factor: f32, _vertical: bool) -> (f32, f32) {
291 let skew_min = (bottom as f32 + 0.5) * skew_factor;
292 let skew_max = (top as f32 - 0.5) * skew_factor;
293 (skew_min.min(skew_max).floor(), skew_min.max(skew_max).ceil())
295}
296
297fn skew_bitmap(
298 bitmap: &[u8],
299 width: usize,
300 height: usize,
301 left: i32,
302 top: i32,
303 skew_factor: f32,
304 vertical: bool, ) -> (Vec<u8>, usize, i32) {
306 let stride = width * 4;
307 let (skew_min, skew_max) = get_skew_bounds(top - height as i32, top, skew_factor, vertical);
309 let skew_width = width + (skew_max - skew_min) as usize;
311 let mut skew_buffer = vec![0u8; skew_width * height * 4];
312 for y in 0 .. height {
313 let offset = (top as f32 - y as f32 - 0.5) * skew_factor - skew_min;
315 let blend = (offset.fract() * 256.0) as u32;
317 let src_row = y * stride;
318 let dest_row = (y * skew_width + offset.floor() as usize) * 4;
319 let mut prev_px = [0u32; 4];
320 for (src, dest) in
321 bitmap[src_row .. src_row + stride].chunks(4).zip(
322 skew_buffer[dest_row .. dest_row + stride].chunks_mut(4)
323 ) {
324 let px = [src[0] as u32, src[1] as u32, src[2] as u32, src[3] as u32];
325 let next_px = [px[0] * blend, px[1] * blend, px[2] * blend, px[3] * blend];
327 dest[0] = ((((px[0] << 8) - next_px[0]) + prev_px[0] + 128) >> 8) as u8;
328 dest[1] = ((((px[1] << 8) - next_px[1]) + prev_px[1] + 128) >> 8) as u8;
329 dest[2] = ((((px[2] << 8) - next_px[2]) + prev_px[2] + 128) >> 8) as u8;
330 dest[3] = ((((px[3] << 8) - next_px[3]) + prev_px[3] + 128) >> 8) as u8;
331 prev_px = next_px;
333 }
334 if blend > 0 {
336 let dest = &mut skew_buffer[dest_row + stride .. dest_row + stride + 4];
337 dest[0] = ((prev_px[0] + 128) >> 8) as u8;
338 dest[1] = ((prev_px[1] + 128) >> 8) as u8;
339 dest[2] = ((prev_px[2] + 128) >> 8) as u8;
340 dest[3] = ((prev_px[3] + 128) >> 8) as u8;
341 }
342 }
343 (skew_buffer, skew_width, left + skew_min as i32)
344}
345
346fn transpose_bitmap(bitmap: &[u8], width: usize, height: usize) -> Vec<u8> {
347 let mut transposed = vec![0u8; width * height * 4];
348 for (y, row) in bitmap.chunks(width * 4).enumerate() {
349 let mut offset = y * 4;
350 for src in row.chunks(4) {
351 transposed[offset .. offset + 4].copy_from_slice(src);
352 offset += height * 4;
353 }
354 }
355 transposed
356}
357
358fn flip_bitmap_x(bitmap: &mut [u8], width: usize, height: usize) {
359 assert!(bitmap.len() == width * height * 4);
360 let pixels = unsafe { slice::from_raw_parts_mut(bitmap.as_mut_ptr() as *mut u32, width * height) };
361 for row in pixels.chunks_mut(width) {
362 row.reverse();
363 }
364}
365
366fn flip_bitmap_y(bitmap: &mut [u8], width: usize, height: usize) {
367 assert!(bitmap.len() == width * height * 4);
368 let pixels = unsafe { slice::from_raw_parts_mut(bitmap.as_mut_ptr() as *mut u32, width * height) };
369 for y in 0 .. height / 2 {
370 let low_row = y * width;
371 let high_row = (height - 1 - y) * width;
372 for x in 0 .. width {
373 pixels.swap(low_row + x, high_row + x);
374 }
375 }
376}
377
378impl FontContext {
379 pub fn distribute_across_threads() -> bool {
380 false
381 }
382
383 pub fn new() -> FontContext {
384 FontContext {
385 fonts: FastHashMap::default(),
386 gamma_luts: FastHashMap::default(),
387 }
388 }
389
390 pub fn add_raw_font(&mut self, font_key: &FontKey, bytes: Arc<Vec<u8>>, index: u32) {
391 if !self.fonts.contains_key(font_key) {
392 let len = bytes.len();
393 match FONT_CACHE.lock().unwrap().add_font(FontTemplate::Raw(bytes, index)) {
394 Ok(font) => self.fonts.insert(*font_key, font),
395 Err(result) => panic!("adding raw font failed: {} bytes, err={:?}", len, result),
396 };
397 }
398 }
399
400 pub fn add_native_font(&mut self, font_key: &FontKey, native_font_handle: NativeFontHandle) {
401 if !self.fonts.contains_key(font_key) {
402 let path = native_font_handle.path.to_string_lossy().into_owned();
403 match FONT_CACHE.lock().unwrap().add_font(FontTemplate::Native(native_font_handle)) {
404 Ok(font) => self.fonts.insert(*font_key, font),
405 Err(result) => panic!("adding native font failed: file={} err={:?}", path, result),
406 };
407 }
408 }
409
410 pub fn delete_font(&mut self, font_key: &FontKey) {
411 if let Some(cached) = self.fonts.remove(font_key) {
412 if Arc::strong_count(&cached) <= 2 {
415 FONT_CACHE.lock().unwrap().delete_font(cached);
416 }
417 }
418 }
419
420 pub fn delete_font_instance(&mut self, _instance: &FontInstance) {
421 }
422
423 fn load_glyph<'a>(
424 fonts: &'a FastHashMap<FontKey, Arc<Mutex<CachedFont>>>,
425 font: &FontInstance,
426 glyph: &GlyphKey,
427 ) -> Option<(MutexGuard<'a, CachedFont>, FT_GlyphSlot, f32)> {
428 let mut cached = fonts.get(&font.font_key)?.lock().ok()?;
429 let face = cached.face;
430
431 let mm_var = cached.mm_var;
432 if !mm_var.is_null() && font.variations != cached.variations {
433 cached.variations.clear();
434 cached.variations.extend_from_slice(&font.variations);
435
436 unsafe {
437 let num_axis = (*mm_var).num_axis;
438 let mut coords: Vec<FT_Fixed> = Vec::with_capacity(num_axis as usize);
439 for i in 0 .. num_axis {
440 let axis = (*mm_var).axis.offset(i as isize);
441 let mut value = (*axis).def;
442 for var in &font.variations {
443 if var.tag as FT_ULong == (*axis).tag {
444 value = (var.value * 65536.0 + 0.5) as FT_Fixed;
445 value = cmp::min(value, (*axis).maximum);
446 value = cmp::max(value, (*axis).minimum);
447 break;
448 }
449 }
450 coords.push(value);
451 }
452 let res = FT_Set_Var_Design_Coordinates(face, num_axis, coords.as_mut_ptr());
453 debug_assert!(succeeded(res));
454 }
455 }
456
457 let mut load_flags = FT_LOAD_DEFAULT;
458 let FontInstancePlatformOptions { mut hinting, .. } = font.platform_options.unwrap_or_default();
459 if font.synthetic_italics.is_enabled() ||
461 ((font.transform.scale_x != 0.0 || font.transform.scale_y != 0.0) &&
462 (font.transform.skew_x != 0.0 || font.transform.skew_y != 0.0)) {
463 hinting = FontHinting::None;
464 }
465 match (hinting, font.render_mode) {
466 (FontHinting::None, _) => load_flags |= FT_LOAD_NO_HINTING,
467 (FontHinting::Mono, _) => load_flags = FT_LOAD_TARGET_MONO,
468 (FontHinting::Light, _) => load_flags = FT_LOAD_TARGET_LIGHT,
469 (FontHinting::LCD, FontRenderMode::Subpixel) => {
470 load_flags = if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
471 FT_LOAD_TARGET_LCD_V
472 } else {
473 FT_LOAD_TARGET_LCD
474 };
475 if font.flags.contains(FontInstanceFlags::FORCE_AUTOHINT) {
476 load_flags |= FT_LOAD_FORCE_AUTOHINT;
477 }
478 }
479 _ => {
480 if font.flags.contains(FontInstanceFlags::FORCE_AUTOHINT) {
481 load_flags |= FT_LOAD_FORCE_AUTOHINT;
482 }
483 }
484 }
485
486 if font.flags.contains(FontInstanceFlags::NO_AUTOHINT) {
487 load_flags |= FT_LOAD_NO_AUTOHINT;
488 }
489 if !font.flags.contains(FontInstanceFlags::EMBEDDED_BITMAPS) {
490 load_flags |= FT_LOAD_NO_BITMAP;
491 }
492
493 let face_flags = unsafe { (*face).face_flags };
494 if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 {
495 load_flags |= FT_LOAD_COLOR;
499 }
500
501 load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
502
503 let (x_scale, y_scale) = font.transform.compute_scale().unwrap_or((1.0, 1.0));
504 let req_size = font.size.to_f64_px();
505
506 let mut result = if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 &&
507 (face_flags & (FT_FACE_FLAG_SCALABLE as FT_Long)) == 0 &&
508 (load_flags & FT_LOAD_NO_BITMAP) == 0 {
509 unsafe { FT_Set_Transform(face, ptr::null_mut(), ptr::null_mut()) };
510 Self::choose_bitmap_size(face, req_size * y_scale)
511 } else {
512 let mut shape = font.transform.invert_scale(x_scale, y_scale);
513 if font.flags.contains(FontInstanceFlags::FLIP_X) {
514 shape = shape.flip_x();
515 }
516 if font.flags.contains(FontInstanceFlags::FLIP_Y) {
517 shape = shape.flip_y();
518 }
519 if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
520 shape = shape.swap_xy();
521 }
522 let (mut tx, mut ty) = (0.0, 0.0);
523 if font.synthetic_italics.is_enabled() {
524 let (shape_, (tx_, ty_)) = font.synthesize_italics(shape, y_scale * req_size);
525 shape = shape_;
526 tx = tx_;
527 ty = ty_;
528 };
529 let mut ft_shape = FT_Matrix {
530 xx: (shape.scale_x * 65536.0) as FT_Fixed,
531 xy: (shape.skew_x * -65536.0) as FT_Fixed,
532 yx: (shape.skew_y * -65536.0) as FT_Fixed,
533 yy: (shape.scale_y * 65536.0) as FT_Fixed,
534 };
535 let mut ft_delta = FT_Vector {
537 x: (tx * 64.0) as FT_F26Dot6,
538 y: (ty * -64.0) as FT_F26Dot6,
539 };
540 unsafe {
541 FT_Set_Transform(face, &mut ft_shape, &mut ft_delta);
542 FT_Set_Char_Size(
543 face,
544 (req_size * x_scale * 64.0 + 0.5) as FT_F26Dot6,
545 (req_size * y_scale * 64.0 + 0.5) as FT_F26Dot6,
546 0,
547 0,
548 )
549 }
550 };
551
552 if !succeeded(result) {
553 error!("Unable to set glyph size and transform: {}", result);
554 debug!(
559 "\t[{}] for size {:?} and scale {:?} from font {:?}",
560 glyph.index(),
561 req_size,
562 (x_scale, y_scale),
563 font.font_key,
564 );
565 return None;
566 }
567
568 result = unsafe { FT_Load_Glyph(face, glyph.index() as FT_UInt, load_flags as FT_Int32) };
569 if !succeeded(result) {
570 error!("Unable to load glyph: {}", result);
571 debug!(
576 "\t[{}] with flags {:?} from font {:?}",
577 glyph.index(),
578 load_flags,
579 font.font_key,
580 );
581 return None;
582 }
583
584 let slot = unsafe { (*face).glyph };
585 assert!(slot != ptr::null_mut());
586
587 if font.flags.contains(FontInstanceFlags::SYNTHETIC_BOLD) {
588 mozilla_glyphslot_embolden_less(slot);
589 }
590
591 let format = unsafe { (*slot).format };
592 match format {
593 FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
594 let bitmap_size = unsafe { (*(*(*slot).face).size).metrics.y_ppem };
595 Some((cached, slot, req_size as f32 / bitmap_size as f32))
596 }
597 FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => Some((cached, slot, 1.0)),
598 _ => {
599 error!("Unsupported format");
600 debug!("format={:?}", format);
601 None
602 }
603 }
604 }
605
606 fn pad_bounding_box(font: &FontInstance, cbox: &mut FT_BBox) {
607 if font.render_mode == FontRenderMode::Subpixel {
609 let lcd_extra_pixels = 1;
615 let padding = (lcd_extra_pixels * 64) as FT_Pos;
616 if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
617 cbox.yMin -= padding;
618 cbox.yMax += padding;
619 } else {
620 cbox.xMin -= padding;
621 cbox.xMax += padding;
622 }
623 }
624 }
625
626 fn get_bounding_box(
628 slot: FT_GlyphSlot,
629 font: &FontInstance,
630 glyph: &GlyphKey,
631 scale: f32,
632 ) -> FT_BBox {
633 let mut cbox = FT_BBox { xMin: 0, yMin: 0, xMax: 0, yMax: 0 };
635
636 unsafe {
637 FT_Outline_Get_CBox(&(*slot).outline, &mut cbox);
638 }
639
640 if unsafe { (*slot).outline.n_contours } == 0 {
642 return cbox;
643 }
644
645 Self::pad_bounding_box(font, &mut cbox);
646
647 let (dx, dy) = font.get_subpx_offset(glyph);
650 let (dx, dy) = (
651 (dx / scale as f64 * 64.0 + 0.5) as FT_Pos,
652 -(dy / scale as f64 * 64.0 + 0.5) as FT_Pos,
653 );
654 cbox.xMin += dx;
655 cbox.xMax += dx;
656 cbox.yMin += dy;
657 cbox.yMax += dy;
658
659 cbox.xMin &= !63;
661 cbox.yMin &= !63;
662 cbox.xMax = (cbox.xMax + 63) & !63;
663 cbox.yMax = (cbox.yMax + 63) & !63;
664
665 cbox
666 }
667
668 fn get_glyph_dimensions_impl(
669 slot: FT_GlyphSlot,
670 font: &FontInstance,
671 glyph: &GlyphKey,
672 scale: f32,
673 use_transform: bool,
674 ) -> Option<GlyphDimensions> {
675 let format = unsafe { (*slot).format };
676 let (mut left, mut top, mut width, mut height) = match format {
677 FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
678 unsafe { (
679 (*slot).bitmap_left as i32,
680 (*slot).bitmap_top as i32,
681 (*slot).bitmap.width as i32,
682 (*slot).bitmap.rows as i32,
683 ) }
684 }
685 FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
686 let cbox = Self::get_bounding_box(slot, font, glyph, scale);
687 (
688 (cbox.xMin >> 6) as i32,
689 (cbox.yMax >> 6) as i32,
690 ((cbox.xMax - cbox.xMin) >> 6) as i32,
691 ((cbox.yMax - cbox.yMin) >> 6) as i32,
692 )
693 }
694 _ => return None,
695 };
696 let mut advance = unsafe { (*slot).metrics.horiAdvance as f32 / 64.0 };
697 if use_transform {
698 if scale != 1.0 {
699 let x0 = left as f32 * scale;
700 let x1 = width as f32 * scale + x0;
701 let y1 = top as f32 * scale;
702 let y0 = y1 - height as f32 * scale;
703 left = x0.round() as i32;
704 top = y1.round() as i32;
705 width = (x1.ceil() - x0.floor()) as i32;
706 height = (y1.ceil() - y0.floor()) as i32;
707 advance *= scale;
708 }
709 if format == FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP {
712 if font.synthetic_italics.is_enabled() {
713 let (skew_min, skew_max) = get_skew_bounds(
714 top - height as i32,
715 top,
716 font.synthetic_italics.to_skew(),
717 font.flags.contains(FontInstanceFlags::VERTICAL),
718 );
719 left += skew_min as i32;
720 width += (skew_max - skew_min) as i32;
721 }
722 if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
723 mem::swap(&mut width, &mut height);
724 mem::swap(&mut left, &mut top);
725 left -= width as i32;
726 top += height as i32;
727 }
728 if font.flags.contains(FontInstanceFlags::FLIP_X) {
729 left = -(left + width as i32);
730 }
731 if font.flags.contains(FontInstanceFlags::FLIP_Y) {
732 top = -(top - height as i32);
733 }
734 }
735 }
736 Some(GlyphDimensions {
737 left,
738 top,
739 width,
740 height,
741 advance,
742 })
743 }
744
745 pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
746 let cached = self.fonts.get(&font_key)?.lock().ok()?;
747 let face = cached.face;
748 unsafe {
749 let idx = FT_Get_Char_Index(face, ch as _);
750 if idx != 0 {
751 Some(idx)
752 } else {
753 None
754 }
755 }
756 }
757
758 pub fn get_glyph_dimensions(
759 &mut self,
760 font: &FontInstance,
761 key: &GlyphKey,
762 ) -> Option<GlyphDimensions> {
763 let (_cached, slot, scale) = Self::load_glyph(&self.fonts, font, key)?;
764 Self::get_glyph_dimensions_impl(slot, &font, key, scale, true)
765 }
766
767 fn choose_bitmap_size(face: FT_Face, requested_size: f64) -> FT_Error {
768 let mut best_dist = unsafe { *(*face).available_sizes.offset(0) }.y_ppem as f64 / 64.0 - requested_size;
769 let mut best_size = 0;
770 let num_fixed_sizes = unsafe { (*face).num_fixed_sizes };
771 for i in 1 .. num_fixed_sizes {
772 let dist = unsafe { *(*face).available_sizes.offset(i as isize) }.y_ppem as f64 / 64.0 - requested_size;
776 if (best_dist < 0.0 && dist >= best_dist) || dist.abs() <= best_dist {
777 best_dist = dist;
778 best_size = i;
779 }
780 }
781 unsafe { FT_Select_Size(face, best_size) }
782 }
783
784 pub fn prepare_font(font: &mut FontInstance) {
785 let preblend_enabled = font.platform_options.map_or(false, |o| o.gamma >= 0 || o.enhanced_contrast > 0);
786 match font.render_mode {
787 FontRenderMode::Mono => {
788 font.color = ColorU::new(0xFF, 0xFF, 0xFF, 0xFF);
790 font.disable_subpixel_position();
792 }
793 FontRenderMode::Alpha => {
794 if preblend_enabled {
795 font.color = font.color.luminance_color().quantize();
796 } else {
797 font.color = ColorU::new(0xFF, 0xFF, 0xFF, 0xFF);
799 }
800 }
801 FontRenderMode::Subpixel => {
802 if preblend_enabled {
803 font.color = font.color.quantize();
804 } else {
805 font.color = ColorU::new(0xFF, 0xFF, 0xFF, 0xFF);
807 }
808 }
809 }
810 }
811
812 fn rasterize_glyph_outline(
813 slot: FT_GlyphSlot,
814 font: &FontInstance,
815 key: &GlyphKey,
816 scale: f32,
817 ) -> bool {
818 let (dx, dy) = font.get_subpx_offset(key);
820 let (dx, dy) = (
821 (dx / scale as f64 * 64.0 + 0.5) as FT_Pos,
822 -(dy / scale as f64 * 64.0 + 0.5) as FT_Pos,
823 );
824
825 unsafe {
828 let outline = &(*slot).outline;
829 let mut cbox = FT_BBox { xMin: 0, yMin: 0, xMax: 0, yMax: 0 };
830 FT_Outline_Get_CBox(outline, &mut cbox);
831 Self::pad_bounding_box(font, &mut cbox);
832 FT_Outline_Translate(
833 outline,
834 dx - ((cbox.xMin + dx) & !63),
835 dy - ((cbox.yMin + dy) & !63),
836 );
837 }
838
839 let render_mode = match font.render_mode {
840 FontRenderMode::Mono => FT_Render_Mode::FT_RENDER_MODE_MONO,
841 FontRenderMode::Alpha => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
842 FontRenderMode::Subpixel => if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
843 FT_Render_Mode::FT_RENDER_MODE_LCD_V
844 } else {
845 FT_Render_Mode::FT_RENDER_MODE_LCD
846 },
847 };
848 let result = unsafe { FT_Render_Glyph(slot, render_mode) };
849 if !succeeded(result) {
850 error!("Unable to rasterize");
851 debug!(
852 "{:?} with {:?}, {:?}",
853 key,
854 render_mode,
855 result
856 );
857 false
858 } else {
859 true
860 }
861 }
862
863 pub fn begin_rasterize(font: &FontInstance) {
864 if font.render_mode == FontRenderMode::Subpixel {
866 let mut cache = FONT_CACHE.lock().unwrap();
867 let FontInstancePlatformOptions { lcd_filter, .. } = font.platform_options.unwrap_or_default();
868 if cache.lcd_filter != lcd_filter {
870 while cache.lcd_filter_uses != 0 {
873 cache = LCD_FILTER_UNUSED.wait(cache).unwrap();
874 }
875 cache.lcd_filter = lcd_filter;
877 let filter = match lcd_filter {
878 FontLCDFilter::None => FT_LcdFilter::FT_LCD_FILTER_NONE,
879 FontLCDFilter::Default => FT_LcdFilter::FT_LCD_FILTER_DEFAULT,
880 FontLCDFilter::Light => FT_LcdFilter::FT_LCD_FILTER_LIGHT,
881 FontLCDFilter::Legacy => FT_LcdFilter::FT_LCD_FILTER_LEGACY,
882 };
883 unsafe {
884 let result = FT_Library_SetLcdFilter(cache.lib, filter);
885 if !succeeded(result) {
887 FT_Library_SetLcdFilter(cache.lib, FT_LcdFilter::FT_LCD_FILTER_DEFAULT);
888 }
889 }
890 }
891 cache.lcd_filter_uses += 1;
892 }
893 }
894
895 pub fn end_rasterize(font: &FontInstance) {
896 if font.render_mode == FontRenderMode::Subpixel {
897 let mut cache = FONT_CACHE.lock().unwrap();
898 cache.lcd_filter_uses -= 1;
900 if cache.lcd_filter_uses == 0 {
901 LCD_FILTER_UNUSED.notify_all();
902 }
903 }
904 }
905
906 pub fn rasterize_glyph(&mut self, font: &FontInstance, key: &GlyphKey) -> GlyphRasterResult {
907 let (_cached, slot, scale) = Self::load_glyph(&self.fonts, font, key)
908 .ok_or(GlyphRasterError::LoadFailed)?;
909
910 let dimensions = Self::get_glyph_dimensions_impl(slot, font, key, scale, false)
914 .ok_or(GlyphRasterError::LoadFailed)?;
915 let GlyphDimensions { mut left, mut top, width, height, .. } = dimensions;
916
917 if width == 0 || height == 0 {
919 return Err(GlyphRasterError::LoadFailed);
920 }
921
922 let format = unsafe { (*slot).format };
923 match format {
924 FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {}
925 FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
926 if !Self::rasterize_glyph_outline(slot, font, key, scale) {
927 return Err(GlyphRasterError::LoadFailed);
928 }
929 }
930 _ => {
931 error!("Unsupported format");
932 debug!("format={:?}", format);
933 return Err(GlyphRasterError::LoadFailed);
934 }
935 };
936
937 debug!(
938 "Rasterizing {:?} as {:?} with dimensions {:?}",
939 key,
940 font.render_mode,
941 dimensions
942 );
943
944 let bitmap = unsafe { &(*slot).bitmap };
945 let pixel_mode = unsafe { mem::transmute(bitmap.pixel_mode as u32) };
946 let (mut actual_width, mut actual_height) = match pixel_mode {
947 FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
948 assert!(bitmap.width % 3 == 0);
949 ((bitmap.width / 3) as usize, bitmap.rows as usize)
950 }
951 FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V => {
952 assert!(bitmap.rows % 3 == 0);
953 (bitmap.width as usize, (bitmap.rows / 3) as usize)
954 }
955 FT_Pixel_Mode::FT_PIXEL_MODE_MONO |
956 FT_Pixel_Mode::FT_PIXEL_MODE_GRAY |
957 FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
958 (bitmap.width as usize, bitmap.rows as usize)
959 }
960 _ => panic!("Unsupported mode"),
961 };
962
963 let (buffer_width, buffer_height, padding) = if font.use_texture_padding() {
965 (actual_width + 2, actual_height + 2, 1)
966 } else {
967 (actual_width, actual_height, 0)
968 };
969
970 let mut final_buffer = vec![0u8; buffer_width * buffer_height * 4];
971
972 let subpixel_bgr = font.flags.contains(FontInstanceFlags::SUBPIXEL_BGR);
975 let mut src_row = bitmap.buffer;
976 let mut dest = 4 * padding * (padding + buffer_width);
977 let actual_end = final_buffer.len() - 4 * padding * (buffer_width + 1);
978 while dest < actual_end {
979 let mut src = src_row;
980 let row_end = dest + actual_width * 4;
981 match pixel_mode {
982 FT_Pixel_Mode::FT_PIXEL_MODE_MONO => {
983 while dest < row_end {
984 let mut byte: i8 = unsafe { *src as i8 };
987 src = unsafe { src.offset(1) };
988 let byte_end = cmp::min(row_end, dest + 8 * 4);
989 while dest < byte_end {
990 let alpha = (byte >> 7) as u8;
991 final_buffer[dest + 0] = alpha;
992 final_buffer[dest + 1] = alpha;
993 final_buffer[dest + 2] = alpha;
994 final_buffer[dest + 3] = alpha;
995 dest += 4;
996 byte <<= 1;
997 }
998 }
999 }
1000 FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => {
1001 while dest < row_end {
1002 let alpha = unsafe { *src };
1003 final_buffer[dest + 0] = alpha;
1004 final_buffer[dest + 1] = alpha;
1005 final_buffer[dest + 2] = alpha;
1006 final_buffer[dest + 3] = alpha;
1007 src = unsafe { src.offset(1) };
1008 dest += 4;
1009 }
1010 }
1011 FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
1012 while dest < row_end {
1013 let (mut r, g, mut b) = unsafe { (*src, *src.offset(1), *src.offset(2)) };
1014 if subpixel_bgr {
1015 mem::swap(&mut r, &mut b);
1016 }
1017 final_buffer[dest + 0] = b;
1018 final_buffer[dest + 1] = g;
1019 final_buffer[dest + 2] = r;
1020 final_buffer[dest + 3] = max(max(b, g), r);
1021 src = unsafe { src.offset(3) };
1022 dest += 4;
1023 }
1024 }
1025 FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V => {
1026 while dest < row_end {
1027 let (mut r, g, mut b) =
1028 unsafe { (*src, *src.offset(bitmap.pitch as isize),
1029 *src.offset((2 * bitmap.pitch) as isize)) };
1030 if subpixel_bgr {
1031 mem::swap(&mut r, &mut b);
1032 }
1033 final_buffer[dest + 0] = b;
1034 final_buffer[dest + 1] = g;
1035 final_buffer[dest + 2] = r;
1036 final_buffer[dest + 3] = max(max(b, g), r);
1037 src = unsafe { src.offset(1) };
1038 dest += 4;
1039 }
1040 src_row = unsafe { src_row.offset((2 * bitmap.pitch) as isize) };
1041 }
1042 FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
1043 let dest_slice = &mut final_buffer[dest .. row_end];
1045 let src_slice = unsafe { slice::from_raw_parts(src, dest_slice.len()) };
1046 dest_slice.copy_from_slice(src_slice);
1047 }
1048 _ => panic!("Unsupported mode"),
1049 }
1050 src_row = unsafe { src_row.offset(bitmap.pitch as isize) };
1051 dest = row_end + 8 * padding;
1052 }
1053
1054 if font.use_texture_padding() {
1055 left -= padding as i32;
1056 top += padding as i32;
1057 actual_width = buffer_width;
1058 actual_height = buffer_height;
1059 }
1060
1061 match format {
1062 FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
1063 if font.synthetic_italics.is_enabled() {
1064 let (skew_buffer, skew_width, skew_left) = skew_bitmap(
1065 &final_buffer,
1066 actual_width,
1067 actual_height,
1068 left,
1069 top,
1070 font.synthetic_italics.to_skew(),
1071 font.flags.contains(FontInstanceFlags::VERTICAL),
1072 );
1073 final_buffer = skew_buffer;
1074 actual_width = skew_width;
1075 left = skew_left;
1076 }
1077 if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
1078 final_buffer = transpose_bitmap(&final_buffer, actual_width, actual_height);
1079 mem::swap(&mut actual_width, &mut actual_height);
1080 mem::swap(&mut left, &mut top);
1081 left -= actual_width as i32;
1082 top += actual_height as i32;
1083 }
1084 if font.flags.contains(FontInstanceFlags::FLIP_X) {
1085 flip_bitmap_x(&mut final_buffer, actual_width, actual_height);
1086 left = -(left + actual_width as i32);
1087 }
1088 if font.flags.contains(FontInstanceFlags::FLIP_Y) {
1089 flip_bitmap_y(&mut final_buffer, actual_width, actual_height);
1090 top = -(top - actual_height as i32);
1091 }
1092 }
1093 FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
1094 unsafe {
1095 left += (*slot).bitmap_left;
1096 top += (*slot).bitmap_top - height as i32;
1097 }
1098 }
1099 _ => {}
1100 }
1101
1102 let glyph_format = match (pixel_mode, format) {
1103 (FT_Pixel_Mode::FT_PIXEL_MODE_LCD, _) |
1104 (FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V, _) => font.get_subpixel_glyph_format(),
1105 (FT_Pixel_Mode::FT_PIXEL_MODE_BGRA, _) => GlyphFormat::ColorBitmap,
1106 (_, FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP) => GlyphFormat::Bitmap,
1107 _ => font.get_alpha_glyph_format(),
1108 };
1109
1110 Self::gamma_correct_pixels(font, &mut self.gamma_luts, &mut final_buffer, glyph_format);
1111
1112 Ok(RasterizedGlyph {
1113 left: left as f32,
1114 top: top as f32,
1115 width: actual_width as i32,
1116 height: actual_height as i32,
1117 scale,
1118 format: glyph_format,
1119 bytes: final_buffer,
1120 is_packed_glyph: false,
1121 })
1122 }
1123
1124 fn gamma_correct_pixels(
1125 font: &FontInstance,
1126 gamma_luts: &mut FastHashMap<(i16, i16), GammaLut>,
1127 pixels: &mut Vec<u8>,
1128 glyph_format: GlyphFormat,
1129 ) {
1130 let FontInstancePlatformOptions { gamma, enhanced_contrast, .. } =
1131 font.platform_options.unwrap_or_default();
1132
1133 if gamma < 0 && enhanced_contrast <= 0 {
1134 return;
1135 }
1136
1137 match glyph_format {
1138 GlyphFormat::ColorBitmap | GlyphFormat::Bitmap => return,
1139 _ => {}
1140 }
1141
1142 let gamma = gamma.min(400);
1143 let enhanced_contrast = enhanced_contrast.clamp(0, 100);
1144 let g = if gamma < 0 { 1.0 } else { gamma as f32 / 100.0 };
1145 let c = enhanced_contrast as f32 / 100.0;
1146
1147 if gamma_luts.len() > 4 {
1148 gamma_luts.clear();
1149 }
1150 let gamma_lut = gamma_luts
1151 .entry((gamma, enhanced_contrast))
1152 .or_insert_with(|| GammaLut::new(c, g, g));
1153
1154 match font.render_mode {
1155 FontRenderMode::Alpha => {
1156 gamma_lut.preblend_grayscale(pixels, font.color);
1157 }
1158 FontRenderMode::Subpixel => {
1159 gamma_lut.preblend(pixels, font.color);
1160 }
1161 _ => {}
1162 }
1163 }
1164}
1165