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 #[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, Args = ()>>: FontRead<'a, Args = ()> {
50 fn extension(&self) -> Result<T, ReadError>;
51}
52
53pub enum Subtables<'a, T: FontRead<'a, Args = ()>, Ext: ExtensionLookup<'a, T>> {
58 Subtable(ArrayOfOffsets<'a, T>),
59 Extension(ArrayOfOffsets<'a, Ext>),
60}
61
62impl<'a, T: FontRead<'a, Args = ()> + '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> FontRead<'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 class_values = self.class_value_array();
467 if class_values.is_empty() {
468 out.insert(0);
469 return out;
470 }
471 let end_glyph = start_glyph + class_values.len() as u32 - 1;
472 if glyphs.first().unwrap().to_u32() < start_glyph
473 || glyphs.last().unwrap().to_u32() > end_glyph
474 {
475 out.insert(0);
476 }
477
478 if glyphs.contains(GlyphId::from(start_glyph)) {
479 let Some(start_glyph_class) = class_values.first() else {
480 return out;
481 };
482 out.insert(start_glyph_class.get());
483 }
484
485 for g in glyphs.iter_after(GlyphId::from(start_glyph)) {
486 let g = g.to_u32();
487 if g > end_glyph {
488 break;
489 }
490
491 let idx = g - start_glyph;
492 let Some(class) = class_values.get(idx as usize) else {
493 break;
494 };
495 out.insert(class.get());
496 }
497 out
498 }
499
500 #[cfg(feature = "std")]
502 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
503 let mut out = IntSet::empty();
504 if glyphs.is_empty() {
505 return out;
506 }
507
508 let start_glyph = self.start_glyph_id().to_u32();
509 let glyph_count = self.glyph_count();
510 let end_glyph = start_glyph + glyph_count as u32 - 1;
511 if class == 0 {
512 let first = glyphs.first().unwrap();
513 if first.to_u32() < start_glyph {
514 out.extend(glyphs.range(first..GlyphId::from(start_glyph)));
515 }
516
517 let last = glyphs.last().unwrap();
518 if last.to_u32() > end_glyph {
519 out.extend(glyphs.range(GlyphId::from(end_glyph + 1)..=last));
520 }
521 return out;
522 }
523
524 let class_values = self.class_value_array();
525 for g in glyphs.range(GlyphId::from(start_glyph)..=GlyphId::from(end_glyph)) {
526 let idx = g.to_u32() - start_glyph;
527 let Some(c) = class_values.get(idx as usize) else {
528 break;
529 };
530 if c.get() == class {
531 out.insert(g);
532 }
533 }
534 out
535 }
536
537 #[cfg(feature = "std")]
539 fn intersects_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> bool {
540 if glyphs.is_empty() {
541 return false;
542 }
543
544 let start_glyph = self.start_glyph_id().to_u32();
545 let end_glyph = start_glyph + self.glyph_count() as u32 - 1;
546 if class == 0 {
547 let first = glyphs.first().unwrap();
548 if first.to_u32() < start_glyph {
549 return true;
550 }
551
552 let last = glyphs.last().unwrap();
553 if last.to_u32() > end_glyph {
554 return true;
555 }
556 }
557
558 let class_values = self.class_value_array();
559 for g in glyphs.range(GlyphId::from(start_glyph)..=GlyphId::from(end_glyph)) {
560 let idx = g.to_u32() - start_glyph;
561 let Some(c) = class_values.get(idx as usize) else {
562 return false;
563 };
564 if c.get() == class {
565 return true;
566 }
567 }
568 false
569 }
570}
571
572impl<'a> ClassDefFormat2<'a> {
573 #[inline]
575 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
576 let gid = gid.into().to_u32();
577 let records = self.class_range_records();
578 let ix = match records.binary_search_by(|rec| rec.start_glyph_id().to_u32().cmp(&gid)) {
579 Ok(ix) => ix,
580 Err(ix) => ix.saturating_sub(1),
581 };
582 if let Some(record) = records.get(ix) {
583 if (record.start_glyph_id().to_u32()..=record.end_glyph_id().to_u32()).contains(&gid) {
584 return record.class();
585 }
586 }
587 0
588 }
589
590 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
592 self.class_range_records().iter().flat_map(|range| {
593 let start = range.start_glyph_id().to_u16();
594 let end = range.end_glyph_id().to_u16();
595 (start..=end).map(|gid| (GlyphId16::new(gid), range.class()))
596 })
597 }
598
599 pub fn population(&self) -> usize {
601 self.class_range_records()
602 .iter()
603 .fold(0, |acc, record| acc + record.population())
604 }
605
606 pub fn cost(&self) -> u32 {
608 bit_storage(self.class_range_count() as u32)
609 }
610
611 #[cfg(feature = "std")]
613 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
614 let mut out = IntSet::empty();
615 if glyphs.is_empty() {
616 return out;
617 }
618
619 let range_records = self.class_range_records();
620 let Some(first_record) = range_records.first() else {
621 out.insert(0);
622 return out;
623 };
624
625 if glyphs.first().unwrap() < first_record.start_glyph_id() {
626 out.insert(0);
627 } else {
628 let mut glyph = GlyphId::from(first_record.end_glyph_id());
629 for record in range_records.iter().skip(1) {
630 let Some(g) = glyphs.iter_after(glyph).next() else {
631 break;
632 };
633
634 if g < record.start_glyph_id() {
635 out.insert(0);
636 break;
637 }
638 glyph = GlyphId::from(record.end_glyph_id());
639 }
640 if glyphs.iter_after(glyph).next().is_some() {
641 out.insert(0);
642 }
643 }
644
645 let num_ranges = self.class_range_count();
646 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
647 for g in glyphs.iter() {
648 let class = self.get(g);
649 if class != 0 {
650 out.insert(class);
651 }
652 }
653 } else {
654 for record in range_records {
655 if glyphs.intersects_range(
656 GlyphId::from(record.start_glyph_id())..=GlyphId::from(record.end_glyph_id()),
657 ) {
658 out.insert(record.class());
659 }
660 }
661 }
662 out
663 }
664
665 #[cfg(feature = "std")]
667 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
668 let mut out = IntSet::empty();
669 if glyphs.is_empty() {
670 return out;
671 }
672
673 let first = glyphs.first().unwrap().to_u32();
674 let last = glyphs.last().unwrap().to_u32();
675 if class == 0 {
676 let mut start = first;
677 for range in self.class_range_records() {
678 let range_start = range.start_glyph_id().to_u32();
679 if start < range_start {
680 out.extend(glyphs.range(GlyphId::from(start)..GlyphId::from(range_start)));
681 }
682
683 let range_end = range.end_glyph_id().to_u32();
684 if range_end >= last {
685 break;
686 }
687 start = range_end + 1;
688 }
689
690 if start <= last {
691 out.extend(glyphs.range(GlyphId::from(start)..=GlyphId::from(last)));
692 }
693 return out;
694 }
695
696 let num_ranges = self.class_range_count();
697 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
698 for g in glyphs.iter() {
699 let c = self.get(g);
700 if c == class {
701 out.insert(g);
702 }
703 }
704 } else {
705 for range in self.class_range_records() {
706 let range_start = range.start_glyph_id().to_u32();
707 let range_end = range.end_glyph_id().to_u32();
708 if range_start > last {
709 break;
710 }
711 if range.class() != class || range.end_glyph_id().to_u32() < first {
712 continue;
713 }
714 out.extend(glyphs.range(GlyphId::from(range_start)..=GlyphId::from(range_end)));
715 }
716 }
717 out
718 }
719
720 #[cfg(feature = "std")]
722 fn intersects_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> bool {
723 if glyphs.is_empty() {
724 return false;
725 }
726
727 let first = glyphs.first().unwrap().to_u32();
728 if class == 0 {
729 let mut last_end = first;
730 for (i, range) in self.class_range_records().iter().enumerate() {
731 let range_start = range.start_glyph_id().to_u32();
732 let range_end = range.end_glyph_id().to_u32();
733 if i == 0 {
734 if first < range_start {
735 return true;
736 }
737 last_end = range_end;
738 continue;
739 }
740
741 if range_start == last_end + 1 {
742 last_end = range_end;
743 continue;
744 }
745
746 if glyphs
747 .intersects_range(GlyphId::from(last_end + 1)..=GlyphId::from(range_start - 1))
748 {
749 return true;
750 };
751 last_end = range_end + 1;
752 }
753 if glyphs
754 .iter_after(GlyphId::from(last_end + 1))
755 .next()
756 .is_some()
757 {
758 return true;
759 }
760 }
761
762 let num_ranges = self.class_range_count();
763 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
764 for g in glyphs.iter() {
765 let c = self.get(g);
766 if c == class {
767 return true;
768 }
769 }
770 } else {
771 let last = glyphs.last().unwrap().to_u32();
772 for range in self.class_range_records() {
773 let range_start = range.start_glyph_id().to_u32();
774 let range_end = range.end_glyph_id().to_u32();
775 if range_start > last {
776 break;
777 }
778 if range_end < first {
779 continue;
780 }
781 if range.class() == class
782 && glyphs
783 .intersects_range(GlyphId::from(range_start)..=GlyphId::from(range_end))
784 {
785 return true;
786 }
787 }
788 }
789 false
790 }
791}
792
793impl ClassRangeRecord {
794 pub fn population(&self) -> usize {
796 let start = self.start_glyph_id().to_u32() as usize;
797 let end = self.end_glyph_id().to_u32() as usize;
798 if start > end {
799 0
800 } else {
801 end - start + 1
802 }
803 }
804}
805
806impl ClassDef<'_> {
807 #[inline]
809 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
810 match self {
811 ClassDef::Format1(table) => table.get(gid),
812 ClassDef::Format2(table) => table.get(gid),
813 }
814 }
815
816 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + '_ {
820 let (one, two) = match self {
821 ClassDef::Format1(inner) => (Some(inner.iter()), None),
822 ClassDef::Format2(inner) => (None, Some(inner.iter())),
823 };
824 one.into_iter().flatten().chain(two.into_iter().flatten())
825 }
826
827 pub fn population(&self) -> usize {
829 match self {
830 ClassDef::Format1(table) => table.population(),
831 ClassDef::Format2(table) => table.population(),
832 }
833 }
834
835 pub fn cost(&self) -> u32 {
837 match self {
838 ClassDef::Format1(sub) => sub.cost(),
839 ClassDef::Format2(sub) => sub.cost(),
840 }
841 }
842
843 #[cfg(feature = "std")]
845 pub fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
846 match self {
847 ClassDef::Format1(table) => table.intersect_classes(glyphs),
848 ClassDef::Format2(table) => table.intersect_classes(glyphs),
849 }
850 }
851
852 #[cfg(feature = "std")]
854 pub fn intersected_class_glyphs(
855 &self,
856 glyphs: &IntSet<GlyphId>,
857 class: u16,
858 ) -> IntSet<GlyphId> {
859 match self {
860 ClassDef::Format1(table) => table.intersected_class_glyphs(glyphs, class),
861 ClassDef::Format2(table) => table.intersected_class_glyphs(glyphs, class),
862 }
863 }
864
865 #[cfg(feature = "std")]
867 pub fn intersects_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> bool {
868 match self {
869 ClassDef::Format1(table) => table.intersects_class_glyphs(glyphs, class),
870 ClassDef::Format2(table) => table.intersects_class_glyphs(glyphs, class),
871 }
872 }
873}
874
875impl<'a> Device<'a> {
876 pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
878 let format = self.delta_format();
879 let mut n = self
880 .end_size()
881 .checked_sub(self.start_size())
882 .map(|x| x as usize + 1)
883 .unwrap_or(0);
884 let deltas_per_word = match format {
885 DeltaFormat::Local2BitDeltas => 8,
886 DeltaFormat::Local4BitDeltas => 4,
887 DeltaFormat::Local8BitDeltas => 2,
888 _ => 0,
889 };
890
891 self.delta_value().iter().flat_map(move |val| {
892 let iter = iter_packed_values(val.get(), format, n);
893 n = n.saturating_sub(deltas_per_word);
894 iter
895 })
896 }
897}
898
899fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
900 let mut decoded = [None; 8];
901 let (mask, sign_mask, bits) = match format {
902 DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
903 DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
904 DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
905 _ => (0, 0, 0),
906 };
907
908 let max_per_word = 16 / bits;
909 #[allow(clippy::needless_range_loop)] for i in 0..n.min(max_per_word) {
911 let mask = mask << ((16 - bits) - i * bits);
912 let val = (raw & mask) >> ((16 - bits) - i * bits);
913 let sign = val & sign_mask != 0;
914
915 let val = if sign {
916 -((((!val) & mask) + 1) as i8)
918 } else {
919 val as i8
920 };
921 decoded[i] = Some(val)
922 }
923 decoded.into_iter().flatten()
924}
925
926impl From<VariationIndex<'_>> for DeltaSetIndex {
927 fn from(src: VariationIndex) -> DeltaSetIndex {
928 DeltaSetIndex {
929 outer: src.delta_set_outer_index(),
930 inner: src.delta_set_inner_index(),
931 }
932 }
933}
934
935#[derive(Clone)]
941pub struct TaggedElement<T> {
942 pub tag: Tag,
943 pub element: T,
944}
945
946impl<T> TaggedElement<T> {
947 pub fn new(tag: Tag, element: T) -> Self {
948 Self { tag, element }
949 }
950}
951
952impl<T> std::ops::Deref for TaggedElement<T> {
953 type Target = T;
954
955 fn deref(&self) -> &Self::Target {
956 &self.element
957 }
958}
959
960#[cfg(test)]
961mod tests {
962 use super::*;
963
964 #[test]
965 fn coverage_get_format1() {
966 const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
968
969 let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
970 assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
971 assert_eq!(coverage.get(GlyphId::new(2)), None);
972 assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
973 assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
974 assert_eq!(coverage.get(GlyphId::new(45)), None);
975 }
976
977 #[test]
978 fn coverage_get_format2() {
979 const COV2_DATA: FontData =
981 FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
982 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
983 assert_eq!(coverage.get(GlyphId::new(2)), None);
984 assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
985 assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
986 assert_eq!(coverage.get(GlyphId::new(10)), None);
987 assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
988 assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
989 assert_eq!(coverage.get(GlyphId::new(40)), None);
990 }
991
992 #[test]
994 fn coverage_get_format2_no_u16_overflow() {
995 const COV2_DATA: FontData =
999 FontData::new(&[0, 2, 0, 1, 0x9c, 0x40, 0x9c, 0x4a, 0x9c, 0x40]);
1000 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
1001 assert_eq!(coverage.get(GlyphId::new(40000)), Some(40000));
1002 assert_eq!(coverage.get(GlyphId::new(40005)), Some(40005));
1003 assert_eq!(coverage.get(GlyphId::new(40010)), Some(40010));
1004 assert_eq!(coverage.get(GlyphId::new(40011)), None);
1005 }
1006
1007 #[test]
1008 fn coverage_get_format2_rejects_overflowing_coverage_index() {
1009 const COV2_DATA: FontData = FontData::new(&[0, 2, 0, 1, 0, 1, 0, 2, 0xff, 0xff]);
1011 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
1012 assert_eq!(coverage.get(GlyphId::new(1)), Some(u16::MAX));
1013 assert_eq!(coverage.get(GlyphId::new(2)), None);
1014 }
1015
1016 #[test]
1017 fn classdef_get_format2() {
1018 let classdef = ClassDef::read(FontData::new(
1019 font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
1020 ))
1021 .unwrap();
1022 assert!(matches!(classdef, ClassDef::Format2(..)));
1023 let gid_class_pairs = [
1024 (616, 1),
1025 (617, 1),
1026 (618, 1),
1027 (624, 1),
1028 (625, 1),
1029 (626, 1),
1030 (652, 2),
1031 (653, 2),
1032 (654, 2),
1033 (655, 2),
1034 (661, 2),
1035 ];
1036 for (gid, class) in gid_class_pairs {
1037 assert_eq!(classdef.get(GlyphId16::new(gid)), class);
1038 }
1039 for (gid, class) in classdef.iter() {
1040 assert_eq!(classdef.get(gid), class);
1041 }
1042 }
1043
1044 #[test]
1045 fn classdef_format1_short_read_no_panic() {
1046 let classdef = ClassDefFormat1::read(FontData::new(&[0, 1, 0, 10, 0, 5, 0, 1])).unwrap();
1048 let glyphs: IntSet<GlyphId> = [GlyphId::new(10), GlyphId::new(11), GlyphId::new(14)]
1049 .into_iter()
1050 .collect();
1051
1052 assert_eq!(classdef.get(GlyphId::new(10)), 0);
1053 assert_eq!(classdef.get(GlyphId::new(11)), 0);
1054 assert!(!classdef.intersects_class_glyphs(&glyphs, 2));
1055
1056 let class_ones = classdef.intersected_class_glyphs(&glyphs, 1);
1057 assert!(class_ones.is_empty());
1058 }
1059
1060 #[test]
1061 fn delta_decode() {
1062 assert_eq!(
1064 iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
1065 &[1, 2, 3, -1]
1066 );
1067
1068 assert_eq!(
1069 iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
1070 &[1, 1, 1, 1, 1]
1071 );
1072 }
1073
1074 #[test]
1075 fn delta_decode_all() {
1076 let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
1078 let device = Device::read(bytes.into()).unwrap();
1079 assert_eq!(
1080 device.iter().collect::<Vec<_>>(),
1081 &[1i8, -12, 30, -11, 101, 8, 42]
1082 );
1083 }
1084
1085 #[test]
1086 fn device_decode_does_not_overflow() {
1087 let bytes: &[u8] = &[0, 0xA, 0, 1, 0, 1];
1089 Device::read(bytes.into()).unwrap().iter().count();
1091 }
1092
1093 #[test]
1094 fn bit_storage_tests() {
1095 assert_eq!(bit_storage(0), 0);
1096 assert_eq!(bit_storage(1), 1);
1097 assert_eq!(bit_storage(2), 2);
1098 assert_eq!(bit_storage(4), 3);
1099 assert_eq!(bit_storage(9), 4);
1100 assert_eq!(bit_storage(0x123), 9);
1101 assert_eq!(bit_storage(0x1234), 13);
1102 assert_eq!(bit_storage(0xffff), 16);
1103 assert_eq!(bit_storage(0xffff_ffff), 32);
1104 }
1105
1106 #[test]
1107 fn default_coverage() {
1108 let coverage = CoverageTable::default();
1109 assert_eq!(coverage.iter().count(), 0)
1110 }
1111
1112 #[test]
1113 fn default_classdef() {
1114 let classdef = ClassDef::default();
1115 assert_eq!(classdef.population(), 0);
1116 assert_eq!(classdef.iter().count(), 0);
1117 }
1118}