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.offset_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 ReadArgs for Base<'_> {
24 type Args = ();
25}
26
27impl<'a> FontRead<'a> for Base<'a> {
28 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
29 #[allow(clippy::absurd_extreme_comparisons)]
30 if data.len() < Self::MIN_SIZE {
31 return Err(ReadError::OutOfBounds);
32 }
33 let Some(data) = TableDataRef::new(data.as_bytes()) else {
34 return Err(ReadError::OutOfBounds);
35 };
36 Ok(Self { data })
37 }
38}
39
40#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
42#[repr(C, packed)]
43#[doc(hidden)]
44pub struct BaseFixedHeader {
45 pub version: BigEndian<MajorMinor>,
46 pub horiz_axis_offset: BigEndian<Nullable<Offset16>>,
47 pub vert_axis_offset: BigEndian<Nullable<Offset16>>,
48}
49
50#[allow(clippy::absurd_extreme_comparisons)]
51const _: () = assert!(std::mem::size_of::<BaseFixedHeader>() <= Base::MIN_SIZE);
52
53#[derive(Clone)]
55pub struct Base<'a> {
56 data: TableDataRef<'a, BaseFixedHeader>,
57}
58
59#[allow(clippy::needless_lifetimes)]
60impl<'a> Base<'a> {
61 pub const MIN_SIZE: usize =
62 (MajorMinor::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
63 basic_table_impls!(impl_the_methods);
64
65 pub fn version(&self) -> MajorMinor {
67 self.data.header().version.get()
68 }
69
70 pub fn horiz_axis_offset(&self) -> Nullable<Offset16> {
72 self.data.header().horiz_axis_offset.get()
73 }
74
75 pub fn horiz_axis(&self) -> Option<Result<Axis<'a>, ReadError>> {
77 let data = self.offset_data();
78 self.horiz_axis_offset().resolve(data)
79 }
80
81 pub fn vert_axis_offset(&self) -> Nullable<Offset16> {
83 self.data.header().vert_axis_offset.get()
84 }
85
86 pub fn vert_axis(&self) -> Option<Result<Axis<'a>, ReadError>> {
88 let data = self.offset_data();
89 self.vert_axis_offset().resolve(data)
90 }
91
92 pub fn item_var_store_offset(&self) -> Option<Nullable<Offset32>> {
94 let range = self.item_var_store_offset_byte_range();
95 (!range.is_empty())
96 .then(|| self.offset_data().read_at(range.start).ok())
97 .flatten()
98 }
99
100 pub fn item_var_store(&self) -> Option<Result<ItemVariationStore<'a>, ReadError>> {
102 let data = self.offset_data();
103 self.item_var_store_offset().map(|x| x.resolve(data))?
104 }
105
106 pub fn version_byte_range(&self) -> Range<usize> {
107 let start = 0;
108 let end = start + MajorMinor::RAW_BYTE_LEN;
109 start..end
110 }
111
112 pub fn horiz_axis_offset_byte_range(&self) -> Range<usize> {
113 let start = self.version_byte_range().end;
114 let end = start + Offset16::RAW_BYTE_LEN;
115 start..end
116 }
117
118 pub fn vert_axis_offset_byte_range(&self) -> Range<usize> {
119 let start = self.horiz_axis_offset_byte_range().end;
120 let end = start + Offset16::RAW_BYTE_LEN;
121 start..end
122 }
123
124 pub fn item_var_store_offset_byte_range(&self) -> Range<usize> {
125 let start = self.vert_axis_offset_byte_range().end;
126 let end = if self.version().compatible((1u16, 1u16)) {
127 start + Offset32::RAW_BYTE_LEN
128 } else {
129 start
130 };
131 start..end
132 }
133}
134
135const _: () = assert!(FontData::default_data_long_enough(Base::MIN_SIZE));
136
137impl Default for Base<'_> {
138 fn default() -> Self {
139 Self {
140 data: TableDataRef::new(FontData::default_table_data().as_bytes())
141 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
142 }
143 }
144}
145
146impl<'a> MinByteRange<'a> for Axis<'a> {
147 fn min_byte_range(&self) -> Range<usize> {
148 0..self.base_script_list_offset_byte_range().end
149 }
150 fn min_table_bytes(&self) -> &'a [u8] {
151 let range = self.min_byte_range();
152 self.offset_data().as_bytes().get(range).unwrap_or_default()
153 }
154}
155
156impl ReadArgs for Axis<'_> {
157 type Args = ();
158}
159
160impl<'a> FontRead<'a> for Axis<'a> {
161 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
162 #[allow(clippy::absurd_extreme_comparisons)]
163 if data.len() < Self::MIN_SIZE {
164 return Err(ReadError::OutOfBounds);
165 }
166 let Some(data) = TableDataRef::new(data.as_bytes()) else {
167 return Err(ReadError::OutOfBounds);
168 };
169 Ok(Self { data })
170 }
171}
172
173#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
175#[repr(C, packed)]
176#[doc(hidden)]
177pub struct AxisFixedHeader {
178 pub base_tag_list_offset: BigEndian<Nullable<Offset16>>,
179 pub base_script_list_offset: BigEndian<Offset16>,
180}
181
182#[allow(clippy::absurd_extreme_comparisons)]
183const _: () = assert!(std::mem::size_of::<AxisFixedHeader>() <= Axis::MIN_SIZE);
184
185#[derive(Clone)]
187pub struct Axis<'a> {
188 data: TableDataRef<'a, AxisFixedHeader>,
189}
190
191#[allow(clippy::needless_lifetimes)]
192impl<'a> Axis<'a> {
193 pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
194 basic_table_impls!(impl_the_methods);
195
196 pub fn base_tag_list_offset(&self) -> Nullable<Offset16> {
199 self.data.header().base_tag_list_offset.get()
200 }
201
202 pub fn base_tag_list(&self) -> Option<Result<BaseTagList<'a>, ReadError>> {
204 let data = self.offset_data();
205 self.base_tag_list_offset().resolve(data)
206 }
207
208 pub fn base_script_list_offset(&self) -> Offset16 {
210 self.data.header().base_script_list_offset.get()
211 }
212
213 pub fn base_script_list(&self) -> Result<BaseScriptList<'a>, ReadError> {
215 let data = self.offset_data();
216 self.base_script_list_offset().resolve(data)
217 }
218
219 pub fn base_tag_list_offset_byte_range(&self) -> Range<usize> {
220 let start = 0;
221 let end = start + Offset16::RAW_BYTE_LEN;
222 start..end
223 }
224
225 pub fn base_script_list_offset_byte_range(&self) -> Range<usize> {
226 let start = self.base_tag_list_offset_byte_range().end;
227 let end = start + Offset16::RAW_BYTE_LEN;
228 start..end
229 }
230}
231
232const _: () = assert!(FontData::default_data_long_enough(Axis::MIN_SIZE));
233
234impl Default for Axis<'_> {
235 fn default() -> Self {
236 Self {
237 data: TableDataRef::new(FontData::default_table_data().as_bytes())
238 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
239 }
240 }
241}
242
243impl<'a> MinByteRange<'a> for BaseTagList<'a> {
244 fn min_byte_range(&self) -> Range<usize> {
245 0..self.baseline_tags_byte_range().end
246 }
247 fn min_table_bytes(&self) -> &'a [u8] {
248 let range = self.min_byte_range();
249 self.offset_data().as_bytes().get(range).unwrap_or_default()
250 }
251}
252
253impl ReadArgs for BaseTagList<'_> {
254 type Args = ();
255}
256
257impl<'a> FontRead<'a> for BaseTagList<'a> {
258 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
259 #[allow(clippy::absurd_extreme_comparisons)]
260 if data.len() < Self::MIN_SIZE {
261 return Err(ReadError::OutOfBounds);
262 }
263 let Some(data) = TableDataRef::new(data.as_bytes()) else {
264 return Err(ReadError::OutOfBounds);
265 };
266 Ok(Self { data })
267 }
268}
269
270#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
272#[repr(C, packed)]
273#[doc(hidden)]
274pub struct BaseTagListFixedHeader {
275 pub base_tag_count: BigEndian<u16>,
276}
277
278#[allow(clippy::absurd_extreme_comparisons)]
279const _: () = assert!(std::mem::size_of::<BaseTagListFixedHeader>() <= BaseTagList::MIN_SIZE);
280
281#[derive(Clone)]
283pub struct BaseTagList<'a> {
284 data: TableDataRef<'a, BaseTagListFixedHeader>,
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 self.data.header().base_tag_count.get()
296 }
297
298 pub fn baseline_tags(&self) -> &'a [BigEndian<Tag>] {
301 let range = self.baseline_tags_byte_range();
302 self.offset_data()
303 .read_array(range)
304 .ok()
305 .unwrap_or_default()
306 }
307
308 pub fn base_tag_count_byte_range(&self) -> Range<usize> {
309 let start = 0;
310 let end = start + u16::RAW_BYTE_LEN;
311 start..end
312 }
313
314 pub fn baseline_tags_byte_range(&self) -> Range<usize> {
315 let base_tag_count = self.base_tag_count();
316 let start = self.base_tag_count_byte_range().end;
317 let end = start + (transforms::to_usize(base_tag_count)).saturating_mul(Tag::RAW_BYTE_LEN);
318 start..end
319 }
320}
321
322const _: () = assert!(FontData::default_data_long_enough(BaseTagList::MIN_SIZE));
323
324impl Default for BaseTagList<'_> {
325 fn default() -> Self {
326 Self {
327 data: TableDataRef::new(FontData::default_table_data().as_bytes())
328 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
329 }
330 }
331}
332
333impl<'a> MinByteRange<'a> for BaseScriptList<'a> {
334 fn min_byte_range(&self) -> Range<usize> {
335 0..self.base_script_records_byte_range().end
336 }
337 fn min_table_bytes(&self) -> &'a [u8] {
338 let range = self.min_byte_range();
339 self.offset_data().as_bytes().get(range).unwrap_or_default()
340 }
341}
342
343impl ReadArgs for BaseScriptList<'_> {
344 type Args = ();
345}
346
347impl<'a> FontRead<'a> for BaseScriptList<'a> {
348 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
349 #[allow(clippy::absurd_extreme_comparisons)]
350 if data.len() < Self::MIN_SIZE {
351 return Err(ReadError::OutOfBounds);
352 }
353 let Some(data) = TableDataRef::new(data.as_bytes()) else {
354 return Err(ReadError::OutOfBounds);
355 };
356 Ok(Self { data })
357 }
358}
359
360#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
362#[repr(C, packed)]
363#[doc(hidden)]
364pub struct BaseScriptListFixedHeader {
365 pub base_script_count: BigEndian<u16>,
366}
367
368#[allow(clippy::absurd_extreme_comparisons)]
369const _: () = assert!(std::mem::size_of::<BaseScriptListFixedHeader>() <= BaseScriptList::MIN_SIZE);
370
371#[derive(Clone)]
373pub struct BaseScriptList<'a> {
374 data: TableDataRef<'a, BaseScriptListFixedHeader>,
375}
376
377#[allow(clippy::needless_lifetimes)]
378impl<'a> BaseScriptList<'a> {
379 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
380 basic_table_impls!(impl_the_methods);
381
382 pub fn base_script_count(&self) -> u16 {
384 self.data.header().base_script_count.get()
385 }
386
387 pub fn base_script_records(&self) -> &'a [BaseScriptRecord] {
390 let range = self.base_script_records_byte_range();
391 self.offset_data()
392 .read_array(range)
393 .ok()
394 .unwrap_or_default()
395 }
396
397 pub fn base_script_count_byte_range(&self) -> Range<usize> {
398 let start = 0;
399 let end = start + u16::RAW_BYTE_LEN;
400 start..end
401 }
402
403 pub fn base_script_records_byte_range(&self) -> Range<usize> {
404 let base_script_count = self.base_script_count();
405 let start = self.base_script_count_byte_range().end;
406 let end = start
407 + (transforms::to_usize(base_script_count))
408 .saturating_mul(BaseScriptRecord::RAW_BYTE_LEN);
409 start..end
410 }
411}
412
413const _: () = assert!(FontData::default_data_long_enough(BaseScriptList::MIN_SIZE));
414
415impl Default for BaseScriptList<'_> {
416 fn default() -> Self {
417 Self {
418 data: TableDataRef::new(FontData::default_table_data().as_bytes())
419 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
420 }
421 }
422}
423
424#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
426#[repr(C)]
427#[repr(packed)]
428pub struct BaseScriptRecord {
429 pub base_script_tag: BigEndian<Tag>,
431 pub base_script_offset: BigEndian<Offset16>,
433}
434
435impl BaseScriptRecord {
436 pub fn base_script_tag(&self) -> Tag {
438 self.base_script_tag.get()
439 }
440
441 pub fn base_script_offset(&self) -> Offset16 {
443 self.base_script_offset.get()
444 }
445
446 pub fn base_script<'a>(&self, data: FontData<'a>) -> Result<BaseScript<'a>, ReadError> {
451 self.base_script_offset().resolve(data)
452 }
453}
454
455impl FixedSize for BaseScriptRecord {
456 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
457}
458
459impl<'a> MinByteRange<'a> for BaseScript<'a> {
460 fn min_byte_range(&self) -> Range<usize> {
461 0..self.base_lang_sys_records_byte_range().end
462 }
463 fn min_table_bytes(&self) -> &'a [u8] {
464 let range = self.min_byte_range();
465 self.offset_data().as_bytes().get(range).unwrap_or_default()
466 }
467}
468
469impl ReadArgs for BaseScript<'_> {
470 type Args = ();
471}
472
473impl<'a> FontRead<'a> for BaseScript<'a> {
474 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
475 #[allow(clippy::absurd_extreme_comparisons)]
476 if data.len() < Self::MIN_SIZE {
477 return Err(ReadError::OutOfBounds);
478 }
479 let Some(data) = TableDataRef::new(data.as_bytes()) else {
480 return Err(ReadError::OutOfBounds);
481 };
482 Ok(Self { data })
483 }
484}
485
486#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
488#[repr(C, packed)]
489#[doc(hidden)]
490pub struct BaseScriptFixedHeader {
491 pub base_values_offset: BigEndian<Nullable<Offset16>>,
492 pub default_min_max_offset: BigEndian<Nullable<Offset16>>,
493 pub base_lang_sys_count: BigEndian<u16>,
494}
495
496#[allow(clippy::absurd_extreme_comparisons)]
497const _: () = assert!(std::mem::size_of::<BaseScriptFixedHeader>() <= BaseScript::MIN_SIZE);
498
499#[derive(Clone)]
501pub struct BaseScript<'a> {
502 data: TableDataRef<'a, BaseScriptFixedHeader>,
503}
504
505#[allow(clippy::needless_lifetimes)]
506impl<'a> BaseScript<'a> {
507 pub const MIN_SIZE: usize =
508 (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
509 basic_table_impls!(impl_the_methods);
510
511 pub fn base_values_offset(&self) -> Nullable<Offset16> {
513 self.data.header().base_values_offset.get()
514 }
515
516 pub fn base_values(&self) -> Option<Result<BaseValues<'a>, ReadError>> {
518 let data = self.offset_data();
519 self.base_values_offset().resolve(data)
520 }
521
522 pub fn default_min_max_offset(&self) -> Nullable<Offset16> {
524 self.data.header().default_min_max_offset.get()
525 }
526
527 pub fn default_min_max(&self) -> Option<Result<MinMax<'a>, ReadError>> {
529 let data = self.offset_data();
530 self.default_min_max_offset().resolve(data)
531 }
532
533 pub fn base_lang_sys_count(&self) -> u16 {
535 self.data.header().base_lang_sys_count.get()
536 }
537
538 pub fn base_lang_sys_records(&self) -> &'a [BaseLangSysRecord] {
541 let range = self.base_lang_sys_records_byte_range();
542 self.offset_data()
543 .read_array(range)
544 .ok()
545 .unwrap_or_default()
546 }
547
548 pub fn base_values_offset_byte_range(&self) -> Range<usize> {
549 let start = 0;
550 let end = start + Offset16::RAW_BYTE_LEN;
551 start..end
552 }
553
554 pub fn default_min_max_offset_byte_range(&self) -> Range<usize> {
555 let start = self.base_values_offset_byte_range().end;
556 let end = start + Offset16::RAW_BYTE_LEN;
557 start..end
558 }
559
560 pub fn base_lang_sys_count_byte_range(&self) -> Range<usize> {
561 let start = self.default_min_max_offset_byte_range().end;
562 let end = start + u16::RAW_BYTE_LEN;
563 start..end
564 }
565
566 pub fn base_lang_sys_records_byte_range(&self) -> Range<usize> {
567 let base_lang_sys_count = self.base_lang_sys_count();
568 let start = self.base_lang_sys_count_byte_range().end;
569 let end = start
570 + (transforms::to_usize(base_lang_sys_count))
571 .saturating_mul(BaseLangSysRecord::RAW_BYTE_LEN);
572 start..end
573 }
574}
575
576const _: () = assert!(FontData::default_data_long_enough(BaseScript::MIN_SIZE));
577
578impl Default for BaseScript<'_> {
579 fn default() -> Self {
580 Self {
581 data: TableDataRef::new(FontData::default_table_data().as_bytes())
582 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
583 }
584 }
585}
586
587#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
589#[repr(C)]
590#[repr(packed)]
591pub struct BaseLangSysRecord {
592 pub base_lang_sys_tag: BigEndian<Tag>,
594 pub min_max_offset: BigEndian<Offset16>,
596}
597
598impl BaseLangSysRecord {
599 pub fn base_lang_sys_tag(&self) -> Tag {
601 self.base_lang_sys_tag.get()
602 }
603
604 pub fn min_max_offset(&self) -> Offset16 {
606 self.min_max_offset.get()
607 }
608
609 pub fn min_max<'a>(&self, data: FontData<'a>) -> Result<MinMax<'a>, ReadError> {
614 self.min_max_offset().resolve(data)
615 }
616}
617
618impl FixedSize for BaseLangSysRecord {
619 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
620}
621
622impl<'a> MinByteRange<'a> for BaseValues<'a> {
623 fn min_byte_range(&self) -> Range<usize> {
624 0..self.base_coord_offsets_byte_range().end
625 }
626 fn min_table_bytes(&self) -> &'a [u8] {
627 let range = self.min_byte_range();
628 self.offset_data().as_bytes().get(range).unwrap_or_default()
629 }
630}
631
632impl ReadArgs for BaseValues<'_> {
633 type Args = ();
634}
635
636impl<'a> FontRead<'a> for BaseValues<'a> {
637 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
638 #[allow(clippy::absurd_extreme_comparisons)]
639 if data.len() < Self::MIN_SIZE {
640 return Err(ReadError::OutOfBounds);
641 }
642 let Some(data) = TableDataRef::new(data.as_bytes()) else {
643 return Err(ReadError::OutOfBounds);
644 };
645 Ok(Self { data })
646 }
647}
648
649#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
651#[repr(C, packed)]
652#[doc(hidden)]
653pub struct BaseValuesFixedHeader {
654 pub default_baseline_index: BigEndian<u16>,
655 pub base_coord_count: BigEndian<u16>,
656}
657
658#[allow(clippy::absurd_extreme_comparisons)]
659const _: () = assert!(std::mem::size_of::<BaseValuesFixedHeader>() <= BaseValues::MIN_SIZE);
660
661#[derive(Clone)]
663pub struct BaseValues<'a> {
664 data: TableDataRef<'a, BaseValuesFixedHeader>,
665}
666
667#[allow(clippy::needless_lifetimes)]
668impl<'a> BaseValues<'a> {
669 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
670 basic_table_impls!(impl_the_methods);
671
672 pub fn default_baseline_index(&self) -> u16 {
676 self.data.header().default_baseline_index.get()
677 }
678
679 pub fn base_coord_count(&self) -> u16 {
682 self.data.header().base_coord_count.get()
683 }
684
685 pub fn base_coord_offsets(&self) -> &'a [BigEndian<Offset16>] {
689 let range = self.base_coord_offsets_byte_range();
690 self.offset_data()
691 .read_array(range)
692 .ok()
693 .unwrap_or_default()
694 }
695
696 pub fn base_coords(&self) -> ArrayOfOffsets<'a, BaseCoord<'a>, Offset16> {
698 let data = self.offset_data();
699 let offsets = self.base_coord_offsets();
700 ArrayOfOffsets::new(offsets, data, ())
701 }
702
703 pub fn default_baseline_index_byte_range(&self) -> Range<usize> {
704 let start = 0;
705 let end = start + u16::RAW_BYTE_LEN;
706 start..end
707 }
708
709 pub fn base_coord_count_byte_range(&self) -> Range<usize> {
710 let start = self.default_baseline_index_byte_range().end;
711 let end = start + u16::RAW_BYTE_LEN;
712 start..end
713 }
714
715 pub fn base_coord_offsets_byte_range(&self) -> Range<usize> {
716 let base_coord_count = self.base_coord_count();
717 let start = self.base_coord_count_byte_range().end;
718 let end =
719 start + (transforms::to_usize(base_coord_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
720 start..end
721 }
722}
723
724const _: () = assert!(FontData::default_data_long_enough(BaseValues::MIN_SIZE));
725
726impl Default for BaseValues<'_> {
727 fn default() -> Self {
728 Self {
729 data: TableDataRef::new(FontData::default_table_data().as_bytes())
730 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
731 }
732 }
733}
734
735impl<'a> MinByteRange<'a> for MinMax<'a> {
736 fn min_byte_range(&self) -> Range<usize> {
737 0..self.feat_min_max_records_byte_range().end
738 }
739 fn min_table_bytes(&self) -> &'a [u8] {
740 let range = self.min_byte_range();
741 self.offset_data().as_bytes().get(range).unwrap_or_default()
742 }
743}
744
745impl ReadArgs for MinMax<'_> {
746 type Args = ();
747}
748
749impl<'a> FontRead<'a> for MinMax<'a> {
750 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
751 #[allow(clippy::absurd_extreme_comparisons)]
752 if data.len() < Self::MIN_SIZE {
753 return Err(ReadError::OutOfBounds);
754 }
755 let Some(data) = TableDataRef::new(data.as_bytes()) else {
756 return Err(ReadError::OutOfBounds);
757 };
758 Ok(Self { data })
759 }
760}
761
762#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
764#[repr(C, packed)]
765#[doc(hidden)]
766pub struct MinMaxFixedHeader {
767 pub min_coord_offset: BigEndian<Nullable<Offset16>>,
768 pub max_coord_offset: BigEndian<Nullable<Offset16>>,
769 pub feat_min_max_count: BigEndian<u16>,
770}
771
772#[allow(clippy::absurd_extreme_comparisons)]
773const _: () = assert!(std::mem::size_of::<MinMaxFixedHeader>() <= MinMax::MIN_SIZE);
774
775#[derive(Clone)]
777pub struct MinMax<'a> {
778 data: TableDataRef<'a, MinMaxFixedHeader>,
779}
780
781#[allow(clippy::needless_lifetimes)]
782impl<'a> MinMax<'a> {
783 pub const MIN_SIZE: usize =
784 (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
785 basic_table_impls!(impl_the_methods);
786
787 pub fn min_coord_offset(&self) -> Nullable<Offset16> {
790 self.data.header().min_coord_offset.get()
791 }
792
793 pub fn min_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
795 let data = self.offset_data();
796 self.min_coord_offset().resolve(data)
797 }
798
799 pub fn max_coord_offset(&self) -> Nullable<Offset16> {
802 self.data.header().max_coord_offset.get()
803 }
804
805 pub fn max_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
807 let data = self.offset_data();
808 self.max_coord_offset().resolve(data)
809 }
810
811 pub fn feat_min_max_count(&self) -> u16 {
813 self.data.header().feat_min_max_count.get()
814 }
815
816 pub fn feat_min_max_records(&self) -> &'a [FeatMinMaxRecord] {
819 let range = self.feat_min_max_records_byte_range();
820 self.offset_data()
821 .read_array(range)
822 .ok()
823 .unwrap_or_default()
824 }
825
826 pub fn min_coord_offset_byte_range(&self) -> Range<usize> {
827 let start = 0;
828 let end = start + Offset16::RAW_BYTE_LEN;
829 start..end
830 }
831
832 pub fn max_coord_offset_byte_range(&self) -> Range<usize> {
833 let start = self.min_coord_offset_byte_range().end;
834 let end = start + Offset16::RAW_BYTE_LEN;
835 start..end
836 }
837
838 pub fn feat_min_max_count_byte_range(&self) -> Range<usize> {
839 let start = self.max_coord_offset_byte_range().end;
840 let end = start + u16::RAW_BYTE_LEN;
841 start..end
842 }
843
844 pub fn feat_min_max_records_byte_range(&self) -> Range<usize> {
845 let feat_min_max_count = self.feat_min_max_count();
846 let start = self.feat_min_max_count_byte_range().end;
847 let end = start
848 + (transforms::to_usize(feat_min_max_count))
849 .saturating_mul(FeatMinMaxRecord::RAW_BYTE_LEN);
850 start..end
851 }
852}
853
854const _: () = assert!(FontData::default_data_long_enough(MinMax::MIN_SIZE));
855
856impl Default for MinMax<'_> {
857 fn default() -> Self {
858 Self {
859 data: TableDataRef::new(FontData::default_table_data().as_bytes())
860 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
861 }
862 }
863}
864
865#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
867#[repr(C)]
868#[repr(packed)]
869pub struct FeatMinMaxRecord {
870 pub feature_table_tag: BigEndian<Tag>,
873 pub min_coord_offset: BigEndian<Nullable<Offset16>>,
876 pub max_coord_offset: BigEndian<Nullable<Offset16>>,
879}
880
881impl FeatMinMaxRecord {
882 pub fn feature_table_tag(&self) -> Tag {
885 self.feature_table_tag.get()
886 }
887
888 pub fn min_coord_offset(&self) -> Nullable<Offset16> {
891 self.min_coord_offset.get()
892 }
893
894 pub fn min_coord<'a>(&self, data: FontData<'a>) -> Option<Result<BaseCoord<'a>, ReadError>> {
900 self.min_coord_offset().resolve(data)
901 }
902
903 pub fn max_coord_offset(&self) -> Nullable<Offset16> {
906 self.max_coord_offset.get()
907 }
908
909 pub fn max_coord<'a>(&self, data: FontData<'a>) -> Option<Result<BaseCoord<'a>, ReadError>> {
915 self.max_coord_offset().resolve(data)
916 }
917}
918
919impl FixedSize for FeatMinMaxRecord {
920 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
921}
922
923#[derive(Clone)]
924pub enum BaseCoord<'a> {
925 Format1(BaseCoordFormat1<'a>),
926 Format2(BaseCoordFormat2<'a>),
927 Format3(BaseCoordFormat3<'a>),
928}
929
930impl Default for BaseCoord<'_> {
931 fn default() -> Self {
932 Self::Format1(Default::default())
933 }
934}
935
936impl<'a> BaseCoord<'a> {
937 pub fn offset_data(&self) -> FontData<'a> {
939 match self {
940 Self::Format1(item) => item.offset_data(),
941 Self::Format2(item) => item.offset_data(),
942 Self::Format3(item) => item.offset_data(),
943 }
944 }
945
946 pub fn base_coord_format(&self) -> u16 {
948 match self {
949 Self::Format1(item) => item.base_coord_format(),
950 Self::Format2(item) => item.base_coord_format(),
951 Self::Format3(item) => item.base_coord_format(),
952 }
953 }
954
955 pub fn coordinate(&self) -> i16 {
957 match self {
958 Self::Format1(item) => item.coordinate(),
959 Self::Format2(item) => item.coordinate(),
960 Self::Format3(item) => item.coordinate(),
961 }
962 }
963}
964
965impl ReadArgs for BaseCoord<'_> {
966 type Args = ();
967}
968
969impl<'a> FontRead<'a> for BaseCoord<'a> {
970 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
971 let format: u16 = data.read_at(0usize)?;
972 match format {
973 BaseCoordFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
974 BaseCoordFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
975 BaseCoordFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
976 other => Err(ReadError::InvalidFormat(other.into())),
977 }
978 }
979}
980
981impl<'a> MinByteRange<'a> for BaseCoord<'a> {
982 fn min_byte_range(&self) -> Range<usize> {
983 match self {
984 Self::Format1(item) => item.min_byte_range(),
985 Self::Format2(item) => item.min_byte_range(),
986 Self::Format3(item) => item.min_byte_range(),
987 }
988 }
989 fn min_table_bytes(&self) -> &'a [u8] {
990 match self {
991 Self::Format1(item) => item.min_table_bytes(),
992 Self::Format2(item) => item.min_table_bytes(),
993 Self::Format3(item) => item.min_table_bytes(),
994 }
995 }
996}
997
998impl Format<u16> for BaseCoordFormat1<'_> {
999 const FORMAT: u16 = 1;
1000}
1001
1002impl<'a> MinByteRange<'a> for BaseCoordFormat1<'a> {
1003 fn min_byte_range(&self) -> Range<usize> {
1004 0..self.coordinate_byte_range().end
1005 }
1006 fn min_table_bytes(&self) -> &'a [u8] {
1007 let range = self.min_byte_range();
1008 self.offset_data().as_bytes().get(range).unwrap_or_default()
1009 }
1010}
1011
1012impl ReadArgs for BaseCoordFormat1<'_> {
1013 type Args = ();
1014}
1015
1016impl<'a> FontRead<'a> for BaseCoordFormat1<'a> {
1017 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1018 #[allow(clippy::absurd_extreme_comparisons)]
1019 if data.len() < Self::MIN_SIZE {
1020 return Err(ReadError::OutOfBounds);
1021 }
1022 let Some(data) = TableDataRef::new(data.as_bytes()) else {
1023 return Err(ReadError::OutOfBounds);
1024 };
1025 Ok(Self { data })
1026 }
1027}
1028
1029#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1031#[repr(C, packed)]
1032#[doc(hidden)]
1033pub struct BaseCoordFormat1FixedHeader {
1034 pub base_coord_format: BigEndian<u16>,
1035 pub coordinate: BigEndian<i16>,
1036}
1037
1038#[allow(clippy::absurd_extreme_comparisons)]
1039const _: () =
1040 assert!(std::mem::size_of::<BaseCoordFormat1FixedHeader>() <= BaseCoordFormat1::MIN_SIZE);
1041
1042#[derive(Clone)]
1044pub struct BaseCoordFormat1<'a> {
1045 data: TableDataRef<'a, BaseCoordFormat1FixedHeader>,
1046}
1047
1048#[allow(clippy::needless_lifetimes)]
1049impl<'a> BaseCoordFormat1<'a> {
1050 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
1051 basic_table_impls!(impl_the_methods);
1052
1053 pub fn base_coord_format(&self) -> u16 {
1055 self.data.header().base_coord_format.get()
1056 }
1057
1058 pub fn coordinate(&self) -> i16 {
1060 self.data.header().coordinate.get()
1061 }
1062
1063 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1064 let start = 0;
1065 let end = start + u16::RAW_BYTE_LEN;
1066 start..end
1067 }
1068
1069 pub fn coordinate_byte_range(&self) -> Range<usize> {
1070 let start = self.base_coord_format_byte_range().end;
1071 let end = start + i16::RAW_BYTE_LEN;
1072 start..end
1073 }
1074}
1075
1076const _: () = assert!(FontData::default_data_long_enough(
1077 BaseCoordFormat1::MIN_SIZE
1078));
1079
1080impl Default for BaseCoordFormat1<'_> {
1081 fn default() -> Self {
1082 Self {
1083 data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
1084 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1085 }
1086 }
1087}
1088
1089impl Format<u16> for BaseCoordFormat2<'_> {
1090 const FORMAT: u16 = 2;
1091}
1092
1093impl<'a> MinByteRange<'a> for BaseCoordFormat2<'a> {
1094 fn min_byte_range(&self) -> Range<usize> {
1095 0..self.base_coord_point_byte_range().end
1096 }
1097 fn min_table_bytes(&self) -> &'a [u8] {
1098 let range = self.min_byte_range();
1099 self.offset_data().as_bytes().get(range).unwrap_or_default()
1100 }
1101}
1102
1103impl ReadArgs for BaseCoordFormat2<'_> {
1104 type Args = ();
1105}
1106
1107impl<'a> FontRead<'a> for BaseCoordFormat2<'a> {
1108 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1109 #[allow(clippy::absurd_extreme_comparisons)]
1110 if data.len() < Self::MIN_SIZE {
1111 return Err(ReadError::OutOfBounds);
1112 }
1113 let Some(data) = TableDataRef::new(data.as_bytes()) else {
1114 return Err(ReadError::OutOfBounds);
1115 };
1116 Ok(Self { data })
1117 }
1118}
1119
1120#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1122#[repr(C, packed)]
1123#[doc(hidden)]
1124pub struct BaseCoordFormat2FixedHeader {
1125 pub base_coord_format: BigEndian<u16>,
1126 pub coordinate: BigEndian<i16>,
1127 pub reference_glyph: BigEndian<u16>,
1128 pub base_coord_point: BigEndian<u16>,
1129}
1130
1131#[allow(clippy::absurd_extreme_comparisons)]
1132const _: () =
1133 assert!(std::mem::size_of::<BaseCoordFormat2FixedHeader>() <= BaseCoordFormat2::MIN_SIZE);
1134
1135#[derive(Clone)]
1137pub struct BaseCoordFormat2<'a> {
1138 data: TableDataRef<'a, BaseCoordFormat2FixedHeader>,
1139}
1140
1141#[allow(clippy::needless_lifetimes)]
1142impl<'a> BaseCoordFormat2<'a> {
1143 pub const MIN_SIZE: usize =
1144 (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1145 basic_table_impls!(impl_the_methods);
1146
1147 pub fn base_coord_format(&self) -> u16 {
1149 self.data.header().base_coord_format.get()
1150 }
1151
1152 pub fn coordinate(&self) -> i16 {
1154 self.data.header().coordinate.get()
1155 }
1156
1157 pub fn reference_glyph(&self) -> u16 {
1159 self.data.header().reference_glyph.get()
1160 }
1161
1162 pub fn base_coord_point(&self) -> u16 {
1164 self.data.header().base_coord_point.get()
1165 }
1166
1167 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1168 let start = 0;
1169 let end = start + u16::RAW_BYTE_LEN;
1170 start..end
1171 }
1172
1173 pub fn coordinate_byte_range(&self) -> Range<usize> {
1174 let start = self.base_coord_format_byte_range().end;
1175 let end = start + i16::RAW_BYTE_LEN;
1176 start..end
1177 }
1178
1179 pub fn reference_glyph_byte_range(&self) -> Range<usize> {
1180 let start = self.coordinate_byte_range().end;
1181 let end = start + u16::RAW_BYTE_LEN;
1182 start..end
1183 }
1184
1185 pub fn base_coord_point_byte_range(&self) -> Range<usize> {
1186 let start = self.reference_glyph_byte_range().end;
1187 let end = start + u16::RAW_BYTE_LEN;
1188 start..end
1189 }
1190}
1191
1192impl Format<u16> for BaseCoordFormat3<'_> {
1193 const FORMAT: u16 = 3;
1194}
1195
1196impl<'a> MinByteRange<'a> for BaseCoordFormat3<'a> {
1197 fn min_byte_range(&self) -> Range<usize> {
1198 0..self.device_offset_byte_range().end
1199 }
1200 fn min_table_bytes(&self) -> &'a [u8] {
1201 let range = self.min_byte_range();
1202 self.offset_data().as_bytes().get(range).unwrap_or_default()
1203 }
1204}
1205
1206impl ReadArgs for BaseCoordFormat3<'_> {
1207 type Args = ();
1208}
1209
1210impl<'a> FontRead<'a> for BaseCoordFormat3<'a> {
1211 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1212 #[allow(clippy::absurd_extreme_comparisons)]
1213 if data.len() < Self::MIN_SIZE {
1214 return Err(ReadError::OutOfBounds);
1215 }
1216 let Some(data) = TableDataRef::new(data.as_bytes()) else {
1217 return Err(ReadError::OutOfBounds);
1218 };
1219 Ok(Self { data })
1220 }
1221}
1222
1223#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1225#[repr(C, packed)]
1226#[doc(hidden)]
1227pub struct BaseCoordFormat3FixedHeader {
1228 pub base_coord_format: BigEndian<u16>,
1229 pub coordinate: BigEndian<i16>,
1230 pub device_offset: BigEndian<Nullable<Offset16>>,
1231}
1232
1233#[allow(clippy::absurd_extreme_comparisons)]
1234const _: () =
1235 assert!(std::mem::size_of::<BaseCoordFormat3FixedHeader>() <= BaseCoordFormat3::MIN_SIZE);
1236
1237#[derive(Clone)]
1239pub struct BaseCoordFormat3<'a> {
1240 data: TableDataRef<'a, BaseCoordFormat3FixedHeader>,
1241}
1242
1243#[allow(clippy::needless_lifetimes)]
1244impl<'a> BaseCoordFormat3<'a> {
1245 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
1246 basic_table_impls!(impl_the_methods);
1247
1248 pub fn base_coord_format(&self) -> u16 {
1250 self.data.header().base_coord_format.get()
1251 }
1252
1253 pub fn coordinate(&self) -> i16 {
1255 self.data.header().coordinate.get()
1256 }
1257
1258 pub fn device_offset(&self) -> Nullable<Offset16> {
1262 self.data.header().device_offset.get()
1263 }
1264
1265 pub fn device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1267 let data = self.offset_data();
1268 self.device_offset().resolve(data)
1269 }
1270
1271 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1272 let start = 0;
1273 let end = start + u16::RAW_BYTE_LEN;
1274 start..end
1275 }
1276
1277 pub fn coordinate_byte_range(&self) -> Range<usize> {
1278 let start = self.base_coord_format_byte_range().end;
1279 let end = start + i16::RAW_BYTE_LEN;
1280 start..end
1281 }
1282
1283 pub fn device_offset_byte_range(&self) -> Range<usize> {
1284 let start = self.coordinate_byte_range().end;
1285 let end = start + Offset16::RAW_BYTE_LEN;
1286 start..end
1287 }
1288}