1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for Morx<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.chains_byte_range().end
11 }
12 fn min_table_bytes(&self) -> &'a [u8] {
13 let range = self.min_byte_range();
14 self.data.as_bytes().get(range).unwrap_or_default()
15 }
16}
17
18impl TopLevelTable for Morx<'_> {
19 const TAG: Tag = Tag::new(b"morx");
21}
22
23impl<'a> FontRead<'a> for Morx<'a> {
24 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
25 #[allow(clippy::absurd_extreme_comparisons)]
26 if data.len() < Self::MIN_SIZE {
27 return Err(ReadError::OutOfBounds);
28 }
29 Ok(Self { data })
30 }
31}
32
33#[derive(Clone)]
35pub struct Morx<'a> {
36 data: FontData<'a>,
37}
38
39#[allow(clippy::needless_lifetimes)]
40impl<'a> Morx<'a> {
41 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
42 basic_table_impls!(impl_the_methods);
43
44 pub fn version(&self) -> u16 {
46 let range = self.version_byte_range();
47 self.data.read_at(range.start).ok().unwrap()
48 }
49
50 pub fn n_chains(&self) -> u32 {
52 let range = self.n_chains_byte_range();
53 self.data.read_at(range.start).ok().unwrap()
54 }
55
56 pub fn chains(&self) -> VarLenArray<'a, Chain<'a>> {
57 let range = self.chains_byte_range();
58 self.data
59 .split_off(range.start)
60 .and_then(|d| VarLenArray::read(d).ok())
61 .unwrap_or_default()
62 }
63
64 pub fn version_byte_range(&self) -> Range<usize> {
65 let start = 0;
66 let end = start + u16::RAW_BYTE_LEN;
67 start..end
68 }
69
70 pub fn unused_byte_range(&self) -> Range<usize> {
71 let start = self.version_byte_range().end;
72 let end = start + u16::RAW_BYTE_LEN;
73 start..end
74 }
75
76 pub fn n_chains_byte_range(&self) -> Range<usize> {
77 let start = self.unused_byte_range().end;
78 let end = start + u32::RAW_BYTE_LEN;
79 start..end
80 }
81
82 pub fn chains_byte_range(&self) -> Range<usize> {
83 let n_chains = self.n_chains();
84 let start = self.n_chains_byte_range().end;
85 let end = start + {
86 let data = self.data.split_off(start).unwrap_or_default();
87 <Chain as VarSize>::total_len_for_count(data, transforms::to_usize(n_chains))
88 .unwrap_or(0)
89 };
90 start..end
91 }
92}
93
94const _: () = assert!(FontData::default_data_long_enough(Morx::MIN_SIZE));
95
96impl Default for Morx<'_> {
97 fn default() -> Self {
98 Self {
99 data: FontData::default_table_data(),
100 }
101 }
102}
103
104#[cfg(feature = "experimental_traverse")]
105impl<'a> SomeTable<'a> for Morx<'a> {
106 fn type_name(&self) -> &str {
107 "Morx"
108 }
109 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
110 match idx {
111 0usize => Some(Field::new("version", self.version())),
112 1usize => Some(Field::new("n_chains", self.n_chains())),
113 2usize => Some(Field::new(
114 "chains",
115 traversal::FieldType::var_array("Chain", self.chains(), self.offset_data()),
116 )),
117 _ => None,
118 }
119 }
120}
121
122#[cfg(feature = "experimental_traverse")]
123#[allow(clippy::needless_lifetimes)]
124impl<'a> std::fmt::Debug for Morx<'a> {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 (self as &dyn SomeTable<'a>).fmt(f)
127 }
128}
129
130impl<'a> MinByteRange<'a> for Chain<'a> {
131 fn min_byte_range(&self) -> Range<usize> {
132 0..self.subtables_byte_range().end
133 }
134 fn min_table_bytes(&self) -> &'a [u8] {
135 let range = self.min_byte_range();
136 self.data.as_bytes().get(range).unwrap_or_default()
137 }
138}
139
140impl<'a> FontRead<'a> for Chain<'a> {
141 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
142 #[allow(clippy::absurd_extreme_comparisons)]
143 if data.len() < Self::MIN_SIZE {
144 return Err(ReadError::OutOfBounds);
145 }
146 Ok(Self { data })
147 }
148}
149
150#[derive(Clone)]
152pub struct Chain<'a> {
153 data: FontData<'a>,
154}
155
156#[allow(clippy::needless_lifetimes)]
157impl<'a> Chain<'a> {
158 pub const MIN_SIZE: usize =
159 (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
160 basic_table_impls!(impl_the_methods);
161
162 pub fn default_flags(&self) -> u32 {
164 let range = self.default_flags_byte_range();
165 self.data.read_at(range.start).ok().unwrap()
166 }
167
168 pub fn chain_length(&self) -> u32 {
170 let range = self.chain_length_byte_range();
171 self.data.read_at(range.start).ok().unwrap()
172 }
173
174 pub fn n_feature_entries(&self) -> u32 {
176 let range = self.n_feature_entries_byte_range();
177 self.data.read_at(range.start).ok().unwrap()
178 }
179
180 pub fn n_subtables(&self) -> u32 {
182 let range = self.n_subtables_byte_range();
183 self.data.read_at(range.start).ok().unwrap()
184 }
185
186 pub fn features(&self) -> &'a [Feature] {
188 let range = self.features_byte_range();
189 self.data.read_array(range).ok().unwrap_or_default()
190 }
191
192 pub fn subtables(&self) -> VarLenArray<'a, Subtable<'a>> {
194 let range = self.subtables_byte_range();
195 self.data
196 .split_off(range.start)
197 .and_then(|d| VarLenArray::read(d).ok())
198 .unwrap_or_default()
199 }
200
201 pub fn default_flags_byte_range(&self) -> Range<usize> {
202 let start = 0;
203 let end = start + u32::RAW_BYTE_LEN;
204 start..end
205 }
206
207 pub fn chain_length_byte_range(&self) -> Range<usize> {
208 let start = self.default_flags_byte_range().end;
209 let end = start + u32::RAW_BYTE_LEN;
210 start..end
211 }
212
213 pub fn n_feature_entries_byte_range(&self) -> Range<usize> {
214 let start = self.chain_length_byte_range().end;
215 let end = start + u32::RAW_BYTE_LEN;
216 start..end
217 }
218
219 pub fn n_subtables_byte_range(&self) -> Range<usize> {
220 let start = self.n_feature_entries_byte_range().end;
221 let end = start + u32::RAW_BYTE_LEN;
222 start..end
223 }
224
225 pub fn features_byte_range(&self) -> Range<usize> {
226 let n_feature_entries = self.n_feature_entries();
227 let start = self.n_subtables_byte_range().end;
228 let end =
229 start + (transforms::to_usize(n_feature_entries)).saturating_mul(Feature::RAW_BYTE_LEN);
230 start..end
231 }
232
233 pub fn subtables_byte_range(&self) -> Range<usize> {
234 let n_subtables = self.n_subtables();
235 let start = self.features_byte_range().end;
236 let end = start + {
237 let data = self.data.split_off(start).unwrap_or_default();
238 <Subtable as VarSize>::total_len_for_count(data, transforms::to_usize(n_subtables))
239 .unwrap_or(0)
240 };
241 start..end
242 }
243}
244
245const _: () = assert!(FontData::default_data_long_enough(Chain::MIN_SIZE));
246
247impl Default for Chain<'_> {
248 fn default() -> Self {
249 Self {
250 data: FontData::default_table_data(),
251 }
252 }
253}
254
255#[cfg(feature = "experimental_traverse")]
256impl<'a> SomeTable<'a> for Chain<'a> {
257 fn type_name(&self) -> &str {
258 "Chain"
259 }
260 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
261 match idx {
262 0usize => Some(Field::new("default_flags", self.default_flags())),
263 1usize => Some(Field::new("chain_length", self.chain_length())),
264 2usize => Some(Field::new("n_feature_entries", self.n_feature_entries())),
265 3usize => Some(Field::new("n_subtables", self.n_subtables())),
266 4usize => Some(Field::new(
267 "features",
268 traversal::FieldType::array_of_records(
269 stringify!(Feature),
270 self.features(),
271 self.offset_data(),
272 ),
273 )),
274 5usize => Some(Field::new(
275 "subtables",
276 traversal::FieldType::var_array("Subtable", self.subtables(), self.offset_data()),
277 )),
278 _ => None,
279 }
280 }
281}
282
283#[cfg(feature = "experimental_traverse")]
284#[allow(clippy::needless_lifetimes)]
285impl<'a> std::fmt::Debug for Chain<'a> {
286 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287 (self as &dyn SomeTable<'a>).fmt(f)
288 }
289}
290
291#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
293#[repr(C)]
294#[repr(packed)]
295pub struct Feature {
296 pub feature_type: BigEndian<u16>,
298 pub feature_settings: BigEndian<u16>,
300 pub enable_flags: BigEndian<u32>,
302 pub disable_flags: BigEndian<u32>,
304}
305
306impl Feature {
307 pub fn feature_type(&self) -> u16 {
309 self.feature_type.get()
310 }
311
312 pub fn feature_settings(&self) -> u16 {
314 self.feature_settings.get()
315 }
316
317 pub fn enable_flags(&self) -> u32 {
319 self.enable_flags.get()
320 }
321
322 pub fn disable_flags(&self) -> u32 {
324 self.disable_flags.get()
325 }
326}
327
328impl FixedSize for Feature {
329 const RAW_BYTE_LEN: usize =
330 u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
331}
332
333#[cfg(feature = "experimental_traverse")]
334impl<'a> SomeRecord<'a> for Feature {
335 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
336 RecordResolver {
337 name: "Feature",
338 get_field: Box::new(move |idx, _data| match idx {
339 0usize => Some(Field::new("feature_type", self.feature_type())),
340 1usize => Some(Field::new("feature_settings", self.feature_settings())),
341 2usize => Some(Field::new("enable_flags", self.enable_flags())),
342 3usize => Some(Field::new("disable_flags", self.disable_flags())),
343 _ => None,
344 }),
345 data,
346 }
347 }
348}
349
350impl<'a> MinByteRange<'a> for Subtable<'a> {
351 fn min_byte_range(&self) -> Range<usize> {
352 0..self.data_byte_range().end
353 }
354 fn min_table_bytes(&self) -> &'a [u8] {
355 let range = self.min_byte_range();
356 self.data.as_bytes().get(range).unwrap_or_default()
357 }
358}
359
360impl<'a> FontRead<'a> for Subtable<'a> {
361 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
362 #[allow(clippy::absurd_extreme_comparisons)]
363 if data.len() < Self::MIN_SIZE {
364 return Err(ReadError::OutOfBounds);
365 }
366 Ok(Self { data })
367 }
368}
369
370#[derive(Clone)]
372pub struct Subtable<'a> {
373 data: FontData<'a>,
374}
375
376#[allow(clippy::needless_lifetimes)]
377impl<'a> Subtable<'a> {
378 pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
379 basic_table_impls!(impl_the_methods);
380
381 pub fn length(&self) -> u32 {
383 let range = self.length_byte_range();
384 self.data.read_at(range.start).ok().unwrap()
385 }
386
387 pub fn coverage(&self) -> u32 {
389 let range = self.coverage_byte_range();
390 self.data.read_at(range.start).ok().unwrap()
391 }
392
393 pub fn sub_feature_flags(&self) -> u32 {
395 let range = self.sub_feature_flags_byte_range();
396 self.data.read_at(range.start).ok().unwrap()
397 }
398
399 pub fn data(&self) -> &'a [u8] {
401 let range = self.data_byte_range();
402 self.data.read_array(range).ok().unwrap_or_default()
403 }
404
405 pub fn length_byte_range(&self) -> Range<usize> {
406 let start = 0;
407 let end = start + u32::RAW_BYTE_LEN;
408 start..end
409 }
410
411 pub fn coverage_byte_range(&self) -> Range<usize> {
412 let start = self.length_byte_range().end;
413 let end = start + u32::RAW_BYTE_LEN;
414 start..end
415 }
416
417 pub fn sub_feature_flags_byte_range(&self) -> Range<usize> {
418 let start = self.coverage_byte_range().end;
419 let end = start + u32::RAW_BYTE_LEN;
420 start..end
421 }
422
423 pub fn data_byte_range(&self) -> Range<usize> {
424 let start = self.sub_feature_flags_byte_range().end;
425 let end =
426 start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
427 start..end
428 }
429}
430
431const _: () = assert!(FontData::default_data_long_enough(Subtable::MIN_SIZE));
432
433impl Default for Subtable<'_> {
434 fn default() -> Self {
435 Self {
436 data: FontData::default_table_data(),
437 }
438 }
439}
440
441#[cfg(feature = "experimental_traverse")]
442impl<'a> SomeTable<'a> for Subtable<'a> {
443 fn type_name(&self) -> &str {
444 "Subtable"
445 }
446 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
447 match idx {
448 0usize => Some(Field::new("length", self.length())),
449 1usize => Some(Field::new("coverage", self.coverage())),
450 2usize => Some(Field::new("sub_feature_flags", self.sub_feature_flags())),
451 3usize => Some(Field::new("data", self.data())),
452 _ => None,
453 }
454 }
455}
456
457#[cfg(feature = "experimental_traverse")]
458#[allow(clippy::needless_lifetimes)]
459impl<'a> std::fmt::Debug for Subtable<'a> {
460 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
461 (self as &dyn SomeTable<'a>).fmt(f)
462 }
463}
464
465#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
467#[repr(C)]
468#[repr(packed)]
469pub struct ContextualEntryData {
470 pub mark_index: BigEndian<u16>,
473 pub current_index: BigEndian<u16>,
476}
477
478impl ContextualEntryData {
479 pub fn mark_index(&self) -> u16 {
482 self.mark_index.get()
483 }
484
485 pub fn current_index(&self) -> u16 {
488 self.current_index.get()
489 }
490}
491
492impl FixedSize for ContextualEntryData {
493 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
494}
495
496#[cfg(feature = "experimental_traverse")]
497impl<'a> SomeRecord<'a> for ContextualEntryData {
498 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
499 RecordResolver {
500 name: "ContextualEntryData",
501 get_field: Box::new(move |idx, _data| match idx {
502 0usize => Some(Field::new("mark_index", self.mark_index())),
503 1usize => Some(Field::new("current_index", self.current_index())),
504 _ => None,
505 }),
506 data,
507 }
508 }
509}
510
511#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
513#[repr(C)]
514#[repr(packed)]
515pub struct InsertionEntryData {
516 pub current_insert_index: BigEndian<u16>,
520 pub marked_insert_index: BigEndian<u16>,
525}
526
527impl InsertionEntryData {
528 pub fn current_insert_index(&self) -> u16 {
532 self.current_insert_index.get()
533 }
534
535 pub fn marked_insert_index(&self) -> u16 {
540 self.marked_insert_index.get()
541 }
542}
543
544impl FixedSize for InsertionEntryData {
545 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
546}
547
548#[cfg(feature = "experimental_traverse")]
549impl<'a> SomeRecord<'a> for InsertionEntryData {
550 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
551 RecordResolver {
552 name: "InsertionEntryData",
553 get_field: Box::new(move |idx, _data| match idx {
554 0usize => Some(Field::new(
555 "current_insert_index",
556 self.current_insert_index(),
557 )),
558 1usize => Some(Field::new(
559 "marked_insert_index",
560 self.marked_insert_index(),
561 )),
562 _ => None,
563 }),
564 data,
565 }
566 }
567}