owned_ttf_parser/
preparse.rs

1//! Logic to avoid re-parsing subtables in ttf_parser::Face methods
2use crate::{AsFaceRef, FaceMut, OwnedFace};
3#[cfg(not(feature = "std"))]
4use alloc::vec::Vec;
5use core::fmt;
6use ttf_parser::{cmap, kern, Face, GlyphId};
7
8/// A `Face` with cmap & kern subtables parsed once on initialization.
9///
10/// Provides much faster [`PreParsedSubtables::glyph_index`] &
11/// [`PreParsedSubtables::glyphs_hor_kerning`] methods compared to the
12/// `.as_face_ref()` equivalents that must parse their subtables on each call.
13///
14/// # Example
15/// ```
16/// use owned_ttf_parser::{AsFaceRef, GlyphId, OwnedFace, PreParsedSubtables};
17///
18/// # let owned_font_data = include_bytes!("../fonts/font.ttf").to_vec();
19/// let owned_face = OwnedFace::from_vec(owned_font_data, 0).unwrap();
20/// let faster_face = PreParsedSubtables::from(owned_face);
21///
22/// // Lookup a GlyphId using the pre-parsed cmap subtables
23/// // this is much faster than doing: .as_face_ref().glyph_index('x')
24/// assert_eq!(faster_face.glyph_index('x'), Some(GlyphId(91)));
25///
26/// // The rest of the methods are still available as normal
27/// assert_eq!(faster_face.as_face_ref().ascender(), 2254);
28/// ```
29#[derive(Clone)]
30pub struct PreParsedSubtables<'face, F> {
31    pub(crate) face: F,
32    // note must not be public as could be self-referencing
33    pub(crate) subtables: FaceSubtables<'face>,
34}
35
36impl<'face> From<Face<'face>> for PreParsedSubtables<'face, Face<'face>> {
37    fn from(face: Face<'face>) -> Self {
38        let subtables = FaceSubtables::from(&face);
39        Self { face, subtables }
40    }
41}
42
43impl From<OwnedFace> for PreParsedSubtables<'static, OwnedFace> {
44    fn from(face: OwnedFace) -> Self {
45        face.pre_parse_subtables()
46    }
47}
48
49impl<F> fmt::Debug for PreParsedSubtables<'_, F> {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        write!(f, "PreParsedSubtables")
52    }
53}
54
55#[derive(Clone)]
56pub(crate) struct FaceSubtables<'face> {
57    /// Unicode cmap subtables.
58    cmap: Vec<cmap::Subtable<'face>>,
59    /// Horizontal kern subtables.
60    h_kern: Vec<kern::Subtable<'face>>,
61}
62
63impl<'face> From<&Face<'face>> for FaceSubtables<'face> {
64    fn from(face: &Face<'face>) -> Self {
65        let cmap = face
66            .tables()
67            .cmap
68            .iter()
69            .flat_map(|cmap| cmap.subtables)
70            .filter(|st| st.is_unicode())
71            .collect();
72        let h_kern = face
73            .tables()
74            .kern
75            .iter()
76            .flat_map(|c| c.subtables)
77            .filter(|st| st.horizontal && !st.variable)
78            .collect();
79        Self { cmap, h_kern }
80    }
81}
82
83impl<F> PreParsedSubtables<'_, F> {
84    /// Maps a character to a `GlyphId` using pre-parsed unicode cmap subtables.
85    #[inline]
86    pub fn glyph_index(&self, c: char) -> Option<GlyphId> {
87        self.subtables
88            .cmap
89            .iter()
90            .find_map(|t| t.glyph_index(c.into()))
91    }
92
93    /// Returns horizontal kerning for a pair of glyphs using pre-parsed kern subtables.
94    #[inline]
95    pub fn glyphs_hor_kerning(&self, first: GlyphId, second: GlyphId) -> Option<i16> {
96        self.subtables
97            .h_kern
98            .iter()
99            .find_map(|st| st.glyphs_kerning(first, second))
100    }
101}
102
103impl<F> AsFaceRef for PreParsedSubtables<'_, F>
104where
105    F: AsFaceRef,
106{
107    #[inline]
108    fn as_face_ref(&self) -> &ttf_parser::Face<'_> {
109        self.face.as_face_ref()
110    }
111}
112impl<F> AsFaceRef for &PreParsedSubtables<'_, F>
113where
114    F: AsFaceRef,
115{
116    #[inline]
117    fn as_face_ref(&self) -> &ttf_parser::Face<'_> {
118        (*self).as_face_ref()
119    }
120}
121
122impl<F> FaceMut for PreParsedSubtables<'_, F>
123where
124    F: FaceMut,
125{
126    #[inline]
127    fn set_variation(&mut self, axis: ttf_parser::Tag, value: f32) -> Option<()> {
128        self.face.set_variation(axis, value)
129    }
130}
131impl<F> FaceMut for &mut PreParsedSubtables<'_, F>
132where
133    F: FaceMut,
134{
135    #[inline]
136    fn set_variation(&mut self, axis: ttf_parser::Tag, value: f32) -> Option<()> {
137        (*self).set_variation(axis, value)
138    }
139}