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, SeqCache, 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, Args = ()>> Lookup<'a, T> {
35 pub fn get_subtable(&self, offset: Offset16) -> Result<T, ReadError> {
36 self.resolve_offset(offset)
37 }
38}
39
40pub trait ExtensionLookup<'a, T: FontRead<'a, Args = ()>>: FontRead<'a, Args = ()> {
45 fn extension(&self) -> Result<T, ReadError>;
46}
47
48pub enum Subtables<'a, T: FontRead<'a, Args = ()>, Ext: ExtensionLookup<'a, T>> {
53 Subtable(ArrayOfOffsets<'a, T>),
54 Extension(ArrayOfOffsets<'a, Ext>),
55}
56
57impl<'a, T: FontRead<'a, Args = ()> + 'a, Ext: ExtensionLookup<'a, T> + 'a> Subtables<'a, T, Ext> {
58 pub(crate) fn new(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
60 Subtables::Subtable(ArrayOfOffsets::new(offsets, data, ()))
61 }
62
63 pub(crate) fn new_ext(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
65 Subtables::Extension(ArrayOfOffsets::new(offsets, data, ()))
66 }
67
68 pub fn len(&self) -> usize {
70 match self {
71 Subtables::Subtable(inner) => inner.len(),
72 Subtables::Extension(inner) => inner.len(),
73 }
74 }
75
76 pub fn is_empty(&self) -> bool {
77 self.len() == 0
78 }
79
80 pub fn get(&self, idx: usize) -> Result<T, ReadError> {
82 match self {
83 Subtables::Subtable(inner) => inner.get(idx),
84 Subtables::Extension(inner) => inner.get(idx).and_then(|ext| ext.extension()),
85 }
86 }
87
88 pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
90 let (left, right) = match self {
91 Subtables::Subtable(inner) => (Some(inner.iter()), None),
92 Subtables::Extension(inner) => (
93 None,
94 Some(inner.iter().map(|ext| ext.and_then(|ext| ext.extension()))),
95 ),
96 };
97 left.into_iter()
98 .flatten()
99 .chain(right.into_iter().flatten())
100 }
101}
102
103pub enum FeatureParams<'a> {
105 StylisticSet(StylisticSetParams<'a>),
106 Size(SizeParams<'a>),
107 CharacterVariant(CharacterVariantParams<'a>),
108}
109
110impl ReadArgs for FeatureParams<'_> {
111 type Args = Tag;
112}
113
114impl<'a> FontRead<'a> for FeatureParams<'a> {
115 fn read_with_args(bytes: FontData<'a>, args: Tag) -> Result<FeatureParams<'a>, ReadError> {
116 match args {
117 t if t == Tag::new(b"size") => SizeParams::read(bytes).map(Self::Size),
118 t if &t.to_raw()[..2] == b"ss" => {
120 StylisticSetParams::read(bytes).map(Self::StylisticSet)
121 }
122 t if &t.to_raw()[..2] == b"cv" => {
123 CharacterVariantParams::read(bytes).map(Self::CharacterVariant)
124 }
125 _ => Err(ReadError::InvalidFormat(0xdead)),
128 }
129 }
130}
131
132impl FeatureTableSubstitutionRecord {
133 pub fn alternate_feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
134 self.alternate_feature_offset()
135 .resolve_with_args(data, Tag::new(b"NULL"))
136 }
137}
138
139fn bit_storage(v: u32) -> u32 {
140 u32::BITS - v.leading_zeros()
141}
142
143impl<'a> CoverageTable<'a> {
144 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + 'a {
145 let (iter1, iter2) = match self {
147 CoverageTable::Format1(t) => (Some(t.glyph_array().iter().map(|g| g.get())), None),
148 CoverageTable::Format2(t) => {
149 let iter = t.range_records().iter().flat_map(RangeRecord::iter);
150 (None, Some(iter))
151 }
152 };
153
154 iter1
155 .into_iter()
156 .flatten()
157 .chain(iter2.into_iter().flatten())
158 }
159
160 #[inline]
162 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
163 match self {
164 CoverageTable::Format1(sub) => sub.get(gid),
165 CoverageTable::Format2(sub) => sub.get(gid),
166 }
167 }
168
169 #[cfg(feature = "std")]
171 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
172 match self {
173 CoverageTable::Format1(sub) => sub.intersects(glyphs),
174 CoverageTable::Format2(sub) => sub.intersects(glyphs),
175 }
176 }
177
178 #[cfg(feature = "std")]
180 pub fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
181 match self {
182 CoverageTable::Format1(sub) => sub.intersect_set(glyphs),
183 CoverageTable::Format2(sub) => sub.intersect_set(glyphs),
184 }
185 }
186
187 pub fn population(&self) -> usize {
189 match self {
190 CoverageTable::Format1(sub) => sub.population(),
191 CoverageTable::Format2(sub) => sub.population(),
192 }
193 }
194
195 pub fn cost(&self) -> u32 {
197 match self {
198 CoverageTable::Format1(sub) => sub.cost(),
199 CoverageTable::Format2(sub) => sub.cost(),
200 }
201 }
202}
203
204impl CoverageFormat1<'_> {
205 #[inline]
207 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
208 let gid16: GlyphId16 = gid.into().try_into().ok()?;
209 let be_glyph: BigEndian<GlyphId16> = gid16.into();
210 self.glyph_array()
211 .binary_search(&be_glyph)
212 .ok()
213 .map(|idx| idx as _)
214 }
215
216 #[cfg(feature = "std")]
218 fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
219 let glyph_count = self.glyph_count() as u32;
220 if glyph_count > (glyphs.len() as u32) * self.cost() {
221 glyphs.iter().any(|g| self.get(g).is_some())
222 } else {
223 self.glyph_array()
224 .iter()
225 .any(|g| glyphs.contains(GlyphId::from(g.get())))
226 }
227 }
228
229 #[cfg(feature = "std")]
231 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
232 let glyph_count = self.glyph_count() as u32;
233 if glyph_count > (glyphs.len() as u32) * self.cost() {
234 glyphs
235 .iter()
236 .filter_map(|g| self.get(g).map(|_| g))
237 .collect()
238 } else {
239 self.glyph_array()
240 .iter()
241 .filter(|g| glyphs.contains(GlyphId::from(g.get())))
242 .map(|g| GlyphId::from(g.get()))
243 .collect()
244 }
245 }
246
247 pub fn population(&self) -> usize {
249 self.glyph_count() as usize
250 }
251
252 pub fn cost(&self) -> u32 {
254 bit_storage(self.glyph_count() as u32)
255 }
256}
257
258impl CoverageFormat2<'_> {
259 #[inline]
261 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
262 let gid: GlyphId16 = gid.into().try_into().ok()?;
263 self.range_records()
264 .binary_search_by(|rec| {
265 if rec.end_glyph_id() < gid {
266 Ordering::Less
267 } else if rec.start_glyph_id() > gid {
268 Ordering::Greater
269 } else {
270 Ordering::Equal
271 }
272 })
273 .ok()
274 .and_then(|idx| {
275 let rec = &self.range_records()[idx];
276 rec.start_coverage_index()
278 .checked_add(gid.to_u16() - rec.start_glyph_id().to_u16())
279 })
280 }
281
282 #[cfg(feature = "std")]
284 fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
285 let range_count = self.range_count() as u32;
286 if range_count > (glyphs.len() as u32) * self.cost() {
287 glyphs.iter().any(|g| self.get(g).is_some())
288 } else {
289 self.range_records()
290 .iter()
291 .any(|record| record.intersects(glyphs))
292 }
293 }
294
295 #[cfg(feature = "std")]
297 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
298 let range_count = self.range_count() as u32;
299 if range_count > (glyphs.len() as u32) * self.cost() {
300 glyphs
301 .iter()
302 .filter_map(|g| self.get(g).map(|_| g))
303 .collect()
304 } else {
305 let mut out = IntSet::empty();
306 let mut last = GlyphId16::from(0);
307 for record in self.range_records() {
308 let start_glyph = record.start_glyph_id();
310 if start_glyph < last {
311 break;
312 }
313 let end = record.end_glyph_id();
314 last = end;
315
316 let start = GlyphId::from(start_glyph);
317 if glyphs.contains(start) {
318 out.insert(start);
319 }
320
321 for g in glyphs.iter_after(start) {
322 if g.to_u32() > end.to_u32() {
323 break;
324 }
325 out.insert(g);
326 }
327 }
328 out
329 }
330 }
331
332 pub fn population(&self) -> usize {
334 self.range_records()
335 .iter()
336 .fold(0, |acc, record| acc + record.population())
337 }
338
339 pub fn cost(&self) -> u32 {
341 bit_storage(self.range_count() as u32)
342 }
343}
344
345impl RangeRecord {
346 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + '_ {
347 (self.start_glyph_id().to_u16()..=self.end_glyph_id().to_u16()).map(GlyphId16::new)
348 }
349
350 #[cfg(feature = "std")]
352 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
353 glyphs.intersects_range(
354 GlyphId::from(self.start_glyph_id())..=GlyphId::from(self.end_glyph_id()),
355 )
356 }
357
358 pub fn population(&self) -> usize {
360 let start = self.start_glyph_id().to_u32() as usize;
361 let end = self.end_glyph_id().to_u32() as usize;
362 if start > end {
363 0
364 } else {
365 end - start + 1
366 }
367 }
368}
369
370impl DeltaFormat {
371 pub(crate) fn value_count(self, start_size: u16, end_size: u16) -> usize {
372 let range_len = end_size.saturating_add(1).saturating_sub(start_size) as usize;
373 let val_per_word = match self {
374 DeltaFormat::Local2BitDeltas => 8,
375 DeltaFormat::Local4BitDeltas => 4,
376 DeltaFormat::Local8BitDeltas => 2,
377 _ => return 0,
378 };
379
380 let count = range_len / val_per_word;
381 let extra = (range_len % val_per_word).min(1);
382 count + extra
383 }
384}
385
386impl From<DeltaFormat> for i64 {
389 fn from(value: DeltaFormat) -> Self {
390 value as u16 as _
391 }
392}
393
394impl<'a> ClassDefFormat1<'a> {
395 #[inline]
397 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
398 let Some(idx) = gid
399 .into()
400 .to_u32()
401 .checked_sub(self.start_glyph_id().to_u32())
402 else {
403 return 0;
404 };
405 self.class_value_array()
406 .get(idx as usize)
407 .map(|x| x.get())
408 .unwrap_or(0)
409 }
410
411 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
413 let start = self.start_glyph_id();
414 self.class_value_array()
415 .iter()
416 .enumerate()
417 .map(move |(i, val)| {
418 let gid = start.to_u16().saturating_add(i as u16);
419 (GlyphId16::new(gid), val.get())
420 })
421 }
422
423 pub fn population(&self) -> usize {
425 self.glyph_count() as usize
426 }
427
428 pub fn cost(&self) -> u32 {
430 1
431 }
432
433 #[cfg(feature = "std")]
435 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
436 let mut out = IntSet::empty();
437 if glyphs.is_empty() {
438 return out;
439 }
440
441 let start_glyph = self.start_glyph_id().to_u32();
442 let class_values = self.class_value_array();
443 if class_values.is_empty() {
444 out.insert(0);
445 return out;
446 }
447 let end_glyph = start_glyph + class_values.len() as u32 - 1;
448 if glyphs.first().unwrap().to_u32() < start_glyph
449 || glyphs.last().unwrap().to_u32() > end_glyph
450 {
451 out.insert(0);
452 }
453
454 if glyphs.contains(GlyphId::from(start_glyph)) {
455 let Some(start_glyph_class) = class_values.first() else {
456 return out;
457 };
458 out.insert(start_glyph_class.get());
459 }
460
461 for g in glyphs.iter_after(GlyphId::from(start_glyph)) {
462 let g = g.to_u32();
463 if g > end_glyph {
464 break;
465 }
466
467 let idx = g - start_glyph;
468 let Some(class) = class_values.get(idx as usize) else {
469 break;
470 };
471 out.insert(class.get());
472 }
473 out
474 }
475
476 #[cfg(feature = "std")]
478 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
479 let mut out = IntSet::empty();
480 if glyphs.is_empty() {
481 return out;
482 }
483
484 let start_glyph = self.start_glyph_id().to_u32();
485 let glyph_count = self.glyph_count();
486 let end_glyph = start_glyph + glyph_count as u32 - 1;
487 if class == 0 {
488 let first = glyphs.first().unwrap();
489 if first.to_u32() < start_glyph {
490 out.extend(glyphs.range(first..GlyphId::from(start_glyph)));
491 }
492
493 let last = glyphs.last().unwrap();
494 if last.to_u32() > end_glyph {
495 out.extend(glyphs.range(GlyphId::from(end_glyph + 1)..=last));
496 }
497 return out;
498 }
499
500 let class_values = self.class_value_array();
501 for g in glyphs.range(GlyphId::from(start_glyph)..=GlyphId::from(end_glyph)) {
502 let idx = g.to_u32() - start_glyph;
503 let Some(c) = class_values.get(idx as usize) else {
504 break;
505 };
506 if c.get() == class {
507 out.insert(g);
508 }
509 }
510 out
511 }
512
513 #[cfg(feature = "std")]
515 fn intersects_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> bool {
516 if glyphs.is_empty() {
517 return false;
518 }
519
520 let start_glyph = self.start_glyph_id().to_u32();
521 let end_glyph = start_glyph + self.glyph_count() as u32 - 1;
522 if class == 0 {
523 let first = glyphs.first().unwrap();
524 if first.to_u32() < start_glyph {
525 return true;
526 }
527
528 let last = glyphs.last().unwrap();
529 if last.to_u32() > end_glyph {
530 return true;
531 }
532 }
533
534 let class_values = self.class_value_array();
535 for g in glyphs.range(GlyphId::from(start_glyph)..=GlyphId::from(end_glyph)) {
536 let idx = g.to_u32() - start_glyph;
537 let Some(c) = class_values.get(idx as usize) else {
538 return false;
539 };
540 if c.get() == class {
541 return true;
542 }
543 }
544 false
545 }
546}
547
548impl<'a> ClassDefFormat2<'a> {
549 #[inline]
551 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
552 let gid = gid.into().to_u32();
553 let records = self.class_range_records();
554 let ix = match records.binary_search_by(|rec| rec.start_glyph_id().to_u32().cmp(&gid)) {
555 Ok(ix) => ix,
556 Err(ix) => ix.saturating_sub(1),
557 };
558 if let Some(record) = records.get(ix) {
559 if (record.start_glyph_id().to_u32()..=record.end_glyph_id().to_u32()).contains(&gid) {
560 return record.class();
561 }
562 }
563 0
564 }
565
566 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
568 self.class_range_records().iter().flat_map(|range| {
569 let start = range.start_glyph_id().to_u16();
570 let end = range.end_glyph_id().to_u16();
571 (start..=end).map(|gid| (GlyphId16::new(gid), range.class()))
572 })
573 }
574
575 pub fn population(&self) -> usize {
577 self.class_range_records()
578 .iter()
579 .fold(0, |acc, record| acc + record.population())
580 }
581
582 pub fn cost(&self) -> u32 {
584 bit_storage(self.class_range_count() as u32)
585 }
586
587 #[cfg(feature = "std")]
589 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
590 let mut out = IntSet::empty();
591 if glyphs.is_empty() {
592 return out;
593 }
594
595 let range_records = self.class_range_records();
596 let Some(first_record) = range_records.first() else {
597 out.insert(0);
598 return out;
599 };
600
601 if glyphs.first().unwrap() < first_record.start_glyph_id() {
602 out.insert(0);
603 } else {
604 let mut glyph = GlyphId::from(first_record.end_glyph_id());
605 for record in range_records.iter().skip(1) {
606 let Some(g) = glyphs.iter_after(glyph).next() else {
607 break;
608 };
609
610 if g < record.start_glyph_id() {
611 out.insert(0);
612 break;
613 }
614 glyph = GlyphId::from(record.end_glyph_id());
615 }
616 if glyphs.iter_after(glyph).next().is_some() {
617 out.insert(0);
618 }
619 }
620
621 let num_ranges = self.class_range_count();
622 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
623 for g in glyphs.iter() {
624 let class = self.get(g);
625 if class != 0 {
626 out.insert(class);
627 }
628 }
629 } else {
630 for record in range_records {
631 if glyphs.intersects_range(
632 GlyphId::from(record.start_glyph_id())..=GlyphId::from(record.end_glyph_id()),
633 ) {
634 out.insert(record.class());
635 }
636 }
637 }
638 out
639 }
640
641 #[cfg(feature = "std")]
643 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
644 let mut out = IntSet::empty();
645 if glyphs.is_empty() {
646 return out;
647 }
648
649 let first = glyphs.first().unwrap().to_u32();
650 let last = glyphs.last().unwrap().to_u32();
651 if class == 0 {
652 let mut start = first;
653 for range in self.class_range_records() {
654 let range_start = range.start_glyph_id().to_u32();
655 if start < range_start {
656 out.extend(glyphs.range(GlyphId::from(start)..GlyphId::from(range_start)));
657 }
658
659 let range_end = range.end_glyph_id().to_u32();
660 if range_end >= last {
661 break;
662 }
663 start = range_end + 1;
664 }
665
666 if start <= last {
667 out.extend(glyphs.range(GlyphId::from(start)..=GlyphId::from(last)));
668 }
669 return out;
670 }
671
672 let num_ranges = self.class_range_count();
673 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
674 for g in glyphs.iter() {
675 let c = self.get(g);
676 if c == class {
677 out.insert(g);
678 }
679 }
680 } else {
681 for range in self.class_range_records() {
682 let range_start = range.start_glyph_id().to_u32();
683 let range_end = range.end_glyph_id().to_u32();
684 if range_start > last {
685 break;
686 }
687 if range.class() != class || range.end_glyph_id().to_u32() < first {
688 continue;
689 }
690 out.extend(glyphs.range(GlyphId::from(range_start)..=GlyphId::from(range_end)));
691 }
692 }
693 out
694 }
695
696 #[cfg(feature = "std")]
698 fn intersects_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> bool {
699 if glyphs.is_empty() {
700 return false;
701 }
702
703 let first = glyphs.first().unwrap().to_u32();
704 if class == 0 {
705 let mut last_end = first;
706 for (i, range) in self.class_range_records().iter().enumerate() {
707 let range_start = range.start_glyph_id().to_u32();
708 let range_end = range.end_glyph_id().to_u32();
709 if i == 0 {
710 if first < range_start {
711 return true;
712 }
713 last_end = range_end;
714 continue;
715 }
716
717 if range_start == last_end + 1 {
718 last_end = range_end;
719 continue;
720 }
721
722 if glyphs
723 .intersects_range(GlyphId::from(last_end + 1)..=GlyphId::from(range_start - 1))
724 {
725 return true;
726 };
727 last_end = range_end + 1;
728 }
729 if glyphs
730 .iter_after(GlyphId::from(last_end + 1))
731 .next()
732 .is_some()
733 {
734 return true;
735 }
736 }
737
738 let num_ranges = self.class_range_count();
739 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
740 for g in glyphs.iter() {
741 let c = self.get(g);
742 if c == class {
743 return true;
744 }
745 }
746 } else {
747 let last = glyphs.last().unwrap().to_u32();
748 for range in self.class_range_records() {
749 let range_start = range.start_glyph_id().to_u32();
750 let range_end = range.end_glyph_id().to_u32();
751 if range_start > last {
752 break;
753 }
754 if range_end < first {
755 continue;
756 }
757 if range.class() == class
758 && glyphs
759 .intersects_range(GlyphId::from(range_start)..=GlyphId::from(range_end))
760 {
761 return true;
762 }
763 }
764 }
765 false
766 }
767}
768
769impl ClassRangeRecord {
770 pub fn population(&self) -> usize {
772 let start = self.start_glyph_id().to_u32() as usize;
773 let end = self.end_glyph_id().to_u32() as usize;
774 if start > end {
775 0
776 } else {
777 end - start + 1
778 }
779 }
780}
781
782impl ClassDef<'_> {
783 #[inline]
785 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
786 match self {
787 ClassDef::Format1(table) => table.get(gid),
788 ClassDef::Format2(table) => table.get(gid),
789 }
790 }
791
792 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + '_ {
796 let (one, two) = match self {
797 ClassDef::Format1(inner) => (Some(inner.iter()), None),
798 ClassDef::Format2(inner) => (None, Some(inner.iter())),
799 };
800 one.into_iter().flatten().chain(two.into_iter().flatten())
801 }
802
803 pub fn population(&self) -> usize {
805 match self {
806 ClassDef::Format1(table) => table.population(),
807 ClassDef::Format2(table) => table.population(),
808 }
809 }
810
811 pub fn cost(&self) -> u32 {
813 match self {
814 ClassDef::Format1(sub) => sub.cost(),
815 ClassDef::Format2(sub) => sub.cost(),
816 }
817 }
818
819 #[cfg(feature = "std")]
821 pub fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
822 match self {
823 ClassDef::Format1(table) => table.intersect_classes(glyphs),
824 ClassDef::Format2(table) => table.intersect_classes(glyphs),
825 }
826 }
827
828 #[cfg(feature = "std")]
830 pub fn intersected_class_glyphs(
831 &self,
832 glyphs: &IntSet<GlyphId>,
833 class: u16,
834 ) -> IntSet<GlyphId> {
835 match self {
836 ClassDef::Format1(table) => table.intersected_class_glyphs(glyphs, class),
837 ClassDef::Format2(table) => table.intersected_class_glyphs(glyphs, class),
838 }
839 }
840
841 #[cfg(feature = "std")]
843 pub fn intersects_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> bool {
844 match self {
845 ClassDef::Format1(table) => table.intersects_class_glyphs(glyphs, class),
846 ClassDef::Format2(table) => table.intersects_class_glyphs(glyphs, class),
847 }
848 }
849}
850
851impl<'a> Device<'a> {
852 pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
854 let format = self.delta_format();
855 let mut n = self
856 .end_size()
857 .checked_sub(self.start_size())
858 .map(|x| x as usize + 1)
859 .unwrap_or(0);
860 let deltas_per_word = match format {
861 DeltaFormat::Local2BitDeltas => 8,
862 DeltaFormat::Local4BitDeltas => 4,
863 DeltaFormat::Local8BitDeltas => 2,
864 _ => 0,
865 };
866
867 self.delta_value().iter().flat_map(move |val| {
868 let iter = iter_packed_values(val.get(), format, n);
869 n = n.saturating_sub(deltas_per_word);
870 iter
871 })
872 }
873}
874
875fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
876 let mut decoded = [None; 8];
877 let (mask, sign_mask, bits) = match format {
878 DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
879 DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
880 DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
881 _ => (0, 0, 0),
882 };
883
884 let max_per_word = 16 / bits;
885 #[allow(clippy::needless_range_loop)] for i in 0..n.min(max_per_word) {
887 let shift = (16 - bits) - i * bits;
888 let val = (raw >> shift) & mask;
891 let val = if val & sign_mask != 0 {
892 (val | !mask) as i8
894 } else {
895 val as i8
896 };
897 decoded[i] = Some(val)
898 }
899 decoded.into_iter().flatten()
900}
901
902impl From<VariationIndex<'_>> for DeltaSetIndex {
903 fn from(src: VariationIndex) -> DeltaSetIndex {
904 DeltaSetIndex {
905 outer: src.delta_set_outer_index(),
906 inner: src.delta_set_inner_index(),
907 }
908 }
909}
910
911#[derive(Clone)]
917pub struct TaggedElement<T> {
918 pub tag: Tag,
919 pub element: T,
920}
921
922impl<T> TaggedElement<T> {
923 pub fn new(tag: Tag, element: T) -> Self {
924 Self { tag, element }
925 }
926}
927
928impl<T> std::ops::Deref for TaggedElement<T> {
929 type Target = T;
930
931 fn deref(&self) -> &Self::Target {
932 &self.element
933 }
934}
935
936#[cfg(test)]
937mod tests {
938 use super::*;
939
940 #[test]
941 fn coverage_get_format1() {
942 const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
944
945 let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
946 assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
947 assert_eq!(coverage.get(GlyphId::new(2)), None);
948 assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
949 assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
950 assert_eq!(coverage.get(GlyphId::new(45)), None);
951 }
952
953 #[test]
954 fn coverage_get_format2() {
955 const COV2_DATA: FontData =
957 FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
958 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
959 assert_eq!(coverage.get(GlyphId::new(2)), None);
960 assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
961 assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
962 assert_eq!(coverage.get(GlyphId::new(10)), None);
963 assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
964 assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
965 assert_eq!(coverage.get(GlyphId::new(40)), None);
966 }
967
968 #[test]
970 fn coverage_get_format2_no_u16_overflow() {
971 const COV2_DATA: FontData =
975 FontData::new(&[0, 2, 0, 1, 0x9c, 0x40, 0x9c, 0x4a, 0x9c, 0x40]);
976 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
977 assert_eq!(coverage.get(GlyphId::new(40000)), Some(40000));
978 assert_eq!(coverage.get(GlyphId::new(40005)), Some(40005));
979 assert_eq!(coverage.get(GlyphId::new(40010)), Some(40010));
980 assert_eq!(coverage.get(GlyphId::new(40011)), None);
981 }
982
983 #[test]
984 fn coverage_get_format2_rejects_overflowing_coverage_index() {
985 const COV2_DATA: FontData = FontData::new(&[0, 2, 0, 1, 0, 1, 0, 2, 0xff, 0xff]);
987 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
988 assert_eq!(coverage.get(GlyphId::new(1)), Some(u16::MAX));
989 assert_eq!(coverage.get(GlyphId::new(2)), None);
990 }
991
992 #[test]
993 fn classdef_get_format2() {
994 let classdef = ClassDef::read(FontData::new(
995 font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
996 ))
997 .unwrap();
998 assert!(matches!(classdef, ClassDef::Format2(..)));
999 let gid_class_pairs = [
1000 (616, 1),
1001 (617, 1),
1002 (618, 1),
1003 (624, 1),
1004 (625, 1),
1005 (626, 1),
1006 (652, 2),
1007 (653, 2),
1008 (654, 2),
1009 (655, 2),
1010 (661, 2),
1011 ];
1012 for (gid, class) in gid_class_pairs {
1013 assert_eq!(classdef.get(GlyphId16::new(gid)), class);
1014 }
1015 for (gid, class) in classdef.iter() {
1016 assert_eq!(classdef.get(gid), class);
1017 }
1018 }
1019
1020 #[test]
1021 fn classdef_format1_short_read_no_panic() {
1022 let classdef = ClassDefFormat1::read(FontData::new(&[0, 1, 0, 10, 0, 5, 0, 1])).unwrap();
1024 let glyphs: IntSet<GlyphId> = [GlyphId::new(10), GlyphId::new(11), GlyphId::new(14)]
1025 .into_iter()
1026 .collect();
1027
1028 assert_eq!(classdef.get(GlyphId::new(10)), 0);
1029 assert_eq!(classdef.get(GlyphId::new(11)), 0);
1030 assert!(!classdef.intersects_class_glyphs(&glyphs, 2));
1031
1032 let class_ones = classdef.intersected_class_glyphs(&glyphs, 1);
1033 assert!(class_ones.is_empty());
1034 }
1035
1036 #[test]
1037 fn delta_decode() {
1038 assert_eq!(
1040 iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
1041 &[1, 2, 3, -1]
1042 );
1043
1044 assert_eq!(
1045 iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
1046 &[1, 1, 1, 1, 1]
1047 );
1048 }
1049
1050 #[test]
1051 fn delta_decode_negative_not_in_last_slot() {
1052 assert_eq!(
1056 iter_packed_values(0xf401, DeltaFormat::Local8BitDeltas, 2).collect::<Vec<_>>(),
1057 &[-12, 1]
1058 );
1059 assert_eq!(
1061 iter_packed_values(0x8123, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
1062 &[-8, 1, 2, 3]
1063 );
1064 assert_eq!(
1066 iter_packed_values(0x9540, DeltaFormat::Local2BitDeltas, 4).collect::<Vec<_>>(),
1067 &[-2, 1, 1, 1]
1068 );
1069 assert_eq!(
1071 iter_packed_values(0x8000, DeltaFormat::Local8BitDeltas, 2).collect::<Vec<_>>(),
1072 &[-128, 0]
1073 );
1074 }
1075
1076 #[test]
1077 fn delta_decode_all() {
1078 let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
1080 let device = Device::read(bytes.into()).unwrap();
1081 assert_eq!(
1082 device.iter().collect::<Vec<_>>(),
1083 &[1i8, -12, 30, -11, 101, 8, 42]
1084 );
1085 }
1086
1087 #[test]
1088 fn device_decode_does_not_overflow() {
1089 let bytes: &[u8] = &[0, 0xA, 0, 1, 0, 1];
1091 Device::read(bytes.into()).unwrap().iter().count();
1093 }
1094
1095 #[test]
1096 fn bit_storage_tests() {
1097 assert_eq!(bit_storage(0), 0);
1098 assert_eq!(bit_storage(1), 1);
1099 assert_eq!(bit_storage(2), 2);
1100 assert_eq!(bit_storage(4), 3);
1101 assert_eq!(bit_storage(9), 4);
1102 assert_eq!(bit_storage(0x123), 9);
1103 assert_eq!(bit_storage(0x1234), 13);
1104 assert_eq!(bit_storage(0xffff), 16);
1105 assert_eq!(bit_storage(0xffff_ffff), 32);
1106 }
1107
1108 #[test]
1109 fn default_coverage() {
1110 let coverage = CoverageTable::default();
1111 assert_eq!(coverage.iter().count(), 0)
1112 }
1113
1114 #[test]
1115 fn default_classdef() {
1116 let classdef = ClassDef::default();
1117 assert_eq!(classdef.population(), 0);
1118 assert_eq!(classdef.iter().count(), 0);
1119 }
1120}