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<'_> = 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: Vec> = faceimpl Iterator>
67 .tables()
68 .cmap
69 .iter()
70 .flat_map(|cmap: &Table<'_>| cmap.subtables)
71 .filter(|st: &Subtable<'_>| st.is_unicode())
72 .collect();
73 let h_kern: Vec> = faceimpl Iterator>
74 .tables()
75 .kern
76 .iter()
77 .flat_map(|c: &Table<'_>| c.subtables)
78 .filter(|st: &Subtable<'_>| 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}
154