1#[cfg(feature = "std")]
4mod closure;
5
6mod feature;
7mod lookup_flag;
8mod script;
9
10use core::cmp::Ordering;
11
12pub use lookup_flag::LookupFlag;
13pub use script::{ScriptTags, SelectedScript, UNICODE_TO_NEW_OPENTYPE_SCRIPT_TAGS};
14
15use super::variations::DeltaSetIndex;
16
17#[cfg(feature = "std")]
18use crate::collections::IntSet;
19
20#[cfg(feature = "std")]
21pub(crate) use closure::{
22 ContextFormat1, ContextFormat2, ContextFormat3, LayoutLookupList, LookupClosure,
23 LookupClosureCtx, MAX_LOOKUP_VISIT_COUNT, MAX_NESTING_LEVEL,
24};
25
26#[cfg(feature = "std")]
27pub use closure::Intersect;
28
29#[cfg(test)]
30mod spec_tests;
31
32include!("../../generated/generated_layout.rs");
33
34impl<'a, T: FontRead<'a>> Lookup<'a, T> {
35 pub fn get_subtable(&self, offset: Offset16) -> Result<T, ReadError> {
36 self.resolve_offset(offset)
37 }
38
39 #[cfg(feature = "experimental_traverse")]
40 fn traverse_lookup_flag(&self) -> traversal::FieldType<'a> {
41 self.lookup_flag().to_bits().into()
42 }
43}
44
45pub trait ExtensionLookup<'a, T: FontRead<'a>>: FontRead<'a> {
50 fn extension(&self) -> Result<T, ReadError>;
51}
52
53pub enum Subtables<'a, T: FontRead<'a>, Ext: ExtensionLookup<'a, T>> {
58 Subtable(ArrayOfOffsets<'a, T>),
59 Extension(ArrayOfOffsets<'a, Ext>),
60}
61
62impl<'a, T: FontRead<'a> + 'a, Ext: ExtensionLookup<'a, T> + 'a> Subtables<'a, T, Ext> {
63 pub(crate) fn new(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
65 Subtables::Subtable(ArrayOfOffsets::new(offsets, data, ()))
66 }
67
68 pub(crate) fn new_ext(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
70 Subtables::Extension(ArrayOfOffsets::new(offsets, data, ()))
71 }
72
73 pub fn len(&self) -> usize {
75 match self {
76 Subtables::Subtable(inner) => inner.len(),
77 Subtables::Extension(inner) => inner.len(),
78 }
79 }
80
81 pub fn is_empty(&self) -> bool {
82 self.len() == 0
83 }
84
85 pub fn get(&self, idx: usize) -> Result<T, ReadError> {
87 match self {
88 Subtables::Subtable(inner) => inner.get(idx),
89 Subtables::Extension(inner) => inner.get(idx).and_then(|ext| ext.extension()),
90 }
91 }
92
93 pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
95 let (left, right) = match self {
96 Subtables::Subtable(inner) => (Some(inner.iter()), None),
97 Subtables::Extension(inner) => (
98 None,
99 Some(inner.iter().map(|ext| ext.and_then(|ext| ext.extension()))),
100 ),
101 };
102 left.into_iter()
103 .flatten()
104 .chain(right.into_iter().flatten())
105 }
106}
107
108pub enum FeatureParams<'a> {
110 StylisticSet(StylisticSetParams<'a>),
111 Size(SizeParams<'a>),
112 CharacterVariant(CharacterVariantParams<'a>),
113}
114
115impl ReadArgs for FeatureParams<'_> {
116 type Args = Tag;
117}
118
119impl<'a> FontReadWithArgs<'a> for FeatureParams<'a> {
120 fn read_with_args(bytes: FontData<'a>, args: &Tag) -> Result<FeatureParams<'a>, ReadError> {
121 match *args {
122 t if t == Tag::new(b"size") => SizeParams::read(bytes).map(Self::Size),
123 t if &t.to_raw()[..2] == b"ss" => {
125 StylisticSetParams::read(bytes).map(Self::StylisticSet)
126 }
127 t if &t.to_raw()[..2] == b"cv" => {
128 CharacterVariantParams::read(bytes).map(Self::CharacterVariant)
129 }
130 _ => Err(ReadError::InvalidFormat(0xdead)),
133 }
134 }
135}
136
137#[cfg(feature = "experimental_traverse")]
138impl<'a> SomeTable<'a> for FeatureParams<'a> {
139 fn type_name(&self) -> &str {
140 match self {
141 FeatureParams::StylisticSet(table) => table.type_name(),
142 FeatureParams::Size(table) => table.type_name(),
143 FeatureParams::CharacterVariant(table) => table.type_name(),
144 }
145 }
146
147 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
148 match self {
149 FeatureParams::StylisticSet(table) => table.get_field(idx),
150 FeatureParams::Size(table) => table.get_field(idx),
151 FeatureParams::CharacterVariant(table) => table.get_field(idx),
152 }
153 }
154}
155
156impl FeatureTableSubstitutionRecord {
157 pub fn alternate_feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
158 self.alternate_feature_offset()
159 .resolve_with_args(data, &Tag::new(b"NULL"))
160 }
161}
162
163fn bit_storage(v: u32) -> u32 {
164 u32::BITS - v.leading_zeros()
165}
166
167impl<'a> CoverageTable<'a> {
168 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + 'a {
169 let (iter1, iter2) = match self {
171 CoverageTable::Format1(t) => (Some(t.glyph_array().iter().map(|g| g.get())), None),
172 CoverageTable::Format2(t) => {
173 let iter = t.range_records().iter().flat_map(RangeRecord::iter);
174 (None, Some(iter))
175 }
176 };
177
178 iter1
179 .into_iter()
180 .flatten()
181 .chain(iter2.into_iter().flatten())
182 }
183
184 #[inline]
186 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
187 match self {
188 CoverageTable::Format1(sub) => sub.get(gid),
189 CoverageTable::Format2(sub) => sub.get(gid),
190 }
191 }
192
193 #[cfg(feature = "std")]
195 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
196 match self {
197 CoverageTable::Format1(sub) => sub.intersects(glyphs),
198 CoverageTable::Format2(sub) => sub.intersects(glyphs),
199 }
200 }
201
202 #[cfg(feature = "std")]
204 pub fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
205 match self {
206 CoverageTable::Format1(sub) => sub.intersect_set(glyphs),
207 CoverageTable::Format2(sub) => sub.intersect_set(glyphs),
208 }
209 }
210
211 pub fn population(&self) -> usize {
213 match self {
214 CoverageTable::Format1(sub) => sub.population(),
215 CoverageTable::Format2(sub) => sub.population(),
216 }
217 }
218
219 pub fn cost(&self) -> u32 {
221 match self {
222 CoverageTable::Format1(sub) => sub.cost(),
223 CoverageTable::Format2(sub) => sub.cost(),
224 }
225 }
226}
227
228impl CoverageFormat1<'_> {
229 #[inline]
231 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
232 let gid16: GlyphId16 = gid.into().try_into().ok()?;
233 let be_glyph: BigEndian<GlyphId16> = gid16.into();
234 self.glyph_array()
235 .binary_search(&be_glyph)
236 .ok()
237 .map(|idx| idx as _)
238 }
239
240 #[cfg(feature = "std")]
242 fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
243 let glyph_count = self.glyph_count() as u32;
244 let num_bits = 32 - glyph_count.leading_zeros();
245 if glyph_count > (glyphs.len() as u32) * num_bits {
246 glyphs.iter().any(|g| self.get(g).is_some())
247 } else {
248 self.glyph_array()
249 .iter()
250 .any(|g| glyphs.contains(GlyphId::from(g.get())))
251 }
252 }
253
254 #[cfg(feature = "std")]
256 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
257 let glyph_count = self.glyph_count() as u32;
258 let num_bits = 32 - glyph_count.leading_zeros();
259 if glyph_count > (glyphs.len() as u32) * num_bits {
260 glyphs
261 .iter()
262 .filter_map(|g| self.get(g).map(|_| g))
263 .collect()
264 } else {
265 self.glyph_array()
266 .iter()
267 .filter(|g| glyphs.contains(GlyphId::from(g.get())))
268 .map(|g| GlyphId::from(g.get()))
269 .collect()
270 }
271 }
272
273 pub fn population(&self) -> usize {
275 self.glyph_count() as usize
276 }
277
278 pub fn cost(&self) -> u32 {
280 bit_storage(self.glyph_count() as u32)
281 }
282}
283
284impl CoverageFormat2<'_> {
285 #[inline]
287 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
288 let gid: GlyphId16 = gid.into().try_into().ok()?;
289 self.range_records()
290 .binary_search_by(|rec| {
291 if rec.end_glyph_id() < gid {
292 Ordering::Less
293 } else if rec.start_glyph_id() > gid {
294 Ordering::Greater
295 } else {
296 Ordering::Equal
297 }
298 })
299 .ok()
300 .map(|idx| {
301 let rec = &self.range_records()[idx];
302 rec.start_coverage_index() + gid.to_u16() - rec.start_glyph_id().to_u16()
303 })
304 }
305
306 #[cfg(feature = "std")]
308 fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
309 let range_count = self.range_count() as u32;
310 let num_bits = 32 - range_count.leading_zeros();
311 if range_count > (glyphs.len() as u32) * num_bits {
312 glyphs.iter().any(|g| self.get(g).is_some())
313 } else {
314 self.range_records()
315 .iter()
316 .any(|record| record.intersects(glyphs))
317 }
318 }
319
320 #[cfg(feature = "std")]
322 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
323 let range_count = self.range_count() as u32;
324 let num_bits = 32 - range_count.leading_zeros();
325 if range_count > (glyphs.len() as u32) * num_bits {
326 glyphs
327 .iter()
328 .filter_map(|g| self.get(g).map(|_| g))
329 .collect()
330 } else {
331 let mut out = IntSet::empty();
332 let mut last = GlyphId16::from(0);
333 for record in self.range_records() {
334 let start_glyph = record.start_glyph_id();
336 if start_glyph < last {
337 break;
338 }
339 let end = record.end_glyph_id();
340 last = end;
341
342 let start = GlyphId::from(start_glyph);
343 if glyphs.contains(start) {
344 out.insert(start);
345 }
346
347 for g in glyphs.iter_after(start) {
348 if g.to_u32() > end.to_u32() {
349 break;
350 }
351 out.insert(g);
352 }
353 }
354 out
355 }
356 }
357
358 pub fn population(&self) -> usize {
360 self.range_records()
361 .iter()
362 .fold(0, |acc, record| acc + record.population())
363 }
364
365 pub fn cost(&self) -> u32 {
367 bit_storage(self.range_count() as u32)
368 }
369}
370
371impl RangeRecord {
372 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + '_ {
373 (self.start_glyph_id().to_u16()..=self.end_glyph_id().to_u16()).map(GlyphId16::new)
374 }
375
376 #[cfg(feature = "std")]
378 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
379 glyphs.intersects_range(
380 GlyphId::from(self.start_glyph_id())..=GlyphId::from(self.end_glyph_id()),
381 )
382 }
383
384 pub fn population(&self) -> usize {
386 let start = self.start_glyph_id().to_u32() as usize;
387 let end = self.end_glyph_id().to_u32() as usize;
388 if start > end {
389 0
390 } else {
391 end - start + 1
392 }
393 }
394}
395
396impl DeltaFormat {
397 pub(crate) fn value_count(self, start_size: u16, end_size: u16) -> usize {
398 let range_len = end_size.saturating_add(1).saturating_sub(start_size) as usize;
399 let val_per_word = match self {
400 DeltaFormat::Local2BitDeltas => 8,
401 DeltaFormat::Local4BitDeltas => 4,
402 DeltaFormat::Local8BitDeltas => 2,
403 _ => return 0,
404 };
405
406 let count = range_len / val_per_word;
407 let extra = (range_len % val_per_word).min(1);
408 count + extra
409 }
410}
411
412impl From<DeltaFormat> for i64 {
415 fn from(value: DeltaFormat) -> Self {
416 value as u16 as _
417 }
418}
419
420impl<'a> ClassDefFormat1<'a> {
421 #[inline]
423 pub fn get(&self, gid: GlyphId16) -> u16 {
424 if gid < self.start_glyph_id() {
425 return 0;
426 }
427 let idx = gid.to_u16() - self.start_glyph_id().to_u16();
428 self.class_value_array()
429 .get(idx as usize)
430 .map(|x| x.get())
431 .unwrap_or(0)
432 }
433
434 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
436 let start = self.start_glyph_id();
437 self.class_value_array()
438 .iter()
439 .enumerate()
440 .map(move |(i, val)| {
441 let gid = start.to_u16().saturating_add(i as u16);
442 (GlyphId16::new(gid), val.get())
443 })
444 }
445
446 pub fn population(&self) -> usize {
448 self.glyph_count() as usize
449 }
450
451 pub fn cost(&self) -> u32 {
453 1
454 }
455
456 #[cfg(feature = "std")]
458 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
459 let mut out = IntSet::empty();
460 if glyphs.is_empty() {
461 return out;
462 }
463
464 let start_glyph = self.start_glyph_id().to_u32();
465 let glyph_count = self.glyph_count();
466 let end_glyph = start_glyph + glyph_count as u32 - 1;
467 if glyphs.first().unwrap().to_u32() < start_glyph
468 || glyphs.last().unwrap().to_u32() > end_glyph
469 {
470 out.insert(0);
471 }
472
473 let class_values = self.class_value_array();
474 if glyphs.contains(GlyphId::from(start_glyph)) {
475 let Some(start_glyph_class) = class_values.first() else {
476 return out;
477 };
478 out.insert(start_glyph_class.get());
479 }
480
481 for g in glyphs.iter_after(GlyphId::from(start_glyph)) {
482 let g = g.to_u32();
483 if g > end_glyph {
484 break;
485 }
486
487 let idx = g - start_glyph;
488 let Some(class) = class_values.get(idx as usize) else {
489 break;
490 };
491 out.insert(class.get());
492 }
493 out
494 }
495
496 #[cfg(feature = "std")]
498 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
499 let mut out = IntSet::empty();
500 if glyphs.is_empty() {
501 return out;
502 }
503
504 let start_glyph = self.start_glyph_id().to_u32();
505 let glyph_count = self.glyph_count();
506 let end_glyph = start_glyph + glyph_count as u32 - 1;
507 if class == 0 {
508 let first = glyphs.first().unwrap();
509 if first.to_u32() < start_glyph {
510 out.extend(glyphs.range(first..GlyphId::from(start_glyph)));
511 }
512
513 let last = glyphs.last().unwrap();
514 if last.to_u32() > end_glyph {
515 out.extend(glyphs.range(GlyphId::from(end_glyph + 1)..=last));
516 }
517 return out;
518 }
519
520 let class_values = self.class_value_array();
521 for g in glyphs.range(GlyphId::from(start_glyph)..=GlyphId::from(end_glyph)) {
522 let idx = g.to_u32() - start_glyph;
523 let Some(c) = class_values.get(idx as usize) else {
524 break;
525 };
526 if c.get() == class {
527 out.insert(g);
528 }
529 }
530 out
531 }
532}
533
534impl<'a> ClassDefFormat2<'a> {
535 #[inline]
537 pub fn get(&self, gid: GlyphId16) -> u16 {
538 let records = self.class_range_records();
539 let ix = match records.binary_search_by(|rec| rec.start_glyph_id().cmp(&gid)) {
540 Ok(ix) => ix,
541 Err(ix) => ix.saturating_sub(1),
542 };
543 if let Some(record) = records.get(ix) {
544 if (record.start_glyph_id()..=record.end_glyph_id()).contains(&gid) {
545 return record.class();
546 }
547 }
548 0
549 }
550
551 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
553 self.class_range_records().iter().flat_map(|range| {
554 let start = range.start_glyph_id().to_u16();
555 let end = range.end_glyph_id().to_u16();
556 (start..=end).map(|gid| (GlyphId16::new(gid), range.class()))
557 })
558 }
559
560 pub fn population(&self) -> usize {
562 self.class_range_records()
563 .iter()
564 .fold(0, |acc, record| acc + record.population())
565 }
566
567 pub fn cost(&self) -> u32 {
569 bit_storage(self.class_range_count() as u32)
570 }
571
572 #[cfg(feature = "std")]
574 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
575 let mut out = IntSet::empty();
576 if glyphs.is_empty() {
577 return out;
578 }
579
580 if self.class_range_count() == 0 {
581 out.insert(0);
582 return out;
583 }
584
585 let range_records = self.class_range_records();
586 let first_record = range_records[0];
587
588 if glyphs.first().unwrap() < first_record.start_glyph_id() {
589 out.insert(0);
590 } else {
591 let mut glyph = GlyphId::from(first_record.end_glyph_id());
592 for record in range_records.iter().skip(1) {
593 let Some(g) = glyphs.iter_after(glyph).next() else {
594 break;
595 };
596
597 if g < record.start_glyph_id() {
598 out.insert(0);
599 break;
600 }
601 glyph = GlyphId::from(record.end_glyph_id());
602 }
603 if glyphs.iter_after(glyph).next().is_some() {
604 out.insert(0);
605 }
606 }
607
608 let num_ranges = self.class_range_count();
609 let num_bits = 16 - num_ranges.leading_zeros();
610 if num_ranges as u64 > glyphs.len() * num_bits as u64 {
611 for g in glyphs.iter() {
612 let class = self.get(GlyphId16::from(g.to_u32() as u16));
613 if class != 0 {
614 out.insert(class);
615 }
616 }
617 } else {
618 for record in range_records {
619 if glyphs.intersects_range(
620 GlyphId::from(record.start_glyph_id())..=GlyphId::from(record.end_glyph_id()),
621 ) {
622 out.insert(record.class());
623 }
624 }
625 }
626 out
627 }
628
629 #[cfg(feature = "std")]
631 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
632 let mut out = IntSet::empty();
633 if glyphs.is_empty() {
634 return out;
635 }
636
637 let first = glyphs.first().unwrap().to_u32();
638 let last = glyphs.last().unwrap().to_u32();
639 if class == 0 {
640 let mut start = first;
641 for range in self.class_range_records() {
642 let range_start = range.start_glyph_id().to_u32();
643 if start < range_start {
644 out.extend(glyphs.range(GlyphId::from(start)..GlyphId::from(range_start)));
645 }
646
647 let range_end = range.end_glyph_id().to_u32();
648 if range_end >= last {
649 break;
650 }
651 start = range_end + 1;
652 }
653 return out;
654 }
655
656 let num_ranges = self.class_range_count();
657 let num_bits = 16 - num_ranges.leading_zeros();
658 if num_ranges as u64 > glyphs.len() * num_bits as u64 {
659 for g in glyphs.iter() {
660 let c = self.get(GlyphId16::from(g.to_u32() as u16));
661 if c == class {
662 out.insert(g);
663 }
664 }
665 } else {
666 for range in self.class_range_records() {
667 let range_start = range.start_glyph_id().to_u32();
668 let range_end = range.end_glyph_id().to_u32();
669 if range_start > last || range.end_glyph_id().to_u32() < first {
670 break;
671 }
672 if range.class() != class {
673 continue;
674 }
675 out.extend(glyphs.range(GlyphId::from(range_start)..=GlyphId::from(range_end)));
676 }
677 }
678 out
679 }
680}
681
682impl ClassRangeRecord {
683 pub fn population(&self) -> usize {
685 let start = self.start_glyph_id().to_u32() as usize;
686 let end = self.end_glyph_id().to_u32() as usize;
687 if start > end {
688 0
689 } else {
690 end - start + 1
691 }
692 }
693}
694
695impl ClassDef<'_> {
696 #[inline]
698 pub fn get(&self, gid: GlyphId16) -> u16 {
699 match self {
700 ClassDef::Format1(table) => table.get(gid),
701 ClassDef::Format2(table) => table.get(gid),
702 }
703 }
704
705 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + '_ {
709 let (one, two) = match self {
710 ClassDef::Format1(inner) => (Some(inner.iter()), None),
711 ClassDef::Format2(inner) => (None, Some(inner.iter())),
712 };
713 one.into_iter().flatten().chain(two.into_iter().flatten())
714 }
715
716 pub fn population(&self) -> usize {
718 match self {
719 ClassDef::Format1(table) => table.population(),
720 ClassDef::Format2(table) => table.population(),
721 }
722 }
723
724 pub fn cost(&self) -> u32 {
726 match self {
727 ClassDef::Format1(sub) => sub.cost(),
728 ClassDef::Format2(sub) => sub.cost(),
729 }
730 }
731
732 #[cfg(feature = "std")]
734 pub fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
735 match self {
736 ClassDef::Format1(table) => table.intersect_classes(glyphs),
737 ClassDef::Format2(table) => table.intersect_classes(glyphs),
738 }
739 }
740
741 #[cfg(feature = "std")]
743 pub fn intersected_class_glyphs(
744 &self,
745 glyphs: &IntSet<GlyphId>,
746 class: u16,
747 ) -> IntSet<GlyphId> {
748 match self {
749 ClassDef::Format1(table) => table.intersected_class_glyphs(glyphs, class),
750 ClassDef::Format2(table) => table.intersected_class_glyphs(glyphs, class),
751 }
752 }
753}
754
755impl<'a> Device<'a> {
756 pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
758 let format = self.delta_format();
759 let mut n = (self.end_size() - self.start_size()) as usize + 1;
760 let deltas_per_word = match format {
761 DeltaFormat::Local2BitDeltas => 8,
762 DeltaFormat::Local4BitDeltas => 4,
763 DeltaFormat::Local8BitDeltas => 2,
764 _ => 0,
765 };
766
767 self.delta_value().iter().flat_map(move |val| {
768 let iter = iter_packed_values(val.get(), format, n);
769 n = n.saturating_sub(deltas_per_word);
770 iter
771 })
772 }
773}
774
775fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
776 let mut decoded = [None; 8];
777 let (mask, sign_mask, bits) = match format {
778 DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
779 DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
780 DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
781 _ => (0, 0, 0),
782 };
783
784 let max_per_word = 16 / bits;
785 #[allow(clippy::needless_range_loop)] for i in 0..n.min(max_per_word) {
787 let mask = mask << ((16 - bits) - i * bits);
788 let val = (raw & mask) >> ((16 - bits) - i * bits);
789 let sign = val & sign_mask != 0;
790
791 let val = if sign {
792 -((((!val) & mask) + 1) as i8)
794 } else {
795 val as i8
796 };
797 decoded[i] = Some(val)
798 }
799 decoded.into_iter().flatten()
800}
801
802impl From<VariationIndex<'_>> for DeltaSetIndex {
803 fn from(src: VariationIndex) -> DeltaSetIndex {
804 DeltaSetIndex {
805 outer: src.delta_set_outer_index(),
806 inner: src.delta_set_inner_index(),
807 }
808 }
809}
810
811#[derive(Clone)]
817pub struct TaggedElement<T> {
818 pub tag: Tag,
819 pub element: T,
820}
821
822impl<T> TaggedElement<T> {
823 pub fn new(tag: Tag, element: T) -> Self {
824 Self { tag, element }
825 }
826}
827
828impl<T> std::ops::Deref for TaggedElement<T> {
829 type Target = T;
830
831 fn deref(&self) -> &Self::Target {
832 &self.element
833 }
834}
835
836#[cfg(test)]
837mod tests {
838 use super::*;
839
840 #[test]
841 fn coverage_get_format1() {
842 const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
844
845 let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
846 assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
847 assert_eq!(coverage.get(GlyphId::new(2)), None);
848 assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
849 assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
850 assert_eq!(coverage.get(GlyphId::new(45)), None);
851 }
852
853 #[test]
854 fn coverage_get_format2() {
855 const COV2_DATA: FontData =
857 FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
858 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
859 assert_eq!(coverage.get(GlyphId::new(2)), None);
860 assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
861 assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
862 assert_eq!(coverage.get(GlyphId::new(10)), None);
863 assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
864 assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
865 assert_eq!(coverage.get(GlyphId::new(40)), None);
866 }
867
868 #[test]
869 fn classdef_get_format2() {
870 let classdef = ClassDef::read(FontData::new(
871 font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
872 ))
873 .unwrap();
874 assert!(matches!(classdef, ClassDef::Format2(..)));
875 let gid_class_pairs = [
876 (616, 1),
877 (617, 1),
878 (618, 1),
879 (624, 1),
880 (625, 1),
881 (626, 1),
882 (652, 2),
883 (653, 2),
884 (654, 2),
885 (655, 2),
886 (661, 2),
887 ];
888 for (gid, class) in gid_class_pairs {
889 assert_eq!(classdef.get(GlyphId16::new(gid)), class);
890 }
891 for (gid, class) in classdef.iter() {
892 assert_eq!(classdef.get(gid), class);
893 }
894 }
895
896 #[test]
897 fn delta_decode() {
898 assert_eq!(
900 iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
901 &[1, 2, 3, -1]
902 );
903
904 assert_eq!(
905 iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
906 &[1, 1, 1, 1, 1]
907 );
908 }
909
910 #[test]
911 fn delta_decode_all() {
912 let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
914 let device = Device::read(bytes.into()).unwrap();
915 assert_eq!(
916 device.iter().collect::<Vec<_>>(),
917 &[1i8, -12, 30, -11, 101, 8, 42]
918 );
919 }
920
921 #[test]
922 fn bit_storage_tests() {
923 assert_eq!(bit_storage(0), 0);
924 assert_eq!(bit_storage(1), 1);
925 assert_eq!(bit_storage(2), 2);
926 assert_eq!(bit_storage(4), 3);
927 assert_eq!(bit_storage(9), 4);
928 assert_eq!(bit_storage(0x123), 9);
929 assert_eq!(bit_storage(0x1234), 13);
930 assert_eq!(bit_storage(0xffff), 16);
931 assert_eq!(bit_storage(0xffff_ffff), 32);
932 }
933}