1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for Base<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.vert_axis_offset_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 TopLevelTable for Base<'_> {
19 const TAG: Tag = Tag::new(b"BASE");
21}
22
23impl<'a> FontRead<'a> for Base<'a> {
24 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
25 #[allow(clippy::absurd_extreme_comparisons)]
26 if data.len() < Self::MIN_SIZE {
27 return Err(ReadError::OutOfBounds);
28 }
29 Ok(Self { data })
30 }
31}
32
33#[derive(Clone)]
35pub struct Base<'a> {
36 data: FontData<'a>,
37}
38
39#[allow(clippy::needless_lifetimes)]
40impl<'a> Base<'a> {
41 pub const MIN_SIZE: usize =
42 (MajorMinor::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
43 basic_table_impls!(impl_the_methods);
44
45 pub fn version(&self) -> MajorMinor {
47 let range = self.version_byte_range();
48 self.data.read_at(range.start).ok().unwrap()
49 }
50
51 pub fn horiz_axis_offset(&self) -> Nullable<Offset16> {
53 let range = self.horiz_axis_offset_byte_range();
54 self.data.read_at(range.start).ok().unwrap()
55 }
56
57 pub fn horiz_axis(&self) -> Option<Result<Axis<'a>, ReadError>> {
59 let data = self.data;
60 self.horiz_axis_offset().resolve(data)
61 }
62
63 pub fn vert_axis_offset(&self) -> Nullable<Offset16> {
65 let range = self.vert_axis_offset_byte_range();
66 self.data.read_at(range.start).ok().unwrap()
67 }
68
69 pub fn vert_axis(&self) -> Option<Result<Axis<'a>, ReadError>> {
71 let data = self.data;
72 self.vert_axis_offset().resolve(data)
73 }
74
75 pub fn item_var_store_offset(&self) -> Option<Nullable<Offset32>> {
77 let range = self.item_var_store_offset_byte_range();
78 (!range.is_empty())
79 .then(|| self.data.read_at(range.start).ok())
80 .flatten()
81 }
82
83 pub fn item_var_store(&self) -> Option<Result<ItemVariationStore<'a>, ReadError>> {
85 let data = self.data;
86 self.item_var_store_offset().map(|x| x.resolve(data))?
87 }
88
89 pub fn version_byte_range(&self) -> Range<usize> {
90 let start = 0;
91 start..start + MajorMinor::RAW_BYTE_LEN
92 }
93
94 pub fn horiz_axis_offset_byte_range(&self) -> Range<usize> {
95 let start = self.version_byte_range().end;
96 start..start + Offset16::RAW_BYTE_LEN
97 }
98
99 pub fn vert_axis_offset_byte_range(&self) -> Range<usize> {
100 let start = self.horiz_axis_offset_byte_range().end;
101 start..start + Offset16::RAW_BYTE_LEN
102 }
103
104 pub fn item_var_store_offset_byte_range(&self) -> Range<usize> {
105 let start = self.vert_axis_offset_byte_range().end;
106 start
107 ..(self.version().compatible((1u16, 1u16)))
108 .then(|| start + Offset32::RAW_BYTE_LEN)
109 .unwrap_or(start)
110 }
111}
112
113const _: () = assert!(FontData::default_data_long_enough(Base::MIN_SIZE));
114
115impl Default for Base<'_> {
116 fn default() -> Self {
117 Self {
118 data: FontData::default_table_data(),
119 }
120 }
121}
122
123#[cfg(feature = "experimental_traverse")]
124impl<'a> SomeTable<'a> for Base<'a> {
125 fn type_name(&self) -> &str {
126 "Base"
127 }
128 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
129 match idx {
130 0usize => Some(Field::new("version", self.version())),
131 1usize => Some(Field::new(
132 "horiz_axis_offset",
133 FieldType::offset(self.horiz_axis_offset(), self.horiz_axis()),
134 )),
135 2usize => Some(Field::new(
136 "vert_axis_offset",
137 FieldType::offset(self.vert_axis_offset(), self.vert_axis()),
138 )),
139 3usize if self.version().compatible((1u16, 1u16)) => Some(Field::new(
140 "item_var_store_offset",
141 FieldType::offset(self.item_var_store_offset().unwrap(), self.item_var_store()),
142 )),
143 _ => None,
144 }
145 }
146}
147
148#[cfg(feature = "experimental_traverse")]
149#[allow(clippy::needless_lifetimes)]
150impl<'a> std::fmt::Debug for Base<'a> {
151 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152 (self as &dyn SomeTable<'a>).fmt(f)
153 }
154}
155
156impl<'a> MinByteRange<'a> for Axis<'a> {
157 fn min_byte_range(&self) -> Range<usize> {
158 0..self.base_script_list_offset_byte_range().end
159 }
160 fn min_table_bytes(&self) -> &'a [u8] {
161 let range = self.min_byte_range();
162 self.data.as_bytes().get(range).unwrap_or_default()
163 }
164}
165
166impl<'a> FontRead<'a> for Axis<'a> {
167 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
168 #[allow(clippy::absurd_extreme_comparisons)]
169 if data.len() < Self::MIN_SIZE {
170 return Err(ReadError::OutOfBounds);
171 }
172 Ok(Self { data })
173 }
174}
175
176#[derive(Clone)]
178pub struct Axis<'a> {
179 data: FontData<'a>,
180}
181
182#[allow(clippy::needless_lifetimes)]
183impl<'a> Axis<'a> {
184 pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
185 basic_table_impls!(impl_the_methods);
186
187 pub fn base_tag_list_offset(&self) -> Nullable<Offset16> {
190 let range = self.base_tag_list_offset_byte_range();
191 self.data.read_at(range.start).ok().unwrap()
192 }
193
194 pub fn base_tag_list(&self) -> Option<Result<BaseTagList<'a>, ReadError>> {
196 let data = self.data;
197 self.base_tag_list_offset().resolve(data)
198 }
199
200 pub fn base_script_list_offset(&self) -> Offset16 {
202 let range = self.base_script_list_offset_byte_range();
203 self.data.read_at(range.start).ok().unwrap()
204 }
205
206 pub fn base_script_list(&self) -> Result<BaseScriptList<'a>, ReadError> {
208 let data = self.data;
209 self.base_script_list_offset().resolve(data)
210 }
211
212 pub fn base_tag_list_offset_byte_range(&self) -> Range<usize> {
213 let start = 0;
214 start..start + Offset16::RAW_BYTE_LEN
215 }
216
217 pub fn base_script_list_offset_byte_range(&self) -> Range<usize> {
218 let start = self.base_tag_list_offset_byte_range().end;
219 start..start + Offset16::RAW_BYTE_LEN
220 }
221}
222
223const _: () = assert!(FontData::default_data_long_enough(Axis::MIN_SIZE));
224
225impl Default for Axis<'_> {
226 fn default() -> Self {
227 Self {
228 data: FontData::default_table_data(),
229 }
230 }
231}
232
233#[cfg(feature = "experimental_traverse")]
234impl<'a> SomeTable<'a> for Axis<'a> {
235 fn type_name(&self) -> &str {
236 "Axis"
237 }
238 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
239 match idx {
240 0usize => Some(Field::new(
241 "base_tag_list_offset",
242 FieldType::offset(self.base_tag_list_offset(), self.base_tag_list()),
243 )),
244 1usize => Some(Field::new(
245 "base_script_list_offset",
246 FieldType::offset(self.base_script_list_offset(), self.base_script_list()),
247 )),
248 _ => None,
249 }
250 }
251}
252
253#[cfg(feature = "experimental_traverse")]
254#[allow(clippy::needless_lifetimes)]
255impl<'a> std::fmt::Debug for Axis<'a> {
256 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257 (self as &dyn SomeTable<'a>).fmt(f)
258 }
259}
260
261impl<'a> MinByteRange<'a> for BaseTagList<'a> {
262 fn min_byte_range(&self) -> Range<usize> {
263 0..self.baseline_tags_byte_range().end
264 }
265 fn min_table_bytes(&self) -> &'a [u8] {
266 let range = self.min_byte_range();
267 self.data.as_bytes().get(range).unwrap_or_default()
268 }
269}
270
271impl<'a> FontRead<'a> for BaseTagList<'a> {
272 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
273 #[allow(clippy::absurd_extreme_comparisons)]
274 if data.len() < Self::MIN_SIZE {
275 return Err(ReadError::OutOfBounds);
276 }
277 Ok(Self { data })
278 }
279}
280
281#[derive(Clone)]
283pub struct BaseTagList<'a> {
284 data: FontData<'a>,
285}
286
287#[allow(clippy::needless_lifetimes)]
288impl<'a> BaseTagList<'a> {
289 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
290 basic_table_impls!(impl_the_methods);
291
292 pub fn base_tag_count(&self) -> u16 {
295 let range = self.base_tag_count_byte_range();
296 self.data.read_at(range.start).ok().unwrap()
297 }
298
299 pub fn baseline_tags(&self) -> &'a [BigEndian<Tag>] {
302 let range = self.baseline_tags_byte_range();
303 self.data.read_array(range).ok().unwrap_or_default()
304 }
305
306 pub fn base_tag_count_byte_range(&self) -> Range<usize> {
307 let start = 0;
308 start..start + u16::RAW_BYTE_LEN
309 }
310
311 pub fn baseline_tags_byte_range(&self) -> Range<usize> {
312 let base_tag_count = self.base_tag_count();
313 let start = self.base_tag_count_byte_range().end;
314 start..start + (transforms::to_usize(base_tag_count)).saturating_mul(Tag::RAW_BYTE_LEN)
315 }
316}
317
318const _: () = assert!(FontData::default_data_long_enough(BaseTagList::MIN_SIZE));
319
320impl Default for BaseTagList<'_> {
321 fn default() -> Self {
322 Self {
323 data: FontData::default_table_data(),
324 }
325 }
326}
327
328#[cfg(feature = "experimental_traverse")]
329impl<'a> SomeTable<'a> for BaseTagList<'a> {
330 fn type_name(&self) -> &str {
331 "BaseTagList"
332 }
333 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
334 match idx {
335 0usize => Some(Field::new("base_tag_count", self.base_tag_count())),
336 1usize => Some(Field::new("baseline_tags", self.baseline_tags())),
337 _ => None,
338 }
339 }
340}
341
342#[cfg(feature = "experimental_traverse")]
343#[allow(clippy::needless_lifetimes)]
344impl<'a> std::fmt::Debug for BaseTagList<'a> {
345 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
346 (self as &dyn SomeTable<'a>).fmt(f)
347 }
348}
349
350impl<'a> MinByteRange<'a> for BaseScriptList<'a> {
351 fn min_byte_range(&self) -> Range<usize> {
352 0..self.base_script_records_byte_range().end
353 }
354 fn min_table_bytes(&self) -> &'a [u8] {
355 let range = self.min_byte_range();
356 self.data.as_bytes().get(range).unwrap_or_default()
357 }
358}
359
360impl<'a> FontRead<'a> for BaseScriptList<'a> {
361 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
362 #[allow(clippy::absurd_extreme_comparisons)]
363 if data.len() < Self::MIN_SIZE {
364 return Err(ReadError::OutOfBounds);
365 }
366 Ok(Self { data })
367 }
368}
369
370#[derive(Clone)]
372pub struct BaseScriptList<'a> {
373 data: FontData<'a>,
374}
375
376#[allow(clippy::needless_lifetimes)]
377impl<'a> BaseScriptList<'a> {
378 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
379 basic_table_impls!(impl_the_methods);
380
381 pub fn base_script_count(&self) -> u16 {
383 let range = self.base_script_count_byte_range();
384 self.data.read_at(range.start).ok().unwrap()
385 }
386
387 pub fn base_script_records(&self) -> &'a [BaseScriptRecord] {
390 let range = self.base_script_records_byte_range();
391 self.data.read_array(range).ok().unwrap_or_default()
392 }
393
394 pub fn base_script_count_byte_range(&self) -> Range<usize> {
395 let start = 0;
396 start..start + u16::RAW_BYTE_LEN
397 }
398
399 pub fn base_script_records_byte_range(&self) -> Range<usize> {
400 let base_script_count = self.base_script_count();
401 let start = self.base_script_count_byte_range().end;
402 start
403 ..start
404 + (transforms::to_usize(base_script_count))
405 .saturating_mul(BaseScriptRecord::RAW_BYTE_LEN)
406 }
407}
408
409const _: () = assert!(FontData::default_data_long_enough(BaseScriptList::MIN_SIZE));
410
411impl Default for BaseScriptList<'_> {
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 BaseScriptList<'a> {
421 fn type_name(&self) -> &str {
422 "BaseScriptList"
423 }
424 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
425 match idx {
426 0usize => Some(Field::new("base_script_count", self.base_script_count())),
427 1usize => Some(Field::new(
428 "base_script_records",
429 traversal::FieldType::array_of_records(
430 stringify!(BaseScriptRecord),
431 self.base_script_records(),
432 self.offset_data(),
433 ),
434 )),
435 _ => None,
436 }
437 }
438}
439
440#[cfg(feature = "experimental_traverse")]
441#[allow(clippy::needless_lifetimes)]
442impl<'a> std::fmt::Debug for BaseScriptList<'a> {
443 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
444 (self as &dyn SomeTable<'a>).fmt(f)
445 }
446}
447
448#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
450#[repr(C)]
451#[repr(packed)]
452pub struct BaseScriptRecord {
453 pub base_script_tag: BigEndian<Tag>,
455 pub base_script_offset: BigEndian<Offset16>,
457}
458
459impl BaseScriptRecord {
460 pub fn base_script_tag(&self) -> Tag {
462 self.base_script_tag.get()
463 }
464
465 pub fn base_script_offset(&self) -> Offset16 {
467 self.base_script_offset.get()
468 }
469
470 pub fn base_script<'a>(&self, data: FontData<'a>) -> Result<BaseScript<'a>, ReadError> {
475 self.base_script_offset().resolve(data)
476 }
477}
478
479impl FixedSize for BaseScriptRecord {
480 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
481}
482
483#[cfg(feature = "experimental_traverse")]
484impl<'a> SomeRecord<'a> for BaseScriptRecord {
485 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
486 RecordResolver {
487 name: "BaseScriptRecord",
488 get_field: Box::new(move |idx, _data| match idx {
489 0usize => Some(Field::new("base_script_tag", self.base_script_tag())),
490 1usize => Some(Field::new(
491 "base_script_offset",
492 FieldType::offset(self.base_script_offset(), self.base_script(_data)),
493 )),
494 _ => None,
495 }),
496 data,
497 }
498 }
499}
500
501impl<'a> MinByteRange<'a> for BaseScript<'a> {
502 fn min_byte_range(&self) -> Range<usize> {
503 0..self.base_lang_sys_records_byte_range().end
504 }
505 fn min_table_bytes(&self) -> &'a [u8] {
506 let range = self.min_byte_range();
507 self.data.as_bytes().get(range).unwrap_or_default()
508 }
509}
510
511impl<'a> FontRead<'a> for BaseScript<'a> {
512 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
513 #[allow(clippy::absurd_extreme_comparisons)]
514 if data.len() < Self::MIN_SIZE {
515 return Err(ReadError::OutOfBounds);
516 }
517 Ok(Self { data })
518 }
519}
520
521#[derive(Clone)]
523pub struct BaseScript<'a> {
524 data: FontData<'a>,
525}
526
527#[allow(clippy::needless_lifetimes)]
528impl<'a> BaseScript<'a> {
529 pub const MIN_SIZE: usize =
530 (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
531 basic_table_impls!(impl_the_methods);
532
533 pub fn base_values_offset(&self) -> Nullable<Offset16> {
535 let range = self.base_values_offset_byte_range();
536 self.data.read_at(range.start).ok().unwrap()
537 }
538
539 pub fn base_values(&self) -> Option<Result<BaseValues<'a>, ReadError>> {
541 let data = self.data;
542 self.base_values_offset().resolve(data)
543 }
544
545 pub fn default_min_max_offset(&self) -> Nullable<Offset16> {
547 let range = self.default_min_max_offset_byte_range();
548 self.data.read_at(range.start).ok().unwrap()
549 }
550
551 pub fn default_min_max(&self) -> Option<Result<MinMax<'a>, ReadError>> {
553 let data = self.data;
554 self.default_min_max_offset().resolve(data)
555 }
556
557 pub fn base_lang_sys_count(&self) -> u16 {
559 let range = self.base_lang_sys_count_byte_range();
560 self.data.read_at(range.start).ok().unwrap()
561 }
562
563 pub fn base_lang_sys_records(&self) -> &'a [BaseLangSysRecord] {
566 let range = self.base_lang_sys_records_byte_range();
567 self.data.read_array(range).ok().unwrap_or_default()
568 }
569
570 pub fn base_values_offset_byte_range(&self) -> Range<usize> {
571 let start = 0;
572 start..start + Offset16::RAW_BYTE_LEN
573 }
574
575 pub fn default_min_max_offset_byte_range(&self) -> Range<usize> {
576 let start = self.base_values_offset_byte_range().end;
577 start..start + Offset16::RAW_BYTE_LEN
578 }
579
580 pub fn base_lang_sys_count_byte_range(&self) -> Range<usize> {
581 let start = self.default_min_max_offset_byte_range().end;
582 start..start + u16::RAW_BYTE_LEN
583 }
584
585 pub fn base_lang_sys_records_byte_range(&self) -> Range<usize> {
586 let base_lang_sys_count = self.base_lang_sys_count();
587 let start = self.base_lang_sys_count_byte_range().end;
588 start
589 ..start
590 + (transforms::to_usize(base_lang_sys_count))
591 .saturating_mul(BaseLangSysRecord::RAW_BYTE_LEN)
592 }
593}
594
595const _: () = assert!(FontData::default_data_long_enough(BaseScript::MIN_SIZE));
596
597impl Default for BaseScript<'_> {
598 fn default() -> Self {
599 Self {
600 data: FontData::default_table_data(),
601 }
602 }
603}
604
605#[cfg(feature = "experimental_traverse")]
606impl<'a> SomeTable<'a> for BaseScript<'a> {
607 fn type_name(&self) -> &str {
608 "BaseScript"
609 }
610 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
611 match idx {
612 0usize => Some(Field::new(
613 "base_values_offset",
614 FieldType::offset(self.base_values_offset(), self.base_values()),
615 )),
616 1usize => Some(Field::new(
617 "default_min_max_offset",
618 FieldType::offset(self.default_min_max_offset(), self.default_min_max()),
619 )),
620 2usize => Some(Field::new(
621 "base_lang_sys_count",
622 self.base_lang_sys_count(),
623 )),
624 3usize => Some(Field::new(
625 "base_lang_sys_records",
626 traversal::FieldType::array_of_records(
627 stringify!(BaseLangSysRecord),
628 self.base_lang_sys_records(),
629 self.offset_data(),
630 ),
631 )),
632 _ => None,
633 }
634 }
635}
636
637#[cfg(feature = "experimental_traverse")]
638#[allow(clippy::needless_lifetimes)]
639impl<'a> std::fmt::Debug for BaseScript<'a> {
640 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
641 (self as &dyn SomeTable<'a>).fmt(f)
642 }
643}
644
645#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
647#[repr(C)]
648#[repr(packed)]
649pub struct BaseLangSysRecord {
650 pub base_lang_sys_tag: BigEndian<Tag>,
652 pub min_max_offset: BigEndian<Offset16>,
654}
655
656impl BaseLangSysRecord {
657 pub fn base_lang_sys_tag(&self) -> Tag {
659 self.base_lang_sys_tag.get()
660 }
661
662 pub fn min_max_offset(&self) -> Offset16 {
664 self.min_max_offset.get()
665 }
666
667 pub fn min_max<'a>(&self, data: FontData<'a>) -> Result<MinMax<'a>, ReadError> {
672 self.min_max_offset().resolve(data)
673 }
674}
675
676impl FixedSize for BaseLangSysRecord {
677 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
678}
679
680#[cfg(feature = "experimental_traverse")]
681impl<'a> SomeRecord<'a> for BaseLangSysRecord {
682 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
683 RecordResolver {
684 name: "BaseLangSysRecord",
685 get_field: Box::new(move |idx, _data| match idx {
686 0usize => Some(Field::new("base_lang_sys_tag", self.base_lang_sys_tag())),
687 1usize => Some(Field::new(
688 "min_max_offset",
689 FieldType::offset(self.min_max_offset(), self.min_max(_data)),
690 )),
691 _ => None,
692 }),
693 data,
694 }
695 }
696}
697
698impl<'a> MinByteRange<'a> for BaseValues<'a> {
699 fn min_byte_range(&self) -> Range<usize> {
700 0..self.base_coord_offsets_byte_range().end
701 }
702 fn min_table_bytes(&self) -> &'a [u8] {
703 let range = self.min_byte_range();
704 self.data.as_bytes().get(range).unwrap_or_default()
705 }
706}
707
708impl<'a> FontRead<'a> for BaseValues<'a> {
709 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
710 #[allow(clippy::absurd_extreme_comparisons)]
711 if data.len() < Self::MIN_SIZE {
712 return Err(ReadError::OutOfBounds);
713 }
714 Ok(Self { data })
715 }
716}
717
718#[derive(Clone)]
720pub struct BaseValues<'a> {
721 data: FontData<'a>,
722}
723
724#[allow(clippy::needless_lifetimes)]
725impl<'a> BaseValues<'a> {
726 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
727 basic_table_impls!(impl_the_methods);
728
729 pub fn default_baseline_index(&self) -> u16 {
733 let range = self.default_baseline_index_byte_range();
734 self.data.read_at(range.start).ok().unwrap()
735 }
736
737 pub fn base_coord_count(&self) -> u16 {
740 let range = self.base_coord_count_byte_range();
741 self.data.read_at(range.start).ok().unwrap()
742 }
743
744 pub fn base_coord_offsets(&self) -> &'a [BigEndian<Offset16>] {
748 let range = self.base_coord_offsets_byte_range();
749 self.data.read_array(range).ok().unwrap_or_default()
750 }
751
752 pub fn base_coords(&self) -> ArrayOfOffsets<'a, BaseCoord<'a>, Offset16> {
754 let data = self.data;
755 let offsets = self.base_coord_offsets();
756 ArrayOfOffsets::new(offsets, data, ())
757 }
758
759 pub fn default_baseline_index_byte_range(&self) -> Range<usize> {
760 let start = 0;
761 start..start + u16::RAW_BYTE_LEN
762 }
763
764 pub fn base_coord_count_byte_range(&self) -> Range<usize> {
765 let start = self.default_baseline_index_byte_range().end;
766 start..start + u16::RAW_BYTE_LEN
767 }
768
769 pub fn base_coord_offsets_byte_range(&self) -> Range<usize> {
770 let base_coord_count = self.base_coord_count();
771 let start = self.base_coord_count_byte_range().end;
772 start
773 ..start
774 + (transforms::to_usize(base_coord_count)).saturating_mul(Offset16::RAW_BYTE_LEN)
775 }
776}
777
778const _: () = assert!(FontData::default_data_long_enough(BaseValues::MIN_SIZE));
779
780impl Default for BaseValues<'_> {
781 fn default() -> Self {
782 Self {
783 data: FontData::default_table_data(),
784 }
785 }
786}
787
788#[cfg(feature = "experimental_traverse")]
789impl<'a> SomeTable<'a> for BaseValues<'a> {
790 fn type_name(&self) -> &str {
791 "BaseValues"
792 }
793 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
794 match idx {
795 0usize => Some(Field::new(
796 "default_baseline_index",
797 self.default_baseline_index(),
798 )),
799 1usize => Some(Field::new("base_coord_count", self.base_coord_count())),
800 2usize => Some(Field::new(
801 "base_coord_offsets",
802 FieldType::from(self.base_coords()),
803 )),
804 _ => None,
805 }
806 }
807}
808
809#[cfg(feature = "experimental_traverse")]
810#[allow(clippy::needless_lifetimes)]
811impl<'a> std::fmt::Debug for BaseValues<'a> {
812 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
813 (self as &dyn SomeTable<'a>).fmt(f)
814 }
815}
816
817impl<'a> MinByteRange<'a> for MinMax<'a> {
818 fn min_byte_range(&self) -> Range<usize> {
819 0..self.feat_min_max_records_byte_range().end
820 }
821 fn min_table_bytes(&self) -> &'a [u8] {
822 let range = self.min_byte_range();
823 self.data.as_bytes().get(range).unwrap_or_default()
824 }
825}
826
827impl<'a> FontRead<'a> for MinMax<'a> {
828 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
829 #[allow(clippy::absurd_extreme_comparisons)]
830 if data.len() < Self::MIN_SIZE {
831 return Err(ReadError::OutOfBounds);
832 }
833 Ok(Self { data })
834 }
835}
836
837#[derive(Clone)]
839pub struct MinMax<'a> {
840 data: FontData<'a>,
841}
842
843#[allow(clippy::needless_lifetimes)]
844impl<'a> MinMax<'a> {
845 pub const MIN_SIZE: usize =
846 (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
847 basic_table_impls!(impl_the_methods);
848
849 pub fn min_coord_offset(&self) -> Nullable<Offset16> {
852 let range = self.min_coord_offset_byte_range();
853 self.data.read_at(range.start).ok().unwrap()
854 }
855
856 pub fn min_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
858 let data = self.data;
859 self.min_coord_offset().resolve(data)
860 }
861
862 pub fn max_coord_offset(&self) -> Nullable<Offset16> {
865 let range = self.max_coord_offset_byte_range();
866 self.data.read_at(range.start).ok().unwrap()
867 }
868
869 pub fn max_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
871 let data = self.data;
872 self.max_coord_offset().resolve(data)
873 }
874
875 pub fn feat_min_max_count(&self) -> u16 {
877 let range = self.feat_min_max_count_byte_range();
878 self.data.read_at(range.start).ok().unwrap()
879 }
880
881 pub fn feat_min_max_records(&self) -> &'a [FeatMinMaxRecord] {
884 let range = self.feat_min_max_records_byte_range();
885 self.data.read_array(range).ok().unwrap_or_default()
886 }
887
888 pub fn min_coord_offset_byte_range(&self) -> Range<usize> {
889 let start = 0;
890 start..start + Offset16::RAW_BYTE_LEN
891 }
892
893 pub fn max_coord_offset_byte_range(&self) -> Range<usize> {
894 let start = self.min_coord_offset_byte_range().end;
895 start..start + Offset16::RAW_BYTE_LEN
896 }
897
898 pub fn feat_min_max_count_byte_range(&self) -> Range<usize> {
899 let start = self.max_coord_offset_byte_range().end;
900 start..start + u16::RAW_BYTE_LEN
901 }
902
903 pub fn feat_min_max_records_byte_range(&self) -> Range<usize> {
904 let feat_min_max_count = self.feat_min_max_count();
905 let start = self.feat_min_max_count_byte_range().end;
906 start
907 ..start
908 + (transforms::to_usize(feat_min_max_count))
909 .saturating_mul(FeatMinMaxRecord::RAW_BYTE_LEN)
910 }
911}
912
913const _: () = assert!(FontData::default_data_long_enough(MinMax::MIN_SIZE));
914
915impl Default for MinMax<'_> {
916 fn default() -> Self {
917 Self {
918 data: FontData::default_table_data(),
919 }
920 }
921}
922
923#[cfg(feature = "experimental_traverse")]
924impl<'a> SomeTable<'a> for MinMax<'a> {
925 fn type_name(&self) -> &str {
926 "MinMax"
927 }
928 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
929 match idx {
930 0usize => Some(Field::new(
931 "min_coord_offset",
932 FieldType::offset(self.min_coord_offset(), self.min_coord()),
933 )),
934 1usize => Some(Field::new(
935 "max_coord_offset",
936 FieldType::offset(self.max_coord_offset(), self.max_coord()),
937 )),
938 2usize => Some(Field::new("feat_min_max_count", self.feat_min_max_count())),
939 3usize => Some(Field::new(
940 "feat_min_max_records",
941 traversal::FieldType::array_of_records(
942 stringify!(FeatMinMaxRecord),
943 self.feat_min_max_records(),
944 self.offset_data(),
945 ),
946 )),
947 _ => None,
948 }
949 }
950}
951
952#[cfg(feature = "experimental_traverse")]
953#[allow(clippy::needless_lifetimes)]
954impl<'a> std::fmt::Debug for MinMax<'a> {
955 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
956 (self as &dyn SomeTable<'a>).fmt(f)
957 }
958}
959
960#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
962#[repr(C)]
963#[repr(packed)]
964pub struct FeatMinMaxRecord {
965 pub feature_table_tag: BigEndian<Tag>,
968 pub min_coord_offset: BigEndian<Nullable<Offset16>>,
971 pub max_coord_offset: BigEndian<Nullable<Offset16>>,
974}
975
976impl FeatMinMaxRecord {
977 pub fn feature_table_tag(&self) -> Tag {
980 self.feature_table_tag.get()
981 }
982
983 pub fn min_coord_offset(&self) -> Nullable<Offset16> {
986 self.min_coord_offset.get()
987 }
988
989 pub fn min_coord<'a>(&self, data: FontData<'a>) -> Option<Result<BaseCoord<'a>, ReadError>> {
995 self.min_coord_offset().resolve(data)
996 }
997
998 pub fn max_coord_offset(&self) -> Nullable<Offset16> {
1001 self.max_coord_offset.get()
1002 }
1003
1004 pub fn max_coord<'a>(&self, data: FontData<'a>) -> Option<Result<BaseCoord<'a>, ReadError>> {
1010 self.max_coord_offset().resolve(data)
1011 }
1012}
1013
1014impl FixedSize for FeatMinMaxRecord {
1015 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
1016}
1017
1018#[cfg(feature = "experimental_traverse")]
1019impl<'a> SomeRecord<'a> for FeatMinMaxRecord {
1020 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1021 RecordResolver {
1022 name: "FeatMinMaxRecord",
1023 get_field: Box::new(move |idx, _data| match idx {
1024 0usize => Some(Field::new("feature_table_tag", self.feature_table_tag())),
1025 1usize => Some(Field::new(
1026 "min_coord_offset",
1027 FieldType::offset(self.min_coord_offset(), self.min_coord(_data)),
1028 )),
1029 2usize => Some(Field::new(
1030 "max_coord_offset",
1031 FieldType::offset(self.max_coord_offset(), self.max_coord(_data)),
1032 )),
1033 _ => None,
1034 }),
1035 data,
1036 }
1037 }
1038}
1039
1040#[derive(Clone)]
1041pub enum BaseCoord<'a> {
1042 Format1(BaseCoordFormat1<'a>),
1043 Format2(BaseCoordFormat2<'a>),
1044 Format3(BaseCoordFormat3<'a>),
1045}
1046
1047impl Default for BaseCoord<'_> {
1048 fn default() -> Self {
1049 Self::Format1(Default::default())
1050 }
1051}
1052
1053impl<'a> BaseCoord<'a> {
1054 pub fn offset_data(&self) -> FontData<'a> {
1056 match self {
1057 Self::Format1(item) => item.offset_data(),
1058 Self::Format2(item) => item.offset_data(),
1059 Self::Format3(item) => item.offset_data(),
1060 }
1061 }
1062
1063 pub fn base_coord_format(&self) -> u16 {
1065 match self {
1066 Self::Format1(item) => item.base_coord_format(),
1067 Self::Format2(item) => item.base_coord_format(),
1068 Self::Format3(item) => item.base_coord_format(),
1069 }
1070 }
1071
1072 pub fn coordinate(&self) -> i16 {
1074 match self {
1075 Self::Format1(item) => item.coordinate(),
1076 Self::Format2(item) => item.coordinate(),
1077 Self::Format3(item) => item.coordinate(),
1078 }
1079 }
1080}
1081
1082impl<'a> FontRead<'a> for BaseCoord<'a> {
1083 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1084 let format: u16 = data.read_at(0usize)?;
1085 match format {
1086 BaseCoordFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1087 BaseCoordFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1088 BaseCoordFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
1089 other => Err(ReadError::InvalidFormat(other.into())),
1090 }
1091 }
1092}
1093
1094impl<'a> MinByteRange<'a> for BaseCoord<'a> {
1095 fn min_byte_range(&self) -> Range<usize> {
1096 match self {
1097 Self::Format1(item) => item.min_byte_range(),
1098 Self::Format2(item) => item.min_byte_range(),
1099 Self::Format3(item) => item.min_byte_range(),
1100 }
1101 }
1102 fn min_table_bytes(&self) -> &'a [u8] {
1103 match self {
1104 Self::Format1(item) => item.min_table_bytes(),
1105 Self::Format2(item) => item.min_table_bytes(),
1106 Self::Format3(item) => item.min_table_bytes(),
1107 }
1108 }
1109}
1110
1111#[cfg(feature = "experimental_traverse")]
1112impl<'a> BaseCoord<'a> {
1113 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1114 match self {
1115 Self::Format1(table) => table,
1116 Self::Format2(table) => table,
1117 Self::Format3(table) => table,
1118 }
1119 }
1120}
1121
1122#[cfg(feature = "experimental_traverse")]
1123impl std::fmt::Debug for BaseCoord<'_> {
1124 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1125 self.dyn_inner().fmt(f)
1126 }
1127}
1128
1129#[cfg(feature = "experimental_traverse")]
1130impl<'a> SomeTable<'a> for BaseCoord<'a> {
1131 fn type_name(&self) -> &str {
1132 self.dyn_inner().type_name()
1133 }
1134 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1135 self.dyn_inner().get_field(idx)
1136 }
1137}
1138
1139impl Format<u16> for BaseCoordFormat1<'_> {
1140 const FORMAT: u16 = 1;
1141}
1142
1143impl<'a> MinByteRange<'a> for BaseCoordFormat1<'a> {
1144 fn min_byte_range(&self) -> Range<usize> {
1145 0..self.coordinate_byte_range().end
1146 }
1147 fn min_table_bytes(&self) -> &'a [u8] {
1148 let range = self.min_byte_range();
1149 self.data.as_bytes().get(range).unwrap_or_default()
1150 }
1151}
1152
1153impl<'a> FontRead<'a> for BaseCoordFormat1<'a> {
1154 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1155 #[allow(clippy::absurd_extreme_comparisons)]
1156 if data.len() < Self::MIN_SIZE {
1157 return Err(ReadError::OutOfBounds);
1158 }
1159 Ok(Self { data })
1160 }
1161}
1162
1163#[derive(Clone)]
1165pub struct BaseCoordFormat1<'a> {
1166 data: FontData<'a>,
1167}
1168
1169#[allow(clippy::needless_lifetimes)]
1170impl<'a> BaseCoordFormat1<'a> {
1171 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
1172 basic_table_impls!(impl_the_methods);
1173
1174 pub fn base_coord_format(&self) -> u16 {
1176 let range = self.base_coord_format_byte_range();
1177 self.data.read_at(range.start).ok().unwrap()
1178 }
1179
1180 pub fn coordinate(&self) -> i16 {
1182 let range = self.coordinate_byte_range();
1183 self.data.read_at(range.start).ok().unwrap()
1184 }
1185
1186 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1187 let start = 0;
1188 start..start + u16::RAW_BYTE_LEN
1189 }
1190
1191 pub fn coordinate_byte_range(&self) -> Range<usize> {
1192 let start = self.base_coord_format_byte_range().end;
1193 start..start + i16::RAW_BYTE_LEN
1194 }
1195}
1196
1197const _: () = assert!(FontData::default_data_long_enough(
1198 BaseCoordFormat1::MIN_SIZE
1199));
1200
1201impl Default for BaseCoordFormat1<'_> {
1202 fn default() -> Self {
1203 Self {
1204 data: FontData::default_format_1_u16_table_data(),
1205 }
1206 }
1207}
1208
1209#[cfg(feature = "experimental_traverse")]
1210impl<'a> SomeTable<'a> for BaseCoordFormat1<'a> {
1211 fn type_name(&self) -> &str {
1212 "BaseCoordFormat1"
1213 }
1214 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1215 match idx {
1216 0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1217 1usize => Some(Field::new("coordinate", self.coordinate())),
1218 _ => None,
1219 }
1220 }
1221}
1222
1223#[cfg(feature = "experimental_traverse")]
1224#[allow(clippy::needless_lifetimes)]
1225impl<'a> std::fmt::Debug for BaseCoordFormat1<'a> {
1226 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1227 (self as &dyn SomeTable<'a>).fmt(f)
1228 }
1229}
1230
1231impl Format<u16> for BaseCoordFormat2<'_> {
1232 const FORMAT: u16 = 2;
1233}
1234
1235impl<'a> MinByteRange<'a> for BaseCoordFormat2<'a> {
1236 fn min_byte_range(&self) -> Range<usize> {
1237 0..self.base_coord_point_byte_range().end
1238 }
1239 fn min_table_bytes(&self) -> &'a [u8] {
1240 let range = self.min_byte_range();
1241 self.data.as_bytes().get(range).unwrap_or_default()
1242 }
1243}
1244
1245impl<'a> FontRead<'a> for BaseCoordFormat2<'a> {
1246 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1247 #[allow(clippy::absurd_extreme_comparisons)]
1248 if data.len() < Self::MIN_SIZE {
1249 return Err(ReadError::OutOfBounds);
1250 }
1251 Ok(Self { data })
1252 }
1253}
1254
1255#[derive(Clone)]
1257pub struct BaseCoordFormat2<'a> {
1258 data: FontData<'a>,
1259}
1260
1261#[allow(clippy::needless_lifetimes)]
1262impl<'a> BaseCoordFormat2<'a> {
1263 pub const MIN_SIZE: usize =
1264 (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1265 basic_table_impls!(impl_the_methods);
1266
1267 pub fn base_coord_format(&self) -> u16 {
1269 let range = self.base_coord_format_byte_range();
1270 self.data.read_at(range.start).ok().unwrap()
1271 }
1272
1273 pub fn coordinate(&self) -> i16 {
1275 let range = self.coordinate_byte_range();
1276 self.data.read_at(range.start).ok().unwrap()
1277 }
1278
1279 pub fn reference_glyph(&self) -> u16 {
1281 let range = self.reference_glyph_byte_range();
1282 self.data.read_at(range.start).ok().unwrap()
1283 }
1284
1285 pub fn base_coord_point(&self) -> u16 {
1287 let range = self.base_coord_point_byte_range();
1288 self.data.read_at(range.start).ok().unwrap()
1289 }
1290
1291 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1292 let start = 0;
1293 start..start + u16::RAW_BYTE_LEN
1294 }
1295
1296 pub fn coordinate_byte_range(&self) -> Range<usize> {
1297 let start = self.base_coord_format_byte_range().end;
1298 start..start + i16::RAW_BYTE_LEN
1299 }
1300
1301 pub fn reference_glyph_byte_range(&self) -> Range<usize> {
1302 let start = self.coordinate_byte_range().end;
1303 start..start + u16::RAW_BYTE_LEN
1304 }
1305
1306 pub fn base_coord_point_byte_range(&self) -> Range<usize> {
1307 let start = self.reference_glyph_byte_range().end;
1308 start..start + u16::RAW_BYTE_LEN
1309 }
1310}
1311
1312#[cfg(feature = "experimental_traverse")]
1313impl<'a> SomeTable<'a> for BaseCoordFormat2<'a> {
1314 fn type_name(&self) -> &str {
1315 "BaseCoordFormat2"
1316 }
1317 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1318 match idx {
1319 0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1320 1usize => Some(Field::new("coordinate", self.coordinate())),
1321 2usize => Some(Field::new("reference_glyph", self.reference_glyph())),
1322 3usize => Some(Field::new("base_coord_point", self.base_coord_point())),
1323 _ => None,
1324 }
1325 }
1326}
1327
1328#[cfg(feature = "experimental_traverse")]
1329#[allow(clippy::needless_lifetimes)]
1330impl<'a> std::fmt::Debug for BaseCoordFormat2<'a> {
1331 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1332 (self as &dyn SomeTable<'a>).fmt(f)
1333 }
1334}
1335
1336impl Format<u16> for BaseCoordFormat3<'_> {
1337 const FORMAT: u16 = 3;
1338}
1339
1340impl<'a> MinByteRange<'a> for BaseCoordFormat3<'a> {
1341 fn min_byte_range(&self) -> Range<usize> {
1342 0..self.device_offset_byte_range().end
1343 }
1344 fn min_table_bytes(&self) -> &'a [u8] {
1345 let range = self.min_byte_range();
1346 self.data.as_bytes().get(range).unwrap_or_default()
1347 }
1348}
1349
1350impl<'a> FontRead<'a> for BaseCoordFormat3<'a> {
1351 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1352 #[allow(clippy::absurd_extreme_comparisons)]
1353 if data.len() < Self::MIN_SIZE {
1354 return Err(ReadError::OutOfBounds);
1355 }
1356 Ok(Self { data })
1357 }
1358}
1359
1360#[derive(Clone)]
1362pub struct BaseCoordFormat3<'a> {
1363 data: FontData<'a>,
1364}
1365
1366#[allow(clippy::needless_lifetimes)]
1367impl<'a> BaseCoordFormat3<'a> {
1368 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
1369 basic_table_impls!(impl_the_methods);
1370
1371 pub fn base_coord_format(&self) -> u16 {
1373 let range = self.base_coord_format_byte_range();
1374 self.data.read_at(range.start).ok().unwrap()
1375 }
1376
1377 pub fn coordinate(&self) -> i16 {
1379 let range = self.coordinate_byte_range();
1380 self.data.read_at(range.start).ok().unwrap()
1381 }
1382
1383 pub fn device_offset(&self) -> Nullable<Offset16> {
1387 let range = self.device_offset_byte_range();
1388 self.data.read_at(range.start).ok().unwrap()
1389 }
1390
1391 pub fn device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1393 let data = self.data;
1394 self.device_offset().resolve(data)
1395 }
1396
1397 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1398 let start = 0;
1399 start..start + u16::RAW_BYTE_LEN
1400 }
1401
1402 pub fn coordinate_byte_range(&self) -> Range<usize> {
1403 let start = self.base_coord_format_byte_range().end;
1404 start..start + i16::RAW_BYTE_LEN
1405 }
1406
1407 pub fn device_offset_byte_range(&self) -> Range<usize> {
1408 let start = self.coordinate_byte_range().end;
1409 start..start + Offset16::RAW_BYTE_LEN
1410 }
1411}
1412
1413#[cfg(feature = "experimental_traverse")]
1414impl<'a> SomeTable<'a> for BaseCoordFormat3<'a> {
1415 fn type_name(&self) -> &str {
1416 "BaseCoordFormat3"
1417 }
1418 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1419 match idx {
1420 0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1421 1usize => Some(Field::new("coordinate", self.coordinate())),
1422 2usize => Some(Field::new(
1423 "device_offset",
1424 FieldType::offset(self.device_offset(), self.device()),
1425 )),
1426 _ => None,
1427 }
1428 }
1429}
1430
1431#[cfg(feature = "experimental_traverse")]
1432#[allow(clippy::needless_lifetimes)]
1433impl<'a> std::fmt::Debug for BaseCoordFormat3<'a> {
1434 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1435 (self as &dyn SomeTable<'a>).fmt(f)
1436 }
1437}