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 #[inline]
971 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
972 let format: u16 = data.read_at(0usize)?;
973 match format {
974 BaseCoordFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
975 BaseCoordFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
976 BaseCoordFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
977 other => Err(ReadError::InvalidFormat(other.into())),
978 }
979 }
980}
981
982impl<'a> MinByteRange<'a> for BaseCoord<'a> {
983 fn min_byte_range(&self) -> Range<usize> {
984 match self {
985 Self::Format1(item) => item.min_byte_range(),
986 Self::Format2(item) => item.min_byte_range(),
987 Self::Format3(item) => item.min_byte_range(),
988 }
989 }
990 fn min_table_bytes(&self) -> &'a [u8] {
991 match self {
992 Self::Format1(item) => item.min_table_bytes(),
993 Self::Format2(item) => item.min_table_bytes(),
994 Self::Format3(item) => item.min_table_bytes(),
995 }
996 }
997}
998
999impl Format<u16> for BaseCoordFormat1<'_> {
1000 const FORMAT: u16 = 1;
1001}
1002
1003impl<'a> MinByteRange<'a> for BaseCoordFormat1<'a> {
1004 fn min_byte_range(&self) -> Range<usize> {
1005 0..self.coordinate_byte_range().end
1006 }
1007 fn min_table_bytes(&self) -> &'a [u8] {
1008 let range = self.min_byte_range();
1009 self.offset_data().as_bytes().get(range).unwrap_or_default()
1010 }
1011}
1012
1013impl ReadArgs for BaseCoordFormat1<'_> {
1014 type Args = ();
1015}
1016
1017impl<'a> FontRead<'a> for BaseCoordFormat1<'a> {
1018 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1019 #[allow(clippy::absurd_extreme_comparisons)]
1020 if data.len() < Self::MIN_SIZE {
1021 return Err(ReadError::OutOfBounds);
1022 }
1023 let Some(data) = TableDataRef::new(data.as_bytes()) else {
1024 return Err(ReadError::OutOfBounds);
1025 };
1026 Ok(Self { data })
1027 }
1028}
1029
1030#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1032#[repr(C, packed)]
1033#[doc(hidden)]
1034pub struct BaseCoordFormat1FixedHeader {
1035 pub base_coord_format: BigEndian<u16>,
1036 pub coordinate: BigEndian<i16>,
1037}
1038
1039#[allow(clippy::absurd_extreme_comparisons)]
1040const _: () =
1041 assert!(std::mem::size_of::<BaseCoordFormat1FixedHeader>() <= BaseCoordFormat1::MIN_SIZE);
1042
1043#[derive(Clone)]
1045pub struct BaseCoordFormat1<'a> {
1046 data: TableDataRef<'a, BaseCoordFormat1FixedHeader>,
1047}
1048
1049#[allow(clippy::needless_lifetimes)]
1050impl<'a> BaseCoordFormat1<'a> {
1051 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
1052 basic_table_impls!(impl_the_methods);
1053
1054 pub fn base_coord_format(&self) -> u16 {
1056 self.data.header().base_coord_format.get()
1057 }
1058
1059 pub fn coordinate(&self) -> i16 {
1061 self.data.header().coordinate.get()
1062 }
1063
1064 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1065 let start = 0;
1066 let end = start + u16::RAW_BYTE_LEN;
1067 start..end
1068 }
1069
1070 pub fn coordinate_byte_range(&self) -> Range<usize> {
1071 let start = self.base_coord_format_byte_range().end;
1072 let end = start + i16::RAW_BYTE_LEN;
1073 start..end
1074 }
1075}
1076
1077const _: () = assert!(FontData::default_data_long_enough(
1078 BaseCoordFormat1::MIN_SIZE
1079));
1080
1081impl Default for BaseCoordFormat1<'_> {
1082 fn default() -> Self {
1083 Self {
1084 data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
1085 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1086 }
1087 }
1088}
1089
1090impl Format<u16> for BaseCoordFormat2<'_> {
1091 const FORMAT: u16 = 2;
1092}
1093
1094impl<'a> MinByteRange<'a> for BaseCoordFormat2<'a> {
1095 fn min_byte_range(&self) -> Range<usize> {
1096 0..self.base_coord_point_byte_range().end
1097 }
1098 fn min_table_bytes(&self) -> &'a [u8] {
1099 let range = self.min_byte_range();
1100 self.offset_data().as_bytes().get(range).unwrap_or_default()
1101 }
1102}
1103
1104impl ReadArgs for BaseCoordFormat2<'_> {
1105 type Args = ();
1106}
1107
1108impl<'a> FontRead<'a> for BaseCoordFormat2<'a> {
1109 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1110 #[allow(clippy::absurd_extreme_comparisons)]
1111 if data.len() < Self::MIN_SIZE {
1112 return Err(ReadError::OutOfBounds);
1113 }
1114 let Some(data) = TableDataRef::new(data.as_bytes()) else {
1115 return Err(ReadError::OutOfBounds);
1116 };
1117 Ok(Self { data })
1118 }
1119}
1120
1121#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1123#[repr(C, packed)]
1124#[doc(hidden)]
1125pub struct BaseCoordFormat2FixedHeader {
1126 pub base_coord_format: BigEndian<u16>,
1127 pub coordinate: BigEndian<i16>,
1128 pub reference_glyph: BigEndian<u16>,
1129 pub base_coord_point: BigEndian<u16>,
1130}
1131
1132#[allow(clippy::absurd_extreme_comparisons)]
1133const _: () =
1134 assert!(std::mem::size_of::<BaseCoordFormat2FixedHeader>() <= BaseCoordFormat2::MIN_SIZE);
1135
1136#[derive(Clone)]
1138pub struct BaseCoordFormat2<'a> {
1139 data: TableDataRef<'a, BaseCoordFormat2FixedHeader>,
1140}
1141
1142#[allow(clippy::needless_lifetimes)]
1143impl<'a> BaseCoordFormat2<'a> {
1144 pub const MIN_SIZE: usize =
1145 (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1146 basic_table_impls!(impl_the_methods);
1147
1148 pub fn base_coord_format(&self) -> u16 {
1150 self.data.header().base_coord_format.get()
1151 }
1152
1153 pub fn coordinate(&self) -> i16 {
1155 self.data.header().coordinate.get()
1156 }
1157
1158 pub fn reference_glyph(&self) -> u16 {
1160 self.data.header().reference_glyph.get()
1161 }
1162
1163 pub fn base_coord_point(&self) -> u16 {
1165 self.data.header().base_coord_point.get()
1166 }
1167
1168 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1169 let start = 0;
1170 let end = start + u16::RAW_BYTE_LEN;
1171 start..end
1172 }
1173
1174 pub fn coordinate_byte_range(&self) -> Range<usize> {
1175 let start = self.base_coord_format_byte_range().end;
1176 let end = start + i16::RAW_BYTE_LEN;
1177 start..end
1178 }
1179
1180 pub fn reference_glyph_byte_range(&self) -> Range<usize> {
1181 let start = self.coordinate_byte_range().end;
1182 let end = start + u16::RAW_BYTE_LEN;
1183 start..end
1184 }
1185
1186 pub fn base_coord_point_byte_range(&self) -> Range<usize> {
1187 let start = self.reference_glyph_byte_range().end;
1188 let end = start + u16::RAW_BYTE_LEN;
1189 start..end
1190 }
1191}
1192
1193impl Format<u16> for BaseCoordFormat3<'_> {
1194 const FORMAT: u16 = 3;
1195}
1196
1197impl<'a> MinByteRange<'a> for BaseCoordFormat3<'a> {
1198 fn min_byte_range(&self) -> Range<usize> {
1199 0..self.device_offset_byte_range().end
1200 }
1201 fn min_table_bytes(&self) -> &'a [u8] {
1202 let range = self.min_byte_range();
1203 self.offset_data().as_bytes().get(range).unwrap_or_default()
1204 }
1205}
1206
1207impl ReadArgs for BaseCoordFormat3<'_> {
1208 type Args = ();
1209}
1210
1211impl<'a> FontRead<'a> for BaseCoordFormat3<'a> {
1212 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1213 #[allow(clippy::absurd_extreme_comparisons)]
1214 if data.len() < Self::MIN_SIZE {
1215 return Err(ReadError::OutOfBounds);
1216 }
1217 let Some(data) = TableDataRef::new(data.as_bytes()) else {
1218 return Err(ReadError::OutOfBounds);
1219 };
1220 Ok(Self { data })
1221 }
1222}
1223
1224#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1226#[repr(C, packed)]
1227#[doc(hidden)]
1228pub struct BaseCoordFormat3FixedHeader {
1229 pub base_coord_format: BigEndian<u16>,
1230 pub coordinate: BigEndian<i16>,
1231 pub device_offset: BigEndian<Nullable<Offset16>>,
1232}
1233
1234#[allow(clippy::absurd_extreme_comparisons)]
1235const _: () =
1236 assert!(std::mem::size_of::<BaseCoordFormat3FixedHeader>() <= BaseCoordFormat3::MIN_SIZE);
1237
1238#[derive(Clone)]
1240pub struct BaseCoordFormat3<'a> {
1241 data: TableDataRef<'a, BaseCoordFormat3FixedHeader>,
1242}
1243
1244#[allow(clippy::needless_lifetimes)]
1245impl<'a> BaseCoordFormat3<'a> {
1246 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
1247 basic_table_impls!(impl_the_methods);
1248
1249 pub fn base_coord_format(&self) -> u16 {
1251 self.data.header().base_coord_format.get()
1252 }
1253
1254 pub fn coordinate(&self) -> i16 {
1256 self.data.header().coordinate.get()
1257 }
1258
1259 pub fn device_offset(&self) -> Nullable<Offset16> {
1263 self.data.header().device_offset.get()
1264 }
1265
1266 pub fn device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1268 let data = self.offset_data();
1269 self.device_offset().resolve(data)
1270 }
1271
1272 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1273 let start = 0;
1274 let end = start + u16::RAW_BYTE_LEN;
1275 start..end
1276 }
1277
1278 pub fn coordinate_byte_range(&self) -> Range<usize> {
1279 let start = self.base_coord_format_byte_range().end;
1280 let end = start + i16::RAW_BYTE_LEN;
1281 start..end
1282 }
1283
1284 pub fn device_offset_byte_range(&self) -> Range<usize> {
1285 let start = self.coordinate_byte_range().end;
1286 let end = start + Offset16::RAW_BYTE_LEN;
1287 start..end
1288 }
1289}