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(any(target_os = "android", target_env = "ohos")), 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(any(target_os = "android", target_env = "ohos")), 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(any(target_os = "android", target_env = "ohos"), 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 has_bitmap_strikes(template: &FontTemplate) -> bool {
419 let cached = match FONT_CACHE.lock().unwrap().add_font(template.clone()) {
420 Ok(font) => font,
421 Err(_) => return false,
422 };
423 let cached = cached.lock().unwrap();
424 (unsafe { (*cached.face).face_flags } & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0
425 }
426
427 pub fn delete_font(&mut self, font_key: &FontKey) {
428 if let Some(cached) = self.fonts.remove(font_key) {
429 if Arc::strong_count(&cached) <= 2 {
432 FONT_CACHE.lock().unwrap().delete_font(cached);
433 }
434 }
435 }
436
437 pub fn delete_font_instance(&mut self, _instance: &FontInstance) {
438 }
439
440 fn load_glyph<'a>(
441 fonts: &'a FastHashMap<FontKey, Arc<Mutex<CachedFont>>>,
442 font: &FontInstance,
443 glyph: &GlyphKey,
444 ) -> Option<(MutexGuard<'a, CachedFont>, FT_GlyphSlot, f32)> {
445 let mut cached = fonts.get(&font.font_key)?.lock().ok()?;
446 let face = cached.face;
447
448 let mm_var = cached.mm_var;
449 if !mm_var.is_null() && font.variations != cached.variations {
450 cached.variations.clear();
451 cached.variations.extend_from_slice(&font.variations);
452
453 unsafe {
454 let num_axis = (*mm_var).num_axis;
455 let mut coords: Vec<FT_Fixed> = Vec::with_capacity(num_axis as usize);
456 for i in 0 .. num_axis {
457 let axis = (*mm_var).axis.offset(i as isize);
458 let mut value = (*axis).def;
459 for var in &font.variations {
460 if var.tag as FT_ULong == (*axis).tag {
461 value = (var.value * 65536.0 + 0.5) as FT_Fixed;
462 value = cmp::min(value, (*axis).maximum);
463 value = cmp::max(value, (*axis).minimum);
464 break;
465 }
466 }
467 coords.push(value);
468 }
469 let res = FT_Set_Var_Design_Coordinates(face, num_axis, coords.as_mut_ptr());
470 debug_assert!(succeeded(res));
471 }
472 }
473
474 let mut load_flags = FT_LOAD_DEFAULT;
475 let FontInstancePlatformOptions { mut hinting, .. } = font.platform_options.unwrap_or_default();
476 if font.synthetic_italics.is_enabled() ||
478 ((font.transform.scale_x != 0.0 || font.transform.scale_y != 0.0) &&
479 (font.transform.skew_x != 0.0 || font.transform.skew_y != 0.0)) {
480 hinting = FontHinting::None;
481 }
482 match (hinting, font.render_mode) {
483 (FontHinting::None, _) => load_flags |= FT_LOAD_NO_HINTING,
484 (FontHinting::Mono, _) => load_flags = FT_LOAD_TARGET_MONO,
485 (FontHinting::Light, _) => load_flags = FT_LOAD_TARGET_LIGHT,
486 (FontHinting::LCD, FontRenderMode::Subpixel) => {
487 load_flags = if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
488 FT_LOAD_TARGET_LCD_V
489 } else {
490 FT_LOAD_TARGET_LCD
491 };
492 if font.flags.contains(FontInstanceFlags::FORCE_AUTOHINT) {
493 load_flags |= FT_LOAD_FORCE_AUTOHINT;
494 }
495 }
496 _ => {
497 if font.flags.contains(FontInstanceFlags::FORCE_AUTOHINT) {
498 load_flags |= FT_LOAD_FORCE_AUTOHINT;
499 }
500 }
501 }
502
503 if font.flags.contains(FontInstanceFlags::NO_AUTOHINT) {
504 load_flags |= FT_LOAD_NO_AUTOHINT;
505 }
506 if !font.flags.contains(FontInstanceFlags::EMBEDDED_BITMAPS) {
507 load_flags |= FT_LOAD_NO_BITMAP;
508 }
509
510 let face_flags = unsafe { (*face).face_flags };
511 if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 {
512 load_flags |= FT_LOAD_COLOR;
516 }
517
518 load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
519
520 let (x_scale, y_scale) = font.transform.compute_scale().unwrap_or((1.0, 1.0));
521 let req_size = font.size.to_f64_px();
522
523 let mut result = if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 &&
524 (face_flags & (FT_FACE_FLAG_SCALABLE as FT_Long)) == 0 &&
525 (load_flags & FT_LOAD_NO_BITMAP) == 0 {
526 unsafe { FT_Set_Transform(face, ptr::null_mut(), ptr::null_mut()) };
527 Self::choose_bitmap_size(face, req_size * y_scale)
528 } else {
529 let mut shape = font.transform.invert_scale(x_scale, y_scale);
530 if font.flags.contains(FontInstanceFlags::FLIP_X) {
531 shape = shape.flip_x();
532 }
533 if font.flags.contains(FontInstanceFlags::FLIP_Y) {
534 shape = shape.flip_y();
535 }
536 if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
537 shape = shape.swap_xy();
538 }
539 let (mut tx, mut ty) = (0.0, 0.0);
540 if font.synthetic_italics.is_enabled() {
541 let (shape_, (tx_, ty_)) = font.synthesize_italics(shape, y_scale * req_size);
542 shape = shape_;
543 tx = tx_;
544 ty = ty_;
545 };
546 let mut ft_shape = FT_Matrix {
547 xx: (shape.scale_x * 65536.0) as FT_Fixed,
548 xy: (shape.skew_x * -65536.0) as FT_Fixed,
549 yx: (shape.skew_y * -65536.0) as FT_Fixed,
550 yy: (shape.scale_y * 65536.0) as FT_Fixed,
551 };
552 let mut ft_delta = FT_Vector {
554 x: (tx * 64.0) as FT_F26Dot6,
555 y: (ty * -64.0) as FT_F26Dot6,
556 };
557 unsafe {
558 FT_Set_Transform(face, &mut ft_shape, &mut ft_delta);
559 FT_Set_Char_Size(
560 face,
561 (req_size * x_scale * 64.0 + 0.5) as FT_F26Dot6,
562 (req_size * y_scale * 64.0 + 0.5) as FT_F26Dot6,
563 0,
564 0,
565 )
566 }
567 };
568
569 if !succeeded(result) {
570 error!("Unable to set glyph size and transform: {}", result);
571 debug!(
576 "\t[{}] for size {:?} and scale {:?} from font {:?}",
577 glyph.index(),
578 req_size,
579 (x_scale, y_scale),
580 font.font_key,
581 );
582 return None;
583 }
584
585 result = unsafe { FT_Load_Glyph(face, glyph.index() as FT_UInt, load_flags as FT_Int32) };
586 if !succeeded(result) {
587 error!("Unable to load glyph: {}", result);
588 debug!(
593 "\t[{}] with flags {:?} from font {:?}",
594 glyph.index(),
595 load_flags,
596 font.font_key,
597 );
598 return None;
599 }
600
601 let slot = unsafe { (*face).glyph };
602 assert!(slot != ptr::null_mut());
603
604 if font.flags.contains(FontInstanceFlags::SYNTHETIC_BOLD) {
605 mozilla_glyphslot_embolden_less(slot);
606 }
607
608 let format = unsafe { (*slot).format };
609 match format {
610 FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
611 let bitmap_size = unsafe { (*(*(*slot).face).size).metrics.y_ppem };
612 Some((cached, slot, req_size as f32 / bitmap_size as f32))
613 }
614 FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => Some((cached, slot, 1.0)),
615 _ => {
616 error!("Unsupported format");
617 debug!("format={:?}", format);
618 None
619 }
620 }
621 }
622
623 fn pad_bounding_box(font: &FontInstance, cbox: &mut FT_BBox) {
624 if font.render_mode == FontRenderMode::Subpixel {
626 let lcd_extra_pixels = 1;
632 let padding = (lcd_extra_pixels * 64) as FT_Pos;
633 if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
634 cbox.yMin -= padding;
635 cbox.yMax += padding;
636 } else {
637 cbox.xMin -= padding;
638 cbox.xMax += padding;
639 }
640 }
641 }
642
643 fn get_bounding_box(
645 slot: FT_GlyphSlot,
646 font: &FontInstance,
647 glyph: &GlyphKey,
648 scale: f32,
649 ) -> FT_BBox {
650 let mut cbox = FT_BBox { xMin: 0, yMin: 0, xMax: 0, yMax: 0 };
652
653 unsafe {
654 FT_Outline_Get_CBox(&(*slot).outline, &mut cbox);
655 }
656
657 if unsafe { (*slot).outline.n_contours } == 0 {
659 return cbox;
660 }
661
662 Self::pad_bounding_box(font, &mut cbox);
663
664 let (dx, dy) = font.get_subpx_offset(glyph);
667 let (dx, dy) = (
668 (dx / scale as f64 * 64.0 + 0.5) as FT_Pos,
669 -(dy / scale as f64 * 64.0 + 0.5) as FT_Pos,
670 );
671 cbox.xMin += dx;
672 cbox.xMax += dx;
673 cbox.yMin += dy;
674 cbox.yMax += dy;
675
676 cbox.xMin &= !63;
678 cbox.yMin &= !63;
679 cbox.xMax = (cbox.xMax + 63) & !63;
680 cbox.yMax = (cbox.yMax + 63) & !63;
681
682 cbox
683 }
684
685 fn get_glyph_dimensions_impl(
686 slot: FT_GlyphSlot,
687 font: &FontInstance,
688 glyph: &GlyphKey,
689 scale: f32,
690 use_transform: bool,
691 ) -> Option<GlyphDimensions> {
692 let format = unsafe { (*slot).format };
693 let (mut left, mut top, mut width, mut height) = match format {
694 FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
695 unsafe { (
696 (*slot).bitmap_left as i32,
697 (*slot).bitmap_top as i32,
698 (*slot).bitmap.width as i32,
699 (*slot).bitmap.rows as i32,
700 ) }
701 }
702 FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
703 let cbox = Self::get_bounding_box(slot, font, glyph, scale);
704 (
705 (cbox.xMin >> 6) as i32,
706 (cbox.yMax >> 6) as i32,
707 ((cbox.xMax - cbox.xMin) >> 6) as i32,
708 ((cbox.yMax - cbox.yMin) >> 6) as i32,
709 )
710 }
711 _ => return None,
712 };
713 let mut advance = unsafe { (*slot).metrics.horiAdvance as f32 / 64.0 };
714 if use_transform {
715 if scale != 1.0 {
716 let x0 = left as f32 * scale;
717 let x1 = width as f32 * scale + x0;
718 let y1 = top as f32 * scale;
719 let y0 = y1 - height as f32 * scale;
720 left = x0.round() as i32;
721 top = y1.round() as i32;
722 width = (x1.ceil() - x0.floor()) as i32;
723 height = (y1.ceil() - y0.floor()) as i32;
724 advance *= scale;
725 }
726 if format == FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP {
729 if font.synthetic_italics.is_enabled() {
730 let (skew_min, skew_max) = get_skew_bounds(
731 top - height as i32,
732 top,
733 font.synthetic_italics.to_skew(),
734 font.flags.contains(FontInstanceFlags::VERTICAL),
735 );
736 left += skew_min as i32;
737 width += (skew_max - skew_min) as i32;
738 }
739 if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
740 mem::swap(&mut width, &mut height);
741 mem::swap(&mut left, &mut top);
742 left -= width as i32;
743 top += height as i32;
744 }
745 if font.flags.contains(FontInstanceFlags::FLIP_X) {
746 left = -(left + width as i32);
747 }
748 if font.flags.contains(FontInstanceFlags::FLIP_Y) {
749 top = -(top - height as i32);
750 }
751 }
752 }
753 Some(GlyphDimensions {
754 left,
755 top,
756 width,
757 height,
758 advance,
759 })
760 }
761
762 pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
763 let cached = self.fonts.get(&font_key)?.lock().ok()?;
764 let face = cached.face;
765 unsafe {
766 let idx = FT_Get_Char_Index(face, ch as _);
767 if idx != 0 {
768 Some(idx)
769 } else {
770 None
771 }
772 }
773 }
774
775 pub fn get_glyph_dimensions(
776 &mut self,
777 font: &FontInstance,
778 key: &GlyphKey,
779 ) -> Option<GlyphDimensions> {
780 let (_cached, slot, scale) = Self::load_glyph(&self.fonts, font, key)?;
781 Self::get_glyph_dimensions_impl(slot, &font, key, scale, true)
782 }
783
784 fn choose_bitmap_size(face: FT_Face, requested_size: f64) -> FT_Error {
785 let mut best_dist = unsafe { *(*face).available_sizes.offset(0) }.y_ppem as f64 / 64.0 - requested_size;
786 let mut best_size = 0;
787 let num_fixed_sizes = unsafe { (*face).num_fixed_sizes };
788 for i in 1 .. num_fixed_sizes {
789 let dist = unsafe { *(*face).available_sizes.offset(i as isize) }.y_ppem as f64 / 64.0 - requested_size;
793 if (best_dist < 0.0 && dist >= best_dist) || dist.abs() <= best_dist {
794 best_dist = dist;
795 best_size = i;
796 }
797 }
798 unsafe { FT_Select_Size(face, best_size) }
799 }
800
801 pub fn prepare_font(font: &mut FontInstance) {
802 let preblend_enabled = font.platform_options.map_or(false, |o| o.gamma >= 0 || o.enhanced_contrast > 0);
803 match font.render_mode {
804 FontRenderMode::Mono => {
805 font.color = ColorU::new(0xFF, 0xFF, 0xFF, 0xFF);
807 font.disable_subpixel_position();
809 }
810 FontRenderMode::Alpha => {
811 if preblend_enabled {
812 font.color = font.color.luminance_color().quantize();
813 } else {
814 font.color = ColorU::new(0xFF, 0xFF, 0xFF, 0xFF);
816 }
817 }
818 FontRenderMode::Subpixel => {
819 if preblend_enabled {
820 font.color = font.color.quantize();
821 } else {
822 font.color = ColorU::new(0xFF, 0xFF, 0xFF, 0xFF);
824 }
825 }
826 }
827 }
828
829 fn rasterize_glyph_outline(
830 slot: FT_GlyphSlot,
831 font: &FontInstance,
832 key: &GlyphKey,
833 scale: f32,
834 ) -> bool {
835 let (dx, dy) = font.get_subpx_offset(key);
837 let (dx, dy) = (
838 (dx / scale as f64 * 64.0 + 0.5) as FT_Pos,
839 -(dy / scale as f64 * 64.0 + 0.5) as FT_Pos,
840 );
841
842 unsafe {
845 let outline = &(*slot).outline;
846 let mut cbox = FT_BBox { xMin: 0, yMin: 0, xMax: 0, yMax: 0 };
847 FT_Outline_Get_CBox(outline, &mut cbox);
848 Self::pad_bounding_box(font, &mut cbox);
849 FT_Outline_Translate(
850 outline,
851 dx - ((cbox.xMin + dx) & !63),
852 dy - ((cbox.yMin + dy) & !63),
853 );
854 }
855
856 let render_mode = match font.render_mode {
857 FontRenderMode::Mono => FT_Render_Mode::FT_RENDER_MODE_MONO,
858 FontRenderMode::Alpha => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
859 FontRenderMode::Subpixel => if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
860 FT_Render_Mode::FT_RENDER_MODE_LCD_V
861 } else {
862 FT_Render_Mode::FT_RENDER_MODE_LCD
863 },
864 };
865 let result = unsafe { FT_Render_Glyph(slot, render_mode) };
866 if !succeeded(result) {
867 error!("Unable to rasterize");
868 debug!(
869 "{:?} with {:?}, {:?}",
870 key,
871 render_mode,
872 result
873 );
874 false
875 } else {
876 true
877 }
878 }
879
880 pub fn begin_rasterize(font: &FontInstance) {
881 if font.render_mode == FontRenderMode::Subpixel {
883 let mut cache = FONT_CACHE.lock().unwrap();
884 let FontInstancePlatformOptions { lcd_filter, .. } = font.platform_options.unwrap_or_default();
885 if cache.lcd_filter != lcd_filter {
887 while cache.lcd_filter_uses != 0 {
890 cache = LCD_FILTER_UNUSED.wait(cache).unwrap();
891 }
892 cache.lcd_filter = lcd_filter;
894 let filter = match lcd_filter {
895 FontLCDFilter::None => FT_LcdFilter::FT_LCD_FILTER_NONE,
896 FontLCDFilter::Default => FT_LcdFilter::FT_LCD_FILTER_DEFAULT,
897 FontLCDFilter::Light => FT_LcdFilter::FT_LCD_FILTER_LIGHT,
898 FontLCDFilter::Legacy => FT_LcdFilter::FT_LCD_FILTER_LEGACY,
899 };
900 unsafe {
901 let result = FT_Library_SetLcdFilter(cache.lib, filter);
902 if !succeeded(result) {
904 FT_Library_SetLcdFilter(cache.lib, FT_LcdFilter::FT_LCD_FILTER_DEFAULT);
905 }
906 }
907 }
908 cache.lcd_filter_uses += 1;
909 }
910 }
911
912 pub fn end_rasterize(font: &FontInstance) {
913 if font.render_mode == FontRenderMode::Subpixel {
914 let mut cache = FONT_CACHE.lock().unwrap();
915 cache.lcd_filter_uses -= 1;
917 if cache.lcd_filter_uses == 0 {
918 LCD_FILTER_UNUSED.notify_all();
919 }
920 }
921 }
922
923 pub fn rasterize_glyph(&mut self, font: &FontInstance, key: &GlyphKey) -> GlyphRasterResult {
924 let (_cached, slot, scale) = Self::load_glyph(&self.fonts, font, key)
925 .ok_or(GlyphRasterError::LoadFailed)?;
926
927 let dimensions = Self::get_glyph_dimensions_impl(slot, font, key, scale, false)
931 .ok_or(GlyphRasterError::LoadFailed)?;
932 let GlyphDimensions { mut left, mut top, width, height, .. } = dimensions;
933
934 if width == 0 || height == 0 {
936 return Err(GlyphRasterError::LoadFailed);
937 }
938
939 let format = unsafe { (*slot).format };
940 match format {
941 FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {}
942 FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
943 if !Self::rasterize_glyph_outline(slot, font, key, scale) {
944 return Err(GlyphRasterError::LoadFailed);
945 }
946 }
947 _ => {
948 error!("Unsupported format");
949 debug!("format={:?}", format);
950 return Err(GlyphRasterError::LoadFailed);
951 }
952 };
953
954 debug!(
955 "Rasterizing {:?} as {:?} with dimensions {:?}",
956 key,
957 font.render_mode,
958 dimensions
959 );
960
961 let bitmap = unsafe { &(*slot).bitmap };
962 let pixel_mode = unsafe { mem::transmute(bitmap.pixel_mode as u32) };
963 let (mut actual_width, mut actual_height) = match pixel_mode {
964 FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
965 assert!(bitmap.width % 3 == 0);
966 ((bitmap.width / 3) as usize, bitmap.rows as usize)
967 }
968 FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V => {
969 assert!(bitmap.rows % 3 == 0);
970 (bitmap.width as usize, (bitmap.rows / 3) as usize)
971 }
972 FT_Pixel_Mode::FT_PIXEL_MODE_MONO |
973 FT_Pixel_Mode::FT_PIXEL_MODE_GRAY |
974 FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
975 (bitmap.width as usize, bitmap.rows as usize)
976 }
977 _ => panic!("Unsupported mode"),
978 };
979
980 let (buffer_width, buffer_height, padding) = if font.use_texture_padding() {
982 (actual_width + 2, actual_height + 2, 1)
983 } else {
984 (actual_width, actual_height, 0)
985 };
986
987 let mut final_buffer = vec![0u8; buffer_width * buffer_height * 4];
988
989 let subpixel_bgr = font.flags.contains(FontInstanceFlags::SUBPIXEL_BGR);
992 let mut src_row = bitmap.buffer;
993 let mut dest = 4 * padding * (padding + buffer_width);
994 let actual_end = final_buffer.len() - 4 * padding * (buffer_width + 1);
995 while dest < actual_end {
996 let mut src = src_row;
997 let row_end = dest + actual_width * 4;
998 match pixel_mode {
999 FT_Pixel_Mode::FT_PIXEL_MODE_MONO => {
1000 while dest < row_end {
1001 let mut byte: i8 = unsafe { *src as i8 };
1004 src = unsafe { src.offset(1) };
1005 let byte_end = cmp::min(row_end, dest + 8 * 4);
1006 while dest < byte_end {
1007 let alpha = (byte >> 7) as u8;
1008 final_buffer[dest + 0] = alpha;
1009 final_buffer[dest + 1] = alpha;
1010 final_buffer[dest + 2] = alpha;
1011 final_buffer[dest + 3] = alpha;
1012 dest += 4;
1013 byte <<= 1;
1014 }
1015 }
1016 }
1017 FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => {
1018 while dest < row_end {
1019 let alpha = unsafe { *src };
1020 final_buffer[dest + 0] = alpha;
1021 final_buffer[dest + 1] = alpha;
1022 final_buffer[dest + 2] = alpha;
1023 final_buffer[dest + 3] = alpha;
1024 src = unsafe { src.offset(1) };
1025 dest += 4;
1026 }
1027 }
1028 FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
1029 while dest < row_end {
1030 let (mut r, g, mut b) = unsafe { (*src, *src.offset(1), *src.offset(2)) };
1031 if subpixel_bgr {
1032 mem::swap(&mut r, &mut b);
1033 }
1034 final_buffer[dest + 0] = b;
1035 final_buffer[dest + 1] = g;
1036 final_buffer[dest + 2] = r;
1037 final_buffer[dest + 3] = max(max(b, g), r);
1038 src = unsafe { src.offset(3) };
1039 dest += 4;
1040 }
1041 }
1042 FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V => {
1043 while dest < row_end {
1044 let (mut r, g, mut b) =
1045 unsafe { (*src, *src.offset(bitmap.pitch as isize),
1046 *src.offset((2 * bitmap.pitch) as isize)) };
1047 if subpixel_bgr {
1048 mem::swap(&mut r, &mut b);
1049 }
1050 final_buffer[dest + 0] = b;
1051 final_buffer[dest + 1] = g;
1052 final_buffer[dest + 2] = r;
1053 final_buffer[dest + 3] = max(max(b, g), r);
1054 src = unsafe { src.offset(1) };
1055 dest += 4;
1056 }
1057 src_row = unsafe { src_row.offset((2 * bitmap.pitch) as isize) };
1058 }
1059 FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
1060 let dest_slice = &mut final_buffer[dest .. row_end];
1062 let src_slice = unsafe { slice::from_raw_parts(src, dest_slice.len()) };
1063 dest_slice.copy_from_slice(src_slice);
1064 }
1065 _ => panic!("Unsupported mode"),
1066 }
1067 src_row = unsafe { src_row.offset(bitmap.pitch as isize) };
1068 dest = row_end + 8 * padding;
1069 }
1070
1071 if font.use_texture_padding() {
1072 left -= padding as i32;
1073 top += padding as i32;
1074 actual_width = buffer_width;
1075 actual_height = buffer_height;
1076 }
1077
1078 match format {
1079 FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
1080 if font.synthetic_italics.is_enabled() {
1081 let (skew_buffer, skew_width, skew_left) = skew_bitmap(
1082 &final_buffer,
1083 actual_width,
1084 actual_height,
1085 left,
1086 top,
1087 font.synthetic_italics.to_skew(),
1088 font.flags.contains(FontInstanceFlags::VERTICAL),
1089 );
1090 final_buffer = skew_buffer;
1091 actual_width = skew_width;
1092 left = skew_left;
1093 }
1094 if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
1095 final_buffer = transpose_bitmap(&final_buffer, actual_width, actual_height);
1096 mem::swap(&mut actual_width, &mut actual_height);
1097 mem::swap(&mut left, &mut top);
1098 left -= actual_width as i32;
1099 top += actual_height as i32;
1100 }
1101 if font.flags.contains(FontInstanceFlags::FLIP_X) {
1102 flip_bitmap_x(&mut final_buffer, actual_width, actual_height);
1103 left = -(left + actual_width as i32);
1104 }
1105 if font.flags.contains(FontInstanceFlags::FLIP_Y) {
1106 flip_bitmap_y(&mut final_buffer, actual_width, actual_height);
1107 top = -(top - actual_height as i32);
1108 }
1109 }
1110 FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
1111 unsafe {
1112 left += (*slot).bitmap_left;
1113 top += (*slot).bitmap_top - height as i32;
1114 }
1115 }
1116 _ => {}
1117 }
1118
1119 let glyph_format = match (pixel_mode, format) {
1120 (FT_Pixel_Mode::FT_PIXEL_MODE_LCD, _) |
1121 (FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V, _) => font.get_subpixel_glyph_format(),
1122 (FT_Pixel_Mode::FT_PIXEL_MODE_BGRA, _) => GlyphFormat::ColorBitmap,
1123 (_, FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP) => GlyphFormat::Bitmap,
1124 _ => font.get_alpha_glyph_format(),
1125 };
1126
1127 Self::gamma_correct_pixels(font, &mut self.gamma_luts, &mut final_buffer, glyph_format);
1128
1129 Ok(RasterizedGlyph {
1130 left: left as f32,
1131 top: top as f32,
1132 width: actual_width as i32,
1133 height: actual_height as i32,
1134 scale,
1135 format: glyph_format,
1136 bytes: final_buffer,
1137 is_packed_glyph: false,
1138 })
1139 }
1140
1141 fn gamma_correct_pixels(
1142 font: &FontInstance,
1143 gamma_luts: &mut FastHashMap<(i16, i16), GammaLut>,
1144 pixels: &mut Vec<u8>,
1145 glyph_format: GlyphFormat,
1146 ) {
1147 let FontInstancePlatformOptions { gamma, enhanced_contrast, .. } =
1148 font.platform_options.unwrap_or_default();
1149
1150 if gamma < 0 && enhanced_contrast <= 0 {
1151 return;
1152 }
1153
1154 match glyph_format {
1155 GlyphFormat::ColorBitmap | GlyphFormat::Bitmap => return,
1156 _ => {}
1157 }
1158
1159 let gamma = gamma.min(400);
1160 let enhanced_contrast = enhanced_contrast.clamp(0, 100);
1161 let g = if gamma < 0 { 1.0 } else { gamma as f32 / 100.0 };
1162 let c = enhanced_contrast as f32 / 100.0;
1163
1164 if gamma_luts.len() > 4 {
1165 gamma_luts.clear();
1166 }
1167 let gamma_lut = gamma_luts
1168 .entry((gamma, enhanced_contrast))
1169 .or_insert_with(|| GammaLut::new(c, g, g));
1170
1171 match font.render_mode {
1172 FontRenderMode::Alpha => {
1173 gamma_lut.preblend_grayscale(pixels, font.color);
1174 }
1175 FontRenderMode::Subpixel => {
1176 gamma_lut.preblend(pixels, font.color);
1177 }
1178 _ => {}
1179 }
1180 }
1181}
1182