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;
19use crate::TableProvider;
20
21#[cfg(feature = "std")]
22pub(crate) use closure::{
23 ContextFormat1, ContextFormat2, ContextFormat3, LayoutLookupList, LookupClosure,
24 LookupClosureCtx, SeqCache,
25};
26
27#[cfg(feature = "std")]
28pub use closure::Intersect;
29
30#[cfg(test)]
31mod spec_tests;
32
33include!("../../generated/generated_layout.rs");
34
35impl<'a, T: FontRead<'a, Args = ()>> Lookup<'a, T> {
36 pub fn get_subtable(&self, offset: Offset16) -> Result<T, ReadError> {
37 self.resolve_offset(offset)
38 }
39}
40
41pub trait ExtensionLookup<'a, T: FontRead<'a, Args = ()>>: FontRead<'a, Args = ()> {
46 fn extension(&self) -> Result<T, ReadError>;
47}
48
49pub enum Subtables<'a, T: FontRead<'a, Args = ()>, Ext: ExtensionLookup<'a, T>> {
54 Subtable(ArrayOfOffsets<'a, T>),
55 Extension(ArrayOfOffsets<'a, Ext>),
56}
57
58impl<'a, T: FontRead<'a, Args = ()> + 'a, Ext: ExtensionLookup<'a, T> + 'a> Subtables<'a, T, Ext> {
59 pub(crate) fn new(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
61 Subtables::Subtable(ArrayOfOffsets::new(offsets, data, ()))
62 }
63
64 pub(crate) fn new_ext(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
66 Subtables::Extension(ArrayOfOffsets::new(offsets, data, ()))
67 }
68
69 pub fn len(&self) -> usize {
71 match self {
72 Subtables::Subtable(inner) => inner.len(),
73 Subtables::Extension(inner) => inner.len(),
74 }
75 }
76
77 pub fn is_empty(&self) -> bool {
78 self.len() == 0
79 }
80
81 pub fn get(&self, idx: usize) -> Result<T, ReadError> {
83 match self {
84 Subtables::Subtable(inner) => inner.get(idx),
85 Subtables::Extension(inner) => inner.get(idx).and_then(|ext| ext.extension()),
86 }
87 }
88
89 pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
91 let (left, right) = match self {
92 Subtables::Subtable(inner) => (Some(inner.iter()), None),
93 Subtables::Extension(inner) => (
94 None,
95 Some(inner.iter().map(|ext| ext.and_then(|ext| ext.extension()))),
96 ),
97 };
98 left.into_iter()
99 .flatten()
100 .chain(right.into_iter().flatten())
101 }
102}
103
104pub enum FeatureParams<'a> {
106 StylisticSet(StylisticSetParams<'a>),
107 Size(SizeParams<'a>),
108 CharacterVariant(CharacterVariantParams<'a>),
109}
110
111impl ReadArgs for FeatureParams<'_> {
112 type Args = Tag;
113}
114
115impl<'a> FontRead<'a> for FeatureParams<'a> {
116 fn read_with_args(bytes: FontData<'a>, args: Tag) -> Result<FeatureParams<'a>, ReadError> {
117 match args {
118 t if t == Tag::new(b"size") => SizeParams::read(bytes).map(Self::Size),
119 t if &t.to_raw()[..2] == b"ss" => {
121 StylisticSetParams::read(bytes).map(Self::StylisticSet)
122 }
123 t if &t.to_raw()[..2] == b"cv" => {
124 CharacterVariantParams::read(bytes).map(Self::CharacterVariant)
125 }
126 _ => Err(ReadError::InvalidFormat(0xdead)),
129 }
130 }
131}
132
133impl FeatureVariations<'_> {
134 pub fn index_for_coords(&self, coords: &[F2Dot14]) -> Option<u32> {
137 for (index, rec) in self.feature_variation_records().iter().enumerate() {
138 if rec.condition_set_offset().is_null() {
141 return Some(index as u32);
142 }
143 let Some(Ok(condition_set)) = rec.condition_set(self.offset_data()) else {
144 continue;
145 };
146 if condition_set
148 .conditions()
149 .iter()
150 .filter_map(Result::ok)
152 .all(|cond| match cond {
153 Condition::Format1AxisRange(format1) => {
154 let coord = coords
155 .get(format1.axis_index() as usize)
156 .copied()
157 .unwrap_or_default();
158 coord >= format1.filter_range_min_value()
159 && coord <= format1.filter_range_max_value()
160 }
161 _ => false,
162 })
163 {
164 return Some(index as u32);
165 }
166 }
167 None
168 }
169}
170
171#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
173pub struct SelectedFeatureVariations {
174 pub gsub: Option<u32>,
176 pub gpos: Option<u32>,
178}
179
180impl SelectedFeatureVariations {
181 pub fn new<'a>(tables: &impl TableProvider<'a>, coords: &[F2Dot14]) -> Self {
184 let feature_var_tables = [
185 tables
186 .gsub()
187 .ok()
188 .and_then(|gsub| gsub.feature_variations()),
189 tables
190 .gpos()
191 .ok()
192 .and_then(|gpos| gpos.feature_variations()),
193 ];
194 let [gsub, gpos] = feature_var_tables.map(|feature_vars| {
195 feature_vars
196 .transpose()
197 .ok()
198 .flatten()
199 .and_then(|feature_vars| feature_vars.index_for_coords(coords))
200 });
201 Self { gsub, gpos }
202 }
203}
204
205impl FeatureTableSubstitutionRecord {
206 pub fn alternate_feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
207 self.alternate_feature_offset()
208 .resolve_with_args(data, Tag::new(b"NULL"))
209 }
210}
211
212fn bit_storage(v: u32) -> u32 {
213 u32::BITS - v.leading_zeros()
214}
215
216impl<'a> CoverageTable<'a> {
217 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + 'a {
218 let (iter1, iter2) = match self {
220 CoverageTable::Format1(t) => (Some(t.glyph_array().iter().map(|g| g.get())), None),
221 CoverageTable::Format2(t) => {
222 let iter = t.range_records().iter().flat_map(RangeRecord::iter);
223 (None, Some(iter))
224 }
225 };
226
227 iter1
228 .into_iter()
229 .flatten()
230 .chain(iter2.into_iter().flatten())
231 }
232
233 #[inline]
235 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
236 match self {
237 CoverageTable::Format1(sub) => sub.get(gid),
238 CoverageTable::Format2(sub) => sub.get(gid),
239 }
240 }
241
242 #[cfg(feature = "std")]
244 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
245 match self {
246 CoverageTable::Format1(sub) => sub.intersects(glyphs),
247 CoverageTable::Format2(sub) => sub.intersects(glyphs),
248 }
249 }
250
251 #[cfg(feature = "std")]
253 pub fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
254 match self {
255 CoverageTable::Format1(sub) => sub.intersect_set(glyphs),
256 CoverageTable::Format2(sub) => sub.intersect_set(glyphs),
257 }
258 }
259
260 pub fn population(&self) -> usize {
262 match self {
263 CoverageTable::Format1(sub) => sub.population(),
264 CoverageTable::Format2(sub) => sub.population(),
265 }
266 }
267
268 pub fn cost(&self) -> u32 {
270 match self {
271 CoverageTable::Format1(sub) => sub.cost(),
272 CoverageTable::Format2(sub) => sub.cost(),
273 }
274 }
275}
276
277impl CoverageFormat1<'_> {
278 #[inline]
280 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
281 let gid16: GlyphId16 = gid.into().try_into().ok()?;
282 let be_glyph: BigEndian<GlyphId16> = gid16.into();
283 self.glyph_array()
284 .binary_search(&be_glyph)
285 .ok()
286 .map(|idx| idx as _)
287 }
288
289 #[cfg(feature = "std")]
291 fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
292 let glyph_count = self.glyph_count() as u32;
293 if glyph_count > (glyphs.len() as u32) * self.cost() {
294 glyphs.iter().any(|g| self.get(g).is_some())
295 } else {
296 self.glyph_array()
297 .iter()
298 .any(|g| glyphs.contains(GlyphId::from(g.get())))
299 }
300 }
301
302 #[cfg(feature = "std")]
304 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
305 let glyph_count = self.glyph_count() as u32;
306 if glyph_count > (glyphs.len() as u32) * self.cost() {
307 glyphs
308 .iter()
309 .filter_map(|g| self.get(g).map(|_| g))
310 .collect()
311 } else {
312 self.glyph_array()
313 .iter()
314 .filter(|g| glyphs.contains(GlyphId::from(g.get())))
315 .map(|g| GlyphId::from(g.get()))
316 .collect()
317 }
318 }
319
320 pub fn population(&self) -> usize {
322 self.glyph_count() as usize
323 }
324
325 pub fn cost(&self) -> u32 {
327 bit_storage(self.glyph_count() as u32)
328 }
329}
330
331impl CoverageFormat2<'_> {
332 #[inline]
334 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
335 let gid: GlyphId16 = gid.into().try_into().ok()?;
336 self.range_records()
337 .binary_search_by(|rec| {
338 if rec.end_glyph_id() < gid {
339 Ordering::Less
340 } else if rec.start_glyph_id() > gid {
341 Ordering::Greater
342 } else {
343 Ordering::Equal
344 }
345 })
346 .ok()
347 .and_then(|idx| {
348 let rec = &self.range_records()[idx];
349 rec.start_coverage_index()
351 .checked_add(gid.to_u16() - rec.start_glyph_id().to_u16())
352 })
353 }
354
355 #[cfg(feature = "std")]
357 fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
358 let range_count = self.range_count() as u32;
359 if range_count > (glyphs.len() as u32) * self.cost() {
360 glyphs.iter().any(|g| self.get(g).is_some())
361 } else {
362 self.range_records()
363 .iter()
364 .any(|record| record.intersects(glyphs))
365 }
366 }
367
368 #[cfg(feature = "std")]
370 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
371 let range_count = self.range_count() as u32;
372 if range_count > (glyphs.len() as u32) * self.cost() {
373 glyphs
374 .iter()
375 .filter_map(|g| self.get(g).map(|_| g))
376 .collect()
377 } else {
378 let mut out = IntSet::empty();
379 let mut last = GlyphId16::from(0);
380 for record in self.range_records() {
381 let start_glyph = record.start_glyph_id();
383 if start_glyph < last {
384 break;
385 }
386 let end = record.end_glyph_id();
387 last = end;
388
389 let start = GlyphId::from(start_glyph);
390 if glyphs.contains(start) {
391 out.insert(start);
392 }
393
394 for g in glyphs.iter_after(start) {
395 if g.to_u32() > end.to_u32() {
396 break;
397 }
398 out.insert(g);
399 }
400 }
401 out
402 }
403 }
404
405 pub fn population(&self) -> usize {
407 self.range_records()
408 .iter()
409 .fold(0, |acc, record| acc + record.population())
410 }
411
412 pub fn cost(&self) -> u32 {
414 bit_storage(self.range_count() as u32)
415 }
416}
417
418impl RangeRecord {
419 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + '_ {
420 (self.start_glyph_id().to_u16()..=self.end_glyph_id().to_u16()).map(GlyphId16::new)
421 }
422
423 #[cfg(feature = "std")]
425 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
426 glyphs.intersects_range(
427 GlyphId::from(self.start_glyph_id())..=GlyphId::from(self.end_glyph_id()),
428 )
429 }
430
431 pub fn population(&self) -> usize {
433 let start = self.start_glyph_id().to_u32() as usize;
434 let end = self.end_glyph_id().to_u32() as usize;
435 if start > end {
436 0
437 } else {
438 end - start + 1
439 }
440 }
441}
442
443impl DeltaFormat {
444 pub(crate) fn value_count(self, start_size: u16, end_size: u16) -> usize {
445 let range_len = end_size.saturating_add(1).saturating_sub(start_size) as usize;
446 let val_per_word = match self {
447 DeltaFormat::Local2BitDeltas => 8,
448 DeltaFormat::Local4BitDeltas => 4,
449 DeltaFormat::Local8BitDeltas => 2,
450 _ => return 0,
451 };
452
453 let count = range_len / val_per_word;
454 let extra = (range_len % val_per_word).min(1);
455 count + extra
456 }
457}
458
459impl From<DeltaFormat> for i64 {
462 fn from(value: DeltaFormat) -> Self {
463 value as u16 as _
464 }
465}
466
467impl<'a> ClassDefFormat1<'a> {
468 #[inline]
470 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
471 let Some(idx) = gid
472 .into()
473 .to_u32()
474 .checked_sub(self.start_glyph_id().to_u32())
475 else {
476 return 0;
477 };
478 self.class_value_array()
479 .get(idx as usize)
480 .map(|x| x.get())
481 .unwrap_or(0)
482 }
483
484 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
486 let start = self.start_glyph_id();
487 self.class_value_array()
488 .iter()
489 .enumerate()
490 .map(move |(i, val)| {
491 let gid = start.to_u16().saturating_add(i as u16);
492 (GlyphId16::new(gid), val.get())
493 })
494 }
495
496 pub fn population(&self) -> usize {
498 self.glyph_count() as usize
499 }
500
501 pub fn cost(&self) -> u32 {
503 1
504 }
505
506 #[cfg(feature = "std")]
508 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
509 let mut out = IntSet::empty();
510 if glyphs.is_empty() {
511 return out;
512 }
513
514 let start_glyph = self.start_glyph_id().to_u32();
515 let class_values = self.class_value_array();
516 if class_values.is_empty() {
517 out.insert(0);
518 return out;
519 }
520 let end_glyph = start_glyph + class_values.len() as u32 - 1;
521 if glyphs.first().unwrap().to_u32() < start_glyph
522 || glyphs.last().unwrap().to_u32() > end_glyph
523 {
524 out.insert(0);
525 }
526
527 if glyphs.contains(GlyphId::from(start_glyph)) {
528 let Some(start_glyph_class) = class_values.first() else {
529 return out;
530 };
531 out.insert(start_glyph_class.get());
532 }
533
534 for g in glyphs.iter_after(GlyphId::from(start_glyph)) {
535 let g = g.to_u32();
536 if g > end_glyph {
537 break;
538 }
539
540 let idx = g - start_glyph;
541 let Some(class) = class_values.get(idx as usize) else {
542 break;
543 };
544 out.insert(class.get());
545 }
546 out
547 }
548
549 #[cfg(feature = "std")]
551 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
552 let mut out = IntSet::empty();
553 if glyphs.is_empty() {
554 return out;
555 }
556
557 let start_glyph = self.start_glyph_id().to_u32();
558 let glyph_count = self.glyph_count();
559 if glyph_count == 0 {
563 if class == 0 {
564 out.extend(glyphs.iter());
565 }
566 return out;
567 }
568 let end_glyph = start_glyph + glyph_count as u32 - 1;
569 if class == 0 {
570 let first = glyphs.first().unwrap();
571 if first.to_u32() < start_glyph {
572 out.extend(glyphs.range(first..GlyphId::from(start_glyph)));
573 }
574
575 let last = glyphs.last().unwrap();
576 if last.to_u32() > end_glyph {
577 out.extend(glyphs.range(GlyphId::from(end_glyph + 1)..=last));
578 }
579 return out;
580 }
581
582 let class_values = self.class_value_array();
583 for g in glyphs.range(GlyphId::from(start_glyph)..=GlyphId::from(end_glyph)) {
584 let idx = g.to_u32() - start_glyph;
585 let Some(c) = class_values.get(idx as usize) else {
586 break;
587 };
588 if c.get() == class {
589 out.insert(g);
590 }
591 }
592 out
593 }
594
595 #[cfg(feature = "std")]
597 fn intersects_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> bool {
598 if glyphs.is_empty() {
599 return false;
600 }
601
602 let start_glyph = self.start_glyph_id().to_u32();
603 let glyph_count = self.glyph_count();
604 if glyph_count == 0 {
608 return class == 0;
609 }
610 let end_glyph = start_glyph + glyph_count as u32 - 1;
611 if class == 0 {
612 let first = glyphs.first().unwrap();
613 if first.to_u32() < start_glyph {
614 return true;
615 }
616
617 let last = glyphs.last().unwrap();
618 if last.to_u32() > end_glyph {
619 return true;
620 }
621 }
622
623 let class_values = self.class_value_array();
624 for g in glyphs.range(GlyphId::from(start_glyph)..=GlyphId::from(end_glyph)) {
625 let idx = g.to_u32() - start_glyph;
626 let Some(c) = class_values.get(idx as usize) else {
627 return false;
628 };
629 if c.get() == class {
630 return true;
631 }
632 }
633 false
634 }
635}
636
637impl<'a> ClassDefFormat2<'a> {
638 #[inline]
640 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
641 let gid = gid.into().to_u32();
642 let records = self.class_range_records();
643 let ix = match records.binary_search_by(|rec| rec.start_glyph_id().to_u32().cmp(&gid)) {
644 Ok(ix) => ix,
645 Err(ix) => ix.saturating_sub(1),
646 };
647 if let Some(record) = records.get(ix) {
648 if (record.start_glyph_id().to_u32()..=record.end_glyph_id().to_u32()).contains(&gid) {
649 return record.class();
650 }
651 }
652 0
653 }
654
655 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
657 self.class_range_records().iter().flat_map(|range| {
658 let start = range.start_glyph_id().to_u16();
659 let end = range.end_glyph_id().to_u16();
660 (start..=end).map(|gid| (GlyphId16::new(gid), range.class()))
661 })
662 }
663
664 pub fn population(&self) -> usize {
666 self.class_range_records()
667 .iter()
668 .fold(0, |acc, record| acc + record.population())
669 }
670
671 pub fn cost(&self) -> u32 {
673 bit_storage(self.class_range_count() as u32)
674 }
675
676 #[cfg(feature = "std")]
678 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
679 let mut out = IntSet::empty();
680 if glyphs.is_empty() {
681 return out;
682 }
683
684 let range_records = self.class_range_records();
685 let Some(first_record) = range_records.first() else {
686 out.insert(0);
687 return out;
688 };
689
690 if glyphs.first().unwrap() < first_record.start_glyph_id() {
691 out.insert(0);
692 } else {
693 let mut glyph = GlyphId::from(first_record.end_glyph_id());
694 for record in range_records.iter().skip(1) {
695 let Some(g) = glyphs.iter_after(glyph).next() else {
696 break;
697 };
698
699 if g < record.start_glyph_id() {
700 out.insert(0);
701 break;
702 }
703 glyph = GlyphId::from(record.end_glyph_id());
704 }
705 if glyphs.iter_after(glyph).next().is_some() {
706 out.insert(0);
707 }
708 }
709
710 let num_ranges = self.class_range_count();
711 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
712 for g in glyphs.iter() {
713 let class = self.get(g);
714 if class != 0 {
715 out.insert(class);
716 }
717 }
718 } else {
719 for record in range_records {
720 if glyphs.intersects_range(
721 GlyphId::from(record.start_glyph_id())..=GlyphId::from(record.end_glyph_id()),
722 ) {
723 out.insert(record.class());
724 }
725 }
726 }
727 out
728 }
729
730 #[cfg(feature = "std")]
732 fn intersected_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> IntSet<GlyphId> {
733 let mut out = IntSet::empty();
734 if glyphs.is_empty() {
735 return out;
736 }
737
738 let first = glyphs.first().unwrap().to_u32();
739 let last = glyphs.last().unwrap().to_u32();
740 if class == 0 {
741 let mut start = first;
742 for range in self.class_range_records() {
743 let range_start = range.start_glyph_id().to_u32();
744 if start < range_start {
745 out.extend(glyphs.range(GlyphId::from(start)..GlyphId::from(range_start)));
746 }
747
748 let range_end = range.end_glyph_id().to_u32();
749 if range_end >= last {
750 break;
751 }
752 start = range_end + 1;
753 }
754
755 if start <= last {
756 out.extend(glyphs.range(GlyphId::from(start)..=GlyphId::from(last)));
757 }
758 return out;
759 }
760
761 let num_ranges = self.class_range_count();
762 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
763 for g in glyphs.iter() {
764 let c = self.get(g);
765 if c == class {
766 out.insert(g);
767 }
768 }
769 } else {
770 for range in self.class_range_records() {
771 let range_start = range.start_glyph_id().to_u32();
772 let range_end = range.end_glyph_id().to_u32();
773 if range_start > last {
774 break;
775 }
776 if range.class() != class || range.end_glyph_id().to_u32() < first {
777 continue;
778 }
779 out.extend(glyphs.range(GlyphId::from(range_start)..=GlyphId::from(range_end)));
780 }
781 }
782 out
783 }
784
785 #[cfg(feature = "std")]
787 fn intersects_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> bool {
788 if glyphs.is_empty() {
789 return false;
790 }
791
792 if self.class_range_count() == 0 {
796 return class == 0;
797 }
798
799 let first = glyphs.first().unwrap().to_u32();
800 if class == 0 {
801 let mut last_end = first;
802 for (i, range) in self.class_range_records().iter().enumerate() {
803 let range_start = range.start_glyph_id().to_u32();
804 let range_end = range.end_glyph_id().to_u32();
805 if i == 0 {
806 if first < range_start {
807 return true;
808 }
809 last_end = range_end;
810 continue;
811 }
812
813 if range_start == last_end + 1 {
814 last_end = range_end;
815 continue;
816 }
817
818 if glyphs
819 .intersects_range(GlyphId::from(last_end + 1)..=GlyphId::from(range_start - 1))
820 {
821 return true;
822 };
823 last_end = range_end + 1;
824 }
825 if glyphs
826 .iter_after(GlyphId::from(last_end + 1))
827 .next()
828 .is_some()
829 {
830 return true;
831 }
832 }
833
834 let num_ranges = self.class_range_count();
835 if num_ranges as u64 > glyphs.len() * self.cost() as u64 {
836 for g in glyphs.iter() {
837 let c = self.get(g);
838 if c == class {
839 return true;
840 }
841 }
842 } else {
843 let last = glyphs.last().unwrap().to_u32();
844 for range in self.class_range_records() {
845 let range_start = range.start_glyph_id().to_u32();
846 let range_end = range.end_glyph_id().to_u32();
847 if range_start > last {
848 break;
849 }
850 if range_end < first {
851 continue;
852 }
853 if range.class() == class
854 && glyphs
855 .intersects_range(GlyphId::from(range_start)..=GlyphId::from(range_end))
856 {
857 return true;
858 }
859 }
860 }
861 false
862 }
863}
864
865impl ClassRangeRecord {
866 pub fn population(&self) -> usize {
868 let start = self.start_glyph_id().to_u32() as usize;
869 let end = self.end_glyph_id().to_u32() as usize;
870 if start > end {
871 0
872 } else {
873 end - start + 1
874 }
875 }
876}
877
878impl ClassDef<'_> {
879 #[inline]
881 pub fn get(&self, gid: impl Into<GlyphId>) -> u16 {
882 match self {
883 ClassDef::Format1(table) => table.get(gid),
884 ClassDef::Format2(table) => table.get(gid),
885 }
886 }
887
888 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + '_ {
892 let (one, two) = match self {
893 ClassDef::Format1(inner) => (Some(inner.iter()), None),
894 ClassDef::Format2(inner) => (None, Some(inner.iter())),
895 };
896 one.into_iter().flatten().chain(two.into_iter().flatten())
897 }
898
899 pub fn population(&self) -> usize {
901 match self {
902 ClassDef::Format1(table) => table.population(),
903 ClassDef::Format2(table) => table.population(),
904 }
905 }
906
907 pub fn cost(&self) -> u32 {
909 match self {
910 ClassDef::Format1(sub) => sub.cost(),
911 ClassDef::Format2(sub) => sub.cost(),
912 }
913 }
914
915 #[cfg(feature = "std")]
917 pub fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
918 match self {
919 ClassDef::Format1(table) => table.intersect_classes(glyphs),
920 ClassDef::Format2(table) => table.intersect_classes(glyphs),
921 }
922 }
923
924 #[cfg(feature = "std")]
926 pub fn intersected_class_glyphs(
927 &self,
928 glyphs: &IntSet<GlyphId>,
929 class: u16,
930 ) -> IntSet<GlyphId> {
931 match self {
932 ClassDef::Format1(table) => table.intersected_class_glyphs(glyphs, class),
933 ClassDef::Format2(table) => table.intersected_class_glyphs(glyphs, class),
934 }
935 }
936
937 #[cfg(feature = "std")]
939 pub fn intersects_class_glyphs(&self, glyphs: &IntSet<GlyphId>, class: u16) -> bool {
940 match self {
941 ClassDef::Format1(table) => table.intersects_class_glyphs(glyphs, class),
942 ClassDef::Format2(table) => table.intersects_class_glyphs(glyphs, class),
943 }
944 }
945}
946
947impl<'a> Device<'a> {
948 pub fn delta_for_ppem(&self, ppem: u16) -> i32 {
954 let start = self.start_size();
955 if ppem == 0 || ppem < start || ppem > self.end_size() {
956 return 0;
957 }
958 self.iter()
959 .nth((ppem - start) as usize)
960 .map_or(0, |delta| delta as i32)
961 }
962
963 pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
965 let format = self.delta_format();
966 let mut n = self
967 .end_size()
968 .checked_sub(self.start_size())
969 .map(|x| x as usize + 1)
970 .unwrap_or(0);
971 let deltas_per_word = match format {
972 DeltaFormat::Local2BitDeltas => 8,
973 DeltaFormat::Local4BitDeltas => 4,
974 DeltaFormat::Local8BitDeltas => 2,
975 _ => 0,
976 };
977
978 self.delta_value().iter().flat_map(move |val| {
979 let iter = iter_packed_values(val.get(), format, n);
980 n = n.saturating_sub(deltas_per_word);
981 iter
982 })
983 }
984}
985
986fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
987 let mut decoded = [None; 8];
988 let (mask, sign_mask, bits) = match format {
989 DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
990 DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
991 DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
992 _ => (0, 0, 0),
993 };
994
995 let max_per_word = 16 / bits;
996 #[allow(clippy::needless_range_loop)] for i in 0..n.min(max_per_word) {
998 let shift = (16 - bits) - i * bits;
999 let val = (raw >> shift) & mask;
1002 let val = if val & sign_mask != 0 {
1003 (val | !mask) as i8
1005 } else {
1006 val as i8
1007 };
1008 decoded[i] = Some(val)
1009 }
1010 decoded.into_iter().flatten()
1011}
1012
1013impl From<VariationIndex<'_>> for DeltaSetIndex {
1014 fn from(src: VariationIndex) -> DeltaSetIndex {
1015 DeltaSetIndex {
1016 outer: src.delta_set_outer_index(),
1017 inner: src.delta_set_inner_index(),
1018 }
1019 }
1020}
1021
1022#[derive(Clone)]
1028pub struct TaggedElement<T> {
1029 pub tag: Tag,
1030 pub element: T,
1031}
1032
1033impl<T> TaggedElement<T> {
1034 pub fn new(tag: Tag, element: T) -> Self {
1035 Self { tag, element }
1036 }
1037}
1038
1039impl<T> std::ops::Deref for TaggedElement<T> {
1040 type Target = T;
1041
1042 fn deref(&self) -> &Self::Target {
1043 &self.element
1044 }
1045}
1046
1047#[cfg(test)]
1048mod tests {
1049 use super::*;
1050 use crate::FontRef;
1051 use types::Fixed;
1052
1053 #[test]
1054 fn coverage_get_format1() {
1055 const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
1057
1058 let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
1059 assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
1060 assert_eq!(coverage.get(GlyphId::new(2)), None);
1061 assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
1062 assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
1063 assert_eq!(coverage.get(GlyphId::new(45)), None);
1064 }
1065
1066 #[test]
1067 fn coverage_get_format2() {
1068 const COV2_DATA: FontData =
1070 FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
1071 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
1072 assert_eq!(coverage.get(GlyphId::new(2)), None);
1073 assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
1074 assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
1075 assert_eq!(coverage.get(GlyphId::new(10)), None);
1076 assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
1077 assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
1078 assert_eq!(coverage.get(GlyphId::new(40)), None);
1079 }
1080
1081 #[test]
1083 fn coverage_get_format2_no_u16_overflow() {
1084 const COV2_DATA: FontData =
1088 FontData::new(&[0, 2, 0, 1, 0x9c, 0x40, 0x9c, 0x4a, 0x9c, 0x40]);
1089 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
1090 assert_eq!(coverage.get(GlyphId::new(40000)), Some(40000));
1091 assert_eq!(coverage.get(GlyphId::new(40005)), Some(40005));
1092 assert_eq!(coverage.get(GlyphId::new(40010)), Some(40010));
1093 assert_eq!(coverage.get(GlyphId::new(40011)), None);
1094 }
1095
1096 #[test]
1097 fn coverage_get_format2_rejects_overflowing_coverage_index() {
1098 const COV2_DATA: FontData = FontData::new(&[0, 2, 0, 1, 0, 1, 0, 2, 0xff, 0xff]);
1100 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
1101 assert_eq!(coverage.get(GlyphId::new(1)), Some(u16::MAX));
1102 assert_eq!(coverage.get(GlyphId::new(2)), None);
1103 }
1104
1105 #[test]
1106 fn classdef_get_format2() {
1107 let classdef = ClassDef::read(FontData::new(
1108 font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
1109 ))
1110 .unwrap();
1111 assert!(matches!(classdef, ClassDef::Format2(..)));
1112 let gid_class_pairs = [
1113 (616, 1),
1114 (617, 1),
1115 (618, 1),
1116 (624, 1),
1117 (625, 1),
1118 (626, 1),
1119 (652, 2),
1120 (653, 2),
1121 (654, 2),
1122 (655, 2),
1123 (661, 2),
1124 ];
1125 for (gid, class) in gid_class_pairs {
1126 assert_eq!(classdef.get(GlyphId16::new(gid)), class);
1127 }
1128 for (gid, class) in classdef.iter() {
1129 assert_eq!(classdef.get(gid), class);
1130 }
1131 }
1132
1133 #[test]
1134 fn classdef_format1_short_read_no_panic() {
1135 let classdef = ClassDefFormat1::read(FontData::new(&[0, 1, 0, 10, 0, 5, 0, 1])).unwrap();
1137 let glyphs: IntSet<GlyphId> = [GlyphId::new(10), GlyphId::new(11), GlyphId::new(14)]
1138 .into_iter()
1139 .collect();
1140
1141 assert_eq!(classdef.get(GlyphId::new(10)), 0);
1142 assert_eq!(classdef.get(GlyphId::new(11)), 0);
1143 assert!(!classdef.intersects_class_glyphs(&glyphs, 2));
1144
1145 let class_ones = classdef.intersected_class_glyphs(&glyphs, 1);
1146 assert!(class_ones.is_empty());
1147 }
1148
1149 #[test]
1151 fn classdef_format1_empty() {
1152 let classdef = ClassDefFormat1::read(FontData::new(&[0, 1, 0, 0, 0, 0])).unwrap();
1155 let glyphs: IntSet<GlyphId> = [GlyphId::new(48), GlyphId::new(49), GlyphId::new(50)]
1156 .into_iter()
1157 .collect();
1158
1159 assert!(classdef.intersects_class_glyphs(&glyphs, 0));
1160 assert!(!classdef.intersects_class_glyphs(&glyphs, 1));
1161
1162 assert!(classdef
1163 .intersected_class_glyphs(&glyphs, 0)
1164 .iter()
1165 .eq(glyphs.iter()));
1166 assert!(classdef.intersected_class_glyphs(&glyphs, 1).is_empty());
1167
1168 assert_eq!(
1169 classdef
1170 .intersect_classes(&glyphs)
1171 .iter()
1172 .collect::<Vec<_>>(),
1173 vec![0]
1174 );
1175
1176 let one: IntSet<GlyphId> = [GlyphId::new(48)].into_iter().collect();
1178 assert!(classdef.intersects_class_glyphs(&one, 0));
1179
1180 let none = IntSet::<GlyphId>::empty();
1182 assert!(!classdef.intersects_class_glyphs(&none, 0));
1183 assert!(classdef.intersected_class_glyphs(&none, 0).is_empty());
1184 }
1185
1186 #[test]
1189 fn classdef_format1_empty_nonzero_start_glyph() {
1190 let classdef = ClassDefFormat1::read(FontData::new(&[0, 1, 0, 60, 0, 0])).unwrap();
1191
1192 for gids in [vec![48u16, 49], vec![70, 71], vec![48, 70]] {
1194 let glyphs: IntSet<GlyphId> = gids.iter().map(|g| GlyphId::new(*g as u32)).collect();
1195 assert!(classdef.intersects_class_glyphs(&glyphs, 0), "{gids:?}");
1196 assert!(!classdef.intersects_class_glyphs(&glyphs, 1), "{gids:?}");
1197 assert_eq!(
1198 classdef
1199 .intersected_class_glyphs(&glyphs, 0)
1200 .iter()
1201 .collect::<Vec<_>>(),
1202 glyphs.iter().collect::<Vec<_>>(),
1203 "{gids:?}"
1204 );
1205 }
1206 }
1207
1208 #[test]
1209 fn classdef_format2_empty() {
1210 let classdef = ClassDefFormat2::read(FontData::new(&[0, 2, 0, 0])).unwrap();
1212 let glyphs: IntSet<GlyphId> = [GlyphId::new(48), GlyphId::new(49), GlyphId::new(50)]
1213 .into_iter()
1214 .collect();
1215
1216 assert!(classdef.intersects_class_glyphs(&glyphs, 0));
1217 assert!(!classdef.intersects_class_glyphs(&glyphs, 1));
1218
1219 let one: IntSet<GlyphId> = [GlyphId::new(48)].into_iter().collect();
1222 assert!(classdef.intersects_class_glyphs(&one, 0));
1223
1224 assert_eq!(
1225 classdef
1226 .intersected_class_glyphs(&glyphs, 0)
1227 .iter()
1228 .collect::<Vec<_>>(),
1229 glyphs.iter().collect::<Vec<_>>()
1230 );
1231 assert!(classdef.intersected_class_glyphs(&glyphs, 1).is_empty());
1232
1233 assert_eq!(
1234 classdef
1235 .intersect_classes(&glyphs)
1236 .iter()
1237 .collect::<Vec<_>>(),
1238 vec![0]
1239 );
1240 }
1241
1242 #[test]
1244 fn classdef_empty_formats_agree() {
1245 let f1 = ClassDef::read(FontData::new(&[0, 1, 0, 0, 0, 0])).unwrap();
1246 let f2 = ClassDef::read(FontData::new(&[0, 2, 0, 0])).unwrap();
1247 assert!(matches!(f1, ClassDef::Format1(..)));
1248 assert!(matches!(f2, ClassDef::Format2(..)));
1249
1250 for gids in [vec![0u32], vec![48], vec![48, 49, 50]] {
1251 let glyphs: IntSet<GlyphId> = gids.iter().copied().map(GlyphId::new).collect();
1252 for class in [0u16, 1] {
1253 assert_eq!(
1254 f1.intersects_class_glyphs(&glyphs, class),
1255 f2.intersects_class_glyphs(&glyphs, class),
1256 "{gids:?} class {class}"
1257 );
1258 assert_eq!(
1259 f1.intersected_class_glyphs(&glyphs, class)
1260 .iter()
1261 .collect::<Vec<_>>(),
1262 f2.intersected_class_glyphs(&glyphs, class)
1263 .iter()
1264 .collect::<Vec<_>>(),
1265 "{gids:?} class {class}"
1266 );
1267 }
1268 assert_eq!(
1269 f1.intersect_classes(&glyphs).iter().collect::<Vec<_>>(),
1270 f2.intersect_classes(&glyphs).iter().collect::<Vec<_>>(),
1271 "{gids:?}"
1272 );
1273 }
1274 }
1275
1276 #[test]
1277 fn delta_decode() {
1278 assert_eq!(
1280 iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
1281 &[1, 2, 3, -1]
1282 );
1283
1284 assert_eq!(
1285 iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
1286 &[1, 1, 1, 1, 1]
1287 );
1288 }
1289
1290 #[test]
1291 fn delta_decode_negative_not_in_last_slot() {
1292 assert_eq!(
1296 iter_packed_values(0xf401, DeltaFormat::Local8BitDeltas, 2).collect::<Vec<_>>(),
1297 &[-12, 1]
1298 );
1299 assert_eq!(
1301 iter_packed_values(0x8123, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
1302 &[-8, 1, 2, 3]
1303 );
1304 assert_eq!(
1306 iter_packed_values(0x9540, DeltaFormat::Local2BitDeltas, 4).collect::<Vec<_>>(),
1307 &[-2, 1, 1, 1]
1308 );
1309 assert_eq!(
1311 iter_packed_values(0x8000, DeltaFormat::Local8BitDeltas, 2).collect::<Vec<_>>(),
1312 &[-128, 0]
1313 );
1314 }
1315
1316 #[test]
1317 fn delta_decode_all() {
1318 let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
1320 let device = Device::read(bytes.into()).unwrap();
1321 assert_eq!(
1322 device.iter().collect::<Vec<_>>(),
1323 &[1i8, -12, 30, -11, 101, 8, 42]
1324 );
1325 }
1326
1327 #[test]
1328 fn device_decode_does_not_overflow() {
1329 let bytes: &[u8] = &[0, 0xA, 0, 1, 0, 1];
1331 Device::read(bytes.into()).unwrap().iter().count();
1333 }
1334
1335 #[test]
1336 fn bit_storage_tests() {
1337 assert_eq!(bit_storage(0), 0);
1338 assert_eq!(bit_storage(1), 1);
1339 assert_eq!(bit_storage(2), 2);
1340 assert_eq!(bit_storage(4), 3);
1341 assert_eq!(bit_storage(9), 4);
1342 assert_eq!(bit_storage(0x123), 9);
1343 assert_eq!(bit_storage(0x1234), 13);
1344 assert_eq!(bit_storage(0xffff), 16);
1345 assert_eq!(bit_storage(0xffff_ffff), 32);
1346 }
1347
1348 #[test]
1349 fn default_coverage() {
1350 let coverage = CoverageTable::default();
1351 assert_eq!(coverage.iter().count(), 0)
1352 }
1353
1354 fn coords_at(font: &FontRef, tag: Tag, value: f32) -> Vec<F2Dot14> {
1356 let fvar = font.fvar().unwrap();
1357 let mut coords = vec![F2Dot14::ZERO; fvar.axis_count() as usize];
1358 fvar.user_to_normalized(
1359 font.avar().ok().as_ref(),
1360 [(tag, Fixed::from_f64(value as f64))],
1361 &mut coords,
1362 );
1363 coords
1364 }
1365
1366 #[test]
1367 fn index_for_coords_honors_the_condition_set() {
1368 let font = FontRef::new(font_test_data::MATERIAL_SYMBOLS_SUBSET).unwrap();
1369 let feature_vars = font.gsub().unwrap().feature_variations().unwrap().unwrap();
1370 let fill = Tag::new(b"FILL");
1371 assert_eq!(
1372 feature_vars.index_for_coords(&coords_at(&font, fill, 1.0)),
1373 Some(0)
1374 );
1375 assert_eq!(
1376 feature_vars.index_for_coords(&coords_at(&font, fill, 0.5)),
1377 None
1378 );
1379 assert_eq!(feature_vars.index_for_coords(&[]), None);
1382 }
1383
1384 #[test]
1385 fn selected_feature_variations() {
1386 let font = FontRef::new(font_test_data::MATERIAL_SYMBOLS_SUBSET).unwrap();
1387 let cases = [
1388 (0.0, [None, None]),
1390 (0.5, [None, None]),
1391 (0.98, [None, None]),
1392 (0.99, [Some(0), None]),
1393 (1.0, [Some(0), None]),
1394 ];
1395 for (fill, expected) in cases {
1396 let coords = coords_at(&font, Tag::new(b"FILL"), fill);
1397 let selected = SelectedFeatureVariations::new(&font, &coords);
1398 assert_eq!([selected.gsub, selected.gpos], expected, "fill={fill}");
1399 }
1400 }
1401
1402 #[test]
1403 fn a_font_without_the_layout_tables_selects_nothing() {
1404 let font = FontRef::new(font_test_data::NAMES_ONLY).unwrap();
1405 assert_eq!(
1406 SelectedFeatureVariations::new(&font, &[]),
1407 SelectedFeatureVariations::default()
1408 );
1409 }
1410
1411 #[test]
1412 fn default_classdef() {
1413 let classdef = ClassDef::default();
1414 assert_eq!(classdef.population(), 0);
1415 assert_eq!(classdef.iter().count(), 0);
1416 }
1417}