1use byteorder::{BigEndian, ReadBytesExt};
17use freetype_sys::{
18 ft_sfnt_os2, FT_Byte, FT_Done_Face, FT_Done_FreeType, FT_Error, FT_Face, FT_Fixed,
19 FT_Get_Char_Index, FT_Get_Name_Index, FT_Get_Postscript_Name, FT_Get_Sfnt_Name,
20 FT_Get_Sfnt_Name_Count, FT_Get_Sfnt_Table, FT_Init_FreeType, FT_Library,
21 FT_Library_SetLcdFilter, FT_Load_Glyph, FT_Long, FT_Matrix, FT_New_Memory_Face, FT_Pos,
22 FT_Reference_Face, FT_Set_Char_Size, FT_Set_Transform, FT_UInt, FT_ULong, FT_Vector,
23 FT_FACE_FLAG_FIXED_WIDTH, FT_LCD_FILTER_DEFAULT, FT_LOAD_DEFAULT, FT_LOAD_MONOCHROME,
24 FT_LOAD_NO_HINTING, FT_LOAD_RENDER, FT_LOAD_TARGET_LCD, FT_LOAD_TARGET_LIGHT,
25 FT_LOAD_TARGET_MONO, FT_LOAD_TARGET_NORMAL, FT_PIXEL_MODE_GRAY, FT_PIXEL_MODE_LCD,
26 FT_PIXEL_MODE_LCD_V, FT_PIXEL_MODE_MONO, FT_STYLE_FLAG_ITALIC, TT_OS2,
27};
28use log::warn;
29use pathfinder_geometry::line_segment::LineSegment2F;
30use pathfinder_geometry::rect::{RectF, RectI};
31use pathfinder_geometry::transform2d::Transform2F;
32use pathfinder_geometry::vector::{Vector2F, Vector2I};
33use pathfinder_simd::default::F32x4;
34use std::f32;
35use std::ffi::{CStr, CString};
36use std::fmt::{self, Debug, Formatter};
37use std::io::{Seek, SeekFrom};
38use std::iter;
39use std::mem;
40use std::os::raw::{c_char, c_void};
41use std::ptr;
42use std::slice;
43use std::sync::Arc;
44
45use crate::canvas::{Canvas, Format, RasterizationOptions};
46use crate::error::{FontLoadingError, GlyphLoadingError};
47use crate::file_type::FileType;
48use crate::handle::Handle;
49use crate::hinting::HintingOptions;
50use crate::loader::{FallbackResult, Loader};
51use crate::metrics::Metrics;
52use crate::outline::OutlineSink;
53use crate::properties::{Properties, Stretch, Style, Weight};
54use crate::utils;
55
56#[cfg(not(target_arch = "wasm32"))]
57use std::fs::File;
58#[cfg(not(target_arch = "wasm32"))]
59use std::path::Path;
60
61const PS_DICT_FULL_NAME: u32 = 38;
62const TT_NAME_ID_FULL_NAME: u16 = 4;
63
64const TT_PLATFORM_APPLE_UNICODE: u16 = 0;
65
66const FT_POINT_TAG_ON_CURVE: c_char = 0x01;
67const FT_POINT_TAG_CUBIC_CONTROL: c_char = 0x02;
68
69const OS2_FS_SELECTION_OBLIQUE: u16 = 1 << 9;
70
71#[allow(dead_code)]
73const BDF_PROPERTY_TYPE_NONE: BDF_PropertyType = 0;
74#[allow(dead_code)]
75const BDF_PROPERTY_TYPE_ATOM: BDF_PropertyType = 1;
76#[allow(dead_code)]
77const BDF_PROPERTY_TYPE_INTEGER: BDF_PropertyType = 2;
78#[allow(dead_code)]
79const BDF_PROPERTY_TYPE_CARDINAL: BDF_PropertyType = 3;
80
81thread_local! {
82 static FREETYPE_LIBRARY: FtLibrary = {
83 unsafe {
84 let mut library = ptr::null_mut();
85 assert_eq!(FT_Init_FreeType(&mut library), 0);
86 FT_Library_SetLcdFilter(library, FT_LCD_FILTER_DEFAULT);
87 FtLibrary(library)
88 }
89 };
90}
91
92#[repr(transparent)]
93struct FtLibrary(FT_Library);
94
95impl Drop for FtLibrary {
96 fn drop(&mut self) {
97 unsafe {
98 let mut library = ptr::null_mut();
99 mem::swap(&mut library, &mut self.0);
100 FT_Done_FreeType(library);
101 }
102 }
103}
104
105pub type NativeFont = FT_Face;
107
108#[allow(non_camel_case_types)]
110type BDF_PropertyType = i32;
111
112#[repr(C)]
114struct BDF_PropertyRec {
115 property_type: BDF_PropertyType,
116 value: *const c_char,
117}
118
119pub struct Font {
125 freetype_face: FT_Face,
126 font_data: Arc<Vec<u8>>,
127}
128
129impl Font {
130 pub fn from_bytes(font_data: Arc<Vec<u8>>, font_index: u32) -> Result<Font, FontLoadingError> {
135 FREETYPE_LIBRARY.with(|freetype_library| unsafe {
136 let mut freetype_face = ptr::null_mut();
137 if FT_New_Memory_Face(
138 freetype_library.0,
139 (*font_data).as_ptr(),
140 font_data.len() as FT_Long,
141 font_index as FT_Long,
142 &mut freetype_face,
143 ) != 0
144 {
145 return Err(FontLoadingError::Parse);
146 }
147
148 setup_freetype_face(freetype_face);
149
150 Ok(Font {
151 freetype_face,
152 font_data,
153 })
154 })
155 }
156
157 #[cfg(not(target_arch = "wasm32"))]
162 pub fn from_file(file: &mut File, font_index: u32) -> Result<Font, FontLoadingError> {
163 file.seek(SeekFrom::Start(0))?;
164 let font_data = Arc::new(utils::slurp_file(file).map_err(FontLoadingError::Io)?);
165 Font::from_bytes(font_data, font_index)
166 }
167
168 #[inline]
173 #[cfg(not(target_arch = "wasm32"))]
174 pub fn from_path<P>(path: P, font_index: u32) -> Result<Font, FontLoadingError>
175 where
176 P: AsRef<Path>,
177 {
178 <Font as Loader>::from_path(path, font_index)
180 }
181
182 pub unsafe fn from_native_font(freetype_face: &NativeFont) -> Font {
184 let freetype_face = *freetype_face;
187 const CHUNK_SIZE: usize = 4096;
188 let mut font_data = vec![];
189 loop {
190 font_data.extend(iter::repeat(0).take(CHUNK_SIZE));
191 let freetype_stream = (*freetype_face).stream;
192 let n_read = ((*freetype_stream).read)(
193 freetype_stream,
194 font_data.len() as FT_ULong,
195 font_data.as_mut_ptr(),
196 CHUNK_SIZE as FT_ULong,
197 );
198 if n_read < CHUNK_SIZE as FT_ULong {
199 break;
200 }
201 }
202
203 Font::from_bytes(Arc::new(font_data), (*freetype_face).face_index as u32).unwrap()
204 }
205
206 #[inline]
208 pub fn from_handle(handle: &Handle) -> Result<Self, FontLoadingError> {
209 <Self as Loader>::from_handle(handle)
210 }
211
212 pub fn analyze_bytes(font_data: Arc<Vec<u8>>) -> Result<FileType, FontLoadingError> {
215 FREETYPE_LIBRARY.with(|freetype_library| unsafe {
216 let mut freetype_face = ptr::null_mut();
217 if FT_New_Memory_Face(
218 freetype_library.0,
219 (*font_data).as_ptr(),
220 font_data.len() as FT_Long,
221 0,
222 &mut freetype_face,
223 ) != 0
224 {
225 return Err(FontLoadingError::Parse);
226 }
227
228 let font_type = match (*freetype_face).num_faces {
229 1 => FileType::Single,
230 num_faces => FileType::Collection(num_faces as u32),
231 };
232 FT_Done_Face(freetype_face);
233 Ok(font_type)
234 })
235 }
236
237 #[cfg(not(target_arch = "wasm32"))]
239 pub fn analyze_file(file: &mut File) -> Result<FileType, FontLoadingError> {
240 FREETYPE_LIBRARY.with(|freetype_library| unsafe {
241 file.seek(SeekFrom::Start(0))?;
242 let font_data = Arc::new(utils::slurp_file(file).map_err(FontLoadingError::Io)?);
243
244 let mut freetype_face = ptr::null_mut();
245 if FT_New_Memory_Face(
246 freetype_library.0,
247 (*font_data).as_ptr(),
248 font_data.len() as FT_Long,
249 0,
250 &mut freetype_face,
251 ) != 0
252 {
253 return Err(FontLoadingError::Parse);
254 }
255
256 let font_type = match (*freetype_face).num_faces {
257 1 => FileType::Single,
258 num_faces => FileType::Collection(num_faces as u32),
259 };
260 FT_Done_Face(freetype_face);
261 Ok(font_type)
262 })
263 }
264
265 #[inline]
267 #[cfg(not(target_arch = "wasm32"))]
268 pub fn analyze_path<P>(path: P) -> Result<FileType, FontLoadingError>
269 where
270 P: AsRef<Path>,
271 {
272 <Self as Loader>::analyze_path(path)
273 }
274
275 pub fn native_font(&self) -> NativeFont {
280 unsafe {
281 assert_eq!(FT_Reference_Face(self.freetype_face), 0);
282 self.freetype_face
283 }
284 }
285
286 pub fn postscript_name(&self) -> Option<String> {
288 unsafe {
289 let postscript_name = FT_Get_Postscript_Name(self.freetype_face);
290 if !postscript_name.is_null() {
291 return Some(CStr::from_ptr(postscript_name).to_str().unwrap().to_owned());
292 }
293
294 let font_format = FT_Get_Font_Format(self.freetype_face);
295 assert!(!font_format.is_null());
296 let font_format = CStr::from_ptr(font_format).to_str().unwrap();
297 if font_format != "BDF" && font_format != "PCF" {
298 return None;
299 }
300
301 let mut property = mem::zeroed();
302 if FT_Get_BDF_Property(
303 self.freetype_face,
304 "_DEC_DEVICE_FONTNAMES\0".as_ptr() as *const c_char,
305 &mut property,
306 ) != 0
307 {
308 return None;
309 }
310 if property.property_type != BDF_PROPERTY_TYPE_ATOM {
311 return None;
312 }
313 let dec_device_fontnames = CStr::from_ptr(property.value).to_str().unwrap();
314 if !dec_device_fontnames.starts_with("PS=") {
315 return None;
316 }
317 Some(dec_device_fontnames[3..].to_string())
318 }
319 }
320
321 pub fn full_name(&self) -> String {
323 self.get_type_1_or_sfnt_name(PS_DICT_FULL_NAME, TT_NAME_ID_FULL_NAME)
324 .unwrap_or_else(|| self.family_name())
325 }
326
327 pub fn family_name(&self) -> String {
329 unsafe {
330 let ptr = (*self.freetype_face).family_name;
331 if ptr.is_null() {
333 String::new()
334 } else {
335 CStr::from_ptr(ptr).to_str().unwrap().to_owned()
336 }
337 }
338 }
339
340 pub fn is_monospace(&self) -> bool {
342 unsafe { (*self.freetype_face).face_flags & (FT_FACE_FLAG_FIXED_WIDTH as FT_Long) != 0 }
343 }
344
345 pub fn properties(&self) -> Properties {
347 unsafe {
348 let os2_table = self.get_os2_table();
349 let style = match os2_table {
350 Some(os2_table) if ((*os2_table).fsSelection & OS2_FS_SELECTION_OBLIQUE) != 0 => {
351 Style::Oblique
352 }
353 _ if ((*self.freetype_face).style_flags & (FT_STYLE_FLAG_ITALIC) as FT_Long)
354 != 0 =>
355 {
356 Style::Italic
357 }
358 _ => Style::Normal,
359 };
360 let stretch = match os2_table {
361 Some(os2_table) if (1..=9).contains(&(*os2_table).usWidthClass) => {
362 Stretch(Stretch::MAPPING[((*os2_table).usWidthClass as usize) - 1])
363 }
364 _ => Stretch::NORMAL,
365 };
366 let weight = match os2_table {
367 None => Weight::NORMAL,
368 Some(os2_table) => Weight((*os2_table).usWeightClass as f32),
369 };
370 Properties {
371 style,
372 stretch,
373 weight,
374 }
375 }
376 }
377
378 #[inline]
384 pub fn glyph_for_char(&self, character: char) -> Option<u32> {
385 unsafe {
386 let res = FT_Get_Char_Index(self.freetype_face, character as FT_ULong);
387 match res {
388 0 => None,
389 _ => Some(res),
390 }
391 }
392 }
393
394 #[inline]
396 pub fn glyph_by_name(&self, name: &str) -> Option<u32> {
397 if let Ok(ffi_name) = CString::new(name) {
398 let code =
399 unsafe { FT_Get_Name_Index(self.freetype_face, ffi_name.as_ptr() as *mut c_char) };
400
401 if code > 0 {
402 return Some(code);
403 }
404 }
405 None
406 }
407
408 #[inline]
412 pub fn glyph_count(&self) -> u32 {
413 unsafe { (*self.freetype_face).num_glyphs as u32 }
414 }
415
416 pub fn outline<S>(
423 &self,
424 glyph_id: u32,
425 hinting: HintingOptions,
426 sink: &mut S,
427 ) -> Result<(), GlyphLoadingError>
428 where
429 S: OutlineSink,
430 {
431 unsafe {
432 let rasterization_options = RasterizationOptions::GrayscaleAa;
433 let load_flags = self
434 .hinting_and_rasterization_options_to_load_flags(hinting, rasterization_options);
435
436 let units_per_em = (*self.freetype_face).units_per_EM;
437 let grid_fitting_size = hinting.grid_fitting_size();
438 if let Some(size) = grid_fitting_size {
439 assert_eq!(
440 FT_Set_Char_Size(self.freetype_face, size.f32_to_ft_fixed_26_6(), 0, 0, 0),
441 0
442 );
443 }
444
445 if FT_Load_Glyph(self.freetype_face, glyph_id, load_flags) != 0 {
446 return Err(GlyphLoadingError::NoSuchGlyph);
447 }
448
449 let outline = &(*(*self.freetype_face).glyph).outline;
450 if outline.n_contours == 0 {
451 return Ok(());
452 }
453 let contours = slice::from_raw_parts(outline.contours, outline.n_contours as usize);
454 let point_positions = slice::from_raw_parts(outline.points, outline.n_points as usize);
455 let point_tags = slice::from_raw_parts(outline.tags, outline.n_points as usize);
456
457 let mut current_point_index = 0;
458 for &last_point_index_in_contour in contours {
459 let last_point_index_in_contour = last_point_index_in_contour as usize;
460 let (mut first_point, first_tag) = get_point(
461 &mut current_point_index,
462 point_positions,
463 point_tags,
464 last_point_index_in_contour,
465 grid_fitting_size,
466 units_per_em,
467 );
468 if (first_tag & FT_POINT_TAG_ON_CURVE) == 0 {
469 let mut temp_point_index = last_point_index_in_contour;
473 let (last_point, last_tag) = get_point(
474 &mut temp_point_index,
475 point_positions,
476 point_tags,
477 last_point_index_in_contour,
478 grid_fitting_size,
479 units_per_em,
480 );
481 if (last_tag & FT_POINT_TAG_ON_CURVE) != 0 {
482 first_point = last_point
483 } else {
484 first_point = last_point.lerp(first_point, 0.5)
485 }
486 current_point_index -= 1;
488 }
489 sink.move_to(first_point);
490
491 while current_point_index <= last_point_index_in_contour {
492 let (mut point0, tag0) = get_point(
493 &mut current_point_index,
494 point_positions,
495 point_tags,
496 last_point_index_in_contour,
497 grid_fitting_size,
498 units_per_em,
499 );
500 if (tag0 & FT_POINT_TAG_ON_CURVE) != 0 {
501 sink.line_to(point0);
502 continue;
503 }
504
505 loop {
506 if current_point_index > last_point_index_in_contour {
507 sink.quadratic_curve_to(point0, first_point);
510 break;
511 }
512
513 let (point1, tag1) = get_point(
514 &mut current_point_index,
515 point_positions,
516 point_tags,
517 last_point_index_in_contour,
518 grid_fitting_size,
519 units_per_em,
520 );
521
522 if (tag0 & FT_POINT_TAG_CUBIC_CONTROL) != 0 {
523 let ctrl = LineSegment2F::new(point0, point1);
524 if current_point_index <= last_point_index_in_contour {
525 let (point2, _) = get_point(
528 &mut current_point_index,
529 point_positions,
530 point_tags,
531 last_point_index_in_contour,
532 grid_fitting_size,
533 units_per_em,
534 );
535 sink.cubic_curve_to(ctrl, point2);
536 } else {
537 sink.cubic_curve_to(ctrl, first_point);
539 }
540 break;
541 }
542
543 if (tag1 & FT_POINT_TAG_ON_CURVE) != 0 {
544 sink.quadratic_curve_to(point0, point1);
545 break;
546 }
547
548 let point_half = point0.lerp(point1, 0.5);
551 sink.quadratic_curve_to(point0, point_half);
552 point0 = point1;
553 }
554 }
555 sink.close();
556 }
557
558 if hinting.grid_fitting_size().is_some() {
559 reset_freetype_face_char_size(self.freetype_face)
560 }
561 }
562
563 return Ok(());
564
565 fn get_point(
566 current_point_index: &mut usize,
567 point_positions: &[FT_Vector],
568 point_tags: &[c_char],
569 last_point_index_in_contour: usize,
570 grid_fitting_size: Option<f32>,
571 units_per_em: u16,
572 ) -> (Vector2F, c_char) {
573 assert!(*current_point_index <= last_point_index_in_contour);
574 let point_position = point_positions[*current_point_index];
575 let point_tag = point_tags[*current_point_index];
576 *current_point_index += 1;
577
578 let point_position = Vector2I::new(point_position.x as i32, point_position.y as i32);
579 let mut point_position = point_position.ft_fixed_26_6_to_f32();
580 if let Some(grid_fitting_size) = grid_fitting_size {
581 point_position = point_position * (units_per_em as f32) / grid_fitting_size;
582 }
583
584 (point_position, point_tag)
585 }
586 }
587
588 pub fn typographic_bounds(&self, glyph_id: u32) -> Result<RectF, GlyphLoadingError> {
590 unsafe {
591 if FT_Load_Glyph(
592 self.freetype_face,
593 glyph_id,
594 FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING,
595 ) != 0
596 {
597 return Err(GlyphLoadingError::NoSuchGlyph);
598 }
599
600 let metrics = &(*(*self.freetype_face).glyph).metrics;
601 let rect = RectI::new(
602 Vector2I::new(
603 metrics.horiBearingX as i32,
604 (metrics.horiBearingY - metrics.height) as i32,
605 ),
606 Vector2I::new(metrics.width as i32, metrics.height as i32),
607 );
608 Ok(rect.ft_fixed_26_6_to_f32())
609 }
610 }
611
612 pub fn advance(&self, glyph_id: u32) -> Result<Vector2F, GlyphLoadingError> {
615 unsafe {
616 if FT_Load_Glyph(
617 self.freetype_face,
618 glyph_id,
619 FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING,
620 ) != 0
621 {
622 return Err(GlyphLoadingError::NoSuchGlyph);
623 }
624
625 let advance = (*(*self.freetype_face).glyph).advance;
626 Ok(Vector2I::new(advance.x as i32, advance.y as i32).ft_fixed_26_6_to_f32())
627 }
628 }
629
630 pub fn origin(&self, _: u32) -> Result<Vector2F, GlyphLoadingError> {
634 warn!("unimplemented");
635 Ok(Vector2F::default())
636 }
637
638 pub fn metrics(&self) -> Metrics {
640 let os2_table = self.get_os2_table();
641 unsafe {
642 let ascender = (*self.freetype_face).ascender;
643 let descender = (*self.freetype_face).descender;
644 let underline_position = (*self.freetype_face).underline_position;
645 let underline_thickness = (*self.freetype_face).underline_thickness;
646
647 let bbox = (*self.freetype_face).bbox;
648 let bounding_box_origin = Vector2I::new(bbox.xMin as i32, bbox.yMin as i32);
649 let bounding_box_lower_right = Vector2I::new(bbox.xMax as i32, bbox.yMax as i32);
650 let bounding_box = RectI::from_points(bounding_box_origin, bounding_box_lower_right);
651
652 Metrics {
653 units_per_em: (*self.freetype_face).units_per_EM as u32,
654 ascent: ascender as f32,
655 descent: descender as f32,
656 line_gap: ((*self.freetype_face).height + descender - ascender) as f32,
657 underline_position: (underline_position + underline_thickness / 2) as f32,
658 underline_thickness: underline_thickness as f32,
659 cap_height: os2_table
660 .map(|table| (*table).sCapHeight as f32)
661 .unwrap_or(0.0),
662 x_height: os2_table
663 .map(|table| (*table).sxHeight as f32)
664 .unwrap_or(0.0),
665 bounding_box: bounding_box.to_f32(),
666 }
667 }
668 }
669
670 #[inline]
677 pub fn supports_hinting_options(
678 &self,
679 hinting_options: HintingOptions,
680 for_rasterization: bool,
681 ) -> bool {
682 match (hinting_options, for_rasterization) {
683 (HintingOptions::None, _)
684 | (HintingOptions::Vertical(_), true)
685 | (HintingOptions::VerticalSubpixel(_), true)
686 | (HintingOptions::Full(_), true) => true,
687 (HintingOptions::Vertical(_), false)
688 | (HintingOptions::VerticalSubpixel(_), false)
689 | (HintingOptions::Full(_), false) => false,
690 }
691 }
692
693 fn get_type_1_or_sfnt_name(&self, type_1_id: u32, sfnt_id: u16) -> Option<String> {
694 unsafe {
695 let ps_value_size =
696 FT_Get_PS_Font_Value(self.freetype_face, type_1_id, 0, ptr::null_mut(), 0);
697 if ps_value_size > 0 {
698 let mut buffer = vec![0; ps_value_size as usize];
699 if FT_Get_PS_Font_Value(
700 self.freetype_face,
701 type_1_id,
702 0,
703 buffer.as_mut_ptr() as *mut c_void,
704 buffer.len() as FT_Long,
705 ) == 0
706 {
707 return String::from_utf8(buffer).ok();
708 }
709 }
710
711 let sfnt_name_count = FT_Get_Sfnt_Name_Count(self.freetype_face);
712 let mut sfnt_name = mem::zeroed();
713 for sfnt_name_index in 0..sfnt_name_count {
714 assert_eq!(
715 FT_Get_Sfnt_Name(self.freetype_face, sfnt_name_index, &mut sfnt_name),
716 0
717 );
718 if sfnt_name.name_id != sfnt_id {
719 continue;
720 }
721
722 match (sfnt_name.platform_id, sfnt_name.encoding_id) {
723 (TT_PLATFORM_APPLE_UNICODE, _) => {
724 let mut sfnt_name_bytes =
725 slice::from_raw_parts(sfnt_name.string, sfnt_name.string_len as usize);
726 let mut sfnt_name_string = Vec::with_capacity(sfnt_name_bytes.len() / 2);
727 while !sfnt_name_bytes.is_empty() {
728 sfnt_name_string.push(sfnt_name_bytes.read_u16::<BigEndian>().unwrap())
729 }
730 if let Ok(result) = String::from_utf16(&sfnt_name_string) {
731 return Some(result);
732 }
733 }
734 (platform_id, _) => {
735 warn!(
736 "get_type_1_or_sfnt_name(): found invalid platform ID {}",
737 platform_id
738 );
739 }
741 }
742 }
743
744 None
745 }
746 }
747
748 fn get_os2_table(&self) -> Option<*const TT_OS2> {
749 unsafe {
750 let table = FT_Get_Sfnt_Table(self.freetype_face, ft_sfnt_os2);
751 if table.is_null() {
752 None
753 } else {
754 Some(table as *const TT_OS2)
755 }
756 }
757 }
758
759 #[inline]
762 pub fn raster_bounds(
763 &self,
764 glyph_id: u32,
765 point_size: f32,
766 transform: Transform2F,
767 hinting_options: HintingOptions,
768 rasterization_options: RasterizationOptions,
769 ) -> Result<RectI, GlyphLoadingError> {
770 <Self as Loader>::raster_bounds(
771 self,
772 glyph_id,
773 point_size,
774 transform,
775 hinting_options,
776 rasterization_options,
777 )
778 }
779
780 pub fn rasterize_glyph(
790 &self,
791 canvas: &mut Canvas,
792 glyph_id: u32,
793 point_size: f32,
794 transform: Transform2F,
795 hinting_options: HintingOptions,
796 rasterization_options: RasterizationOptions,
797 ) -> Result<(), GlyphLoadingError> {
798 unsafe {
801 let matrix = transform.matrix.0 * F32x4::new(65536.0, -65536.0, -65536.0, 65536.0);
802 let matrix = matrix.to_i32x4();
803 let vector = transform.vector.f32_to_ft_fixed_26_6();
804
805 let mut delta = FT_Vector {
806 x: vector.x() as FT_Pos,
807 y: -vector.y() as FT_Pos,
808 };
809 let mut ft_shape = FT_Matrix {
810 xx: matrix.x() as FT_Fixed,
811 xy: matrix.y() as FT_Fixed,
812 yx: matrix.z() as FT_Fixed,
813 yy: matrix.w() as FT_Fixed,
814 };
815 FT_Set_Transform(self.freetype_face, &mut ft_shape, &mut delta);
816
817 assert_eq!(
818 FT_Set_Char_Size(
819 self.freetype_face,
820 point_size.f32_to_ft_fixed_26_6(),
821 0,
822 0,
823 0
824 ),
825 0
826 );
827
828 let mut load_flags = FT_LOAD_DEFAULT | FT_LOAD_RENDER;
829 load_flags |= self.hinting_and_rasterization_options_to_load_flags(
830 hinting_options,
831 rasterization_options,
832 );
833 if FT_Load_Glyph(self.freetype_face, glyph_id, load_flags) != 0 {
834 return Err(GlyphLoadingError::NoSuchGlyph);
835 }
836
837 let bitmap = &(*(*self.freetype_face).glyph).bitmap;
841 let bitmap_stride = bitmap.pitch as usize;
842 let bitmap_width = bitmap.width;
843 let bitmap_height = bitmap.rows;
844 let bitmap_size = Vector2I::new(bitmap_width, bitmap_height);
845 let bitmap_buffer = bitmap.buffer as *const i8 as *const u8;
846 let bitmap_length = bitmap_stride * bitmap_height as usize;
847 if bitmap_buffer.is_null() {
848 assert_eq!(
849 bitmap_length, 0,
850 "bitmap length should be 0 when bitmap_buffer is nullptr"
851 );
852 } else {
853 let buffer = slice::from_raw_parts(bitmap_buffer, bitmap_length);
854 let dst_point = Vector2I::new(
855 (*(*self.freetype_face).glyph).bitmap_left,
856 -(*(*self.freetype_face).glyph).bitmap_top,
857 );
858
859 match bitmap.pixel_mode as u32 {
861 FT_PIXEL_MODE_GRAY => {
862 canvas.blit_from(dst_point, buffer, bitmap_size, bitmap_stride, Format::A8);
863 }
864 FT_PIXEL_MODE_LCD | FT_PIXEL_MODE_LCD_V => {
865 canvas.blit_from(
866 dst_point,
867 buffer,
868 bitmap_size,
869 bitmap_stride,
870 Format::Rgb24,
871 );
872 }
873 FT_PIXEL_MODE_MONO => {
874 canvas.blit_from_bitmap_1bpp(dst_point, buffer, bitmap_size, bitmap_stride);
875 }
876 _ => panic!("Unexpected FreeType pixel mode!"),
877 }
878 }
879
880 FT_Set_Transform(self.freetype_face, ptr::null_mut(), ptr::null_mut());
881 reset_freetype_face_char_size(self.freetype_face);
882 Ok(())
883 }
884 }
885
886 fn hinting_and_rasterization_options_to_load_flags(
887 &self,
888 hinting: HintingOptions,
889 rasterization: RasterizationOptions,
890 ) -> i32 {
891 let mut options = match (hinting, rasterization) {
892 (HintingOptions::VerticalSubpixel(_), _) | (_, RasterizationOptions::SubpixelAa) => {
893 FT_LOAD_TARGET_LCD
894 }
895 (HintingOptions::None, _) => FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING,
896 (HintingOptions::Vertical(_), RasterizationOptions::Bilevel)
897 | (HintingOptions::Full(_), RasterizationOptions::Bilevel) => FT_LOAD_TARGET_MONO,
898 (HintingOptions::Vertical(_), _) => FT_LOAD_TARGET_LIGHT,
899 (HintingOptions::Full(_), _) => FT_LOAD_TARGET_NORMAL,
900 };
901 if rasterization == RasterizationOptions::Bilevel {
902 options |= FT_LOAD_MONOCHROME
903 }
904 options
905 }
906
907 #[inline]
911 pub fn handle(&self) -> Option<Handle> {
912 <Self as Loader>::handle(self)
913 }
914
915 pub fn copy_font_data(&self) -> Option<Arc<Vec<u8>>> {
920 Some(self.font_data.clone())
921 }
922
923 fn get_fallbacks(&self, text: &str, _locale: &str) -> FallbackResult<Font> {
929 warn!("unsupported");
930 FallbackResult {
931 fonts: Vec::new(),
932 valid_len: text.len(),
933 }
934 }
935
936 pub fn load_font_table(&self, table_tag: u32) -> Option<Box<[u8]>> {
942 unsafe {
943 let mut len = 0;
944
945 if 0 != FT_Load_Sfnt_Table(
946 self.freetype_face,
947 table_tag as FT_ULong,
948 0,
949 ptr::null_mut(),
950 &mut len,
951 ) {
952 return None;
953 }
954
955 let mut buf = Box::<[u8]>::from(vec![0; len as usize]);
956 if 0 != FT_Load_Sfnt_Table(
957 self.freetype_face,
958 table_tag as FT_ULong,
959 0,
960 buf.as_mut_ptr() as *mut FT_Byte,
961 &mut len,
962 ) {
963 return None;
964 }
965
966 Some(buf)
967 }
968 }
969}
970
971impl Clone for Font {
972 fn clone(&self) -> Font {
973 unsafe {
974 assert_eq!(FT_Reference_Face(self.freetype_face), 0);
975 Font {
976 freetype_face: self.freetype_face,
977 font_data: self.font_data.clone(),
978 }
979 }
980 }
981}
982
983impl Drop for Font {
984 fn drop(&mut self) {
985 let _ = FREETYPE_LIBRARY.try_with(|freetype_library| unsafe {
989 if !freetype_library.0.is_null() && !self.freetype_face.is_null() {
990 assert_eq!(FT_Done_Face(self.freetype_face), 0);
991 }
992 });
993 }
994}
995
996impl Debug for Font {
997 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
998 self.family_name().fmt(fmt)
999 }
1000}
1001
1002impl Loader for Font {
1003 type NativeFont = NativeFont;
1004
1005 #[inline]
1006 fn from_bytes(font_data: Arc<Vec<u8>>, font_index: u32) -> Result<Self, FontLoadingError> {
1007 Font::from_bytes(font_data, font_index)
1008 }
1009
1010 #[inline]
1011 #[cfg(not(target_arch = "wasm32"))]
1012 fn from_file(file: &mut File, font_index: u32) -> Result<Font, FontLoadingError> {
1013 Font::from_file(file, font_index)
1014 }
1015
1016 #[inline]
1017 fn analyze_bytes(font_data: Arc<Vec<u8>>) -> Result<FileType, FontLoadingError> {
1018 Font::analyze_bytes(font_data)
1019 }
1020
1021 #[cfg(not(target_arch = "wasm32"))]
1022 fn analyze_file(file: &mut File) -> Result<FileType, FontLoadingError> {
1023 Font::analyze_file(file)
1024 }
1025
1026 #[inline]
1027 fn native_font(&self) -> Self::NativeFont {
1028 self.native_font()
1029 }
1030
1031 #[inline]
1032 unsafe fn from_native_font(native_font: &Self::NativeFont) -> Self {
1033 Font::from_native_font(native_font)
1034 }
1035
1036 #[inline]
1037 fn postscript_name(&self) -> Option<String> {
1038 self.postscript_name()
1039 }
1040
1041 #[inline]
1042 fn full_name(&self) -> String {
1043 self.full_name()
1044 }
1045
1046 #[inline]
1047 fn family_name(&self) -> String {
1048 self.family_name()
1049 }
1050
1051 #[inline]
1052 fn is_monospace(&self) -> bool {
1053 self.is_monospace()
1054 }
1055
1056 #[inline]
1057 fn properties(&self) -> Properties {
1058 self.properties()
1059 }
1060
1061 #[inline]
1062 fn glyph_for_char(&self, character: char) -> Option<u32> {
1063 self.glyph_for_char(character)
1064 }
1065
1066 #[inline]
1067 fn glyph_by_name(&self, name: &str) -> Option<u32> {
1068 self.glyph_by_name(name)
1069 }
1070
1071 #[inline]
1072 fn glyph_count(&self) -> u32 {
1073 self.glyph_count()
1074 }
1075
1076 #[inline]
1077 fn outline<S>(
1078 &self,
1079 glyph_id: u32,
1080 hinting_mode: HintingOptions,
1081 sink: &mut S,
1082 ) -> Result<(), GlyphLoadingError>
1083 where
1084 S: OutlineSink,
1085 {
1086 self.outline(glyph_id, hinting_mode, sink)
1087 }
1088
1089 #[inline]
1090 fn typographic_bounds(&self, glyph_id: u32) -> Result<RectF, GlyphLoadingError> {
1091 self.typographic_bounds(glyph_id)
1092 }
1093
1094 #[inline]
1095 fn advance(&self, glyph_id: u32) -> Result<Vector2F, GlyphLoadingError> {
1096 self.advance(glyph_id)
1097 }
1098
1099 #[inline]
1100 fn origin(&self, origin: u32) -> Result<Vector2F, GlyphLoadingError> {
1101 self.origin(origin)
1102 }
1103
1104 #[inline]
1105 fn metrics(&self) -> Metrics {
1106 self.metrics()
1107 }
1108
1109 #[inline]
1110 fn copy_font_data(&self) -> Option<Arc<Vec<u8>>> {
1111 self.copy_font_data()
1112 }
1113
1114 #[inline]
1115 fn supports_hinting_options(
1116 &self,
1117 hinting_options: HintingOptions,
1118 for_rasterization: bool,
1119 ) -> bool {
1120 self.supports_hinting_options(hinting_options, for_rasterization)
1121 }
1122
1123 #[inline]
1124 fn rasterize_glyph(
1125 &self,
1126 canvas: &mut Canvas,
1127 glyph_id: u32,
1128 point_size: f32,
1129 transform: Transform2F,
1130 hinting_options: HintingOptions,
1131 rasterization_options: RasterizationOptions,
1132 ) -> Result<(), GlyphLoadingError> {
1133 self.rasterize_glyph(
1134 canvas,
1135 glyph_id,
1136 point_size,
1137 transform,
1138 hinting_options,
1139 rasterization_options,
1140 )
1141 }
1142
1143 #[inline]
1144 fn get_fallbacks(&self, text: &str, locale: &str) -> FallbackResult<Self> {
1145 self.get_fallbacks(text, locale)
1146 }
1147
1148 #[inline]
1149 fn load_font_table(&self, table_tag: u32) -> Option<Box<[u8]>> {
1150 self.load_font_table(table_tag)
1151 }
1152}
1153
1154unsafe fn setup_freetype_face(face: FT_Face) {
1155 reset_freetype_face_char_size(face);
1156}
1157
1158unsafe fn reset_freetype_face_char_size(face: FT_Face) {
1159 let units_per_em = (*face).units_per_EM as i64;
1161 if units_per_em > 0 {
1162 assert_eq!(
1163 FT_Set_Char_Size(face, ((*face).units_per_EM as FT_Long) << 6, 0, 0, 0),
1164 0
1165 );
1166 }
1167}
1168
1169trait F32ToFtFixed {
1170 type Output;
1171 fn f32_to_ft_fixed_26_6(self) -> Self::Output;
1172}
1173
1174trait FtFixedToF32 {
1175 type Output;
1176 fn ft_fixed_26_6_to_f32(self) -> Self::Output;
1177}
1178
1179impl F32ToFtFixed for Vector2F {
1180 type Output = Vector2I;
1181 #[inline]
1182 fn f32_to_ft_fixed_26_6(self) -> Vector2I {
1183 (self * 64.0).to_i32()
1184 }
1185}
1186
1187impl F32ToFtFixed for f32 {
1188 type Output = FT_Fixed;
1189 #[inline]
1190 fn f32_to_ft_fixed_26_6(self) -> FT_Fixed {
1191 (self * 64.0) as FT_Fixed
1192 }
1193}
1194
1195impl FtFixedToF32 for Vector2I {
1196 type Output = Vector2F;
1197 #[inline]
1198 fn ft_fixed_26_6_to_f32(self) -> Vector2F {
1199 (self.to_f32() * (1.0 / 64.0)).round()
1200 }
1201}
1202
1203impl FtFixedToF32 for RectI {
1204 type Output = RectF;
1205 #[inline]
1206 fn ft_fixed_26_6_to_f32(self) -> RectF {
1207 self.to_f32() * (1.0 / 64.0)
1208 }
1209}
1210
1211extern "C" {
1212 fn FT_Get_Font_Format(face: FT_Face) -> *const c_char;
1213 fn FT_Get_BDF_Property(
1214 face: FT_Face,
1215 prop_name: *const c_char,
1216 aproperty: *mut BDF_PropertyRec,
1217 ) -> FT_Error;
1218 fn FT_Get_PS_Font_Value(
1219 face: FT_Face,
1220 key: u32,
1221 idx: FT_UInt,
1222 value: *mut c_void,
1223 value_len: FT_Long,
1224 ) -> FT_Long;
1225 fn FT_Load_Sfnt_Table(
1226 face: FT_Face,
1227 tag: FT_ULong,
1228 offset: FT_Long,
1229 buffer: *mut FT_Byte,
1230 length: *mut FT_ULong,
1231 ) -> FT_Error;
1232}
1233
1234#[cfg(test)]
1235mod test {
1236 use crate::loaders::freetype::Font;
1237
1238 static PCF_FONT_PATH: &str = "resources/tests/times-roman-pcf/timR12.pcf";
1239 static PCF_FONT_POSTSCRIPT_NAME: &str = "Times-Roman";
1240
1241 #[test]
1242 fn get_pcf_postscript_name() {
1243 let font = Font::from_path(PCF_FONT_PATH, 0).unwrap();
1244 assert_eq!(font.postscript_name().unwrap(), PCF_FONT_POSTSCRIPT_NAME);
1245 }
1246}