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