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