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