ttf_parser/ggg/
layout_table.rs1#![allow(unused_variables)]
3
4use super::LookupList;
5use crate::parser::{FromData, LazyArray16, Offset, Offset16, Stream};
6use crate::Tag;
7#[cfg(feature = "variable-fonts")] use super::FeatureVariations;
8#[cfg(feature = "variable-fonts")] use crate::parser::Offset32;
9
10#[derive(Clone, Copy, Debug)]
12pub struct LayoutTable<'a> {
13 pub scripts: ScriptList<'a>,
15 pub features: FeatureList<'a>,
17 pub lookups: LookupList<'a>,
19 #[cfg(feature = "variable-fonts")]
22 pub variations: Option<FeatureVariations<'a>>,
23}
24
25impl<'a> LayoutTable<'a> {
26 pub(crate) fn parse(data: &'a [u8]) -> Option<Self> {
27 let mut s = Stream::new(data);
28
29 let major_version = s.read::<u16>()?;
30 let minor_version = s.read::<u16>()?;
31 if major_version != 1 {
32 return None;
33 }
34
35 let scripts = ScriptList::parse(s.read_at_offset16(data)?)?;
36 let features = FeatureList::parse(s.read_at_offset16(data)?)?;
37 let lookups = LookupList::parse(s.read_at_offset16(data)?)?;
38
39 #[cfg(feature = "variable-fonts")] {
40 let mut variations_offset = None;
41 if minor_version >= 1 {
42 variations_offset = s.read::<Option<Offset32>>()?;
43 }
44
45 let variations = match variations_offset {
46 Some(offset) => data.get(offset.to_usize()..).and_then(FeatureVariations::parse),
47 None => None,
48 };
49
50 Some(Self { scripts, features, lookups, variations })
51 }
52
53 #[cfg(not(feature = "variable-fonts"))] {
54 Some(Self { scripts, features, lookups })
55 }
56 }
57}
58
59pub type ScriptIndex = u16;
61pub type LanguageIndex = u16;
63pub type FeatureIndex = u16;
65pub type LookupIndex = u16;
67pub type VariationIndex = u32;
69
70pub trait RecordListItem<'a>: Sized {
74 fn parse(tag: Tag, data: &'a [u8]) -> Option<Self>;
76}
77
78#[derive(Clone, Copy, Debug)]
80pub struct RecordList<'a, T: RecordListItem<'a>> {
81 data: &'a [u8],
82 records: LazyArray16<'a, TagRecord>,
83 data_type: core::marker::PhantomData<T>,
84}
85
86impl<'a, T: RecordListItem<'a>> RecordList<'a, T> {
87 fn parse(data: &'a [u8]) -> Option<Self> {
88 let mut s = Stream::new(data);
89 let count = s.read::<u16>()?;
90 let records = s.read_array16(count)?;
91 Some(Self { data, records, data_type: core::marker::PhantomData })
92 }
93
94 pub fn len(&self) -> u16 {
96 self.records.len()
97 }
98
99 pub fn is_empty(&self) -> bool {
101 self.records.is_empty()
102 }
103
104 pub fn get(&self, index: u16) -> Option<T> {
106 let record = self.records.get(index)?;
107 self.data.get(record.offset.to_usize()..).and_then(|data| T::parse(record.tag, data))
108 }
109
110 pub fn find(&self, tag: Tag) -> Option<T> {
112 let record = self.records.binary_search_by(|record| record.tag.cmp(&tag)).map(|p| p.1)?;
113 self.data.get(record.offset.to_usize()..).and_then(|data| T::parse(record.tag, data))
114 }
115
116 pub fn index(&self, tag: Tag) -> Option<u16> {
118 self.records.binary_search_by(|record| record.tag.cmp(&tag)).map(|p| p.0)
119 }
120}
121
122impl<'a, T: RecordListItem<'a>> IntoIterator for RecordList<'a, T> {
123 type Item = T;
124 type IntoIter = RecordListIter<'a, T>;
125
126 #[inline]
127 fn into_iter(self) -> Self::IntoIter {
128 RecordListIter {
129 list: self,
130 index: 0,
131 }
132 }
133}
134
135#[allow(missing_debug_implementations)]
137pub struct RecordListIter<'a, T: RecordListItem<'a>> {
138 list: RecordList<'a, T>,
139 index: u16,
140}
141
142impl<'a, T: RecordListItem<'a>> Iterator for RecordListIter<'a, T> {
143 type Item = T;
144
145 fn next(&mut self) -> Option<Self::Item> {
146 if self.index < self.list.len() {
147 self.index += 1;
148 self.list.get(self.index - 1)
149 } else {
150 None
151 }
152 }
153}
154
155pub type ScriptList<'a> = RecordList<'a, Script<'a>>;
157pub type LanguageSystemList<'a> = RecordList<'a, LanguageSystem<'a>>;
159pub type FeatureList<'a> = RecordList<'a, Feature<'a>>;
161
162
163#[derive(Clone, Copy, Debug)]
164struct TagRecord {
165 tag: Tag,
166 offset: Offset16,
167}
168
169impl FromData for TagRecord {
170 const SIZE: usize = 6;
171
172 #[inline]
173 fn parse(data: &[u8]) -> Option<Self> {
174 let mut s = Stream::new(data);
175 Some(Self {
176 tag: s.read::<Tag>()?,
177 offset: s.read::<Offset16>()?,
178 })
179 }
180}
181
182#[derive(Clone, Copy, Debug)]
184pub struct Script<'a> {
185 pub tag: Tag,
187 pub default_language: Option<LanguageSystem<'a>>,
189 pub languages: LanguageSystemList<'a>,
191}
192
193impl<'a> RecordListItem<'a> for Script<'a> {
194 fn parse(tag: Tag, data: &'a [u8]) -> Option<Self> {
195 let mut s = Stream::new(data);
196 let mut default_language = None;
197 if let Some(offset) = s.read::<Option<Offset16>>()? {
198 default_language = LanguageSystem::parse(
199 Tag::from_bytes(b"dflt"),
200 data.get(offset.to_usize()..)?
201 );
202 }
203 let mut languages = RecordList::parse(s.tail()?)?;
204 languages.data = data;
206 Some(Self { tag, default_language, languages })
207 }
208}
209
210#[derive(Clone, Copy, Debug)]
212pub struct LanguageSystem<'a> {
213 pub tag: Tag,
215 pub required_feature: Option<FeatureIndex>,
217 pub feature_indices: LazyArray16<'a, FeatureIndex>
219}
220
221impl<'a> RecordListItem<'a> for LanguageSystem<'a> {
222 fn parse(tag: Tag, data: &'a [u8]) -> Option<Self> {
223 let mut s = Stream::new(data);
224 let _lookup_order = s.read::<Offset16>()?; let required_feature = match s.read::<FeatureIndex>()? {
226 0xFFFF => None,
227 v => Some(v),
228 };
229 let count = s.read::<u16>()?;
230 let feature_indices = s.read_array16(count)?;
231 Some(Self { tag, required_feature, feature_indices })
232 }
233}
234
235#[allow(missing_docs)]
237#[derive(Clone, Copy, Debug)]
238pub struct Feature<'a> {
239 pub tag: Tag,
240 pub lookup_indices: LazyArray16<'a, LookupIndex>,
241}
242
243impl<'a> RecordListItem<'a> for Feature<'a> {
244 fn parse(tag: Tag, data: &'a [u8]) -> Option<Self> {
245 let mut s = Stream::new(data);
246 let _params_offset = s.read::<Offset16>()?; let count = s.read::<u16>()?;
248 let lookup_indices = s.read_array16(count)?;
249 Some(Self { tag, lookup_indices })
250 }
251}