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