1#![no_std]
36#![forbid(unsafe_code)]
37#![warn(missing_docs)]
38#![warn(missing_copy_implementations)]
39#![warn(missing_debug_implementations)]
40#![allow(clippy::get_first)] #![allow(clippy::identity_op)] #![allow(clippy::too_many_arguments)]
43#![allow(clippy::collapsible_else_if)]
44#![allow(clippy::field_reassign_with_default)]
45#![allow(clippy::upper_case_acronyms)]
46#![allow(clippy::bool_assert_comparison)]
47
48#[cfg(feature = "std")]
49#[macro_use]
50extern crate std;
51
52#[cfg(not(any(feature = "std", feature = "no-std-float")))]
53compile_error!("You have to activate either the `std` or the `no-std-float` feature.");
54
55#[cfg(not(feature = "std"))]
56use core_maths::CoreFloat;
57
58#[cfg(feature = "apple-layout")]
59mod aat;
60#[cfg(feature = "variable-fonts")]
61mod delta_set;
62#[cfg(feature = "opentype-layout")]
63mod ggg;
64mod language;
65mod parser;
66mod tables;
67#[cfg(feature = "variable-fonts")]
68mod var_store;
69
70use head::IndexToLocationFormat;
71pub use parser::{Fixed, FromData, LazyArray16, LazyArray32, LazyArrayIter16, LazyArrayIter32};
72use parser::{NumFrom, Offset, Offset32, Stream, TryNumFrom};
73
74#[cfg(feature = "variable-fonts")]
75pub use fvar::VariationAxis;
76
77pub use language::Language;
78pub use name::{name_id, PlatformId};
79pub use os2::{Permissions, ScriptMetrics, Style, UnicodeRanges, Weight, Width};
80pub use tables::CFFError;
81#[cfg(feature = "apple-layout")]
82pub use tables::{ankr, feat, kerx, morx, trak};
83#[cfg(feature = "variable-fonts")]
84pub use tables::{avar, cff2, fvar, gvar, hvar, mvar, vvar};
85pub use tables::{cbdt, cblc, cff1 as cff, vhea};
86pub use tables::{
87 cmap, colr, cpal, glyf, head, hhea, hmtx, kern, loca, maxp, name, os2, post, sbix, stat, svg,
88 vorg,
89};
90#[cfg(feature = "opentype-layout")]
91pub use tables::{gdef, gpos, gsub, math};
92
93#[cfg(feature = "opentype-layout")]
94pub mod opentype_layout {
95 pub use crate::ggg::*;
99}
100
101#[cfg(feature = "apple-layout")]
102pub mod apple_layout {
103 pub use crate::aat::*;
108}
109
110#[repr(transparent)]
112#[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Default, Debug, Hash)]
113pub struct GlyphId(pub u16);
114
115impl FromData for GlyphId {
116 const SIZE: usize = 2;
117
118 #[inline]
119 fn parse(data: &[u8]) -> Option<Self> {
120 u16::parse(data).map(GlyphId)
121 }
122}
123
124#[derive(Clone, Copy, PartialEq, Debug)]
128enum Magic {
129 TrueType,
130 OpenType,
131 FontCollection,
132}
133
134impl FromData for Magic {
135 const SIZE: usize = 4;
136
137 #[inline]
138 fn parse(data: &[u8]) -> Option<Self> {
139 match u32::parse(data)? {
140 0x00010000 | 0x74727565 => Some(Magic::TrueType),
141 0x4F54544F => Some(Magic::OpenType),
142 0x74746366 => Some(Magic::FontCollection),
143 _ => None,
144 }
145 }
146}
147
148#[repr(transparent)]
155#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
156pub struct NormalizedCoordinate(i16);
157
158impl From<i16> for NormalizedCoordinate {
159 #[inline]
163 fn from(n: i16) -> Self {
164 NormalizedCoordinate(parser::i16_bound(-16384, n, 16384))
165 }
166}
167
168impl From<f32> for NormalizedCoordinate {
169 #[inline]
173 fn from(n: f32) -> Self {
174 NormalizedCoordinate((parser::f32_bound(-1.0, n, 1.0) * 16384.0) as i16)
175 }
176}
177
178impl NormalizedCoordinate {
179 #[inline]
181 pub fn get(self) -> i16 {
182 self.0
183 }
184}
185
186#[derive(Clone, Copy, PartialEq, Debug)]
196pub struct Variation {
197 pub axis: Tag,
199 pub value: f32,
201}
202
203#[repr(transparent)]
205#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
206pub struct Tag(pub u32);
207
208impl Tag {
209 #[inline]
217 pub const fn from_bytes(bytes: &[u8; 4]) -> Self {
218 Tag(((bytes[0] as u32) << 24)
219 | ((bytes[1] as u32) << 16)
220 | ((bytes[2] as u32) << 8)
221 | (bytes[3] as u32))
222 }
223
224 #[inline]
232 pub fn from_bytes_lossy(bytes: &[u8]) -> Self {
233 if bytes.is_empty() {
234 return Tag::from_bytes(&[0, 0, 0, 0]);
235 }
236
237 let mut iter = bytes.iter().cloned().chain(core::iter::repeat(b' '));
238 Tag::from_bytes(&[
239 iter.next().unwrap(),
240 iter.next().unwrap(),
241 iter.next().unwrap(),
242 iter.next().unwrap(),
243 ])
244 }
245
246 #[inline]
248 pub const fn to_bytes(self) -> [u8; 4] {
249 [
250 (self.0 >> 24 & 0xff) as u8,
251 (self.0 >> 16 & 0xff) as u8,
252 (self.0 >> 8 & 0xff) as u8,
253 (self.0 >> 0 & 0xff) as u8,
254 ]
255 }
256
257 #[inline]
259 pub const fn to_chars(self) -> [char; 4] {
260 [
261 (self.0 >> 24 & 0xff) as u8 as char,
262 (self.0 >> 16 & 0xff) as u8 as char,
263 (self.0 >> 8 & 0xff) as u8 as char,
264 (self.0 >> 0 & 0xff) as u8 as char,
265 ]
266 }
267
268 #[inline]
270 pub const fn is_null(&self) -> bool {
271 self.0 == 0
272 }
273
274 #[inline]
276 pub const fn as_u32(&self) -> u32 {
277 self.0
278 }
279}
280
281impl core::fmt::Debug for Tag {
282 #[inline]
283 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
284 write!(f, "Tag({})", self)
285 }
286}
287
288impl core::fmt::Display for Tag {
289 #[inline]
290 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
291 let b = self.to_chars();
292 write!(
293 f,
294 "{}{}{}{}",
295 b.get(0).unwrap_or(&' '),
296 b.get(1).unwrap_or(&' '),
297 b.get(2).unwrap_or(&' '),
298 b.get(3).unwrap_or(&' ')
299 )
300 }
301}
302
303impl FromData for Tag {
304 const SIZE: usize = 4;
305
306 #[inline]
307 fn parse(data: &[u8]) -> Option<Self> {
308 u32::parse(data).map(Tag)
309 }
310}
311
312#[repr(C)]
316#[derive(Clone, Copy, PartialEq, Eq, Debug)]
317pub struct LineMetrics {
318 pub position: i16,
320
321 pub thickness: i16,
323}
324
325#[repr(C)]
329#[allow(missing_docs)]
330#[derive(Clone, Copy, PartialEq, Eq, Debug)]
331pub struct Rect {
332 pub x_min: i16,
333 pub y_min: i16,
334 pub x_max: i16,
335 pub y_max: i16,
336}
337
338impl Rect {
339 #[inline]
340 fn zero() -> Self {
341 Self {
342 x_min: 0,
343 y_min: 0,
344 x_max: 0,
345 y_max: 0,
346 }
347 }
348
349 #[inline]
351 pub fn width(&self) -> i16 {
352 self.x_max - self.x_min
353 }
354
355 #[inline]
357 pub fn height(&self) -> i16 {
358 self.y_max - self.y_min
359 }
360}
361
362#[derive(Clone, Copy, Debug, PartialEq)]
364pub struct RectF {
365 pub x_min: f32,
367 pub y_min: f32,
369 pub x_max: f32,
371 pub y_max: f32,
373}
374
375impl RectF {
376 #[inline]
377 fn new() -> Self {
378 RectF {
379 x_min: f32::MAX,
380 y_min: f32::MAX,
381 x_max: f32::MIN,
382 y_max: f32::MIN,
383 }
384 }
385
386 #[inline]
387 fn is_default(&self) -> bool {
388 self.x_min == f32::MAX
389 && self.y_min == f32::MAX
390 && self.x_max == f32::MIN
391 && self.y_max == f32::MIN
392 }
393
394 #[inline]
395 fn extend_by(&mut self, x: f32, y: f32) {
396 self.x_min = self.x_min.min(x);
397 self.y_min = self.y_min.min(y);
398 self.x_max = self.x_max.max(x);
399 self.y_max = self.y_max.max(y);
400 }
401
402 #[inline]
403 fn to_rect(self) -> Option<Rect> {
404 Some(Rect {
405 x_min: i16::try_num_from(self.x_min)?,
406 y_min: i16::try_num_from(self.y_min)?,
407 x_max: i16::try_num_from(self.x_max)?,
408 y_max: i16::try_num_from(self.y_max)?,
409 })
410 }
411}
412
413#[derive(Clone, Copy, PartialEq)]
415pub struct Transform {
416 pub a: f32,
418 pub b: f32,
420 pub c: f32,
422 pub d: f32,
424 pub e: f32,
426 pub f: f32,
428}
429
430impl Transform {
431 #[inline]
433 pub fn new(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) -> Self {
434 Transform { a, b, c, d, e, f }
435 }
436
437 #[inline]
439 pub fn new_translate(tx: f32, ty: f32) -> Self {
440 Transform::new(1.0, 0.0, 0.0, 1.0, tx, ty)
441 }
442
443 #[inline]
445 pub fn new_rotate(angle: f32) -> Self {
446 let cc = (angle * core::f32::consts::PI).cos();
447 let ss = (angle * core::f32::consts::PI).sin();
448
449 Transform::new(cc, ss, -ss, cc, 0.0, 0.0)
450 }
451
452 #[inline]
454 pub fn new_skew(skew_x: f32, skew_y: f32) -> Self {
455 let x = (skew_x * core::f32::consts::PI).tan();
456 let y = (skew_y * core::f32::consts::PI).tan();
457
458 Transform::new(1.0, y, -x, 1.0, 0.0, 0.0)
459 }
460
461 #[inline]
463 pub fn new_scale(sx: f32, sy: f32) -> Self {
464 Transform::new(sx, 0.0, 0.0, sy, 0.0, 0.0)
465 }
466
467 #[inline]
469 pub fn combine(ts1: Self, ts2: Self) -> Self {
470 Transform {
471 a: ts1.a * ts2.a + ts1.c * ts2.b,
472 b: ts1.b * ts2.a + ts1.d * ts2.b,
473 c: ts1.a * ts2.c + ts1.c * ts2.d,
474 d: ts1.b * ts2.c + ts1.d * ts2.d,
475 e: ts1.a * ts2.e + ts1.c * ts2.f + ts1.e,
476 f: ts1.b * ts2.e + ts1.d * ts2.f + ts1.f,
477 }
478 }
479
480 #[inline]
481 fn apply_to(&self, x: &mut f32, y: &mut f32) {
482 let tx = *x;
483 let ty = *y;
484 *x = self.a * tx + self.c * ty + self.e;
485 *y = self.b * tx + self.d * ty + self.f;
486 }
487
488 #[inline]
490 pub fn is_default(&self) -> bool {
491 self.a == 1.0
493 && self.b == 0.0
494 && self.c == 0.0
495 && self.d == 1.0
496 && self.e == 0.0
497 && self.f == 0.0
498 }
499}
500
501impl Default for Transform {
502 #[inline]
503 fn default() -> Self {
504 Transform {
505 a: 1.0,
506 b: 0.0,
507 c: 0.0,
508 d: 1.0,
509 e: 0.0,
510 f: 0.0,
511 }
512 }
513}
514
515impl core::fmt::Debug for Transform {
516 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
517 write!(
518 f,
519 "Transform({} {} {} {} {} {})",
520 self.a, self.b, self.c, self.d, self.e, self.f
521 )
522 }
523}
524
525#[derive(Clone, Copy, Debug)]
527pub struct PointF {
528 pub x: f32,
530 pub y: f32,
532}
533
534#[derive(Clone, Copy, Debug)]
538pub struct PhantomPoints {
539 pub left: PointF,
541 pub right: PointF,
543 pub top: PointF,
545 pub bottom: PointF,
547}
548
549#[allow(missing_docs)]
551#[derive(Clone, Copy, PartialEq, Eq, Debug)]
552pub struct RgbaColor {
553 pub red: u8,
554 pub green: u8,
555 pub blue: u8,
556 pub alpha: u8,
557}
558
559impl RgbaColor {
560 #[inline]
562 pub fn new(red: u8, green: u8, blue: u8, alpha: u8) -> Self {
563 Self {
564 blue,
565 green,
566 red,
567 alpha,
568 }
569 }
570
571 pub(crate) fn apply_alpha(&mut self, alpha: f32) {
572 self.alpha = (((f32::from(self.alpha) / 255.0) * alpha) * 255.0) as u8;
573 }
574}
575
576pub trait OutlineBuilder {
578 fn move_to(&mut self, x: f32, y: f32);
582
583 fn line_to(&mut self, x: f32, y: f32);
585
586 fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32);
588
589 fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32);
591
592 fn close(&mut self);
596}
597
598struct DummyOutline;
599impl OutlineBuilder for DummyOutline {
600 fn move_to(&mut self, _: f32, _: f32) {}
601 fn line_to(&mut self, _: f32, _: f32) {}
602 fn quad_to(&mut self, _: f32, _: f32, _: f32, _: f32) {}
603 fn curve_to(&mut self, _: f32, _: f32, _: f32, _: f32, _: f32, _: f32) {}
604 fn close(&mut self) {}
605}
606
607#[allow(missing_docs)]
609#[derive(Clone, Copy, PartialEq, Eq, Debug)]
610pub enum RasterImageFormat {
611 PNG,
612
613 BitmapMono,
620
621 BitmapMonoPacked,
627
628 BitmapGray2,
634
635 BitmapGray2Packed,
640
641 BitmapGray4,
647
648 BitmapGray4Packed,
653
654 BitmapGray8,
659
660 BitmapPremulBgra32,
668}
669
670#[derive(Clone, Copy, PartialEq, Eq, Debug)]
674pub struct RasterGlyphImage<'a> {
675 pub x: i16,
677
678 pub y: i16,
680
681 pub width: u16,
685
686 pub height: u16,
690
691 pub pixels_per_em: u16,
693
694 pub format: RasterImageFormat,
696
697 pub data: &'a [u8],
699}
700
701#[derive(Clone, Copy, Debug)]
703#[allow(missing_docs)]
704pub struct TableRecord {
705 pub tag: Tag,
706 #[allow(dead_code)]
707 pub check_sum: u32,
708 pub offset: u32,
709 pub length: u32,
710}
711
712impl FromData for TableRecord {
713 const SIZE: usize = 16;
714
715 #[inline]
716 fn parse(data: &[u8]) -> Option<Self> {
717 let mut s = Stream::new(data);
718 Some(TableRecord {
719 tag: s.read::<Tag>()?,
720 check_sum: s.read::<u32>()?,
721 offset: s.read::<u32>()?,
722 length: s.read::<u32>()?,
723 })
724 }
725}
726
727#[cfg(feature = "variable-fonts")]
728const MAX_VAR_COORDS: usize = 64;
729
730#[cfg(feature = "variable-fonts")]
731#[derive(Clone)]
732struct VarCoords {
733 data: [NormalizedCoordinate; MAX_VAR_COORDS],
734 len: u8,
735}
736
737#[cfg(feature = "variable-fonts")]
738impl Default for VarCoords {
739 fn default() -> Self {
740 Self {
741 data: [NormalizedCoordinate::default(); MAX_VAR_COORDS],
742 len: u8::default(),
743 }
744 }
745}
746
747#[cfg(feature = "variable-fonts")]
748impl VarCoords {
749 #[inline]
750 fn as_slice(&self) -> &[NormalizedCoordinate] {
751 &self.data[0..usize::from(self.len)]
752 }
753
754 #[inline]
755 fn as_mut_slice(&mut self) -> &mut [NormalizedCoordinate] {
756 let end = usize::from(self.len);
757 &mut self.data[0..end]
758 }
759}
760
761#[derive(Clone, Copy, PartialEq, Eq, Debug)]
763pub enum FaceParsingError {
764 MalformedFont,
768
769 UnknownMagic,
771
772 FaceIndexOutOfBounds,
774
775 NoHeadTable,
777
778 NoHheaTable,
780
781 NoMaxpTable,
783}
784
785impl core::fmt::Display for FaceParsingError {
786 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
787 match self {
788 FaceParsingError::MalformedFont => write!(f, "malformed font"),
789 FaceParsingError::UnknownMagic => write!(f, "unknown magic"),
790 FaceParsingError::FaceIndexOutOfBounds => write!(f, "face index is out of bounds"),
791 FaceParsingError::NoHeadTable => write!(f, "the head table is missing or malformed"),
792 FaceParsingError::NoHheaTable => write!(f, "the hhea table is missing or malformed"),
793 FaceParsingError::NoMaxpTable => write!(f, "the maxp table is missing or malformed"),
794 }
795 }
796}
797
798#[cfg(feature = "std")]
799impl std::error::Error for FaceParsingError {}
800
801#[derive(Clone, Copy)]
810pub struct RawFace<'a> {
811 pub data: &'a [u8],
813 pub table_records: LazyArray16<'a, TableRecord>,
815}
816
817impl<'a> RawFace<'a> {
818 #[deprecated(since = "0.16.0", note = "use `parse` instead")]
826 pub fn from_slice(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> {
827 Self::parse(data, index)
828 }
829
830 pub fn parse(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> {
838 let mut s = Stream::new(data);
841
842 let magic = s.read::<Magic>().ok_or(FaceParsingError::UnknownMagic)?;
844 if magic == Magic::FontCollection {
845 s.skip::<u32>(); let number_of_faces = s.read::<u32>().ok_or(FaceParsingError::MalformedFont)?;
847 let offsets = s
848 .read_array32::<Offset32>(number_of_faces)
849 .ok_or(FaceParsingError::MalformedFont)?;
850
851 let face_offset = offsets
852 .get(index)
853 .ok_or(FaceParsingError::FaceIndexOutOfBounds)?;
854 let face_offset = face_offset
857 .to_usize()
858 .checked_sub(s.offset())
859 .ok_or(FaceParsingError::MalformedFont)?;
860 s.advance_checked(face_offset)
861 .ok_or(FaceParsingError::MalformedFont)?;
862
863 let magic = s.read::<Magic>().ok_or(FaceParsingError::UnknownMagic)?;
866 if magic == Magic::FontCollection {
868 return Err(FaceParsingError::UnknownMagic);
869 }
870 } else {
871 if index != 0 {
874 return Err(FaceParsingError::FaceIndexOutOfBounds);
875 }
876 }
877
878 let num_tables = s.read::<u16>().ok_or(FaceParsingError::MalformedFont)?;
879 s.advance(6); let table_records = s
881 .read_array16::<TableRecord>(num_tables)
882 .ok_or(FaceParsingError::MalformedFont)?;
883
884 Ok(RawFace {
885 data,
886 table_records,
887 })
888 }
889
890 pub fn table(&self, tag: Tag) -> Option<&'a [u8]> {
892 let (_, table) = self
893 .table_records
894 .binary_search_by(|record| record.tag.cmp(&tag))?;
895 let offset = usize::num_from(table.offset);
896 let length = usize::num_from(table.length);
897 let end = offset.checked_add(length)?;
898 self.data.get(offset..end)
899 }
900}
901
902impl core::fmt::Debug for RawFace<'_> {
903 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
904 write!(f, "RawFace {{ ... }}")
905 }
906}
907
908#[allow(missing_docs)]
916#[allow(missing_debug_implementations)]
917#[derive(Clone, Default)]
918pub struct RawFaceTables<'a> {
919 pub head: &'a [u8],
921 pub hhea: &'a [u8],
922 pub maxp: &'a [u8],
923
924 pub bdat: Option<&'a [u8]>,
925 pub bloc: Option<&'a [u8]>,
926 pub cbdt: Option<&'a [u8]>,
927 pub cblc: Option<&'a [u8]>,
928 pub cff: Option<&'a [u8]>,
929 pub cmap: Option<&'a [u8]>,
930 pub colr: Option<&'a [u8]>,
931 pub cpal: Option<&'a [u8]>,
932 pub ebdt: Option<&'a [u8]>,
933 pub eblc: Option<&'a [u8]>,
934 pub glyf: Option<&'a [u8]>,
935 pub hmtx: Option<&'a [u8]>,
936 pub kern: Option<&'a [u8]>,
937 pub loca: Option<&'a [u8]>,
938 pub name: Option<&'a [u8]>,
939 pub os2: Option<&'a [u8]>,
940 pub post: Option<&'a [u8]>,
941 pub sbix: Option<&'a [u8]>,
942 pub stat: Option<&'a [u8]>,
943 pub svg: Option<&'a [u8]>,
944 pub vhea: Option<&'a [u8]>,
945 pub vmtx: Option<&'a [u8]>,
946 pub vorg: Option<&'a [u8]>,
947
948 #[cfg(feature = "opentype-layout")]
949 pub gdef: Option<&'a [u8]>,
950 #[cfg(feature = "opentype-layout")]
951 pub gpos: Option<&'a [u8]>,
952 #[cfg(feature = "opentype-layout")]
953 pub gsub: Option<&'a [u8]>,
954 #[cfg(feature = "opentype-layout")]
955 pub math: Option<&'a [u8]>,
956
957 #[cfg(feature = "apple-layout")]
958 pub ankr: Option<&'a [u8]>,
959 #[cfg(feature = "apple-layout")]
960 pub feat: Option<&'a [u8]>,
961 #[cfg(feature = "apple-layout")]
962 pub kerx: Option<&'a [u8]>,
963 #[cfg(feature = "apple-layout")]
964 pub morx: Option<&'a [u8]>,
965 #[cfg(feature = "apple-layout")]
966 pub trak: Option<&'a [u8]>,
967
968 #[cfg(feature = "variable-fonts")]
969 pub avar: Option<&'a [u8]>,
970 #[cfg(feature = "variable-fonts")]
971 pub cff2: Option<&'a [u8]>,
972 #[cfg(feature = "variable-fonts")]
973 pub fvar: Option<&'a [u8]>,
974 #[cfg(feature = "variable-fonts")]
975 pub gvar: Option<&'a [u8]>,
976 #[cfg(feature = "variable-fonts")]
977 pub hvar: Option<&'a [u8]>,
978 #[cfg(feature = "variable-fonts")]
979 pub mvar: Option<&'a [u8]>,
980 #[cfg(feature = "variable-fonts")]
981 pub vvar: Option<&'a [u8]>,
982}
983
984#[allow(missing_docs)]
992#[allow(missing_debug_implementations)]
993#[derive(Clone)]
994pub struct FaceTables<'a> {
995 pub head: head::Table,
997 pub hhea: hhea::Table,
998 pub maxp: maxp::Table,
999
1000 pub bdat: Option<cbdt::Table<'a>>,
1001 pub cbdt: Option<cbdt::Table<'a>>,
1002 pub cff: Option<cff::Table<'a>>,
1003 pub cmap: Option<cmap::Table<'a>>,
1004 pub colr: Option<colr::Table<'a>>,
1005 pub ebdt: Option<cbdt::Table<'a>>,
1006 pub glyf: Option<glyf::Table<'a>>,
1007 pub hmtx: Option<hmtx::Table<'a>>,
1008 pub kern: Option<kern::Table<'a>>,
1009 pub name: Option<name::Table<'a>>,
1010 pub os2: Option<os2::Table<'a>>,
1011 pub post: Option<post::Table<'a>>,
1012 pub sbix: Option<sbix::Table<'a>>,
1013 pub stat: Option<stat::Table<'a>>,
1014 pub svg: Option<svg::Table<'a>>,
1015 pub vhea: Option<vhea::Table>,
1016 pub vmtx: Option<hmtx::Table<'a>>,
1017 pub vorg: Option<vorg::Table<'a>>,
1018
1019 #[cfg(feature = "opentype-layout")]
1020 pub gdef: Option<gdef::Table<'a>>,
1021 #[cfg(feature = "opentype-layout")]
1022 pub gpos: Option<opentype_layout::LayoutTable<'a>>,
1023 #[cfg(feature = "opentype-layout")]
1024 pub gsub: Option<opentype_layout::LayoutTable<'a>>,
1025 #[cfg(feature = "opentype-layout")]
1026 pub math: Option<math::Table<'a>>,
1027
1028 #[cfg(feature = "apple-layout")]
1029 pub ankr: Option<ankr::Table<'a>>,
1030 #[cfg(feature = "apple-layout")]
1031 pub feat: Option<feat::Table<'a>>,
1032 #[cfg(feature = "apple-layout")]
1033 pub kerx: Option<kerx::Table<'a>>,
1034 #[cfg(feature = "apple-layout")]
1035 pub morx: Option<morx::Table<'a>>,
1036 #[cfg(feature = "apple-layout")]
1037 pub trak: Option<trak::Table<'a>>,
1038
1039 #[cfg(feature = "variable-fonts")]
1040 pub avar: Option<avar::Table<'a>>,
1041 #[cfg(feature = "variable-fonts")]
1042 pub cff2: Option<cff2::Table<'a>>,
1043 #[cfg(feature = "variable-fonts")]
1044 pub fvar: Option<fvar::Table<'a>>,
1045 #[cfg(feature = "variable-fonts")]
1046 pub gvar: Option<gvar::Table<'a>>,
1047 #[cfg(feature = "variable-fonts")]
1048 pub hvar: Option<hvar::Table<'a>>,
1049 #[cfg(feature = "variable-fonts")]
1050 pub mvar: Option<mvar::Table<'a>>,
1051 #[cfg(feature = "variable-fonts")]
1052 pub vvar: Option<vvar::Table<'a>>,
1053}
1054
1055#[derive(Clone)]
1071pub struct Face<'a> {
1072 raw_face: RawFace<'a>,
1073 tables: FaceTables<'a>, #[cfg(feature = "variable-fonts")]
1075 coordinates: VarCoords,
1076}
1077
1078impl<'a> Face<'a> {
1079 #[deprecated(since = "0.16.0", note = "use `parse` instead")]
1092 pub fn from_slice(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> {
1093 Self::parse(data, index)
1094 }
1095
1096 pub fn parse(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> {
1109 let raw_face = RawFace::parse(data, index)?;
1110 let raw_tables = Self::collect_tables(raw_face);
1111
1112 #[allow(unused_mut)]
1113 let mut face = Face {
1114 raw_face,
1115 #[cfg(feature = "variable-fonts")]
1116 coordinates: VarCoords::default(),
1117 tables: Self::parse_tables(raw_tables)?,
1118 };
1119
1120 #[cfg(feature = "variable-fonts")]
1121 {
1122 if let Some(ref fvar) = face.tables.fvar {
1123 face.coordinates.len = fvar.axes.len().min(MAX_VAR_COORDS as u16) as u8;
1124 }
1125 }
1126
1127 Ok(face)
1128 }
1129
1130 fn collect_tables(raw_face: RawFace<'a>) -> RawFaceTables<'a> {
1131 let mut tables = RawFaceTables::default();
1132
1133 for record in raw_face.table_records {
1134 let start = usize::num_from(record.offset);
1135 let end = match start.checked_add(usize::num_from(record.length)) {
1136 Some(v) => v,
1137 None => continue,
1138 };
1139
1140 let table_data = raw_face.data.get(start..end);
1141 match &record.tag.to_bytes() {
1142 b"bdat" => tables.bdat = table_data,
1143 b"bloc" => tables.bloc = table_data,
1144 b"CBDT" => tables.cbdt = table_data,
1145 b"CBLC" => tables.cblc = table_data,
1146 b"CFF " => tables.cff = table_data,
1147 #[cfg(feature = "variable-fonts")]
1148 b"CFF2" => tables.cff2 = table_data,
1149 b"COLR" => tables.colr = table_data,
1150 b"CPAL" => tables.cpal = table_data,
1151 b"EBDT" => tables.ebdt = table_data,
1152 b"EBLC" => tables.eblc = table_data,
1153 #[cfg(feature = "opentype-layout")]
1154 b"GDEF" => tables.gdef = table_data,
1155 #[cfg(feature = "opentype-layout")]
1156 b"GPOS" => tables.gpos = table_data,
1157 #[cfg(feature = "opentype-layout")]
1158 b"GSUB" => tables.gsub = table_data,
1159 #[cfg(feature = "opentype-layout")]
1160 b"MATH" => tables.math = table_data,
1161 #[cfg(feature = "variable-fonts")]
1162 b"HVAR" => tables.hvar = table_data,
1163 #[cfg(feature = "variable-fonts")]
1164 b"MVAR" => tables.mvar = table_data,
1165 b"OS/2" => tables.os2 = table_data,
1166 b"SVG " => tables.svg = table_data,
1167 b"VORG" => tables.vorg = table_data,
1168 #[cfg(feature = "variable-fonts")]
1169 b"VVAR" => tables.vvar = table_data,
1170 #[cfg(feature = "apple-layout")]
1171 b"ankr" => tables.ankr = table_data,
1172 #[cfg(feature = "variable-fonts")]
1173 b"avar" => tables.avar = table_data,
1174 b"cmap" => tables.cmap = table_data,
1175 #[cfg(feature = "apple-layout")]
1176 b"feat" => tables.feat = table_data,
1177 #[cfg(feature = "variable-fonts")]
1178 b"fvar" => tables.fvar = table_data,
1179 b"glyf" => tables.glyf = table_data,
1180 #[cfg(feature = "variable-fonts")]
1181 b"gvar" => tables.gvar = table_data,
1182 b"head" => tables.head = table_data.unwrap_or_default(),
1183 b"hhea" => tables.hhea = table_data.unwrap_or_default(),
1184 b"hmtx" => tables.hmtx = table_data,
1185 b"kern" => tables.kern = table_data,
1186 #[cfg(feature = "apple-layout")]
1187 b"kerx" => tables.kerx = table_data,
1188 b"loca" => tables.loca = table_data,
1189 b"maxp" => tables.maxp = table_data.unwrap_or_default(),
1190 #[cfg(feature = "apple-layout")]
1191 b"morx" => tables.morx = table_data,
1192 b"name" => tables.name = table_data,
1193 b"post" => tables.post = table_data,
1194 b"sbix" => tables.sbix = table_data,
1195 b"STAT" => tables.stat = table_data,
1196 #[cfg(feature = "apple-layout")]
1197 b"trak" => tables.trak = table_data,
1198 b"vhea" => tables.vhea = table_data,
1199 b"vmtx" => tables.vmtx = table_data,
1200 _ => {}
1201 }
1202 }
1203
1204 tables
1205 }
1206
1207 pub fn from_raw_tables(raw_tables: RawFaceTables<'a>) -> Result<Self, FaceParsingError> {
1209 #[allow(unused_mut)]
1210 let mut face = Face {
1211 raw_face: RawFace {
1212 data: &[],
1213 table_records: LazyArray16::default(),
1214 },
1215 #[cfg(feature = "variable-fonts")]
1216 coordinates: VarCoords::default(),
1217 tables: Self::parse_tables(raw_tables)?,
1218 };
1219
1220 #[cfg(feature = "variable-fonts")]
1221 {
1222 if let Some(ref fvar) = face.tables.fvar {
1223 face.coordinates.len = fvar.axes.len().min(MAX_VAR_COORDS as u16) as u8;
1224 }
1225 }
1226
1227 Ok(face)
1228 }
1229
1230 fn parse_tables(raw_tables: RawFaceTables<'a>) -> Result<FaceTables<'a>, FaceParsingError> {
1231 let head = head::Table::parse(raw_tables.head).ok_or(FaceParsingError::NoHeadTable)?;
1232 let hhea = hhea::Table::parse(raw_tables.hhea).ok_or(FaceParsingError::NoHheaTable)?;
1233 let maxp = maxp::Table::parse(raw_tables.maxp).ok_or(FaceParsingError::NoMaxpTable)?;
1234
1235 let hmtx = raw_tables.hmtx.and_then(|data| {
1236 hmtx::Table::parse(hhea.number_of_metrics, maxp.number_of_glyphs, data)
1237 });
1238
1239 let vhea = raw_tables.vhea.and_then(vhea::Table::parse);
1240 let vmtx = if let Some(vhea) = vhea {
1241 raw_tables.vmtx.and_then(|data| {
1242 hmtx::Table::parse(vhea.number_of_metrics, maxp.number_of_glyphs, data)
1243 })
1244 } else {
1245 None
1246 };
1247
1248 let loca = raw_tables.loca.and_then(|data| {
1249 loca::Table::parse(maxp.number_of_glyphs, head.index_to_location_format, data)
1250 });
1251 let glyf = if let Some(loca) = loca {
1252 raw_tables
1253 .glyf
1254 .and_then(|data| glyf::Table::parse(loca, data))
1255 } else {
1256 None
1257 };
1258
1259 let bdat = if let Some(bloc) = raw_tables.bloc.and_then(cblc::Table::parse) {
1260 raw_tables
1261 .bdat
1262 .and_then(|data| cbdt::Table::parse(bloc, data))
1263 } else {
1264 None
1265 };
1266
1267 let cbdt = if let Some(cblc) = raw_tables.cblc.and_then(cblc::Table::parse) {
1268 raw_tables
1269 .cbdt
1270 .and_then(|data| cbdt::Table::parse(cblc, data))
1271 } else {
1272 None
1273 };
1274
1275 let ebdt = if let Some(eblc) = raw_tables.eblc.and_then(cblc::Table::parse) {
1276 raw_tables
1277 .ebdt
1278 .and_then(|data| cbdt::Table::parse(eblc, data))
1279 } else {
1280 None
1281 };
1282
1283 let cpal = raw_tables.cpal.and_then(cpal::Table::parse);
1284 let colr = if let Some(cpal) = cpal {
1285 raw_tables
1286 .colr
1287 .and_then(|data| colr::Table::parse(cpal, data))
1288 } else {
1289 None
1290 };
1291
1292 Ok(FaceTables {
1293 head,
1294 hhea,
1295 maxp,
1296
1297 bdat,
1298 cbdt,
1299 cff: raw_tables.cff.and_then(cff::Table::parse),
1300 cmap: raw_tables.cmap.and_then(cmap::Table::parse),
1301 colr,
1302 ebdt,
1303 glyf,
1304 hmtx,
1305 kern: raw_tables.kern.and_then(kern::Table::parse),
1306 name: raw_tables.name.and_then(name::Table::parse),
1307 os2: raw_tables.os2.and_then(os2::Table::parse),
1308 post: raw_tables.post.and_then(post::Table::parse),
1309 sbix: raw_tables
1310 .sbix
1311 .and_then(|data| sbix::Table::parse(maxp.number_of_glyphs, data)),
1312 stat: raw_tables.stat.and_then(stat::Table::parse),
1313 svg: raw_tables.svg.and_then(svg::Table::parse),
1314 vhea: raw_tables.vhea.and_then(vhea::Table::parse),
1315 vmtx,
1316 vorg: raw_tables.vorg.and_then(vorg::Table::parse),
1317
1318 #[cfg(feature = "opentype-layout")]
1319 gdef: raw_tables.gdef.and_then(gdef::Table::parse),
1320 #[cfg(feature = "opentype-layout")]
1321 gpos: raw_tables
1322 .gpos
1323 .and_then(opentype_layout::LayoutTable::parse),
1324 #[cfg(feature = "opentype-layout")]
1325 gsub: raw_tables
1326 .gsub
1327 .and_then(opentype_layout::LayoutTable::parse),
1328 #[cfg(feature = "opentype-layout")]
1329 math: raw_tables.math.and_then(math::Table::parse),
1330
1331 #[cfg(feature = "apple-layout")]
1332 ankr: raw_tables
1333 .ankr
1334 .and_then(|data| ankr::Table::parse(maxp.number_of_glyphs, data)),
1335 #[cfg(feature = "apple-layout")]
1336 feat: raw_tables.feat.and_then(feat::Table::parse),
1337 #[cfg(feature = "apple-layout")]
1338 kerx: raw_tables
1339 .kerx
1340 .and_then(|data| kerx::Table::parse(maxp.number_of_glyphs, data)),
1341 #[cfg(feature = "apple-layout")]
1342 morx: raw_tables
1343 .morx
1344 .and_then(|data| morx::Table::parse(maxp.number_of_glyphs, data)),
1345 #[cfg(feature = "apple-layout")]
1346 trak: raw_tables.trak.and_then(trak::Table::parse),
1347
1348 #[cfg(feature = "variable-fonts")]
1349 avar: raw_tables.avar.and_then(avar::Table::parse),
1350 #[cfg(feature = "variable-fonts")]
1351 cff2: raw_tables.cff2.and_then(cff2::Table::parse),
1352 #[cfg(feature = "variable-fonts")]
1353 fvar: raw_tables.fvar.and_then(fvar::Table::parse),
1354 #[cfg(feature = "variable-fonts")]
1355 gvar: raw_tables.gvar.and_then(gvar::Table::parse),
1356 #[cfg(feature = "variable-fonts")]
1357 hvar: raw_tables.hvar.and_then(hvar::Table::parse),
1358 #[cfg(feature = "variable-fonts")]
1359 mvar: raw_tables.mvar.and_then(mvar::Table::parse),
1360 #[cfg(feature = "variable-fonts")]
1361 vvar: raw_tables.vvar.and_then(vvar::Table::parse),
1362 })
1363 }
1364
1365 #[inline]
1367 pub fn tables(&self) -> &FaceTables<'a> {
1368 &self.tables
1369 }
1370
1371 #[inline]
1377 pub fn raw_face(&self) -> &RawFace<'a> {
1378 &self.raw_face
1379 }
1380
1381 #[deprecated(since = "0.16.0", note = "use `self.raw_face().table()` instead")]
1387 #[inline]
1388 pub fn table_data(&self, tag: Tag) -> Option<&'a [u8]> {
1389 self.raw_face.table(tag)
1390 }
1391
1392 #[inline]
1396 pub fn names(&self) -> name::Names<'a> {
1397 self.tables.name.unwrap_or_default().names
1398 }
1399
1400 #[inline]
1404 pub fn is_regular(&self) -> bool {
1405 self.style() == Style::Normal
1406 }
1407
1408 #[inline]
1410 pub fn is_italic(&self) -> bool {
1411 self.style() == Style::Italic || self.italic_angle() != 0.0
1413 }
1414
1415 #[inline]
1419 pub fn is_bold(&self) -> bool {
1420 self.tables.os2.map(|os2| os2.is_bold()).unwrap_or(false)
1421 }
1422
1423 #[inline]
1427 pub fn is_oblique(&self) -> bool {
1428 self.style() == Style::Oblique
1429 }
1430
1431 #[inline]
1433 pub fn style(&self) -> Style {
1434 self.tables.os2.map(|os2| os2.style()).unwrap_or_default()
1435 }
1436
1437 #[inline]
1441 pub fn is_monospaced(&self) -> bool {
1442 self.tables
1443 .post
1444 .map(|post| post.is_monospaced)
1445 .unwrap_or(false)
1446 }
1447
1448 #[inline]
1452 pub fn is_variable(&self) -> bool {
1453 #[cfg(feature = "variable-fonts")]
1454 {
1455 self.tables.fvar.is_some()
1457 }
1458
1459 #[cfg(not(feature = "variable-fonts"))]
1460 {
1461 false
1462 }
1463 }
1464
1465 #[inline]
1469 pub fn weight(&self) -> Weight {
1470 self.tables.os2.map(|os2| os2.weight()).unwrap_or_default()
1471 }
1472
1473 #[inline]
1477 pub fn width(&self) -> Width {
1478 self.tables.os2.map(|os2| os2.width()).unwrap_or_default()
1479 }
1480
1481 #[inline]
1485 pub fn italic_angle(&self) -> f32 {
1486 self.tables
1487 .post
1488 .map(|table| table.italic_angle)
1489 .unwrap_or(0.0)
1490 }
1491
1492 #[inline]
1499 pub fn ascender(&self) -> i16 {
1500 if let Some(os_2) = self.tables.os2 {
1501 if os_2.use_typographic_metrics() {
1502 let value = os_2.typographic_ascender();
1503 return self.apply_metrics_variation(Tag::from_bytes(b"hasc"), value);
1504 }
1505 }
1506
1507 let mut value = self.tables.hhea.ascender;
1508 if value == 0 {
1509 if let Some(os_2) = self.tables.os2 {
1510 value = os_2.typographic_ascender();
1511 if value == 0 {
1512 value = os_2.windows_ascender();
1513 value = self.apply_metrics_variation(Tag::from_bytes(b"hcla"), value);
1514 } else {
1515 value = self.apply_metrics_variation(Tag::from_bytes(b"hasc"), value);
1516 }
1517 }
1518 }
1519
1520 value
1521 }
1522
1523 #[inline]
1527 pub fn descender(&self) -> i16 {
1528 if let Some(os_2) = self.tables.os2 {
1529 if os_2.use_typographic_metrics() {
1530 let value = os_2.typographic_descender();
1531 return self.apply_metrics_variation(Tag::from_bytes(b"hdsc"), value);
1532 }
1533 }
1534
1535 let mut value = self.tables.hhea.descender;
1536 if value == 0 {
1537 if let Some(os_2) = self.tables.os2 {
1538 value = os_2.typographic_descender();
1539 if value == 0 {
1540 value = os_2.windows_descender();
1541 value = self.apply_metrics_variation(Tag::from_bytes(b"hcld"), value);
1542 } else {
1543 value = self.apply_metrics_variation(Tag::from_bytes(b"hdsc"), value);
1544 }
1545 }
1546 }
1547
1548 value
1549 }
1550
1551 #[inline]
1555 pub fn height(&self) -> i16 {
1556 self.ascender() - self.descender()
1557 }
1558
1559 #[inline]
1563 pub fn line_gap(&self) -> i16 {
1564 if let Some(os_2) = self.tables.os2 {
1565 if os_2.use_typographic_metrics() {
1566 let value = os_2.typographic_line_gap();
1567 return self.apply_metrics_variation(Tag::from_bytes(b"hlgp"), value);
1568 }
1569 }
1570
1571 let mut value = self.tables.hhea.line_gap;
1572 if self.tables.hhea.ascender == 0 || self.tables.hhea.descender == 0 {
1574 if let Some(os_2) = self.tables.os2 {
1575 if os_2.typographic_ascender() != 0 || os_2.typographic_descender() != 0 {
1576 value = os_2.typographic_line_gap();
1577 value = self.apply_metrics_variation(Tag::from_bytes(b"hlgp"), value);
1578 } else {
1579 value = 0;
1580 }
1581 }
1582 }
1583
1584 value
1585 }
1586
1587 #[inline]
1596 pub fn typographic_ascender(&self) -> Option<i16> {
1597 self.tables.os2.map(|table| {
1598 let v = table.typographic_ascender();
1599 self.apply_metrics_variation(Tag::from_bytes(b"hasc"), v)
1600 })
1601 }
1602
1603 #[inline]
1612 pub fn typographic_descender(&self) -> Option<i16> {
1613 self.tables.os2.map(|table| {
1614 let v = table.typographic_descender();
1615 self.apply_metrics_variation(Tag::from_bytes(b"hdsc"), v)
1616 })
1617 }
1618
1619 #[inline]
1628 pub fn typographic_line_gap(&self) -> Option<i16> {
1629 self.tables.os2.map(|table| {
1630 let v = table.typographic_line_gap();
1631 self.apply_metrics_variation(Tag::from_bytes(b"hlgp"), v)
1632 })
1633 }
1634
1635 #[inline]
1639 pub fn vertical_ascender(&self) -> Option<i16> {
1640 self.tables
1641 .vhea
1642 .map(|vhea| vhea.ascender)
1643 .map(|v| self.apply_metrics_variation(Tag::from_bytes(b"vasc"), v))
1644 }
1645
1646 #[inline]
1650 pub fn vertical_descender(&self) -> Option<i16> {
1651 self.tables
1652 .vhea
1653 .map(|vhea| vhea.descender)
1654 .map(|v| self.apply_metrics_variation(Tag::from_bytes(b"vdsc"), v))
1655 }
1656
1657 #[inline]
1661 pub fn vertical_height(&self) -> Option<i16> {
1662 Some(self.vertical_ascender()? - self.vertical_descender()?)
1663 }
1664
1665 #[inline]
1669 pub fn vertical_line_gap(&self) -> Option<i16> {
1670 self.tables
1671 .vhea
1672 .map(|vhea| vhea.line_gap)
1673 .map(|v| self.apply_metrics_variation(Tag::from_bytes(b"vlgp"), v))
1674 }
1675
1676 #[inline]
1680 pub fn units_per_em(&self) -> u16 {
1681 self.tables.head.units_per_em
1682 }
1683
1684 #[inline]
1690 pub fn x_height(&self) -> Option<i16> {
1691 self.tables
1692 .os2
1693 .and_then(|os_2| os_2.x_height())
1694 .map(|v| self.apply_metrics_variation(Tag::from_bytes(b"xhgt"), v))
1695 }
1696
1697 #[inline]
1703 pub fn capital_height(&self) -> Option<i16> {
1704 self.tables
1705 .os2
1706 .and_then(|os_2| os_2.capital_height())
1707 .map(|v| self.apply_metrics_variation(Tag::from_bytes(b"cpht"), v))
1708 }
1709
1710 #[inline]
1716 pub fn underline_metrics(&self) -> Option<LineMetrics> {
1717 let mut metrics = self.tables.post?.underline_metrics;
1718
1719 if self.is_variable() {
1720 self.apply_metrics_variation_to(Tag::from_bytes(b"undo"), &mut metrics.position);
1721 self.apply_metrics_variation_to(Tag::from_bytes(b"unds"), &mut metrics.thickness);
1722 }
1723
1724 Some(metrics)
1725 }
1726
1727 #[inline]
1733 pub fn strikeout_metrics(&self) -> Option<LineMetrics> {
1734 let mut metrics = self.tables.os2?.strikeout_metrics();
1735
1736 if self.is_variable() {
1737 self.apply_metrics_variation_to(Tag::from_bytes(b"stro"), &mut metrics.position);
1738 self.apply_metrics_variation_to(Tag::from_bytes(b"strs"), &mut metrics.thickness);
1739 }
1740
1741 Some(metrics)
1742 }
1743
1744 #[inline]
1750 pub fn subscript_metrics(&self) -> Option<ScriptMetrics> {
1751 let mut metrics = self.tables.os2?.subscript_metrics();
1752
1753 if self.is_variable() {
1754 self.apply_metrics_variation_to(Tag::from_bytes(b"sbxs"), &mut metrics.x_size);
1755 self.apply_metrics_variation_to(Tag::from_bytes(b"sbys"), &mut metrics.y_size);
1756 self.apply_metrics_variation_to(Tag::from_bytes(b"sbxo"), &mut metrics.x_offset);
1757 self.apply_metrics_variation_to(Tag::from_bytes(b"sbyo"), &mut metrics.y_offset);
1758 }
1759
1760 Some(metrics)
1761 }
1762
1763 #[inline]
1769 pub fn superscript_metrics(&self) -> Option<ScriptMetrics> {
1770 let mut metrics = self.tables.os2?.superscript_metrics();
1771
1772 if self.is_variable() {
1773 self.apply_metrics_variation_to(Tag::from_bytes(b"spxs"), &mut metrics.x_size);
1774 self.apply_metrics_variation_to(Tag::from_bytes(b"spys"), &mut metrics.y_size);
1775 self.apply_metrics_variation_to(Tag::from_bytes(b"spxo"), &mut metrics.x_offset);
1776 self.apply_metrics_variation_to(Tag::from_bytes(b"spyo"), &mut metrics.y_offset);
1777 }
1778
1779 Some(metrics)
1780 }
1781
1782 #[inline]
1786 pub fn permissions(&self) -> Option<Permissions> {
1787 self.tables.os2?.permissions()
1788 }
1789
1790 #[inline]
1792 pub fn is_subsetting_allowed(&self) -> bool {
1793 self.tables
1794 .os2
1795 .map(|t| t.is_subsetting_allowed())
1796 .unwrap_or(false)
1797 }
1798
1799 #[inline]
1805 pub fn is_outline_embedding_allowed(&self) -> bool {
1806 self.tables
1807 .os2
1808 .map(|t| t.is_outline_embedding_allowed())
1809 .unwrap_or(false)
1810 }
1811
1812 #[inline]
1814 pub fn unicode_ranges(&self) -> UnicodeRanges {
1815 self.tables
1816 .os2
1817 .map(|t| t.unicode_ranges())
1818 .unwrap_or_default()
1819 }
1820
1821 #[inline]
1827 pub fn number_of_glyphs(&self) -> u16 {
1828 self.tables.maxp.number_of_glyphs.get()
1829 }
1830
1831 #[inline]
1839 pub fn glyph_index(&self, code_point: char) -> Option<GlyphId> {
1840 for subtable in self.tables.cmap?.subtables {
1841 if !subtable.is_unicode() {
1842 continue;
1843 }
1844
1845 if let Some(id) = subtable.glyph_index(u32::from(code_point)) {
1846 return Some(id);
1847 }
1848 }
1849
1850 None
1851 }
1852
1853 #[cfg(feature = "glyph-names")]
1859 #[inline]
1860 pub fn glyph_index_by_name(&self, name: &str) -> Option<GlyphId> {
1861 if let Some(name) = self
1862 .tables
1863 .post
1864 .and_then(|post| post.glyph_index_by_name(name))
1865 {
1866 return Some(name);
1867 }
1868
1869 if let Some(name) = self
1870 .tables
1871 .cff
1872 .as_ref()
1873 .and_then(|cff| cff.glyph_index_by_name(name))
1874 {
1875 return Some(name);
1876 }
1877
1878 None
1879 }
1880
1881 #[inline]
1889 pub fn glyph_variation_index(&self, code_point: char, variation: char) -> Option<GlyphId> {
1890 for subtable in self.tables.cmap?.subtables {
1891 if let cmap::Format::UnicodeVariationSequences(ref table) = subtable.format {
1892 return match table.glyph_index(u32::from(code_point), u32::from(variation))? {
1893 cmap::GlyphVariationResult::Found(v) => Some(v),
1894 cmap::GlyphVariationResult::UseDefault => self.glyph_index(code_point),
1895 };
1896 }
1897 }
1898
1899 None
1900 }
1901
1902 #[inline]
1906 pub fn glyph_hor_advance(&self, glyph_id: GlyphId) -> Option<u16> {
1907 #[cfg(feature = "variable-fonts")]
1908 {
1909 let mut advance = self.tables.hmtx?.advance(glyph_id)? as f32;
1910
1911 if self.is_variable() {
1912 if let Some(hvar) = self.tables.hvar {
1914 if let Some(offset) = hvar.advance_offset(glyph_id, self.coords()) {
1915 advance += offset + 0.5;
1917 }
1918 } else if let Some(points) = self.glyph_phantom_points(glyph_id) {
1919 advance += points.right.x + 0.5
1921 }
1922 }
1923
1924 u16::try_num_from(advance)
1925 }
1926
1927 #[cfg(not(feature = "variable-fonts"))]
1928 {
1929 self.tables.hmtx?.advance(glyph_id)
1930 }
1931 }
1932
1933 #[inline]
1937 pub fn glyph_ver_advance(&self, glyph_id: GlyphId) -> Option<u16> {
1938 #[cfg(feature = "variable-fonts")]
1939 {
1940 let mut advance = self.tables.vmtx?.advance(glyph_id)? as f32;
1941
1942 if self.is_variable() {
1943 if let Some(vvar) = self.tables.vvar {
1945 if let Some(offset) = vvar.advance_offset(glyph_id, self.coords()) {
1946 advance += offset + 0.5;
1948 }
1949 } else if let Some(points) = self.glyph_phantom_points(glyph_id) {
1950 advance += points.bottom.y + 0.5
1952 }
1953 }
1954
1955 u16::try_num_from(advance)
1956 }
1957
1958 #[cfg(not(feature = "variable-fonts"))]
1959 {
1960 self.tables.vmtx?.advance(glyph_id)
1961 }
1962 }
1963
1964 #[inline]
1968 pub fn glyph_hor_side_bearing(&self, glyph_id: GlyphId) -> Option<i16> {
1969 #[cfg(feature = "variable-fonts")]
1970 {
1971 let mut bearing = self.tables.hmtx?.side_bearing(glyph_id)? as f32;
1972
1973 if self.is_variable() {
1974 if let Some(hvar) = self.tables.hvar {
1976 if let Some(offset) = hvar.left_side_bearing_offset(glyph_id, self.coords()) {
1977 bearing += offset + 0.5;
1979 }
1980 }
1981 }
1982
1983 i16::try_num_from(bearing)
1984 }
1985
1986 #[cfg(not(feature = "variable-fonts"))]
1987 {
1988 self.tables.hmtx?.side_bearing(glyph_id)
1989 }
1990 }
1991
1992 #[inline]
1996 pub fn glyph_ver_side_bearing(&self, glyph_id: GlyphId) -> Option<i16> {
1997 #[cfg(feature = "variable-fonts")]
1998 {
1999 let mut bearing = self.tables.vmtx?.side_bearing(glyph_id)? as f32;
2000
2001 if self.is_variable() {
2002 if let Some(vvar) = self.tables.vvar {
2004 if let Some(offset) = vvar.top_side_bearing_offset(glyph_id, self.coords()) {
2005 bearing += offset + 0.5;
2007 }
2008 }
2009 }
2010
2011 i16::try_num_from(bearing)
2012 }
2013
2014 #[cfg(not(feature = "variable-fonts"))]
2015 {
2016 self.tables.vmtx?.side_bearing(glyph_id)
2017 }
2018 }
2019
2020 pub fn glyph_y_origin(&self, glyph_id: GlyphId) -> Option<i16> {
2025 #[cfg(feature = "variable-fonts")]
2026 {
2027 let mut origin = self.tables.vorg.map(|vorg| vorg.glyph_y_origin(glyph_id))? as f32;
2028
2029 if self.is_variable() {
2030 if let Some(vvar) = self.tables.vvar {
2032 if let Some(offset) = vvar.vertical_origin_offset(glyph_id, self.coords()) {
2033 origin += offset + 0.5;
2035 }
2036 }
2037 }
2038
2039 i16::try_num_from(origin)
2040 }
2041
2042 #[cfg(not(feature = "variable-fonts"))]
2043 {
2044 self.tables.vorg.map(|vorg| vorg.glyph_y_origin(glyph_id))
2045 }
2046 }
2047
2048 #[cfg(feature = "glyph-names")]
2054 #[inline]
2055 pub fn glyph_name(&self, glyph_id: GlyphId) -> Option<&str> {
2056 if let Some(name) = self.tables.post.and_then(|post| post.glyph_name(glyph_id)) {
2057 return Some(name);
2058 }
2059
2060 if let Some(name) = self
2061 .tables
2062 .cff
2063 .as_ref()
2064 .and_then(|cff1| cff1.glyph_name(glyph_id))
2065 {
2066 return Some(name);
2067 }
2068
2069 None
2070 }
2071
2072 #[inline]
2125 pub fn outline_glyph(
2126 &self,
2127 glyph_id: GlyphId,
2128 builder: &mut dyn OutlineBuilder,
2129 ) -> Option<Rect> {
2130 #[cfg(feature = "variable-fonts")]
2131 {
2132 if let Some(ref gvar) = self.tables.gvar {
2133 return gvar.outline(self.tables.glyf?, self.coords(), glyph_id, builder);
2134 }
2135 }
2136
2137 if let Some(table) = self.tables.glyf {
2138 return table.outline(glyph_id, builder);
2139 }
2140
2141 if let Some(ref cff) = self.tables.cff {
2142 return cff.outline(glyph_id, builder).ok();
2143 }
2144
2145 #[cfg(feature = "variable-fonts")]
2146 {
2147 if let Some(ref cff2) = self.tables.cff2 {
2148 return cff2.outline(self.coords(), glyph_id, builder).ok();
2149 }
2150 }
2151
2152 None
2153 }
2154
2155 #[inline]
2172 pub fn glyph_bounding_box(&self, glyph_id: GlyphId) -> Option<Rect> {
2173 self.outline_glyph(glyph_id, &mut DummyOutline)
2174 }
2175
2176 #[inline]
2178 pub fn global_bounding_box(&self) -> Rect {
2179 self.tables.head.global_bbox
2180 }
2181
2182 #[inline]
2203 pub fn glyph_raster_image(
2204 &self,
2205 glyph_id: GlyphId,
2206 pixels_per_em: u16,
2207 ) -> Option<RasterGlyphImage> {
2208 if let Some(table) = self.tables.sbix {
2209 if let Some(strike) = table.best_strike(pixels_per_em) {
2210 return strike.get(glyph_id);
2211 }
2212 }
2213 if let Some(bdat) = self.tables.bdat {
2214 return bdat.get(glyph_id, pixels_per_em);
2215 }
2216
2217 if let Some(ebdt) = self.tables.ebdt {
2218 return ebdt.get(glyph_id, pixels_per_em);
2219 }
2220
2221 if let Some(cbdt) = self.tables.cbdt {
2222 return cbdt.get(glyph_id, pixels_per_em);
2223 }
2224
2225 None
2226 }
2227
2228 #[inline]
2240 pub fn glyph_svg_image(&self, glyph_id: GlyphId) -> Option<svg::SvgDocument<'a>> {
2241 self.tables.svg.and_then(|svg| svg.documents.find(glyph_id))
2242 }
2243
2244 pub fn is_color_glyph(&self, glyph_id: GlyphId) -> bool {
2248 self.tables()
2249 .colr
2250 .map(|colr| colr.contains(glyph_id))
2251 .unwrap_or(false)
2252 }
2253
2254 pub fn color_palettes(&self) -> Option<core::num::NonZeroU16> {
2258 Some(self.tables().colr?.palettes.palettes())
2259 }
2260
2261 #[inline]
2280 pub fn paint_color_glyph(
2281 &self,
2282 glyph_id: GlyphId,
2283 palette: u16,
2284 foreground_color: RgbaColor,
2285 painter: &mut dyn colr::Painter<'a>,
2286 ) -> Option<()> {
2287 self.tables.colr?.paint(
2288 glyph_id,
2289 palette,
2290 painter,
2291 #[cfg(feature = "variable-fonts")]
2292 self.coords(),
2293 foreground_color,
2294 )
2295 }
2296
2297 #[cfg(feature = "variable-fonts")]
2299 #[inline]
2300 pub fn variation_axes(&self) -> LazyArray16<'a, VariationAxis> {
2301 self.tables.fvar.map(|fvar| fvar.axes).unwrap_or_default()
2302 }
2303
2304 #[cfg(feature = "variable-fonts")]
2314 pub fn set_variation(&mut self, axis: Tag, value: f32) -> Option<()> {
2315 if !self.is_variable() {
2316 return None;
2317 }
2318
2319 if usize::from(self.variation_axes().len()) >= MAX_VAR_COORDS {
2320 return None;
2321 }
2322
2323 for (i, var_axis) in self.variation_axes().into_iter().enumerate() {
2324 if var_axis.tag == axis {
2325 self.coordinates.data[i] = var_axis.normalized_value(value);
2326
2327 if let Some(avar) = self.tables.avar {
2328 let _ = avar.map_coordinate(self.coordinates.as_mut_slice(), i);
2329 }
2330 }
2331 }
2332
2333 Some(())
2334 }
2335
2336 #[cfg(feature = "variable-fonts")]
2338 #[inline]
2339 pub fn variation_coordinates(&self) -> &[NormalizedCoordinate] {
2340 self.coordinates.as_slice()
2341 }
2342
2343 #[cfg(feature = "variable-fonts")]
2345 #[inline]
2346 pub fn has_non_default_variation_coordinates(&self) -> bool {
2347 self.coordinates.as_slice().iter().any(|c| c.0 != 0)
2348 }
2349
2350 #[cfg(feature = "variable-fonts")]
2354 pub fn glyph_phantom_points(&self, glyph_id: GlyphId) -> Option<PhantomPoints> {
2355 let glyf = self.tables.glyf?;
2356 let gvar = self.tables.gvar?;
2357 gvar.phantom_points(glyf, self.coords(), glyph_id)
2358 }
2359
2360 #[cfg(feature = "variable-fonts")]
2361 #[inline]
2362 fn metrics_var_offset(&self, tag: Tag) -> f32 {
2363 self.tables
2364 .mvar
2365 .and_then(|table| table.metric_offset(tag, self.coords()))
2366 .unwrap_or(0.0)
2367 }
2368
2369 #[inline]
2370 fn apply_metrics_variation(&self, tag: Tag, mut value: i16) -> i16 {
2371 self.apply_metrics_variation_to(tag, &mut value);
2372 value
2373 }
2374
2375 #[cfg(feature = "variable-fonts")]
2376 #[inline]
2377 fn apply_metrics_variation_to(&self, tag: Tag, value: &mut i16) {
2378 if self.is_variable() {
2379 let v = f32::from(*value) + self.metrics_var_offset(tag);
2380 if let Some(v) = i16::try_num_from(v) {
2382 *value = v;
2383 }
2384 }
2385 }
2386
2387 #[cfg(not(feature = "variable-fonts"))]
2388 #[inline]
2389 fn apply_metrics_variation_to(&self, _: Tag, _: &mut i16) {}
2390
2391 #[cfg(feature = "variable-fonts")]
2392 #[inline]
2393 fn coords(&self) -> &[NormalizedCoordinate] {
2394 self.coordinates.as_slice()
2395 }
2396}
2397
2398impl core::fmt::Debug for Face<'_> {
2399 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2400 write!(f, "Face()")
2401 }
2402}
2403
2404#[inline]
2408pub fn fonts_in_collection(data: &[u8]) -> Option<u32> {
2409 let mut s = Stream::new(data);
2410 if s.read::<Magic>()? != Magic::FontCollection {
2411 return None;
2412 }
2413
2414 s.skip::<u32>(); s.read::<u32>()
2416}