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::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: &RangeRecord| {
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: (u16, RangeRecord)| 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<'_> = 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<'_> = Stream::new(data);
84 match s.read::<u16>()? {
85 1 => {
86 let count: u16 = s.read::<u16>()?;
87 let glyphs: LazyArray16<'_, GlyphId> = s.read_array16(count)?;
88 Some(Self::Format1 { glyphs })
89 }
90 2 => {
91 let count: u16 = s.read::<u16>()?;
92 let records: LazyArray16<'_, RangeRecord> = 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: &LazyArray16<'_, GlyphId> } => glyphs.binary_search(&glyph).map(|p: (u16, GlyphId)| p.0),
110 Self::Format2 { records: &LazyArray16<'_, RangeRecord> } => {
111 let record: RangeRecord = records.range(glyph)?;
112 let offset: u16 = 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 } => glyph
161 .0
162 .checked_sub(start.0)
163 .and_then(|index| classes.get(index)),
164 Self::Format2 { records } => records.range(glyph).map(|record| record.value),
165 }
166 .unwrap_or(0)
167 }
168}
169