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, LookupClosure, LookupClosureCtx,
23};
24
25#[cfg(test)]
26mod spec_tests;
27
28include!("../../generated/generated_layout.rs");
29
30impl<'a, T: FontRead<'a>> Lookup<'a, T> {
31 pub fn get_subtable(&self, offset: Offset16) -> Result<T, ReadError> {
32 self.resolve_offset(offset)
33 }
34
35 #[cfg(feature = "experimental_traverse")]
36 fn traverse_lookup_flag(&self) -> traversal::FieldType<'a> {
37 self.lookup_flag().to_bits().into()
38 }
39}
40
41pub trait ExtensionLookup<'a, T: FontRead<'a>>: FontRead<'a> {
46 fn extension(&self) -> Result<T, ReadError>;
47}
48
49pub enum Subtables<'a, T: FontRead<'a>, Ext: ExtensionLookup<'a, T>> {
54 Subtable(ArrayOfOffsets<'a, T>),
55 Extension(ArrayOfOffsets<'a, Ext>),
56}
57
58impl<'a, T: FontRead<'a> + '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> FontReadWithArgs<'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
133#[cfg(feature = "experimental_traverse")]
134impl<'a> SomeTable<'a> for FeatureParams<'a> {
135 fn type_name(&self) -> &str {
136 match self {
137 FeatureParams::StylisticSet(table) => table.type_name(),
138 FeatureParams::Size(table) => table.type_name(),
139 FeatureParams::CharacterVariant(table) => table.type_name(),
140 }
141 }
142
143 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
144 match self {
145 FeatureParams::StylisticSet(table) => table.get_field(idx),
146 FeatureParams::Size(table) => table.get_field(idx),
147 FeatureParams::CharacterVariant(table) => table.get_field(idx),
148 }
149 }
150}
151
152impl FeatureTableSubstitutionRecord {
153 pub fn alternate_feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
154 self.alternate_feature_offset()
155 .resolve_with_args(data, &Tag::new(b"NULL"))
156 }
157}
158
159impl<'a> CoverageTable<'a> {
160 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + 'a {
161 let (iter1, iter2) = match self {
163 CoverageTable::Format1(t) => (Some(t.glyph_array().iter().map(|g| g.get())), None),
164 CoverageTable::Format2(t) => {
165 let iter = t.range_records().iter().flat_map(RangeRecord::iter);
166 (None, Some(iter))
167 }
168 };
169
170 iter1
171 .into_iter()
172 .flatten()
173 .chain(iter2.into_iter().flatten())
174 }
175
176 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
178 match self {
179 CoverageTable::Format1(sub) => sub.get(gid),
180 CoverageTable::Format2(sub) => sub.get(gid),
181 }
182 }
183
184 #[cfg(feature = "std")]
186 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
187 match self {
188 CoverageTable::Format1(sub) => sub.intersects(glyphs),
189 CoverageTable::Format2(sub) => sub.intersects(glyphs),
190 }
191 }
192
193 #[cfg(feature = "std")]
195 pub fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
196 match self {
197 CoverageTable::Format1(sub) => sub.intersect_set(glyphs),
198 CoverageTable::Format2(sub) => sub.intersect_set(glyphs),
199 }
200 }
201}
202
203impl CoverageFormat1<'_> {
204 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
206 let gid16: GlyphId16 = gid.into().try_into().ok()?;
207 let be_glyph: BigEndian<GlyphId16> = gid16.into();
208 self.glyph_array()
209 .binary_search(&be_glyph)
210 .ok()
211 .map(|idx| idx as _)
212 }
213
214 #[cfg(feature = "std")]
216 fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
217 let glyph_count = self.glyph_count() as u32;
218 let num_bits = 32 - glyph_count.leading_zeros();
219 if glyph_count > (glyphs.len() as u32) * num_bits {
220 glyphs.iter().any(|g| self.get(g).is_some())
221 } else {
222 self.glyph_array()
223 .iter()
224 .any(|g| glyphs.contains(GlyphId::from(g.get())))
225 }
226 }
227
228 #[cfg(feature = "std")]
230 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
231 let glyph_count = self.glyph_count() as u32;
232 let num_bits = 32 - glyph_count.leading_zeros();
233 if glyph_count > (glyphs.len() as u32) * num_bits {
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
253impl CoverageFormat2<'_> {
254 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
256 let gid: GlyphId16 = gid.into().try_into().ok()?;
257 self.range_records()
258 .binary_search_by(|rec| {
259 if rec.end_glyph_id() < gid {
260 Ordering::Less
261 } else if rec.start_glyph_id() > gid {
262 Ordering::Greater
263 } else {
264 Ordering::Equal
265 }
266 })
267 .ok()
268 .map(|idx| {
269 let rec = &self.range_records()[idx];
270 rec.start_coverage_index() + gid.to_u16() - rec.start_glyph_id().to_u16()
271 })
272 }
273
274 #[cfg(feature = "std")]
276 fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
277 let range_count = self.range_count() as u32;
278 let num_bits = 32 - range_count.leading_zeros();
279 if range_count > (glyphs.len() as u32) * num_bits {
280 glyphs.iter().any(|g| self.get(g).is_some())
281 } else {
282 self.range_records()
283 .iter()
284 .any(|record| record.intersects(glyphs))
285 }
286 }
287
288 #[cfg(feature = "std")]
290 fn intersect_set(&self, glyphs: &IntSet<GlyphId>) -> IntSet<GlyphId> {
291 let range_count = self.range_count() as u32;
292 let num_bits = 32 - range_count.leading_zeros();
293 if range_count > (glyphs.len() as u32) * num_bits {
294 glyphs
295 .iter()
296 .filter_map(|g| self.get(g).map(|_| g))
297 .collect()
298 } else {
299 let mut out = IntSet::empty();
300 let mut last = GlyphId16::from(0);
301 for record in self.range_records() {
302 let start_glyph = record.start_glyph_id();
304 if start_glyph < last {
305 break;
306 }
307 let end = record.end_glyph_id();
308 last = end;
309
310 let start = GlyphId::from(start_glyph);
311 if glyphs.contains(start) {
312 out.insert(start);
313 }
314
315 for g in glyphs.iter_after(start) {
316 if g.to_u32() > end.to_u32() {
317 break;
318 }
319 out.insert(g);
320 }
321 }
322 out
323 }
324 }
325
326 pub fn population(&self) -> usize {
328 self.range_records()
329 .iter()
330 .fold(0, |acc, record| acc + record.population())
331 }
332}
333
334impl RangeRecord {
335 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + '_ {
336 (self.start_glyph_id().to_u16()..=self.end_glyph_id().to_u16()).map(GlyphId16::new)
337 }
338
339 #[cfg(feature = "std")]
341 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
342 glyphs.intersects_range(
343 GlyphId::from(self.start_glyph_id())..=GlyphId::from(self.end_glyph_id()),
344 )
345 }
346
347 pub fn population(&self) -> usize {
349 let start = self.start_glyph_id().to_u32() as usize;
350 let end = self.end_glyph_id().to_u32() as usize;
351 if start > end {
352 0
353 } else {
354 end - start + 1
355 }
356 }
357}
358
359impl DeltaFormat {
360 pub(crate) fn value_count(self, start_size: u16, end_size: u16) -> usize {
361 let range_len = end_size.saturating_add(1).saturating_sub(start_size) as usize;
362 let val_per_word = match self {
363 DeltaFormat::Local2BitDeltas => 8,
364 DeltaFormat::Local4BitDeltas => 4,
365 DeltaFormat::Local8BitDeltas => 2,
366 _ => return 0,
367 };
368
369 let count = range_len / val_per_word;
370 let extra = (range_len % val_per_word).min(1);
371 count + extra
372 }
373}
374
375impl From<DeltaFormat> for i64 {
378 fn from(value: DeltaFormat) -> Self {
379 value as u16 as _
380 }
381}
382
383impl<'a> ClassDefFormat1<'a> {
384 pub fn get(&self, gid: GlyphId16) -> u16 {
386 if gid < self.start_glyph_id() {
387 return 0;
388 }
389 let idx = gid.to_u16() - self.start_glyph_id().to_u16();
390 self.class_value_array()
391 .get(idx as usize)
392 .map(|x| x.get())
393 .unwrap_or(0)
394 }
395
396 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
398 let start = self.start_glyph_id();
399 self.class_value_array()
400 .iter()
401 .enumerate()
402 .map(move |(i, val)| {
403 let gid = start.to_u16().saturating_add(i as u16);
404 (GlyphId16::new(gid), val.get())
405 })
406 }
407
408 pub fn population(&self) -> usize {
410 self.glyph_count() as usize
411 }
412
413 #[cfg(feature = "std")]
415 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
416 let mut out = IntSet::empty();
417 if glyphs.is_empty() {
418 return out;
419 }
420
421 let start_glyph = self.start_glyph_id().to_u32();
422 let glyph_count = self.glyph_count();
423 let end_glyph = start_glyph + glyph_count as u32 - 1;
424 if glyphs.first().unwrap().to_u32() < start_glyph
425 || glyphs.last().unwrap().to_u32() > end_glyph
426 {
427 out.insert(0);
428 }
429
430 let class_values = self.class_value_array();
431 if glyphs.contains(GlyphId::from(start_glyph)) {
432 let Some(start_glyph_class) = class_values.first() else {
433 return out;
434 };
435 out.insert(start_glyph_class.get());
436 }
437
438 for g in glyphs.iter_after(GlyphId::from(start_glyph)) {
439 let g = g.to_u32();
440 if g > end_glyph {
441 break;
442 }
443
444 let idx = g - start_glyph;
445 let Some(class) = class_values.get(idx as usize) else {
446 break;
447 };
448 out.insert(class.get());
449 }
450 out
451 }
452}
453
454impl<'a> ClassDefFormat2<'a> {
455 pub fn get(&self, gid: GlyphId16) -> u16 {
457 let records = self.class_range_records();
458 let ix = match records.binary_search_by(|rec| rec.start_glyph_id().cmp(&gid)) {
459 Ok(ix) => ix,
460 Err(ix) => ix.saturating_sub(1),
461 };
462 if let Some(record) = records.get(ix) {
463 if (record.start_glyph_id()..=record.end_glyph_id()).contains(&gid) {
464 return record.class();
465 }
466 }
467 0
468 }
469
470 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
472 self.class_range_records().iter().flat_map(|range| {
473 let start = range.start_glyph_id().to_u16();
474 let end = range.end_glyph_id().to_u16();
475 (start..=end).map(|gid| (GlyphId16::new(gid), range.class()))
476 })
477 }
478
479 pub fn population(&self) -> usize {
481 self.class_range_records()
482 .iter()
483 .fold(0, |acc, record| acc + record.population())
484 }
485
486 #[cfg(feature = "std")]
488 fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
489 let mut out = IntSet::empty();
490 if glyphs.is_empty() {
491 return out;
492 }
493
494 if self.class_range_count() == 0 {
495 out.insert(0);
496 return out;
497 }
498
499 let range_records = self.class_range_records();
500 let first_record = range_records[0];
501
502 if glyphs.first().unwrap() < first_record.start_glyph_id() {
503 out.insert(0);
504 } else {
505 let mut glyph = GlyphId::from(first_record.end_glyph_id());
506 for record in range_records.iter().skip(1) {
507 let Some(g) = glyphs.iter_after(glyph).next() else {
508 break;
509 };
510
511 if g < record.start_glyph_id() {
512 out.insert(0);
513 break;
514 }
515 glyph = GlyphId::from(record.end_glyph_id());
516 }
517 if glyphs.iter_after(glyph).next().is_some() {
518 out.insert(0);
519 }
520 }
521
522 let num_ranges = self.class_range_count();
523 let num_bits = 16 - num_ranges.leading_zeros();
524 if num_ranges as u64 > glyphs.len() * num_bits as u64 {
525 for g in glyphs.iter() {
526 let class = self.get(GlyphId16::from(g.to_u32() as u16));
527 if class != 0 {
528 out.insert(class);
529 }
530 }
531 } else {
532 for record in range_records {
533 if glyphs.intersects_range(
534 GlyphId::from(record.start_glyph_id())..=GlyphId::from(record.end_glyph_id()),
535 ) {
536 out.insert(record.class());
537 }
538 }
539 }
540 out
541 }
542}
543
544impl ClassRangeRecord {
545 pub fn population(&self) -> usize {
547 let start = self.start_glyph_id().to_u32() as usize;
548 let end = self.end_glyph_id().to_u32() as usize;
549 if start > end {
550 0
551 } else {
552 end - start + 1
553 }
554 }
555}
556
557impl ClassDef<'_> {
558 pub fn get(&self, gid: GlyphId16) -> u16 {
560 match self {
561 ClassDef::Format1(table) => table.get(gid),
562 ClassDef::Format2(table) => table.get(gid),
563 }
564 }
565
566 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + '_ {
570 let (one, two) = match self {
571 ClassDef::Format1(inner) => (Some(inner.iter()), None),
572 ClassDef::Format2(inner) => (None, Some(inner.iter())),
573 };
574 one.into_iter().flatten().chain(two.into_iter().flatten())
575 }
576
577 pub fn population(&self) -> usize {
579 match self {
580 ClassDef::Format1(table) => table.population(),
581 ClassDef::Format2(table) => table.population(),
582 }
583 }
584
585 #[cfg(feature = "std")]
587 pub fn intersect_classes(&self, glyphs: &IntSet<GlyphId>) -> IntSet<u16> {
588 match self {
589 ClassDef::Format1(table) => table.intersect_classes(glyphs),
590 ClassDef::Format2(table) => table.intersect_classes(glyphs),
591 }
592 }
593}
594
595impl<'a> Device<'a> {
596 pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
598 let format = self.delta_format();
599 let mut n = (self.end_size() - self.start_size()) as usize + 1;
600 let deltas_per_word = match format {
601 DeltaFormat::Local2BitDeltas => 8,
602 DeltaFormat::Local4BitDeltas => 4,
603 DeltaFormat::Local8BitDeltas => 2,
604 _ => 0,
605 };
606
607 self.delta_value().iter().flat_map(move |val| {
608 let iter = iter_packed_values(val.get(), format, n);
609 n = n.saturating_sub(deltas_per_word);
610 iter
611 })
612 }
613}
614
615fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
616 let mut decoded = [None; 8];
617 let (mask, sign_mask, bits) = match format {
618 DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
619 DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
620 DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
621 _ => (0, 0, 0),
622 };
623
624 let max_per_word = 16 / bits;
625 #[allow(clippy::needless_range_loop)] for i in 0..n.min(max_per_word) {
627 let mask = mask << ((16 - bits) - i * bits);
628 let val = (raw & mask) >> ((16 - bits) - i * bits);
629 let sign = val & sign_mask != 0;
630
631 let val = if sign {
632 -((((!val) & mask) + 1) as i8)
634 } else {
635 val as i8
636 };
637 decoded[i] = Some(val)
638 }
639 decoded.into_iter().flatten()
640}
641
642impl From<VariationIndex<'_>> for DeltaSetIndex {
643 fn from(src: VariationIndex) -> DeltaSetIndex {
644 DeltaSetIndex {
645 outer: src.delta_set_outer_index(),
646 inner: src.delta_set_inner_index(),
647 }
648 }
649}
650
651#[derive(Clone)]
657pub struct TaggedElement<T> {
658 pub tag: Tag,
659 pub element: T,
660}
661
662impl<T> TaggedElement<T> {
663 pub fn new(tag: Tag, element: T) -> Self {
664 Self { tag, element }
665 }
666}
667
668impl<T> std::ops::Deref for TaggedElement<T> {
669 type Target = T;
670
671 fn deref(&self) -> &Self::Target {
672 &self.element
673 }
674}
675
676#[cfg(test)]
677mod tests {
678 use super::*;
679
680 #[test]
681 fn coverage_get_format1() {
682 const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
684
685 let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
686 assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
687 assert_eq!(coverage.get(GlyphId::new(2)), None);
688 assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
689 assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
690 assert_eq!(coverage.get(GlyphId::new(45)), None);
691 }
692
693 #[test]
694 fn coverage_get_format2() {
695 const COV2_DATA: FontData =
697 FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
698 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
699 assert_eq!(coverage.get(GlyphId::new(2)), None);
700 assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
701 assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
702 assert_eq!(coverage.get(GlyphId::new(10)), None);
703 assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
704 assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
705 assert_eq!(coverage.get(GlyphId::new(40)), None);
706 }
707
708 #[test]
709 fn classdef_get_format2() {
710 let classdef = ClassDef::read(FontData::new(
711 font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
712 ))
713 .unwrap();
714 assert!(matches!(classdef, ClassDef::Format2(..)));
715 let gid_class_pairs = [
716 (616, 1),
717 (617, 1),
718 (618, 1),
719 (624, 1),
720 (625, 1),
721 (626, 1),
722 (652, 2),
723 (653, 2),
724 (654, 2),
725 (655, 2),
726 (661, 2),
727 ];
728 for (gid, class) in gid_class_pairs {
729 assert_eq!(classdef.get(GlyphId16::new(gid)), class);
730 }
731 for (gid, class) in classdef.iter() {
732 assert_eq!(classdef.get(gid), class);
733 }
734 }
735
736 #[test]
737 fn delta_decode() {
738 assert_eq!(
740 iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
741 &[1, 2, 3, -1]
742 );
743
744 assert_eq!(
745 iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
746 &[1, 1, 1, 1, 1]
747 );
748 }
749
750 #[test]
751 fn delta_decode_all() {
752 let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
754 let device = Device::read(bytes.into()).unwrap();
755 assert_eq!(
756 device.iter().collect::<Vec<_>>(),
757 &[1i8, -12, 30, -11, 101, 8, 42]
758 );
759 }
760}