1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8#[derive(Debug, Clone, Copy)]
10#[doc(hidden)]
11pub struct BaseMarker {
12 item_var_store_offset_byte_start: Option<usize>,
13}
14
15impl BaseMarker {
16 pub fn version_byte_range(&self) -> Range<usize> {
17 let start = 0;
18 start..start + MajorMinor::RAW_BYTE_LEN
19 }
20
21 pub fn horiz_axis_offset_byte_range(&self) -> Range<usize> {
22 let start = self.version_byte_range().end;
23 start..start + Offset16::RAW_BYTE_LEN
24 }
25
26 pub fn vert_axis_offset_byte_range(&self) -> Range<usize> {
27 let start = self.horiz_axis_offset_byte_range().end;
28 start..start + Offset16::RAW_BYTE_LEN
29 }
30
31 pub fn item_var_store_offset_byte_range(&self) -> Option<Range<usize>> {
32 let start = self.item_var_store_offset_byte_start?;
33 Some(start..start + Offset32::RAW_BYTE_LEN)
34 }
35}
36
37impl MinByteRange for BaseMarker {
38 fn min_byte_range(&self) -> Range<usize> {
39 0..self.vert_axis_offset_byte_range().end
40 }
41}
42
43impl TopLevelTable for Base<'_> {
44 const TAG: Tag = Tag::new(b"BASE");
46}
47
48impl<'a> FontRead<'a> for Base<'a> {
49 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
50 let mut cursor = data.cursor();
51 let version: MajorMinor = cursor.read()?;
52 cursor.advance::<Offset16>();
53 cursor.advance::<Offset16>();
54 let item_var_store_offset_byte_start = version
55 .compatible((1u16, 1u16))
56 .then(|| cursor.position())
57 .transpose()?;
58 version
59 .compatible((1u16, 1u16))
60 .then(|| cursor.advance::<Offset32>());
61 cursor.finish(BaseMarker {
62 item_var_store_offset_byte_start,
63 })
64 }
65}
66
67pub type Base<'a> = TableRef<'a, BaseMarker>;
69
70#[allow(clippy::needless_lifetimes)]
71impl<'a> Base<'a> {
72 pub fn version(&self) -> MajorMinor {
74 let range = self.shape.version_byte_range();
75 self.data.read_at(range.start).unwrap()
76 }
77
78 pub fn horiz_axis_offset(&self) -> Nullable<Offset16> {
80 let range = self.shape.horiz_axis_offset_byte_range();
81 self.data.read_at(range.start).unwrap()
82 }
83
84 pub fn horiz_axis(&self) -> Option<Result<Axis<'a>, ReadError>> {
86 let data = self.data;
87 self.horiz_axis_offset().resolve(data)
88 }
89
90 pub fn vert_axis_offset(&self) -> Nullable<Offset16> {
92 let range = self.shape.vert_axis_offset_byte_range();
93 self.data.read_at(range.start).unwrap()
94 }
95
96 pub fn vert_axis(&self) -> Option<Result<Axis<'a>, ReadError>> {
98 let data = self.data;
99 self.vert_axis_offset().resolve(data)
100 }
101
102 pub fn item_var_store_offset(&self) -> Option<Nullable<Offset32>> {
104 let range = self.shape.item_var_store_offset_byte_range()?;
105 Some(self.data.read_at(range.start).unwrap())
106 }
107
108 pub fn item_var_store(&self) -> Option<Result<ItemVariationStore<'a>, ReadError>> {
110 let data = self.data;
111 self.item_var_store_offset().map(|x| x.resolve(data))?
112 }
113}
114
115#[cfg(feature = "experimental_traverse")]
116impl<'a> SomeTable<'a> for Base<'a> {
117 fn type_name(&self) -> &str {
118 "Base"
119 }
120 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
121 let version = self.version();
122 match idx {
123 0usize => Some(Field::new("version", self.version())),
124 1usize => Some(Field::new(
125 "horiz_axis_offset",
126 FieldType::offset(self.horiz_axis_offset(), self.horiz_axis()),
127 )),
128 2usize => Some(Field::new(
129 "vert_axis_offset",
130 FieldType::offset(self.vert_axis_offset(), self.vert_axis()),
131 )),
132 3usize if version.compatible((1u16, 1u16)) => Some(Field::new(
133 "item_var_store_offset",
134 FieldType::offset(self.item_var_store_offset().unwrap(), self.item_var_store()),
135 )),
136 _ => None,
137 }
138 }
139}
140
141#[cfg(feature = "experimental_traverse")]
142#[allow(clippy::needless_lifetimes)]
143impl<'a> std::fmt::Debug for Base<'a> {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 (self as &dyn SomeTable<'a>).fmt(f)
146 }
147}
148
149#[derive(Debug, Clone, Copy)]
151#[doc(hidden)]
152pub struct AxisMarker {}
153
154impl AxisMarker {
155 pub fn base_tag_list_offset_byte_range(&self) -> Range<usize> {
156 let start = 0;
157 start..start + Offset16::RAW_BYTE_LEN
158 }
159
160 pub fn base_script_list_offset_byte_range(&self) -> Range<usize> {
161 let start = self.base_tag_list_offset_byte_range().end;
162 start..start + Offset16::RAW_BYTE_LEN
163 }
164}
165
166impl MinByteRange for AxisMarker {
167 fn min_byte_range(&self) -> Range<usize> {
168 0..self.base_script_list_offset_byte_range().end
169 }
170}
171
172impl<'a> FontRead<'a> for Axis<'a> {
173 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
174 let mut cursor = data.cursor();
175 cursor.advance::<Offset16>();
176 cursor.advance::<Offset16>();
177 cursor.finish(AxisMarker {})
178 }
179}
180
181pub type Axis<'a> = TableRef<'a, AxisMarker>;
183
184#[allow(clippy::needless_lifetimes)]
185impl<'a> Axis<'a> {
186 pub fn base_tag_list_offset(&self) -> Nullable<Offset16> {
189 let range = self.shape.base_tag_list_offset_byte_range();
190 self.data.read_at(range.start).unwrap()
191 }
192
193 pub fn base_tag_list(&self) -> Option<Result<BaseTagList<'a>, ReadError>> {
195 let data = self.data;
196 self.base_tag_list_offset().resolve(data)
197 }
198
199 pub fn base_script_list_offset(&self) -> Offset16 {
201 let range = self.shape.base_script_list_offset_byte_range();
202 self.data.read_at(range.start).unwrap()
203 }
204
205 pub fn base_script_list(&self) -> Result<BaseScriptList<'a>, ReadError> {
207 let data = self.data;
208 self.base_script_list_offset().resolve(data)
209 }
210}
211
212#[cfg(feature = "experimental_traverse")]
213impl<'a> SomeTable<'a> for Axis<'a> {
214 fn type_name(&self) -> &str {
215 "Axis"
216 }
217 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
218 match idx {
219 0usize => Some(Field::new(
220 "base_tag_list_offset",
221 FieldType::offset(self.base_tag_list_offset(), self.base_tag_list()),
222 )),
223 1usize => Some(Field::new(
224 "base_script_list_offset",
225 FieldType::offset(self.base_script_list_offset(), self.base_script_list()),
226 )),
227 _ => None,
228 }
229 }
230}
231
232#[cfg(feature = "experimental_traverse")]
233#[allow(clippy::needless_lifetimes)]
234impl<'a> std::fmt::Debug for Axis<'a> {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 (self as &dyn SomeTable<'a>).fmt(f)
237 }
238}
239
240#[derive(Debug, Clone, Copy)]
242#[doc(hidden)]
243pub struct BaseTagListMarker {
244 baseline_tags_byte_len: usize,
245}
246
247impl BaseTagListMarker {
248 pub fn base_tag_count_byte_range(&self) -> Range<usize> {
249 let start = 0;
250 start..start + u16::RAW_BYTE_LEN
251 }
252
253 pub fn baseline_tags_byte_range(&self) -> Range<usize> {
254 let start = self.base_tag_count_byte_range().end;
255 start..start + self.baseline_tags_byte_len
256 }
257}
258
259impl MinByteRange for BaseTagListMarker {
260 fn min_byte_range(&self) -> Range<usize> {
261 0..self.baseline_tags_byte_range().end
262 }
263}
264
265impl<'a> FontRead<'a> for BaseTagList<'a> {
266 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
267 let mut cursor = data.cursor();
268 let base_tag_count: u16 = cursor.read()?;
269 let baseline_tags_byte_len = (base_tag_count as usize)
270 .checked_mul(Tag::RAW_BYTE_LEN)
271 .ok_or(ReadError::OutOfBounds)?;
272 cursor.advance_by(baseline_tags_byte_len);
273 cursor.finish(BaseTagListMarker {
274 baseline_tags_byte_len,
275 })
276 }
277}
278
279pub type BaseTagList<'a> = TableRef<'a, BaseTagListMarker>;
281
282#[allow(clippy::needless_lifetimes)]
283impl<'a> BaseTagList<'a> {
284 pub fn base_tag_count(&self) -> u16 {
287 let range = self.shape.base_tag_count_byte_range();
288 self.data.read_at(range.start).unwrap()
289 }
290
291 pub fn baseline_tags(&self) -> &'a [BigEndian<Tag>] {
294 let range = self.shape.baseline_tags_byte_range();
295 self.data.read_array(range).unwrap()
296 }
297}
298
299#[cfg(feature = "experimental_traverse")]
300impl<'a> SomeTable<'a> for BaseTagList<'a> {
301 fn type_name(&self) -> &str {
302 "BaseTagList"
303 }
304 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
305 match idx {
306 0usize => Some(Field::new("base_tag_count", self.base_tag_count())),
307 1usize => Some(Field::new("baseline_tags", self.baseline_tags())),
308 _ => None,
309 }
310 }
311}
312
313#[cfg(feature = "experimental_traverse")]
314#[allow(clippy::needless_lifetimes)]
315impl<'a> std::fmt::Debug for BaseTagList<'a> {
316 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317 (self as &dyn SomeTable<'a>).fmt(f)
318 }
319}
320
321#[derive(Debug, Clone, Copy)]
323#[doc(hidden)]
324pub struct BaseScriptListMarker {
325 base_script_records_byte_len: usize,
326}
327
328impl BaseScriptListMarker {
329 pub fn base_script_count_byte_range(&self) -> Range<usize> {
330 let start = 0;
331 start..start + u16::RAW_BYTE_LEN
332 }
333
334 pub fn base_script_records_byte_range(&self) -> Range<usize> {
335 let start = self.base_script_count_byte_range().end;
336 start..start + self.base_script_records_byte_len
337 }
338}
339
340impl MinByteRange for BaseScriptListMarker {
341 fn min_byte_range(&self) -> Range<usize> {
342 0..self.base_script_records_byte_range().end
343 }
344}
345
346impl<'a> FontRead<'a> for BaseScriptList<'a> {
347 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
348 let mut cursor = data.cursor();
349 let base_script_count: u16 = cursor.read()?;
350 let base_script_records_byte_len = (base_script_count as usize)
351 .checked_mul(BaseScriptRecord::RAW_BYTE_LEN)
352 .ok_or(ReadError::OutOfBounds)?;
353 cursor.advance_by(base_script_records_byte_len);
354 cursor.finish(BaseScriptListMarker {
355 base_script_records_byte_len,
356 })
357 }
358}
359
360pub type BaseScriptList<'a> = TableRef<'a, BaseScriptListMarker>;
362
363#[allow(clippy::needless_lifetimes)]
364impl<'a> BaseScriptList<'a> {
365 pub fn base_script_count(&self) -> u16 {
367 let range = self.shape.base_script_count_byte_range();
368 self.data.read_at(range.start).unwrap()
369 }
370
371 pub fn base_script_records(&self) -> &'a [BaseScriptRecord] {
374 let range = self.shape.base_script_records_byte_range();
375 self.data.read_array(range).unwrap()
376 }
377}
378
379#[cfg(feature = "experimental_traverse")]
380impl<'a> SomeTable<'a> for BaseScriptList<'a> {
381 fn type_name(&self) -> &str {
382 "BaseScriptList"
383 }
384 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
385 match idx {
386 0usize => Some(Field::new("base_script_count", self.base_script_count())),
387 1usize => Some(Field::new(
388 "base_script_records",
389 traversal::FieldType::array_of_records(
390 stringify!(BaseScriptRecord),
391 self.base_script_records(),
392 self.offset_data(),
393 ),
394 )),
395 _ => None,
396 }
397 }
398}
399
400#[cfg(feature = "experimental_traverse")]
401#[allow(clippy::needless_lifetimes)]
402impl<'a> std::fmt::Debug for BaseScriptList<'a> {
403 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
404 (self as &dyn SomeTable<'a>).fmt(f)
405 }
406}
407
408#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
410#[repr(C)]
411#[repr(packed)]
412pub struct BaseScriptRecord {
413 pub base_script_tag: BigEndian<Tag>,
415 pub base_script_offset: BigEndian<Offset16>,
417}
418
419impl BaseScriptRecord {
420 pub fn base_script_tag(&self) -> Tag {
422 self.base_script_tag.get()
423 }
424
425 pub fn base_script_offset(&self) -> Offset16 {
427 self.base_script_offset.get()
428 }
429
430 pub fn base_script<'a>(&self, data: FontData<'a>) -> Result<BaseScript<'a>, ReadError> {
435 self.base_script_offset().resolve(data)
436 }
437}
438
439impl FixedSize for BaseScriptRecord {
440 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
441}
442
443#[cfg(feature = "experimental_traverse")]
444impl<'a> SomeRecord<'a> for BaseScriptRecord {
445 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
446 RecordResolver {
447 name: "BaseScriptRecord",
448 get_field: Box::new(move |idx, _data| match idx {
449 0usize => Some(Field::new("base_script_tag", self.base_script_tag())),
450 1usize => Some(Field::new(
451 "base_script_offset",
452 FieldType::offset(self.base_script_offset(), self.base_script(_data)),
453 )),
454 _ => None,
455 }),
456 data,
457 }
458 }
459}
460
461#[derive(Debug, Clone, Copy)]
463#[doc(hidden)]
464pub struct BaseScriptMarker {
465 base_lang_sys_records_byte_len: usize,
466}
467
468impl BaseScriptMarker {
469 pub fn base_values_offset_byte_range(&self) -> Range<usize> {
470 let start = 0;
471 start..start + Offset16::RAW_BYTE_LEN
472 }
473
474 pub fn default_min_max_offset_byte_range(&self) -> Range<usize> {
475 let start = self.base_values_offset_byte_range().end;
476 start..start + Offset16::RAW_BYTE_LEN
477 }
478
479 pub fn base_lang_sys_count_byte_range(&self) -> Range<usize> {
480 let start = self.default_min_max_offset_byte_range().end;
481 start..start + u16::RAW_BYTE_LEN
482 }
483
484 pub fn base_lang_sys_records_byte_range(&self) -> Range<usize> {
485 let start = self.base_lang_sys_count_byte_range().end;
486 start..start + self.base_lang_sys_records_byte_len
487 }
488}
489
490impl MinByteRange for BaseScriptMarker {
491 fn min_byte_range(&self) -> Range<usize> {
492 0..self.base_lang_sys_records_byte_range().end
493 }
494}
495
496impl<'a> FontRead<'a> for BaseScript<'a> {
497 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
498 let mut cursor = data.cursor();
499 cursor.advance::<Offset16>();
500 cursor.advance::<Offset16>();
501 let base_lang_sys_count: u16 = cursor.read()?;
502 let base_lang_sys_records_byte_len = (base_lang_sys_count as usize)
503 .checked_mul(BaseLangSysRecord::RAW_BYTE_LEN)
504 .ok_or(ReadError::OutOfBounds)?;
505 cursor.advance_by(base_lang_sys_records_byte_len);
506 cursor.finish(BaseScriptMarker {
507 base_lang_sys_records_byte_len,
508 })
509 }
510}
511
512pub type BaseScript<'a> = TableRef<'a, BaseScriptMarker>;
514
515#[allow(clippy::needless_lifetimes)]
516impl<'a> BaseScript<'a> {
517 pub fn base_values_offset(&self) -> Nullable<Offset16> {
519 let range = self.shape.base_values_offset_byte_range();
520 self.data.read_at(range.start).unwrap()
521 }
522
523 pub fn base_values(&self) -> Option<Result<BaseValues<'a>, ReadError>> {
525 let data = self.data;
526 self.base_values_offset().resolve(data)
527 }
528
529 pub fn default_min_max_offset(&self) -> Nullable<Offset16> {
531 let range = self.shape.default_min_max_offset_byte_range();
532 self.data.read_at(range.start).unwrap()
533 }
534
535 pub fn default_min_max(&self) -> Option<Result<MinMax<'a>, ReadError>> {
537 let data = self.data;
538 self.default_min_max_offset().resolve(data)
539 }
540
541 pub fn base_lang_sys_count(&self) -> u16 {
543 let range = self.shape.base_lang_sys_count_byte_range();
544 self.data.read_at(range.start).unwrap()
545 }
546
547 pub fn base_lang_sys_records(&self) -> &'a [BaseLangSysRecord] {
550 let range = self.shape.base_lang_sys_records_byte_range();
551 self.data.read_array(range).unwrap()
552 }
553}
554
555#[cfg(feature = "experimental_traverse")]
556impl<'a> SomeTable<'a> for BaseScript<'a> {
557 fn type_name(&self) -> &str {
558 "BaseScript"
559 }
560 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
561 match idx {
562 0usize => Some(Field::new(
563 "base_values_offset",
564 FieldType::offset(self.base_values_offset(), self.base_values()),
565 )),
566 1usize => Some(Field::new(
567 "default_min_max_offset",
568 FieldType::offset(self.default_min_max_offset(), self.default_min_max()),
569 )),
570 2usize => Some(Field::new(
571 "base_lang_sys_count",
572 self.base_lang_sys_count(),
573 )),
574 3usize => Some(Field::new(
575 "base_lang_sys_records",
576 traversal::FieldType::array_of_records(
577 stringify!(BaseLangSysRecord),
578 self.base_lang_sys_records(),
579 self.offset_data(),
580 ),
581 )),
582 _ => None,
583 }
584 }
585}
586
587#[cfg(feature = "experimental_traverse")]
588#[allow(clippy::needless_lifetimes)]
589impl<'a> std::fmt::Debug for BaseScript<'a> {
590 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
591 (self as &dyn SomeTable<'a>).fmt(f)
592 }
593}
594
595#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
597#[repr(C)]
598#[repr(packed)]
599pub struct BaseLangSysRecord {
600 pub base_lang_sys_tag: BigEndian<Tag>,
602 pub min_max_offset: BigEndian<Offset16>,
604}
605
606impl BaseLangSysRecord {
607 pub fn base_lang_sys_tag(&self) -> Tag {
609 self.base_lang_sys_tag.get()
610 }
611
612 pub fn min_max_offset(&self) -> Offset16 {
614 self.min_max_offset.get()
615 }
616
617 pub fn min_max<'a>(&self, data: FontData<'a>) -> Result<MinMax<'a>, ReadError> {
622 self.min_max_offset().resolve(data)
623 }
624}
625
626impl FixedSize for BaseLangSysRecord {
627 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
628}
629
630#[cfg(feature = "experimental_traverse")]
631impl<'a> SomeRecord<'a> for BaseLangSysRecord {
632 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
633 RecordResolver {
634 name: "BaseLangSysRecord",
635 get_field: Box::new(move |idx, _data| match idx {
636 0usize => Some(Field::new("base_lang_sys_tag", self.base_lang_sys_tag())),
637 1usize => Some(Field::new(
638 "min_max_offset",
639 FieldType::offset(self.min_max_offset(), self.min_max(_data)),
640 )),
641 _ => None,
642 }),
643 data,
644 }
645 }
646}
647
648#[derive(Debug, Clone, Copy)]
650#[doc(hidden)]
651pub struct BaseValuesMarker {
652 base_coord_offsets_byte_len: usize,
653}
654
655impl BaseValuesMarker {
656 pub fn default_baseline_index_byte_range(&self) -> Range<usize> {
657 let start = 0;
658 start..start + u16::RAW_BYTE_LEN
659 }
660
661 pub fn base_coord_count_byte_range(&self) -> Range<usize> {
662 let start = self.default_baseline_index_byte_range().end;
663 start..start + u16::RAW_BYTE_LEN
664 }
665
666 pub fn base_coord_offsets_byte_range(&self) -> Range<usize> {
667 let start = self.base_coord_count_byte_range().end;
668 start..start + self.base_coord_offsets_byte_len
669 }
670}
671
672impl MinByteRange for BaseValuesMarker {
673 fn min_byte_range(&self) -> Range<usize> {
674 0..self.base_coord_offsets_byte_range().end
675 }
676}
677
678impl<'a> FontRead<'a> for BaseValues<'a> {
679 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
680 let mut cursor = data.cursor();
681 cursor.advance::<u16>();
682 let base_coord_count: u16 = cursor.read()?;
683 let base_coord_offsets_byte_len = (base_coord_count as usize)
684 .checked_mul(Offset16::RAW_BYTE_LEN)
685 .ok_or(ReadError::OutOfBounds)?;
686 cursor.advance_by(base_coord_offsets_byte_len);
687 cursor.finish(BaseValuesMarker {
688 base_coord_offsets_byte_len,
689 })
690 }
691}
692
693pub type BaseValues<'a> = TableRef<'a, BaseValuesMarker>;
695
696#[allow(clippy::needless_lifetimes)]
697impl<'a> BaseValues<'a> {
698 pub fn default_baseline_index(&self) -> u16 {
702 let range = self.shape.default_baseline_index_byte_range();
703 self.data.read_at(range.start).unwrap()
704 }
705
706 pub fn base_coord_count(&self) -> u16 {
709 let range = self.shape.base_coord_count_byte_range();
710 self.data.read_at(range.start).unwrap()
711 }
712
713 pub fn base_coord_offsets(&self) -> &'a [BigEndian<Offset16>] {
717 let range = self.shape.base_coord_offsets_byte_range();
718 self.data.read_array(range).unwrap()
719 }
720
721 pub fn base_coords(&self) -> ArrayOfOffsets<'a, BaseCoord<'a>, Offset16> {
723 let data = self.data;
724 let offsets = self.base_coord_offsets();
725 ArrayOfOffsets::new(offsets, data, ())
726 }
727}
728
729#[cfg(feature = "experimental_traverse")]
730impl<'a> SomeTable<'a> for BaseValues<'a> {
731 fn type_name(&self) -> &str {
732 "BaseValues"
733 }
734 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
735 match idx {
736 0usize => Some(Field::new(
737 "default_baseline_index",
738 self.default_baseline_index(),
739 )),
740 1usize => Some(Field::new("base_coord_count", self.base_coord_count())),
741 2usize => Some({
742 let data = self.data;
743 Field::new(
744 "base_coord_offsets",
745 FieldType::array_of_offsets(
746 better_type_name::<BaseCoord>(),
747 self.base_coord_offsets(),
748 move |off| {
749 let target = off.get().resolve::<BaseCoord>(data);
750 FieldType::offset(off.get(), target)
751 },
752 ),
753 )
754 }),
755 _ => None,
756 }
757 }
758}
759
760#[cfg(feature = "experimental_traverse")]
761#[allow(clippy::needless_lifetimes)]
762impl<'a> std::fmt::Debug for BaseValues<'a> {
763 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
764 (self as &dyn SomeTable<'a>).fmt(f)
765 }
766}
767
768#[derive(Debug, Clone, Copy)]
770#[doc(hidden)]
771pub struct MinMaxMarker {
772 feat_min_max_records_byte_len: usize,
773}
774
775impl MinMaxMarker {
776 pub fn min_coord_offset_byte_range(&self) -> Range<usize> {
777 let start = 0;
778 start..start + Offset16::RAW_BYTE_LEN
779 }
780
781 pub fn max_coord_offset_byte_range(&self) -> Range<usize> {
782 let start = self.min_coord_offset_byte_range().end;
783 start..start + Offset16::RAW_BYTE_LEN
784 }
785
786 pub fn feat_min_max_count_byte_range(&self) -> Range<usize> {
787 let start = self.max_coord_offset_byte_range().end;
788 start..start + u16::RAW_BYTE_LEN
789 }
790
791 pub fn feat_min_max_records_byte_range(&self) -> Range<usize> {
792 let start = self.feat_min_max_count_byte_range().end;
793 start..start + self.feat_min_max_records_byte_len
794 }
795}
796
797impl MinByteRange for MinMaxMarker {
798 fn min_byte_range(&self) -> Range<usize> {
799 0..self.feat_min_max_records_byte_range().end
800 }
801}
802
803impl<'a> FontRead<'a> for MinMax<'a> {
804 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
805 let mut cursor = data.cursor();
806 cursor.advance::<Offset16>();
807 cursor.advance::<Offset16>();
808 let feat_min_max_count: u16 = cursor.read()?;
809 let feat_min_max_records_byte_len = (feat_min_max_count as usize)
810 .checked_mul(FeatMinMaxRecord::RAW_BYTE_LEN)
811 .ok_or(ReadError::OutOfBounds)?;
812 cursor.advance_by(feat_min_max_records_byte_len);
813 cursor.finish(MinMaxMarker {
814 feat_min_max_records_byte_len,
815 })
816 }
817}
818
819pub type MinMax<'a> = TableRef<'a, MinMaxMarker>;
821
822#[allow(clippy::needless_lifetimes)]
823impl<'a> MinMax<'a> {
824 pub fn min_coord_offset(&self) -> Nullable<Offset16> {
827 let range = self.shape.min_coord_offset_byte_range();
828 self.data.read_at(range.start).unwrap()
829 }
830
831 pub fn min_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
833 let data = self.data;
834 self.min_coord_offset().resolve(data)
835 }
836
837 pub fn max_coord_offset(&self) -> Nullable<Offset16> {
840 let range = self.shape.max_coord_offset_byte_range();
841 self.data.read_at(range.start).unwrap()
842 }
843
844 pub fn max_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
846 let data = self.data;
847 self.max_coord_offset().resolve(data)
848 }
849
850 pub fn feat_min_max_count(&self) -> u16 {
852 let range = self.shape.feat_min_max_count_byte_range();
853 self.data.read_at(range.start).unwrap()
854 }
855
856 pub fn feat_min_max_records(&self) -> &'a [FeatMinMaxRecord] {
859 let range = self.shape.feat_min_max_records_byte_range();
860 self.data.read_array(range).unwrap()
861 }
862}
863
864#[cfg(feature = "experimental_traverse")]
865impl<'a> SomeTable<'a> for MinMax<'a> {
866 fn type_name(&self) -> &str {
867 "MinMax"
868 }
869 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
870 match idx {
871 0usize => Some(Field::new(
872 "min_coord_offset",
873 FieldType::offset(self.min_coord_offset(), self.min_coord()),
874 )),
875 1usize => Some(Field::new(
876 "max_coord_offset",
877 FieldType::offset(self.max_coord_offset(), self.max_coord()),
878 )),
879 2usize => Some(Field::new("feat_min_max_count", self.feat_min_max_count())),
880 3usize => Some(Field::new(
881 "feat_min_max_records",
882 traversal::FieldType::array_of_records(
883 stringify!(FeatMinMaxRecord),
884 self.feat_min_max_records(),
885 self.offset_data(),
886 ),
887 )),
888 _ => None,
889 }
890 }
891}
892
893#[cfg(feature = "experimental_traverse")]
894#[allow(clippy::needless_lifetimes)]
895impl<'a> std::fmt::Debug for MinMax<'a> {
896 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
897 (self as &dyn SomeTable<'a>).fmt(f)
898 }
899}
900
901#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
903#[repr(C)]
904#[repr(packed)]
905pub struct FeatMinMaxRecord {
906 pub feature_table_tag: BigEndian<Tag>,
909 pub min_coord_offset: BigEndian<Nullable<Offset16>>,
912 pub max_coord_offset: BigEndian<Nullable<Offset16>>,
915}
916
917impl FeatMinMaxRecord {
918 pub fn feature_table_tag(&self) -> Tag {
921 self.feature_table_tag.get()
922 }
923
924 pub fn min_coord_offset(&self) -> Nullable<Offset16> {
927 self.min_coord_offset.get()
928 }
929
930 pub fn min_coord<'a>(&self, data: FontData<'a>) -> Option<Result<MinMax<'a>, ReadError>> {
936 self.min_coord_offset().resolve(data)
937 }
938
939 pub fn max_coord_offset(&self) -> Nullable<Offset16> {
942 self.max_coord_offset.get()
943 }
944
945 pub fn max_coord<'a>(&self, data: FontData<'a>) -> Option<Result<MinMax<'a>, ReadError>> {
951 self.max_coord_offset().resolve(data)
952 }
953}
954
955impl FixedSize for FeatMinMaxRecord {
956 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
957}
958
959#[cfg(feature = "experimental_traverse")]
960impl<'a> SomeRecord<'a> for FeatMinMaxRecord {
961 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
962 RecordResolver {
963 name: "FeatMinMaxRecord",
964 get_field: Box::new(move |idx, _data| match idx {
965 0usize => Some(Field::new("feature_table_tag", self.feature_table_tag())),
966 1usize => Some(Field::new(
967 "min_coord_offset",
968 FieldType::offset(self.min_coord_offset(), self.min_coord(_data)),
969 )),
970 2usize => Some(Field::new(
971 "max_coord_offset",
972 FieldType::offset(self.max_coord_offset(), self.max_coord(_data)),
973 )),
974 _ => None,
975 }),
976 data,
977 }
978 }
979}
980
981#[derive(Clone)]
982pub enum BaseCoord<'a> {
983 Format1(BaseCoordFormat1<'a>),
984 Format2(BaseCoordFormat2<'a>),
985 Format3(BaseCoordFormat3<'a>),
986}
987
988impl<'a> BaseCoord<'a> {
989 pub fn offset_data(&self) -> FontData<'a> {
991 match self {
992 Self::Format1(item) => item.offset_data(),
993 Self::Format2(item) => item.offset_data(),
994 Self::Format3(item) => item.offset_data(),
995 }
996 }
997
998 pub fn base_coord_format(&self) -> u16 {
1000 match self {
1001 Self::Format1(item) => item.base_coord_format(),
1002 Self::Format2(item) => item.base_coord_format(),
1003 Self::Format3(item) => item.base_coord_format(),
1004 }
1005 }
1006
1007 pub fn coordinate(&self) -> i16 {
1009 match self {
1010 Self::Format1(item) => item.coordinate(),
1011 Self::Format2(item) => item.coordinate(),
1012 Self::Format3(item) => item.coordinate(),
1013 }
1014 }
1015}
1016
1017impl<'a> FontRead<'a> for BaseCoord<'a> {
1018 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1019 let format: u16 = data.read_at(0usize)?;
1020 match format {
1021 BaseCoordFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1022 BaseCoordFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1023 BaseCoordFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
1024 other => Err(ReadError::InvalidFormat(other.into())),
1025 }
1026 }
1027}
1028
1029impl MinByteRange for BaseCoord<'_> {
1030 fn min_byte_range(&self) -> Range<usize> {
1031 match self {
1032 Self::Format1(item) => item.min_byte_range(),
1033 Self::Format2(item) => item.min_byte_range(),
1034 Self::Format3(item) => item.min_byte_range(),
1035 }
1036 }
1037}
1038
1039#[cfg(feature = "experimental_traverse")]
1040impl<'a> BaseCoord<'a> {
1041 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1042 match self {
1043 Self::Format1(table) => table,
1044 Self::Format2(table) => table,
1045 Self::Format3(table) => table,
1046 }
1047 }
1048}
1049
1050#[cfg(feature = "experimental_traverse")]
1051impl std::fmt::Debug for BaseCoord<'_> {
1052 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1053 self.dyn_inner().fmt(f)
1054 }
1055}
1056
1057#[cfg(feature = "experimental_traverse")]
1058impl<'a> SomeTable<'a> for BaseCoord<'a> {
1059 fn type_name(&self) -> &str {
1060 self.dyn_inner().type_name()
1061 }
1062 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1063 self.dyn_inner().get_field(idx)
1064 }
1065}
1066
1067impl Format<u16> for BaseCoordFormat1Marker {
1068 const FORMAT: u16 = 1;
1069}
1070
1071#[derive(Debug, Clone, Copy)]
1073#[doc(hidden)]
1074pub struct BaseCoordFormat1Marker {}
1075
1076impl BaseCoordFormat1Marker {
1077 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1078 let start = 0;
1079 start..start + u16::RAW_BYTE_LEN
1080 }
1081
1082 pub fn coordinate_byte_range(&self) -> Range<usize> {
1083 let start = self.base_coord_format_byte_range().end;
1084 start..start + i16::RAW_BYTE_LEN
1085 }
1086}
1087
1088impl MinByteRange for BaseCoordFormat1Marker {
1089 fn min_byte_range(&self) -> Range<usize> {
1090 0..self.coordinate_byte_range().end
1091 }
1092}
1093
1094impl<'a> FontRead<'a> for BaseCoordFormat1<'a> {
1095 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1096 let mut cursor = data.cursor();
1097 cursor.advance::<u16>();
1098 cursor.advance::<i16>();
1099 cursor.finish(BaseCoordFormat1Marker {})
1100 }
1101}
1102
1103pub type BaseCoordFormat1<'a> = TableRef<'a, BaseCoordFormat1Marker>;
1105
1106#[allow(clippy::needless_lifetimes)]
1107impl<'a> BaseCoordFormat1<'a> {
1108 pub fn base_coord_format(&self) -> u16 {
1110 let range = self.shape.base_coord_format_byte_range();
1111 self.data.read_at(range.start).unwrap()
1112 }
1113
1114 pub fn coordinate(&self) -> i16 {
1116 let range = self.shape.coordinate_byte_range();
1117 self.data.read_at(range.start).unwrap()
1118 }
1119}
1120
1121#[cfg(feature = "experimental_traverse")]
1122impl<'a> SomeTable<'a> for BaseCoordFormat1<'a> {
1123 fn type_name(&self) -> &str {
1124 "BaseCoordFormat1"
1125 }
1126 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1127 match idx {
1128 0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1129 1usize => Some(Field::new("coordinate", self.coordinate())),
1130 _ => None,
1131 }
1132 }
1133}
1134
1135#[cfg(feature = "experimental_traverse")]
1136#[allow(clippy::needless_lifetimes)]
1137impl<'a> std::fmt::Debug for BaseCoordFormat1<'a> {
1138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1139 (self as &dyn SomeTable<'a>).fmt(f)
1140 }
1141}
1142
1143impl Format<u16> for BaseCoordFormat2Marker {
1144 const FORMAT: u16 = 2;
1145}
1146
1147#[derive(Debug, Clone, Copy)]
1149#[doc(hidden)]
1150pub struct BaseCoordFormat2Marker {}
1151
1152impl BaseCoordFormat2Marker {
1153 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1154 let start = 0;
1155 start..start + u16::RAW_BYTE_LEN
1156 }
1157
1158 pub fn coordinate_byte_range(&self) -> Range<usize> {
1159 let start = self.base_coord_format_byte_range().end;
1160 start..start + i16::RAW_BYTE_LEN
1161 }
1162
1163 pub fn reference_glyph_byte_range(&self) -> Range<usize> {
1164 let start = self.coordinate_byte_range().end;
1165 start..start + u16::RAW_BYTE_LEN
1166 }
1167
1168 pub fn base_coord_point_byte_range(&self) -> Range<usize> {
1169 let start = self.reference_glyph_byte_range().end;
1170 start..start + u16::RAW_BYTE_LEN
1171 }
1172}
1173
1174impl MinByteRange for BaseCoordFormat2Marker {
1175 fn min_byte_range(&self) -> Range<usize> {
1176 0..self.base_coord_point_byte_range().end
1177 }
1178}
1179
1180impl<'a> FontRead<'a> for BaseCoordFormat2<'a> {
1181 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1182 let mut cursor = data.cursor();
1183 cursor.advance::<u16>();
1184 cursor.advance::<i16>();
1185 cursor.advance::<u16>();
1186 cursor.advance::<u16>();
1187 cursor.finish(BaseCoordFormat2Marker {})
1188 }
1189}
1190
1191pub type BaseCoordFormat2<'a> = TableRef<'a, BaseCoordFormat2Marker>;
1193
1194#[allow(clippy::needless_lifetimes)]
1195impl<'a> BaseCoordFormat2<'a> {
1196 pub fn base_coord_format(&self) -> u16 {
1198 let range = self.shape.base_coord_format_byte_range();
1199 self.data.read_at(range.start).unwrap()
1200 }
1201
1202 pub fn coordinate(&self) -> i16 {
1204 let range = self.shape.coordinate_byte_range();
1205 self.data.read_at(range.start).unwrap()
1206 }
1207
1208 pub fn reference_glyph(&self) -> u16 {
1210 let range = self.shape.reference_glyph_byte_range();
1211 self.data.read_at(range.start).unwrap()
1212 }
1213
1214 pub fn base_coord_point(&self) -> u16 {
1216 let range = self.shape.base_coord_point_byte_range();
1217 self.data.read_at(range.start).unwrap()
1218 }
1219}
1220
1221#[cfg(feature = "experimental_traverse")]
1222impl<'a> SomeTable<'a> for BaseCoordFormat2<'a> {
1223 fn type_name(&self) -> &str {
1224 "BaseCoordFormat2"
1225 }
1226 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1227 match idx {
1228 0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1229 1usize => Some(Field::new("coordinate", self.coordinate())),
1230 2usize => Some(Field::new("reference_glyph", self.reference_glyph())),
1231 3usize => Some(Field::new("base_coord_point", self.base_coord_point())),
1232 _ => None,
1233 }
1234 }
1235}
1236
1237#[cfg(feature = "experimental_traverse")]
1238#[allow(clippy::needless_lifetimes)]
1239impl<'a> std::fmt::Debug for BaseCoordFormat2<'a> {
1240 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1241 (self as &dyn SomeTable<'a>).fmt(f)
1242 }
1243}
1244
1245impl Format<u16> for BaseCoordFormat3Marker {
1246 const FORMAT: u16 = 3;
1247}
1248
1249#[derive(Debug, Clone, Copy)]
1251#[doc(hidden)]
1252pub struct BaseCoordFormat3Marker {}
1253
1254impl BaseCoordFormat3Marker {
1255 pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1256 let start = 0;
1257 start..start + u16::RAW_BYTE_LEN
1258 }
1259
1260 pub fn coordinate_byte_range(&self) -> Range<usize> {
1261 let start = self.base_coord_format_byte_range().end;
1262 start..start + i16::RAW_BYTE_LEN
1263 }
1264
1265 pub fn device_offset_byte_range(&self) -> Range<usize> {
1266 let start = self.coordinate_byte_range().end;
1267 start..start + Offset16::RAW_BYTE_LEN
1268 }
1269}
1270
1271impl MinByteRange for BaseCoordFormat3Marker {
1272 fn min_byte_range(&self) -> Range<usize> {
1273 0..self.device_offset_byte_range().end
1274 }
1275}
1276
1277impl<'a> FontRead<'a> for BaseCoordFormat3<'a> {
1278 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1279 let mut cursor = data.cursor();
1280 cursor.advance::<u16>();
1281 cursor.advance::<i16>();
1282 cursor.advance::<Offset16>();
1283 cursor.finish(BaseCoordFormat3Marker {})
1284 }
1285}
1286
1287pub type BaseCoordFormat3<'a> = TableRef<'a, BaseCoordFormat3Marker>;
1289
1290#[allow(clippy::needless_lifetimes)]
1291impl<'a> BaseCoordFormat3<'a> {
1292 pub fn base_coord_format(&self) -> u16 {
1294 let range = self.shape.base_coord_format_byte_range();
1295 self.data.read_at(range.start).unwrap()
1296 }
1297
1298 pub fn coordinate(&self) -> i16 {
1300 let range = self.shape.coordinate_byte_range();
1301 self.data.read_at(range.start).unwrap()
1302 }
1303
1304 pub fn device_offset(&self) -> Nullable<Offset16> {
1308 let range = self.shape.device_offset_byte_range();
1309 self.data.read_at(range.start).unwrap()
1310 }
1311
1312 pub fn device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1314 let data = self.data;
1315 self.device_offset().resolve(data)
1316 }
1317}
1318
1319#[cfg(feature = "experimental_traverse")]
1320impl<'a> SomeTable<'a> for BaseCoordFormat3<'a> {
1321 fn type_name(&self) -> &str {
1322 "BaseCoordFormat3"
1323 }
1324 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1325 match idx {
1326 0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1327 1usize => Some(Field::new("coordinate", self.coordinate())),
1328 2usize => Some(Field::new(
1329 "device_offset",
1330 FieldType::offset(self.device_offset(), self.device()),
1331 )),
1332 _ => None,
1333 }
1334 }
1335}
1336
1337#[cfg(feature = "experimental_traverse")]
1338#[allow(clippy::needless_lifetimes)]
1339impl<'a> std::fmt::Debug for BaseCoordFormat3<'a> {
1340 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1341 (self as &dyn SomeTable<'a>).fmt(f)
1342 }
1343}