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