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    /// Underlying face.
32    pub face: F,
33    // note must not be public as could be self-referencing
34    pub(crate) subtables: FaceSubtables<'face>,
35}
36
37impl<'face> From<Face<'face>> for PreParsedSubtables<'face, Face<'face>> {
38    fn from(face: Face<'face>) -> Self {
39        let subtables = FaceSubtables::from(&face);
40        Self { face, subtables }
41    }
42}
43
44impl From<OwnedFace> for PreParsedSubtables<'static, OwnedFace> {
45    fn from(face: OwnedFace) -> Self {
46        face.pre_parse_subtables()
47    }
48}
49
50impl<F> fmt::Debug for PreParsedSubtables<'_, F> {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        write!(f, "PreParsedSubtables")
53    }
54}
55
56#[derive(Clone)]
57pub(crate) struct FaceSubtables<'face> {
58    /// Unicode cmap subtables.
59    cmap: Vec<cmap::Subtable<'face>>,
60    /// Horizontal kern subtables.
61    h_kern: Vec<kern::Subtable<'face>>,
62}
63
64impl<'face> From<&Face<'face>> for FaceSubtables<'face> {
65    fn from(face: &Face<'face>) -> Self {
66        let cmap = face
67            .tables()
68            .cmap
69            .iter()
70            .flat_map(|cmap| cmap.subtables)
71            .filter(|st| st.is_unicode())
72            .collect();
73        let h_kern = face
74            .tables()
75            .kern
76            .iter()
77            .flat_map(|c| c.subtables)
78            .filter(|st| st.horizontal && !st.variable)
79            .collect();
80        Self { cmap, h_kern }
81    }
82}
83
84impl<F> PreParsedSubtables<'_, F> {
85    /// Maps a character to a `GlyphId` using pre-parsed unicode cmap subtables.
86    #[inline]
87    pub fn glyph_index(&self, c: char) -> Option<GlyphId> {
88        self.subtables
89            .cmap
90            .iter()
91            .find_map(|t| t.glyph_index(c.into()))
92    }
93
94    /// Maps a variation of a character to a `GlyphId` using pre-parsed unicode cmap subtables.
95    #[inline]
96    pub fn glyph_variation_index(&self, c: char, v: char) -> Option<GlyphId> {
97        self.subtables
98            .cmap
99            .iter()
100            .find_map(|t| t.glyph_variation_index(c.into(), v.into()))
101            .and_then(|r| match r {
102                cmap::GlyphVariationResult::Found(v) => Some(v),
103                cmap::GlyphVariationResult::UseDefault => self.glyph_index(c),
104            })
105    }
106
107    /// Returns horizontal kerning for a pair of glyphs using pre-parsed kern subtables.
108    #[inline]
109    pub fn glyphs_hor_kerning(&self, first: GlyphId, second: GlyphId) -> Option<i16> {
110        self.subtables
111            .h_kern
112            .iter()
113            .find_map(|st| st.glyphs_kerning(first, second))
114    }
115}
116
117impl<F> AsFaceRef for PreParsedSubtables<'_, F>
118where
119    F: AsFaceRef,
120{
121    #[inline]
122    fn as_face_ref(&self) -> &ttf_parser::Face<'_> {
123        self.face.as_face_ref()
124    }
125}
126impl<F> AsFaceRef for &PreParsedSubtables<'_, F>
127where
128    F: AsFaceRef,
129{
130    #[inline]
131    fn as_face_ref(&self) -> &ttf_parser::Face<'_> {
132        (*self).as_face_ref()
133    }
134}
135
136impl<F> FaceMut for PreParsedSubtables<'_, F>
137where
138    F: FaceMut,
139{
140    #[inline]
141    fn set_variation(&mut self, axis: ttf_parser::Tag, value: f32) -> Option<()> {
142        self.face.set_variation(axis, value)
143    }
144}
145impl<F> FaceMut for &mut PreParsedSubtables<'_, F>
146where
147    F: FaceMut,
148{
149    #[inline]
150    fn set_variation(&mut self, axis: ttf_parser::Tag, value: f32) -> Option<()> {
151        (*self).set_variation(axis, value)
152    }
153}