ttf_parser/
lib.rs

1/*!
2A high-level, safe, zero-allocation font parser for:
3* [TrueType](https://docs.microsoft.com/en-us/typography/truetype/),
4* [OpenType](https://docs.microsoft.com/en-us/typography/opentype/spec/), and
5* [AAT](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html)
6  fonts.
7
8Font parsing starts with a [`Face`].
9
10## Features
11
12- A high-level API for most common properties, hiding all parsing and data resolving logic.
13- A low-level, but safe API to access TrueType tables data.
14- Highly configurable. You can disable most of the features, reducing binary size.
15  You can also parse TrueType tables separately, without loading the whole font/face.
16- Zero heap allocations.
17- Zero unsafe.
18- Zero dependencies.
19- `no_std`/WASM compatible.
20- Fast.
21- Stateless. All parsing methods are immutable.
22- Simple and maintainable code (no magic numbers).
23
24## Safety
25
26- The library must not panic. Any panic considered as a critical bug and should be reported.
27- The library forbids unsafe code.
28- No heap allocations, so crash due to OOM is not possible.
29- All recursive methods have a depth limit.
30- Technically, should use less than 64KiB of stack in worst case scenario.
31- Most of arithmetic operations are checked.
32- Most of numeric casts are checked.
33*/
34
35#![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)] // we use it for readability
41#![allow(clippy::identity_op)] // we use it for readability
42#![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    //! This module contains
96    //! [OpenType Layout](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#overview)
97    //! supplementary tables implementation.
98    pub use crate::ggg::*;
99}
100
101#[cfg(feature = "apple-layout")]
102pub mod apple_layout {
103    //! This module contains
104    //! [Apple Advanced Typography Layout](
105    //! https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html)
106    //! supplementary tables implementation.
107    pub use crate::aat::*;
108}
109
110/// A type-safe wrapper for glyph ID.
111#[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/// A TrueType font magic.
125///
126/// https://docs.microsoft.com/en-us/typography/opentype/spec/otff#organization-of-an-opentype-font
127#[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/// A variation coordinate in a normalized coordinate system.
149///
150/// Basically any number in a -1.0..1.0 range.
151/// Where 0 is a default value.
152///
153/// The number is stored as f2.16
154#[repr(transparent)]
155#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
156pub struct NormalizedCoordinate(i16);
157
158impl From<i16> for NormalizedCoordinate {
159    /// Creates a new coordinate.
160    ///
161    /// The provided number will be clamped to the -16384..16384 range.
162    #[inline]
163    fn from(n: i16) -> Self {
164        NormalizedCoordinate(parser::i16_bound(-16384, n, 16384))
165    }
166}
167
168impl From<f32> for NormalizedCoordinate {
169    /// Creates a new coordinate.
170    ///
171    /// The provided number will be clamped to the -1.0..1.0 range.
172    #[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    /// Returns the coordinate value as f2.14.
180    #[inline]
181    pub fn get(self) -> i16 {
182        self.0
183    }
184}
185
186/// A font variation value.
187///
188/// # Example
189///
190/// ```
191/// use ttf_parser::{Variation, Tag};
192///
193/// Variation { axis: Tag::from_bytes(b"wght"), value: 500.0 };
194/// ```
195#[derive(Clone, Copy, PartialEq, Debug)]
196pub struct Variation {
197    /// An axis tag name.
198    pub axis: Tag,
199    /// An axis value.
200    pub value: f32,
201}
202
203/// A 4-byte tag.
204#[repr(transparent)]
205#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
206pub struct Tag(pub u32);
207
208impl Tag {
209    /// Creates a `Tag` from bytes.
210    ///
211    /// # Example
212    ///
213    /// ```rust
214    /// println!("{}", ttf_parser::Tag::from_bytes(b"name"));
215    /// ```
216    #[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    /// Creates a `Tag` from bytes.
225    ///
226    /// In case of empty data will return `Tag` set to 0.
227    ///
228    /// When `bytes` are shorter than 4, will set missing bytes to ` `.
229    ///
230    /// Data after first 4 bytes is ignored.
231    #[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    /// Returns tag as 4-element byte array.
247    #[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    /// Returns tag as 4-element byte array.
258    #[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    /// Checks if tag is null / `[0, 0, 0, 0]`.
269    #[inline]
270    pub const fn is_null(&self) -> bool {
271        self.0 == 0
272    }
273
274    /// Returns tag value as `u32` number.
275    #[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/// A line metrics.
313///
314/// Used for underline and strikeout.
315#[repr(C)]
316#[derive(Clone, Copy, PartialEq, Eq, Debug)]
317pub struct LineMetrics {
318    /// Line position.
319    pub position: i16,
320
321    /// Line thickness.
322    pub thickness: i16,
323}
324
325/// A rectangle.
326///
327/// Doesn't guarantee that `x_min` <= `x_max` and/or `y_min` <= `y_max`.
328#[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    /// Returns rect's width.
350    #[inline]
351    pub fn width(&self) -> i16 {
352        self.x_max - self.x_min
353    }
354
355    /// Returns rect's height.
356    #[inline]
357    pub fn height(&self) -> i16 {
358        self.y_max - self.y_min
359    }
360}
361
362/// A rectangle described by the left-lower and upper-right points.
363#[derive(Clone, Copy, Debug, PartialEq)]
364pub struct RectF {
365    /// The horizontal minimum of the rect.
366    pub x_min: f32,
367    /// The vertical minimum of the rect.
368    pub y_min: f32,
369    /// The horizontal maximum of the rect.
370    pub x_max: f32,
371    /// The vertical maximum of the rect.
372    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/// An affine transform.
414#[derive(Clone, Copy, PartialEq)]
415pub struct Transform {
416    /// The 'a' component of the transform.
417    pub a: f32,
418    /// The 'b' component of the transform.
419    pub b: f32,
420    /// The 'c' component of the transform.
421    pub c: f32,
422    /// The 'd' component of the transform.
423    pub d: f32,
424    /// The 'e' component of the transform.
425    pub e: f32,
426    /// The 'f' component of the transform.
427    pub f: f32,
428}
429
430impl Transform {
431    /// Creates a new transform with the specified components.
432    #[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    /// Creates a new translation transform.
438    #[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    /// Creates a new rotation transform.
444    #[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    /// Creates a new skew transform.
453    #[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    /// Creates a new scale transform.
462    #[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    /// Combines two transforms with each other.
468    #[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    /// Checks whether a transform is the identity transform.
489    #[inline]
490    pub fn is_default(&self) -> bool {
491        // A direct float comparison is fine in our case.
492        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/// A float point.
526#[derive(Clone, Copy, Debug)]
527pub struct PointF {
528    /// The X-axis coordinate.
529    pub x: f32,
530    /// The Y-axis coordinate.
531    pub y: f32,
532}
533
534/// Phantom points.
535///
536/// Available only for variable fonts with the `gvar` table.
537#[derive(Clone, Copy, Debug)]
538pub struct PhantomPoints {
539    /// Left side bearing point.
540    pub left: PointF,
541    /// Right side bearing point.
542    pub right: PointF,
543    /// Top side bearing point.
544    pub top: PointF,
545    /// Bottom side bearing point.
546    pub bottom: PointF,
547}
548
549/// A RGBA color in the sRGB color space.
550#[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    /// Creates a new `RgbaColor`.
561    #[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
576/// A trait for glyph outline construction.
577pub trait OutlineBuilder {
578    /// Appends a MoveTo segment.
579    ///
580    /// Start of a contour.
581    fn move_to(&mut self, x: f32, y: f32);
582
583    /// Appends a LineTo segment.
584    fn line_to(&mut self, x: f32, y: f32);
585
586    /// Appends a QuadTo segment.
587    fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32);
588
589    /// Appends a CurveTo segment.
590    fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32);
591
592    /// Appends a ClosePath segment.
593    ///
594    /// End of a contour.
595    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/// A glyph raster image format.
608#[allow(missing_docs)]
609#[derive(Clone, Copy, PartialEq, Eq, Debug)]
610pub enum RasterImageFormat {
611    PNG,
612
613    /// A monochrome bitmap.
614    ///
615    /// The most significant bit of the first byte corresponds to the top-left pixel, proceeding
616    /// through succeeding bits moving left to right. The data for each row is padded to a byte
617    /// boundary, so the next row begins with the most significant bit of a new byte. 1 corresponds
618    /// to black, and 0 to white.
619    BitmapMono,
620
621    /// A packed monochrome bitmap.
622    ///
623    /// The most significant bit of the first byte corresponds to the top-left pixel, proceeding
624    /// through succeeding bits moving left to right. Data is tightly packed with no padding. 1
625    /// corresponds to black, and 0 to white.
626    BitmapMonoPacked,
627
628    /// A grayscale bitmap with 2 bits per pixel.
629    ///
630    /// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
631    /// through succeeding bits moving left to right. The data for each row is padded to a byte
632    /// boundary, so the next row begins with the most significant bit of a new byte.
633    BitmapGray2,
634
635    /// A packed grayscale bitmap with 2 bits per pixel.
636    ///
637    /// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
638    /// through succeeding bits moving left to right. Data is tightly packed with no padding.
639    BitmapGray2Packed,
640
641    /// A grayscale bitmap with 4 bits per pixel.
642    ///
643    /// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
644    /// through succeeding bits moving left to right. The data for each row is padded to a byte
645    /// boundary, so the next row begins with the most significant bit of a new byte.
646    BitmapGray4,
647
648    /// A packed grayscale bitmap with 4 bits per pixel.
649    ///
650    /// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
651    /// through succeeding bits moving left to right. Data is tightly packed with no padding.
652    BitmapGray4Packed,
653
654    /// A grayscale bitmap with 8 bits per pixel.
655    ///
656    /// The first byte corresponds to the top-left pixel, proceeding through succeeding bytes
657    /// moving left to right.
658    BitmapGray8,
659
660    /// A color bitmap with 32 bits per pixel.
661    ///
662    /// The first group of four bytes corresponds to the top-left pixel, proceeding through
663    /// succeeding pixels moving left to right. Each byte corresponds to a color channel and the
664    /// channels within a pixel are in blue, green, red, alpha order. Color values are
665    /// pre-multiplied by the alpha. For example, the color "full-green with half translucency"
666    /// is encoded as `\x00\x80\x00\x80`, and not `\x00\xFF\x00\x80`.
667    BitmapPremulBgra32,
668}
669
670/// A glyph's raster image.
671///
672/// Note, that glyph metrics are in pixels and not in font units.
673#[derive(Clone, Copy, PartialEq, Eq, Debug)]
674pub struct RasterGlyphImage<'a> {
675    /// Horizontal offset.
676    pub x: i16,
677
678    /// Vertical offset.
679    pub y: i16,
680
681    /// Image width.
682    ///
683    /// It doesn't guarantee that this value is the same as set in the `data`.
684    pub width: u16,
685
686    /// Image height.
687    ///
688    /// It doesn't guarantee that this value is the same as set in the `data`.
689    pub height: u16,
690
691    /// A pixels per em of the selected strike.
692    pub pixels_per_em: u16,
693
694    /// An image format.
695    pub format: RasterImageFormat,
696
697    /// A raw image data. It's up to the caller to decode it.
698    pub data: &'a [u8],
699}
700
701/// A raw table record.
702#[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/// A list of font face parsing errors.
762#[derive(Clone, Copy, PartialEq, Eq, Debug)]
763pub enum FaceParsingError {
764    /// An attempt to read out of bounds detected.
765    ///
766    /// Should occur only on malformed fonts.
767    MalformedFont,
768
769    /// Face data must start with `0x00010000`, `0x74727565`, `0x4F54544F` or `0x74746366`.
770    UnknownMagic,
771
772    /// The face index is larger than the number of faces in the font.
773    FaceIndexOutOfBounds,
774
775    /// The `head` table is missing or malformed.
776    NoHeadTable,
777
778    /// The `hhea` table is missing or malformed.
779    NoHheaTable,
780
781    /// The `maxp` table is missing or malformed.
782    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/// A raw font face.
802///
803/// You are probably looking for [`Face`]. This is a low-level type.
804///
805/// Unlike [`Face`], [`RawFace`] parses only face table records.
806/// Meaning all you can get from this type is a raw (`&[u8]`) data of a requested table.
807/// Then you can either parse just a singe table from a font/face or populate [`RawFaceTables`]
808/// manually before passing it to [`Face::from_raw_tables`].
809#[derive(Clone, Copy)]
810pub struct RawFace<'a> {
811    /// The input font file data.
812    pub data: &'a [u8],
813    /// An array of table records.
814    pub table_records: LazyArray16<'a, TableRecord>,
815}
816
817impl<'a> RawFace<'a> {
818    /// Creates a new [`RawFace`] from a raw data.
819    ///
820    /// `index` indicates the specific font face in a font collection.
821    /// Use [`fonts_in_collection`] to get the total number of font faces.
822    /// Set to 0 if unsure.
823    ///
824    /// While we do reuse [`FaceParsingError`], `No*Table` errors will not be throws.
825    #[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    /// Creates a new [`RawFace`] from a raw data.
831    ///
832    /// `index` indicates the specific font face in a font collection.
833    /// Use [`fonts_in_collection`] to get the total number of font faces.
834    /// Set to 0 if unsure.
835    ///
836    /// While we do reuse [`FaceParsingError`], `No*Table` errors will not be throws.
837    pub fn parse(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> {
838        // https://docs.microsoft.com/en-us/typography/opentype/spec/otff#organization-of-an-opentype-font
839
840        let mut s = Stream::new(data);
841
842        // Read **font** magic.
843        let magic = s.read::<Magic>().ok_or(FaceParsingError::UnknownMagic)?;
844        if magic == Magic::FontCollection {
845            s.skip::<u32>(); // version
846            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            // Face offset is from the start of the font data,
855            // so we have to adjust it to the current parser offset.
856            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            // Read **face** magic.
864            // Each face in a font collection also starts with a magic.
865            let magic = s.read::<Magic>().ok_or(FaceParsingError::UnknownMagic)?;
866            // And face in a font collection can't be another collection.
867            if magic == Magic::FontCollection {
868                return Err(FaceParsingError::UnknownMagic);
869            }
870        } else {
871            // When reading from a regular font (not a collection) disallow index to be non-zero
872            // Basically treat the font as a one-element collection
873            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); // searchRange (u16) + entrySelector (u16) + rangeShift (u16)
880        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    /// Returns the raw data of a selected table.
891    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/// A list of all supported tables as raw data.
909///
910/// This type should be used in tandem with
911/// [`Face::from_raw_tables()`](struct.Face.html#method.from_raw_tables).
912///
913/// This allows loading font faces not only from TrueType font files,
914/// but from any source. Mainly used for parsing WOFF.
915#[allow(missing_docs)]
916#[allow(missing_debug_implementations)]
917#[derive(Clone, Default)]
918pub struct RawFaceTables<'a> {
919    // Mandatory tables.
920    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/// Parsed face tables.
985///
986/// Unlike [`Face`], provides a low-level parsing abstraction over TrueType tables.
987/// Useful when you need a direct access to tables data.
988///
989/// Also, used when high-level API is problematic to implement.
990/// A good example would be OpenType layout tables (GPOS/GSUB).
991#[allow(missing_docs)]
992#[allow(missing_debug_implementations)]
993#[derive(Clone)]
994pub struct FaceTables<'a> {
995    // Mandatory tables.
996    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/// A font face.
1056///
1057/// Provides a high-level API for working with TrueType fonts.
1058/// If you're not familiar with how TrueType works internally, you should use this type.
1059/// If you do know and want a bit more low-level access - checkout [`FaceTables`].
1060///
1061/// Note that `Face` doesn't own the font data and doesn't allocate anything in heap.
1062/// Therefore you cannot "store" it. The idea is that you should parse the `Face`
1063/// when needed, get required data and forget about it.
1064/// That's why the initial parsing is highly optimized and should not become a bottleneck.
1065///
1066/// If you still want to store `Face` - checkout
1067/// [owned_ttf_parser](https://crates.io/crates/owned_ttf_parser). Requires `unsafe`.
1068///
1069/// While `Face` is technically copyable, we disallow it because it's almost 2KB big.
1070#[derive(Clone)]
1071pub struct Face<'a> {
1072    raw_face: RawFace<'a>,
1073    tables: FaceTables<'a>, // Parsed tables.
1074    #[cfg(feature = "variable-fonts")]
1075    coordinates: VarCoords,
1076}
1077
1078impl<'a> Face<'a> {
1079    /// Creates a new [`Face`] from a raw data.
1080    ///
1081    /// `index` indicates the specific font face in a font collection.
1082    /// Use [`fonts_in_collection`] to get the total number of font faces.
1083    /// Set to 0 if unsure.
1084    ///
1085    /// This method will do some parsing and sanitization,
1086    /// but in general can be considered free. No significant performance overhead.
1087    ///
1088    /// Required tables: `head`, `hhea` and `maxp`.
1089    ///
1090    /// If an optional table has invalid data it will be skipped.
1091    #[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    /// Creates a new [`Face`] from a raw data.
1097    ///
1098    /// `index` indicates the specific font face in a font collection.
1099    /// Use [`fonts_in_collection`] to get the total number of font faces.
1100    /// Set to 0 if unsure.
1101    ///
1102    /// This method will do some parsing and sanitization,
1103    /// but in general can be considered free. No significant performance overhead.
1104    ///
1105    /// Required tables: `head`, `hhea` and `maxp`.
1106    ///
1107    /// If an optional table has invalid data it will be skipped.
1108    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    /// Creates a new [`Face`] from provided [`RawFaceTables`].
1208    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    /// Returns low-level face tables.
1366    #[inline]
1367    pub fn tables(&self) -> &FaceTables<'a> {
1368        &self.tables
1369    }
1370
1371    /// Returns the `RawFace` used to create this `Face`.
1372    ///
1373    /// Useful if you want to parse the data manually.
1374    ///
1375    /// Available only for faces created using [`Face::parse()`](struct.Face.html#method.parse).
1376    #[inline]
1377    pub fn raw_face(&self) -> &RawFace<'a> {
1378        &self.raw_face
1379    }
1380
1381    /// Returns the raw data of a selected table.
1382    ///
1383    /// Useful if you want to parse the data manually.
1384    ///
1385    /// Available only for faces created using [`Face::parse()`](struct.Face.html#method.parse).
1386    #[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    /// Returns a list of names.
1393    ///
1394    /// Contains face name and other strings.
1395    #[inline]
1396    pub fn names(&self) -> name::Names<'a> {
1397        self.tables.name.unwrap_or_default().names
1398    }
1399
1400    /// Checks that face is marked as *Regular*.
1401    ///
1402    /// Returns `false` when OS/2 table is not present.
1403    #[inline]
1404    pub fn is_regular(&self) -> bool {
1405        self.style() == Style::Normal
1406    }
1407
1408    /// Checks that face is marked as *Italic*.
1409    #[inline]
1410    pub fn is_italic(&self) -> bool {
1411        // A face can have a Normal style and a non-zero italic angle, which also makes it italic.
1412        self.style() == Style::Italic || self.italic_angle() != 0.0
1413    }
1414
1415    /// Checks that face is marked as *Bold*.
1416    ///
1417    /// Returns `false` when OS/2 table is not present.
1418    #[inline]
1419    pub fn is_bold(&self) -> bool {
1420        self.tables.os2.map(|os2| os2.is_bold()).unwrap_or(false)
1421    }
1422
1423    /// Checks that face is marked as *Oblique*.
1424    ///
1425    /// Returns `false` when OS/2 table is not present or when its version is < 4.
1426    #[inline]
1427    pub fn is_oblique(&self) -> bool {
1428        self.style() == Style::Oblique
1429    }
1430
1431    /// Returns face style.
1432    #[inline]
1433    pub fn style(&self) -> Style {
1434        self.tables.os2.map(|os2| os2.style()).unwrap_or_default()
1435    }
1436
1437    /// Checks that face is marked as *Monospaced*.
1438    ///
1439    /// Returns `false` when `post` table is not present.
1440    #[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    /// Checks that face is variable.
1449    ///
1450    /// Simply checks the presence of a `fvar` table.
1451    #[inline]
1452    pub fn is_variable(&self) -> bool {
1453        #[cfg(feature = "variable-fonts")]
1454        {
1455            // `fvar::Table::parse` already checked that `axisCount` is non-zero.
1456            self.tables.fvar.is_some()
1457        }
1458
1459        #[cfg(not(feature = "variable-fonts"))]
1460        {
1461            false
1462        }
1463    }
1464
1465    /// Returns face's weight.
1466    ///
1467    /// Returns `Weight::Normal` when OS/2 table is not present.
1468    #[inline]
1469    pub fn weight(&self) -> Weight {
1470        self.tables.os2.map(|os2| os2.weight()).unwrap_or_default()
1471    }
1472
1473    /// Returns face's width.
1474    ///
1475    /// Returns `Width::Normal` when OS/2 table is not present or when value is invalid.
1476    #[inline]
1477    pub fn width(&self) -> Width {
1478        self.tables.os2.map(|os2| os2.width()).unwrap_or_default()
1479    }
1480
1481    /// Returns face's italic angle.
1482    ///
1483    /// Returns `0.0` when `post` table is not present.
1484    #[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    // Read https://github.com/freetype/freetype/blob/49270c17011491227ec7bd3fb73ede4f674aa065/src/sfnt/sfobjs.c#L1279
1493    // to learn more about the logic behind the following functions.
1494
1495    /// Returns a horizontal face ascender.
1496    ///
1497    /// This method is affected by variation axes.
1498    #[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    /// Returns a horizontal face descender.
1524    ///
1525    /// This method is affected by variation axes.
1526    #[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    /// Returns face's height.
1552    ///
1553    /// This method is affected by variation axes.
1554    #[inline]
1555    pub fn height(&self) -> i16 {
1556        self.ascender() - self.descender()
1557    }
1558
1559    /// Returns a horizontal face line gap.
1560    ///
1561    /// This method is affected by variation axes.
1562    #[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        // For line gap, we have to check that ascender or descender are 0, not line gap itself.
1573        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    /// Returns a horizontal typographic face ascender.
1588    ///
1589    /// Prefer `Face::ascender` unless you explicitly want this. This is a more
1590    /// low-level alternative.
1591    ///
1592    /// This method is affected by variation axes.
1593    ///
1594    /// Returns `None` when OS/2 table is not present.
1595    #[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    /// Returns a horizontal typographic face descender.
1604    ///
1605    /// Prefer `Face::descender` unless you explicitly want this. This is a more
1606    /// low-level alternative.
1607    ///
1608    /// This method is affected by variation axes.
1609    ///
1610    /// Returns `None` when OS/2 table is not present.
1611    #[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    /// Returns a horizontal typographic face line gap.
1620    ///
1621    /// Prefer `Face::line_gap` unless you explicitly want this. This is a more
1622    /// low-level alternative.
1623    ///
1624    /// This method is affected by variation axes.
1625    ///
1626    /// Returns `None` when OS/2 table is not present.
1627    #[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    /// Returns a vertical face ascender.
1636    ///
1637    /// This method is affected by variation axes.
1638    #[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    /// Returns a vertical face descender.
1647    ///
1648    /// This method is affected by variation axes.
1649    #[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    /// Returns a vertical face height.
1658    ///
1659    /// This method is affected by variation axes.
1660    #[inline]
1661    pub fn vertical_height(&self) -> Option<i16> {
1662        Some(self.vertical_ascender()? - self.vertical_descender()?)
1663    }
1664
1665    /// Returns a vertical face line gap.
1666    ///
1667    /// This method is affected by variation axes.
1668    #[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    /// Returns face's units per EM.
1677    ///
1678    /// Guarantee to be in a 16..=16384 range.
1679    #[inline]
1680    pub fn units_per_em(&self) -> u16 {
1681        self.tables.head.units_per_em
1682    }
1683
1684    /// Returns face's x height.
1685    ///
1686    /// This method is affected by variation axes.
1687    ///
1688    /// Returns `None` when OS/2 table is not present or when its version is < 2.
1689    #[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    /// Returns face's capital height.
1698    ///
1699    /// This method is affected by variation axes.
1700    ///
1701    /// Returns `None` when OS/2 table is not present or when its version is < 2.
1702    #[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    /// Returns face's underline metrics.
1711    ///
1712    /// This method is affected by variation axes.
1713    ///
1714    /// Returns `None` when `post` table is not present.
1715    #[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    /// Returns face's strikeout metrics.
1728    ///
1729    /// This method is affected by variation axes.
1730    ///
1731    /// Returns `None` when OS/2 table is not present.
1732    #[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    /// Returns face's subscript metrics.
1745    ///
1746    /// This method is affected by variation axes.
1747    ///
1748    /// Returns `None` when OS/2 table is not present.
1749    #[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    /// Returns face's superscript metrics.
1764    ///
1765    /// This method is affected by variation axes.
1766    ///
1767    /// Returns `None` when OS/2 table is not present.
1768    #[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    /// Returns face permissions.
1783    ///
1784    /// Returns `None` in case of a malformed value.
1785    #[inline]
1786    pub fn permissions(&self) -> Option<Permissions> {
1787        self.tables.os2?.permissions()
1788    }
1789
1790    /// Checks if the face allows embedding a subset, further restricted by [`Self::permissions`].
1791    #[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    /// Checks if the face allows outline data to be embedded.
1800    ///
1801    /// If false, only bitmaps may be embedded in accordance with [`Self::permissions`].
1802    ///
1803    /// If the font contains no bitmaps and this flag is not set, it implies no embedding is allowed.
1804    #[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    /// Returns [Unicode Ranges](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur).
1813    #[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    /// Returns a total number of glyphs in the face.
1822    ///
1823    /// Never zero.
1824    ///
1825    /// The value was already parsed, so this function doesn't involve any parsing.
1826    #[inline]
1827    pub fn number_of_glyphs(&self) -> u16 {
1828        self.tables.maxp.number_of_glyphs.get()
1829    }
1830
1831    /// Resolves a Glyph ID for a code point.
1832    ///
1833    /// Returns `None` instead of `0` when glyph is not found.
1834    ///
1835    /// All subtable formats except Mixed Coverage (8) are supported.
1836    ///
1837    /// If you need a more low-level control, prefer `Face::tables().cmap`.
1838    #[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    /// Resolves a Glyph ID for a glyph name.
1854    ///
1855    /// Uses the `post` and `CFF` tables as sources.
1856    ///
1857    /// Returns `None` when no name is associated with a `glyph`.
1858    #[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    /// Resolves a variation of a Glyph ID from two code points.
1882    ///
1883    /// Implemented according to
1884    /// [Unicode Variation Sequences](
1885    /// https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences).
1886    ///
1887    /// Returns `None` instead of `0` when glyph is not found.
1888    #[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    /// Returns glyph's horizontal advance.
1903    ///
1904    /// This method is affected by variation axes.
1905    #[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                // Ignore variation offset when `hvar` is not set.
1913                if let Some(hvar) = self.tables.hvar {
1914                    if let Some(offset) = hvar.advance_offset(glyph_id, self.coords()) {
1915                        // We can't use `round()` in `no_std`, so this is the next best thing.
1916                        advance += offset + 0.5;
1917                    }
1918                } else if let Some(points) = self.glyph_phantom_points(glyph_id) {
1919                    // We can't use `round()` in `no_std`, so this is the next best thing.
1920                    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    /// Returns glyph's vertical advance.
1934    ///
1935    /// This method is affected by variation axes.
1936    #[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                // Ignore variation offset when `vvar` is not set.
1944                if let Some(vvar) = self.tables.vvar {
1945                    if let Some(offset) = vvar.advance_offset(glyph_id, self.coords()) {
1946                        // We can't use `round()` in `no_std`, so this is the next best thing.
1947                        advance += offset + 0.5;
1948                    }
1949                } else if let Some(points) = self.glyph_phantom_points(glyph_id) {
1950                    // We can't use `round()` in `no_std`, so this is the next best thing.
1951                    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    /// Returns glyph's horizontal side bearing.
1965    ///
1966    /// This method is affected by variation axes.
1967    #[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                // Ignore variation offset when `hvar` is not set.
1975                if let Some(hvar) = self.tables.hvar {
1976                    if let Some(offset) = hvar.left_side_bearing_offset(glyph_id, self.coords()) {
1977                        // We can't use `round()` in `no_std`, so this is the next best thing.
1978                        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    /// Returns glyph's vertical side bearing.
1993    ///
1994    /// This method is affected by variation axes.
1995    #[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                // Ignore variation offset when `vvar` is not set.
2003                if let Some(vvar) = self.tables.vvar {
2004                    if let Some(offset) = vvar.top_side_bearing_offset(glyph_id, self.coords()) {
2005                        // We can't use `round()` in `no_std`, so this is the next best thing.
2006                        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    /// Returns glyph's vertical origin according to
2021    /// [Vertical Origin Table](https://docs.microsoft.com/en-us/typography/opentype/spec/vorg).
2022    ///
2023    /// This method is affected by variation axes.
2024    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                // Ignore variation offset when `vvar` is not set.
2031                if let Some(vvar) = self.tables.vvar {
2032                    if let Some(offset) = vvar.vertical_origin_offset(glyph_id, self.coords()) {
2033                        // We can't use `round()` in `no_std`, so this is the next best thing.
2034                        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    /// Returns glyph's name.
2049    ///
2050    /// Uses the `post` and `CFF` tables as sources.
2051    ///
2052    /// Returns `None` when no name is associated with a `glyph`.
2053    #[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    /// Outlines a glyph and returns its tight bounding box.
2073    ///
2074    /// **Warning**: since `ttf-parser` is a pull parser,
2075    /// `OutlineBuilder` will emit segments even when outline is partially malformed.
2076    /// You must check `outline_glyph()` result before using
2077    /// `OutlineBuilder`'s output.
2078    ///
2079    /// `gvar`, `glyf`, `CFF` and `CFF2` tables are supported.
2080    /// And they will be accesses in this specific order.
2081    ///
2082    /// This method is affected by variation axes.
2083    ///
2084    /// Returns `None` when glyph has no outline or on error.
2085    ///
2086    /// # Example
2087    ///
2088    /// ```
2089    /// use std::fmt::Write;
2090    /// use ttf_parser;
2091    ///
2092    /// struct Builder(String);
2093    ///
2094    /// impl ttf_parser::OutlineBuilder for Builder {
2095    ///     fn move_to(&mut self, x: f32, y: f32) {
2096    ///         write!(&mut self.0, "M {} {} ", x, y).unwrap();
2097    ///     }
2098    ///
2099    ///     fn line_to(&mut self, x: f32, y: f32) {
2100    ///         write!(&mut self.0, "L {} {} ", x, y).unwrap();
2101    ///     }
2102    ///
2103    ///     fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
2104    ///         write!(&mut self.0, "Q {} {} {} {} ", x1, y1, x, y).unwrap();
2105    ///     }
2106    ///
2107    ///     fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
2108    ///         write!(&mut self.0, "C {} {} {} {} {} {} ", x1, y1, x2, y2, x, y).unwrap();
2109    ///     }
2110    ///
2111    ///     fn close(&mut self) {
2112    ///         write!(&mut self.0, "Z ").unwrap();
2113    ///     }
2114    /// }
2115    ///
2116    /// let data = std::fs::read("tests/fonts/demo.ttf").unwrap();
2117    /// let face = ttf_parser::Face::parse(&data, 0).unwrap();
2118    /// let mut builder = Builder(String::new());
2119    /// let bbox = face.outline_glyph(ttf_parser::GlyphId(1), &mut builder).unwrap();
2120    /// assert_eq!(builder.0, "M 173 267 L 369 267 L 270 587 L 173 267 Z M 6 0 L 224 656 \
2121    ///                        L 320 656 L 541 0 L 452 0 L 390 200 L 151 200 L 85 0 L 6 0 Z ");
2122    /// assert_eq!(bbox, ttf_parser::Rect { x_min: 6, y_min: 0, x_max: 541, y_max: 656 });
2123    /// ```
2124    #[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    /// Returns a tight glyph bounding box.
2156    ///
2157    /// This is just a shorthand for `outline_glyph()` since only the `glyf` table stores
2158    /// a bounding box. We ignore `glyf` table bboxes because they can be malformed.
2159    /// In case of CFF and variable fonts we have to actually outline
2160    /// a glyph to find it's bounding box.
2161    ///
2162    /// When a glyph is defined by a raster or a vector image,
2163    /// that can be obtained via `glyph_image()`,
2164    /// the bounding box must be calculated manually and this method will return `None`.
2165    ///
2166    /// Note: the returned bbox is not validated in any way. A font file can have a glyph bbox
2167    /// set to zero/negative width and/or height and this is perfectly ok.
2168    /// For calculated bboxes, zero width and/or height is also perfectly fine.
2169    ///
2170    /// This method is affected by variation axes.
2171    #[inline]
2172    pub fn glyph_bounding_box(&self, glyph_id: GlyphId) -> Option<Rect> {
2173        self.outline_glyph(glyph_id, &mut DummyOutline)
2174    }
2175
2176    /// Returns a bounding box that large enough to enclose any glyph from the face.
2177    #[inline]
2178    pub fn global_bounding_box(&self) -> Rect {
2179        self.tables.head.global_bbox
2180    }
2181
2182    /// Returns a reference to a glyph's raster image.
2183    ///
2184    /// A font can define a glyph using a raster or a vector image instead of a simple outline.
2185    /// Which is primarily used for emojis. This method should be used to access raster images.
2186    ///
2187    /// `pixels_per_em` allows selecting a preferred image size. The chosen size will
2188    /// be closer to an upper one. So when font has 64px and 96px images and `pixels_per_em`
2189    /// is set to 72, 96px image will be returned.
2190    /// To get the largest image simply use `std::u16::MAX`.
2191    ///
2192    /// Note that this method will return an encoded image. It should be decoded
2193    /// by the caller. We don't validate or preprocess it in any way.
2194    ///
2195    /// Also, a font can contain both: images and outlines. So when this method returns `None`
2196    /// you should also try `outline_glyph()` afterwards.
2197    ///
2198    /// There are multiple ways an image can be stored in a TrueType font
2199    /// and this method supports most of them.
2200    /// This includes `sbix`, `bloc` + `bdat`, `EBLC` + `EBDT`, `CBLC` + `CBDT`.
2201    /// And font's tables will be accesses in this specific order.
2202    #[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    /// Returns a reference to a glyph's SVG image.
2229    ///
2230    /// A font can define a glyph using a raster or a vector image instead of a simple outline.
2231    /// Which is primarily used for emojis. This method should be used to access SVG images.
2232    ///
2233    /// Note that this method will return just an SVG data. It should be rendered
2234    /// or even decompressed (in case of SVGZ) by the caller.
2235    /// We don't validate or preprocess it in any way.
2236    ///
2237    /// Also, a font can contain both: images and outlines. So when this method returns `None`
2238    /// you should also try `outline_glyph()` afterwards.
2239    #[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    /// Returns `true` if the glyph can be colored/painted using the `COLR`+`CPAL` tables.
2245    ///
2246    /// See [`paint_color_glyph`](Face::paint_color_glyph) for details.
2247    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    /// Returns the number of palettes stored in the `COLR`+`CPAL` tables.
2255    ///
2256    /// See [`paint_color_glyph`](Face::paint_color_glyph) for details.
2257    pub fn color_palettes(&self) -> Option<core::num::NonZeroU16> {
2258        Some(self.tables().colr?.palettes.palettes())
2259    }
2260
2261    /// Paints a color glyph from the `COLR` table.
2262    ///
2263    /// A font can have multiple palettes, which you can check via
2264    /// [`color_palettes`](Face::color_palettes).
2265    /// If unsure, just pass 0 to the `palette` argument, which is the default.
2266    ///
2267    /// A font can define a glyph using layers of colored shapes instead of a
2268    /// simple outline. Which is primarily used for emojis. This method should
2269    /// be used to access glyphs defined in the `COLR` table.
2270    ///
2271    /// Also, a font can contain both: a layered definition and outlines. So
2272    /// when this method returns `None` you should also try
2273    /// [`outline_glyph`](Face::outline_glyph) afterwards.
2274    ///
2275    /// Returns `None` if the glyph has no `COLR` definition or if the glyph
2276    /// definition is malformed.
2277    ///
2278    /// See `examples/font2svg.rs` for usage examples.
2279    #[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    /// Returns an iterator over variation axes.
2298    #[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    /// Sets a variation axis coordinate.
2305    ///
2306    /// This is one of the two only mutable methods in the library.
2307    /// We can simplify the API a lot by storing the variable coordinates
2308    /// in the face object itself.
2309    ///
2310    /// Since coordinates are stored on the stack, we allow only 64 of them.
2311    ///
2312    /// Returns `None` when face is not variable or doesn't have such axis.
2313    #[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    /// Returns the current normalized variation coordinates.
2337    #[cfg(feature = "variable-fonts")]
2338    #[inline]
2339    pub fn variation_coordinates(&self) -> &[NormalizedCoordinate] {
2340        self.coordinates.as_slice()
2341    }
2342
2343    /// Checks that face has non-default variation coordinates.
2344    #[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    /// Parses glyph's phantom points.
2351    ///
2352    /// Available only for variable fonts with the `gvar` table.
2353    #[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            // TODO: Should probably round it, but f32::round is not available in core.
2381            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/// Returns the number of fonts stored in a TrueType font collection.
2405///
2406/// Returns `None` if a provided data is not a TrueType font collection.
2407#[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>(); // version
2415    s.read::<u32>()
2416}