1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for ScriptList<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.script_records_byte_range().end
11 }
12 fn min_table_bytes(&self) -> &'a [u8] {
13 let range = self.min_byte_range();
14 self.data.as_bytes().get(range).unwrap_or_default()
15 }
16}
17
18impl<'a> FontRead<'a> for ScriptList<'a> {
19 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
20 #[allow(clippy::absurd_extreme_comparisons)]
21 if data.len() < Self::MIN_SIZE {
22 return Err(ReadError::OutOfBounds);
23 }
24 Ok(Self { data })
25 }
26}
27
28#[derive(Clone)]
30pub struct ScriptList<'a> {
31 data: FontData<'a>,
32}
33
34#[allow(clippy::needless_lifetimes)]
35impl<'a> ScriptList<'a> {
36 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
37 basic_table_impls!(impl_the_methods);
38
39 pub fn script_count(&self) -> u16 {
41 let range = self.script_count_byte_range();
42 self.data.read_at(range.start).ok().unwrap()
43 }
44
45 pub fn script_records(&self) -> &'a [ScriptRecord] {
47 let range = self.script_records_byte_range();
48 self.data.read_array(range).ok().unwrap_or_default()
49 }
50
51 pub fn script_count_byte_range(&self) -> Range<usize> {
52 let start = 0;
53 start..start + u16::RAW_BYTE_LEN
54 }
55
56 pub fn script_records_byte_range(&self) -> Range<usize> {
57 let script_count = self.script_count();
58 let start = self.script_count_byte_range().end;
59 start..start + (script_count as usize).saturating_mul(ScriptRecord::RAW_BYTE_LEN)
60 }
61}
62
63#[cfg(feature = "experimental_traverse")]
64impl<'a> SomeTable<'a> for ScriptList<'a> {
65 fn type_name(&self) -> &str {
66 "ScriptList"
67 }
68 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
69 match idx {
70 0usize => Some(Field::new("script_count", self.script_count())),
71 1usize => Some(Field::new(
72 "script_records",
73 traversal::FieldType::array_of_records(
74 stringify!(ScriptRecord),
75 self.script_records(),
76 self.offset_data(),
77 ),
78 )),
79 _ => None,
80 }
81 }
82}
83
84#[cfg(feature = "experimental_traverse")]
85#[allow(clippy::needless_lifetimes)]
86impl<'a> std::fmt::Debug for ScriptList<'a> {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 (self as &dyn SomeTable<'a>).fmt(f)
89 }
90}
91
92#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
94#[repr(C)]
95#[repr(packed)]
96pub struct ScriptRecord {
97 pub script_tag: BigEndian<Tag>,
99 pub script_offset: BigEndian<Offset16>,
101}
102
103impl ScriptRecord {
104 pub fn script_tag(&self) -> Tag {
106 self.script_tag.get()
107 }
108
109 pub fn script_offset(&self) -> Offset16 {
111 self.script_offset.get()
112 }
113
114 pub fn script<'a>(&self, data: FontData<'a>) -> Result<Script<'a>, ReadError> {
119 self.script_offset().resolve(data)
120 }
121}
122
123impl FixedSize for ScriptRecord {
124 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
125}
126
127#[cfg(feature = "experimental_traverse")]
128impl<'a> SomeRecord<'a> for ScriptRecord {
129 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
130 RecordResolver {
131 name: "ScriptRecord",
132 get_field: Box::new(move |idx, _data| match idx {
133 0usize => Some(Field::new("script_tag", self.script_tag())),
134 1usize => Some(Field::new(
135 "script_offset",
136 FieldType::offset(self.script_offset(), self.script(_data)),
137 )),
138 _ => None,
139 }),
140 data,
141 }
142 }
143}
144
145impl<'a> MinByteRange<'a> for Script<'a> {
146 fn min_byte_range(&self) -> Range<usize> {
147 0..self.lang_sys_records_byte_range().end
148 }
149 fn min_table_bytes(&self) -> &'a [u8] {
150 let range = self.min_byte_range();
151 self.data.as_bytes().get(range).unwrap_or_default()
152 }
153}
154
155impl<'a> FontRead<'a> for Script<'a> {
156 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
157 #[allow(clippy::absurd_extreme_comparisons)]
158 if data.len() < Self::MIN_SIZE {
159 return Err(ReadError::OutOfBounds);
160 }
161 Ok(Self { data })
162 }
163}
164
165#[derive(Clone)]
167pub struct Script<'a> {
168 data: FontData<'a>,
169}
170
171#[allow(clippy::needless_lifetimes)]
172impl<'a> Script<'a> {
173 pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
174 basic_table_impls!(impl_the_methods);
175
176 pub fn default_lang_sys_offset(&self) -> Nullable<Offset16> {
179 let range = self.default_lang_sys_offset_byte_range();
180 self.data.read_at(range.start).ok().unwrap()
181 }
182
183 pub fn default_lang_sys(&self) -> Option<Result<LangSys<'a>, ReadError>> {
185 let data = self.data;
186 self.default_lang_sys_offset().resolve(data)
187 }
188
189 pub fn lang_sys_count(&self) -> u16 {
192 let range = self.lang_sys_count_byte_range();
193 self.data.read_at(range.start).ok().unwrap()
194 }
195
196 pub fn lang_sys_records(&self) -> &'a [LangSysRecord] {
198 let range = self.lang_sys_records_byte_range();
199 self.data.read_array(range).ok().unwrap_or_default()
200 }
201
202 pub fn default_lang_sys_offset_byte_range(&self) -> Range<usize> {
203 let start = 0;
204 start..start + Offset16::RAW_BYTE_LEN
205 }
206
207 pub fn lang_sys_count_byte_range(&self) -> Range<usize> {
208 let start = self.default_lang_sys_offset_byte_range().end;
209 start..start + u16::RAW_BYTE_LEN
210 }
211
212 pub fn lang_sys_records_byte_range(&self) -> Range<usize> {
213 let lang_sys_count = self.lang_sys_count();
214 let start = self.lang_sys_count_byte_range().end;
215 start..start + (lang_sys_count as usize).saturating_mul(LangSysRecord::RAW_BYTE_LEN)
216 }
217}
218
219#[cfg(feature = "experimental_traverse")]
220impl<'a> SomeTable<'a> for Script<'a> {
221 fn type_name(&self) -> &str {
222 "Script"
223 }
224 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
225 match idx {
226 0usize => Some(Field::new(
227 "default_lang_sys_offset",
228 FieldType::offset(self.default_lang_sys_offset(), self.default_lang_sys()),
229 )),
230 1usize => Some(Field::new("lang_sys_count", self.lang_sys_count())),
231 2usize => Some(Field::new(
232 "lang_sys_records",
233 traversal::FieldType::array_of_records(
234 stringify!(LangSysRecord),
235 self.lang_sys_records(),
236 self.offset_data(),
237 ),
238 )),
239 _ => None,
240 }
241 }
242}
243
244#[cfg(feature = "experimental_traverse")]
245#[allow(clippy::needless_lifetimes)]
246impl<'a> std::fmt::Debug for Script<'a> {
247 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
248 (self as &dyn SomeTable<'a>).fmt(f)
249 }
250}
251
252#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
253#[repr(C)]
254#[repr(packed)]
255pub struct LangSysRecord {
256 pub lang_sys_tag: BigEndian<Tag>,
258 pub lang_sys_offset: BigEndian<Offset16>,
260}
261
262impl LangSysRecord {
263 pub fn lang_sys_tag(&self) -> Tag {
265 self.lang_sys_tag.get()
266 }
267
268 pub fn lang_sys_offset(&self) -> Offset16 {
270 self.lang_sys_offset.get()
271 }
272
273 pub fn lang_sys<'a>(&self, data: FontData<'a>) -> Result<LangSys<'a>, ReadError> {
278 self.lang_sys_offset().resolve(data)
279 }
280}
281
282impl FixedSize for LangSysRecord {
283 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
284}
285
286#[cfg(feature = "experimental_traverse")]
287impl<'a> SomeRecord<'a> for LangSysRecord {
288 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
289 RecordResolver {
290 name: "LangSysRecord",
291 get_field: Box::new(move |idx, _data| match idx {
292 0usize => Some(Field::new("lang_sys_tag", self.lang_sys_tag())),
293 1usize => Some(Field::new(
294 "lang_sys_offset",
295 FieldType::offset(self.lang_sys_offset(), self.lang_sys(_data)),
296 )),
297 _ => None,
298 }),
299 data,
300 }
301 }
302}
303
304impl<'a> MinByteRange<'a> for LangSys<'a> {
305 fn min_byte_range(&self) -> Range<usize> {
306 0..self.feature_indices_byte_range().end
307 }
308 fn min_table_bytes(&self) -> &'a [u8] {
309 let range = self.min_byte_range();
310 self.data.as_bytes().get(range).unwrap_or_default()
311 }
312}
313
314impl<'a> FontRead<'a> for LangSys<'a> {
315 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
316 #[allow(clippy::absurd_extreme_comparisons)]
317 if data.len() < Self::MIN_SIZE {
318 return Err(ReadError::OutOfBounds);
319 }
320 Ok(Self { data })
321 }
322}
323
324#[derive(Clone)]
326pub struct LangSys<'a> {
327 data: FontData<'a>,
328}
329
330#[allow(clippy::needless_lifetimes)]
331impl<'a> LangSys<'a> {
332 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
333 basic_table_impls!(impl_the_methods);
334
335 pub fn required_feature_index(&self) -> u16 {
338 let range = self.required_feature_index_byte_range();
339 self.data.read_at(range.start).ok().unwrap()
340 }
341
342 pub fn feature_index_count(&self) -> u16 {
345 let range = self.feature_index_count_byte_range();
346 self.data.read_at(range.start).ok().unwrap()
347 }
348
349 pub fn feature_indices(&self) -> &'a [BigEndian<u16>] {
351 let range = self.feature_indices_byte_range();
352 self.data.read_array(range).ok().unwrap_or_default()
353 }
354
355 pub fn lookup_order_offset_byte_range(&self) -> Range<usize> {
356 let start = 0;
357 start..start + u16::RAW_BYTE_LEN
358 }
359
360 pub fn required_feature_index_byte_range(&self) -> Range<usize> {
361 let start = self.lookup_order_offset_byte_range().end;
362 start..start + u16::RAW_BYTE_LEN
363 }
364
365 pub fn feature_index_count_byte_range(&self) -> Range<usize> {
366 let start = self.required_feature_index_byte_range().end;
367 start..start + u16::RAW_BYTE_LEN
368 }
369
370 pub fn feature_indices_byte_range(&self) -> Range<usize> {
371 let feature_index_count = self.feature_index_count();
372 let start = self.feature_index_count_byte_range().end;
373 start..start + (feature_index_count as usize).saturating_mul(u16::RAW_BYTE_LEN)
374 }
375}
376
377#[cfg(feature = "experimental_traverse")]
378impl<'a> SomeTable<'a> for LangSys<'a> {
379 fn type_name(&self) -> &str {
380 "LangSys"
381 }
382 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
383 match idx {
384 0usize => Some(Field::new(
385 "required_feature_index",
386 self.required_feature_index(),
387 )),
388 1usize => Some(Field::new(
389 "feature_index_count",
390 self.feature_index_count(),
391 )),
392 2usize => Some(Field::new("feature_indices", self.feature_indices())),
393 _ => None,
394 }
395 }
396}
397
398#[cfg(feature = "experimental_traverse")]
399#[allow(clippy::needless_lifetimes)]
400impl<'a> std::fmt::Debug for LangSys<'a> {
401 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
402 (self as &dyn SomeTable<'a>).fmt(f)
403 }
404}
405
406impl<'a> MinByteRange<'a> for FeatureList<'a> {
407 fn min_byte_range(&self) -> Range<usize> {
408 0..self.feature_records_byte_range().end
409 }
410 fn min_table_bytes(&self) -> &'a [u8] {
411 let range = self.min_byte_range();
412 self.data.as_bytes().get(range).unwrap_or_default()
413 }
414}
415
416impl<'a> FontRead<'a> for FeatureList<'a> {
417 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
418 #[allow(clippy::absurd_extreme_comparisons)]
419 if data.len() < Self::MIN_SIZE {
420 return Err(ReadError::OutOfBounds);
421 }
422 Ok(Self { data })
423 }
424}
425
426#[derive(Clone)]
428pub struct FeatureList<'a> {
429 data: FontData<'a>,
430}
431
432#[allow(clippy::needless_lifetimes)]
433impl<'a> FeatureList<'a> {
434 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
435 basic_table_impls!(impl_the_methods);
436
437 pub fn feature_count(&self) -> u16 {
439 let range = self.feature_count_byte_range();
440 self.data.read_at(range.start).ok().unwrap()
441 }
442
443 pub fn feature_records(&self) -> &'a [FeatureRecord] {
446 let range = self.feature_records_byte_range();
447 self.data.read_array(range).ok().unwrap_or_default()
448 }
449
450 pub fn feature_count_byte_range(&self) -> Range<usize> {
451 let start = 0;
452 start..start + u16::RAW_BYTE_LEN
453 }
454
455 pub fn feature_records_byte_range(&self) -> Range<usize> {
456 let feature_count = self.feature_count();
457 let start = self.feature_count_byte_range().end;
458 start..start + (feature_count as usize).saturating_mul(FeatureRecord::RAW_BYTE_LEN)
459 }
460}
461
462#[cfg(feature = "experimental_traverse")]
463impl<'a> SomeTable<'a> for FeatureList<'a> {
464 fn type_name(&self) -> &str {
465 "FeatureList"
466 }
467 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
468 match idx {
469 0usize => Some(Field::new("feature_count", self.feature_count())),
470 1usize => Some(Field::new(
471 "feature_records",
472 traversal::FieldType::array_of_records(
473 stringify!(FeatureRecord),
474 self.feature_records(),
475 self.offset_data(),
476 ),
477 )),
478 _ => None,
479 }
480 }
481}
482
483#[cfg(feature = "experimental_traverse")]
484#[allow(clippy::needless_lifetimes)]
485impl<'a> std::fmt::Debug for FeatureList<'a> {
486 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
487 (self as &dyn SomeTable<'a>).fmt(f)
488 }
489}
490
491#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
493#[repr(C)]
494#[repr(packed)]
495pub struct FeatureRecord {
496 pub feature_tag: BigEndian<Tag>,
498 pub feature_offset: BigEndian<Offset16>,
500}
501
502impl FeatureRecord {
503 pub fn feature_tag(&self) -> Tag {
505 self.feature_tag.get()
506 }
507
508 pub fn feature_offset(&self) -> Offset16 {
510 self.feature_offset.get()
511 }
512
513 pub fn feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
518 let args = self.feature_tag();
519 self.feature_offset().resolve_with_args(data, &args)
520 }
521}
522
523impl FixedSize for FeatureRecord {
524 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
525}
526
527#[cfg(feature = "experimental_traverse")]
528impl<'a> SomeRecord<'a> for FeatureRecord {
529 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
530 RecordResolver {
531 name: "FeatureRecord",
532 get_field: Box::new(move |idx, _data| match idx {
533 0usize => Some(Field::new("feature_tag", self.feature_tag())),
534 1usize => Some(Field::new(
535 "feature_offset",
536 FieldType::offset(self.feature_offset(), self.feature(_data)),
537 )),
538 _ => None,
539 }),
540 data,
541 }
542 }
543}
544
545impl<'a> MinByteRange<'a> for Feature<'a> {
546 fn min_byte_range(&self) -> Range<usize> {
547 0..self.lookup_list_indices_byte_range().end
548 }
549 fn min_table_bytes(&self) -> &'a [u8] {
550 let range = self.min_byte_range();
551 self.data.as_bytes().get(range).unwrap_or_default()
552 }
553}
554
555impl ReadArgs for Feature<'_> {
556 type Args = Tag;
557}
558
559impl<'a> FontReadWithArgs<'a> for Feature<'a> {
560 fn read_with_args(data: FontData<'a>, args: &Tag) -> Result<Self, ReadError> {
561 let feature_tag = *args;
562
563 #[allow(clippy::absurd_extreme_comparisons)]
564 if data.len() < Self::MIN_SIZE {
565 return Err(ReadError::OutOfBounds);
566 }
567 Ok(Self { data, feature_tag })
568 }
569}
570
571impl<'a> Feature<'a> {
572 pub fn read(data: FontData<'a>, feature_tag: Tag) -> Result<Self, ReadError> {
577 let args = feature_tag;
578 Self::read_with_args(data, &args)
579 }
580}
581
582#[derive(Clone)]
584pub struct Feature<'a> {
585 data: FontData<'a>,
586 feature_tag: Tag,
587}
588
589#[allow(clippy::needless_lifetimes)]
590impl<'a> Feature<'a> {
591 pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
592 basic_table_impls!(impl_the_methods);
593
594 pub fn feature_params_offset(&self) -> Nullable<Offset16> {
596 let range = self.feature_params_offset_byte_range();
597 self.data.read_at(range.start).ok().unwrap()
598 }
599
600 pub fn feature_params(&self) -> Option<Result<FeatureParams<'a>, ReadError>> {
602 let data = self.data;
603 let args = self.feature_tag();
604 self.feature_params_offset().resolve_with_args(data, &args)
605 }
606
607 pub fn lookup_index_count(&self) -> u16 {
609 let range = self.lookup_index_count_byte_range();
610 self.data.read_at(range.start).ok().unwrap()
611 }
612
613 pub fn lookup_list_indices(&self) -> &'a [BigEndian<u16>] {
616 let range = self.lookup_list_indices_byte_range();
617 self.data.read_array(range).ok().unwrap_or_default()
618 }
619
620 pub(crate) fn feature_tag(&self) -> Tag {
621 self.feature_tag
622 }
623
624 pub fn feature_params_offset_byte_range(&self) -> Range<usize> {
625 let start = 0;
626 start..start + Offset16::RAW_BYTE_LEN
627 }
628
629 pub fn lookup_index_count_byte_range(&self) -> Range<usize> {
630 let start = self.feature_params_offset_byte_range().end;
631 start..start + u16::RAW_BYTE_LEN
632 }
633
634 pub fn lookup_list_indices_byte_range(&self) -> Range<usize> {
635 let lookup_index_count = self.lookup_index_count();
636 let start = self.lookup_index_count_byte_range().end;
637 start..start + (lookup_index_count as usize).saturating_mul(u16::RAW_BYTE_LEN)
638 }
639}
640
641#[cfg(feature = "experimental_traverse")]
642impl<'a> SomeTable<'a> for Feature<'a> {
643 fn type_name(&self) -> &str {
644 "Feature"
645 }
646 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
647 match idx {
648 0usize => Some(Field::new(
649 "feature_params_offset",
650 FieldType::offset(self.feature_params_offset(), self.feature_params()),
651 )),
652 1usize => Some(Field::new("lookup_index_count", self.lookup_index_count())),
653 2usize => Some(Field::new(
654 "lookup_list_indices",
655 self.lookup_list_indices(),
656 )),
657 _ => None,
658 }
659 }
660}
661
662#[cfg(feature = "experimental_traverse")]
663#[allow(clippy::needless_lifetimes)]
664impl<'a> std::fmt::Debug for Feature<'a> {
665 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
666 (self as &dyn SomeTable<'a>).fmt(f)
667 }
668}
669
670impl<'a, T> MinByteRange<'a> for LookupList<'a, T> {
671 fn min_byte_range(&self) -> Range<usize> {
672 0..self.lookup_offsets_byte_range().end
673 }
674 fn min_table_bytes(&self) -> &'a [u8] {
675 let range = self.min_byte_range();
676 self.data.as_bytes().get(range).unwrap_or_default()
677 }
678}
679
680impl<'a, T> FontRead<'a> for LookupList<'a, T> {
681 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
682 #[allow(clippy::absurd_extreme_comparisons)]
683 if data.len() < Self::MIN_SIZE {
684 return Err(ReadError::OutOfBounds);
685 }
686 Ok(Self {
687 data,
688 offset_type: std::marker::PhantomData,
689 })
690 }
691}
692
693impl<'a> LookupList<'a, ()> {
694 #[allow(dead_code)]
695 pub(crate) fn into_concrete<T>(self) -> LookupList<'a, T> {
696 LookupList {
697 data: self.data,
698 offset_type: std::marker::PhantomData,
699 }
700 }
701}
702
703impl<'a, T> LookupList<'a, T> {
704 #[allow(dead_code)]
705 pub(crate) fn of_unit_type(&self) -> LookupList<'a, ()> {
707 LookupList {
708 data: self.data,
709 offset_type: std::marker::PhantomData,
710 }
711 }
712}
713
714#[derive(Clone)]
716pub struct LookupList<'a, T = ()> {
717 data: FontData<'a>,
718 offset_type: std::marker::PhantomData<*const T>,
719}
720
721#[allow(clippy::needless_lifetimes)]
722impl<'a, T> LookupList<'a, T> {
723 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
724 basic_table_impls!(impl_the_methods);
725
726 pub fn lookup_count(&self) -> u16 {
728 let range = self.lookup_count_byte_range();
729 self.data.read_at(range.start).ok().unwrap()
730 }
731
732 pub fn lookup_offsets(&self) -> &'a [BigEndian<Offset16>] {
735 let range = self.lookup_offsets_byte_range();
736 self.data.read_array(range).ok().unwrap_or_default()
737 }
738
739 pub fn lookups(&self) -> ArrayOfOffsets<'a, T, Offset16>
741 where
742 T: FontRead<'a>,
743 {
744 let data = self.data;
745 let offsets = self.lookup_offsets();
746 ArrayOfOffsets::new(offsets, data, ())
747 }
748
749 pub fn lookup_count_byte_range(&self) -> Range<usize> {
750 let start = 0;
751 start..start + u16::RAW_BYTE_LEN
752 }
753
754 pub fn lookup_offsets_byte_range(&self) -> Range<usize> {
755 let lookup_count = self.lookup_count();
756 let start = self.lookup_count_byte_range().end;
757 start..start + (lookup_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
758 }
759}
760
761#[cfg(feature = "experimental_traverse")]
762impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for LookupList<'a, T> {
763 fn type_name(&self) -> &str {
764 "LookupList"
765 }
766 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
767 match idx {
768 0usize => Some(Field::new("lookup_count", self.lookup_count())),
769 1usize => Some({
770 let data = self.data;
771 Field::new(
772 "lookup_offsets",
773 FieldType::array_of_offsets(
774 better_type_name::<T>(),
775 self.lookup_offsets(),
776 move |off| {
777 let target = off.get().resolve::<T>(data);
778 FieldType::offset(off.get(), target)
779 },
780 ),
781 )
782 }),
783 _ => None,
784 }
785 }
786}
787
788#[cfg(feature = "experimental_traverse")]
789#[allow(clippy::needless_lifetimes)]
790impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for LookupList<'a, T> {
791 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
792 (self as &dyn SomeTable<'a>).fmt(f)
793 }
794}
795
796impl<'a, T> MinByteRange<'a> for Lookup<'a, T> {
797 fn min_byte_range(&self) -> Range<usize> {
798 0..self.subtable_offsets_byte_range().end
799 }
800 fn min_table_bytes(&self) -> &'a [u8] {
801 let range = self.min_byte_range();
802 self.data.as_bytes().get(range).unwrap_or_default()
803 }
804}
805
806impl<'a, T> FontRead<'a> for Lookup<'a, T> {
807 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
808 #[allow(clippy::absurd_extreme_comparisons)]
809 if data.len() < Self::MIN_SIZE {
810 return Err(ReadError::OutOfBounds);
811 }
812 Ok(Self {
813 data,
814 offset_type: std::marker::PhantomData,
815 })
816 }
817}
818
819impl<'a> Lookup<'a, ()> {
820 #[allow(dead_code)]
821 pub(crate) fn into_concrete<T>(self) -> Lookup<'a, T> {
822 Lookup {
823 data: self.data,
824 offset_type: std::marker::PhantomData,
825 }
826 }
827}
828
829impl<'a, T> Lookup<'a, T> {
830 #[allow(dead_code)]
831 pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
833 Lookup {
834 data: self.data,
835 offset_type: std::marker::PhantomData,
836 }
837 }
838}
839
840#[derive(Clone)]
842pub struct Lookup<'a, T = ()> {
843 data: FontData<'a>,
844 offset_type: std::marker::PhantomData<*const T>,
845}
846
847#[allow(clippy::needless_lifetimes)]
848impl<'a, T> Lookup<'a, T> {
849 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + LookupFlag::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
850 basic_table_impls!(impl_the_methods);
851
852 pub fn lookup_type(&self) -> u16 {
854 let range = self.lookup_type_byte_range();
855 self.data.read_at(range.start).ok().unwrap()
856 }
857
858 pub fn lookup_flag(&self) -> LookupFlag {
860 let range = self.lookup_flag_byte_range();
861 self.data.read_at(range.start).ok().unwrap()
862 }
863
864 pub fn sub_table_count(&self) -> u16 {
866 let range = self.sub_table_count_byte_range();
867 self.data.read_at(range.start).ok().unwrap()
868 }
869
870 pub fn subtable_offsets(&self) -> &'a [BigEndian<Offset16>] {
873 let range = self.subtable_offsets_byte_range();
874 self.data.read_array(range).ok().unwrap_or_default()
875 }
876
877 pub fn subtables(&self) -> ArrayOfOffsets<'a, T, Offset16>
879 where
880 T: FontRead<'a>,
881 {
882 let data = self.data;
883 let offsets = self.subtable_offsets();
884 ArrayOfOffsets::new(offsets, data, ())
885 }
886
887 pub fn mark_filtering_set(&self) -> Option<u16> {
891 let range = self.mark_filtering_set_byte_range();
892 (!range.is_empty())
893 .then(|| self.data.read_at(range.start).ok())
894 .flatten()
895 }
896
897 pub fn lookup_type_byte_range(&self) -> Range<usize> {
898 let start = 0;
899 start..start + u16::RAW_BYTE_LEN
900 }
901
902 pub fn lookup_flag_byte_range(&self) -> Range<usize> {
903 let start = self.lookup_type_byte_range().end;
904 start..start + LookupFlag::RAW_BYTE_LEN
905 }
906
907 pub fn sub_table_count_byte_range(&self) -> Range<usize> {
908 let start = self.lookup_flag_byte_range().end;
909 start..start + u16::RAW_BYTE_LEN
910 }
911
912 pub fn subtable_offsets_byte_range(&self) -> Range<usize> {
913 let sub_table_count = self.sub_table_count();
914 let start = self.sub_table_count_byte_range().end;
915 start..start + (sub_table_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
916 }
917
918 pub fn mark_filtering_set_byte_range(&self) -> Range<usize> {
919 let start = self.subtable_offsets_byte_range().end;
920 start
921 ..(self
922 .lookup_flag()
923 .contains(LookupFlag::USE_MARK_FILTERING_SET))
924 .then(|| start + u16::RAW_BYTE_LEN)
925 .unwrap_or(start)
926 }
927}
928
929#[cfg(feature = "experimental_traverse")]
930impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for Lookup<'a, T> {
931 fn type_name(&self) -> &str {
932 "Lookup"
933 }
934 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
935 match idx {
936 0usize => Some(Field::new("lookup_type", self.lookup_type())),
937 1usize => Some(Field::new("lookup_flag", self.traverse_lookup_flag())),
938 2usize => Some(Field::new("sub_table_count", self.sub_table_count())),
939 3usize => Some({
940 let data = self.data;
941 Field::new(
942 "subtable_offsets",
943 FieldType::array_of_offsets(
944 better_type_name::<T>(),
945 self.subtable_offsets(),
946 move |off| {
947 let target = off.get().resolve::<T>(data);
948 FieldType::offset(off.get(), target)
949 },
950 ),
951 )
952 }),
953 4usize
954 if self
955 .lookup_flag()
956 .contains(LookupFlag::USE_MARK_FILTERING_SET) =>
957 {
958 Some(Field::new(
959 "mark_filtering_set",
960 self.mark_filtering_set().unwrap(),
961 ))
962 }
963 _ => None,
964 }
965 }
966}
967
968#[cfg(feature = "experimental_traverse")]
969#[allow(clippy::needless_lifetimes)]
970impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for Lookup<'a, T> {
971 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
972 (self as &dyn SomeTable<'a>).fmt(f)
973 }
974}
975
976impl Format<u16> for CoverageFormat1<'_> {
977 const FORMAT: u16 = 1;
978}
979
980impl<'a> MinByteRange<'a> for CoverageFormat1<'a> {
981 fn min_byte_range(&self) -> Range<usize> {
982 0..self.glyph_array_byte_range().end
983 }
984 fn min_table_bytes(&self) -> &'a [u8] {
985 let range = self.min_byte_range();
986 self.data.as_bytes().get(range).unwrap_or_default()
987 }
988}
989
990impl<'a> FontRead<'a> for CoverageFormat1<'a> {
991 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
992 #[allow(clippy::absurd_extreme_comparisons)]
993 if data.len() < Self::MIN_SIZE {
994 return Err(ReadError::OutOfBounds);
995 }
996 Ok(Self { data })
997 }
998}
999
1000#[derive(Clone)]
1002pub struct CoverageFormat1<'a> {
1003 data: FontData<'a>,
1004}
1005
1006#[allow(clippy::needless_lifetimes)]
1007impl<'a> CoverageFormat1<'a> {
1008 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1009 basic_table_impls!(impl_the_methods);
1010
1011 pub fn coverage_format(&self) -> u16 {
1013 let range = self.coverage_format_byte_range();
1014 self.data.read_at(range.start).ok().unwrap()
1015 }
1016
1017 pub fn glyph_count(&self) -> u16 {
1019 let range = self.glyph_count_byte_range();
1020 self.data.read_at(range.start).ok().unwrap()
1021 }
1022
1023 pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId16>] {
1025 let range = self.glyph_array_byte_range();
1026 self.data.read_array(range).ok().unwrap_or_default()
1027 }
1028
1029 pub fn coverage_format_byte_range(&self) -> Range<usize> {
1030 let start = 0;
1031 start..start + u16::RAW_BYTE_LEN
1032 }
1033
1034 pub fn glyph_count_byte_range(&self) -> Range<usize> {
1035 let start = self.coverage_format_byte_range().end;
1036 start..start + u16::RAW_BYTE_LEN
1037 }
1038
1039 pub fn glyph_array_byte_range(&self) -> Range<usize> {
1040 let glyph_count = self.glyph_count();
1041 let start = self.glyph_count_byte_range().end;
1042 start..start + (glyph_count as usize).saturating_mul(GlyphId16::RAW_BYTE_LEN)
1043 }
1044}
1045
1046#[cfg(feature = "experimental_traverse")]
1047impl<'a> SomeTable<'a> for CoverageFormat1<'a> {
1048 fn type_name(&self) -> &str {
1049 "CoverageFormat1"
1050 }
1051 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1052 match idx {
1053 0usize => Some(Field::new("coverage_format", self.coverage_format())),
1054 1usize => Some(Field::new("glyph_count", self.glyph_count())),
1055 2usize => Some(Field::new("glyph_array", self.glyph_array())),
1056 _ => None,
1057 }
1058 }
1059}
1060
1061#[cfg(feature = "experimental_traverse")]
1062#[allow(clippy::needless_lifetimes)]
1063impl<'a> std::fmt::Debug for CoverageFormat1<'a> {
1064 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1065 (self as &dyn SomeTable<'a>).fmt(f)
1066 }
1067}
1068
1069impl Format<u16> for CoverageFormat2<'_> {
1070 const FORMAT: u16 = 2;
1071}
1072
1073impl<'a> MinByteRange<'a> for CoverageFormat2<'a> {
1074 fn min_byte_range(&self) -> Range<usize> {
1075 0..self.range_records_byte_range().end
1076 }
1077 fn min_table_bytes(&self) -> &'a [u8] {
1078 let range = self.min_byte_range();
1079 self.data.as_bytes().get(range).unwrap_or_default()
1080 }
1081}
1082
1083impl<'a> FontRead<'a> for CoverageFormat2<'a> {
1084 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1085 #[allow(clippy::absurd_extreme_comparisons)]
1086 if data.len() < Self::MIN_SIZE {
1087 return Err(ReadError::OutOfBounds);
1088 }
1089 Ok(Self { data })
1090 }
1091}
1092
1093#[derive(Clone)]
1095pub struct CoverageFormat2<'a> {
1096 data: FontData<'a>,
1097}
1098
1099#[allow(clippy::needless_lifetimes)]
1100impl<'a> CoverageFormat2<'a> {
1101 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1102 basic_table_impls!(impl_the_methods);
1103
1104 pub fn coverage_format(&self) -> u16 {
1106 let range = self.coverage_format_byte_range();
1107 self.data.read_at(range.start).ok().unwrap()
1108 }
1109
1110 pub fn range_count(&self) -> u16 {
1112 let range = self.range_count_byte_range();
1113 self.data.read_at(range.start).ok().unwrap()
1114 }
1115
1116 pub fn range_records(&self) -> &'a [RangeRecord] {
1118 let range = self.range_records_byte_range();
1119 self.data.read_array(range).ok().unwrap_or_default()
1120 }
1121
1122 pub fn coverage_format_byte_range(&self) -> Range<usize> {
1123 let start = 0;
1124 start..start + u16::RAW_BYTE_LEN
1125 }
1126
1127 pub fn range_count_byte_range(&self) -> Range<usize> {
1128 let start = self.coverage_format_byte_range().end;
1129 start..start + u16::RAW_BYTE_LEN
1130 }
1131
1132 pub fn range_records_byte_range(&self) -> Range<usize> {
1133 let range_count = self.range_count();
1134 let start = self.range_count_byte_range().end;
1135 start..start + (range_count as usize).saturating_mul(RangeRecord::RAW_BYTE_LEN)
1136 }
1137}
1138
1139#[cfg(feature = "experimental_traverse")]
1140impl<'a> SomeTable<'a> for CoverageFormat2<'a> {
1141 fn type_name(&self) -> &str {
1142 "CoverageFormat2"
1143 }
1144 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1145 match idx {
1146 0usize => Some(Field::new("coverage_format", self.coverage_format())),
1147 1usize => Some(Field::new("range_count", self.range_count())),
1148 2usize => Some(Field::new(
1149 "range_records",
1150 traversal::FieldType::array_of_records(
1151 stringify!(RangeRecord),
1152 self.range_records(),
1153 self.offset_data(),
1154 ),
1155 )),
1156 _ => None,
1157 }
1158 }
1159}
1160
1161#[cfg(feature = "experimental_traverse")]
1162#[allow(clippy::needless_lifetimes)]
1163impl<'a> std::fmt::Debug for CoverageFormat2<'a> {
1164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1165 (self as &dyn SomeTable<'a>).fmt(f)
1166 }
1167}
1168
1169#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1171#[repr(C)]
1172#[repr(packed)]
1173pub struct RangeRecord {
1174 pub start_glyph_id: BigEndian<GlyphId16>,
1176 pub end_glyph_id: BigEndian<GlyphId16>,
1178 pub start_coverage_index: BigEndian<u16>,
1180}
1181
1182impl RangeRecord {
1183 pub fn start_glyph_id(&self) -> GlyphId16 {
1185 self.start_glyph_id.get()
1186 }
1187
1188 pub fn end_glyph_id(&self) -> GlyphId16 {
1190 self.end_glyph_id.get()
1191 }
1192
1193 pub fn start_coverage_index(&self) -> u16 {
1195 self.start_coverage_index.get()
1196 }
1197}
1198
1199impl FixedSize for RangeRecord {
1200 const RAW_BYTE_LEN: usize =
1201 GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1202}
1203
1204#[cfg(feature = "experimental_traverse")]
1205impl<'a> SomeRecord<'a> for RangeRecord {
1206 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1207 RecordResolver {
1208 name: "RangeRecord",
1209 get_field: Box::new(move |idx, _data| match idx {
1210 0usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1211 1usize => Some(Field::new("end_glyph_id", self.end_glyph_id())),
1212 2usize => Some(Field::new(
1213 "start_coverage_index",
1214 self.start_coverage_index(),
1215 )),
1216 _ => None,
1217 }),
1218 data,
1219 }
1220 }
1221}
1222
1223#[derive(Clone)]
1225pub enum CoverageTable<'a> {
1226 Format1(CoverageFormat1<'a>),
1227 Format2(CoverageFormat2<'a>),
1228}
1229
1230impl<'a> CoverageTable<'a> {
1231 pub fn offset_data(&self) -> FontData<'a> {
1233 match self {
1234 Self::Format1(item) => item.offset_data(),
1235 Self::Format2(item) => item.offset_data(),
1236 }
1237 }
1238
1239 pub fn coverage_format(&self) -> u16 {
1241 match self {
1242 Self::Format1(item) => item.coverage_format(),
1243 Self::Format2(item) => item.coverage_format(),
1244 }
1245 }
1246}
1247
1248impl<'a> FontRead<'a> for CoverageTable<'a> {
1249 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1250 let format: u16 = data.read_at(0usize)?;
1251 match format {
1252 CoverageFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1253 CoverageFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1254 other => Err(ReadError::InvalidFormat(other.into())),
1255 }
1256 }
1257}
1258
1259impl<'a> MinByteRange<'a> for CoverageTable<'a> {
1260 fn min_byte_range(&self) -> Range<usize> {
1261 match self {
1262 Self::Format1(item) => item.min_byte_range(),
1263 Self::Format2(item) => item.min_byte_range(),
1264 }
1265 }
1266 fn min_table_bytes(&self) -> &'a [u8] {
1267 match self {
1268 Self::Format1(item) => item.min_table_bytes(),
1269 Self::Format2(item) => item.min_table_bytes(),
1270 }
1271 }
1272}
1273
1274#[cfg(feature = "experimental_traverse")]
1275impl<'a> CoverageTable<'a> {
1276 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1277 match self {
1278 Self::Format1(table) => table,
1279 Self::Format2(table) => table,
1280 }
1281 }
1282}
1283
1284#[cfg(feature = "experimental_traverse")]
1285impl std::fmt::Debug for CoverageTable<'_> {
1286 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1287 self.dyn_inner().fmt(f)
1288 }
1289}
1290
1291#[cfg(feature = "experimental_traverse")]
1292impl<'a> SomeTable<'a> for CoverageTable<'a> {
1293 fn type_name(&self) -> &str {
1294 self.dyn_inner().type_name()
1295 }
1296 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1297 self.dyn_inner().get_field(idx)
1298 }
1299}
1300
1301impl Format<u16> for ClassDefFormat1<'_> {
1302 const FORMAT: u16 = 1;
1303}
1304
1305impl<'a> MinByteRange<'a> for ClassDefFormat1<'a> {
1306 fn min_byte_range(&self) -> Range<usize> {
1307 0..self.class_value_array_byte_range().end
1308 }
1309 fn min_table_bytes(&self) -> &'a [u8] {
1310 let range = self.min_byte_range();
1311 self.data.as_bytes().get(range).unwrap_or_default()
1312 }
1313}
1314
1315impl<'a> FontRead<'a> for ClassDefFormat1<'a> {
1316 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1317 #[allow(clippy::absurd_extreme_comparisons)]
1318 if data.len() < Self::MIN_SIZE {
1319 return Err(ReadError::OutOfBounds);
1320 }
1321 Ok(Self { data })
1322 }
1323}
1324
1325#[derive(Clone)]
1327pub struct ClassDefFormat1<'a> {
1328 data: FontData<'a>,
1329}
1330
1331#[allow(clippy::needless_lifetimes)]
1332impl<'a> ClassDefFormat1<'a> {
1333 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1334 basic_table_impls!(impl_the_methods);
1335
1336 pub fn class_format(&self) -> u16 {
1338 let range = self.class_format_byte_range();
1339 self.data.read_at(range.start).ok().unwrap()
1340 }
1341
1342 pub fn start_glyph_id(&self) -> GlyphId16 {
1344 let range = self.start_glyph_id_byte_range();
1345 self.data.read_at(range.start).ok().unwrap()
1346 }
1347
1348 pub fn glyph_count(&self) -> u16 {
1350 let range = self.glyph_count_byte_range();
1351 self.data.read_at(range.start).ok().unwrap()
1352 }
1353
1354 pub fn class_value_array(&self) -> &'a [BigEndian<u16>] {
1356 let range = self.class_value_array_byte_range();
1357 self.data.read_array(range).ok().unwrap_or_default()
1358 }
1359
1360 pub fn class_format_byte_range(&self) -> Range<usize> {
1361 let start = 0;
1362 start..start + u16::RAW_BYTE_LEN
1363 }
1364
1365 pub fn start_glyph_id_byte_range(&self) -> Range<usize> {
1366 let start = self.class_format_byte_range().end;
1367 start..start + GlyphId16::RAW_BYTE_LEN
1368 }
1369
1370 pub fn glyph_count_byte_range(&self) -> Range<usize> {
1371 let start = self.start_glyph_id_byte_range().end;
1372 start..start + u16::RAW_BYTE_LEN
1373 }
1374
1375 pub fn class_value_array_byte_range(&self) -> Range<usize> {
1376 let glyph_count = self.glyph_count();
1377 let start = self.glyph_count_byte_range().end;
1378 start..start + (glyph_count as usize).saturating_mul(u16::RAW_BYTE_LEN)
1379 }
1380}
1381
1382#[cfg(feature = "experimental_traverse")]
1383impl<'a> SomeTable<'a> for ClassDefFormat1<'a> {
1384 fn type_name(&self) -> &str {
1385 "ClassDefFormat1"
1386 }
1387 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1388 match idx {
1389 0usize => Some(Field::new("class_format", self.class_format())),
1390 1usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1391 2usize => Some(Field::new("glyph_count", self.glyph_count())),
1392 3usize => Some(Field::new("class_value_array", self.class_value_array())),
1393 _ => None,
1394 }
1395 }
1396}
1397
1398#[cfg(feature = "experimental_traverse")]
1399#[allow(clippy::needless_lifetimes)]
1400impl<'a> std::fmt::Debug for ClassDefFormat1<'a> {
1401 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1402 (self as &dyn SomeTable<'a>).fmt(f)
1403 }
1404}
1405
1406impl Format<u16> for ClassDefFormat2<'_> {
1407 const FORMAT: u16 = 2;
1408}
1409
1410impl<'a> MinByteRange<'a> for ClassDefFormat2<'a> {
1411 fn min_byte_range(&self) -> Range<usize> {
1412 0..self.class_range_records_byte_range().end
1413 }
1414 fn min_table_bytes(&self) -> &'a [u8] {
1415 let range = self.min_byte_range();
1416 self.data.as_bytes().get(range).unwrap_or_default()
1417 }
1418}
1419
1420impl<'a> FontRead<'a> for ClassDefFormat2<'a> {
1421 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1422 #[allow(clippy::absurd_extreme_comparisons)]
1423 if data.len() < Self::MIN_SIZE {
1424 return Err(ReadError::OutOfBounds);
1425 }
1426 Ok(Self { data })
1427 }
1428}
1429
1430#[derive(Clone)]
1432pub struct ClassDefFormat2<'a> {
1433 data: FontData<'a>,
1434}
1435
1436#[allow(clippy::needless_lifetimes)]
1437impl<'a> ClassDefFormat2<'a> {
1438 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1439 basic_table_impls!(impl_the_methods);
1440
1441 pub fn class_format(&self) -> u16 {
1443 let range = self.class_format_byte_range();
1444 self.data.read_at(range.start).ok().unwrap()
1445 }
1446
1447 pub fn class_range_count(&self) -> u16 {
1449 let range = self.class_range_count_byte_range();
1450 self.data.read_at(range.start).ok().unwrap()
1451 }
1452
1453 pub fn class_range_records(&self) -> &'a [ClassRangeRecord] {
1455 let range = self.class_range_records_byte_range();
1456 self.data.read_array(range).ok().unwrap_or_default()
1457 }
1458
1459 pub fn class_format_byte_range(&self) -> Range<usize> {
1460 let start = 0;
1461 start..start + u16::RAW_BYTE_LEN
1462 }
1463
1464 pub fn class_range_count_byte_range(&self) -> Range<usize> {
1465 let start = self.class_format_byte_range().end;
1466 start..start + u16::RAW_BYTE_LEN
1467 }
1468
1469 pub fn class_range_records_byte_range(&self) -> Range<usize> {
1470 let class_range_count = self.class_range_count();
1471 let start = self.class_range_count_byte_range().end;
1472 start..start + (class_range_count as usize).saturating_mul(ClassRangeRecord::RAW_BYTE_LEN)
1473 }
1474}
1475
1476#[cfg(feature = "experimental_traverse")]
1477impl<'a> SomeTable<'a> for ClassDefFormat2<'a> {
1478 fn type_name(&self) -> &str {
1479 "ClassDefFormat2"
1480 }
1481 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1482 match idx {
1483 0usize => Some(Field::new("class_format", self.class_format())),
1484 1usize => Some(Field::new("class_range_count", self.class_range_count())),
1485 2usize => Some(Field::new(
1486 "class_range_records",
1487 traversal::FieldType::array_of_records(
1488 stringify!(ClassRangeRecord),
1489 self.class_range_records(),
1490 self.offset_data(),
1491 ),
1492 )),
1493 _ => None,
1494 }
1495 }
1496}
1497
1498#[cfg(feature = "experimental_traverse")]
1499#[allow(clippy::needless_lifetimes)]
1500impl<'a> std::fmt::Debug for ClassDefFormat2<'a> {
1501 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1502 (self as &dyn SomeTable<'a>).fmt(f)
1503 }
1504}
1505
1506#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1508#[repr(C)]
1509#[repr(packed)]
1510pub struct ClassRangeRecord {
1511 pub start_glyph_id: BigEndian<GlyphId16>,
1513 pub end_glyph_id: BigEndian<GlyphId16>,
1515 pub class: BigEndian<u16>,
1517}
1518
1519impl ClassRangeRecord {
1520 pub fn start_glyph_id(&self) -> GlyphId16 {
1522 self.start_glyph_id.get()
1523 }
1524
1525 pub fn end_glyph_id(&self) -> GlyphId16 {
1527 self.end_glyph_id.get()
1528 }
1529
1530 pub fn class(&self) -> u16 {
1532 self.class.get()
1533 }
1534}
1535
1536impl FixedSize for ClassRangeRecord {
1537 const RAW_BYTE_LEN: usize =
1538 GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1539}
1540
1541#[cfg(feature = "experimental_traverse")]
1542impl<'a> SomeRecord<'a> for ClassRangeRecord {
1543 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1544 RecordResolver {
1545 name: "ClassRangeRecord",
1546 get_field: Box::new(move |idx, _data| match idx {
1547 0usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1548 1usize => Some(Field::new("end_glyph_id", self.end_glyph_id())),
1549 2usize => Some(Field::new("class", self.class())),
1550 _ => None,
1551 }),
1552 data,
1553 }
1554 }
1555}
1556
1557#[derive(Clone)]
1559pub enum ClassDef<'a> {
1560 Format1(ClassDefFormat1<'a>),
1561 Format2(ClassDefFormat2<'a>),
1562}
1563
1564impl<'a> ClassDef<'a> {
1565 pub fn offset_data(&self) -> FontData<'a> {
1567 match self {
1568 Self::Format1(item) => item.offset_data(),
1569 Self::Format2(item) => item.offset_data(),
1570 }
1571 }
1572
1573 pub fn class_format(&self) -> u16 {
1575 match self {
1576 Self::Format1(item) => item.class_format(),
1577 Self::Format2(item) => item.class_format(),
1578 }
1579 }
1580}
1581
1582impl<'a> FontRead<'a> for ClassDef<'a> {
1583 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1584 let format: u16 = data.read_at(0usize)?;
1585 match format {
1586 ClassDefFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1587 ClassDefFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1588 other => Err(ReadError::InvalidFormat(other.into())),
1589 }
1590 }
1591}
1592
1593impl<'a> MinByteRange<'a> for ClassDef<'a> {
1594 fn min_byte_range(&self) -> Range<usize> {
1595 match self {
1596 Self::Format1(item) => item.min_byte_range(),
1597 Self::Format2(item) => item.min_byte_range(),
1598 }
1599 }
1600 fn min_table_bytes(&self) -> &'a [u8] {
1601 match self {
1602 Self::Format1(item) => item.min_table_bytes(),
1603 Self::Format2(item) => item.min_table_bytes(),
1604 }
1605 }
1606}
1607
1608#[cfg(feature = "experimental_traverse")]
1609impl<'a> ClassDef<'a> {
1610 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1611 match self {
1612 Self::Format1(table) => table,
1613 Self::Format2(table) => table,
1614 }
1615 }
1616}
1617
1618#[cfg(feature = "experimental_traverse")]
1619impl std::fmt::Debug for ClassDef<'_> {
1620 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1621 self.dyn_inner().fmt(f)
1622 }
1623}
1624
1625#[cfg(feature = "experimental_traverse")]
1626impl<'a> SomeTable<'a> for ClassDef<'a> {
1627 fn type_name(&self) -> &str {
1628 self.dyn_inner().type_name()
1629 }
1630 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1631 self.dyn_inner().get_field(idx)
1632 }
1633}
1634
1635#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1637#[repr(C)]
1638#[repr(packed)]
1639pub struct SequenceLookupRecord {
1640 pub sequence_index: BigEndian<u16>,
1642 pub lookup_list_index: BigEndian<u16>,
1644}
1645
1646impl SequenceLookupRecord {
1647 pub fn sequence_index(&self) -> u16 {
1649 self.sequence_index.get()
1650 }
1651
1652 pub fn lookup_list_index(&self) -> u16 {
1654 self.lookup_list_index.get()
1655 }
1656}
1657
1658impl FixedSize for SequenceLookupRecord {
1659 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1660}
1661
1662#[cfg(feature = "experimental_traverse")]
1663impl<'a> SomeRecord<'a> for SequenceLookupRecord {
1664 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1665 RecordResolver {
1666 name: "SequenceLookupRecord",
1667 get_field: Box::new(move |idx, _data| match idx {
1668 0usize => Some(Field::new("sequence_index", self.sequence_index())),
1669 1usize => Some(Field::new("lookup_list_index", self.lookup_list_index())),
1670 _ => None,
1671 }),
1672 data,
1673 }
1674 }
1675}
1676
1677impl Format<u16> for SequenceContextFormat1<'_> {
1678 const FORMAT: u16 = 1;
1679}
1680
1681impl<'a> MinByteRange<'a> for SequenceContextFormat1<'a> {
1682 fn min_byte_range(&self) -> Range<usize> {
1683 0..self.seq_rule_set_offsets_byte_range().end
1684 }
1685 fn min_table_bytes(&self) -> &'a [u8] {
1686 let range = self.min_byte_range();
1687 self.data.as_bytes().get(range).unwrap_or_default()
1688 }
1689}
1690
1691impl<'a> FontRead<'a> for SequenceContextFormat1<'a> {
1692 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1693 #[allow(clippy::absurd_extreme_comparisons)]
1694 if data.len() < Self::MIN_SIZE {
1695 return Err(ReadError::OutOfBounds);
1696 }
1697 Ok(Self { data })
1698 }
1699}
1700
1701#[derive(Clone)]
1703pub struct SequenceContextFormat1<'a> {
1704 data: FontData<'a>,
1705}
1706
1707#[allow(clippy::needless_lifetimes)]
1708impl<'a> SequenceContextFormat1<'a> {
1709 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1710 basic_table_impls!(impl_the_methods);
1711
1712 pub fn format(&self) -> u16 {
1714 let range = self.format_byte_range();
1715 self.data.read_at(range.start).ok().unwrap()
1716 }
1717
1718 pub fn coverage_offset(&self) -> Offset16 {
1721 let range = self.coverage_offset_byte_range();
1722 self.data.read_at(range.start).ok().unwrap()
1723 }
1724
1725 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1727 let data = self.data;
1728 self.coverage_offset().resolve(data)
1729 }
1730
1731 pub fn seq_rule_set_count(&self) -> u16 {
1733 let range = self.seq_rule_set_count_byte_range();
1734 self.data.read_at(range.start).ok().unwrap()
1735 }
1736
1737 pub fn seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
1740 let range = self.seq_rule_set_offsets_byte_range();
1741 self.data.read_array(range).ok().unwrap_or_default()
1742 }
1743
1744 pub fn seq_rule_sets(&self) -> ArrayOfNullableOffsets<'a, SequenceRuleSet<'a>, Offset16> {
1746 let data = self.data;
1747 let offsets = self.seq_rule_set_offsets();
1748 ArrayOfNullableOffsets::new(offsets, data, ())
1749 }
1750
1751 pub fn format_byte_range(&self) -> Range<usize> {
1752 let start = 0;
1753 start..start + u16::RAW_BYTE_LEN
1754 }
1755
1756 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1757 let start = self.format_byte_range().end;
1758 start..start + Offset16::RAW_BYTE_LEN
1759 }
1760
1761 pub fn seq_rule_set_count_byte_range(&self) -> Range<usize> {
1762 let start = self.coverage_offset_byte_range().end;
1763 start..start + u16::RAW_BYTE_LEN
1764 }
1765
1766 pub fn seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
1767 let seq_rule_set_count = self.seq_rule_set_count();
1768 let start = self.seq_rule_set_count_byte_range().end;
1769 start..start + (seq_rule_set_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
1770 }
1771}
1772
1773#[cfg(feature = "experimental_traverse")]
1774impl<'a> SomeTable<'a> for SequenceContextFormat1<'a> {
1775 fn type_name(&self) -> &str {
1776 "SequenceContextFormat1"
1777 }
1778 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1779 match idx {
1780 0usize => Some(Field::new("format", self.format())),
1781 1usize => Some(Field::new(
1782 "coverage_offset",
1783 FieldType::offset(self.coverage_offset(), self.coverage()),
1784 )),
1785 2usize => Some(Field::new("seq_rule_set_count", self.seq_rule_set_count())),
1786 3usize => Some({
1787 let data = self.data;
1788 Field::new(
1789 "seq_rule_set_offsets",
1790 FieldType::array_of_offsets(
1791 better_type_name::<SequenceRuleSet>(),
1792 self.seq_rule_set_offsets(),
1793 move |off| {
1794 let target = off.get().resolve::<SequenceRuleSet>(data);
1795 FieldType::offset(off.get(), target)
1796 },
1797 ),
1798 )
1799 }),
1800 _ => None,
1801 }
1802 }
1803}
1804
1805#[cfg(feature = "experimental_traverse")]
1806#[allow(clippy::needless_lifetimes)]
1807impl<'a> std::fmt::Debug for SequenceContextFormat1<'a> {
1808 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1809 (self as &dyn SomeTable<'a>).fmt(f)
1810 }
1811}
1812
1813impl<'a> MinByteRange<'a> for SequenceRuleSet<'a> {
1814 fn min_byte_range(&self) -> Range<usize> {
1815 0..self.seq_rule_offsets_byte_range().end
1816 }
1817 fn min_table_bytes(&self) -> &'a [u8] {
1818 let range = self.min_byte_range();
1819 self.data.as_bytes().get(range).unwrap_or_default()
1820 }
1821}
1822
1823impl<'a> FontRead<'a> for SequenceRuleSet<'a> {
1824 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1825 #[allow(clippy::absurd_extreme_comparisons)]
1826 if data.len() < Self::MIN_SIZE {
1827 return Err(ReadError::OutOfBounds);
1828 }
1829 Ok(Self { data })
1830 }
1831}
1832
1833#[derive(Clone)]
1835pub struct SequenceRuleSet<'a> {
1836 data: FontData<'a>,
1837}
1838
1839#[allow(clippy::needless_lifetimes)]
1840impl<'a> SequenceRuleSet<'a> {
1841 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1842 basic_table_impls!(impl_the_methods);
1843
1844 pub fn seq_rule_count(&self) -> u16 {
1846 let range = self.seq_rule_count_byte_range();
1847 self.data.read_at(range.start).ok().unwrap()
1848 }
1849
1850 pub fn seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
1853 let range = self.seq_rule_offsets_byte_range();
1854 self.data.read_array(range).ok().unwrap_or_default()
1855 }
1856
1857 pub fn seq_rules(&self) -> ArrayOfOffsets<'a, SequenceRule<'a>, Offset16> {
1859 let data = self.data;
1860 let offsets = self.seq_rule_offsets();
1861 ArrayOfOffsets::new(offsets, data, ())
1862 }
1863
1864 pub fn seq_rule_count_byte_range(&self) -> Range<usize> {
1865 let start = 0;
1866 start..start + u16::RAW_BYTE_LEN
1867 }
1868
1869 pub fn seq_rule_offsets_byte_range(&self) -> Range<usize> {
1870 let seq_rule_count = self.seq_rule_count();
1871 let start = self.seq_rule_count_byte_range().end;
1872 start..start + (seq_rule_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
1873 }
1874}
1875
1876#[cfg(feature = "experimental_traverse")]
1877impl<'a> SomeTable<'a> for SequenceRuleSet<'a> {
1878 fn type_name(&self) -> &str {
1879 "SequenceRuleSet"
1880 }
1881 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1882 match idx {
1883 0usize => Some(Field::new("seq_rule_count", self.seq_rule_count())),
1884 1usize => Some({
1885 let data = self.data;
1886 Field::new(
1887 "seq_rule_offsets",
1888 FieldType::array_of_offsets(
1889 better_type_name::<SequenceRule>(),
1890 self.seq_rule_offsets(),
1891 move |off| {
1892 let target = off.get().resolve::<SequenceRule>(data);
1893 FieldType::offset(off.get(), target)
1894 },
1895 ),
1896 )
1897 }),
1898 _ => None,
1899 }
1900 }
1901}
1902
1903#[cfg(feature = "experimental_traverse")]
1904#[allow(clippy::needless_lifetimes)]
1905impl<'a> std::fmt::Debug for SequenceRuleSet<'a> {
1906 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1907 (self as &dyn SomeTable<'a>).fmt(f)
1908 }
1909}
1910
1911impl<'a> MinByteRange<'a> for SequenceRule<'a> {
1912 fn min_byte_range(&self) -> Range<usize> {
1913 0..self.seq_lookup_records_byte_range().end
1914 }
1915 fn min_table_bytes(&self) -> &'a [u8] {
1916 let range = self.min_byte_range();
1917 self.data.as_bytes().get(range).unwrap_or_default()
1918 }
1919}
1920
1921impl<'a> FontRead<'a> for SequenceRule<'a> {
1922 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1923 #[allow(clippy::absurd_extreme_comparisons)]
1924 if data.len() < Self::MIN_SIZE {
1925 return Err(ReadError::OutOfBounds);
1926 }
1927 Ok(Self { data })
1928 }
1929}
1930
1931#[derive(Clone)]
1933pub struct SequenceRule<'a> {
1934 data: FontData<'a>,
1935}
1936
1937#[allow(clippy::needless_lifetimes)]
1938impl<'a> SequenceRule<'a> {
1939 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1940 basic_table_impls!(impl_the_methods);
1941
1942 pub fn glyph_count(&self) -> u16 {
1944 let range = self.glyph_count_byte_range();
1945 self.data.read_at(range.start).ok().unwrap()
1946 }
1947
1948 pub fn seq_lookup_count(&self) -> u16 {
1950 let range = self.seq_lookup_count_byte_range();
1951 self.data.read_at(range.start).ok().unwrap()
1952 }
1953
1954 pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
1956 let range = self.input_sequence_byte_range();
1957 self.data.read_array(range).ok().unwrap_or_default()
1958 }
1959
1960 pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
1962 let range = self.seq_lookup_records_byte_range();
1963 self.data.read_array(range).ok().unwrap_or_default()
1964 }
1965
1966 pub fn glyph_count_byte_range(&self) -> Range<usize> {
1967 let start = 0;
1968 start..start + u16::RAW_BYTE_LEN
1969 }
1970
1971 pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
1972 let start = self.glyph_count_byte_range().end;
1973 start..start + u16::RAW_BYTE_LEN
1974 }
1975
1976 pub fn input_sequence_byte_range(&self) -> Range<usize> {
1977 let glyph_count = self.glyph_count();
1978 let start = self.seq_lookup_count_byte_range().end;
1979 start
1980 ..start
1981 + (transforms::subtract(glyph_count, 1_usize))
1982 .saturating_mul(GlyphId16::RAW_BYTE_LEN)
1983 }
1984
1985 pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
1986 let seq_lookup_count = self.seq_lookup_count();
1987 let start = self.input_sequence_byte_range().end;
1988 start
1989 ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
1990 }
1991}
1992
1993#[cfg(feature = "experimental_traverse")]
1994impl<'a> SomeTable<'a> for SequenceRule<'a> {
1995 fn type_name(&self) -> &str {
1996 "SequenceRule"
1997 }
1998 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1999 match idx {
2000 0usize => Some(Field::new("glyph_count", self.glyph_count())),
2001 1usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
2002 2usize => Some(Field::new("input_sequence", self.input_sequence())),
2003 3usize => Some(Field::new(
2004 "seq_lookup_records",
2005 traversal::FieldType::array_of_records(
2006 stringify!(SequenceLookupRecord),
2007 self.seq_lookup_records(),
2008 self.offset_data(),
2009 ),
2010 )),
2011 _ => None,
2012 }
2013 }
2014}
2015
2016#[cfg(feature = "experimental_traverse")]
2017#[allow(clippy::needless_lifetimes)]
2018impl<'a> std::fmt::Debug for SequenceRule<'a> {
2019 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2020 (self as &dyn SomeTable<'a>).fmt(f)
2021 }
2022}
2023
2024impl Format<u16> for SequenceContextFormat2<'_> {
2025 const FORMAT: u16 = 2;
2026}
2027
2028impl<'a> MinByteRange<'a> for SequenceContextFormat2<'a> {
2029 fn min_byte_range(&self) -> Range<usize> {
2030 0..self.class_seq_rule_set_offsets_byte_range().end
2031 }
2032 fn min_table_bytes(&self) -> &'a [u8] {
2033 let range = self.min_byte_range();
2034 self.data.as_bytes().get(range).unwrap_or_default()
2035 }
2036}
2037
2038impl<'a> FontRead<'a> for SequenceContextFormat2<'a> {
2039 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2040 #[allow(clippy::absurd_extreme_comparisons)]
2041 if data.len() < Self::MIN_SIZE {
2042 return Err(ReadError::OutOfBounds);
2043 }
2044 Ok(Self { data })
2045 }
2046}
2047
2048#[derive(Clone)]
2050pub struct SequenceContextFormat2<'a> {
2051 data: FontData<'a>,
2052}
2053
2054#[allow(clippy::needless_lifetimes)]
2055impl<'a> SequenceContextFormat2<'a> {
2056 pub const MIN_SIZE: usize =
2057 (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2058 basic_table_impls!(impl_the_methods);
2059
2060 pub fn format(&self) -> u16 {
2062 let range = self.format_byte_range();
2063 self.data.read_at(range.start).ok().unwrap()
2064 }
2065
2066 pub fn coverage_offset(&self) -> Offset16 {
2069 let range = self.coverage_offset_byte_range();
2070 self.data.read_at(range.start).ok().unwrap()
2071 }
2072
2073 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2075 let data = self.data;
2076 self.coverage_offset().resolve(data)
2077 }
2078
2079 pub fn class_def_offset(&self) -> Offset16 {
2082 let range = self.class_def_offset_byte_range();
2083 self.data.read_at(range.start).ok().unwrap()
2084 }
2085
2086 pub fn class_def(&self) -> Result<ClassDef<'a>, ReadError> {
2088 let data = self.data;
2089 self.class_def_offset().resolve(data)
2090 }
2091
2092 pub fn class_seq_rule_set_count(&self) -> u16 {
2094 let range = self.class_seq_rule_set_count_byte_range();
2095 self.data.read_at(range.start).ok().unwrap()
2096 }
2097
2098 pub fn class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
2101 let range = self.class_seq_rule_set_offsets_byte_range();
2102 self.data.read_array(range).ok().unwrap_or_default()
2103 }
2104
2105 pub fn class_seq_rule_sets(
2107 &self,
2108 ) -> ArrayOfNullableOffsets<'a, ClassSequenceRuleSet<'a>, Offset16> {
2109 let data = self.data;
2110 let offsets = self.class_seq_rule_set_offsets();
2111 ArrayOfNullableOffsets::new(offsets, data, ())
2112 }
2113
2114 pub fn format_byte_range(&self) -> Range<usize> {
2115 let start = 0;
2116 start..start + u16::RAW_BYTE_LEN
2117 }
2118
2119 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2120 let start = self.format_byte_range().end;
2121 start..start + Offset16::RAW_BYTE_LEN
2122 }
2123
2124 pub fn class_def_offset_byte_range(&self) -> Range<usize> {
2125 let start = self.coverage_offset_byte_range().end;
2126 start..start + Offset16::RAW_BYTE_LEN
2127 }
2128
2129 pub fn class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
2130 let start = self.class_def_offset_byte_range().end;
2131 start..start + u16::RAW_BYTE_LEN
2132 }
2133
2134 pub fn class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
2135 let class_seq_rule_set_count = self.class_seq_rule_set_count();
2136 let start = self.class_seq_rule_set_count_byte_range().end;
2137 start..start + (class_seq_rule_set_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
2138 }
2139}
2140
2141#[cfg(feature = "experimental_traverse")]
2142impl<'a> SomeTable<'a> for SequenceContextFormat2<'a> {
2143 fn type_name(&self) -> &str {
2144 "SequenceContextFormat2"
2145 }
2146 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2147 match idx {
2148 0usize => Some(Field::new("format", self.format())),
2149 1usize => Some(Field::new(
2150 "coverage_offset",
2151 FieldType::offset(self.coverage_offset(), self.coverage()),
2152 )),
2153 2usize => Some(Field::new(
2154 "class_def_offset",
2155 FieldType::offset(self.class_def_offset(), self.class_def()),
2156 )),
2157 3usize => Some(Field::new(
2158 "class_seq_rule_set_count",
2159 self.class_seq_rule_set_count(),
2160 )),
2161 4usize => Some({
2162 let data = self.data;
2163 Field::new(
2164 "class_seq_rule_set_offsets",
2165 FieldType::array_of_offsets(
2166 better_type_name::<ClassSequenceRuleSet>(),
2167 self.class_seq_rule_set_offsets(),
2168 move |off| {
2169 let target = off.get().resolve::<ClassSequenceRuleSet>(data);
2170 FieldType::offset(off.get(), target)
2171 },
2172 ),
2173 )
2174 }),
2175 _ => None,
2176 }
2177 }
2178}
2179
2180#[cfg(feature = "experimental_traverse")]
2181#[allow(clippy::needless_lifetimes)]
2182impl<'a> std::fmt::Debug for SequenceContextFormat2<'a> {
2183 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2184 (self as &dyn SomeTable<'a>).fmt(f)
2185 }
2186}
2187
2188impl<'a> MinByteRange<'a> for ClassSequenceRuleSet<'a> {
2189 fn min_byte_range(&self) -> Range<usize> {
2190 0..self.class_seq_rule_offsets_byte_range().end
2191 }
2192 fn min_table_bytes(&self) -> &'a [u8] {
2193 let range = self.min_byte_range();
2194 self.data.as_bytes().get(range).unwrap_or_default()
2195 }
2196}
2197
2198impl<'a> FontRead<'a> for ClassSequenceRuleSet<'a> {
2199 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2200 #[allow(clippy::absurd_extreme_comparisons)]
2201 if data.len() < Self::MIN_SIZE {
2202 return Err(ReadError::OutOfBounds);
2203 }
2204 Ok(Self { data })
2205 }
2206}
2207
2208#[derive(Clone)]
2210pub struct ClassSequenceRuleSet<'a> {
2211 data: FontData<'a>,
2212}
2213
2214#[allow(clippy::needless_lifetimes)]
2215impl<'a> ClassSequenceRuleSet<'a> {
2216 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
2217 basic_table_impls!(impl_the_methods);
2218
2219 pub fn class_seq_rule_count(&self) -> u16 {
2221 let range = self.class_seq_rule_count_byte_range();
2222 self.data.read_at(range.start).ok().unwrap()
2223 }
2224
2225 pub fn class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
2228 let range = self.class_seq_rule_offsets_byte_range();
2229 self.data.read_array(range).ok().unwrap_or_default()
2230 }
2231
2232 pub fn class_seq_rules(&self) -> ArrayOfOffsets<'a, ClassSequenceRule<'a>, Offset16> {
2234 let data = self.data;
2235 let offsets = self.class_seq_rule_offsets();
2236 ArrayOfOffsets::new(offsets, data, ())
2237 }
2238
2239 pub fn class_seq_rule_count_byte_range(&self) -> Range<usize> {
2240 let start = 0;
2241 start..start + u16::RAW_BYTE_LEN
2242 }
2243
2244 pub fn class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
2245 let class_seq_rule_count = self.class_seq_rule_count();
2246 let start = self.class_seq_rule_count_byte_range().end;
2247 start..start + (class_seq_rule_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
2248 }
2249}
2250
2251#[cfg(feature = "experimental_traverse")]
2252impl<'a> SomeTable<'a> for ClassSequenceRuleSet<'a> {
2253 fn type_name(&self) -> &str {
2254 "ClassSequenceRuleSet"
2255 }
2256 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2257 match idx {
2258 0usize => Some(Field::new(
2259 "class_seq_rule_count",
2260 self.class_seq_rule_count(),
2261 )),
2262 1usize => Some({
2263 let data = self.data;
2264 Field::new(
2265 "class_seq_rule_offsets",
2266 FieldType::array_of_offsets(
2267 better_type_name::<ClassSequenceRule>(),
2268 self.class_seq_rule_offsets(),
2269 move |off| {
2270 let target = off.get().resolve::<ClassSequenceRule>(data);
2271 FieldType::offset(off.get(), target)
2272 },
2273 ),
2274 )
2275 }),
2276 _ => None,
2277 }
2278 }
2279}
2280
2281#[cfg(feature = "experimental_traverse")]
2282#[allow(clippy::needless_lifetimes)]
2283impl<'a> std::fmt::Debug for ClassSequenceRuleSet<'a> {
2284 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2285 (self as &dyn SomeTable<'a>).fmt(f)
2286 }
2287}
2288
2289impl<'a> MinByteRange<'a> for ClassSequenceRule<'a> {
2290 fn min_byte_range(&self) -> Range<usize> {
2291 0..self.seq_lookup_records_byte_range().end
2292 }
2293 fn min_table_bytes(&self) -> &'a [u8] {
2294 let range = self.min_byte_range();
2295 self.data.as_bytes().get(range).unwrap_or_default()
2296 }
2297}
2298
2299impl<'a> FontRead<'a> for ClassSequenceRule<'a> {
2300 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2301 #[allow(clippy::absurd_extreme_comparisons)]
2302 if data.len() < Self::MIN_SIZE {
2303 return Err(ReadError::OutOfBounds);
2304 }
2305 Ok(Self { data })
2306 }
2307}
2308
2309#[derive(Clone)]
2311pub struct ClassSequenceRule<'a> {
2312 data: FontData<'a>,
2313}
2314
2315#[allow(clippy::needless_lifetimes)]
2316impl<'a> ClassSequenceRule<'a> {
2317 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2318 basic_table_impls!(impl_the_methods);
2319
2320 pub fn glyph_count(&self) -> u16 {
2322 let range = self.glyph_count_byte_range();
2323 self.data.read_at(range.start).ok().unwrap()
2324 }
2325
2326 pub fn seq_lookup_count(&self) -> u16 {
2328 let range = self.seq_lookup_count_byte_range();
2329 self.data.read_at(range.start).ok().unwrap()
2330 }
2331
2332 pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
2335 let range = self.input_sequence_byte_range();
2336 self.data.read_array(range).ok().unwrap_or_default()
2337 }
2338
2339 pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2341 let range = self.seq_lookup_records_byte_range();
2342 self.data.read_array(range).ok().unwrap_or_default()
2343 }
2344
2345 pub fn glyph_count_byte_range(&self) -> Range<usize> {
2346 let start = 0;
2347 start..start + u16::RAW_BYTE_LEN
2348 }
2349
2350 pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2351 let start = self.glyph_count_byte_range().end;
2352 start..start + u16::RAW_BYTE_LEN
2353 }
2354
2355 pub fn input_sequence_byte_range(&self) -> Range<usize> {
2356 let glyph_count = self.glyph_count();
2357 let start = self.seq_lookup_count_byte_range().end;
2358 start
2359 ..start + (transforms::subtract(glyph_count, 1_usize)).saturating_mul(u16::RAW_BYTE_LEN)
2360 }
2361
2362 pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2363 let seq_lookup_count = self.seq_lookup_count();
2364 let start = self.input_sequence_byte_range().end;
2365 start
2366 ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
2367 }
2368}
2369
2370#[cfg(feature = "experimental_traverse")]
2371impl<'a> SomeTable<'a> for ClassSequenceRule<'a> {
2372 fn type_name(&self) -> &str {
2373 "ClassSequenceRule"
2374 }
2375 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2376 match idx {
2377 0usize => Some(Field::new("glyph_count", self.glyph_count())),
2378 1usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
2379 2usize => Some(Field::new("input_sequence", self.input_sequence())),
2380 3usize => Some(Field::new(
2381 "seq_lookup_records",
2382 traversal::FieldType::array_of_records(
2383 stringify!(SequenceLookupRecord),
2384 self.seq_lookup_records(),
2385 self.offset_data(),
2386 ),
2387 )),
2388 _ => None,
2389 }
2390 }
2391}
2392
2393#[cfg(feature = "experimental_traverse")]
2394#[allow(clippy::needless_lifetimes)]
2395impl<'a> std::fmt::Debug for ClassSequenceRule<'a> {
2396 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2397 (self as &dyn SomeTable<'a>).fmt(f)
2398 }
2399}
2400
2401impl Format<u16> for SequenceContextFormat3<'_> {
2402 const FORMAT: u16 = 3;
2403}
2404
2405impl<'a> MinByteRange<'a> for SequenceContextFormat3<'a> {
2406 fn min_byte_range(&self) -> Range<usize> {
2407 0..self.seq_lookup_records_byte_range().end
2408 }
2409 fn min_table_bytes(&self) -> &'a [u8] {
2410 let range = self.min_byte_range();
2411 self.data.as_bytes().get(range).unwrap_or_default()
2412 }
2413}
2414
2415impl<'a> FontRead<'a> for SequenceContextFormat3<'a> {
2416 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2417 #[allow(clippy::absurd_extreme_comparisons)]
2418 if data.len() < Self::MIN_SIZE {
2419 return Err(ReadError::OutOfBounds);
2420 }
2421 Ok(Self { data })
2422 }
2423}
2424
2425#[derive(Clone)]
2427pub struct SequenceContextFormat3<'a> {
2428 data: FontData<'a>,
2429}
2430
2431#[allow(clippy::needless_lifetimes)]
2432impl<'a> SequenceContextFormat3<'a> {
2433 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2434 basic_table_impls!(impl_the_methods);
2435
2436 pub fn format(&self) -> u16 {
2438 let range = self.format_byte_range();
2439 self.data.read_at(range.start).ok().unwrap()
2440 }
2441
2442 pub fn glyph_count(&self) -> u16 {
2444 let range = self.glyph_count_byte_range();
2445 self.data.read_at(range.start).ok().unwrap()
2446 }
2447
2448 pub fn seq_lookup_count(&self) -> u16 {
2450 let range = self.seq_lookup_count_byte_range();
2451 self.data.read_at(range.start).ok().unwrap()
2452 }
2453
2454 pub fn coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
2457 let range = self.coverage_offsets_byte_range();
2458 self.data.read_array(range).ok().unwrap_or_default()
2459 }
2460
2461 pub fn coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
2463 let data = self.data;
2464 let offsets = self.coverage_offsets();
2465 ArrayOfOffsets::new(offsets, data, ())
2466 }
2467
2468 pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2470 let range = self.seq_lookup_records_byte_range();
2471 self.data.read_array(range).ok().unwrap_or_default()
2472 }
2473
2474 pub fn format_byte_range(&self) -> Range<usize> {
2475 let start = 0;
2476 start..start + u16::RAW_BYTE_LEN
2477 }
2478
2479 pub fn glyph_count_byte_range(&self) -> Range<usize> {
2480 let start = self.format_byte_range().end;
2481 start..start + u16::RAW_BYTE_LEN
2482 }
2483
2484 pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2485 let start = self.glyph_count_byte_range().end;
2486 start..start + u16::RAW_BYTE_LEN
2487 }
2488
2489 pub fn coverage_offsets_byte_range(&self) -> Range<usize> {
2490 let glyph_count = self.glyph_count();
2491 let start = self.seq_lookup_count_byte_range().end;
2492 start..start + (glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
2493 }
2494
2495 pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2496 let seq_lookup_count = self.seq_lookup_count();
2497 let start = self.coverage_offsets_byte_range().end;
2498 start
2499 ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
2500 }
2501}
2502
2503#[cfg(feature = "experimental_traverse")]
2504impl<'a> SomeTable<'a> for SequenceContextFormat3<'a> {
2505 fn type_name(&self) -> &str {
2506 "SequenceContextFormat3"
2507 }
2508 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2509 match idx {
2510 0usize => Some(Field::new("format", self.format())),
2511 1usize => Some(Field::new("glyph_count", self.glyph_count())),
2512 2usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
2513 3usize => Some({
2514 let data = self.data;
2515 Field::new(
2516 "coverage_offsets",
2517 FieldType::array_of_offsets(
2518 better_type_name::<CoverageTable>(),
2519 self.coverage_offsets(),
2520 move |off| {
2521 let target = off.get().resolve::<CoverageTable>(data);
2522 FieldType::offset(off.get(), target)
2523 },
2524 ),
2525 )
2526 }),
2527 4usize => Some(Field::new(
2528 "seq_lookup_records",
2529 traversal::FieldType::array_of_records(
2530 stringify!(SequenceLookupRecord),
2531 self.seq_lookup_records(),
2532 self.offset_data(),
2533 ),
2534 )),
2535 _ => None,
2536 }
2537 }
2538}
2539
2540#[cfg(feature = "experimental_traverse")]
2541#[allow(clippy::needless_lifetimes)]
2542impl<'a> std::fmt::Debug for SequenceContextFormat3<'a> {
2543 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2544 (self as &dyn SomeTable<'a>).fmt(f)
2545 }
2546}
2547
2548#[derive(Clone)]
2549pub enum SequenceContext<'a> {
2550 Format1(SequenceContextFormat1<'a>),
2551 Format2(SequenceContextFormat2<'a>),
2552 Format3(SequenceContextFormat3<'a>),
2553}
2554
2555impl<'a> SequenceContext<'a> {
2556 pub fn offset_data(&self) -> FontData<'a> {
2558 match self {
2559 Self::Format1(item) => item.offset_data(),
2560 Self::Format2(item) => item.offset_data(),
2561 Self::Format3(item) => item.offset_data(),
2562 }
2563 }
2564
2565 pub fn format(&self) -> u16 {
2567 match self {
2568 Self::Format1(item) => item.format(),
2569 Self::Format2(item) => item.format(),
2570 Self::Format3(item) => item.format(),
2571 }
2572 }
2573}
2574
2575impl<'a> FontRead<'a> for SequenceContext<'a> {
2576 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2577 let format: u16 = data.read_at(0usize)?;
2578 match format {
2579 SequenceContextFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
2580 SequenceContextFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
2581 SequenceContextFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
2582 other => Err(ReadError::InvalidFormat(other.into())),
2583 }
2584 }
2585}
2586
2587impl<'a> MinByteRange<'a> for SequenceContext<'a> {
2588 fn min_byte_range(&self) -> Range<usize> {
2589 match self {
2590 Self::Format1(item) => item.min_byte_range(),
2591 Self::Format2(item) => item.min_byte_range(),
2592 Self::Format3(item) => item.min_byte_range(),
2593 }
2594 }
2595 fn min_table_bytes(&self) -> &'a [u8] {
2596 match self {
2597 Self::Format1(item) => item.min_table_bytes(),
2598 Self::Format2(item) => item.min_table_bytes(),
2599 Self::Format3(item) => item.min_table_bytes(),
2600 }
2601 }
2602}
2603
2604#[cfg(feature = "experimental_traverse")]
2605impl<'a> SequenceContext<'a> {
2606 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
2607 match self {
2608 Self::Format1(table) => table,
2609 Self::Format2(table) => table,
2610 Self::Format3(table) => table,
2611 }
2612 }
2613}
2614
2615#[cfg(feature = "experimental_traverse")]
2616impl std::fmt::Debug for SequenceContext<'_> {
2617 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2618 self.dyn_inner().fmt(f)
2619 }
2620}
2621
2622#[cfg(feature = "experimental_traverse")]
2623impl<'a> SomeTable<'a> for SequenceContext<'a> {
2624 fn type_name(&self) -> &str {
2625 self.dyn_inner().type_name()
2626 }
2627 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2628 self.dyn_inner().get_field(idx)
2629 }
2630}
2631
2632impl Format<u16> for ChainedSequenceContextFormat1<'_> {
2633 const FORMAT: u16 = 1;
2634}
2635
2636impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat1<'a> {
2637 fn min_byte_range(&self) -> Range<usize> {
2638 0..self.chained_seq_rule_set_offsets_byte_range().end
2639 }
2640 fn min_table_bytes(&self) -> &'a [u8] {
2641 let range = self.min_byte_range();
2642 self.data.as_bytes().get(range).unwrap_or_default()
2643 }
2644}
2645
2646impl<'a> FontRead<'a> for ChainedSequenceContextFormat1<'a> {
2647 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2648 #[allow(clippy::absurd_extreme_comparisons)]
2649 if data.len() < Self::MIN_SIZE {
2650 return Err(ReadError::OutOfBounds);
2651 }
2652 Ok(Self { data })
2653 }
2654}
2655
2656#[derive(Clone)]
2658pub struct ChainedSequenceContextFormat1<'a> {
2659 data: FontData<'a>,
2660}
2661
2662#[allow(clippy::needless_lifetimes)]
2663impl<'a> ChainedSequenceContextFormat1<'a> {
2664 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2665 basic_table_impls!(impl_the_methods);
2666
2667 pub fn format(&self) -> u16 {
2669 let range = self.format_byte_range();
2670 self.data.read_at(range.start).ok().unwrap()
2671 }
2672
2673 pub fn coverage_offset(&self) -> Offset16 {
2676 let range = self.coverage_offset_byte_range();
2677 self.data.read_at(range.start).ok().unwrap()
2678 }
2679
2680 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2682 let data = self.data;
2683 self.coverage_offset().resolve(data)
2684 }
2685
2686 pub fn chained_seq_rule_set_count(&self) -> u16 {
2688 let range = self.chained_seq_rule_set_count_byte_range();
2689 self.data.read_at(range.start).ok().unwrap()
2690 }
2691
2692 pub fn chained_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
2695 let range = self.chained_seq_rule_set_offsets_byte_range();
2696 self.data.read_array(range).ok().unwrap_or_default()
2697 }
2698
2699 pub fn chained_seq_rule_sets(
2701 &self,
2702 ) -> ArrayOfNullableOffsets<'a, ChainedSequenceRuleSet<'a>, Offset16> {
2703 let data = self.data;
2704 let offsets = self.chained_seq_rule_set_offsets();
2705 ArrayOfNullableOffsets::new(offsets, data, ())
2706 }
2707
2708 pub fn format_byte_range(&self) -> Range<usize> {
2709 let start = 0;
2710 start..start + u16::RAW_BYTE_LEN
2711 }
2712
2713 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2714 let start = self.format_byte_range().end;
2715 start..start + Offset16::RAW_BYTE_LEN
2716 }
2717
2718 pub fn chained_seq_rule_set_count_byte_range(&self) -> Range<usize> {
2719 let start = self.coverage_offset_byte_range().end;
2720 start..start + u16::RAW_BYTE_LEN
2721 }
2722
2723 pub fn chained_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
2724 let chained_seq_rule_set_count = self.chained_seq_rule_set_count();
2725 let start = self.chained_seq_rule_set_count_byte_range().end;
2726 start..start + (chained_seq_rule_set_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
2727 }
2728}
2729
2730#[cfg(feature = "experimental_traverse")]
2731impl<'a> SomeTable<'a> for ChainedSequenceContextFormat1<'a> {
2732 fn type_name(&self) -> &str {
2733 "ChainedSequenceContextFormat1"
2734 }
2735 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2736 match idx {
2737 0usize => Some(Field::new("format", self.format())),
2738 1usize => Some(Field::new(
2739 "coverage_offset",
2740 FieldType::offset(self.coverage_offset(), self.coverage()),
2741 )),
2742 2usize => Some(Field::new(
2743 "chained_seq_rule_set_count",
2744 self.chained_seq_rule_set_count(),
2745 )),
2746 3usize => Some({
2747 let data = self.data;
2748 Field::new(
2749 "chained_seq_rule_set_offsets",
2750 FieldType::array_of_offsets(
2751 better_type_name::<ChainedSequenceRuleSet>(),
2752 self.chained_seq_rule_set_offsets(),
2753 move |off| {
2754 let target = off.get().resolve::<ChainedSequenceRuleSet>(data);
2755 FieldType::offset(off.get(), target)
2756 },
2757 ),
2758 )
2759 }),
2760 _ => None,
2761 }
2762 }
2763}
2764
2765#[cfg(feature = "experimental_traverse")]
2766#[allow(clippy::needless_lifetimes)]
2767impl<'a> std::fmt::Debug for ChainedSequenceContextFormat1<'a> {
2768 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2769 (self as &dyn SomeTable<'a>).fmt(f)
2770 }
2771}
2772
2773impl<'a> MinByteRange<'a> for ChainedSequenceRuleSet<'a> {
2774 fn min_byte_range(&self) -> Range<usize> {
2775 0..self.chained_seq_rule_offsets_byte_range().end
2776 }
2777 fn min_table_bytes(&self) -> &'a [u8] {
2778 let range = self.min_byte_range();
2779 self.data.as_bytes().get(range).unwrap_or_default()
2780 }
2781}
2782
2783impl<'a> FontRead<'a> for ChainedSequenceRuleSet<'a> {
2784 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2785 #[allow(clippy::absurd_extreme_comparisons)]
2786 if data.len() < Self::MIN_SIZE {
2787 return Err(ReadError::OutOfBounds);
2788 }
2789 Ok(Self { data })
2790 }
2791}
2792
2793#[derive(Clone)]
2795pub struct ChainedSequenceRuleSet<'a> {
2796 data: FontData<'a>,
2797}
2798
2799#[allow(clippy::needless_lifetimes)]
2800impl<'a> ChainedSequenceRuleSet<'a> {
2801 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
2802 basic_table_impls!(impl_the_methods);
2803
2804 pub fn chained_seq_rule_count(&self) -> u16 {
2806 let range = self.chained_seq_rule_count_byte_range();
2807 self.data.read_at(range.start).ok().unwrap()
2808 }
2809
2810 pub fn chained_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
2813 let range = self.chained_seq_rule_offsets_byte_range();
2814 self.data.read_array(range).ok().unwrap_or_default()
2815 }
2816
2817 pub fn chained_seq_rules(&self) -> ArrayOfOffsets<'a, ChainedSequenceRule<'a>, Offset16> {
2819 let data = self.data;
2820 let offsets = self.chained_seq_rule_offsets();
2821 ArrayOfOffsets::new(offsets, data, ())
2822 }
2823
2824 pub fn chained_seq_rule_count_byte_range(&self) -> Range<usize> {
2825 let start = 0;
2826 start..start + u16::RAW_BYTE_LEN
2827 }
2828
2829 pub fn chained_seq_rule_offsets_byte_range(&self) -> Range<usize> {
2830 let chained_seq_rule_count = self.chained_seq_rule_count();
2831 let start = self.chained_seq_rule_count_byte_range().end;
2832 start..start + (chained_seq_rule_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
2833 }
2834}
2835
2836#[cfg(feature = "experimental_traverse")]
2837impl<'a> SomeTable<'a> for ChainedSequenceRuleSet<'a> {
2838 fn type_name(&self) -> &str {
2839 "ChainedSequenceRuleSet"
2840 }
2841 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2842 match idx {
2843 0usize => Some(Field::new(
2844 "chained_seq_rule_count",
2845 self.chained_seq_rule_count(),
2846 )),
2847 1usize => Some({
2848 let data = self.data;
2849 Field::new(
2850 "chained_seq_rule_offsets",
2851 FieldType::array_of_offsets(
2852 better_type_name::<ChainedSequenceRule>(),
2853 self.chained_seq_rule_offsets(),
2854 move |off| {
2855 let target = off.get().resolve::<ChainedSequenceRule>(data);
2856 FieldType::offset(off.get(), target)
2857 },
2858 ),
2859 )
2860 }),
2861 _ => None,
2862 }
2863 }
2864}
2865
2866#[cfg(feature = "experimental_traverse")]
2867#[allow(clippy::needless_lifetimes)]
2868impl<'a> std::fmt::Debug for ChainedSequenceRuleSet<'a> {
2869 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2870 (self as &dyn SomeTable<'a>).fmt(f)
2871 }
2872}
2873
2874impl<'a> MinByteRange<'a> for ChainedSequenceRule<'a> {
2875 fn min_byte_range(&self) -> Range<usize> {
2876 0..self.seq_lookup_records_byte_range().end
2877 }
2878 fn min_table_bytes(&self) -> &'a [u8] {
2879 let range = self.min_byte_range();
2880 self.data.as_bytes().get(range).unwrap_or_default()
2881 }
2882}
2883
2884impl<'a> FontRead<'a> for ChainedSequenceRule<'a> {
2885 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2886 #[allow(clippy::absurd_extreme_comparisons)]
2887 if data.len() < Self::MIN_SIZE {
2888 return Err(ReadError::OutOfBounds);
2889 }
2890 Ok(Self { data })
2891 }
2892}
2893
2894#[derive(Clone)]
2896pub struct ChainedSequenceRule<'a> {
2897 data: FontData<'a>,
2898}
2899
2900#[allow(clippy::needless_lifetimes)]
2901impl<'a> ChainedSequenceRule<'a> {
2902 pub const MIN_SIZE: usize =
2903 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2904 basic_table_impls!(impl_the_methods);
2905
2906 pub fn backtrack_glyph_count(&self) -> u16 {
2908 let range = self.backtrack_glyph_count_byte_range();
2909 self.data.read_at(range.start).ok().unwrap()
2910 }
2911
2912 pub fn backtrack_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
2914 let range = self.backtrack_sequence_byte_range();
2915 self.data.read_array(range).ok().unwrap_or_default()
2916 }
2917
2918 pub fn input_glyph_count(&self) -> u16 {
2920 let range = self.input_glyph_count_byte_range();
2921 self.data.read_at(range.start).ok().unwrap_or_default()
2922 }
2923
2924 pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
2926 let range = self.input_sequence_byte_range();
2927 self.data.read_array(range).ok().unwrap_or_default()
2928 }
2929
2930 pub fn lookahead_glyph_count(&self) -> u16 {
2932 let range = self.lookahead_glyph_count_byte_range();
2933 self.data.read_at(range.start).ok().unwrap_or_default()
2934 }
2935
2936 pub fn lookahead_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
2938 let range = self.lookahead_sequence_byte_range();
2939 self.data.read_array(range).ok().unwrap_or_default()
2940 }
2941
2942 pub fn seq_lookup_count(&self) -> u16 {
2944 let range = self.seq_lookup_count_byte_range();
2945 self.data.read_at(range.start).ok().unwrap_or_default()
2946 }
2947
2948 pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2950 let range = self.seq_lookup_records_byte_range();
2951 self.data.read_array(range).ok().unwrap_or_default()
2952 }
2953
2954 pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
2955 let start = 0;
2956 start..start + u16::RAW_BYTE_LEN
2957 }
2958
2959 pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
2960 let backtrack_glyph_count = self.backtrack_glyph_count();
2961 let start = self.backtrack_glyph_count_byte_range().end;
2962 start..start + (backtrack_glyph_count as usize).saturating_mul(GlyphId16::RAW_BYTE_LEN)
2963 }
2964
2965 pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
2966 let start = self.backtrack_sequence_byte_range().end;
2967 start..start + u16::RAW_BYTE_LEN
2968 }
2969
2970 pub fn input_sequence_byte_range(&self) -> Range<usize> {
2971 let input_glyph_count = self.input_glyph_count();
2972 let start = self.input_glyph_count_byte_range().end;
2973 start
2974 ..start
2975 + (transforms::subtract(input_glyph_count, 1_usize))
2976 .saturating_mul(GlyphId16::RAW_BYTE_LEN)
2977 }
2978
2979 pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
2980 let start = self.input_sequence_byte_range().end;
2981 start..start + u16::RAW_BYTE_LEN
2982 }
2983
2984 pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
2985 let lookahead_glyph_count = self.lookahead_glyph_count();
2986 let start = self.lookahead_glyph_count_byte_range().end;
2987 start..start + (lookahead_glyph_count as usize).saturating_mul(GlyphId16::RAW_BYTE_LEN)
2988 }
2989
2990 pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2991 let start = self.lookahead_sequence_byte_range().end;
2992 start..start + u16::RAW_BYTE_LEN
2993 }
2994
2995 pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2996 let seq_lookup_count = self.seq_lookup_count();
2997 let start = self.seq_lookup_count_byte_range().end;
2998 start
2999 ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
3000 }
3001}
3002
3003#[cfg(feature = "experimental_traverse")]
3004impl<'a> SomeTable<'a> for ChainedSequenceRule<'a> {
3005 fn type_name(&self) -> &str {
3006 "ChainedSequenceRule"
3007 }
3008 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3009 match idx {
3010 0usize => Some(Field::new(
3011 "backtrack_glyph_count",
3012 self.backtrack_glyph_count(),
3013 )),
3014 1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())),
3015 2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
3016 3usize => Some(Field::new("input_sequence", self.input_sequence())),
3017 4usize => Some(Field::new(
3018 "lookahead_glyph_count",
3019 self.lookahead_glyph_count(),
3020 )),
3021 5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())),
3022 6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
3023 7usize => Some(Field::new(
3024 "seq_lookup_records",
3025 traversal::FieldType::array_of_records(
3026 stringify!(SequenceLookupRecord),
3027 self.seq_lookup_records(),
3028 self.offset_data(),
3029 ),
3030 )),
3031 _ => None,
3032 }
3033 }
3034}
3035
3036#[cfg(feature = "experimental_traverse")]
3037#[allow(clippy::needless_lifetimes)]
3038impl<'a> std::fmt::Debug for ChainedSequenceRule<'a> {
3039 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3040 (self as &dyn SomeTable<'a>).fmt(f)
3041 }
3042}
3043
3044impl Format<u16> for ChainedSequenceContextFormat2<'_> {
3045 const FORMAT: u16 = 2;
3046}
3047
3048impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat2<'a> {
3049 fn min_byte_range(&self) -> Range<usize> {
3050 0..self.chained_class_seq_rule_set_offsets_byte_range().end
3051 }
3052 fn min_table_bytes(&self) -> &'a [u8] {
3053 let range = self.min_byte_range();
3054 self.data.as_bytes().get(range).unwrap_or_default()
3055 }
3056}
3057
3058impl<'a> FontRead<'a> for ChainedSequenceContextFormat2<'a> {
3059 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3060 #[allow(clippy::absurd_extreme_comparisons)]
3061 if data.len() < Self::MIN_SIZE {
3062 return Err(ReadError::OutOfBounds);
3063 }
3064 Ok(Self { data })
3065 }
3066}
3067
3068#[derive(Clone)]
3070pub struct ChainedSequenceContextFormat2<'a> {
3071 data: FontData<'a>,
3072}
3073
3074#[allow(clippy::needless_lifetimes)]
3075impl<'a> ChainedSequenceContextFormat2<'a> {
3076 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3077 + Offset16::RAW_BYTE_LEN
3078 + Offset16::RAW_BYTE_LEN
3079 + Offset16::RAW_BYTE_LEN
3080 + Offset16::RAW_BYTE_LEN
3081 + u16::RAW_BYTE_LEN);
3082 basic_table_impls!(impl_the_methods);
3083
3084 pub fn format(&self) -> u16 {
3086 let range = self.format_byte_range();
3087 self.data.read_at(range.start).ok().unwrap()
3088 }
3089
3090 pub fn coverage_offset(&self) -> Offset16 {
3093 let range = self.coverage_offset_byte_range();
3094 self.data.read_at(range.start).ok().unwrap()
3095 }
3096
3097 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3099 let data = self.data;
3100 self.coverage_offset().resolve(data)
3101 }
3102
3103 pub fn backtrack_class_def_offset(&self) -> Offset16 {
3106 let range = self.backtrack_class_def_offset_byte_range();
3107 self.data.read_at(range.start).ok().unwrap()
3108 }
3109
3110 pub fn backtrack_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3112 let data = self.data;
3113 self.backtrack_class_def_offset().resolve(data)
3114 }
3115
3116 pub fn input_class_def_offset(&self) -> Offset16 {
3119 let range = self.input_class_def_offset_byte_range();
3120 self.data.read_at(range.start).ok().unwrap()
3121 }
3122
3123 pub fn input_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3125 let data = self.data;
3126 self.input_class_def_offset().resolve(data)
3127 }
3128
3129 pub fn lookahead_class_def_offset(&self) -> Offset16 {
3132 let range = self.lookahead_class_def_offset_byte_range();
3133 self.data.read_at(range.start).ok().unwrap()
3134 }
3135
3136 pub fn lookahead_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3138 let data = self.data;
3139 self.lookahead_class_def_offset().resolve(data)
3140 }
3141
3142 pub fn chained_class_seq_rule_set_count(&self) -> u16 {
3144 let range = self.chained_class_seq_rule_set_count_byte_range();
3145 self.data.read_at(range.start).ok().unwrap()
3146 }
3147
3148 pub fn chained_class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3151 let range = self.chained_class_seq_rule_set_offsets_byte_range();
3152 self.data.read_array(range).ok().unwrap_or_default()
3153 }
3154
3155 pub fn chained_class_seq_rule_sets(
3157 &self,
3158 ) -> ArrayOfNullableOffsets<'a, ChainedClassSequenceRuleSet<'a>, Offset16> {
3159 let data = self.data;
3160 let offsets = self.chained_class_seq_rule_set_offsets();
3161 ArrayOfNullableOffsets::new(offsets, data, ())
3162 }
3163
3164 pub fn format_byte_range(&self) -> Range<usize> {
3165 let start = 0;
3166 start..start + u16::RAW_BYTE_LEN
3167 }
3168
3169 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
3170 let start = self.format_byte_range().end;
3171 start..start + Offset16::RAW_BYTE_LEN
3172 }
3173
3174 pub fn backtrack_class_def_offset_byte_range(&self) -> Range<usize> {
3175 let start = self.coverage_offset_byte_range().end;
3176 start..start + Offset16::RAW_BYTE_LEN
3177 }
3178
3179 pub fn input_class_def_offset_byte_range(&self) -> Range<usize> {
3180 let start = self.backtrack_class_def_offset_byte_range().end;
3181 start..start + Offset16::RAW_BYTE_LEN
3182 }
3183
3184 pub fn lookahead_class_def_offset_byte_range(&self) -> Range<usize> {
3185 let start = self.input_class_def_offset_byte_range().end;
3186 start..start + Offset16::RAW_BYTE_LEN
3187 }
3188
3189 pub fn chained_class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
3190 let start = self.lookahead_class_def_offset_byte_range().end;
3191 start..start + u16::RAW_BYTE_LEN
3192 }
3193
3194 pub fn chained_class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
3195 let chained_class_seq_rule_set_count = self.chained_class_seq_rule_set_count();
3196 let start = self.chained_class_seq_rule_set_count_byte_range().end;
3197 start
3198 ..start
3199 + (chained_class_seq_rule_set_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
3200 }
3201}
3202
3203#[cfg(feature = "experimental_traverse")]
3204impl<'a> SomeTable<'a> for ChainedSequenceContextFormat2<'a> {
3205 fn type_name(&self) -> &str {
3206 "ChainedSequenceContextFormat2"
3207 }
3208 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3209 match idx {
3210 0usize => Some(Field::new("format", self.format())),
3211 1usize => Some(Field::new(
3212 "coverage_offset",
3213 FieldType::offset(self.coverage_offset(), self.coverage()),
3214 )),
3215 2usize => Some(Field::new(
3216 "backtrack_class_def_offset",
3217 FieldType::offset(
3218 self.backtrack_class_def_offset(),
3219 self.backtrack_class_def(),
3220 ),
3221 )),
3222 3usize => Some(Field::new(
3223 "input_class_def_offset",
3224 FieldType::offset(self.input_class_def_offset(), self.input_class_def()),
3225 )),
3226 4usize => Some(Field::new(
3227 "lookahead_class_def_offset",
3228 FieldType::offset(
3229 self.lookahead_class_def_offset(),
3230 self.lookahead_class_def(),
3231 ),
3232 )),
3233 5usize => Some(Field::new(
3234 "chained_class_seq_rule_set_count",
3235 self.chained_class_seq_rule_set_count(),
3236 )),
3237 6usize => Some({
3238 let data = self.data;
3239 Field::new(
3240 "chained_class_seq_rule_set_offsets",
3241 FieldType::array_of_offsets(
3242 better_type_name::<ChainedClassSequenceRuleSet>(),
3243 self.chained_class_seq_rule_set_offsets(),
3244 move |off| {
3245 let target = off.get().resolve::<ChainedClassSequenceRuleSet>(data);
3246 FieldType::offset(off.get(), target)
3247 },
3248 ),
3249 )
3250 }),
3251 _ => None,
3252 }
3253 }
3254}
3255
3256#[cfg(feature = "experimental_traverse")]
3257#[allow(clippy::needless_lifetimes)]
3258impl<'a> std::fmt::Debug for ChainedSequenceContextFormat2<'a> {
3259 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3260 (self as &dyn SomeTable<'a>).fmt(f)
3261 }
3262}
3263
3264impl<'a> MinByteRange<'a> for ChainedClassSequenceRuleSet<'a> {
3265 fn min_byte_range(&self) -> Range<usize> {
3266 0..self.chained_class_seq_rule_offsets_byte_range().end
3267 }
3268 fn min_table_bytes(&self) -> &'a [u8] {
3269 let range = self.min_byte_range();
3270 self.data.as_bytes().get(range).unwrap_or_default()
3271 }
3272}
3273
3274impl<'a> FontRead<'a> for ChainedClassSequenceRuleSet<'a> {
3275 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3276 #[allow(clippy::absurd_extreme_comparisons)]
3277 if data.len() < Self::MIN_SIZE {
3278 return Err(ReadError::OutOfBounds);
3279 }
3280 Ok(Self { data })
3281 }
3282}
3283
3284#[derive(Clone)]
3286pub struct ChainedClassSequenceRuleSet<'a> {
3287 data: FontData<'a>,
3288}
3289
3290#[allow(clippy::needless_lifetimes)]
3291impl<'a> ChainedClassSequenceRuleSet<'a> {
3292 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3293 basic_table_impls!(impl_the_methods);
3294
3295 pub fn chained_class_seq_rule_count(&self) -> u16 {
3297 let range = self.chained_class_seq_rule_count_byte_range();
3298 self.data.read_at(range.start).ok().unwrap()
3299 }
3300
3301 pub fn chained_class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
3304 let range = self.chained_class_seq_rule_offsets_byte_range();
3305 self.data.read_array(range).ok().unwrap_or_default()
3306 }
3307
3308 pub fn chained_class_seq_rules(
3310 &self,
3311 ) -> ArrayOfOffsets<'a, ChainedClassSequenceRule<'a>, Offset16> {
3312 let data = self.data;
3313 let offsets = self.chained_class_seq_rule_offsets();
3314 ArrayOfOffsets::new(offsets, data, ())
3315 }
3316
3317 pub fn chained_class_seq_rule_count_byte_range(&self) -> Range<usize> {
3318 let start = 0;
3319 start..start + u16::RAW_BYTE_LEN
3320 }
3321
3322 pub fn chained_class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
3323 let chained_class_seq_rule_count = self.chained_class_seq_rule_count();
3324 let start = self.chained_class_seq_rule_count_byte_range().end;
3325 start
3326 ..start + (chained_class_seq_rule_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
3327 }
3328}
3329
3330#[cfg(feature = "experimental_traverse")]
3331impl<'a> SomeTable<'a> for ChainedClassSequenceRuleSet<'a> {
3332 fn type_name(&self) -> &str {
3333 "ChainedClassSequenceRuleSet"
3334 }
3335 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3336 match idx {
3337 0usize => Some(Field::new(
3338 "chained_class_seq_rule_count",
3339 self.chained_class_seq_rule_count(),
3340 )),
3341 1usize => Some({
3342 let data = self.data;
3343 Field::new(
3344 "chained_class_seq_rule_offsets",
3345 FieldType::array_of_offsets(
3346 better_type_name::<ChainedClassSequenceRule>(),
3347 self.chained_class_seq_rule_offsets(),
3348 move |off| {
3349 let target = off.get().resolve::<ChainedClassSequenceRule>(data);
3350 FieldType::offset(off.get(), target)
3351 },
3352 ),
3353 )
3354 }),
3355 _ => None,
3356 }
3357 }
3358}
3359
3360#[cfg(feature = "experimental_traverse")]
3361#[allow(clippy::needless_lifetimes)]
3362impl<'a> std::fmt::Debug for ChainedClassSequenceRuleSet<'a> {
3363 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3364 (self as &dyn SomeTable<'a>).fmt(f)
3365 }
3366}
3367
3368impl<'a> MinByteRange<'a> for ChainedClassSequenceRule<'a> {
3369 fn min_byte_range(&self) -> Range<usize> {
3370 0..self.seq_lookup_records_byte_range().end
3371 }
3372 fn min_table_bytes(&self) -> &'a [u8] {
3373 let range = self.min_byte_range();
3374 self.data.as_bytes().get(range).unwrap_or_default()
3375 }
3376}
3377
3378impl<'a> FontRead<'a> for ChainedClassSequenceRule<'a> {
3379 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3380 #[allow(clippy::absurd_extreme_comparisons)]
3381 if data.len() < Self::MIN_SIZE {
3382 return Err(ReadError::OutOfBounds);
3383 }
3384 Ok(Self { data })
3385 }
3386}
3387
3388#[derive(Clone)]
3390pub struct ChainedClassSequenceRule<'a> {
3391 data: FontData<'a>,
3392}
3393
3394#[allow(clippy::needless_lifetimes)]
3395impl<'a> ChainedClassSequenceRule<'a> {
3396 pub const MIN_SIZE: usize =
3397 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
3398 basic_table_impls!(impl_the_methods);
3399
3400 pub fn backtrack_glyph_count(&self) -> u16 {
3402 let range = self.backtrack_glyph_count_byte_range();
3403 self.data.read_at(range.start).ok().unwrap()
3404 }
3405
3406 pub fn backtrack_sequence(&self) -> &'a [BigEndian<u16>] {
3408 let range = self.backtrack_sequence_byte_range();
3409 self.data.read_array(range).ok().unwrap_or_default()
3410 }
3411
3412 pub fn input_glyph_count(&self) -> u16 {
3414 let range = self.input_glyph_count_byte_range();
3415 self.data.read_at(range.start).ok().unwrap_or_default()
3416 }
3417
3418 pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
3421 let range = self.input_sequence_byte_range();
3422 self.data.read_array(range).ok().unwrap_or_default()
3423 }
3424
3425 pub fn lookahead_glyph_count(&self) -> u16 {
3427 let range = self.lookahead_glyph_count_byte_range();
3428 self.data.read_at(range.start).ok().unwrap_or_default()
3429 }
3430
3431 pub fn lookahead_sequence(&self) -> &'a [BigEndian<u16>] {
3433 let range = self.lookahead_sequence_byte_range();
3434 self.data.read_array(range).ok().unwrap_or_default()
3435 }
3436
3437 pub fn seq_lookup_count(&self) -> u16 {
3439 let range = self.seq_lookup_count_byte_range();
3440 self.data.read_at(range.start).ok().unwrap_or_default()
3441 }
3442
3443 pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
3445 let range = self.seq_lookup_records_byte_range();
3446 self.data.read_array(range).ok().unwrap_or_default()
3447 }
3448
3449 pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
3450 let start = 0;
3451 start..start + u16::RAW_BYTE_LEN
3452 }
3453
3454 pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
3455 let backtrack_glyph_count = self.backtrack_glyph_count();
3456 let start = self.backtrack_glyph_count_byte_range().end;
3457 start..start + (backtrack_glyph_count as usize).saturating_mul(u16::RAW_BYTE_LEN)
3458 }
3459
3460 pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
3461 let start = self.backtrack_sequence_byte_range().end;
3462 start..start + u16::RAW_BYTE_LEN
3463 }
3464
3465 pub fn input_sequence_byte_range(&self) -> Range<usize> {
3466 let input_glyph_count = self.input_glyph_count();
3467 let start = self.input_glyph_count_byte_range().end;
3468 start
3469 ..start
3470 + (transforms::subtract(input_glyph_count, 1_usize))
3471 .saturating_mul(u16::RAW_BYTE_LEN)
3472 }
3473
3474 pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
3475 let start = self.input_sequence_byte_range().end;
3476 start..start + u16::RAW_BYTE_LEN
3477 }
3478
3479 pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
3480 let lookahead_glyph_count = self.lookahead_glyph_count();
3481 let start = self.lookahead_glyph_count_byte_range().end;
3482 start..start + (lookahead_glyph_count as usize).saturating_mul(u16::RAW_BYTE_LEN)
3483 }
3484
3485 pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
3486 let start = self.lookahead_sequence_byte_range().end;
3487 start..start + u16::RAW_BYTE_LEN
3488 }
3489
3490 pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
3491 let seq_lookup_count = self.seq_lookup_count();
3492 let start = self.seq_lookup_count_byte_range().end;
3493 start
3494 ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
3495 }
3496}
3497
3498#[cfg(feature = "experimental_traverse")]
3499impl<'a> SomeTable<'a> for ChainedClassSequenceRule<'a> {
3500 fn type_name(&self) -> &str {
3501 "ChainedClassSequenceRule"
3502 }
3503 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3504 match idx {
3505 0usize => Some(Field::new(
3506 "backtrack_glyph_count",
3507 self.backtrack_glyph_count(),
3508 )),
3509 1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())),
3510 2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
3511 3usize => Some(Field::new("input_sequence", self.input_sequence())),
3512 4usize => Some(Field::new(
3513 "lookahead_glyph_count",
3514 self.lookahead_glyph_count(),
3515 )),
3516 5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())),
3517 6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
3518 7usize => Some(Field::new(
3519 "seq_lookup_records",
3520 traversal::FieldType::array_of_records(
3521 stringify!(SequenceLookupRecord),
3522 self.seq_lookup_records(),
3523 self.offset_data(),
3524 ),
3525 )),
3526 _ => None,
3527 }
3528 }
3529}
3530
3531#[cfg(feature = "experimental_traverse")]
3532#[allow(clippy::needless_lifetimes)]
3533impl<'a> std::fmt::Debug for ChainedClassSequenceRule<'a> {
3534 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3535 (self as &dyn SomeTable<'a>).fmt(f)
3536 }
3537}
3538
3539impl Format<u16> for ChainedSequenceContextFormat3<'_> {
3540 const FORMAT: u16 = 3;
3541}
3542
3543impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat3<'a> {
3544 fn min_byte_range(&self) -> Range<usize> {
3545 0..self.seq_lookup_records_byte_range().end
3546 }
3547 fn min_table_bytes(&self) -> &'a [u8] {
3548 let range = self.min_byte_range();
3549 self.data.as_bytes().get(range).unwrap_or_default()
3550 }
3551}
3552
3553impl<'a> FontRead<'a> for ChainedSequenceContextFormat3<'a> {
3554 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3555 #[allow(clippy::absurd_extreme_comparisons)]
3556 if data.len() < Self::MIN_SIZE {
3557 return Err(ReadError::OutOfBounds);
3558 }
3559 Ok(Self { data })
3560 }
3561}
3562
3563#[derive(Clone)]
3565pub struct ChainedSequenceContextFormat3<'a> {
3566 data: FontData<'a>,
3567}
3568
3569#[allow(clippy::needless_lifetimes)]
3570impl<'a> ChainedSequenceContextFormat3<'a> {
3571 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3572 + u16::RAW_BYTE_LEN
3573 + u16::RAW_BYTE_LEN
3574 + u16::RAW_BYTE_LEN
3575 + u16::RAW_BYTE_LEN);
3576 basic_table_impls!(impl_the_methods);
3577
3578 pub fn format(&self) -> u16 {
3580 let range = self.format_byte_range();
3581 self.data.read_at(range.start).ok().unwrap()
3582 }
3583
3584 pub fn backtrack_glyph_count(&self) -> u16 {
3586 let range = self.backtrack_glyph_count_byte_range();
3587 self.data.read_at(range.start).ok().unwrap()
3588 }
3589
3590 pub fn backtrack_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3592 let range = self.backtrack_coverage_offsets_byte_range();
3593 self.data.read_array(range).ok().unwrap_or_default()
3594 }
3595
3596 pub fn backtrack_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3598 let data = self.data;
3599 let offsets = self.backtrack_coverage_offsets();
3600 ArrayOfOffsets::new(offsets, data, ())
3601 }
3602
3603 pub fn input_glyph_count(&self) -> u16 {
3605 let range = self.input_glyph_count_byte_range();
3606 self.data.read_at(range.start).ok().unwrap_or_default()
3607 }
3608
3609 pub fn input_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3611 let range = self.input_coverage_offsets_byte_range();
3612 self.data.read_array(range).ok().unwrap_or_default()
3613 }
3614
3615 pub fn input_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3617 let data = self.data;
3618 let offsets = self.input_coverage_offsets();
3619 ArrayOfOffsets::new(offsets, data, ())
3620 }
3621
3622 pub fn lookahead_glyph_count(&self) -> u16 {
3624 let range = self.lookahead_glyph_count_byte_range();
3625 self.data.read_at(range.start).ok().unwrap_or_default()
3626 }
3627
3628 pub fn lookahead_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3630 let range = self.lookahead_coverage_offsets_byte_range();
3631 self.data.read_array(range).ok().unwrap_or_default()
3632 }
3633
3634 pub fn lookahead_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3636 let data = self.data;
3637 let offsets = self.lookahead_coverage_offsets();
3638 ArrayOfOffsets::new(offsets, data, ())
3639 }
3640
3641 pub fn seq_lookup_count(&self) -> u16 {
3643 let range = self.seq_lookup_count_byte_range();
3644 self.data.read_at(range.start).ok().unwrap_or_default()
3645 }
3646
3647 pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
3649 let range = self.seq_lookup_records_byte_range();
3650 self.data.read_array(range).ok().unwrap_or_default()
3651 }
3652
3653 pub fn format_byte_range(&self) -> Range<usize> {
3654 let start = 0;
3655 start..start + u16::RAW_BYTE_LEN
3656 }
3657
3658 pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
3659 let start = self.format_byte_range().end;
3660 start..start + u16::RAW_BYTE_LEN
3661 }
3662
3663 pub fn backtrack_coverage_offsets_byte_range(&self) -> Range<usize> {
3664 let backtrack_glyph_count = self.backtrack_glyph_count();
3665 let start = self.backtrack_glyph_count_byte_range().end;
3666 start..start + (backtrack_glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
3667 }
3668
3669 pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
3670 let start = self.backtrack_coverage_offsets_byte_range().end;
3671 start..start + u16::RAW_BYTE_LEN
3672 }
3673
3674 pub fn input_coverage_offsets_byte_range(&self) -> Range<usize> {
3675 let input_glyph_count = self.input_glyph_count();
3676 let start = self.input_glyph_count_byte_range().end;
3677 start..start + (input_glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
3678 }
3679
3680 pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
3681 let start = self.input_coverage_offsets_byte_range().end;
3682 start..start + u16::RAW_BYTE_LEN
3683 }
3684
3685 pub fn lookahead_coverage_offsets_byte_range(&self) -> Range<usize> {
3686 let lookahead_glyph_count = self.lookahead_glyph_count();
3687 let start = self.lookahead_glyph_count_byte_range().end;
3688 start..start + (lookahead_glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
3689 }
3690
3691 pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
3692 let start = self.lookahead_coverage_offsets_byte_range().end;
3693 start..start + u16::RAW_BYTE_LEN
3694 }
3695
3696 pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
3697 let seq_lookup_count = self.seq_lookup_count();
3698 let start = self.seq_lookup_count_byte_range().end;
3699 start
3700 ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
3701 }
3702}
3703
3704#[cfg(feature = "experimental_traverse")]
3705impl<'a> SomeTable<'a> for ChainedSequenceContextFormat3<'a> {
3706 fn type_name(&self) -> &str {
3707 "ChainedSequenceContextFormat3"
3708 }
3709 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3710 match idx {
3711 0usize => Some(Field::new("format", self.format())),
3712 1usize => Some(Field::new(
3713 "backtrack_glyph_count",
3714 self.backtrack_glyph_count(),
3715 )),
3716 2usize => Some({
3717 let data = self.data;
3718 Field::new(
3719 "backtrack_coverage_offsets",
3720 FieldType::array_of_offsets(
3721 better_type_name::<CoverageTable>(),
3722 self.backtrack_coverage_offsets(),
3723 move |off| {
3724 let target = off.get().resolve::<CoverageTable>(data);
3725 FieldType::offset(off.get(), target)
3726 },
3727 ),
3728 )
3729 }),
3730 3usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
3731 4usize => Some({
3732 let data = self.data;
3733 Field::new(
3734 "input_coverage_offsets",
3735 FieldType::array_of_offsets(
3736 better_type_name::<CoverageTable>(),
3737 self.input_coverage_offsets(),
3738 move |off| {
3739 let target = off.get().resolve::<CoverageTable>(data);
3740 FieldType::offset(off.get(), target)
3741 },
3742 ),
3743 )
3744 }),
3745 5usize => Some(Field::new(
3746 "lookahead_glyph_count",
3747 self.lookahead_glyph_count(),
3748 )),
3749 6usize => Some({
3750 let data = self.data;
3751 Field::new(
3752 "lookahead_coverage_offsets",
3753 FieldType::array_of_offsets(
3754 better_type_name::<CoverageTable>(),
3755 self.lookahead_coverage_offsets(),
3756 move |off| {
3757 let target = off.get().resolve::<CoverageTable>(data);
3758 FieldType::offset(off.get(), target)
3759 },
3760 ),
3761 )
3762 }),
3763 7usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
3764 8usize => Some(Field::new(
3765 "seq_lookup_records",
3766 traversal::FieldType::array_of_records(
3767 stringify!(SequenceLookupRecord),
3768 self.seq_lookup_records(),
3769 self.offset_data(),
3770 ),
3771 )),
3772 _ => None,
3773 }
3774 }
3775}
3776
3777#[cfg(feature = "experimental_traverse")]
3778#[allow(clippy::needless_lifetimes)]
3779impl<'a> std::fmt::Debug for ChainedSequenceContextFormat3<'a> {
3780 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3781 (self as &dyn SomeTable<'a>).fmt(f)
3782 }
3783}
3784
3785#[derive(Clone)]
3786pub enum ChainedSequenceContext<'a> {
3787 Format1(ChainedSequenceContextFormat1<'a>),
3788 Format2(ChainedSequenceContextFormat2<'a>),
3789 Format3(ChainedSequenceContextFormat3<'a>),
3790}
3791
3792impl<'a> ChainedSequenceContext<'a> {
3793 pub fn offset_data(&self) -> FontData<'a> {
3795 match self {
3796 Self::Format1(item) => item.offset_data(),
3797 Self::Format2(item) => item.offset_data(),
3798 Self::Format3(item) => item.offset_data(),
3799 }
3800 }
3801
3802 pub fn format(&self) -> u16 {
3804 match self {
3805 Self::Format1(item) => item.format(),
3806 Self::Format2(item) => item.format(),
3807 Self::Format3(item) => item.format(),
3808 }
3809 }
3810}
3811
3812impl<'a> FontRead<'a> for ChainedSequenceContext<'a> {
3813 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3814 let format: u16 = data.read_at(0usize)?;
3815 match format {
3816 ChainedSequenceContextFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
3817 ChainedSequenceContextFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
3818 ChainedSequenceContextFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
3819 other => Err(ReadError::InvalidFormat(other.into())),
3820 }
3821 }
3822}
3823
3824impl<'a> MinByteRange<'a> for ChainedSequenceContext<'a> {
3825 fn min_byte_range(&self) -> Range<usize> {
3826 match self {
3827 Self::Format1(item) => item.min_byte_range(),
3828 Self::Format2(item) => item.min_byte_range(),
3829 Self::Format3(item) => item.min_byte_range(),
3830 }
3831 }
3832 fn min_table_bytes(&self) -> &'a [u8] {
3833 match self {
3834 Self::Format1(item) => item.min_table_bytes(),
3835 Self::Format2(item) => item.min_table_bytes(),
3836 Self::Format3(item) => item.min_table_bytes(),
3837 }
3838 }
3839}
3840
3841#[cfg(feature = "experimental_traverse")]
3842impl<'a> ChainedSequenceContext<'a> {
3843 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
3844 match self {
3845 Self::Format1(table) => table,
3846 Self::Format2(table) => table,
3847 Self::Format3(table) => table,
3848 }
3849 }
3850}
3851
3852#[cfg(feature = "experimental_traverse")]
3853impl std::fmt::Debug for ChainedSequenceContext<'_> {
3854 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3855 self.dyn_inner().fmt(f)
3856 }
3857}
3858
3859#[cfg(feature = "experimental_traverse")]
3860impl<'a> SomeTable<'a> for ChainedSequenceContext<'a> {
3861 fn type_name(&self) -> &str {
3862 self.dyn_inner().type_name()
3863 }
3864 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3865 self.dyn_inner().get_field(idx)
3866 }
3867}
3868
3869#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
3872#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3873#[repr(u16)]
3874#[allow(clippy::manual_non_exhaustive)]
3875pub enum DeltaFormat {
3876 #[default]
3878 Local2BitDeltas = 0x0001,
3879 Local4BitDeltas = 0x0002,
3881 Local8BitDeltas = 0x0003,
3883 VariationIndex = 0x8000,
3885 #[doc(hidden)]
3886 Unknown,
3888}
3889
3890impl DeltaFormat {
3891 pub fn new(raw: u16) -> Self {
3895 match raw {
3896 0x0001 => Self::Local2BitDeltas,
3897 0x0002 => Self::Local4BitDeltas,
3898 0x0003 => Self::Local8BitDeltas,
3899 0x8000 => Self::VariationIndex,
3900 _ => Self::Unknown,
3901 }
3902 }
3903}
3904
3905impl font_types::Scalar for DeltaFormat {
3906 type Raw = <u16 as font_types::Scalar>::Raw;
3907 fn to_raw(self) -> Self::Raw {
3908 (self as u16).to_raw()
3909 }
3910 fn from_raw(raw: Self::Raw) -> Self {
3911 let t = <u16>::from_raw(raw);
3912 Self::new(t)
3913 }
3914}
3915
3916#[cfg(feature = "experimental_traverse")]
3917impl<'a> From<DeltaFormat> for FieldType<'a> {
3918 fn from(src: DeltaFormat) -> FieldType<'a> {
3919 (src as u16).into()
3920 }
3921}
3922
3923impl<'a> MinByteRange<'a> for Device<'a> {
3924 fn min_byte_range(&self) -> Range<usize> {
3925 0..self.delta_value_byte_range().end
3926 }
3927 fn min_table_bytes(&self) -> &'a [u8] {
3928 let range = self.min_byte_range();
3929 self.data.as_bytes().get(range).unwrap_or_default()
3930 }
3931}
3932
3933impl<'a> FontRead<'a> for Device<'a> {
3934 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3935 #[allow(clippy::absurd_extreme_comparisons)]
3936 if data.len() < Self::MIN_SIZE {
3937 return Err(ReadError::OutOfBounds);
3938 }
3939 Ok(Self { data })
3940 }
3941}
3942
3943#[derive(Clone)]
3945pub struct Device<'a> {
3946 data: FontData<'a>,
3947}
3948
3949#[allow(clippy::needless_lifetimes)]
3950impl<'a> Device<'a> {
3951 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + DeltaFormat::RAW_BYTE_LEN);
3952 basic_table_impls!(impl_the_methods);
3953
3954 pub fn start_size(&self) -> u16 {
3956 let range = self.start_size_byte_range();
3957 self.data.read_at(range.start).ok().unwrap()
3958 }
3959
3960 pub fn end_size(&self) -> u16 {
3962 let range = self.end_size_byte_range();
3963 self.data.read_at(range.start).ok().unwrap()
3964 }
3965
3966 pub fn delta_format(&self) -> DeltaFormat {
3968 let range = self.delta_format_byte_range();
3969 self.data.read_at(range.start).ok().unwrap()
3970 }
3971
3972 pub fn delta_value(&self) -> &'a [BigEndian<u16>] {
3974 let range = self.delta_value_byte_range();
3975 self.data.read_array(range).ok().unwrap_or_default()
3976 }
3977
3978 pub fn start_size_byte_range(&self) -> Range<usize> {
3979 let start = 0;
3980 start..start + u16::RAW_BYTE_LEN
3981 }
3982
3983 pub fn end_size_byte_range(&self) -> Range<usize> {
3984 let start = self.start_size_byte_range().end;
3985 start..start + u16::RAW_BYTE_LEN
3986 }
3987
3988 pub fn delta_format_byte_range(&self) -> Range<usize> {
3989 let start = self.end_size_byte_range().end;
3990 start..start + DeltaFormat::RAW_BYTE_LEN
3991 }
3992
3993 pub fn delta_value_byte_range(&self) -> Range<usize> {
3994 let delta_format = self.delta_format();
3995 let start_size = self.start_size();
3996 let end_size = self.end_size();
3997 let start = self.delta_format_byte_range().end;
3998 start
3999 ..start
4000 + (DeltaFormat::value_count(delta_format, start_size, end_size))
4001 .saturating_mul(u16::RAW_BYTE_LEN)
4002 }
4003}
4004
4005#[cfg(feature = "experimental_traverse")]
4006impl<'a> SomeTable<'a> for Device<'a> {
4007 fn type_name(&self) -> &str {
4008 "Device"
4009 }
4010 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4011 match idx {
4012 0usize => Some(Field::new("start_size", self.start_size())),
4013 1usize => Some(Field::new("end_size", self.end_size())),
4014 2usize => Some(Field::new("delta_format", self.delta_format())),
4015 3usize => Some(Field::new("delta_value", self.delta_value())),
4016 _ => None,
4017 }
4018 }
4019}
4020
4021#[cfg(feature = "experimental_traverse")]
4022#[allow(clippy::needless_lifetimes)]
4023impl<'a> std::fmt::Debug for Device<'a> {
4024 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4025 (self as &dyn SomeTable<'a>).fmt(f)
4026 }
4027}
4028
4029impl<'a> MinByteRange<'a> for VariationIndex<'a> {
4030 fn min_byte_range(&self) -> Range<usize> {
4031 0..self.delta_format_byte_range().end
4032 }
4033 fn min_table_bytes(&self) -> &'a [u8] {
4034 let range = self.min_byte_range();
4035 self.data.as_bytes().get(range).unwrap_or_default()
4036 }
4037}
4038
4039impl<'a> FontRead<'a> for VariationIndex<'a> {
4040 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4041 #[allow(clippy::absurd_extreme_comparisons)]
4042 if data.len() < Self::MIN_SIZE {
4043 return Err(ReadError::OutOfBounds);
4044 }
4045 Ok(Self { data })
4046 }
4047}
4048
4049#[derive(Clone)]
4051pub struct VariationIndex<'a> {
4052 data: FontData<'a>,
4053}
4054
4055#[allow(clippy::needless_lifetimes)]
4056impl<'a> VariationIndex<'a> {
4057 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + DeltaFormat::RAW_BYTE_LEN);
4058 basic_table_impls!(impl_the_methods);
4059
4060 pub fn delta_set_outer_index(&self) -> u16 {
4063 let range = self.delta_set_outer_index_byte_range();
4064 self.data.read_at(range.start).ok().unwrap()
4065 }
4066
4067 pub fn delta_set_inner_index(&self) -> u16 {
4070 let range = self.delta_set_inner_index_byte_range();
4071 self.data.read_at(range.start).ok().unwrap()
4072 }
4073
4074 pub fn delta_format(&self) -> DeltaFormat {
4076 let range = self.delta_format_byte_range();
4077 self.data.read_at(range.start).ok().unwrap()
4078 }
4079
4080 pub fn delta_set_outer_index_byte_range(&self) -> Range<usize> {
4081 let start = 0;
4082 start..start + u16::RAW_BYTE_LEN
4083 }
4084
4085 pub fn delta_set_inner_index_byte_range(&self) -> Range<usize> {
4086 let start = self.delta_set_outer_index_byte_range().end;
4087 start..start + u16::RAW_BYTE_LEN
4088 }
4089
4090 pub fn delta_format_byte_range(&self) -> Range<usize> {
4091 let start = self.delta_set_inner_index_byte_range().end;
4092 start..start + DeltaFormat::RAW_BYTE_LEN
4093 }
4094}
4095
4096#[cfg(feature = "experimental_traverse")]
4097impl<'a> SomeTable<'a> for VariationIndex<'a> {
4098 fn type_name(&self) -> &str {
4099 "VariationIndex"
4100 }
4101 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4102 match idx {
4103 0usize => Some(Field::new(
4104 "delta_set_outer_index",
4105 self.delta_set_outer_index(),
4106 )),
4107 1usize => Some(Field::new(
4108 "delta_set_inner_index",
4109 self.delta_set_inner_index(),
4110 )),
4111 2usize => Some(Field::new("delta_format", self.delta_format())),
4112 _ => None,
4113 }
4114 }
4115}
4116
4117#[cfg(feature = "experimental_traverse")]
4118#[allow(clippy::needless_lifetimes)]
4119impl<'a> std::fmt::Debug for VariationIndex<'a> {
4120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4121 (self as &dyn SomeTable<'a>).fmt(f)
4122 }
4123}
4124
4125#[derive(Clone)]
4127pub enum DeviceOrVariationIndex<'a> {
4128 Device(Device<'a>),
4129 VariationIndex(VariationIndex<'a>),
4130}
4131
4132impl<'a> DeviceOrVariationIndex<'a> {
4133 pub fn offset_data(&self) -> FontData<'a> {
4135 match self {
4136 Self::Device(item) => item.offset_data(),
4137 Self::VariationIndex(item) => item.offset_data(),
4138 }
4139 }
4140}
4141
4142impl<'a> FontRead<'a> for DeviceOrVariationIndex<'a> {
4143 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4144 let format: DeltaFormat = data.read_at(4usize)?;
4145
4146 #[allow(clippy::redundant_guards)]
4147 match format {
4148 format if format != DeltaFormat::VariationIndex => {
4149 Ok(Self::Device(FontRead::read(data)?))
4150 }
4151 format if format == DeltaFormat::VariationIndex => {
4152 Ok(Self::VariationIndex(FontRead::read(data)?))
4153 }
4154 other => Err(ReadError::InvalidFormat(other.into())),
4155 }
4156 }
4157}
4158
4159impl<'a> MinByteRange<'a> for DeviceOrVariationIndex<'a> {
4160 fn min_byte_range(&self) -> Range<usize> {
4161 match self {
4162 Self::Device(item) => item.min_byte_range(),
4163 Self::VariationIndex(item) => item.min_byte_range(),
4164 }
4165 }
4166 fn min_table_bytes(&self) -> &'a [u8] {
4167 match self {
4168 Self::Device(item) => item.min_table_bytes(),
4169 Self::VariationIndex(item) => item.min_table_bytes(),
4170 }
4171 }
4172}
4173
4174#[cfg(feature = "experimental_traverse")]
4175impl<'a> DeviceOrVariationIndex<'a> {
4176 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
4177 match self {
4178 Self::Device(table) => table,
4179 Self::VariationIndex(table) => table,
4180 }
4181 }
4182}
4183
4184#[cfg(feature = "experimental_traverse")]
4185impl std::fmt::Debug for DeviceOrVariationIndex<'_> {
4186 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4187 self.dyn_inner().fmt(f)
4188 }
4189}
4190
4191#[cfg(feature = "experimental_traverse")]
4192impl<'a> SomeTable<'a> for DeviceOrVariationIndex<'a> {
4193 fn type_name(&self) -> &str {
4194 self.dyn_inner().type_name()
4195 }
4196 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4197 self.dyn_inner().get_field(idx)
4198 }
4199}
4200
4201impl<'a> MinByteRange<'a> for FeatureVariations<'a> {
4202 fn min_byte_range(&self) -> Range<usize> {
4203 0..self.feature_variation_records_byte_range().end
4204 }
4205 fn min_table_bytes(&self) -> &'a [u8] {
4206 let range = self.min_byte_range();
4207 self.data.as_bytes().get(range).unwrap_or_default()
4208 }
4209}
4210
4211impl<'a> FontRead<'a> for FeatureVariations<'a> {
4212 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4213 #[allow(clippy::absurd_extreme_comparisons)]
4214 if data.len() < Self::MIN_SIZE {
4215 return Err(ReadError::OutOfBounds);
4216 }
4217 Ok(Self { data })
4218 }
4219}
4220
4221#[derive(Clone)]
4223pub struct FeatureVariations<'a> {
4224 data: FontData<'a>,
4225}
4226
4227#[allow(clippy::needless_lifetimes)]
4228impl<'a> FeatureVariations<'a> {
4229 pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
4230 basic_table_impls!(impl_the_methods);
4231
4232 pub fn version(&self) -> MajorMinor {
4233 let range = self.version_byte_range();
4234 self.data.read_at(range.start).ok().unwrap()
4235 }
4236
4237 pub fn feature_variation_record_count(&self) -> u32 {
4239 let range = self.feature_variation_record_count_byte_range();
4240 self.data.read_at(range.start).ok().unwrap()
4241 }
4242
4243 pub fn feature_variation_records(&self) -> &'a [FeatureVariationRecord] {
4245 let range = self.feature_variation_records_byte_range();
4246 self.data.read_array(range).ok().unwrap_or_default()
4247 }
4248
4249 pub fn version_byte_range(&self) -> Range<usize> {
4250 let start = 0;
4251 start..start + MajorMinor::RAW_BYTE_LEN
4252 }
4253
4254 pub fn feature_variation_record_count_byte_range(&self) -> Range<usize> {
4255 let start = self.version_byte_range().end;
4256 start..start + u32::RAW_BYTE_LEN
4257 }
4258
4259 pub fn feature_variation_records_byte_range(&self) -> Range<usize> {
4260 let feature_variation_record_count = self.feature_variation_record_count();
4261 let start = self.feature_variation_record_count_byte_range().end;
4262 start
4263 ..start
4264 + (feature_variation_record_count as usize)
4265 .saturating_mul(FeatureVariationRecord::RAW_BYTE_LEN)
4266 }
4267}
4268
4269#[cfg(feature = "experimental_traverse")]
4270impl<'a> SomeTable<'a> for FeatureVariations<'a> {
4271 fn type_name(&self) -> &str {
4272 "FeatureVariations"
4273 }
4274 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4275 match idx {
4276 0usize => Some(Field::new("version", self.version())),
4277 1usize => Some(Field::new(
4278 "feature_variation_record_count",
4279 self.feature_variation_record_count(),
4280 )),
4281 2usize => Some(Field::new(
4282 "feature_variation_records",
4283 traversal::FieldType::array_of_records(
4284 stringify!(FeatureVariationRecord),
4285 self.feature_variation_records(),
4286 self.offset_data(),
4287 ),
4288 )),
4289 _ => None,
4290 }
4291 }
4292}
4293
4294#[cfg(feature = "experimental_traverse")]
4295#[allow(clippy::needless_lifetimes)]
4296impl<'a> std::fmt::Debug for FeatureVariations<'a> {
4297 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4298 (self as &dyn SomeTable<'a>).fmt(f)
4299 }
4300}
4301
4302#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
4304#[repr(C)]
4305#[repr(packed)]
4306pub struct FeatureVariationRecord {
4307 pub condition_set_offset: BigEndian<Nullable<Offset32>>,
4310 pub feature_table_substitution_offset: BigEndian<Nullable<Offset32>>,
4313}
4314
4315impl FeatureVariationRecord {
4316 pub fn condition_set_offset(&self) -> Nullable<Offset32> {
4319 self.condition_set_offset.get()
4320 }
4321
4322 pub fn condition_set<'a>(
4328 &self,
4329 data: FontData<'a>,
4330 ) -> Option<Result<ConditionSet<'a>, ReadError>> {
4331 self.condition_set_offset().resolve(data)
4332 }
4333
4334 pub fn feature_table_substitution_offset(&self) -> Nullable<Offset32> {
4337 self.feature_table_substitution_offset.get()
4338 }
4339
4340 pub fn feature_table_substitution<'a>(
4346 &self,
4347 data: FontData<'a>,
4348 ) -> Option<Result<FeatureTableSubstitution<'a>, ReadError>> {
4349 self.feature_table_substitution_offset().resolve(data)
4350 }
4351}
4352
4353impl FixedSize for FeatureVariationRecord {
4354 const RAW_BYTE_LEN: usize = Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
4355}
4356
4357#[cfg(feature = "experimental_traverse")]
4358impl<'a> SomeRecord<'a> for FeatureVariationRecord {
4359 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
4360 RecordResolver {
4361 name: "FeatureVariationRecord",
4362 get_field: Box::new(move |idx, _data| match idx {
4363 0usize => Some(Field::new(
4364 "condition_set_offset",
4365 FieldType::offset(self.condition_set_offset(), self.condition_set(_data)),
4366 )),
4367 1usize => Some(Field::new(
4368 "feature_table_substitution_offset",
4369 FieldType::offset(
4370 self.feature_table_substitution_offset(),
4371 self.feature_table_substitution(_data),
4372 ),
4373 )),
4374 _ => None,
4375 }),
4376 data,
4377 }
4378 }
4379}
4380
4381impl<'a> MinByteRange<'a> for ConditionSet<'a> {
4382 fn min_byte_range(&self) -> Range<usize> {
4383 0..self.condition_offsets_byte_range().end
4384 }
4385 fn min_table_bytes(&self) -> &'a [u8] {
4386 let range = self.min_byte_range();
4387 self.data.as_bytes().get(range).unwrap_or_default()
4388 }
4389}
4390
4391impl<'a> FontRead<'a> for ConditionSet<'a> {
4392 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4393 #[allow(clippy::absurd_extreme_comparisons)]
4394 if data.len() < Self::MIN_SIZE {
4395 return Err(ReadError::OutOfBounds);
4396 }
4397 Ok(Self { data })
4398 }
4399}
4400
4401#[derive(Clone)]
4403pub struct ConditionSet<'a> {
4404 data: FontData<'a>,
4405}
4406
4407#[allow(clippy::needless_lifetimes)]
4408impl<'a> ConditionSet<'a> {
4409 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
4410 basic_table_impls!(impl_the_methods);
4411
4412 pub fn condition_count(&self) -> u16 {
4414 let range = self.condition_count_byte_range();
4415 self.data.read_at(range.start).ok().unwrap()
4416 }
4417
4418 pub fn condition_offsets(&self) -> &'a [BigEndian<Offset32>] {
4421 let range = self.condition_offsets_byte_range();
4422 self.data.read_array(range).ok().unwrap_or_default()
4423 }
4424
4425 pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset32> {
4427 let data = self.data;
4428 let offsets = self.condition_offsets();
4429 ArrayOfOffsets::new(offsets, data, ())
4430 }
4431
4432 pub fn condition_count_byte_range(&self) -> Range<usize> {
4433 let start = 0;
4434 start..start + u16::RAW_BYTE_LEN
4435 }
4436
4437 pub fn condition_offsets_byte_range(&self) -> Range<usize> {
4438 let condition_count = self.condition_count();
4439 let start = self.condition_count_byte_range().end;
4440 start..start + (condition_count as usize).saturating_mul(Offset32::RAW_BYTE_LEN)
4441 }
4442}
4443
4444#[cfg(feature = "experimental_traverse")]
4445impl<'a> SomeTable<'a> for ConditionSet<'a> {
4446 fn type_name(&self) -> &str {
4447 "ConditionSet"
4448 }
4449 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4450 match idx {
4451 0usize => Some(Field::new("condition_count", self.condition_count())),
4452 1usize => Some({
4453 let data = self.data;
4454 Field::new(
4455 "condition_offsets",
4456 FieldType::array_of_offsets(
4457 better_type_name::<Condition>(),
4458 self.condition_offsets(),
4459 move |off| {
4460 let target = off.get().resolve::<Condition>(data);
4461 FieldType::offset(off.get(), target)
4462 },
4463 ),
4464 )
4465 }),
4466 _ => None,
4467 }
4468 }
4469}
4470
4471#[cfg(feature = "experimental_traverse")]
4472#[allow(clippy::needless_lifetimes)]
4473impl<'a> std::fmt::Debug for ConditionSet<'a> {
4474 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4475 (self as &dyn SomeTable<'a>).fmt(f)
4476 }
4477}
4478
4479#[derive(Clone)]
4484pub enum Condition<'a> {
4485 Format1AxisRange(ConditionFormat1<'a>),
4486 Format2VariableValue(ConditionFormat2<'a>),
4487 Format3And(ConditionFormat3<'a>),
4488 Format4Or(ConditionFormat4<'a>),
4489 Format5Negate(ConditionFormat5<'a>),
4490}
4491
4492impl<'a> Condition<'a> {
4493 pub fn offset_data(&self) -> FontData<'a> {
4495 match self {
4496 Self::Format1AxisRange(item) => item.offset_data(),
4497 Self::Format2VariableValue(item) => item.offset_data(),
4498 Self::Format3And(item) => item.offset_data(),
4499 Self::Format4Or(item) => item.offset_data(),
4500 Self::Format5Negate(item) => item.offset_data(),
4501 }
4502 }
4503
4504 pub fn format(&self) -> u16 {
4506 match self {
4507 Self::Format1AxisRange(item) => item.format(),
4508 Self::Format2VariableValue(item) => item.format(),
4509 Self::Format3And(item) => item.format(),
4510 Self::Format4Or(item) => item.format(),
4511 Self::Format5Negate(item) => item.format(),
4512 }
4513 }
4514}
4515
4516impl<'a> FontRead<'a> for Condition<'a> {
4517 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4518 let format: u16 = data.read_at(0usize)?;
4519 match format {
4520 ConditionFormat1::FORMAT => Ok(Self::Format1AxisRange(FontRead::read(data)?)),
4521 ConditionFormat2::FORMAT => Ok(Self::Format2VariableValue(FontRead::read(data)?)),
4522 ConditionFormat3::FORMAT => Ok(Self::Format3And(FontRead::read(data)?)),
4523 ConditionFormat4::FORMAT => Ok(Self::Format4Or(FontRead::read(data)?)),
4524 ConditionFormat5::FORMAT => Ok(Self::Format5Negate(FontRead::read(data)?)),
4525 other => Err(ReadError::InvalidFormat(other.into())),
4526 }
4527 }
4528}
4529
4530impl<'a> MinByteRange<'a> for Condition<'a> {
4531 fn min_byte_range(&self) -> Range<usize> {
4532 match self {
4533 Self::Format1AxisRange(item) => item.min_byte_range(),
4534 Self::Format2VariableValue(item) => item.min_byte_range(),
4535 Self::Format3And(item) => item.min_byte_range(),
4536 Self::Format4Or(item) => item.min_byte_range(),
4537 Self::Format5Negate(item) => item.min_byte_range(),
4538 }
4539 }
4540 fn min_table_bytes(&self) -> &'a [u8] {
4541 match self {
4542 Self::Format1AxisRange(item) => item.min_table_bytes(),
4543 Self::Format2VariableValue(item) => item.min_table_bytes(),
4544 Self::Format3And(item) => item.min_table_bytes(),
4545 Self::Format4Or(item) => item.min_table_bytes(),
4546 Self::Format5Negate(item) => item.min_table_bytes(),
4547 }
4548 }
4549}
4550
4551#[cfg(feature = "experimental_traverse")]
4552impl<'a> Condition<'a> {
4553 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
4554 match self {
4555 Self::Format1AxisRange(table) => table,
4556 Self::Format2VariableValue(table) => table,
4557 Self::Format3And(table) => table,
4558 Self::Format4Or(table) => table,
4559 Self::Format5Negate(table) => table,
4560 }
4561 }
4562}
4563
4564#[cfg(feature = "experimental_traverse")]
4565impl std::fmt::Debug for Condition<'_> {
4566 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4567 self.dyn_inner().fmt(f)
4568 }
4569}
4570
4571#[cfg(feature = "experimental_traverse")]
4572impl<'a> SomeTable<'a> for Condition<'a> {
4573 fn type_name(&self) -> &str {
4574 self.dyn_inner().type_name()
4575 }
4576 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4577 self.dyn_inner().get_field(idx)
4578 }
4579}
4580
4581impl Format<u16> for ConditionFormat1<'_> {
4582 const FORMAT: u16 = 1;
4583}
4584
4585impl<'a> MinByteRange<'a> for ConditionFormat1<'a> {
4586 fn min_byte_range(&self) -> Range<usize> {
4587 0..self.filter_range_max_value_byte_range().end
4588 }
4589 fn min_table_bytes(&self) -> &'a [u8] {
4590 let range = self.min_byte_range();
4591 self.data.as_bytes().get(range).unwrap_or_default()
4592 }
4593}
4594
4595impl<'a> FontRead<'a> for ConditionFormat1<'a> {
4596 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4597 #[allow(clippy::absurd_extreme_comparisons)]
4598 if data.len() < Self::MIN_SIZE {
4599 return Err(ReadError::OutOfBounds);
4600 }
4601 Ok(Self { data })
4602 }
4603}
4604
4605#[derive(Clone)]
4607pub struct ConditionFormat1<'a> {
4608 data: FontData<'a>,
4609}
4610
4611#[allow(clippy::needless_lifetimes)]
4612impl<'a> ConditionFormat1<'a> {
4613 pub const MIN_SIZE: usize =
4614 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN);
4615 basic_table_impls!(impl_the_methods);
4616
4617 pub fn format(&self) -> u16 {
4619 let range = self.format_byte_range();
4620 self.data.read_at(range.start).ok().unwrap()
4621 }
4622
4623 pub fn axis_index(&self) -> u16 {
4626 let range = self.axis_index_byte_range();
4627 self.data.read_at(range.start).ok().unwrap()
4628 }
4629
4630 pub fn filter_range_min_value(&self) -> F2Dot14 {
4633 let range = self.filter_range_min_value_byte_range();
4634 self.data.read_at(range.start).ok().unwrap()
4635 }
4636
4637 pub fn filter_range_max_value(&self) -> F2Dot14 {
4640 let range = self.filter_range_max_value_byte_range();
4641 self.data.read_at(range.start).ok().unwrap()
4642 }
4643
4644 pub fn format_byte_range(&self) -> Range<usize> {
4645 let start = 0;
4646 start..start + u16::RAW_BYTE_LEN
4647 }
4648
4649 pub fn axis_index_byte_range(&self) -> Range<usize> {
4650 let start = self.format_byte_range().end;
4651 start..start + u16::RAW_BYTE_LEN
4652 }
4653
4654 pub fn filter_range_min_value_byte_range(&self) -> Range<usize> {
4655 let start = self.axis_index_byte_range().end;
4656 start..start + F2Dot14::RAW_BYTE_LEN
4657 }
4658
4659 pub fn filter_range_max_value_byte_range(&self) -> Range<usize> {
4660 let start = self.filter_range_min_value_byte_range().end;
4661 start..start + F2Dot14::RAW_BYTE_LEN
4662 }
4663}
4664
4665#[cfg(feature = "experimental_traverse")]
4666impl<'a> SomeTable<'a> for ConditionFormat1<'a> {
4667 fn type_name(&self) -> &str {
4668 "ConditionFormat1"
4669 }
4670 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4671 match idx {
4672 0usize => Some(Field::new("format", self.format())),
4673 1usize => Some(Field::new("axis_index", self.axis_index())),
4674 2usize => Some(Field::new(
4675 "filter_range_min_value",
4676 self.filter_range_min_value(),
4677 )),
4678 3usize => Some(Field::new(
4679 "filter_range_max_value",
4680 self.filter_range_max_value(),
4681 )),
4682 _ => None,
4683 }
4684 }
4685}
4686
4687#[cfg(feature = "experimental_traverse")]
4688#[allow(clippy::needless_lifetimes)]
4689impl<'a> std::fmt::Debug for ConditionFormat1<'a> {
4690 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4691 (self as &dyn SomeTable<'a>).fmt(f)
4692 }
4693}
4694
4695impl Format<u16> for ConditionFormat2<'_> {
4696 const FORMAT: u16 = 2;
4697}
4698
4699impl<'a> MinByteRange<'a> for ConditionFormat2<'a> {
4700 fn min_byte_range(&self) -> Range<usize> {
4701 0..self.var_index_byte_range().end
4702 }
4703 fn min_table_bytes(&self) -> &'a [u8] {
4704 let range = self.min_byte_range();
4705 self.data.as_bytes().get(range).unwrap_or_default()
4706 }
4707}
4708
4709impl<'a> FontRead<'a> for ConditionFormat2<'a> {
4710 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4711 #[allow(clippy::absurd_extreme_comparisons)]
4712 if data.len() < Self::MIN_SIZE {
4713 return Err(ReadError::OutOfBounds);
4714 }
4715 Ok(Self { data })
4716 }
4717}
4718
4719#[derive(Clone)]
4721pub struct ConditionFormat2<'a> {
4722 data: FontData<'a>,
4723}
4724
4725#[allow(clippy::needless_lifetimes)]
4726impl<'a> ConditionFormat2<'a> {
4727 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
4728 basic_table_impls!(impl_the_methods);
4729
4730 pub fn format(&self) -> u16 {
4732 let range = self.format_byte_range();
4733 self.data.read_at(range.start).ok().unwrap()
4734 }
4735
4736 pub fn default_value(&self) -> i16 {
4738 let range = self.default_value_byte_range();
4739 self.data.read_at(range.start).ok().unwrap()
4740 }
4741
4742 pub fn var_index(&self) -> u32 {
4744 let range = self.var_index_byte_range();
4745 self.data.read_at(range.start).ok().unwrap()
4746 }
4747
4748 pub fn format_byte_range(&self) -> Range<usize> {
4749 let start = 0;
4750 start..start + u16::RAW_BYTE_LEN
4751 }
4752
4753 pub fn default_value_byte_range(&self) -> Range<usize> {
4754 let start = self.format_byte_range().end;
4755 start..start + i16::RAW_BYTE_LEN
4756 }
4757
4758 pub fn var_index_byte_range(&self) -> Range<usize> {
4759 let start = self.default_value_byte_range().end;
4760 start..start + u32::RAW_BYTE_LEN
4761 }
4762}
4763
4764#[cfg(feature = "experimental_traverse")]
4765impl<'a> SomeTable<'a> for ConditionFormat2<'a> {
4766 fn type_name(&self) -> &str {
4767 "ConditionFormat2"
4768 }
4769 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4770 match idx {
4771 0usize => Some(Field::new("format", self.format())),
4772 1usize => Some(Field::new("default_value", self.default_value())),
4773 2usize => Some(Field::new("var_index", self.var_index())),
4774 _ => None,
4775 }
4776 }
4777}
4778
4779#[cfg(feature = "experimental_traverse")]
4780#[allow(clippy::needless_lifetimes)]
4781impl<'a> std::fmt::Debug for ConditionFormat2<'a> {
4782 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4783 (self as &dyn SomeTable<'a>).fmt(f)
4784 }
4785}
4786
4787impl Format<u16> for ConditionFormat3<'_> {
4788 const FORMAT: u16 = 3;
4789}
4790
4791impl<'a> MinByteRange<'a> for ConditionFormat3<'a> {
4792 fn min_byte_range(&self) -> Range<usize> {
4793 0..self.condition_offsets_byte_range().end
4794 }
4795 fn min_table_bytes(&self) -> &'a [u8] {
4796 let range = self.min_byte_range();
4797 self.data.as_bytes().get(range).unwrap_or_default()
4798 }
4799}
4800
4801impl<'a> FontRead<'a> for ConditionFormat3<'a> {
4802 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4803 #[allow(clippy::absurd_extreme_comparisons)]
4804 if data.len() < Self::MIN_SIZE {
4805 return Err(ReadError::OutOfBounds);
4806 }
4807 Ok(Self { data })
4808 }
4809}
4810
4811#[derive(Clone)]
4813pub struct ConditionFormat3<'a> {
4814 data: FontData<'a>,
4815}
4816
4817#[allow(clippy::needless_lifetimes)]
4818impl<'a> ConditionFormat3<'a> {
4819 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
4820 basic_table_impls!(impl_the_methods);
4821
4822 pub fn format(&self) -> u16 {
4824 let range = self.format_byte_range();
4825 self.data.read_at(range.start).ok().unwrap()
4826 }
4827
4828 pub fn condition_count(&self) -> u8 {
4830 let range = self.condition_count_byte_range();
4831 self.data.read_at(range.start).ok().unwrap()
4832 }
4833
4834 pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
4836 let range = self.condition_offsets_byte_range();
4837 self.data.read_array(range).ok().unwrap_or_default()
4838 }
4839
4840 pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
4842 let data = self.data;
4843 let offsets = self.condition_offsets();
4844 ArrayOfOffsets::new(offsets, data, ())
4845 }
4846
4847 pub fn format_byte_range(&self) -> Range<usize> {
4848 let start = 0;
4849 start..start + u16::RAW_BYTE_LEN
4850 }
4851
4852 pub fn condition_count_byte_range(&self) -> Range<usize> {
4853 let start = self.format_byte_range().end;
4854 start..start + u8::RAW_BYTE_LEN
4855 }
4856
4857 pub fn condition_offsets_byte_range(&self) -> Range<usize> {
4858 let condition_count = self.condition_count();
4859 let start = self.condition_count_byte_range().end;
4860 start..start + (condition_count as usize).saturating_mul(Offset24::RAW_BYTE_LEN)
4861 }
4862}
4863
4864#[cfg(feature = "experimental_traverse")]
4865impl<'a> SomeTable<'a> for ConditionFormat3<'a> {
4866 fn type_name(&self) -> &str {
4867 "ConditionFormat3"
4868 }
4869 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4870 match idx {
4871 0usize => Some(Field::new("format", self.format())),
4872 1usize => Some(Field::new("condition_count", self.condition_count())),
4873 2usize => Some({
4874 let data = self.data;
4875 Field::new(
4876 "condition_offsets",
4877 FieldType::array_of_offsets(
4878 better_type_name::<Condition>(),
4879 self.condition_offsets(),
4880 move |off| {
4881 let target = off.get().resolve::<Condition>(data);
4882 FieldType::offset(off.get(), target)
4883 },
4884 ),
4885 )
4886 }),
4887 _ => None,
4888 }
4889 }
4890}
4891
4892#[cfg(feature = "experimental_traverse")]
4893#[allow(clippy::needless_lifetimes)]
4894impl<'a> std::fmt::Debug for ConditionFormat3<'a> {
4895 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4896 (self as &dyn SomeTable<'a>).fmt(f)
4897 }
4898}
4899
4900impl Format<u16> for ConditionFormat4<'_> {
4901 const FORMAT: u16 = 4;
4902}
4903
4904impl<'a> MinByteRange<'a> for ConditionFormat4<'a> {
4905 fn min_byte_range(&self) -> Range<usize> {
4906 0..self.condition_offsets_byte_range().end
4907 }
4908 fn min_table_bytes(&self) -> &'a [u8] {
4909 let range = self.min_byte_range();
4910 self.data.as_bytes().get(range).unwrap_or_default()
4911 }
4912}
4913
4914impl<'a> FontRead<'a> for ConditionFormat4<'a> {
4915 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4916 #[allow(clippy::absurd_extreme_comparisons)]
4917 if data.len() < Self::MIN_SIZE {
4918 return Err(ReadError::OutOfBounds);
4919 }
4920 Ok(Self { data })
4921 }
4922}
4923
4924#[derive(Clone)]
4926pub struct ConditionFormat4<'a> {
4927 data: FontData<'a>,
4928}
4929
4930#[allow(clippy::needless_lifetimes)]
4931impl<'a> ConditionFormat4<'a> {
4932 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
4933 basic_table_impls!(impl_the_methods);
4934
4935 pub fn format(&self) -> u16 {
4937 let range = self.format_byte_range();
4938 self.data.read_at(range.start).ok().unwrap()
4939 }
4940
4941 pub fn condition_count(&self) -> u8 {
4943 let range = self.condition_count_byte_range();
4944 self.data.read_at(range.start).ok().unwrap()
4945 }
4946
4947 pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
4949 let range = self.condition_offsets_byte_range();
4950 self.data.read_array(range).ok().unwrap_or_default()
4951 }
4952
4953 pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
4955 let data = self.data;
4956 let offsets = self.condition_offsets();
4957 ArrayOfOffsets::new(offsets, data, ())
4958 }
4959
4960 pub fn format_byte_range(&self) -> Range<usize> {
4961 let start = 0;
4962 start..start + u16::RAW_BYTE_LEN
4963 }
4964
4965 pub fn condition_count_byte_range(&self) -> Range<usize> {
4966 let start = self.format_byte_range().end;
4967 start..start + u8::RAW_BYTE_LEN
4968 }
4969
4970 pub fn condition_offsets_byte_range(&self) -> Range<usize> {
4971 let condition_count = self.condition_count();
4972 let start = self.condition_count_byte_range().end;
4973 start..start + (condition_count as usize).saturating_mul(Offset24::RAW_BYTE_LEN)
4974 }
4975}
4976
4977#[cfg(feature = "experimental_traverse")]
4978impl<'a> SomeTable<'a> for ConditionFormat4<'a> {
4979 fn type_name(&self) -> &str {
4980 "ConditionFormat4"
4981 }
4982 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4983 match idx {
4984 0usize => Some(Field::new("format", self.format())),
4985 1usize => Some(Field::new("condition_count", self.condition_count())),
4986 2usize => Some({
4987 let data = self.data;
4988 Field::new(
4989 "condition_offsets",
4990 FieldType::array_of_offsets(
4991 better_type_name::<Condition>(),
4992 self.condition_offsets(),
4993 move |off| {
4994 let target = off.get().resolve::<Condition>(data);
4995 FieldType::offset(off.get(), target)
4996 },
4997 ),
4998 )
4999 }),
5000 _ => None,
5001 }
5002 }
5003}
5004
5005#[cfg(feature = "experimental_traverse")]
5006#[allow(clippy::needless_lifetimes)]
5007impl<'a> std::fmt::Debug for ConditionFormat4<'a> {
5008 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5009 (self as &dyn SomeTable<'a>).fmt(f)
5010 }
5011}
5012
5013impl Format<u16> for ConditionFormat5<'_> {
5014 const FORMAT: u16 = 5;
5015}
5016
5017impl<'a> MinByteRange<'a> for ConditionFormat5<'a> {
5018 fn min_byte_range(&self) -> Range<usize> {
5019 0..self.condition_offset_byte_range().end
5020 }
5021 fn min_table_bytes(&self) -> &'a [u8] {
5022 let range = self.min_byte_range();
5023 self.data.as_bytes().get(range).unwrap_or_default()
5024 }
5025}
5026
5027impl<'a> FontRead<'a> for ConditionFormat5<'a> {
5028 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5029 #[allow(clippy::absurd_extreme_comparisons)]
5030 if data.len() < Self::MIN_SIZE {
5031 return Err(ReadError::OutOfBounds);
5032 }
5033 Ok(Self { data })
5034 }
5035}
5036
5037#[derive(Clone)]
5039pub struct ConditionFormat5<'a> {
5040 data: FontData<'a>,
5041}
5042
5043#[allow(clippy::needless_lifetimes)]
5044impl<'a> ConditionFormat5<'a> {
5045 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN);
5046 basic_table_impls!(impl_the_methods);
5047
5048 pub fn format(&self) -> u16 {
5050 let range = self.format_byte_range();
5051 self.data.read_at(range.start).ok().unwrap()
5052 }
5053
5054 pub fn condition_offset(&self) -> Offset24 {
5056 let range = self.condition_offset_byte_range();
5057 self.data.read_at(range.start).ok().unwrap()
5058 }
5059
5060 pub fn condition(&self) -> Result<Condition<'a>, ReadError> {
5062 let data = self.data;
5063 self.condition_offset().resolve(data)
5064 }
5065
5066 pub fn format_byte_range(&self) -> Range<usize> {
5067 let start = 0;
5068 start..start + u16::RAW_BYTE_LEN
5069 }
5070
5071 pub fn condition_offset_byte_range(&self) -> Range<usize> {
5072 let start = self.format_byte_range().end;
5073 start..start + Offset24::RAW_BYTE_LEN
5074 }
5075}
5076
5077#[cfg(feature = "experimental_traverse")]
5078impl<'a> SomeTable<'a> for ConditionFormat5<'a> {
5079 fn type_name(&self) -> &str {
5080 "ConditionFormat5"
5081 }
5082 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5083 match idx {
5084 0usize => Some(Field::new("format", self.format())),
5085 1usize => Some(Field::new(
5086 "condition_offset",
5087 FieldType::offset(self.condition_offset(), self.condition()),
5088 )),
5089 _ => None,
5090 }
5091 }
5092}
5093
5094#[cfg(feature = "experimental_traverse")]
5095#[allow(clippy::needless_lifetimes)]
5096impl<'a> std::fmt::Debug for ConditionFormat5<'a> {
5097 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5098 (self as &dyn SomeTable<'a>).fmt(f)
5099 }
5100}
5101
5102impl<'a> MinByteRange<'a> for FeatureTableSubstitution<'a> {
5103 fn min_byte_range(&self) -> Range<usize> {
5104 0..self.substitutions_byte_range().end
5105 }
5106 fn min_table_bytes(&self) -> &'a [u8] {
5107 let range = self.min_byte_range();
5108 self.data.as_bytes().get(range).unwrap_or_default()
5109 }
5110}
5111
5112impl<'a> FontRead<'a> for FeatureTableSubstitution<'a> {
5113 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5114 #[allow(clippy::absurd_extreme_comparisons)]
5115 if data.len() < Self::MIN_SIZE {
5116 return Err(ReadError::OutOfBounds);
5117 }
5118 Ok(Self { data })
5119 }
5120}
5121
5122#[derive(Clone)]
5124pub struct FeatureTableSubstitution<'a> {
5125 data: FontData<'a>,
5126}
5127
5128#[allow(clippy::needless_lifetimes)]
5129impl<'a> FeatureTableSubstitution<'a> {
5130 pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
5131 basic_table_impls!(impl_the_methods);
5132
5133 pub fn version(&self) -> MajorMinor {
5135 let range = self.version_byte_range();
5136 self.data.read_at(range.start).ok().unwrap()
5137 }
5138
5139 pub fn substitution_count(&self) -> u16 {
5141 let range = self.substitution_count_byte_range();
5142 self.data.read_at(range.start).ok().unwrap()
5143 }
5144
5145 pub fn substitutions(&self) -> &'a [FeatureTableSubstitutionRecord] {
5147 let range = self.substitutions_byte_range();
5148 self.data.read_array(range).ok().unwrap_or_default()
5149 }
5150
5151 pub fn version_byte_range(&self) -> Range<usize> {
5152 let start = 0;
5153 start..start + MajorMinor::RAW_BYTE_LEN
5154 }
5155
5156 pub fn substitution_count_byte_range(&self) -> Range<usize> {
5157 let start = self.version_byte_range().end;
5158 start..start + u16::RAW_BYTE_LEN
5159 }
5160
5161 pub fn substitutions_byte_range(&self) -> Range<usize> {
5162 let substitution_count = self.substitution_count();
5163 let start = self.substitution_count_byte_range().end;
5164 start
5165 ..start
5166 + (substitution_count as usize)
5167 .saturating_mul(FeatureTableSubstitutionRecord::RAW_BYTE_LEN)
5168 }
5169}
5170
5171#[cfg(feature = "experimental_traverse")]
5172impl<'a> SomeTable<'a> for FeatureTableSubstitution<'a> {
5173 fn type_name(&self) -> &str {
5174 "FeatureTableSubstitution"
5175 }
5176 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5177 match idx {
5178 0usize => Some(Field::new("version", self.version())),
5179 1usize => Some(Field::new("substitution_count", self.substitution_count())),
5180 2usize => Some(Field::new(
5181 "substitutions",
5182 traversal::FieldType::array_of_records(
5183 stringify!(FeatureTableSubstitutionRecord),
5184 self.substitutions(),
5185 self.offset_data(),
5186 ),
5187 )),
5188 _ => None,
5189 }
5190 }
5191}
5192
5193#[cfg(feature = "experimental_traverse")]
5194#[allow(clippy::needless_lifetimes)]
5195impl<'a> std::fmt::Debug for FeatureTableSubstitution<'a> {
5196 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5197 (self as &dyn SomeTable<'a>).fmt(f)
5198 }
5199}
5200
5201#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
5203#[repr(C)]
5204#[repr(packed)]
5205pub struct FeatureTableSubstitutionRecord {
5206 pub feature_index: BigEndian<u16>,
5208 pub alternate_feature_offset: BigEndian<Offset32>,
5211}
5212
5213impl FeatureTableSubstitutionRecord {
5214 pub fn feature_index(&self) -> u16 {
5216 self.feature_index.get()
5217 }
5218
5219 pub fn alternate_feature_offset(&self) -> Offset32 {
5222 self.alternate_feature_offset.get()
5223 }
5224}
5225
5226impl FixedSize for FeatureTableSubstitutionRecord {
5227 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
5228}
5229
5230#[cfg(feature = "experimental_traverse")]
5231impl<'a> SomeRecord<'a> for FeatureTableSubstitutionRecord {
5232 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
5233 RecordResolver {
5234 name: "FeatureTableSubstitutionRecord",
5235 get_field: Box::new(move |idx, _data| match idx {
5236 0usize => Some(Field::new("feature_index", self.feature_index())),
5237 1usize => Some(Field::new(
5238 "alternate_feature_offset",
5239 FieldType::offset(
5240 self.alternate_feature_offset(),
5241 self.alternate_feature(_data),
5242 ),
5243 )),
5244 _ => None,
5245 }),
5246 data,
5247 }
5248 }
5249}
5250
5251impl<'a> MinByteRange<'a> for SizeParams<'a> {
5252 fn min_byte_range(&self) -> Range<usize> {
5253 0..self.range_end_byte_range().end
5254 }
5255 fn min_table_bytes(&self) -> &'a [u8] {
5256 let range = self.min_byte_range();
5257 self.data.as_bytes().get(range).unwrap_or_default()
5258 }
5259}
5260
5261impl<'a> FontRead<'a> for SizeParams<'a> {
5262 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5263 #[allow(clippy::absurd_extreme_comparisons)]
5264 if data.len() < Self::MIN_SIZE {
5265 return Err(ReadError::OutOfBounds);
5266 }
5267 Ok(Self { data })
5268 }
5269}
5270
5271#[derive(Clone)]
5272pub struct SizeParams<'a> {
5273 data: FontData<'a>,
5274}
5275
5276#[allow(clippy::needless_lifetimes)]
5277impl<'a> SizeParams<'a> {
5278 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
5279 + u16::RAW_BYTE_LEN
5280 + u16::RAW_BYTE_LEN
5281 + u16::RAW_BYTE_LEN
5282 + u16::RAW_BYTE_LEN);
5283 basic_table_impls!(impl_the_methods);
5284
5285 pub fn design_size(&self) -> u16 {
5290 let range = self.design_size_byte_range();
5291 self.data.read_at(range.start).ok().unwrap()
5292 }
5293
5294 pub fn identifier(&self) -> u16 {
5301 let range = self.identifier_byte_range();
5302 self.data.read_at(range.start).ok().unwrap()
5303 }
5304
5305 pub fn name_entry(&self) -> u16 {
5316 let range = self.name_entry_byte_range();
5317 self.data.read_at(range.start).ok().unwrap()
5318 }
5319
5320 pub fn range_start(&self) -> u16 {
5326 let range = self.range_start_byte_range();
5327 self.data.read_at(range.start).ok().unwrap()
5328 }
5329
5330 pub fn range_end(&self) -> u16 {
5331 let range = self.range_end_byte_range();
5332 self.data.read_at(range.start).ok().unwrap()
5333 }
5334
5335 pub fn design_size_byte_range(&self) -> Range<usize> {
5336 let start = 0;
5337 start..start + u16::RAW_BYTE_LEN
5338 }
5339
5340 pub fn identifier_byte_range(&self) -> Range<usize> {
5341 let start = self.design_size_byte_range().end;
5342 start..start + u16::RAW_BYTE_LEN
5343 }
5344
5345 pub fn name_entry_byte_range(&self) -> Range<usize> {
5346 let start = self.identifier_byte_range().end;
5347 start..start + u16::RAW_BYTE_LEN
5348 }
5349
5350 pub fn range_start_byte_range(&self) -> Range<usize> {
5351 let start = self.name_entry_byte_range().end;
5352 start..start + u16::RAW_BYTE_LEN
5353 }
5354
5355 pub fn range_end_byte_range(&self) -> Range<usize> {
5356 let start = self.range_start_byte_range().end;
5357 start..start + u16::RAW_BYTE_LEN
5358 }
5359}
5360
5361#[cfg(feature = "experimental_traverse")]
5362impl<'a> SomeTable<'a> for SizeParams<'a> {
5363 fn type_name(&self) -> &str {
5364 "SizeParams"
5365 }
5366 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5367 match idx {
5368 0usize => Some(Field::new("design_size", self.design_size())),
5369 1usize => Some(Field::new("identifier", self.identifier())),
5370 2usize => Some(Field::new("name_entry", self.name_entry())),
5371 3usize => Some(Field::new("range_start", self.range_start())),
5372 4usize => Some(Field::new("range_end", self.range_end())),
5373 _ => None,
5374 }
5375 }
5376}
5377
5378#[cfg(feature = "experimental_traverse")]
5379#[allow(clippy::needless_lifetimes)]
5380impl<'a> std::fmt::Debug for SizeParams<'a> {
5381 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5382 (self as &dyn SomeTable<'a>).fmt(f)
5383 }
5384}
5385
5386impl<'a> MinByteRange<'a> for StylisticSetParams<'a> {
5387 fn min_byte_range(&self) -> Range<usize> {
5388 0..self.ui_name_id_byte_range().end
5389 }
5390 fn min_table_bytes(&self) -> &'a [u8] {
5391 let range = self.min_byte_range();
5392 self.data.as_bytes().get(range).unwrap_or_default()
5393 }
5394}
5395
5396impl<'a> FontRead<'a> for StylisticSetParams<'a> {
5397 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5398 #[allow(clippy::absurd_extreme_comparisons)]
5399 if data.len() < Self::MIN_SIZE {
5400 return Err(ReadError::OutOfBounds);
5401 }
5402 Ok(Self { data })
5403 }
5404}
5405
5406#[derive(Clone)]
5407pub struct StylisticSetParams<'a> {
5408 data: FontData<'a>,
5409}
5410
5411#[allow(clippy::needless_lifetimes)]
5412impl<'a> StylisticSetParams<'a> {
5413 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + NameId::RAW_BYTE_LEN);
5414 basic_table_impls!(impl_the_methods);
5415
5416 pub fn version(&self) -> u16 {
5417 let range = self.version_byte_range();
5418 self.data.read_at(range.start).ok().unwrap()
5419 }
5420
5421 pub fn ui_name_id(&self) -> NameId {
5431 let range = self.ui_name_id_byte_range();
5432 self.data.read_at(range.start).ok().unwrap()
5433 }
5434
5435 pub fn version_byte_range(&self) -> Range<usize> {
5436 let start = 0;
5437 start..start + u16::RAW_BYTE_LEN
5438 }
5439
5440 pub fn ui_name_id_byte_range(&self) -> Range<usize> {
5441 let start = self.version_byte_range().end;
5442 start..start + NameId::RAW_BYTE_LEN
5443 }
5444}
5445
5446#[cfg(feature = "experimental_traverse")]
5447impl<'a> SomeTable<'a> for StylisticSetParams<'a> {
5448 fn type_name(&self) -> &str {
5449 "StylisticSetParams"
5450 }
5451 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5452 match idx {
5453 0usize => Some(Field::new("version", self.version())),
5454 1usize => Some(Field::new("ui_name_id", self.ui_name_id())),
5455 _ => None,
5456 }
5457 }
5458}
5459
5460#[cfg(feature = "experimental_traverse")]
5461#[allow(clippy::needless_lifetimes)]
5462impl<'a> std::fmt::Debug for StylisticSetParams<'a> {
5463 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5464 (self as &dyn SomeTable<'a>).fmt(f)
5465 }
5466}
5467
5468impl Format<u16> for CharacterVariantParams<'_> {
5469 const FORMAT: u16 = 0;
5470}
5471
5472impl<'a> MinByteRange<'a> for CharacterVariantParams<'a> {
5473 fn min_byte_range(&self) -> Range<usize> {
5474 0..self.character_byte_range().end
5475 }
5476 fn min_table_bytes(&self) -> &'a [u8] {
5477 let range = self.min_byte_range();
5478 self.data.as_bytes().get(range).unwrap_or_default()
5479 }
5480}
5481
5482impl<'a> FontRead<'a> for CharacterVariantParams<'a> {
5483 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5484 #[allow(clippy::absurd_extreme_comparisons)]
5485 if data.len() < Self::MIN_SIZE {
5486 return Err(ReadError::OutOfBounds);
5487 }
5488 Ok(Self { data })
5489 }
5490}
5491
5492#[derive(Clone)]
5494pub struct CharacterVariantParams<'a> {
5495 data: FontData<'a>,
5496}
5497
5498#[allow(clippy::needless_lifetimes)]
5499impl<'a> CharacterVariantParams<'a> {
5500 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
5501 + NameId::RAW_BYTE_LEN
5502 + NameId::RAW_BYTE_LEN
5503 + NameId::RAW_BYTE_LEN
5504 + u16::RAW_BYTE_LEN
5505 + NameId::RAW_BYTE_LEN
5506 + u16::RAW_BYTE_LEN);
5507 basic_table_impls!(impl_the_methods);
5508
5509 pub fn format(&self) -> u16 {
5511 let range = self.format_byte_range();
5512 self.data.read_at(range.start).ok().unwrap()
5513 }
5514
5515 pub fn feat_ui_label_name_id(&self) -> NameId {
5519 let range = self.feat_ui_label_name_id_byte_range();
5520 self.data.read_at(range.start).ok().unwrap()
5521 }
5522
5523 pub fn feat_ui_tooltip_text_name_id(&self) -> NameId {
5527 let range = self.feat_ui_tooltip_text_name_id_byte_range();
5528 self.data.read_at(range.start).ok().unwrap()
5529 }
5530
5531 pub fn sample_text_name_id(&self) -> NameId {
5534 let range = self.sample_text_name_id_byte_range();
5535 self.data.read_at(range.start).ok().unwrap()
5536 }
5537
5538 pub fn num_named_parameters(&self) -> u16 {
5540 let range = self.num_named_parameters_byte_range();
5541 self.data.read_at(range.start).ok().unwrap()
5542 }
5543
5544 pub fn first_param_ui_label_name_id(&self) -> NameId {
5548 let range = self.first_param_ui_label_name_id_byte_range();
5549 self.data.read_at(range.start).ok().unwrap()
5550 }
5551
5552 pub fn char_count(&self) -> u16 {
5555 let range = self.char_count_byte_range();
5556 self.data.read_at(range.start).ok().unwrap()
5557 }
5558
5559 pub fn character(&self) -> &'a [BigEndian<Uint24>] {
5562 let range = self.character_byte_range();
5563 self.data.read_array(range).ok().unwrap_or_default()
5564 }
5565
5566 pub fn format_byte_range(&self) -> Range<usize> {
5567 let start = 0;
5568 start..start + u16::RAW_BYTE_LEN
5569 }
5570
5571 pub fn feat_ui_label_name_id_byte_range(&self) -> Range<usize> {
5572 let start = self.format_byte_range().end;
5573 start..start + NameId::RAW_BYTE_LEN
5574 }
5575
5576 pub fn feat_ui_tooltip_text_name_id_byte_range(&self) -> Range<usize> {
5577 let start = self.feat_ui_label_name_id_byte_range().end;
5578 start..start + NameId::RAW_BYTE_LEN
5579 }
5580
5581 pub fn sample_text_name_id_byte_range(&self) -> Range<usize> {
5582 let start = self.feat_ui_tooltip_text_name_id_byte_range().end;
5583 start..start + NameId::RAW_BYTE_LEN
5584 }
5585
5586 pub fn num_named_parameters_byte_range(&self) -> Range<usize> {
5587 let start = self.sample_text_name_id_byte_range().end;
5588 start..start + u16::RAW_BYTE_LEN
5589 }
5590
5591 pub fn first_param_ui_label_name_id_byte_range(&self) -> Range<usize> {
5592 let start = self.num_named_parameters_byte_range().end;
5593 start..start + NameId::RAW_BYTE_LEN
5594 }
5595
5596 pub fn char_count_byte_range(&self) -> Range<usize> {
5597 let start = self.first_param_ui_label_name_id_byte_range().end;
5598 start..start + u16::RAW_BYTE_LEN
5599 }
5600
5601 pub fn character_byte_range(&self) -> Range<usize> {
5602 let char_count = self.char_count();
5603 let start = self.char_count_byte_range().end;
5604 start..start + (char_count as usize).saturating_mul(Uint24::RAW_BYTE_LEN)
5605 }
5606}
5607
5608#[cfg(feature = "experimental_traverse")]
5609impl<'a> SomeTable<'a> for CharacterVariantParams<'a> {
5610 fn type_name(&self) -> &str {
5611 "CharacterVariantParams"
5612 }
5613 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5614 match idx {
5615 0usize => Some(Field::new("format", self.format())),
5616 1usize => Some(Field::new(
5617 "feat_ui_label_name_id",
5618 self.feat_ui_label_name_id(),
5619 )),
5620 2usize => Some(Field::new(
5621 "feat_ui_tooltip_text_name_id",
5622 self.feat_ui_tooltip_text_name_id(),
5623 )),
5624 3usize => Some(Field::new(
5625 "sample_text_name_id",
5626 self.sample_text_name_id(),
5627 )),
5628 4usize => Some(Field::new(
5629 "num_named_parameters",
5630 self.num_named_parameters(),
5631 )),
5632 5usize => Some(Field::new(
5633 "first_param_ui_label_name_id",
5634 self.first_param_ui_label_name_id(),
5635 )),
5636 6usize => Some(Field::new("char_count", self.char_count())),
5637 7usize => Some(Field::new("character", self.character())),
5638 _ => None,
5639 }
5640 }
5641}
5642
5643#[cfg(feature = "experimental_traverse")]
5644#[allow(clippy::needless_lifetimes)]
5645impl<'a> std::fmt::Debug for CharacterVariantParams<'a> {
5646 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5647 (self as &dyn SomeTable<'a>).fmt(f)
5648 }
5649}