1use 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#[derive(Clone, Copy, Debug)]
27pub struct RangeRecord {
28 pub start: GlyphId,
30 pub end: GlyphId,
32 pub value: u16,
34}
35
36impl LazyArray16<'_, RangeRecord> {
37 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#[allow(missing_docs)]
69#[derive(Clone, Copy, Debug)]
70pub enum Coverage<'a> {
71 Format1 {
72 glyphs: LazyArray16<'a, GlyphId>,
74 },
75 Format2 {
76 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 pub fn contains(&self, glyph: GlyphId) -> bool {
103 self.get(glyph).is_some()
104 }
105
106 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
119pub type Class = u16;
122
123#[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 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}