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
653 if start <= last {
654 out.extend(glyphs.range(GlyphId::from(start)..=GlyphId::from(last)));
655 }
656 return out;
657 }
658
659 let num_ranges = self.class_range_count();
660 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
661 for g in glyphs.iter() {
662 let c = self.get(g);
663 if c == class {
664 out.insert(g);
665 }
666 }
667 } else {
668 for range in self.class_range_records() {
669 let range_start = range.start_glyph_id().to_u32();
670 let range_end = range.end_glyph_id().to_u32();
671 if range_start > last {
672 break;
673 }
674 if range.class() != class || range.end_glyph_id().to_u32() < first {
675 continue;
676 }
677 out.extend(glyphs.range(GlyphId::from(range_start)..=GlyphId::from(range_end)));
678 }
679 }
680 out
681 }
682}
683
684impl ClassRangeRecord {
685 pub fn population(&self) -> usize {
687 let start = self.start_glyph_id().to_u32() as usize;
688 let end = self.end_glyph_id().to_u32() as usize;
689 if start > end {
690 0
691 } else {
692 end - start + 1
693 }
694 }
695}
696
697impl ClassDef<'_> {
698 #[inline]
700 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
701 match self {
702 ClassDef::Format1(table) => table.get(gid),
703 ClassDef::Format2(table) => table.get(gid),
704 }
705 }
706
707 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + '_ {
711 let (one, two) = match self {
712 ClassDef::Format1(inner) => (Some(inner.iter()), None),
713 ClassDef::Format2(inner) => (None, Some(inner.iter())),
714 };
715 one.into_iter().flatten().chain(two.into_iter().flatten())
716 }
717
718 pub fn population(&self) -> usize {
720 match self {
721 ClassDef::Format1(table) => table.population(),
722 ClassDef::Format2(table) => table.population(),
723 }
724 }
725
726 pub fn cost(&self) -> u32 {
728 match self {
729 ClassDef::Format1(sub) => sub.cost(),
730 ClassDef::Format2(sub) => sub.cost(),
731 }
732 }
733
734 #[cfg(feature = "std")]
736 pub fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
737 match self {
738 ClassDef::Format1(table) => table.intersect_classes(glyphs),
739 ClassDef::Format2(table) => table.intersect_classes(glyphs),
740 }
741 }
742
743 #[cfg(feature = "std")]
745 pub fn intersected_class_glyphs(
746 &self,
747 glyphs: &IntSet<GlyphId>,
748 class: u16,
749 ) -> IntSet<GlyphId> {
750 match self {
751 ClassDef::Format1(table) => table.intersected_class_glyphs(glyphs, class),
752 ClassDef::Format2(table) => table.intersected_class_glyphs(glyphs, class),
753 }
754 }
755}
756
757impl<'a> Device<'a> {
758 pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
760 let format = self.delta_format();
761 let mut n = (self.end_size() - self.start_size()) as usize + 1;
762 let deltas_per_word = match format {
763 DeltaFormat::Local2BitDeltas => 8,
764 DeltaFormat::Local4BitDeltas => 4,
765 DeltaFormat::Local8BitDeltas => 2,
766 _ => 0,
767 };
768
769 self.delta_value().iter().flat_map(move |val| {
770 let iter = iter_packed_values(val.get(), format, n);
771 n = n.saturating_sub(deltas_per_word);
772 iter
773 })
774 }
775}
776
777fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
778 let mut decoded = [None; 8];
779 let (mask, sign_mask, bits) = match format {
780 DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
781 DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
782 DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
783 _ => (0, 0, 0),
784 };
785
786 let max_per_word = 16 / bits;
787 #[allow(clippy::needless_range_loop)] for i in 0..n.min(max_per_word) {
789 let mask = mask << ((16 - bits) - i * bits);
790 let val = (raw & mask) >> ((16 - bits) - i * bits);
791 let sign = val & sign_mask != 0;
792
793 let val = if sign {
794 -((((!val) & mask) + 1) as i8)
796 } else {
797 val as i8
798 };
799 decoded[i] = Some(val)
800 }
801 decoded.into_iter().flatten()
802}
803
804impl From<VariationIndex<'_>> for DeltaSetIndex {
805 fn from(src: VariationIndex) -> DeltaSetIndex {
806 DeltaSetIndex {
807 outer: src.delta_set_outer_index(),
808 inner: src.delta_set_inner_index(),
809 }
810 }
811}
812
813#[derive(Clone)]
819pub struct TaggedElement<T> {
820 pub tag: Tag,
821 pub element: T,
822}
823
824impl<T> TaggedElement<T> {
825 pub fn new(tag: Tag, element: T) -> Self {
826 Self { tag, element }
827 }
828}
829
830impl<T> std::ops::Deref for TaggedElement<T> {
831 type Target = T;
832
833 fn deref(&self) -> &Self::Target {
834 &self.element
835 }
836}
837
838#[cfg(test)]
839mod tests {
840 use super::*;
841
842 #[test]
843 fn coverage_get_format1() {
844 const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
846
847 let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
848 assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
849 assert_eq!(coverage.get(GlyphId::new(2)), None);
850 assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
851 assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
852 assert_eq!(coverage.get(GlyphId::new(45)), None);
853 }
854
855 #[test]
856 fn coverage_get_format2() {
857 const COV2_DATA: FontData =
859 FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
860 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
861 assert_eq!(coverage.get(GlyphId::new(2)), None);
862 assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
863 assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
864 assert_eq!(coverage.get(GlyphId::new(10)), None);
865 assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
866 assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
867 assert_eq!(coverage.get(GlyphId::new(40)), None);
868 }
869
870 #[test]
871 fn classdef_get_format2() {
872 let classdef = ClassDef::read(FontData::new(
873 font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
874 ))
875 .unwrap();
876 assert!(matches!(classdef, ClassDef::Format2(..)));
877 let gid_class_pairs = [
878 (616, 1),
879 (617, 1),
880 (618, 1),
881 (624, 1),
882 (625, 1),
883 (626, 1),
884 (652, 2),
885 (653, 2),
886 (654, 2),
887 (655, 2),
888 (661, 2),
889 ];
890 for (gid, class) in gid_class_pairs {
891 assert_eq!(classdef.get(GlyphId16::new(gid)), class);
892 }
893 for (gid, class) in classdef.iter() {
894 assert_eq!(classdef.get(gid), class);
895 }
896 }
897
898 #[test]
899 fn delta_decode() {
900 assert_eq!(
902 iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
903 &[1, 2, 3, -1]
904 );
905
906 assert_eq!(
907 iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
908 &[1, 1, 1, 1, 1]
909 );
910 }
911
912 #[test]
913 fn delta_decode_all() {
914 let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
916 let device = Device::read(bytes.into()).unwrap();
917 assert_eq!(
918 device.iter().collect::<Vec<_>>(),
919 &[1i8, -12, 30, -11, 101, 8, 42]
920 );
921 }
922
923 #[test]
924 fn bit_storage_tests() {
925 assert_eq!(bit_storage(0), 0);
926 assert_eq!(bit_storage(1), 1);
927 assert_eq!(bit_storage(2), 2);
928 assert_eq!(bit_storage(4), 3);
929 assert_eq!(bit_storage(9), 4);
930 assert_eq!(bit_storage(0x123), 9);
931 assert_eq!(bit_storage(0x1234), 13);
932 assert_eq!(bit_storage(0xffff), 16);
933 assert_eq!(bit_storage(0xffff_ffff), 32);
934 }
935
936 #[test]
937 fn default_coverage() {
938 let coverage = CoverageTable::default();
939 assert_eq!(coverage.iter().count(), 0)
940 }
941
942 #[test]
943 fn default_classdef() {
944 let classdef = ClassDef::default();
945 assert_eq!(classdef.population(), 0);
946 assert_eq!(classdef.iter().count(), 0);
947 }
948}