ttf_parser/ggg/
mod.rs

1//! Common data types used by GDEF/GPOS/GSUB tables.
2//!
3//! <https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2>
4
5// A heavily modified port of https://github.com/harfbuzz/rustybuzz implementation
6// originally written by https://github.com/laurmaedje
7
8use crate::parser::{FromData, FromSlice, LazyArray16, Stream};
9use crate::GlyphId;
10
11mod chained_context;
12mod context;
13#[cfg(feature = "variable-fonts")]
14mod feature_variations;
15mod layout_table;
16mod lookup;
17
18pub use chained_context::*;
19pub use context::*;
20#[cfg(feature = "variable-fonts")]
21pub use feature_variations::*;
22pub use layout_table::*;
23pub use lookup::*;
24
25/// A record that describes a range of glyph IDs.
26#[derive(Clone, Copy, Debug)]
27pub struct RangeRecord {
28    /// First glyph ID in the range
29    pub start: GlyphId,
30    /// Last glyph ID in the range
31    pub end: GlyphId,
32    /// Coverage Index of first glyph ID in range.
33    pub value: u16,
34}
35
36impl LazyArray16<'_, RangeRecord> {
37    /// Returns a [`RangeRecord`] for a glyph.
38    pub fn range(&self, glyph: GlyphId) -> Option<RangeRecord> {
39        self.binary_search_by(|record| {
40            if glyph < record.start {
41                core::cmp::Ordering::Greater
42            } else if glyph <= record.end {
43                core::cmp::Ordering::Equal
44            } else {
45                core::cmp::Ordering::Less
46            }
47        })
48        .map(|p| p.1)
49    }
50}
51
52impl FromData for RangeRecord {
53    const SIZE: usize = 6;
54
55    #[inline]
56    fn parse(data: &[u8]) -> Option<Self> {
57        let mut s = Stream::new(data);
58        Some(RangeRecord {
59            start: s.read::<GlyphId>()?,
60            end: s.read::<GlyphId>()?,
61            value: s.read::<u16>()?,
62        })
63    }
64}
65
66/// A [Coverage Table](
67/// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-table).
68#[allow(missing_docs)]
69#[derive(Clone, Copy, Debug)]
70pub enum Coverage<'a> {
71    Format1 {
72        /// Array of glyph IDs. Sorted.
73        glyphs: LazyArray16<'a, GlyphId>,
74    },
75    Format2 {
76        /// Array of glyph ranges. Ordered by `RangeRecord.start`.
77        records: LazyArray16<'a, RangeRecord>,
78    },
79}
80
81impl<'a> FromSlice<'a> for Coverage<'a> {
82    fn parse(data: &'a [u8]) -> Option<Self> {
83        let mut s = Stream::new(data);
84        match s.read::<u16>()? {
85            1 => {
86                let count = s.read::<u16>()?;
87                let glyphs = s.read_array16(count)?;
88                Some(Self::Format1 { glyphs })
89            }
90            2 => {
91                let count = s.read::<u16>()?;
92                let records = s.read_array16(count)?;
93                Some(Self::Format2 { records })
94            }
95            _ => None,
96        }
97    }
98}
99
100impl<'a> Coverage<'a> {
101    /// Checks that glyph is present.
102    pub fn contains(&self, glyph: GlyphId) -> bool {
103        self.get(glyph).is_some()
104    }
105
106    /// Returns the coverage index of the glyph or `None` if it is not covered.
107    pub fn get(&self, glyph: GlyphId) -> Option<u16> {
108        match self {
109            Self::Format1 { glyphs } => glyphs.binary_search(&glyph).map(|p| p.0),
110            Self::Format2 { records } => {
111                let record = records.range(glyph)?;
112                let offset = glyph.0 - record.start.0;
113                record.value.checked_add(offset)
114            }
115        }
116    }
117}
118
119/// A value of [Class Definition Table](
120/// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table).
121pub type Class = u16;
122
123/// A [Class Definition Table](
124/// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table).
125#[allow(missing_docs)]
126#[derive(Clone, Copy, Debug)]
127pub enum ClassDefinition<'a> {
128    Format1 {
129        start: GlyphId,
130        classes: LazyArray16<'a, Class>,
131    },
132    Format2 {
133        records: LazyArray16<'a, RangeRecord>,
134    },
135    Empty,
136}
137
138impl<'a> ClassDefinition<'a> {
139    #[inline]
140    pub(crate) fn parse(data: &'a [u8]) -> Option<Self> {
141        let mut s = Stream::new(data);
142        match s.read::<u16>()? {
143            1 => {
144                let start = s.read::<GlyphId>()?;
145                let count = s.read::<u16>()?;
146                let classes = s.read_array16(count)?;
147                Some(Self::Format1 { start, classes })
148            }
149            2 => {
150                let count = s.read::<u16>()?;
151                let records = s.read_array16(count)?;
152                Some(Self::Format2 { records })
153            }
154            _ => None,
155        }
156    }
157
158    /// Returns the glyph class of the glyph (zero if it is not defined).
159    pub fn get(&self, glyph: GlyphId) -> Class {
160        match self {
161            Self::Format1 { start, classes } => glyph
162                .0
163                .checked_sub(start.0)
164                .and_then(|index| classes.get(index)),
165            Self::Format2 { records } => records.range(glyph).map(|record| record.value),
166            Self::Empty => Some(0),
167        }
168        .unwrap_or(0)
169    }
170}