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(test)]
27mod spec_tests;
28
29include!("../../generated/generated_layout.rs");
30
31impl<'a, T: FontRead<'a>> Lookup<'a, T> {
32 pub fn get_subtable(&self, offset: Offset16) -> Result<T, ReadError> {
33 self.resolve_offset(offset)
34 }
35
36 #[cfg(feature = "experimental_traverse")]
37 fn traverse_lookup_flag(&self) -> traversal::FieldType<'a> {
38 self.lookup_flag().to_bits().into()
39 }
40}
41
42pub trait ExtensionLookup<'a, T: FontRead<'a>>: FontRead<'a> {
47 fn extension(&self) -> Result<T, ReadError>;
48}
49
50pub enum Subtables<'a, T: FontRead<'a>, Ext: ExtensionLookup<'a, T>> {
55 Subtable(ArrayOfOffsets<'a, T>),
56 Extension(ArrayOfOffsets<'a, Ext>),
57}
58
59impl<'a, T: FontRead<'a> + 'a, Ext: ExtensionLookup<'a, T> + 'a> Subtables<'a, T, Ext> {
60 pub(crate) fn new(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
62 Subtables::Subtable(ArrayOfOffsets::new(offsets, data, ()))
63 }
64
65 pub(crate) fn new_ext(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
67 Subtables::Extension(ArrayOfOffsets::new(offsets, data, ()))
68 }
69
70 pub fn len(&self) -> usize {
72 match self {
73 Subtables::Subtable(inner) => inner.len(),
74 Subtables::Extension(inner) => inner.len(),
75 }
76 }
77
78 pub fn is_empty(&self) -> bool {
79 self.len() == 0
80 }
81
82 pub fn get(&self, idx: usize) -> Result<T, ReadError> {
84 match self {
85 Subtables::Subtable(inner) => inner.get(idx),
86 Subtables::Extension(inner) => inner.get(idx).and_then(|ext| ext.extension()),
87 }
88 }
89
90 pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
92 let (left, right) = match self {
93 Subtables::Subtable(inner) => (Some(inner.iter()), None),
94 Subtables::Extension(inner) => (
95 None,
96 Some(inner.iter().map(|ext| ext.and_then(|ext| ext.extension()))),
97 ),
98 };
99 left.into_iter()
100 .flatten()
101 .chain(right.into_iter().flatten())
102 }
103}
104
105pub enum FeatureParams<'a> {
107 StylisticSet(StylisticSetParams<'a>),
108 Size(SizeParams<'a>),
109 CharacterVariant(CharacterVariantParams<'a>),
110}
111
112impl ReadArgs for FeatureParams<'_> {
113 type Args = Tag;
114}
115
116impl<'a> FontReadWithArgs<'a> for FeatureParams<'a> {
117 fn read_with_args(bytes: FontData<'a>, args: &Tag) -> Result<FeatureParams<'a>, ReadError> {
118 match *args {
119 t if t == Tag::new(b"size") => SizeParams::read(bytes).map(Self::Size),
120 t if &t.to_raw()[..2] == b"ss" => {
122 StylisticSetParams::read(bytes).map(Self::StylisticSet)
123 }
124 t if &t.to_raw()[..2] == b"cv" => {
125 CharacterVariantParams::read(bytes).map(Self::CharacterVariant)
126 }
127 _ => Err(ReadError::InvalidFormat(0xdead)),
130 }
131 }
132}
133
134#[cfg(feature = "experimental_traverse")]
135impl<'a> SomeTable<'a> for FeatureParams<'a> {
136 fn type_name(&self) -> &str {
137 match self {
138 FeatureParams::StylisticSet(table) => table.type_name(),
139 FeatureParams::Size(table) => table.type_name(),
140 FeatureParams::CharacterVariant(table) => table.type_name(),
141 }
142 }
143
144 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
145 match self {
146 FeatureParams::StylisticSet(table) => table.get_field(idx),
147 FeatureParams::Size(table) => table.get_field(idx),
148 FeatureParams::CharacterVariant(table) => table.get_field(idx),
149 }
150 }
151}
152
153impl FeatureTableSubstitutionRecord {
154 pub fn alternate_feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
155 self.alternate_feature_offset()
156 .resolve_with_args(data, &Tag::new(b"NULL"))
157 }
158}
159
160impl<'a> CoverageTable<'a> {
161 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + 'a {
162 let (iter1, iter2) = match self {
164 CoverageTable::Format1(t) => (Some(t.glyph_array().iter().map(|g| g.get())), None),
165 CoverageTable::Format2(t) => {
166 let iter = t.range_records().iter().flat_map(RangeRecord::iter);
167 (None, Some(iter))
168 }
169 };
170
171 iter1
172 .into_iter()
173 .flatten()
174 .chain(iter2.into_iter().flatten())
175 }
176
177 #[inline]
179 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
180 match self {
181 CoverageTable::Format1(sub) => sub.get(gid),
182 CoverageTable::Format2(sub) => sub.get(gid),
183 }
184 }
185
186 #[cfg(feature = "std")]
188 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
189 match self {
190 CoverageTable::Format1(sub) => sub.intersects(glyphs),
191 CoverageTable::Format2(sub) => sub.intersects(glyphs),
192 }
193 }
194
195 #[cfg(feature = "std")]
197 pub fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
198 match self {
199 CoverageTable::Format1(sub) => sub.intersect_set(glyphs),
200 CoverageTable::Format2(sub) => sub.intersect_set(glyphs),
201 }
202 }
203
204 pub fn population(&self) -> usize {
206 match self {
207 CoverageTable::Format1(sub) => sub.population(),
208 CoverageTable::Format2(sub) => sub.population(),
209 }
210 }
211}
212
213impl CoverageFormat1<'_> {
214 #[inline]
216 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
217 let gid16: GlyphId16 = gid.into().try_into().ok()?;
218 let be_glyph: BigEndian<GlyphId16> = gid16.into();
219 self.glyph_array()
220 .binary_search(&be_glyph)
221 .ok()
222 .map(|idx| idx as _)
223 }
224
225 #[cfg(feature = "std")]
227 fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
228 let glyph_count = self.glyph_count() as u32;
229 let num_bits = 32 - glyph_count.leading_zeros();
230 if glyph_count > (glyphs.len() as u32) * num_bits {
231 glyphs.iter().any(|g| self.get(g).is_some())
232 } else {
233 self.glyph_array()
234 .iter()
235 .any(|g| glyphs.contains(GlyphId::from(g.get())))
236 }
237 }
238
239 #[cfg(feature = "std")]
241 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
242 let glyph_count = self.glyph_count() as u32;
243 let num_bits = 32 - glyph_count.leading_zeros();
244 if glyph_count > (glyphs.len() as u32) * num_bits {
245 glyphs
246 .iter()
247 .filter_map(|g| self.get(g).map(|_| g))
248 .collect()
249 } else {
250 self.glyph_array()
251 .iter()
252 .filter(|g| glyphs.contains(GlyphId::from(g.get())))
253 .map(|g| GlyphId::from(g.get()))
254 .collect()
255 }
256 }
257
258 pub fn population(&self) -> usize {
260 self.glyph_count() as usize
261 }
262}
263
264impl CoverageFormat2<'_> {
265 #[inline]
267 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
268 let gid: GlyphId16 = gid.into().try_into().ok()?;
269 self.range_records()
270 .binary_search_by(|rec| {
271 if rec.end_glyph_id() < gid {
272 Ordering::Less
273 } else if rec.start_glyph_id() > gid {
274 Ordering::Greater
275 } else {
276 Ordering::Equal
277 }
278 })
279 .ok()
280 .map(|idx| {
281 let rec = &self.range_records()[idx];
282 rec.start_coverage_index() + gid.to_u16() - rec.start_glyph_id().to_u16()
283 })
284 }
285
286 #[cfg(feature = "std")]
288 fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
289 let range_count = self.range_count() as u32;
290 let num_bits = 32 - range_count.leading_zeros();
291 if range_count > (glyphs.len() as u32) * num_bits {
292 glyphs.iter().any(|g| self.get(g).is_some())
293 } else {
294 self.range_records()
295 .iter()
296 .any(|record| record.intersects(glyphs))
297 }
298 }
299
300 #[cfg(feature = "std")]
302 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
303 let range_count = self.range_count() as u32;
304 let num_bits = 32 - range_count.leading_zeros();
305 if range_count > (glyphs.len() as u32) * num_bits {
306 glyphs
307 .iter()
308 .filter_map(|g| self.get(g).map(|_| g))
309 .collect()
310 } else {
311 let mut out = IntSet::empty();
312 let mut last = GlyphId16::from(0);
313 for record in self.range_records() {
314 let start_glyph = record.start_glyph_id();
316 if start_glyph < last {
317 break;
318 }
319 let end = record.end_glyph_id();
320 last = end;
321
322 let start = GlyphId::from(start_glyph);
323 if glyphs.contains(start) {
324 out.insert(start);
325 }
326
327 for g in glyphs.iter_after(start) {
328 if g.to_u32() > end.to_u32() {
329 break;
330 }
331 out.insert(g);
332 }
333 }
334 out
335 }
336 }
337
338 pub fn population(&self) -> usize {
340 self.range_records()
341 .iter()
342 .fold(0, |acc, record| acc + record.population())
343 }
344}
345
346impl RangeRecord {
347 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + '_ {
348 (self.start_glyph_id().to_u16()..=self.end_glyph_id().to_u16()).map(GlyphId16::new)
349 }
350
351 #[cfg(feature = "std")]
353 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
354 glyphs.intersects_range(
355 GlyphId::from(self.start_glyph_id())..=GlyphId::from(self.end_glyph_id()),
356 )
357 }
358
359 pub fn population(&self) -> usize {
361 let start = self.start_glyph_id().to_u32() as usize;
362 let end = self.end_glyph_id().to_u32() as usize;
363 if start > end {
364 0
365 } else {
366 end - start + 1
367 }
368 }
369}
370
371impl DeltaFormat {
372 pub(crate) fn value_count(self, start_size: u16, end_size: u16) -> usize {
373 let range_len = end_size.saturating_add(1).saturating_sub(start_size) as usize;
374 let val_per_word = match self {
375 DeltaFormat::Local2BitDeltas => 8,
376 DeltaFormat::Local4BitDeltas => 4,
377 DeltaFormat::Local8BitDeltas => 2,
378 _ => return 0,
379 };
380
381 let count = range_len / val_per_word;
382 let extra = (range_len % val_per_word).min(1);
383 count + extra
384 }
385}
386
387impl From<DeltaFormat> for i64 {
390 fn from(value: DeltaFormat) -> Self {
391 value as u16 as _
392 }
393}
394
395impl<'a> ClassDefFormat1<'a> {
396 #[inline]
398 pub fn get(&self, gid: GlyphId16) -> u16 {
399 if gid < self.start_glyph_id() {
400 return 0;
401 }
402 let idx = gid.to_u16() - self.start_glyph_id().to_u16();
403 self.class_value_array()
404 .get(idx as usize)
405 .map(|x| x.get())
406 .unwrap_or(0)
407 }
408
409 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
411 let start = self.start_glyph_id();
412 self.class_value_array()
413 .iter()
414 .enumerate()
415 .map(move |(i, val)| {
416 let gid = start.to_u16().saturating_add(i as u16);
417 (GlyphId16::new(gid), val.get())
418 })
419 }
420
421 pub fn population(&self) -> usize {
423 self.glyph_count() as usize
424 }
425
426 #[cfg(feature = "std")]
428 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
429 let mut out = IntSet::empty();
430 if glyphs.is_empty() {
431 return out;
432 }
433
434 let start_glyph = self.start_glyph_id().to_u32();
435 let glyph_count = self.glyph_count();
436 let end_glyph = start_glyph + glyph_count as u32 - 1;
437 if glyphs.first().unwrap().to_u32() < start_glyph
438 || glyphs.last().unwrap().to_u32() > end_glyph
439 {
440 out.insert(0);
441 }
442
443 let class_values = self.class_value_array();
444 if glyphs.contains(GlyphId::from(start_glyph)) {
445 let Some(start_glyph_class) = class_values.first() else {
446 return out;
447 };
448 out.insert(start_glyph_class.get());
449 }
450
451 for g in glyphs.iter_after(GlyphId::from(start_glyph)) {
452 let g = g.to_u32();
453 if g > end_glyph {
454 break;
455 }
456
457 let idx = g - start_glyph;
458 let Some(class) = class_values.get(idx as usize) else {
459 break;
460 };
461 out.insert(class.get());
462 }
463 out
464 }
465
466 #[cfg(feature = "std")]
468 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
469 let mut out = IntSet::empty();
470 if glyphs.is_empty() {
471 return out;
472 }
473
474 let start_glyph = self.start_glyph_id().to_u32();
475 let glyph_count = self.glyph_count();
476 let end_glyph = start_glyph + glyph_count as u32 - 1;
477 if class == 0 {
478 let first = glyphs.first().unwrap();
479 if first.to_u32() < start_glyph {
480 out.extend(glyphs.range(first..GlyphId::from(start_glyph)));
481 }
482
483 let last = glyphs.last().unwrap();
484 if last.to_u32() > end_glyph {
485 out.extend(glyphs.range(GlyphId::from(end_glyph + 1)..=last));
486 }
487 return out;
488 }
489
490 let class_values = self.class_value_array();
491 for g in glyphs.range(GlyphId::from(start_glyph)..=GlyphId::from(end_glyph)) {
492 let idx = g.to_u32() - start_glyph;
493 let Some(c) = class_values.get(idx as usize) else {
494 break;
495 };
496 if c.get() == class {
497 out.insert(g);
498 }
499 }
500 out
501 }
502}
503
504impl<'a> ClassDefFormat2<'a> {
505 #[inline]
507 pub fn get(&self, gid: GlyphId16) -> u16 {
508 let records = self.class_range_records();
509 let ix = match records.binary_search_by(|rec| rec.start_glyph_id().cmp(&gid)) {
510 Ok(ix) => ix,
511 Err(ix) => ix.saturating_sub(1),
512 };
513 if let Some(record) = records.get(ix) {
514 if (record.start_glyph_id()..=record.end_glyph_id()).contains(&gid) {
515 return record.class();
516 }
517 }
518 0
519 }
520
521 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
523 self.class_range_records().iter().flat_map(|range| {
524 let start = range.start_glyph_id().to_u16();
525 let end = range.end_glyph_id().to_u16();
526 (start..=end).map(|gid| (GlyphId16::new(gid), range.class()))
527 })
528 }
529
530 pub fn population(&self) -> usize {
532 self.class_range_records()
533 .iter()
534 .fold(0, |acc, record| acc + record.population())
535 }
536
537 #[cfg(feature = "std")]
539 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
540 let mut out = IntSet::empty();
541 if glyphs.is_empty() {
542 return out;
543 }
544
545 if self.class_range_count() == 0 {
546 out.insert(0);
547 return out;
548 }
549
550 let range_records = self.class_range_records();
551 let first_record = range_records[0];
552
553 if glyphs.first().unwrap() < first_record.start_glyph_id() {
554 out.insert(0);
555 } else {
556 let mut glyph = GlyphId::from(first_record.end_glyph_id());
557 for record in range_records.iter().skip(1) {
558 let Some(g) = glyphs.iter_after(glyph).next() else {
559 break;
560 };
561
562 if g < record.start_glyph_id() {
563 out.insert(0);
564 break;
565 }
566 glyph = GlyphId::from(record.end_glyph_id());
567 }
568 if glyphs.iter_after(glyph).next().is_some() {
569 out.insert(0);
570 }
571 }
572
573 let num_ranges = self.class_range_count();
574 let num_bits = 16 - num_ranges.leading_zeros();
575 if num_ranges as u64 > glyphs.len() * num_bits as u64 {
576 for g in glyphs.iter() {
577 let class = self.get(GlyphId16::from(g.to_u32() as u16));
578 if class != 0 {
579 out.insert(class);
580 }
581 }
582 } else {
583 for record in range_records {
584 if glyphs.intersects_range(
585 GlyphId::from(record.start_glyph_id())..=GlyphId::from(record.end_glyph_id()),
586 ) {
587 out.insert(record.class());
588 }
589 }
590 }
591 out
592 }
593
594 #[cfg(feature = "std")]
596 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
597 let mut out = IntSet::empty();
598 if glyphs.is_empty() {
599 return out;
600 }
601
602 let first = glyphs.first().unwrap().to_u32();
603 let last = glyphs.last().unwrap().to_u32();
604 if class == 0 {
605 let mut start = first;
606 for range in self.class_range_records() {
607 let range_start = range.start_glyph_id().to_u32();
608 if start < range_start {
609 out.extend(glyphs.range(GlyphId::from(start)..GlyphId::from(range_start)));
610 }
611
612 let range_end = range.end_glyph_id().to_u32();
613 if range_end >= last {
614 break;
615 }
616 start = range_end + 1;
617 }
618 return out;
619 }
620
621 let num_ranges = self.class_range_count();
622 let num_bits = 16 - num_ranges.leading_zeros();
623 if num_ranges as u64 > glyphs.len() * num_bits as u64 {
624 for g in glyphs.iter() {
625 let c = self.get(GlyphId16::from(g.to_u32() as u16));
626 if c == class {
627 out.insert(g);
628 }
629 }
630 } else {
631 for range in self.class_range_records() {
632 let range_start = range.start_glyph_id().to_u32();
633 let range_end = range.end_glyph_id().to_u32();
634 if range_start > last || range.end_glyph_id().to_u32() < first {
635 break;
636 }
637 if range.class() != class {
638 continue;
639 }
640 out.extend(glyphs.range(GlyphId::from(range_start)..=GlyphId::from(range_end)));
641 }
642 }
643 out
644 }
645}
646
647impl ClassRangeRecord {
648 pub fn population(&self) -> usize {
650 let start = self.start_glyph_id().to_u32() as usize;
651 let end = self.end_glyph_id().to_u32() as usize;
652 if start > end {
653 0
654 } else {
655 end - start + 1
656 }
657 }
658}
659
660impl ClassDef<'_> {
661 #[inline]
663 pub fn get(&self, gid: GlyphId16) -> u16 {
664 match self {
665 ClassDef::Format1(table) => table.get(gid),
666 ClassDef::Format2(table) => table.get(gid),
667 }
668 }
669
670 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + '_ {
674 let (one, two) = match self {
675 ClassDef::Format1(inner) => (Some(inner.iter()), None),
676 ClassDef::Format2(inner) => (None, Some(inner.iter())),
677 };
678 one.into_iter().flatten().chain(two.into_iter().flatten())
679 }
680
681 pub fn population(&self) -> usize {
683 match self {
684 ClassDef::Format1(table) => table.population(),
685 ClassDef::Format2(table) => table.population(),
686 }
687 }
688
689 #[cfg(feature = "std")]
691 pub fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
692 match self {
693 ClassDef::Format1(table) => table.intersect_classes(glyphs),
694 ClassDef::Format2(table) => table.intersect_classes(glyphs),
695 }
696 }
697
698 #[cfg(feature = "std")]
700 pub fn intersected_class_glyphs(
701 &self,
702 glyphs: &IntSet<GlyphId>,
703 class: u16,
704 ) -> IntSet<GlyphId> {
705 match self {
706 ClassDef::Format1(table) => table.intersected_class_glyphs(glyphs, class),
707 ClassDef::Format2(table) => table.intersected_class_glyphs(glyphs, class),
708 }
709 }
710}
711
712impl<'a> Device<'a> {
713 pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
715 let format = self.delta_format();
716 let mut n = (self.end_size() - self.start_size()) as usize + 1;
717 let deltas_per_word = match format {
718 DeltaFormat::Local2BitDeltas => 8,
719 DeltaFormat::Local4BitDeltas => 4,
720 DeltaFormat::Local8BitDeltas => 2,
721 _ => 0,
722 };
723
724 self.delta_value().iter().flat_map(move |val| {
725 let iter = iter_packed_values(val.get(), format, n);
726 n = n.saturating_sub(deltas_per_word);
727 iter
728 })
729 }
730}
731
732fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
733 let mut decoded = [None; 8];
734 let (mask, sign_mask, bits) = match format {
735 DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
736 DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
737 DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
738 _ => (0, 0, 0),
739 };
740
741 let max_per_word = 16 / bits;
742 #[allow(clippy::needless_range_loop)] for i in 0..n.min(max_per_word) {
744 let mask = mask << ((16 - bits) - i * bits);
745 let val = (raw & mask) >> ((16 - bits) - i * bits);
746 let sign = val & sign_mask != 0;
747
748 let val = if sign {
749 -((((!val) & mask) + 1) as i8)
751 } else {
752 val as i8
753 };
754 decoded[i] = Some(val)
755 }
756 decoded.into_iter().flatten()
757}
758
759impl From<VariationIndex<'_>> for DeltaSetIndex {
760 fn from(src: VariationIndex) -> DeltaSetIndex {
761 DeltaSetIndex {
762 outer: src.delta_set_outer_index(),
763 inner: src.delta_set_inner_index(),
764 }
765 }
766}
767
768#[derive(Clone)]
774pub struct TaggedElement<T> {
775 pub tag: Tag,
776 pub element: T,
777}
778
779impl<T> TaggedElement<T> {
780 pub fn new(tag: Tag, element: T) -> Self {
781 Self { tag, element }
782 }
783}
784
785impl<T> std::ops::Deref for TaggedElement<T> {
786 type Target = T;
787
788 fn deref(&self) -> &Self::Target {
789 &self.element
790 }
791}
792
793#[cfg(test)]
794mod tests {
795 use super::*;
796
797 #[test]
798 fn coverage_get_format1() {
799 const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
801
802 let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
803 assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
804 assert_eq!(coverage.get(GlyphId::new(2)), None);
805 assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
806 assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
807 assert_eq!(coverage.get(GlyphId::new(45)), None);
808 }
809
810 #[test]
811 fn coverage_get_format2() {
812 const COV2_DATA: FontData =
814 FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
815 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
816 assert_eq!(coverage.get(GlyphId::new(2)), None);
817 assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
818 assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
819 assert_eq!(coverage.get(GlyphId::new(10)), None);
820 assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
821 assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
822 assert_eq!(coverage.get(GlyphId::new(40)), None);
823 }
824
825 #[test]
826 fn classdef_get_format2() {
827 let classdef = ClassDef::read(FontData::new(
828 font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
829 ))
830 .unwrap();
831 assert!(matches!(classdef, ClassDef::Format2(..)));
832 let gid_class_pairs = [
833 (616, 1),
834 (617, 1),
835 (618, 1),
836 (624, 1),
837 (625, 1),
838 (626, 1),
839 (652, 2),
840 (653, 2),
841 (654, 2),
842 (655, 2),
843 (661, 2),
844 ];
845 for (gid, class) in gid_class_pairs {
846 assert_eq!(classdef.get(GlyphId16::new(gid)), class);
847 }
848 for (gid, class) in classdef.iter() {
849 assert_eq!(classdef.get(gid), class);
850 }
851 }
852
853 #[test]
854 fn delta_decode() {
855 assert_eq!(
857 iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
858 &[1, 2, 3, -1]
859 );
860
861 assert_eq!(
862 iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
863 &[1, 1, 1, 1, 1]
864 );
865 }
866
867 #[test]
868 fn delta_decode_all() {
869 let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
871 let device = Device::read(bytes.into()).unwrap();
872 assert_eq!(
873 device.iter().collect::<Vec<_>>(),
874 &[1i8, -12, 30, -11, 101, 8, 42]
875 );
876 }
877}