1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8#[derive(Debug, Clone, Copy)]
10#[doc(hidden)]
11pub struct MorxMarker {
12 chains_byte_len: usize,
13}
14
15impl MorxMarker {
16 pub fn version_byte_range(&self) -> Range<usize> {
17 let start = 0;
18 start..start + u16::RAW_BYTE_LEN
19 }
20
21 pub fn unused_byte_range(&self) -> Range<usize> {
22 let start = self.version_byte_range().end;
23 start..start + u16::RAW_BYTE_LEN
24 }
25
26 pub fn n_chains_byte_range(&self) -> Range<usize> {
27 let start = self.unused_byte_range().end;
28 start..start + u32::RAW_BYTE_LEN
29 }
30
31 pub fn chains_byte_range(&self) -> Range<usize> {
32 let start = self.n_chains_byte_range().end;
33 start..start + self.chains_byte_len
34 }
35}
36
37impl MinByteRange for MorxMarker {
38 fn min_byte_range(&self) -> Range<usize> {
39 0..self.chains_byte_range().end
40 }
41}
42
43impl TopLevelTable for Morx<'_> {
44 const TAG: Tag = Tag::new(b"morx");
46}
47
48impl<'a> FontRead<'a> for Morx<'a> {
49 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
50 let mut cursor = data.cursor();
51 cursor.advance::<u16>();
52 cursor.advance::<u16>();
53 let n_chains: u32 = cursor.read()?;
54 let chains_byte_len = {
55 let data = cursor.remaining().ok_or(ReadError::OutOfBounds)?;
56 <Chain as VarSize>::total_len_for_count(data, n_chains as usize)?
57 };
58 cursor.advance_by(chains_byte_len);
59 cursor.finish(MorxMarker { chains_byte_len })
60 }
61}
62
63pub type Morx<'a> = TableRef<'a, MorxMarker>;
65
66#[allow(clippy::needless_lifetimes)]
67impl<'a> Morx<'a> {
68 pub fn version(&self) -> u16 {
70 let range = self.shape.version_byte_range();
71 self.data.read_at(range.start).unwrap()
72 }
73
74 pub fn n_chains(&self) -> u32 {
76 let range = self.shape.n_chains_byte_range();
77 self.data.read_at(range.start).unwrap()
78 }
79
80 pub fn chains(&self) -> VarLenArray<'a, Chain<'a>> {
81 let range = self.shape.chains_byte_range();
82 VarLenArray::read(self.data.split_off(range.start).unwrap()).unwrap()
83 }
84}
85
86#[cfg(feature = "experimental_traverse")]
87impl<'a> SomeTable<'a> for Morx<'a> {
88 fn type_name(&self) -> &str {
89 "Morx"
90 }
91 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
92 match idx {
93 0usize => Some(Field::new("version", self.version())),
94 1usize => Some(Field::new("n_chains", self.n_chains())),
95 2usize => Some(Field::new(
96 "chains",
97 traversal::FieldType::var_array("Chain", self.chains(), self.offset_data()),
98 )),
99 _ => None,
100 }
101 }
102}
103
104#[cfg(feature = "experimental_traverse")]
105#[allow(clippy::needless_lifetimes)]
106impl<'a> std::fmt::Debug for Morx<'a> {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 (self as &dyn SomeTable<'a>).fmt(f)
109 }
110}
111
112#[derive(Debug, Clone, Copy)]
114#[doc(hidden)]
115pub struct ChainMarker {
116 features_byte_len: usize,
117 subtables_byte_len: usize,
118}
119
120impl ChainMarker {
121 pub fn default_flags_byte_range(&self) -> Range<usize> {
122 let start = 0;
123 start..start + u32::RAW_BYTE_LEN
124 }
125
126 pub fn chain_length_byte_range(&self) -> Range<usize> {
127 let start = self.default_flags_byte_range().end;
128 start..start + u32::RAW_BYTE_LEN
129 }
130
131 pub fn n_feature_entries_byte_range(&self) -> Range<usize> {
132 let start = self.chain_length_byte_range().end;
133 start..start + u32::RAW_BYTE_LEN
134 }
135
136 pub fn n_subtables_byte_range(&self) -> Range<usize> {
137 let start = self.n_feature_entries_byte_range().end;
138 start..start + u32::RAW_BYTE_LEN
139 }
140
141 pub fn features_byte_range(&self) -> Range<usize> {
142 let start = self.n_subtables_byte_range().end;
143 start..start + self.features_byte_len
144 }
145
146 pub fn subtables_byte_range(&self) -> Range<usize> {
147 let start = self.features_byte_range().end;
148 start..start + self.subtables_byte_len
149 }
150}
151
152impl MinByteRange for ChainMarker {
153 fn min_byte_range(&self) -> Range<usize> {
154 0..self.subtables_byte_range().end
155 }
156}
157
158impl<'a> FontRead<'a> for Chain<'a> {
159 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
160 let mut cursor = data.cursor();
161 cursor.advance::<u32>();
162 cursor.advance::<u32>();
163 let n_feature_entries: u32 = cursor.read()?;
164 let n_subtables: u32 = cursor.read()?;
165 let features_byte_len = (n_feature_entries as usize)
166 .checked_mul(Feature::RAW_BYTE_LEN)
167 .ok_or(ReadError::OutOfBounds)?;
168 cursor.advance_by(features_byte_len);
169 let subtables_byte_len = {
170 let data = cursor.remaining().ok_or(ReadError::OutOfBounds)?;
171 <Subtable as VarSize>::total_len_for_count(data, n_subtables as usize)?
172 };
173 cursor.advance_by(subtables_byte_len);
174 cursor.finish(ChainMarker {
175 features_byte_len,
176 subtables_byte_len,
177 })
178 }
179}
180
181pub type Chain<'a> = TableRef<'a, ChainMarker>;
183
184#[allow(clippy::needless_lifetimes)]
185impl<'a> Chain<'a> {
186 pub fn default_flags(&self) -> u32 {
188 let range = self.shape.default_flags_byte_range();
189 self.data.read_at(range.start).unwrap()
190 }
191
192 pub fn chain_length(&self) -> u32 {
194 let range = self.shape.chain_length_byte_range();
195 self.data.read_at(range.start).unwrap()
196 }
197
198 pub fn n_feature_entries(&self) -> u32 {
200 let range = self.shape.n_feature_entries_byte_range();
201 self.data.read_at(range.start).unwrap()
202 }
203
204 pub fn n_subtables(&self) -> u32 {
206 let range = self.shape.n_subtables_byte_range();
207 self.data.read_at(range.start).unwrap()
208 }
209
210 pub fn features(&self) -> &'a [Feature] {
212 let range = self.shape.features_byte_range();
213 self.data.read_array(range).unwrap()
214 }
215
216 pub fn subtables(&self) -> VarLenArray<'a, Subtable<'a>> {
218 let range = self.shape.subtables_byte_range();
219 VarLenArray::read(self.data.split_off(range.start).unwrap()).unwrap()
220 }
221}
222
223#[cfg(feature = "experimental_traverse")]
224impl<'a> SomeTable<'a> for Chain<'a> {
225 fn type_name(&self) -> &str {
226 "Chain"
227 }
228 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
229 match idx {
230 0usize => Some(Field::new("default_flags", self.default_flags())),
231 1usize => Some(Field::new("chain_length", self.chain_length())),
232 2usize => Some(Field::new("n_feature_entries", self.n_feature_entries())),
233 3usize => Some(Field::new("n_subtables", self.n_subtables())),
234 4usize => Some(Field::new(
235 "features",
236 traversal::FieldType::array_of_records(
237 stringify!(Feature),
238 self.features(),
239 self.offset_data(),
240 ),
241 )),
242 5usize => Some(Field::new(
243 "subtables",
244 traversal::FieldType::var_array("Subtable", self.subtables(), self.offset_data()),
245 )),
246 _ => None,
247 }
248 }
249}
250
251#[cfg(feature = "experimental_traverse")]
252#[allow(clippy::needless_lifetimes)]
253impl<'a> std::fmt::Debug for Chain<'a> {
254 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
255 (self as &dyn SomeTable<'a>).fmt(f)
256 }
257}
258
259#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
261#[repr(C)]
262#[repr(packed)]
263pub struct Feature {
264 pub feature_type: BigEndian<u16>,
266 pub feature_settings: BigEndian<u16>,
268 pub enable_flags: BigEndian<u32>,
270 pub disable_flags: BigEndian<u32>,
272}
273
274impl Feature {
275 pub fn feature_type(&self) -> u16 {
277 self.feature_type.get()
278 }
279
280 pub fn feature_settings(&self) -> u16 {
282 self.feature_settings.get()
283 }
284
285 pub fn enable_flags(&self) -> u32 {
287 self.enable_flags.get()
288 }
289
290 pub fn disable_flags(&self) -> u32 {
292 self.disable_flags.get()
293 }
294}
295
296impl FixedSize for Feature {
297 const RAW_BYTE_LEN: usize =
298 u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
299}
300
301#[cfg(feature = "experimental_traverse")]
302impl<'a> SomeRecord<'a> for Feature {
303 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
304 RecordResolver {
305 name: "Feature",
306 get_field: Box::new(move |idx, _data| match idx {
307 0usize => Some(Field::new("feature_type", self.feature_type())),
308 1usize => Some(Field::new("feature_settings", self.feature_settings())),
309 2usize => Some(Field::new("enable_flags", self.enable_flags())),
310 3usize => Some(Field::new("disable_flags", self.disable_flags())),
311 _ => None,
312 }),
313 data,
314 }
315 }
316}
317
318#[derive(Debug, Clone, Copy)]
320#[doc(hidden)]
321pub struct SubtableMarker {
322 data_byte_len: usize,
323}
324
325impl SubtableMarker {
326 pub fn length_byte_range(&self) -> Range<usize> {
327 let start = 0;
328 start..start + u32::RAW_BYTE_LEN
329 }
330
331 pub fn coverage_byte_range(&self) -> Range<usize> {
332 let start = self.length_byte_range().end;
333 start..start + u32::RAW_BYTE_LEN
334 }
335
336 pub fn sub_feature_flags_byte_range(&self) -> Range<usize> {
337 let start = self.coverage_byte_range().end;
338 start..start + u32::RAW_BYTE_LEN
339 }
340
341 pub fn data_byte_range(&self) -> Range<usize> {
342 let start = self.sub_feature_flags_byte_range().end;
343 start..start + self.data_byte_len
344 }
345}
346
347impl MinByteRange for SubtableMarker {
348 fn min_byte_range(&self) -> Range<usize> {
349 0..self.data_byte_range().end
350 }
351}
352
353impl<'a> FontRead<'a> for Subtable<'a> {
354 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
355 let mut cursor = data.cursor();
356 cursor.advance::<u32>();
357 cursor.advance::<u32>();
358 cursor.advance::<u32>();
359 let data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
360 cursor.advance_by(data_byte_len);
361 cursor.finish(SubtableMarker { data_byte_len })
362 }
363}
364
365pub type Subtable<'a> = TableRef<'a, SubtableMarker>;
367
368#[allow(clippy::needless_lifetimes)]
369impl<'a> Subtable<'a> {
370 pub fn length(&self) -> u32 {
372 let range = self.shape.length_byte_range();
373 self.data.read_at(range.start).unwrap()
374 }
375
376 pub fn coverage(&self) -> u32 {
378 let range = self.shape.coverage_byte_range();
379 self.data.read_at(range.start).unwrap()
380 }
381
382 pub fn sub_feature_flags(&self) -> u32 {
384 let range = self.shape.sub_feature_flags_byte_range();
385 self.data.read_at(range.start).unwrap()
386 }
387
388 pub fn data(&self) -> &'a [u8] {
390 let range = self.shape.data_byte_range();
391 self.data.read_array(range).unwrap()
392 }
393}
394
395#[cfg(feature = "experimental_traverse")]
396impl<'a> SomeTable<'a> for Subtable<'a> {
397 fn type_name(&self) -> &str {
398 "Subtable"
399 }
400 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
401 match idx {
402 0usize => Some(Field::new("length", self.length())),
403 1usize => Some(Field::new("coverage", self.coverage())),
404 2usize => Some(Field::new("sub_feature_flags", self.sub_feature_flags())),
405 3usize => Some(Field::new("data", self.data())),
406 _ => None,
407 }
408 }
409}
410
411#[cfg(feature = "experimental_traverse")]
412#[allow(clippy::needless_lifetimes)]
413impl<'a> std::fmt::Debug for Subtable<'a> {
414 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
415 (self as &dyn SomeTable<'a>).fmt(f)
416 }
417}
418
419#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
421#[repr(C)]
422#[repr(packed)]
423pub struct ContextualEntryData {
424 pub mark_index: BigEndian<u16>,
427 pub current_index: BigEndian<u16>,
430}
431
432impl ContextualEntryData {
433 pub fn mark_index(&self) -> u16 {
436 self.mark_index.get()
437 }
438
439 pub fn current_index(&self) -> u16 {
442 self.current_index.get()
443 }
444}
445
446impl FixedSize for ContextualEntryData {
447 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
448}
449
450#[cfg(feature = "experimental_traverse")]
451impl<'a> SomeRecord<'a> for ContextualEntryData {
452 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
453 RecordResolver {
454 name: "ContextualEntryData",
455 get_field: Box::new(move |idx, _data| match idx {
456 0usize => Some(Field::new("mark_index", self.mark_index())),
457 1usize => Some(Field::new("current_index", self.current_index())),
458 _ => None,
459 }),
460 data,
461 }
462 }
463}
464
465#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
467#[repr(C)]
468#[repr(packed)]
469pub struct InsertionEntryData {
470 pub current_insert_index: BigEndian<u16>,
474 pub marked_insert_index: BigEndian<u16>,
479}
480
481impl InsertionEntryData {
482 pub fn current_insert_index(&self) -> u16 {
486 self.current_insert_index.get()
487 }
488
489 pub fn marked_insert_index(&self) -> u16 {
494 self.marked_insert_index.get()
495 }
496}
497
498impl FixedSize for InsertionEntryData {
499 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
500}
501
502#[cfg(feature = "experimental_traverse")]
503impl<'a> SomeRecord<'a> for InsertionEntryData {
504 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
505 RecordResolver {
506 name: "InsertionEntryData",
507 get_field: Box::new(move |idx, _data| match idx {
508 0usize => Some(Field::new(
509 "current_insert_index",
510 self.current_insert_index(),
511 )),
512 1usize => Some(Field::new(
513 "marked_insert_index",
514 self.marked_insert_index(),
515 )),
516 _ => None,
517 }),
518 data,
519 }
520 }
521}