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