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 if glyph_count > (glyphs.len() as u32) * self.cost() {
245 glyphs.iter().any(|g| self.get(g).is_some())
246 } else {
247 self.glyph_array()
248 .iter()
249 .any(|g| glyphs.contains(GlyphId::from(g.get())))
250 }
251 }
252
253 #[cfg(feature = "std")]
255 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
256 let glyph_count = self.glyph_count() as u32;
257 if glyph_count > (glyphs.len() as u32) * self.cost() {
258 glyphs
259 .iter()
260 .filter_map(|g| self.get(g).map(|_| g))
261 .collect()
262 } else {
263 self.glyph_array()
264 .iter()
265 .filter(|g| glyphs.contains(GlyphId::from(g.get())))
266 .map(|g| GlyphId::from(g.get()))
267 .collect()
268 }
269 }
270
271 pub fn population(&self) -> usize {
273 self.glyph_count() as usize
274 }
275
276 pub fn cost(&self) -> u32 {
278 bit_storage(self.glyph_count() as u32)
279 }
280}
281
282impl CoverageFormat2<'_> {
283 #[inline]
285 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
286 let gid: GlyphId16 = gid.into().try_into().ok()?;
287 self.range_records()
288 .binary_search_by(|rec| {
289 if rec.end_glyph_id() < gid {
290 Ordering::Less
291 } else if rec.start_glyph_id() > gid {
292 Ordering::Greater
293 } else {
294 Ordering::Equal
295 }
296 })
297 .ok()
298 .map(|idx| {
299 let rec = &self.range_records()[idx];
300 rec.start_coverage_index() + gid.to_u16() - rec.start_glyph_id().to_u16()
301 })
302 }
303
304 #[cfg(feature = "std")]
306 fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
307 let range_count = self.range_count() as u32;
308 if range_count > (glyphs.len() as u32) * self.cost() {
309 glyphs.iter().any(|g| self.get(g).is_some())
310 } else {
311 self.range_records()
312 .iter()
313 .any(|record| record.intersects(glyphs))
314 }
315 }
316
317 #[cfg(feature = "std")]
319 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
320 let range_count = self.range_count() as u32;
321 if range_count > (glyphs.len() as u32) * self.cost() {
322 glyphs
323 .iter()
324 .filter_map(|g| self.get(g).map(|_| g))
325 .collect()
326 } else {
327 let mut out = IntSet::empty();
328 let mut last = GlyphId16::from(0);
329 for record in self.range_records() {
330 let start_glyph = record.start_glyph_id();
332 if start_glyph < last {
333 break;
334 }
335 let end = record.end_glyph_id();
336 last = end;
337
338 let start = GlyphId::from(start_glyph);
339 if glyphs.contains(start) {
340 out.insert(start);
341 }
342
343 for g in glyphs.iter_after(start) {
344 if g.to_u32() > end.to_u32() {
345 break;
346 }
347 out.insert(g);
348 }
349 }
350 out
351 }
352 }
353
354 pub fn population(&self) -> usize {
356 self.range_records()
357 .iter()
358 .fold(0, |acc, record| acc + record.population())
359 }
360
361 pub fn cost(&self) -> u32 {
363 bit_storage(self.range_count() as u32)
364 }
365}
366
367impl RangeRecord {
368 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + '_ {
369 (self.start_glyph_id().to_u16()..=self.end_glyph_id().to_u16()).map(GlyphId16::new)
370 }
371
372 #[cfg(feature = "std")]
374 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
375 glyphs.intersects_range(
376 GlyphId::from(self.start_glyph_id())..=GlyphId::from(self.end_glyph_id()),
377 )
378 }
379
380 pub fn population(&self) -> usize {
382 let start = self.start_glyph_id().to_u32() as usize;
383 let end = self.end_glyph_id().to_u32() as usize;
384 if start > end {
385 0
386 } else {
387 end - start + 1
388 }
389 }
390}
391
392impl DeltaFormat {
393 pub(crate) fn value_count(self, start_size: u16, end_size: u16) -> usize {
394 let range_len = end_size.saturating_add(1).saturating_sub(start_size) as usize;
395 let val_per_word = match self {
396 DeltaFormat::Local2BitDeltas => 8,
397 DeltaFormat::Local4BitDeltas => 4,
398 DeltaFormat::Local8BitDeltas => 2,
399 _ => return 0,
400 };
401
402 let count = range_len / val_per_word;
403 let extra = (range_len % val_per_word).min(1);
404 count + extra
405 }
406}
407
408impl From<DeltaFormat> for i64 {
411 fn from(value: DeltaFormat) -> Self {
412 value as u16 as _
413 }
414}
415
416impl<'a> ClassDefFormat1<'a> {
417 #[inline]
419 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
420 let Some(idx) = gid
421 .into()
422 .to_u32()
423 .checked_sub(self.start_glyph_id().to_u32())
424 else {
425 return 0;
426 };
427 self.class_value_array()
428 .get(idx as usize)
429 .map(|x| x.get())
430 .unwrap_or(0)
431 }
432
433 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
435 let start = self.start_glyph_id();
436 self.class_value_array()
437 .iter()
438 .enumerate()
439 .map(move |(i, val)| {
440 let gid = start.to_u16().saturating_add(i as u16);
441 (GlyphId16::new(gid), val.get())
442 })
443 }
444
445 pub fn population(&self) -> usize {
447 self.glyph_count() as usize
448 }
449
450 pub fn cost(&self) -> u32 {
452 1
453 }
454
455 #[cfg(feature = "std")]
457 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
458 let mut out = IntSet::empty();
459 if glyphs.is_empty() {
460 return out;
461 }
462
463 let start_glyph = self.start_glyph_id().to_u32();
464 let glyph_count = self.glyph_count();
465 let end_glyph = start_glyph + glyph_count as u32 - 1;
466 if glyphs.first().unwrap().to_u32() < start_glyph
467 || glyphs.last().unwrap().to_u32() > end_glyph
468 {
469 out.insert(0);
470 }
471
472 let class_values = self.class_value_array();
473 if glyphs.contains(GlyphId::from(start_glyph)) {
474 let Some(start_glyph_class) = class_values.first() else {
475 return out;
476 };
477 out.insert(start_glyph_class.get());
478 }
479
480 for g in glyphs.iter_after(GlyphId::from(start_glyph)) {
481 let g = g.to_u32();
482 if g > end_glyph {
483 break;
484 }
485
486 let idx = g - start_glyph;
487 let Some(class) = class_values.get(idx as usize) else {
488 break;
489 };
490 out.insert(class.get());
491 }
492 out
493 }
494
495 #[cfg(feature = "std")]
497 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
498 let mut out = IntSet::empty();
499 if glyphs.is_empty() {
500 return out;
501 }
502
503 let start_glyph = self.start_glyph_id().to_u32();
504 let glyph_count = self.glyph_count();
505 let end_glyph = start_glyph + glyph_count as u32 - 1;
506 if class == 0 {
507 let first = glyphs.first().unwrap();
508 if first.to_u32() < start_glyph {
509 out.extend(glyphs.range(first..GlyphId::from(start_glyph)));
510 }
511
512 let last = glyphs.last().unwrap();
513 if last.to_u32() > end_glyph {
514 out.extend(glyphs.range(GlyphId::from(end_glyph + 1)..=last));
515 }
516 return out;
517 }
518
519 let class_values = self.class_value_array();
520 for g in glyphs.range(GlyphId::from(start_glyph)..=GlyphId::from(end_glyph)) {
521 let idx = g.to_u32() - start_glyph;
522 let Some(c) = class_values.get(idx as usize) else {
523 break;
524 };
525 if c.get() == class {
526 out.insert(g);
527 }
528 }
529 out
530 }
531}
532
533impl<'a> ClassDefFormat2<'a> {
534 #[inline]
536 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
537 let gid = gid.into().to_u32();
538 let records = self.class_range_records();
539 let ix = match records.binary_search_by(|rec| rec.start_glyph_id().to_u32().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().to_u32()..=record.end_glyph_id().to_u32()).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 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
610 for g in glyphs.iter() {
611 let class = self.get(g);
612 if class != 0 {
613 out.insert(class);
614 }
615 }
616 } else {
617 for record in range_records {
618 if glyphs.intersects_range(
619 GlyphId::from(record.start_glyph_id())..=GlyphId::from(record.end_glyph_id()),
620 ) {
621 out.insert(record.class());
622 }
623 }
624 }
625 out
626 }
627
628 #[cfg(feature = "std")]
630 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
631 let mut out = IntSet::empty();
632 if glyphs.is_empty() {
633 return out;
634 }
635
636 let first = glyphs.first().unwrap().to_u32();
637 let last = glyphs.last().unwrap().to_u32();
638 if class == 0 {
639 let mut start = first;
640 for range in self.class_range_records() {
641 let range_start = range.start_glyph_id().to_u32();
642 if start < range_start {
643 out.extend(glyphs.range(GlyphId::from(start)..GlyphId::from(range_start)));
644 }
645
646 let range_end = range.end_glyph_id().to_u32();
647 if range_end >= last {
648 break;
649 }
650 start = range_end + 1;
651 }
652 return out;
653 }
654
655 let num_ranges = self.class_range_count();
656 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
657 for g in glyphs.iter() {
658 let c = self.get(g);
659 if c == class {
660 out.insert(g);
661 }
662 }
663 } else {
664 for range in self.class_range_records() {
665 let range_start = range.start_glyph_id().to_u32();
666 let range_end = range.end_glyph_id().to_u32();
667 if range_start > last || range.end_glyph_id().to_u32() < first {
668 break;
669 }
670 if range.class() != class {
671 continue;
672 }
673 out.extend(glyphs.range(GlyphId::from(range_start)..=GlyphId::from(range_end)));
674 }
675 }
676 out
677 }
678}
679
680impl ClassRangeRecord {
681 pub fn population(&self) -> usize {
683 let start = self.start_glyph_id().to_u32() as usize;
684 let end = self.end_glyph_id().to_u32() as usize;
685 if start > end {
686 0
687 } else {
688 end - start + 1
689 }
690 }
691}
692
693impl ClassDef<'_> {
694 #[inline]
696 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
697 match self {
698 ClassDef::Format1(table) => table.get(gid),
699 ClassDef::Format2(table) => table.get(gid),
700 }
701 }
702
703 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + '_ {
707 let (one, two) = match self {
708 ClassDef::Format1(inner) => (Some(inner.iter()), None),
709 ClassDef::Format2(inner) => (None, Some(inner.iter())),
710 };
711 one.into_iter().flatten().chain(two.into_iter().flatten())
712 }
713
714 pub fn population(&self) -> usize {
716 match self {
717 ClassDef::Format1(table) => table.population(),
718 ClassDef::Format2(table) => table.population(),
719 }
720 }
721
722 pub fn cost(&self) -> u32 {
724 match self {
725 ClassDef::Format1(sub) => sub.cost(),
726 ClassDef::Format2(sub) => sub.cost(),
727 }
728 }
729
730 #[cfg(feature = "std")]
732 pub fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
733 match self {
734 ClassDef::Format1(table) => table.intersect_classes(glyphs),
735 ClassDef::Format2(table) => table.intersect_classes(glyphs),
736 }
737 }
738
739 #[cfg(feature = "std")]
741 pub fn intersected_class_glyphs(
742 &self,
743 glyphs: &IntSet<GlyphId>,
744 class: u16,
745 ) -> IntSet<GlyphId> {
746 match self {
747 ClassDef::Format1(table) => table.intersected_class_glyphs(glyphs, class),
748 ClassDef::Format2(table) => table.intersected_class_glyphs(glyphs, class),
749 }
750 }
751}
752
753impl<'a> Device<'a> {
754 pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
756 let format = self.delta_format();
757 let mut n = (self.end_size() - self.start_size()) as usize + 1;
758 let deltas_per_word = match format {
759 DeltaFormat::Local2BitDeltas => 8,
760 DeltaFormat::Local4BitDeltas => 4,
761 DeltaFormat::Local8BitDeltas => 2,
762 _ => 0,
763 };
764
765 self.delta_value().iter().flat_map(move |val| {
766 let iter = iter_packed_values(val.get(), format, n);
767 n = n.saturating_sub(deltas_per_word);
768 iter
769 })
770 }
771}
772
773fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
774 let mut decoded = [None; 8];
775 let (mask, sign_mask, bits) = match format {
776 DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
777 DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
778 DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
779 _ => (0, 0, 0),
780 };
781
782 let max_per_word = 16 / bits;
783 #[allow(clippy::needless_range_loop)] for i in 0..n.min(max_per_word) {
785 let mask = mask << ((16 - bits) - i * bits);
786 let val = (raw & mask) >> ((16 - bits) - i * bits);
787 let sign = val & sign_mask != 0;
788
789 let val = if sign {
790 -((((!val) & mask) + 1) as i8)
792 } else {
793 val as i8
794 };
795 decoded[i] = Some(val)
796 }
797 decoded.into_iter().flatten()
798}
799
800impl From<VariationIndex<'_>> for DeltaSetIndex {
801 fn from(src: VariationIndex) -> DeltaSetIndex {
802 DeltaSetIndex {
803 outer: src.delta_set_outer_index(),
804 inner: src.delta_set_inner_index(),
805 }
806 }
807}
808
809#[derive(Clone)]
815pub struct TaggedElement<T> {
816 pub tag: Tag,
817 pub element: T,
818}
819
820impl<T> TaggedElement<T> {
821 pub fn new(tag: Tag, element: T) -> Self {
822 Self { tag, element }
823 }
824}
825
826impl<T> std::ops::Deref for TaggedElement<T> {
827 type Target = T;
828
829 fn deref(&self) -> &Self::Target {
830 &self.element
831 }
832}
833
834#[cfg(test)]
835mod tests {
836 use super::*;
837
838 #[test]
839 fn coverage_get_format1() {
840 const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
842
843 let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
844 assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
845 assert_eq!(coverage.get(GlyphId::new(2)), None);
846 assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
847 assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
848 assert_eq!(coverage.get(GlyphId::new(45)), None);
849 }
850
851 #[test]
852 fn coverage_get_format2() {
853 const COV2_DATA: FontData =
855 FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
856 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
857 assert_eq!(coverage.get(GlyphId::new(2)), None);
858 assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
859 assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
860 assert_eq!(coverage.get(GlyphId::new(10)), None);
861 assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
862 assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
863 assert_eq!(coverage.get(GlyphId::new(40)), None);
864 }
865
866 #[test]
867 fn classdef_get_format2() {
868 let classdef = ClassDef::read(FontData::new(
869 font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
870 ))
871 .unwrap();
872 assert!(matches!(classdef, ClassDef::Format2(..)));
873 let gid_class_pairs = [
874 (616, 1),
875 (617, 1),
876 (618, 1),
877 (624, 1),
878 (625, 1),
879 (626, 1),
880 (652, 2),
881 (653, 2),
882 (654, 2),
883 (655, 2),
884 (661, 2),
885 ];
886 for (gid, class) in gid_class_pairs {
887 assert_eq!(classdef.get(GlyphId16::new(gid)), class);
888 }
889 for (gid, class) in classdef.iter() {
890 assert_eq!(classdef.get(gid), class);
891 }
892 }
893
894 #[test]
895 fn delta_decode() {
896 assert_eq!(
898 iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
899 &[1, 2, 3, -1]
900 );
901
902 assert_eq!(
903 iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
904 &[1, 1, 1, 1, 1]
905 );
906 }
907
908 #[test]
909 fn delta_decode_all() {
910 let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
912 let device = Device::read(bytes.into()).unwrap();
913 assert_eq!(
914 device.iter().collect::<Vec<_>>(),
915 &[1i8, -12, 30, -11, 101, 8, 42]
916 );
917 }
918
919 #[test]
920 fn bit_storage_tests() {
921 assert_eq!(bit_storage(0), 0);
922 assert_eq!(bit_storage(1), 1);
923 assert_eq!(bit_storage(2), 2);
924 assert_eq!(bit_storage(4), 3);
925 assert_eq!(bit_storage(9), 4);
926 assert_eq!(bit_storage(0x123), 9);
927 assert_eq!(bit_storage(0x1234), 13);
928 assert_eq!(bit_storage(0xffff), 16);
929 assert_eq!(bit_storage(0xffff_ffff), 32);
930 }
931}