1use 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#[derive(Clone, Copy, Debug)]
25pub struct RangeRecord {
26 pub start: GlyphId,
28 pub end: GlyphId,
30 pub value: u16,
32}
33
34impl LazyArray16<'_, RangeRecord> {
35 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#[allow(missing_docs)]
67#[derive(Clone, Copy, Debug)]
68pub enum Coverage<'a> {
69 Format1 {
70 glyphs: LazyArray16<'a, GlyphId>,
72 },
73 Format2 {
74 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 pub fn contains(&self, glyph: GlyphId) -> bool {
101 self.get(glyph).is_some()
102 }
103
104 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
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}
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 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}