1mod feature;
4mod lookup_flag;
5mod script;
6
7use core::cmp::Ordering;
8
9pub use lookup_flag::LookupFlag;
10pub use script::{ScriptTags, SelectedScript, UNICODE_TO_NEW_OPENTYPE_SCRIPT_TAGS};
11
12use super::variations::DeltaSetIndex;
13
14#[cfg(test)]
15#[path = "../tests/layout.rs"]
16mod spec_tests;
17
18include!("../../generated/generated_layout.rs");
19
20impl<'a, T: FontRead<'a>> Lookup<'a, T> {
21 pub fn get_subtable(&self, offset: Offset16) -> Result<T, ReadError> {
22 self.resolve_offset(offset)
23 }
24
25 #[cfg(feature = "experimental_traverse")]
26 fn traverse_lookup_flag(&self) -> traversal::FieldType<'a> {
27 self.lookup_flag().to_bits().into()
28 }
29}
30
31pub trait ExtensionLookup<'a, T: FontRead<'a>>: FontRead<'a> {
36 fn extension(&self) -> Result<T, ReadError>;
37}
38
39pub enum Subtables<'a, T: FontRead<'a>, Ext: ExtensionLookup<'a, T>> {
44 Subtable(ArrayOfOffsets<'a, T>),
45 Extension(ArrayOfOffsets<'a, Ext>),
46}
47
48impl<'a, T: FontRead<'a> + 'a, Ext: ExtensionLookup<'a, T> + 'a> Subtables<'a, T, Ext> {
49 pub(crate) fn new(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
51 Subtables::Subtable(ArrayOfOffsets::new(offsets, data, ()))
52 }
53
54 pub(crate) fn new_ext(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
56 Subtables::Extension(ArrayOfOffsets::new(offsets, data, ()))
57 }
58
59 pub fn len(&self) -> usize {
61 match self {
62 Subtables::Subtable(inner) => inner.len(),
63 Subtables::Extension(inner) => inner.len(),
64 }
65 }
66
67 pub fn is_empty(&self) -> bool {
68 self.len() == 0
69 }
70
71 pub fn get(&self, idx: usize) -> Result<T, ReadError> {
73 match self {
74 Subtables::Subtable(inner) => inner.get(idx),
75 Subtables::Extension(inner) => inner.get(idx).and_then(|ext| ext.extension()),
76 }
77 }
78
79 pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
81 let (left, right) = match self {
82 Subtables::Subtable(inner) => (Some(inner.iter()), None),
83 Subtables::Extension(inner) => (
84 None,
85 Some(inner.iter().map(|ext| ext.and_then(|ext| ext.extension()))),
86 ),
87 };
88 left.into_iter()
89 .flatten()
90 .chain(right.into_iter().flatten())
91 }
92}
93
94pub enum FeatureParams<'a> {
96 StylisticSet(StylisticSetParams<'a>),
97 Size(SizeParams<'a>),
98 CharacterVariant(CharacterVariantParams<'a>),
99}
100
101impl ReadArgs for FeatureParams<'_> {
102 type Args = Tag;
103}
104
105impl<'a> FontReadWithArgs<'a> for FeatureParams<'a> {
106 fn read_with_args(bytes: FontData<'a>, args: &Tag) -> Result<FeatureParams<'a>, ReadError> {
107 match *args {
108 t if t == Tag::new(b"size") => SizeParams::read(bytes).map(Self::Size),
109 t if &t.to_raw()[..2] == b"ss" => {
111 StylisticSetParams::read(bytes).map(Self::StylisticSet)
112 }
113 t if &t.to_raw()[..2] == b"cv" => {
114 CharacterVariantParams::read(bytes).map(Self::CharacterVariant)
115 }
116 _ => Err(ReadError::InvalidFormat(0xdead)),
119 }
120 }
121}
122
123#[cfg(feature = "experimental_traverse")]
124impl<'a> SomeTable<'a> for FeatureParams<'a> {
125 fn type_name(&self) -> &str {
126 match self {
127 FeatureParams::StylisticSet(table) => table.type_name(),
128 FeatureParams::Size(table) => table.type_name(),
129 FeatureParams::CharacterVariant(table) => table.type_name(),
130 }
131 }
132
133 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
134 match self {
135 FeatureParams::StylisticSet(table) => table.get_field(idx),
136 FeatureParams::Size(table) => table.get_field(idx),
137 FeatureParams::CharacterVariant(table) => table.get_field(idx),
138 }
139 }
140}
141
142impl FeatureTableSubstitutionRecord {
143 pub fn alternate_feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
144 self.alternate_feature_offset()
145 .resolve_with_args(data, &Tag::new(b"NULL"))
146 }
147}
148
149impl<'a> CoverageTable<'a> {
150 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + 'a {
151 let (iter1, iter2) = match self {
153 CoverageTable::Format1(t) => (Some(t.glyph_array().iter().map(|g| g.get())), None),
154 CoverageTable::Format2(t) => {
155 let iter = t.range_records().iter().flat_map(RangeRecord::iter);
156 (None, Some(iter))
157 }
158 };
159
160 iter1
161 .into_iter()
162 .flatten()
163 .chain(iter2.into_iter().flatten())
164 }
165
166 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
168 match self {
169 CoverageTable::Format1(sub) => sub.get(gid),
170 CoverageTable::Format2(sub) => sub.get(gid),
171 }
172 }
173}
174
175impl CoverageFormat1<'_> {
176 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
178 let gid16: GlyphId16 = gid.into().try_into().ok()?;
179 let be_glyph: BigEndian<GlyphId16> = gid16.into();
180 self.glyph_array()
181 .binary_search(&be_glyph)
182 .ok()
183 .map(|idx| idx as _)
184 }
185}
186
187impl CoverageFormat2<'_> {
188 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
190 let gid: GlyphId16 = gid.into().try_into().ok()?;
191 self.range_records()
192 .binary_search_by(|rec| {
193 if rec.end_glyph_id() < gid {
194 Ordering::Less
195 } else if rec.start_glyph_id() > gid {
196 Ordering::Greater
197 } else {
198 Ordering::Equal
199 }
200 })
201 .ok()
202 .map(|idx| {
203 let rec = &self.range_records()[idx];
204 rec.start_coverage_index() + gid.to_u16() - rec.start_glyph_id().to_u16()
205 })
206 }
207}
208
209impl RangeRecord {
210 fn iter(&self) -> impl Iterator<Item = GlyphId16> + '_ {
211 (self.start_glyph_id().to_u16()..=self.end_glyph_id().to_u16()).map(GlyphId16::new)
212 }
213}
214
215impl DeltaFormat {
216 pub(crate) fn value_count(self, start_size: u16, end_size: u16) -> usize {
217 let range_len = end_size.saturating_add(1).saturating_sub(start_size) as usize;
218 let val_per_word = match self {
219 DeltaFormat::Local2BitDeltas => 8,
220 DeltaFormat::Local4BitDeltas => 4,
221 DeltaFormat::Local8BitDeltas => 2,
222 _ => return 0,
223 };
224
225 let count = range_len / val_per_word;
226 let extra = (range_len % val_per_word).min(1);
227 count + extra
228 }
229}
230
231impl From<DeltaFormat> for i64 {
234 fn from(value: DeltaFormat) -> Self {
235 value as u16 as _
236 }
237}
238
239impl<'a> ClassDefFormat1<'a> {
240 pub fn get(&self, gid: GlyphId16) -> u16 {
242 if gid < self.start_glyph_id() {
243 return 0;
244 }
245 let idx = gid.to_u16() - self.start_glyph_id().to_u16();
246 self.class_value_array()
247 .get(idx as usize)
248 .map(|x| x.get())
249 .unwrap_or(0)
250 }
251
252 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
254 let start = self.start_glyph_id();
255 self.class_value_array()
256 .iter()
257 .enumerate()
258 .map(move |(i, val)| {
259 let gid = start.to_u16().saturating_add(i as u16);
260 (GlyphId16::new(gid), val.get())
261 })
262 }
263}
264
265impl<'a> ClassDefFormat2<'a> {
266 pub fn get(&self, gid: GlyphId16) -> u16 {
268 let records = self.class_range_records();
269 let ix = match records.binary_search_by(|rec| rec.start_glyph_id().cmp(&gid)) {
270 Ok(ix) => ix,
271 Err(ix) => ix.saturating_sub(1),
272 };
273 if let Some(record) = records.get(ix) {
274 if (record.start_glyph_id()..=record.end_glyph_id()).contains(&gid) {
275 return record.class();
276 }
277 }
278 0
279 }
280
281 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
283 self.class_range_records().iter().flat_map(|range| {
284 let start = range.start_glyph_id().to_u16();
285 let end = range.end_glyph_id().to_u16();
286 (start..=end).map(|gid| (GlyphId16::new(gid), range.class()))
287 })
288 }
289}
290
291impl ClassDef<'_> {
292 pub fn get(&self, gid: GlyphId16) -> u16 {
294 match self {
295 ClassDef::Format1(table) => table.get(gid),
296 ClassDef::Format2(table) => table.get(gid),
297 }
298 }
299
300 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + '_ {
304 let (one, two) = match self {
305 ClassDef::Format1(inner) => (Some(inner.iter()), None),
306 ClassDef::Format2(inner) => (None, Some(inner.iter())),
307 };
308 one.into_iter().flatten().chain(two.into_iter().flatten())
309 }
310}
311
312impl<'a> Device<'a> {
313 pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
315 let format = self.delta_format();
316 let mut n = (self.end_size() - self.start_size()) as usize + 1;
317 let deltas_per_word = match format {
318 DeltaFormat::Local2BitDeltas => 8,
319 DeltaFormat::Local4BitDeltas => 4,
320 DeltaFormat::Local8BitDeltas => 2,
321 _ => 0,
322 };
323
324 self.delta_value().iter().flat_map(move |val| {
325 let iter = iter_packed_values(val.get(), format, n);
326 n = n.saturating_sub(deltas_per_word);
327 iter
328 })
329 }
330}
331
332fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
333 let mut decoded = [None; 8];
334 let (mask, sign_mask, bits) = match format {
335 DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
336 DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
337 DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
338 _ => (0, 0, 0),
339 };
340
341 let max_per_word = 16 / bits;
342 #[allow(clippy::needless_range_loop)] for i in 0..n.min(max_per_word) {
344 let mask = mask << ((16 - bits) - i * bits);
345 let val = (raw & mask) >> ((16 - bits) - i * bits);
346 let sign = val & sign_mask != 0;
347
348 let val = if sign {
349 -((((!val) & mask) + 1) as i8)
351 } else {
352 val as i8
353 };
354 decoded[i] = Some(val)
355 }
356 decoded.into_iter().flatten()
357}
358
359impl From<VariationIndex<'_>> for DeltaSetIndex {
360 fn from(src: VariationIndex) -> DeltaSetIndex {
361 DeltaSetIndex {
362 outer: src.delta_set_outer_index(),
363 inner: src.delta_set_inner_index(),
364 }
365 }
366}
367
368#[derive(Clone)]
374pub struct TaggedElement<T> {
375 pub tag: Tag,
376 pub element: T,
377}
378
379impl<T> TaggedElement<T> {
380 pub fn new(tag: Tag, element: T) -> Self {
381 Self { tag, element }
382 }
383}
384
385impl<T> std::ops::Deref for TaggedElement<T> {
386 type Target = T;
387
388 fn deref(&self) -> &Self::Target {
389 &self.element
390 }
391}
392
393#[cfg(test)]
394mod tests {
395 use super::*;
396
397 #[test]
398 fn coverage_get_format1() {
399 const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
401
402 let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
403 assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
404 assert_eq!(coverage.get(GlyphId::new(2)), None);
405 assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
406 assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
407 assert_eq!(coverage.get(GlyphId::new(45)), None);
408 }
409
410 #[test]
411 fn coverage_get_format2() {
412 const COV2_DATA: FontData =
414 FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
415 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
416 assert_eq!(coverage.get(GlyphId::new(2)), None);
417 assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
418 assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
419 assert_eq!(coverage.get(GlyphId::new(10)), None);
420 assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
421 assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
422 assert_eq!(coverage.get(GlyphId::new(40)), None);
423 }
424
425 #[test]
426 fn classdef_get_format2() {
427 let classdef = ClassDef::read(FontData::new(
428 font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
429 ))
430 .unwrap();
431 assert!(matches!(classdef, ClassDef::Format2(..)));
432 let gid_class_pairs = [
433 (616, 1),
434 (617, 1),
435 (618, 1),
436 (624, 1),
437 (625, 1),
438 (626, 1),
439 (652, 2),
440 (653, 2),
441 (654, 2),
442 (655, 2),
443 (661, 2),
444 ];
445 for (gid, class) in gid_class_pairs {
446 assert_eq!(classdef.get(GlyphId16::new(gid)), class);
447 }
448 for (gid, class) in classdef.iter() {
449 assert_eq!(classdef.get(gid), class);
450 }
451 }
452
453 #[test]
454 fn delta_decode() {
455 assert_eq!(
457 iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
458 &[1, 2, 3, -1]
459 );
460
461 assert_eq!(
462 iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
463 &[1, 1, 1, 1, 1]
464 );
465 }
466
467 #[test]
468 fn delta_decode_all() {
469 let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
471 let device = Device::read(bytes.into()).unwrap();
472 assert_eq!(
473 device.iter().collect::<Vec<_>>(),
474 &[1i8, -12, 30, -11, 101, 8, 42]
475 );
476 }
477}