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 .and_then(|idx| {
299 let rec = &self.range_records()[idx];
300 rec.start_coverage_index()
302 .checked_add(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 if range_count > (glyphs.len() as u32) * self.cost() {
311 glyphs.iter().any(|g| self.get(g).is_some())
312 } else {
313 self.range_records()
314 .iter()
315 .any(|record| record.intersects(glyphs))
316 }
317 }
318
319 #[cfg(feature = "std")]
321 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
322 let range_count = self.range_count() as u32;
323 if range_count > (glyphs.len() as u32) * self.cost() {
324 glyphs
325 .iter()
326 .filter_map(|g| self.get(g).map(|_| g))
327 .collect()
328 } else {
329 let mut out = IntSet::empty();
330 let mut last = GlyphId16::from(0);
331 for record in self.range_records() {
332 let start_glyph = record.start_glyph_id();
334 if start_glyph < last {
335 break;
336 }
337 let end = record.end_glyph_id();
338 last = end;
339
340 let start = GlyphId::from(start_glyph);
341 if glyphs.contains(start) {
342 out.insert(start);
343 }
344
345 for g in glyphs.iter_after(start) {
346 if g.to_u32() > end.to_u32() {
347 break;
348 }
349 out.insert(g);
350 }
351 }
352 out
353 }
354 }
355
356 pub fn population(&self) -> usize {
358 self.range_records()
359 .iter()
360 .fold(0, |acc, record| acc + record.population())
361 }
362
363 pub fn cost(&self) -> u32 {
365 bit_storage(self.range_count() as u32)
366 }
367}
368
369impl RangeRecord {
370 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + '_ {
371 (self.start_glyph_id().to_u16()..=self.end_glyph_id().to_u16()).map(GlyphId16::new)
372 }
373
374 #[cfg(feature = "std")]
376 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
377 glyphs.intersects_range(
378 GlyphId::from(self.start_glyph_id())..=GlyphId::from(self.end_glyph_id()),
379 )
380 }
381
382 pub fn population(&self) -> usize {
384 let start = self.start_glyph_id().to_u32() as usize;
385 let end = self.end_glyph_id().to_u32() as usize;
386 if start > end {
387 0
388 } else {
389 end - start + 1
390 }
391 }
392}
393
394impl DeltaFormat {
395 pub(crate) fn value_count(self, start_size: u16, end_size: u16) -> usize {
396 let range_len = end_size.saturating_add(1).saturating_sub(start_size) as usize;
397 let val_per_word = match self {
398 DeltaFormat::Local2BitDeltas => 8,
399 DeltaFormat::Local4BitDeltas => 4,
400 DeltaFormat::Local8BitDeltas => 2,
401 _ => return 0,
402 };
403
404 let count = range_len / val_per_word;
405 let extra = (range_len % val_per_word).min(1);
406 count + extra
407 }
408}
409
410impl From<DeltaFormat> for i64 {
413 fn from(value: DeltaFormat) -> Self {
414 value as u16 as _
415 }
416}
417
418impl<'a> ClassDefFormat1<'a> {
419 #[inline]
421 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
422 let Some(idx) = gid
423 .into()
424 .to_u32()
425 .checked_sub(self.start_glyph_id().to_u32())
426 else {
427 return 0;
428 };
429 self.class_value_array()
430 .get(idx as usize)
431 .map(|x| x.get())
432 .unwrap_or(0)
433 }
434
435 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
437 let start = self.start_glyph_id();
438 self.class_value_array()
439 .iter()
440 .enumerate()
441 .map(move |(i, val)| {
442 let gid = start.to_u16().saturating_add(i as u16);
443 (GlyphId16::new(gid), val.get())
444 })
445 }
446
447 pub fn population(&self) -> usize {
449 self.glyph_count() as usize
450 }
451
452 pub fn cost(&self) -> u32 {
454 1
455 }
456
457 #[cfg(feature = "std")]
459 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
460 let mut out = IntSet::empty();
461 if glyphs.is_empty() {
462 return out;
463 }
464
465 let start_glyph = self.start_glyph_id().to_u32();
466 let glyph_count = self.glyph_count();
467 let end_glyph = start_glyph + glyph_count as u32 - 1;
468 if glyphs.first().unwrap().to_u32() < start_glyph
469 || glyphs.last().unwrap().to_u32() > end_glyph
470 {
471 out.insert(0);
472 }
473
474 let class_values = self.class_value_array();
475 if glyphs.contains(GlyphId::from(start_glyph)) {
476 let Some(start_glyph_class) = class_values.first() else {
477 return out;
478 };
479 out.insert(start_glyph_class.get());
480 }
481
482 for g in glyphs.iter_after(GlyphId::from(start_glyph)) {
483 let g = g.to_u32();
484 if g > end_glyph {
485 break;
486 }
487
488 let idx = g - start_glyph;
489 let Some(class) = class_values.get(idx as usize) else {
490 break;
491 };
492 out.insert(class.get());
493 }
494 out
495 }
496
497 #[cfg(feature = "std")]
499 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
500 let mut out = IntSet::empty();
501 if glyphs.is_empty() {
502 return out;
503 }
504
505 let start_glyph = self.start_glyph_id().to_u32();
506 let glyph_count = self.glyph_count();
507 let end_glyph = start_glyph + glyph_count as u32 - 1;
508 if class == 0 {
509 let first = glyphs.first().unwrap();
510 if first.to_u32() < start_glyph {
511 out.extend(glyphs.range(first..GlyphId::from(start_glyph)));
512 }
513
514 let last = glyphs.last().unwrap();
515 if last.to_u32() > end_glyph {
516 out.extend(glyphs.range(GlyphId::from(end_glyph + 1)..=last));
517 }
518 return out;
519 }
520
521 let class_values = self.class_value_array();
522 for g in glyphs.range(GlyphId::from(start_glyph)..=GlyphId::from(end_glyph)) {
523 let idx = g.to_u32() - start_glyph;
524 let Some(c) = class_values.get(idx as usize) else {
525 break;
526 };
527 if c.get() == class {
528 out.insert(g);
529 }
530 }
531 out
532 }
533}
534
535impl<'a> ClassDefFormat2<'a> {
536 #[inline]
538 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
539 let gid = gid.into().to_u32();
540 let records = self.class_range_records();
541 let ix = match records.binary_search_by(|rec| rec.start_glyph_id().to_u32().cmp(&gid)) {
542 Ok(ix) => ix,
543 Err(ix) => ix.saturating_sub(1),
544 };
545 if let Some(record) = records.get(ix) {
546 if (record.start_glyph_id().to_u32()..=record.end_glyph_id().to_u32()).contains(&gid) {
547 return record.class();
548 }
549 }
550 0
551 }
552
553 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
555 self.class_range_records().iter().flat_map(|range| {
556 let start = range.start_glyph_id().to_u16();
557 let end = range.end_glyph_id().to_u16();
558 (start..=end).map(|gid| (GlyphId16::new(gid), range.class()))
559 })
560 }
561
562 pub fn population(&self) -> usize {
564 self.class_range_records()
565 .iter()
566 .fold(0, |acc, record| acc + record.population())
567 }
568
569 pub fn cost(&self) -> u32 {
571 bit_storage(self.class_range_count() as u32)
572 }
573
574 #[cfg(feature = "std")]
576 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
577 let mut out = IntSet::empty();
578 if glyphs.is_empty() {
579 return out;
580 }
581
582 if self.class_range_count() == 0 {
583 out.insert(0);
584 return out;
585 }
586
587 let range_records = self.class_range_records();
588 let first_record = range_records[0];
589
590 if glyphs.first().unwrap() < first_record.start_glyph_id() {
591 out.insert(0);
592 } else {
593 let mut glyph = GlyphId::from(first_record.end_glyph_id());
594 for record in range_records.iter().skip(1) {
595 let Some(g) = glyphs.iter_after(glyph).next() else {
596 break;
597 };
598
599 if g < record.start_glyph_id() {
600 out.insert(0);
601 break;
602 }
603 glyph = GlyphId::from(record.end_glyph_id());
604 }
605 if glyphs.iter_after(glyph).next().is_some() {
606 out.insert(0);
607 }
608 }
609
610 let num_ranges = self.class_range_count();
611 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
612 for g in glyphs.iter() {
613 let class = self.get(g);
614 if class != 0 {
615 out.insert(class);
616 }
617 }
618 } else {
619 for record in range_records {
620 if glyphs.intersects_range(
621 GlyphId::from(record.start_glyph_id())..=GlyphId::from(record.end_glyph_id()),
622 ) {
623 out.insert(record.class());
624 }
625 }
626 }
627 out
628 }
629
630 #[cfg(feature = "std")]
632 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
633 let mut out = IntSet::empty();
634 if glyphs.is_empty() {
635 return out;
636 }
637
638 let first = glyphs.first().unwrap().to_u32();
639 let last = glyphs.last().unwrap().to_u32();
640 if class == 0 {
641 let mut start = first;
642 for range in self.class_range_records() {
643 let range_start = range.start_glyph_id().to_u32();
644 if start < range_start {
645 out.extend(glyphs.range(GlyphId::from(start)..GlyphId::from(range_start)));
646 }
647
648 let range_end = range.end_glyph_id().to_u32();
649 if range_end >= last {
650 break;
651 }
652 start = range_end + 1;
653 }
654
655 if start <= last {
656 out.extend(glyphs.range(GlyphId::from(start)..=GlyphId::from(last)));
657 }
658 return out;
659 }
660
661 let num_ranges = self.class_range_count();
662 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
663 for g in glyphs.iter() {
664 let c = self.get(g);
665 if c == class {
666 out.insert(g);
667 }
668 }
669 } else {
670 for range in self.class_range_records() {
671 let range_start = range.start_glyph_id().to_u32();
672 let range_end = range.end_glyph_id().to_u32();
673 if range_start > last {
674 break;
675 }
676 if range.class() != class || range.end_glyph_id().to_u32() < first {
677 continue;
678 }
679 out.extend(glyphs.range(GlyphId::from(range_start)..=GlyphId::from(range_end)));
680 }
681 }
682 out
683 }
684}
685
686impl ClassRangeRecord {
687 pub fn population(&self) -> usize {
689 let start = self.start_glyph_id().to_u32() as usize;
690 let end = self.end_glyph_id().to_u32() as usize;
691 if start > end {
692 0
693 } else {
694 end - start + 1
695 }
696 }
697}
698
699impl ClassDef<'_> {
700 #[inline]
702 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
703 match self {
704 ClassDef::Format1(table) => table.get(gid),
705 ClassDef::Format2(table) => table.get(gid),
706 }
707 }
708
709 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + '_ {
713 let (one, two) = match self {
714 ClassDef::Format1(inner) => (Some(inner.iter()), None),
715 ClassDef::Format2(inner) => (None, Some(inner.iter())),
716 };
717 one.into_iter().flatten().chain(two.into_iter().flatten())
718 }
719
720 pub fn population(&self) -> usize {
722 match self {
723 ClassDef::Format1(table) => table.population(),
724 ClassDef::Format2(table) => table.population(),
725 }
726 }
727
728 pub fn cost(&self) -> u32 {
730 match self {
731 ClassDef::Format1(sub) => sub.cost(),
732 ClassDef::Format2(sub) => sub.cost(),
733 }
734 }
735
736 #[cfg(feature = "std")]
738 pub fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
739 match self {
740 ClassDef::Format1(table) => table.intersect_classes(glyphs),
741 ClassDef::Format2(table) => table.intersect_classes(glyphs),
742 }
743 }
744
745 #[cfg(feature = "std")]
747 pub fn intersected_class_glyphs(
748 &self,
749 glyphs: &IntSet<GlyphId>,
750 class: u16,
751 ) -> IntSet<GlyphId> {
752 match self {
753 ClassDef::Format1(table) => table.intersected_class_glyphs(glyphs, class),
754 ClassDef::Format2(table) => table.intersected_class_glyphs(glyphs, class),
755 }
756 }
757}
758
759impl<'a> Device<'a> {
760 pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
762 let format = self.delta_format();
763 let mut n = (self.end_size() - self.start_size()) as usize + 1;
764 let deltas_per_word = match format {
765 DeltaFormat::Local2BitDeltas => 8,
766 DeltaFormat::Local4BitDeltas => 4,
767 DeltaFormat::Local8BitDeltas => 2,
768 _ => 0,
769 };
770
771 self.delta_value().iter().flat_map(move |val| {
772 let iter = iter_packed_values(val.get(), format, n);
773 n = n.saturating_sub(deltas_per_word);
774 iter
775 })
776 }
777}
778
779fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
780 let mut decoded = [None; 8];
781 let (mask, sign_mask, bits) = match format {
782 DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
783 DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
784 DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
785 _ => (0, 0, 0),
786 };
787
788 let max_per_word = 16 / bits;
789 #[allow(clippy::needless_range_loop)] for i in 0..n.min(max_per_word) {
791 let mask = mask << ((16 - bits) - i * bits);
792 let val = (raw & mask) >> ((16 - bits) - i * bits);
793 let sign = val & sign_mask != 0;
794
795 let val = if sign {
796 -((((!val) & mask) + 1) as i8)
798 } else {
799 val as i8
800 };
801 decoded[i] = Some(val)
802 }
803 decoded.into_iter().flatten()
804}
805
806impl From<VariationIndex<'_>> for DeltaSetIndex {
807 fn from(src: VariationIndex) -> DeltaSetIndex {
808 DeltaSetIndex {
809 outer: src.delta_set_outer_index(),
810 inner: src.delta_set_inner_index(),
811 }
812 }
813}
814
815#[derive(Clone)]
821pub struct TaggedElement<T> {
822 pub tag: Tag,
823 pub element: T,
824}
825
826impl<T> TaggedElement<T> {
827 pub fn new(tag: Tag, element: T) -> Self {
828 Self { tag, element }
829 }
830}
831
832impl<T> std::ops::Deref for TaggedElement<T> {
833 type Target = T;
834
835 fn deref(&self) -> &Self::Target {
836 &self.element
837 }
838}
839
840#[cfg(test)]
841mod tests {
842 use super::*;
843
844 #[test]
845 fn coverage_get_format1() {
846 const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
848
849 let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
850 assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
851 assert_eq!(coverage.get(GlyphId::new(2)), None);
852 assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
853 assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
854 assert_eq!(coverage.get(GlyphId::new(45)), None);
855 }
856
857 #[test]
858 fn coverage_get_format2() {
859 const COV2_DATA: FontData =
861 FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
862 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
863 assert_eq!(coverage.get(GlyphId::new(2)), None);
864 assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
865 assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
866 assert_eq!(coverage.get(GlyphId::new(10)), None);
867 assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
868 assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
869 assert_eq!(coverage.get(GlyphId::new(40)), None);
870 }
871
872 #[test]
874 fn coverage_get_format2_no_u16_overflow() {
875 const COV2_DATA: FontData =
879 FontData::new(&[0, 2, 0, 1, 0x9c, 0x40, 0x9c, 0x4a, 0x9c, 0x40]);
880 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
881 assert_eq!(coverage.get(GlyphId::new(40000)), Some(40000));
882 assert_eq!(coverage.get(GlyphId::new(40005)), Some(40005));
883 assert_eq!(coverage.get(GlyphId::new(40010)), Some(40010));
884 assert_eq!(coverage.get(GlyphId::new(40011)), None);
885 }
886
887 #[test]
888 fn coverage_get_format2_rejects_overflowing_coverage_index() {
889 const COV2_DATA: FontData = FontData::new(&[0, 2, 0, 1, 0, 1, 0, 2, 0xff, 0xff]);
891 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
892 assert_eq!(coverage.get(GlyphId::new(1)), Some(u16::MAX));
893 assert_eq!(coverage.get(GlyphId::new(2)), None);
894 }
895
896 #[test]
897 fn classdef_get_format2() {
898 let classdef = ClassDef::read(FontData::new(
899 font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
900 ))
901 .unwrap();
902 assert!(matches!(classdef, ClassDef::Format2(..)));
903 let gid_class_pairs = [
904 (616, 1),
905 (617, 1),
906 (618, 1),
907 (624, 1),
908 (625, 1),
909 (626, 1),
910 (652, 2),
911 (653, 2),
912 (654, 2),
913 (655, 2),
914 (661, 2),
915 ];
916 for (gid, class) in gid_class_pairs {
917 assert_eq!(classdef.get(GlyphId16::new(gid)), class);
918 }
919 for (gid, class) in classdef.iter() {
920 assert_eq!(classdef.get(gid), class);
921 }
922 }
923
924 #[test]
925 fn delta_decode() {
926 assert_eq!(
928 iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
929 &[1, 2, 3, -1]
930 );
931
932 assert_eq!(
933 iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
934 &[1, 1, 1, 1, 1]
935 );
936 }
937
938 #[test]
939 fn delta_decode_all() {
940 let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
942 let device = Device::read(bytes.into()).unwrap();
943 assert_eq!(
944 device.iter().collect::<Vec<_>>(),
945 &[1i8, -12, 30, -11, 101, 8, 42]
946 );
947 }
948
949 #[test]
950 fn bit_storage_tests() {
951 assert_eq!(bit_storage(0), 0);
952 assert_eq!(bit_storage(1), 1);
953 assert_eq!(bit_storage(2), 2);
954 assert_eq!(bit_storage(4), 3);
955 assert_eq!(bit_storage(9), 4);
956 assert_eq!(bit_storage(0x123), 9);
957 assert_eq!(bit_storage(0x1234), 13);
958 assert_eq!(bit_storage(0xffff), 16);
959 assert_eq!(bit_storage(0xffff_ffff), 32);
960 }
961
962 #[test]
963 fn default_coverage() {
964 let coverage = CoverageTable::default();
965 assert_eq!(coverage.iter().count(), 0)
966 }
967
968 #[test]
969 fn default_classdef() {
970 let classdef = ClassDef::default();
971 assert_eq!(classdef.population(), 0);
972 assert_eq!(classdef.iter().count(), 0);
973 }
974}