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;
843 let bitmap_height = bitmap.rows;
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 let bitmap_size = Vector2I::new(bitmap_width, bitmap_height);
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 let bitmap_size = Vector2I::new(bitmap_width / 3, bitmap_height);
867 canvas.blit_from(
868 dst_point,
869 buffer,
870 bitmap_size,
871 bitmap_stride,
872 Format::Rgb24,
873 );
874 }
875 FT_PIXEL_MODE_MONO => {
876 let bitmap_size = Vector2I::new(bitmap_width, bitmap_height);
877 canvas.blit_from_bitmap_1bpp(dst_point, buffer, bitmap_size, bitmap_stride);
878 }
879 _ => panic!("Unexpected FreeType pixel mode!"),
880 }
881 }
882
883 FT_Set_Transform(self.freetype_face, ptr::null_mut(), ptr::null_mut());
884 reset_freetype_face_char_size(self.freetype_face);
885 Ok(())
886 }
887 }
888
889 fn hinting_and_rasterization_options_to_load_flags(
890 &self,
891 hinting: HintingOptions,
892 rasterization: RasterizationOptions,
893 ) -> i32 {
894 let mut options = match (hinting, rasterization) {
895 (HintingOptions::VerticalSubpixel(_), _) | (_, RasterizationOptions::SubpixelAa) => {
896 FT_LOAD_TARGET_LCD
897 }
898 (HintingOptions::None, _) => FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING,
899 (HintingOptions::Vertical(_), RasterizationOptions::Bilevel)
900 | (HintingOptions::Full(_), RasterizationOptions::Bilevel) => FT_LOAD_TARGET_MONO,
901 (HintingOptions::Vertical(_), _) => FT_LOAD_TARGET_LIGHT,
902 (HintingOptions::Full(_), _) => FT_LOAD_TARGET_NORMAL,
903 };
904 if rasterization == RasterizationOptions::Bilevel {
905 options |= FT_LOAD_MONOCHROME
906 }
907 options
908 }
909
910 #[inline]
914 pub fn handle(&self) -> Option<Handle> {
915 <Self as Loader>::handle(self)
916 }
917
918 pub fn copy_font_data(&self) -> Option<Arc<Vec<u8>>> {
923 Some(self.font_data.clone())
924 }
925
926 fn get_fallbacks(&self, text: &str, _locale: &str) -> FallbackResult<Font> {
932 warn!("unsupported");
933 FallbackResult {
934 fonts: Vec::new(),
935 valid_len: text.len(),
936 }
937 }
938
939 pub fn load_font_table(&self, table_tag: u32) -> Option<Box<[u8]>> {
945 unsafe {
946 let mut len = 0;
947
948 if 0 != FT_Load_Sfnt_Table(
949 self.freetype_face,
950 table_tag as FT_ULong,
951 0,
952 ptr::null_mut(),
953 &mut len,
954 ) {
955 return None;
956 }
957
958 let mut buf = Box::<[u8]>::from(vec![0; len as usize]);
959 if 0 != FT_Load_Sfnt_Table(
960 self.freetype_face,
961 table_tag as FT_ULong,
962 0,
963 buf.as_mut_ptr() as *mut FT_Byte,
964 &mut len,
965 ) {
966 return None;
967 }
968
969 Some(buf)
970 }
971 }
972}
973
974impl Clone for Font {
975 fn clone(&self) -> Font {
976 unsafe {
977 assert_eq!(FT_Reference_Face(self.freetype_face), 0);
978 Font {
979 freetype_face: self.freetype_face,
980 font_data: self.font_data.clone(),
981 }
982 }
983 }
984}
985
986impl Drop for Font {
987 fn drop(&mut self) {
988 let _ = FREETYPE_LIBRARY.try_with(|freetype_library| unsafe {
992 if !freetype_library.0.is_null() && !self.freetype_face.is_null() {
993 assert_eq!(FT_Done_Face(self.freetype_face), 0);
994 }
995 });
996 }
997}
998
999impl Debug for Font {
1000 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
1001 self.family_name().fmt(fmt)
1002 }
1003}
1004
1005impl Loader for Font {
1006 type NativeFont = NativeFont;
1007
1008 #[inline]
1009 fn from_bytes(font_data: Arc<Vec<u8>>, font_index: u32) -> Result<Self, FontLoadingError> {
1010 Font::from_bytes(font_data, font_index)
1011 }
1012
1013 #[inline]
1014 #[cfg(not(target_arch = "wasm32"))]
1015 fn from_file(file: &mut File, font_index: u32) -> Result<Font, FontLoadingError> {
1016 Font::from_file(file, font_index)
1017 }
1018
1019 #[inline]
1020 fn analyze_bytes(font_data: Arc<Vec<u8>>) -> Result<FileType, FontLoadingError> {
1021 Font::analyze_bytes(font_data)
1022 }
1023
1024 #[cfg(not(target_arch = "wasm32"))]
1025 fn analyze_file(file: &mut File) -> Result<FileType, FontLoadingError> {
1026 Font::analyze_file(file)
1027 }
1028
1029 #[inline]
1030 fn native_font(&self) -> Self::NativeFont {
1031 self.native_font()
1032 }
1033
1034 #[inline]
1035 unsafe fn from_native_font(native_font: Self::NativeFont) -> Self {
1036 Font::from_native_font(native_font)
1037 }
1038
1039 #[inline]
1040 fn postscript_name(&self) -> Option<String> {
1041 self.postscript_name()
1042 }
1043
1044 #[inline]
1045 fn full_name(&self) -> String {
1046 self.full_name()
1047 }
1048
1049 #[inline]
1050 fn family_name(&self) -> String {
1051 self.family_name()
1052 }
1053
1054 #[inline]
1055 fn is_monospace(&self) -> bool {
1056 self.is_monospace()
1057 }
1058
1059 #[inline]
1060 fn properties(&self) -> Properties {
1061 self.properties()
1062 }
1063
1064 #[inline]
1065 fn glyph_for_char(&self, character: char) -> Option<u32> {
1066 self.glyph_for_char(character)
1067 }
1068
1069 #[inline]
1070 fn glyph_by_name(&self, name: &str) -> Option<u32> {
1071 self.glyph_by_name(name)
1072 }
1073
1074 #[inline]
1075 fn glyph_count(&self) -> u32 {
1076 self.glyph_count()
1077 }
1078
1079 #[inline]
1080 fn outline<S>(
1081 &self,
1082 glyph_id: u32,
1083 hinting_mode: HintingOptions,
1084 sink: &mut S,
1085 ) -> Result<(), GlyphLoadingError>
1086 where
1087 S: OutlineSink,
1088 {
1089 self.outline(glyph_id, hinting_mode, sink)
1090 }
1091
1092 #[inline]
1093 fn typographic_bounds(&self, glyph_id: u32) -> Result<RectF, GlyphLoadingError> {
1094 self.typographic_bounds(glyph_id)
1095 }
1096
1097 #[inline]
1098 fn advance(&self, glyph_id: u32) -> Result<Vector2F, GlyphLoadingError> {
1099 self.advance(glyph_id)
1100 }
1101
1102 #[inline]
1103 fn origin(&self, origin: u32) -> Result<Vector2F, GlyphLoadingError> {
1104 self.origin(origin)
1105 }
1106
1107 #[inline]
1108 fn metrics(&self) -> Metrics {
1109 self.metrics()
1110 }
1111
1112 #[inline]
1113 fn copy_font_data(&self) -> Option<Arc<Vec<u8>>> {
1114 self.copy_font_data()
1115 }
1116
1117 #[inline]
1118 fn supports_hinting_options(
1119 &self,
1120 hinting_options: HintingOptions,
1121 for_rasterization: bool,
1122 ) -> bool {
1123 self.supports_hinting_options(hinting_options, for_rasterization)
1124 }
1125
1126 #[inline]
1127 fn rasterize_glyph(
1128 &self,
1129 canvas: &mut Canvas,
1130 glyph_id: u32,
1131 point_size: f32,
1132 transform: Transform2F,
1133 hinting_options: HintingOptions,
1134 rasterization_options: RasterizationOptions,
1135 ) -> Result<(), GlyphLoadingError> {
1136 self.rasterize_glyph(
1137 canvas,
1138 glyph_id,
1139 point_size,
1140 transform,
1141 hinting_options,
1142 rasterization_options,
1143 )
1144 }
1145
1146 #[inline]
1147 fn get_fallbacks(&self, text: &str, locale: &str) -> FallbackResult<Self> {
1148 self.get_fallbacks(text, locale)
1149 }
1150
1151 #[inline]
1152 fn load_font_table(&self, table_tag: u32) -> Option<Box<[u8]>> {
1153 self.load_font_table(table_tag)
1154 }
1155}
1156
1157unsafe fn setup_freetype_face(face: FT_Face) {
1158 reset_freetype_face_char_size(face);
1159}
1160
1161unsafe fn reset_freetype_face_char_size(face: FT_Face) {
1162 let units_per_em = (*face).units_per_EM as i64;
1164 if units_per_em > 0 {
1165 assert_eq!(
1166 FT_Set_Char_Size(face, ((*face).units_per_EM as FT_Long) << 6, 0, 0, 0),
1167 0
1168 );
1169 }
1170}
1171
1172trait F32ToFtFixed {
1173 type Output;
1174 fn f32_to_ft_fixed_26_6(self) -> Self::Output;
1175}
1176
1177trait FtFixedToF32 {
1178 type Output;
1179 fn ft_fixed_26_6_to_f32(self) -> Self::Output;
1180}
1181
1182impl F32ToFtFixed for Vector2F {
1183 type Output = Vector2I;
1184 #[inline]
1185 fn f32_to_ft_fixed_26_6(self) -> Vector2I {
1186 (self * 64.0).to_i32()
1187 }
1188}
1189
1190impl F32ToFtFixed for f32 {
1191 type Output = FT_Fixed;
1192 #[inline]
1193 fn f32_to_ft_fixed_26_6(self) -> FT_Fixed {
1194 (self * 64.0) as FT_Fixed
1195 }
1196}
1197
1198impl FtFixedToF32 for Vector2I {
1199 type Output = Vector2F;
1200 #[inline]
1201 fn ft_fixed_26_6_to_f32(self) -> Vector2F {
1202 (self.to_f32() * (1.0 / 64.0)).round()
1203 }
1204}
1205
1206impl FtFixedToF32 for RectI {
1207 type Output = RectF;
1208 #[inline]
1209 fn ft_fixed_26_6_to_f32(self) -> RectF {
1210 self.to_f32() * (1.0 / 64.0)
1211 }
1212}
1213
1214extern "C" {
1215 fn FT_Get_Font_Format(face: FT_Face) -> *const c_char;
1216 fn FT_Get_BDF_Property(
1217 face: FT_Face,
1218 prop_name: *const c_char,
1219 aproperty: *mut BDF_PropertyRec,
1220 ) -> FT_Error;
1221 fn FT_Get_PS_Font_Value(
1222 face: FT_Face,
1223 key: u32,
1224 idx: FT_UInt,
1225 value: *mut c_void,
1226 value_len: FT_Long,
1227 ) -> FT_Long;
1228 fn FT_Load_Sfnt_Table(
1229 face: FT_Face,
1230 tag: FT_ULong,
1231 offset: FT_Long,
1232 buffer: *mut FT_Byte,
1233 length: *mut FT_ULong,
1234 ) -> FT_Error;
1235}
1236
1237#[cfg(test)]
1238mod test {
1239 use crate::loaders::freetype::Font;
1240
1241 static PCF_FONT_PATH: &str = "resources/tests/times-roman-pcf/timR12.pcf";
1242 static PCF_FONT_POSTSCRIPT_NAME: &str = "Times-Roman";
1243
1244 #[test]
1245 fn get_pcf_postscript_name() {
1246 let font = Font::from_path(PCF_FONT_PATH, 0).unwrap();
1247 assert_eq!(font.postscript_name().unwrap(), PCF_FONT_POSTSCRIPT_NAME);
1248 }
1249}