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
//! Logic to avoid re-parsing subtables in ttf_parser::Face methods
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::fmt;
use ttf_parser::{cmap, kern, Face, GlyphId};

use crate::{AsFaceRef, OwnedFace};

/// 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> {
    pub(crate) 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()))
    }

    /// 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()
    }
}