1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! Logic to avoid re-parsing subtables in ttf_parser::Face methods
use crate::{AsFaceRef, FaceMut, OwnedFace};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::fmt;
use ttf_parser::{cmap, kern, Face, GlyphId};

/// A `Face` with cmap & kern subtables parsed once on initialization.
///
/// Provides much faster [`PreParsedSubtables::glyph_index`] &
/// [`PreParsedSubtables::glyphs_hor_kerning`] methods compared to the
/// `.as_face_ref()` equivalents that must parse their subtables on each call.
///
/// # Example
/// ```
/// use owned_ttf_parser::{AsFaceRef, GlyphId, OwnedFace, PreParsedSubtables};
///
/// # let owned_font_data = include_bytes!("../fonts/font.ttf").to_vec();
/// let owned_face = OwnedFace::from_vec(owned_font_data, 0).unwrap();
/// let faster_face = PreParsedSubtables::from(owned_face);
///
/// // Lookup a GlyphId using the pre-parsed cmap subtables
/// // this is much faster than doing: .as_face_ref().glyph_index('x')
/// assert_eq!(faster_face.glyph_index('x'), Some(GlyphId(91)));
///
/// // The rest of the methods are still available as normal
/// assert_eq!(faster_face.as_face_ref().ascender(), 2254);
/// ```
#[derive(Clone)]
pub struct PreParsedSubtables<'face, F> {
    /// Underlying face.
    pub face: F,
    // note must not be public as could be self-referencing
    pub(crate) subtables: FaceSubtables<'face>,
}

impl<'face> From<Face<'face>> for PreParsedSubtables<'face, Face<'face>> {
    fn from(face: Face<'face>) -> Self {
        let subtables = FaceSubtables::from(&face);
        Self { face, subtables }
    }
}

impl From<OwnedFace> for PreParsedSubtables<'static, OwnedFace> {
    fn from(face: OwnedFace) -> Self {
        face.pre_parse_subtables()
    }
}

impl<F> fmt::Debug for PreParsedSubtables<'_, F> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "PreParsedSubtables")
    }
}

#[derive(Clone)]
pub(crate) struct FaceSubtables<'face> {
    /// Unicode cmap subtables.
    cmap: Vec<cmap::Subtable<'face>>,
    /// Horizontal kern subtables.
    h_kern: Vec<kern::Subtable<'face>>,
}

impl<'face> From<&Face<'face>> for FaceSubtables<'face> {
    fn from(face: &Face<'face>) -> Self {
        let cmap = face
            .tables()
            .cmap
            .iter()
            .flat_map(|cmap| cmap.subtables)
            .filter(|st| st.is_unicode())
            .collect();
        let h_kern = face
            .tables()
            .kern
            .iter()
            .flat_map(|c| c.subtables)
            .filter(|st| st.horizontal && !st.variable)
            .collect();
        Self { cmap, h_kern }
    }
}

impl<F> PreParsedSubtables<'_, F> {
    /// Maps a character to a `GlyphId` using pre-parsed unicode cmap subtables.
    #[inline]
    pub fn glyph_index(&self, c: char) -> Option<GlyphId> {
        self.subtables
            .cmap
            .iter()
            .find_map(|t| t.glyph_index(c.into()))
    }

    /// Maps a variation of a character to a `GlyphId` using pre-parsed unicode cmap subtables.
    #[inline]
    pub fn glyph_variation_index(&self, c: char, v: char) -> Option<GlyphId> {
        self.subtables
            .cmap
            .iter()
            .find_map(|t| t.glyph_variation_index(c.into(), v.into()))
            .and_then(|r| match r {
                cmap::GlyphVariationResult::Found(v) => Some(v),
                cmap::GlyphVariationResult::UseDefault => self.glyph_index(c),
            })
    }

    /// Returns horizontal kerning for a pair of glyphs using pre-parsed kern subtables.
    #[inline]
    pub fn glyphs_hor_kerning(&self, first: GlyphId, second: GlyphId) -> Option<i16> {
        self.subtables
            .h_kern
            .iter()
            .find_map(|st| st.glyphs_kerning(first, second))
    }
}

impl<F> AsFaceRef for PreParsedSubtables<'_, F>
where
    F: AsFaceRef,
{
    #[inline]
    fn as_face_ref(&self) -> &ttf_parser::Face<'_> {
        self.face.as_face_ref()
    }
}
impl<F> AsFaceRef for &PreParsedSubtables<'_, F>
where
    F: AsFaceRef,
{
    #[inline]
    fn as_face_ref(&self) -> &ttf_parser::Face<'_> {
        (*self).as_face_ref()
    }
}

impl<F> FaceMut for PreParsedSubtables<'_, F>
where
    F: FaceMut,
{
    #[inline]
    fn set_variation(&mut self, axis: ttf_parser::Tag, value: f32) -> Option<()> {
        self.face.set_variation(axis, value)
    }
}
impl<F> FaceMut for &mut PreParsedSubtables<'_, F>
where
    F: FaceMut,
{
    #[inline]
    fn set_variation(&mut self, axis: ttf_parser::Tag, value: f32) -> Option<()> {
        (*self).set_variation(axis, value)
    }
}