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 + (base_tag_count as usize).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..start + (base_script_count as usize).saturating_mul(BaseScriptRecord::RAW_BYTE_LEN)
403 }
404}
405
406const _: () = assert!(FontData::default_data_long_enough(BaseScriptList::MIN_SIZE));
407
408impl Default for BaseScriptList<'_> {
409 fn default() -> Self {
410 Self {
411 data: FontData::default_table_data(),
412 }
413 }
414}
415
416#[cfg(feature = "experimental_traverse")]
417impl<'a> SomeTable<'a> for BaseScriptList<'a> {
418 fn type_name(&self) -> &str {
419 "BaseScriptList"
420 }
421 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
422 match idx {
423 0usize => Some(Field::new("base_script_count", self.base_script_count())),
424 1usize => Some(Field::new(
425 "base_script_records",
426 traversal::FieldType::array_of_records(
427 stringify!(BaseScriptRecord),
428 self.base_script_records(),
429 self.offset_data(),
430 ),
431 )),
432 _ => None,
433 }
434 }
435}
436
437#[cfg(feature = "experimental_traverse")]
438#[allow(clippy::needless_lifetimes)]
439impl<'a> std::fmt::Debug for BaseScriptList<'a> {
440 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
441 (self as &dyn SomeTable<'a>).fmt(f)
442 }
443}
444
445#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
447#[repr(C)]
448#[repr(packed)]
449pub struct BaseScriptRecord {
450 pub base_script_tag: BigEndian<Tag>,
452 pub base_script_offset: BigEndian<Offset16>,
454}
455
456impl BaseScriptRecord {
457 pub fn base_script_tag(&self) -> Tag {
459 self.base_script_tag.get()
460 }
461
462 pub fn base_script_offset(&self) -> Offset16 {
464 self.base_script_offset.get()
465 }
466
467 pub fn base_script<'a>(&self, data: FontData<'a>) -> Result<BaseScript<'a>, ReadError> {
472 self.base_script_offset().resolve(data)
473 }
474}
475
476impl FixedSize for BaseScriptRecord {
477 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
478}
479
480#[cfg(feature = "experimental_traverse")]
481impl<'a> SomeRecord<'a> for BaseScriptRecord {
482 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
483 RecordResolver {
484 name: "BaseScriptRecord",
485 get_field: Box::new(move |idx, _data| match idx {
486 0usize => Some(Field::new("base_script_tag", self.base_script_tag())),
487 1usize => Some(Field::new(
488 "base_script_offset",
489 FieldType::offset(self.base_script_offset(), self.base_script(_data)),
490 )),
491 _ => None,
492 }),
493 data,
494 }
495 }
496}
497
498impl<'a> MinByteRange<'a> for BaseScript<'a> {
499 fn min_byte_range(&self) -> Range<usize> {
500 0..self.base_lang_sys_records_byte_range().end
501 }
502 fn min_table_bytes(&self) -> &'a [u8] {
503 let range = self.min_byte_range();
504 self.data.as_bytes().get(range).unwrap_or_default()
505 }
506}
507
508impl<'a> FontRead<'a> for BaseScript<'a> {
509 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
510 #[allow(clippy::absurd_extreme_comparisons)]
511 if data.len() < Self::MIN_SIZE {
512 return Err(ReadError::OutOfBounds);
513 }
514 Ok(Self { data })
515 }
516}
517
518#[derive(Clone)]
520pub struct BaseScript<'a> {
521 data: FontData<'a>,
522}
523
524#[allow(clippy::needless_lifetimes)]
525impl<'a> BaseScript<'a> {
526 pub const MIN_SIZE: usize =
527 (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
528 basic_table_impls!(impl_the_methods);
529
530 pub fn base_values_offset(&self) -> Nullable<Offset16> {
532 let range = self.base_values_offset_byte_range();
533 self.data.read_at(range.start).ok().unwrap()
534 }
535
536 pub fn base_values(&self) -> Option<Result<BaseValues<'a>, ReadError>> {
538 let data = self.data;
539 self.base_values_offset().resolve(data)
540 }
541
542 pub fn default_min_max_offset(&self) -> Nullable<Offset16> {
544 let range = self.default_min_max_offset_byte_range();
545 self.data.read_at(range.start).ok().unwrap()
546 }
547
548 pub fn default_min_max(&self) -> Option<Result<MinMax<'a>, ReadError>> {
550 let data = self.data;
551 self.default_min_max_offset().resolve(data)
552 }
553
554 pub fn base_lang_sys_count(&self) -> u16 {
556 let range = self.base_lang_sys_count_byte_range();
557 self.data.read_at(range.start).ok().unwrap()
558 }
559
560 pub fn base_lang_sys_records(&self) -> &'a [BaseLangSysRecord] {
563 let range = self.base_lang_sys_records_byte_range();
564 self.data.read_array(range).ok().unwrap_or_default()
565 }
566
567 pub fn base_values_offset_byte_range(&self) -> Range<usize> {
568 let start = 0;
569 start..start + Offset16::RAW_BYTE_LEN
570 }
571
572 pub fn default_min_max_offset_byte_range(&self) -> Range<usize> {
573 let start = self.base_values_offset_byte_range().end;
574 start..start + Offset16::RAW_BYTE_LEN
575 }
576
577 pub fn base_lang_sys_count_byte_range(&self) -> Range<usize> {
578 let start = self.default_min_max_offset_byte_range().end;
579 start..start + u16::RAW_BYTE_LEN
580 }
581
582 pub fn base_lang_sys_records_byte_range(&self) -> Range<usize> {
583 let base_lang_sys_count = self.base_lang_sys_count();
584 let start = self.base_lang_sys_count_byte_range().end;
585 start
586 ..start + (base_lang_sys_count as usize).saturating_mul(BaseLangSysRecord::RAW_BYTE_LEN)
587 }
588}
589
590const _: () = assert!(FontData::default_data_long_enough(BaseScript::MIN_SIZE));
591
592impl Default for BaseScript<'_> {
593 fn default() -> Self {
594 Self {
595 data: FontData::default_table_data(),
596 }
597 }
598}
599
600#[cfg(feature = "experimental_traverse")]
601impl<'a> SomeTable<'a> for BaseScript<'a> {
602 fn type_name(&self) -> &str {
603 "BaseScript"
604 }
605 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
606 match idx {
607 0usize => Some(Field::new(
608 "base_values_offset",
609 FieldType::offset(self.base_values_offset(), self.base_values()),
610 )),
611 1usize => Some(Field::new(
612 "default_min_max_offset",
613 FieldType::offset(self.default_min_max_offset(), self.default_min_max()),
614 )),
615 2usize => Some(Field::new(
616 "base_lang_sys_count",
617 self.base_lang_sys_count(),
618 )),
619 3usize => Some(Field::new(
620 "base_lang_sys_records",
621 traversal::FieldType::array_of_records(
622 stringify!(BaseLangSysRecord),
623 self.base_lang_sys_records(),
624 self.offset_data(),
625 ),
626 )),
627 _ => None,
628 }
629 }
630}
631
632#[cfg(feature = "experimental_traverse")]
633#[allow(clippy::needless_lifetimes)]
634impl<'a> std::fmt::Debug for BaseScript<'a> {
635 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
636 (self as &dyn SomeTable<'a>).fmt(f)
637 }
638}
639
640#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
642#[repr(C)]
643#[repr(packed)]
644pub struct BaseLangSysRecord {
645 pub base_lang_sys_tag: BigEndian<Tag>,
647 pub min_max_offset: BigEndian<Offset16>,
649}
650
651impl BaseLangSysRecord {
652 pub fn base_lang_sys_tag(&self) -> Tag {
654 self.base_lang_sys_tag.get()
655 }
656
657 pub fn min_max_offset(&self) -> Offset16 {
659 self.min_max_offset.get()
660 }
661
662 pub fn min_max<'a>(&self, data: FontData<'a>) -> Result<MinMax<'a>, ReadError> {
667 self.min_max_offset().resolve(data)
668 }
669}
670
671impl FixedSize for BaseLangSysRecord {
672 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
673}
674
675#[cfg(feature = "experimental_traverse")]
676impl<'a> SomeRecord<'a> for BaseLangSysRecord {
677 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
678 RecordResolver {
679 name: "BaseLangSysRecord",
680 get_field: Box::new(move |idx, _data| match idx {
681 0usize => Some(Field::new("base_lang_sys_tag", self.base_lang_sys_tag())),
682 1usize => Some(Field::new(
683 "min_max_offset",
684 FieldType::offset(self.min_max_offset(), self.min_max(_data)),
685 )),
686 _ => None,
687 }),
688 data,
689 }
690 }
691}
692
693impl<'a> MinByteRange<'a> for BaseValues<'a> {
694 fn min_byte_range(&self) -> Range<usize> {
695 0..self.base_coord_offsets_byte_range().end
696 }
697 fn min_table_bytes(&self) -> &'a [u8] {
698 let range = self.min_byte_range();
699 self.data.as_bytes().get(range).unwrap_or_default()
700 }
701}
702
703impl<'a> FontRead<'a> for BaseValues<'a> {
704 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
705 #[allow(clippy::absurd_extreme_comparisons)]
706 if data.len() < Self::MIN_SIZE {
707 return Err(ReadError::OutOfBounds);
708 }
709 Ok(Self { data })
710 }
711}
712
713#[derive(Clone)]
715pub struct BaseValues<'a> {
716 data: FontData<'a>,
717}
718
719#[allow(clippy::needless_lifetimes)]
720impl<'a> BaseValues<'a> {
721 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
722 basic_table_impls!(impl_the_methods);
723
724 pub fn default_baseline_index(&self) -> u16 {
728 let range = self.default_baseline_index_byte_range();
729 self.data.read_at(range.start).ok().unwrap()
730 }
731
732 pub fn base_coord_count(&self) -> u16 {
735 let range = self.base_coord_count_byte_range();
736 self.data.read_at(range.start).ok().unwrap()
737 }
738
739 pub fn base_coord_offsets(&self) -> &'a [BigEndian<Offset16>] {
743 let range = self.base_coord_offsets_byte_range();
744 self.data.read_array(range).ok().unwrap_or_default()
745 }
746
747 pub fn base_coords(&self) -> ArrayOfOffsets<'a, BaseCoord<'a>, Offset16> {
749 let data = self.data;
750 let offsets = self.base_coord_offsets();
751 ArrayOfOffsets::new(offsets, data, ())
752 }
753
754 pub fn default_baseline_index_byte_range(&self) -> Range<usize> {
755 let start = 0;
756 start..start + u16::RAW_BYTE_LEN
757 }
758
759 pub fn base_coord_count_byte_range(&self) -> Range<usize> {
760 let start = self.default_baseline_index_byte_range().end;
761 start..start + u16::RAW_BYTE_LEN
762 }
763
764 pub fn base_coord_offsets_byte_range(&self) -> Range<usize> {
765 let base_coord_count = self.base_coord_count();
766 let start = self.base_coord_count_byte_range().end;
767 start..start + (base_coord_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
768 }
769}
770
771const _: () = assert!(FontData::default_data_long_enough(BaseValues::MIN_SIZE));
772
773impl Default for BaseValues<'_> {
774 fn default() -> Self {
775 Self {
776 data: FontData::default_table_data(),
777 }
778 }
779}
780
781#[cfg(feature = "experimental_traverse")]
782impl<'a> SomeTable<'a> for BaseValues<'a> {
783 fn type_name(&self) -> &str {
784 "BaseValues"
785 }
786 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
787 match idx {
788 0usize => Some(Field::new(
789 "default_baseline_index",
790 self.default_baseline_index(),
791 )),
792 1usize => Some(Field::new("base_coord_count", self.base_coord_count())),
793 2usize => Some(Field::new(
794 "base_coord_offsets",
795 FieldType::from(self.base_coords()),
796 )),
797 _ => None,
798 }
799 }
800}
801
802#[cfg(feature = "experimental_traverse")]
803#[allow(clippy::needless_lifetimes)]
804impl<'a> std::fmt::Debug for BaseValues<'a> {
805 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
806 (self as &dyn SomeTable<'a>).fmt(f)
807 }
808}
809
810impl<'a> MinByteRange<'a> for MinMax<'a> {
811 fn min_byte_range(&self) -> Range<usize> {
812 0..self.feat_min_max_records_byte_range().end
813 }
814 fn min_table_bytes(&self) -> &'a [u8] {
815 let range = self.min_byte_range();
816 self.data.as_bytes().get(range).unwrap_or_default()
817 }
818}
819
820impl<'a> FontRead<'a> for MinMax<'a> {
821 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
822 #[allow(clippy::absurd_extreme_comparisons)]
823 if data.len() < Self::MIN_SIZE {
824 return Err(ReadError::OutOfBounds);
825 }
826 Ok(Self { data })
827 }
828}
829
830#[derive(Clone)]
832pub struct MinMax<'a> {
833 data: FontData<'a>,
834}
835
836#[allow(clippy::needless_lifetimes)]
837impl<'a> MinMax<'a> {
838 pub const MIN_SIZE: usize =
839 (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
840 basic_table_impls!(impl_the_methods);
841
842 pub fn min_coord_offset(&self) -> Nullable<Offset16> {
845 let range = self.min_coord_offset_byte_range();
846 self.data.read_at(range.start).ok().unwrap()
847 }
848
849 pub fn min_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
851 let data = self.data;
852 self.min_coord_offset().resolve(data)
853 }
854
855 pub fn max_coord_offset(&self) -> Nullable<Offset16> {
858 let range = self.max_coord_offset_byte_range();
859 self.data.read_at(range.start).ok().unwrap()
860 }
861
862 pub fn max_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
864 let data = self.data;
865 self.max_coord_offset().resolve(data)
866 }
867
868 pub fn feat_min_max_count(&self) -> u16 {
870 let range = self.feat_min_max_count_byte_range();
871 self.data.read_at(range.start).ok().unwrap()
872 }
873
874 pub fn feat_min_max_records(&self) -> &'a [FeatMinMaxRecord] {
877 let range = self.feat_min_max_records_byte_range();
878 self.data.read_array(range).ok().unwrap_or_default()
879 }
880
881 pub fn min_coord_offset_byte_range(&self) -> Range<usize> {
882 let start = 0;
883 start..start + Offset16::RAW_BYTE_LEN
884 }
885
886 pub fn max_coord_offset_byte_range(&self) -> Range<usize> {
887 let start = self.min_coord_offset_byte_range().end;
888 start..start + Offset16::RAW_BYTE_LEN
889 }
890
891 pub fn feat_min_max_count_byte_range(&self) -> Range<usize> {
892 let start = self.max_coord_offset_byte_range().end;
893 start..start + u16::RAW_BYTE_LEN
894 }
895
896 pub fn feat_min_max_records_byte_range(&self) -> Range<usize> {
897 let feat_min_max_count = self.feat_min_max_count();
898 let start = self.feat_min_max_count_byte_range().end;
899 start..start + (feat_min_max_count as usize).saturating_mul(FeatMinMaxRecord::RAW_BYTE_LEN)
900 }
901}
902
903const _: () = assert!(FontData::default_data_long_enough(MinMax::MIN_SIZE));
904
905impl Default for MinMax<'_> {
906 fn default() -> Self {
907 Self {
908 data: FontData::default_table_data(),
909 }
910 }
911}
912
913#[cfg(feature = "experimental_traverse")]
914impl<'a> SomeTable<'a> for MinMax<'a> {
915 fn type_name(&self) -> &str {
916 "MinMax"
917 }
918 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
919 match idx {
920 0usize => Some(Field::new(
921 "min_coord_offset",
922 FieldType::offset(self.min_coord_offset(), self.min_coord()),
923 )),
924 1usize => Some(Field::new(
925 "max_coord_offset",
926 FieldType::offset(self.max_coord_offset(), self.max_coord()),
927 )),
928 2usize => Some(Field::new("feat_min_max_count", self.feat_min_max_count())),
929 3usize => Some(Field::new(
930 "feat_min_max_records",
931 traversal::FieldType::array_of_records(
932 stringify!(FeatMinMaxRecord),
933 self.feat_min_max_records(),
934 self.offset_data(),
935 ),
936 )),
937 _ => None,
938 }
939 }
940}
941
942#[cfg(feature = "experimental_traverse")]
943#[allow(clippy::needless_lifetimes)]
944impl<'a> std::fmt::Debug for MinMax<'a> {
945 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
946 (self as &dyn SomeTable<'a>).fmt(f)
947 }
948}
949
950#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
952#[repr(C)]
953#[repr(packed)]
954pub struct FeatMinMaxRecord {
955 pub feature_table_tag: BigEndian<Tag>,
958 pub min_coord_offset: BigEndian<Nullable<Offset16>>,
961 pub max_coord_offset: BigEndian<Nullable<Offset16>>,
964}
965
966impl FeatMinMaxRecord {
967 pub fn feature_table_tag(&self) -> Tag {
970 self.feature_table_tag.get()
971 }
972
973 pub fn min_coord_offset(&self) -> Nullable<Offset16> {
976 self.min_coord_offset.get()
977 }
978
979 pub fn min_coord<'a>(&self, data: FontData<'a>) -> Option<Result<BaseCoord<'a>, ReadError>> {
985 self.min_coord_offset().resolve(data)
986 }
987
988 pub fn max_coord_offset(&self) -> Nullable<Offset16> {
991 self.max_coord_offset.get()
992 }
993
994 pub fn max_coord<'a>(&self, data: FontData<'a>) -> Option<Result<BaseCoord<'a>, ReadError>> {
1000 self.max_coord_offset().resolve(data)
1001 }
1002}
1003
1004impl FixedSize for FeatMinMaxRecord {
1005 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
1006}
1007
1008#[cfg(feature = "experimental_traverse")]
1009impl<'a> SomeRecord<'a> for FeatMinMaxRecord {
1010 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1011 RecordResolver {
1012 name: "FeatMinMaxRecord",
1013 get_field: Box::new(move |idx, _data| match idx {
1014 0usize => Some(Field::new("feature_table_tag", self.feature_table_tag())),
1015 1usize => Some(Field::new(
1016 "min_coord_offset",
1017 FieldType::offset(self.min_coord_offset(), self.min_coord(_data)),
1018 )),
1019 2usize => Some(Field::new(
1020 "max_coord_offset",
1021 FieldType::offset(self.max_coord_offset(), self.max_coord(_data)),
1022 )),
1023 _ => None,
1024 }),
1025 data,
1026 }
1027 }
1028}
1029
1030#[derive(Clone)]
1031pub enum BaseCoord<'a> {
1032 Format1(BaseCoordFormat1<'a>),
1033 Format2(BaseCoordFormat2<'a>),
1034 Format3(BaseCoordFormat3<'a>),
1035}
1036
1037impl Default for BaseCoord<'_> {
1038 fn default() -> Self {
1039 Self::Format1(Default::default())
1040 }
1041}
1042
1043impl<'a> BaseCoord<'a> {
1044 pub fn offset_data(&self) -> FontData<'a> {
1046 match self {
1047 Self::Format1(item) => item.offset_data(),
1048 Self::Format2(item) => item.offset_data(),
1049 Self::Format3(item) => item.offset_data(),
1050 }
1051 }
1052
1053 pub fn base_coord_format(&self) -> u16 {
1055 match self {
1056 Self::Format1(item) => item.base_coord_format(),
1057 Self::Format2(item) => item.base_coord_format(),
1058 Self::Format3(item) => item.base_coord_format(),
1059 }
1060 }
1061
1062 pub fn coordinate(&self) -> i16 {
1064 match self {
1065 Self::Format1(item) => item.coordinate(),
1066 Self::Format2(item) => item.coordinate(),
1067 Self::Format3(item) => item.coordinate(),
1068 }
1069 }
1070}
1071
1072impl<'a> FontRead<'a> for BaseCoord<'a> {
1073 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1074 let format: u16 = data.read_at(0usize)?;
1075 match format {
1076 BaseCoordFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1077 BaseCoordFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1078 BaseCoordFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
1079 other => Err(ReadError::InvalidFormat(other.into())),
1080 }
1081 }
1082}
1083
1084impl<'a> MinByteRange<'a> for BaseCoord<'a> {
1085 fn min_byte_range(&self) -> Range<usize> {
1086 match self {
1087 Self::Format1(item) => item.min_byte_range(),
1088 Self::Format2(item) => item.min_byte_range(),
1089 Self::Format3(item) => item.min_byte_range(),
1090 }
1091 }
1092 fn min_table_bytes(&self) -> &'a [u8] {
1093 match self {
1094 Self::Format1(item) => item.min_table_bytes(),
1095 Self::Format2(item) => item.min_table_bytes(),
1096 Self::Format3(item) => item.min_table_bytes(),
1097 }
1098 }
1099}
1100
1101#[cfg(feature = "experimental_traverse")]
1102impl<'a> BaseCoord<'a> {
1103 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1104 match self {
1105 Self::Format1(table) => table,
1106 Self::Format2(table) => table,
1107 Self::Format3(table) => table,
1108 }
1109 }
1110}
1111
1112#[cfg(feature = "experimental_traverse")]
1113impl std::fmt::Debug for BaseCoord<'_> {
1114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1115 self.dyn_inner().fmt(f)
1116 }
1117}
1118
1119#[cfg(feature = "experimental_traverse")]
1120impl<'a> SomeTable<'a> for BaseCoord<'a> {
1121 fn type_name(&self) -> &str {
1122 self.dyn_inner().type_name()
1123 }
1124 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1125 self.dyn_inner().get_field(idx)
1126 }
1127}
1128
1129impl Format<u16> for BaseCoordFormat1<'_> {
1130 const FORMAT: u16 = 1;
1131}
1132
1133impl<'a> MinByteRange<'a> for BaseCoordFormat1<'a> {
1134 fn min_byte_range(&self) -> Range<usize> {
1135 0..self.coordinate_byte_range().end
1136 }
1137 fn min_table_bytes(&self) -> &'a [u8] {
1138 let range = self.min_byte_range();
1139 self.data.as_bytes().get(range).unwrap_or_default()
1140 }
1141}
1142
1143impl<'a> FontRead<'a> for BaseCoordFormat1<'a> {
1144 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1145 #[allow(clippy::absurd_extreme_comparisons)]
1146 if data.len() < Self::MIN_SIZE {
1147 return Err(ReadError::OutOfBounds);
1148 }
1149 Ok(Self { data })
1150 }
1151}
1152
1153#[derive(Clone)]
1155pub struct BaseCoordFormat1<'a> {
1156 data: FontData<'a>,
1157}
1158
1159#[allow(clippy::needless_lifetimes)]
1160impl<'a> BaseCoordFormat1<'a> {
1161 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
1162 basic_table_impls!(impl_the_methods);
1163
1164 pub fn base_coord_format(&self) -> u16 {
1166 let range = self.base_coord_format_byte_range();
1167 self.data.read_at(range.start).ok().unwrap()
1168 }
1169
1170 pub fn coordinate(&self) -> i16 {
1172 let range = self.coordinate_byte_range();
1173 self.data.read_at(range.start).ok().unwrap()
1174 }
1175
1176 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1177 let start = 0;
1178 start..start + u16::RAW_BYTE_LEN
1179 }
1180
1181 pub fn coordinate_byte_range(&self) -> Range<usize> {
1182 let start = self.base_coord_format_byte_range().end;
1183 start..start + i16::RAW_BYTE_LEN
1184 }
1185}
1186
1187const _: () = assert!(FontData::default_data_long_enough(
1188 BaseCoordFormat1::MIN_SIZE
1189));
1190
1191impl Default for BaseCoordFormat1<'_> {
1192 fn default() -> Self {
1193 Self {
1194 data: FontData::default_format_1_u16_table_data(),
1195 }
1196 }
1197}
1198
1199#[cfg(feature = "experimental_traverse")]
1200impl<'a> SomeTable<'a> for BaseCoordFormat1<'a> {
1201 fn type_name(&self) -> &str {
1202 "BaseCoordFormat1"
1203 }
1204 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1205 match idx {
1206 0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1207 1usize => Some(Field::new("coordinate", self.coordinate())),
1208 _ => None,
1209 }
1210 }
1211}
1212
1213#[cfg(feature = "experimental_traverse")]
1214#[allow(clippy::needless_lifetimes)]
1215impl<'a> std::fmt::Debug for BaseCoordFormat1<'a> {
1216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1217 (self as &dyn SomeTable<'a>).fmt(f)
1218 }
1219}
1220
1221impl Format<u16> for BaseCoordFormat2<'_> {
1222 const FORMAT: u16 = 2;
1223}
1224
1225impl<'a> MinByteRange<'a> for BaseCoordFormat2<'a> {
1226 fn min_byte_range(&self) -> Range<usize> {
1227 0..self.base_coord_point_byte_range().end
1228 }
1229 fn min_table_bytes(&self) -> &'a [u8] {
1230 let range = self.min_byte_range();
1231 self.data.as_bytes().get(range).unwrap_or_default()
1232 }
1233}
1234
1235impl<'a> FontRead<'a> for BaseCoordFormat2<'a> {
1236 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1237 #[allow(clippy::absurd_extreme_comparisons)]
1238 if data.len() < Self::MIN_SIZE {
1239 return Err(ReadError::OutOfBounds);
1240 }
1241 Ok(Self { data })
1242 }
1243}
1244
1245#[derive(Clone)]
1247pub struct BaseCoordFormat2<'a> {
1248 data: FontData<'a>,
1249}
1250
1251#[allow(clippy::needless_lifetimes)]
1252impl<'a> BaseCoordFormat2<'a> {
1253 pub const MIN_SIZE: usize =
1254 (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1255 basic_table_impls!(impl_the_methods);
1256
1257 pub fn base_coord_format(&self) -> u16 {
1259 let range = self.base_coord_format_byte_range();
1260 self.data.read_at(range.start).ok().unwrap()
1261 }
1262
1263 pub fn coordinate(&self) -> i16 {
1265 let range = self.coordinate_byte_range();
1266 self.data.read_at(range.start).ok().unwrap()
1267 }
1268
1269 pub fn reference_glyph(&self) -> u16 {
1271 let range = self.reference_glyph_byte_range();
1272 self.data.read_at(range.start).ok().unwrap()
1273 }
1274
1275 pub fn base_coord_point(&self) -> u16 {
1277 let range = self.base_coord_point_byte_range();
1278 self.data.read_at(range.start).ok().unwrap()
1279 }
1280
1281 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1282 let start = 0;
1283 start..start + u16::RAW_BYTE_LEN
1284 }
1285
1286 pub fn coordinate_byte_range(&self) -> Range<usize> {
1287 let start = self.base_coord_format_byte_range().end;
1288 start..start + i16::RAW_BYTE_LEN
1289 }
1290
1291 pub fn reference_glyph_byte_range(&self) -> Range<usize> {
1292 let start = self.coordinate_byte_range().end;
1293 start..start + u16::RAW_BYTE_LEN
1294 }
1295
1296 pub fn base_coord_point_byte_range(&self) -> Range<usize> {
1297 let start = self.reference_glyph_byte_range().end;
1298 start..start + u16::RAW_BYTE_LEN
1299 }
1300}
1301
1302#[cfg(feature = "experimental_traverse")]
1303impl<'a> SomeTable<'a> for BaseCoordFormat2<'a> {
1304 fn type_name(&self) -> &str {
1305 "BaseCoordFormat2"
1306 }
1307 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1308 match idx {
1309 0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1310 1usize => Some(Field::new("coordinate", self.coordinate())),
1311 2usize => Some(Field::new("reference_glyph", self.reference_glyph())),
1312 3usize => Some(Field::new("base_coord_point", self.base_coord_point())),
1313 _ => None,
1314 }
1315 }
1316}
1317
1318#[cfg(feature = "experimental_traverse")]
1319#[allow(clippy::needless_lifetimes)]
1320impl<'a> std::fmt::Debug for BaseCoordFormat2<'a> {
1321 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1322 (self as &dyn SomeTable<'a>).fmt(f)
1323 }
1324}
1325
1326impl Format<u16> for BaseCoordFormat3<'_> {
1327 const FORMAT: u16 = 3;
1328}
1329
1330impl<'a> MinByteRange<'a> for BaseCoordFormat3<'a> {
1331 fn min_byte_range(&self) -> Range<usize> {
1332 0..self.device_offset_byte_range().end
1333 }
1334 fn min_table_bytes(&self) -> &'a [u8] {
1335 let range = self.min_byte_range();
1336 self.data.as_bytes().get(range).unwrap_or_default()
1337 }
1338}
1339
1340impl<'a> FontRead<'a> for BaseCoordFormat3<'a> {
1341 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1342 #[allow(clippy::absurd_extreme_comparisons)]
1343 if data.len() < Self::MIN_SIZE {
1344 return Err(ReadError::OutOfBounds);
1345 }
1346 Ok(Self { data })
1347 }
1348}
1349
1350#[derive(Clone)]
1352pub struct BaseCoordFormat3<'a> {
1353 data: FontData<'a>,
1354}
1355
1356#[allow(clippy::needless_lifetimes)]
1357impl<'a> BaseCoordFormat3<'a> {
1358 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
1359 basic_table_impls!(impl_the_methods);
1360
1361 pub fn base_coord_format(&self) -> u16 {
1363 let range = self.base_coord_format_byte_range();
1364 self.data.read_at(range.start).ok().unwrap()
1365 }
1366
1367 pub fn coordinate(&self) -> i16 {
1369 let range = self.coordinate_byte_range();
1370 self.data.read_at(range.start).ok().unwrap()
1371 }
1372
1373 pub fn device_offset(&self) -> Nullable<Offset16> {
1377 let range = self.device_offset_byte_range();
1378 self.data.read_at(range.start).ok().unwrap()
1379 }
1380
1381 pub fn device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1383 let data = self.data;
1384 self.device_offset().resolve(data)
1385 }
1386
1387 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1388 let start = 0;
1389 start..start + u16::RAW_BYTE_LEN
1390 }
1391
1392 pub fn coordinate_byte_range(&self) -> Range<usize> {
1393 let start = self.base_coord_format_byte_range().end;
1394 start..start + i16::RAW_BYTE_LEN
1395 }
1396
1397 pub fn device_offset_byte_range(&self) -> Range<usize> {
1398 let start = self.coordinate_byte_range().end;
1399 start..start + Offset16::RAW_BYTE_LEN
1400 }
1401}
1402
1403#[cfg(feature = "experimental_traverse")]
1404impl<'a> SomeTable<'a> for BaseCoordFormat3<'a> {
1405 fn type_name(&self) -> &str {
1406 "BaseCoordFormat3"
1407 }
1408 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1409 match idx {
1410 0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1411 1usize => Some(Field::new("coordinate", self.coordinate())),
1412 2usize => Some(Field::new(
1413 "device_offset",
1414 FieldType::offset(self.device_offset(), self.device()),
1415 )),
1416 _ => None,
1417 }
1418 }
1419}
1420
1421#[cfg(feature = "experimental_traverse")]
1422#[allow(clippy::needless_lifetimes)]
1423impl<'a> std::fmt::Debug for BaseCoordFormat3<'a> {
1424 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1425 (self as &dyn SomeTable<'a>).fmt(f)
1426 }
1427}