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