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