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