/src/fontations/read-fonts/generated/generated_gdef.rs
Line | Count | Source |
1 | | // THIS FILE IS AUTOGENERATED. |
2 | | // Any changes to this file will be overwritten. |
3 | | // For more information about how codegen works, see font-codegen/README.md |
4 | | |
5 | | #[allow(unused_imports)] |
6 | | use crate::codegen_prelude::*; |
7 | | |
8 | | impl<'a> MinByteRange<'a> for Gdef<'a> { |
9 | 0 | fn min_byte_range(&self) -> Range<usize> { |
10 | 0 | 0..self.mark_attach_class_def_offset_byte_range().end |
11 | 0 | } |
12 | 0 | fn min_table_bytes(&self) -> &'a [u8] { |
13 | 0 | let range = self.min_byte_range(); |
14 | 0 | self.data.as_bytes().get(range).unwrap_or_default() |
15 | 0 | } |
16 | | } |
17 | | |
18 | | impl TopLevelTable for Gdef<'_> { |
19 | | /// `GDEF` |
20 | | const TAG: Tag = Tag::new(b"GDEF"); |
21 | | } |
22 | | |
23 | | impl<'a> FontRead<'a> for Gdef<'a> { |
24 | 0 | fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
25 | | #[allow(clippy::absurd_extreme_comparisons)] |
26 | 0 | if data.len() < Self::MIN_SIZE { |
27 | 0 | return Err(ReadError::OutOfBounds); |
28 | 0 | } |
29 | 0 | Ok(Self { data }) |
30 | 0 | } |
31 | | } |
32 | | |
33 | | /// [GDEF](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#gdef-header) 1.0 |
34 | | #[derive(Clone)] |
35 | | pub struct Gdef<'a> { |
36 | | data: FontData<'a>, |
37 | | } |
38 | | |
39 | | #[allow(clippy::needless_lifetimes)] |
40 | | impl<'a> Gdef<'a> { |
41 | | pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN |
42 | | + Offset16::RAW_BYTE_LEN |
43 | | + Offset16::RAW_BYTE_LEN |
44 | | + Offset16::RAW_BYTE_LEN |
45 | | + Offset16::RAW_BYTE_LEN); |
46 | | basic_table_impls!(impl_the_methods); |
47 | | |
48 | | /// The major/minor version of the GDEF table |
49 | 0 | pub fn version(&self) -> MajorMinor { |
50 | 0 | let range = self.version_byte_range(); |
51 | 0 | self.data.read_at(range.start).ok().unwrap() |
52 | 0 | } |
53 | | |
54 | | /// Offset to class definition table for glyph type, from beginning |
55 | | /// of GDEF header (may be NULL) |
56 | 0 | pub fn glyph_class_def_offset(&self) -> Nullable<Offset16> { |
57 | 0 | let range = self.glyph_class_def_offset_byte_range(); |
58 | 0 | self.data.read_at(range.start).ok().unwrap() |
59 | 0 | } |
60 | | |
61 | | /// Attempt to resolve [`glyph_class_def_offset`][Self::glyph_class_def_offset]. |
62 | 0 | pub fn glyph_class_def(&self) -> Option<Result<ClassDef<'a>, ReadError>> { |
63 | 0 | let data = self.data; |
64 | 0 | self.glyph_class_def_offset().resolve(data) |
65 | 0 | } |
66 | | |
67 | | /// Offset to attachment point list table, from beginning of GDEF |
68 | | /// header (may be NULL) |
69 | 0 | pub fn attach_list_offset(&self) -> Nullable<Offset16> { |
70 | 0 | let range = self.attach_list_offset_byte_range(); |
71 | 0 | self.data.read_at(range.start).ok().unwrap() |
72 | 0 | } |
73 | | |
74 | | /// Attempt to resolve [`attach_list_offset`][Self::attach_list_offset]. |
75 | 0 | pub fn attach_list(&self) -> Option<Result<AttachList<'a>, ReadError>> { |
76 | 0 | let data = self.data; |
77 | 0 | self.attach_list_offset().resolve(data) |
78 | 0 | } |
79 | | |
80 | | /// Offset to ligature caret list table, from beginning of GDEF |
81 | | /// header (may be NULL) |
82 | 0 | pub fn lig_caret_list_offset(&self) -> Nullable<Offset16> { |
83 | 0 | let range = self.lig_caret_list_offset_byte_range(); |
84 | 0 | self.data.read_at(range.start).ok().unwrap() |
85 | 0 | } |
86 | | |
87 | | /// Attempt to resolve [`lig_caret_list_offset`][Self::lig_caret_list_offset]. |
88 | 0 | pub fn lig_caret_list(&self) -> Option<Result<LigCaretList<'a>, ReadError>> { |
89 | 0 | let data = self.data; |
90 | 0 | self.lig_caret_list_offset().resolve(data) |
91 | 0 | } |
92 | | |
93 | | /// Offset to class definition table for mark attachment type, from |
94 | | /// beginning of GDEF header (may be NULL) |
95 | 0 | pub fn mark_attach_class_def_offset(&self) -> Nullable<Offset16> { |
96 | 0 | let range = self.mark_attach_class_def_offset_byte_range(); |
97 | 0 | self.data.read_at(range.start).ok().unwrap() |
98 | 0 | } |
99 | | |
100 | | /// Attempt to resolve [`mark_attach_class_def_offset`][Self::mark_attach_class_def_offset]. |
101 | 0 | pub fn mark_attach_class_def(&self) -> Option<Result<ClassDef<'a>, ReadError>> { |
102 | 0 | let data = self.data; |
103 | 0 | self.mark_attach_class_def_offset().resolve(data) |
104 | 0 | } |
105 | | |
106 | | /// Offset to the table of mark glyph set definitions, from |
107 | | /// beginning of GDEF header (may be NULL) |
108 | 0 | pub fn mark_glyph_sets_def_offset(&self) -> Option<Nullable<Offset16>> { |
109 | 0 | let range = self.mark_glyph_sets_def_offset_byte_range(); |
110 | 0 | (!range.is_empty()) |
111 | 0 | .then(|| self.data.read_at(range.start).ok()) |
112 | 0 | .flatten() |
113 | 0 | } |
114 | | |
115 | | /// Attempt to resolve [`mark_glyph_sets_def_offset`][Self::mark_glyph_sets_def_offset]. |
116 | 0 | pub fn mark_glyph_sets_def(&self) -> Option<Result<MarkGlyphSets<'a>, ReadError>> { |
117 | 0 | let data = self.data; |
118 | 0 | self.mark_glyph_sets_def_offset().map(|x| x.resolve(data))? |
119 | 0 | } |
120 | | |
121 | | /// Offset to the Item Variation Store table, from beginning of |
122 | | /// GDEF header (may be NULL) |
123 | 0 | pub fn item_var_store_offset(&self) -> Option<Nullable<Offset32>> { |
124 | 0 | let range = self.item_var_store_offset_byte_range(); |
125 | 0 | (!range.is_empty()) |
126 | 0 | .then(|| self.data.read_at(range.start).ok()) |
127 | 0 | .flatten() |
128 | 0 | } |
129 | | |
130 | | /// Attempt to resolve [`item_var_store_offset`][Self::item_var_store_offset]. |
131 | 0 | pub fn item_var_store(&self) -> Option<Result<ItemVariationStore<'a>, ReadError>> { |
132 | 0 | let data = self.data; |
133 | 0 | self.item_var_store_offset().map(|x| x.resolve(data))? |
134 | 0 | } |
135 | | |
136 | 0 | pub fn version_byte_range(&self) -> Range<usize> { |
137 | 0 | let start = 0; |
138 | 0 | start..start + MajorMinor::RAW_BYTE_LEN |
139 | 0 | } |
140 | | |
141 | 0 | pub fn glyph_class_def_offset_byte_range(&self) -> Range<usize> { |
142 | 0 | let start = self.version_byte_range().end; |
143 | 0 | start..start + Offset16::RAW_BYTE_LEN |
144 | 0 | } |
145 | | |
146 | 0 | pub fn attach_list_offset_byte_range(&self) -> Range<usize> { |
147 | 0 | let start = self.glyph_class_def_offset_byte_range().end; |
148 | 0 | start..start + Offset16::RAW_BYTE_LEN |
149 | 0 | } |
150 | | |
151 | 0 | pub fn lig_caret_list_offset_byte_range(&self) -> Range<usize> { |
152 | 0 | let start = self.attach_list_offset_byte_range().end; |
153 | 0 | start..start + Offset16::RAW_BYTE_LEN |
154 | 0 | } |
155 | | |
156 | 0 | pub fn mark_attach_class_def_offset_byte_range(&self) -> Range<usize> { |
157 | 0 | let start = self.lig_caret_list_offset_byte_range().end; |
158 | 0 | start..start + Offset16::RAW_BYTE_LEN |
159 | 0 | } |
160 | | |
161 | 0 | pub fn mark_glyph_sets_def_offset_byte_range(&self) -> Range<usize> { |
162 | 0 | let start = self.mark_attach_class_def_offset_byte_range().end; |
163 | 0 | start |
164 | 0 | ..(self.version().compatible((1u16, 2u16))) |
165 | 0 | .then(|| start + Offset16::RAW_BYTE_LEN) |
166 | 0 | .unwrap_or(start) |
167 | 0 | } |
168 | | |
169 | 0 | pub fn item_var_store_offset_byte_range(&self) -> Range<usize> { |
170 | 0 | let start = self.mark_glyph_sets_def_offset_byte_range().end; |
171 | 0 | start |
172 | 0 | ..(self.version().compatible((1u16, 3u16))) |
173 | 0 | .then(|| start + Offset32::RAW_BYTE_LEN) |
174 | 0 | .unwrap_or(start) |
175 | 0 | } |
176 | | } |
177 | | |
178 | | #[cfg(feature = "experimental_traverse")] |
179 | | impl<'a> SomeTable<'a> for Gdef<'a> { |
180 | | fn type_name(&self) -> &str { |
181 | | "Gdef" |
182 | | } |
183 | | fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
184 | | match idx { |
185 | | 0usize => Some(Field::new("version", self.version())), |
186 | | 1usize => Some(Field::new( |
187 | | "glyph_class_def_offset", |
188 | | FieldType::offset(self.glyph_class_def_offset(), self.glyph_class_def()), |
189 | | )), |
190 | | 2usize => Some(Field::new( |
191 | | "attach_list_offset", |
192 | | FieldType::offset(self.attach_list_offset(), self.attach_list()), |
193 | | )), |
194 | | 3usize => Some(Field::new( |
195 | | "lig_caret_list_offset", |
196 | | FieldType::offset(self.lig_caret_list_offset(), self.lig_caret_list()), |
197 | | )), |
198 | | 4usize => Some(Field::new( |
199 | | "mark_attach_class_def_offset", |
200 | | FieldType::offset( |
201 | | self.mark_attach_class_def_offset(), |
202 | | self.mark_attach_class_def(), |
203 | | ), |
204 | | )), |
205 | | 5usize if self.version().compatible((1u16, 2u16)) => Some(Field::new( |
206 | | "mark_glyph_sets_def_offset", |
207 | | FieldType::offset( |
208 | | self.mark_glyph_sets_def_offset().unwrap(), |
209 | | self.mark_glyph_sets_def(), |
210 | | ), |
211 | | )), |
212 | | 6usize if self.version().compatible((1u16, 3u16)) => Some(Field::new( |
213 | | "item_var_store_offset", |
214 | | FieldType::offset(self.item_var_store_offset().unwrap(), self.item_var_store()), |
215 | | )), |
216 | | _ => None, |
217 | | } |
218 | | } |
219 | | } |
220 | | |
221 | | #[cfg(feature = "experimental_traverse")] |
222 | | #[allow(clippy::needless_lifetimes)] |
223 | | impl<'a> std::fmt::Debug for Gdef<'a> { |
224 | | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
225 | | (self as &dyn SomeTable<'a>).fmt(f) |
226 | | } |
227 | | } |
228 | | |
229 | | /// Used in the [Glyph Class Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#glyph-class-definition-table) |
230 | | #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] |
231 | | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
232 | | #[repr(u16)] |
233 | | #[allow(clippy::manual_non_exhaustive)] |
234 | | pub enum GlyphClassDef { |
235 | | #[default] |
236 | | Base = 1, |
237 | | Ligature = 2, |
238 | | Mark = 3, |
239 | | Component = 4, |
240 | | #[doc(hidden)] |
241 | | /// If font data is malformed we will map unknown values to this variant |
242 | | Unknown, |
243 | | } |
244 | | |
245 | | impl GlyphClassDef { |
246 | | /// Create from a raw scalar. |
247 | | /// |
248 | | /// This will never fail; unknown values will be mapped to the `Unknown` variant |
249 | 0 | pub fn new(raw: u16) -> Self { |
250 | 0 | match raw { |
251 | 0 | 1 => Self::Base, |
252 | 0 | 2 => Self::Ligature, |
253 | 0 | 3 => Self::Mark, |
254 | 0 | 4 => Self::Component, |
255 | 0 | _ => Self::Unknown, |
256 | | } |
257 | 0 | } |
258 | | } |
259 | | |
260 | | impl font_types::Scalar for GlyphClassDef { |
261 | | type Raw = <u16 as font_types::Scalar>::Raw; |
262 | 0 | fn to_raw(self) -> Self::Raw { |
263 | 0 | (self as u16).to_raw() |
264 | 0 | } |
265 | 0 | fn from_raw(raw: Self::Raw) -> Self { |
266 | 0 | let t = <u16>::from_raw(raw); |
267 | 0 | Self::new(t) |
268 | 0 | } |
269 | | } |
270 | | |
271 | | #[cfg(feature = "experimental_traverse")] |
272 | | impl<'a> From<GlyphClassDef> for FieldType<'a> { |
273 | | fn from(src: GlyphClassDef) -> FieldType<'a> { |
274 | | (src as u16).into() |
275 | | } |
276 | | } |
277 | | |
278 | | impl<'a> MinByteRange<'a> for AttachList<'a> { |
279 | 0 | fn min_byte_range(&self) -> Range<usize> { |
280 | 0 | 0..self.attach_point_offsets_byte_range().end |
281 | 0 | } |
282 | 0 | fn min_table_bytes(&self) -> &'a [u8] { |
283 | 0 | let range = self.min_byte_range(); |
284 | 0 | self.data.as_bytes().get(range).unwrap_or_default() |
285 | 0 | } |
286 | | } |
287 | | |
288 | | impl<'a> FontRead<'a> for AttachList<'a> { |
289 | 0 | fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
290 | | #[allow(clippy::absurd_extreme_comparisons)] |
291 | 0 | if data.len() < Self::MIN_SIZE { |
292 | 0 | return Err(ReadError::OutOfBounds); |
293 | 0 | } |
294 | 0 | Ok(Self { data }) |
295 | 0 | } |
296 | | } |
297 | | |
298 | | /// [Attachment Point List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#attachment-point-list-table) |
299 | | #[derive(Clone)] |
300 | | pub struct AttachList<'a> { |
301 | | data: FontData<'a>, |
302 | | } |
303 | | |
304 | | #[allow(clippy::needless_lifetimes)] |
305 | | impl<'a> AttachList<'a> { |
306 | | pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); |
307 | | basic_table_impls!(impl_the_methods); |
308 | | |
309 | | /// Offset to Coverage table - from beginning of AttachList table |
310 | 0 | pub fn coverage_offset(&self) -> Offset16 { |
311 | 0 | let range = self.coverage_offset_byte_range(); |
312 | 0 | self.data.read_at(range.start).ok().unwrap() |
313 | 0 | } |
314 | | |
315 | | /// Attempt to resolve [`coverage_offset`][Self::coverage_offset]. |
316 | 0 | pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> { |
317 | 0 | let data = self.data; |
318 | 0 | self.coverage_offset().resolve(data) |
319 | 0 | } |
320 | | |
321 | | /// Number of glyphs with attachment points |
322 | 0 | pub fn glyph_count(&self) -> u16 { |
323 | 0 | let range = self.glyph_count_byte_range(); |
324 | 0 | self.data.read_at(range.start).ok().unwrap() |
325 | 0 | } |
326 | | |
327 | | /// Array of offsets to AttachPoint tables-from beginning of |
328 | | /// AttachList table-in Coverage Index order |
329 | 0 | pub fn attach_point_offsets(&self) -> &'a [BigEndian<Offset16>] { |
330 | 0 | let range = self.attach_point_offsets_byte_range(); |
331 | 0 | self.data.read_array(range).ok().unwrap_or_default() |
332 | 0 | } |
333 | | |
334 | | /// A dynamically resolving wrapper for [`attach_point_offsets`][Self::attach_point_offsets]. |
335 | 0 | pub fn attach_points(&self) -> ArrayOfOffsets<'a, AttachPoint<'a>, Offset16> { |
336 | 0 | let data = self.data; |
337 | 0 | let offsets = self.attach_point_offsets(); |
338 | 0 | ArrayOfOffsets::new(offsets, data, ()) |
339 | 0 | } |
340 | | |
341 | 0 | pub fn coverage_offset_byte_range(&self) -> Range<usize> { |
342 | 0 | let start = 0; |
343 | 0 | start..start + Offset16::RAW_BYTE_LEN |
344 | 0 | } |
345 | | |
346 | 0 | pub fn glyph_count_byte_range(&self) -> Range<usize> { |
347 | 0 | let start = self.coverage_offset_byte_range().end; |
348 | 0 | start..start + u16::RAW_BYTE_LEN |
349 | 0 | } |
350 | | |
351 | 0 | pub fn attach_point_offsets_byte_range(&self) -> Range<usize> { |
352 | 0 | let glyph_count = self.glyph_count(); |
353 | 0 | let start = self.glyph_count_byte_range().end; |
354 | 0 | start..start + (glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN) |
355 | 0 | } |
356 | | } |
357 | | |
358 | | #[cfg(feature = "experimental_traverse")] |
359 | | impl<'a> SomeTable<'a> for AttachList<'a> { |
360 | | fn type_name(&self) -> &str { |
361 | | "AttachList" |
362 | | } |
363 | | fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
364 | | match idx { |
365 | | 0usize => Some(Field::new( |
366 | | "coverage_offset", |
367 | | FieldType::offset(self.coverage_offset(), self.coverage()), |
368 | | )), |
369 | | 1usize => Some(Field::new("glyph_count", self.glyph_count())), |
370 | | 2usize => Some({ |
371 | | let data = self.data; |
372 | | Field::new( |
373 | | "attach_point_offsets", |
374 | | FieldType::array_of_offsets( |
375 | | better_type_name::<AttachPoint>(), |
376 | | self.attach_point_offsets(), |
377 | | move |off| { |
378 | | let target = off.get().resolve::<AttachPoint>(data); |
379 | | FieldType::offset(off.get(), target) |
380 | | }, |
381 | | ), |
382 | | ) |
383 | | }), |
384 | | _ => None, |
385 | | } |
386 | | } |
387 | | } |
388 | | |
389 | | #[cfg(feature = "experimental_traverse")] |
390 | | #[allow(clippy::needless_lifetimes)] |
391 | | impl<'a> std::fmt::Debug for AttachList<'a> { |
392 | | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
393 | | (self as &dyn SomeTable<'a>).fmt(f) |
394 | | } |
395 | | } |
396 | | |
397 | | impl<'a> MinByteRange<'a> for AttachPoint<'a> { |
398 | 0 | fn min_byte_range(&self) -> Range<usize> { |
399 | 0 | 0..self.point_indices_byte_range().end |
400 | 0 | } |
401 | 0 | fn min_table_bytes(&self) -> &'a [u8] { |
402 | 0 | let range = self.min_byte_range(); |
403 | 0 | self.data.as_bytes().get(range).unwrap_or_default() |
404 | 0 | } |
405 | | } |
406 | | |
407 | | impl<'a> FontRead<'a> for AttachPoint<'a> { |
408 | 0 | fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
409 | | #[allow(clippy::absurd_extreme_comparisons)] |
410 | 0 | if data.len() < Self::MIN_SIZE { |
411 | 0 | return Err(ReadError::OutOfBounds); |
412 | 0 | } |
413 | 0 | Ok(Self { data }) |
414 | 0 | } |
415 | | } |
416 | | |
417 | | /// Part of [AttachList] |
418 | | #[derive(Clone)] |
419 | | pub struct AttachPoint<'a> { |
420 | | data: FontData<'a>, |
421 | | } |
422 | | |
423 | | #[allow(clippy::needless_lifetimes)] |
424 | | impl<'a> AttachPoint<'a> { |
425 | | pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; |
426 | | basic_table_impls!(impl_the_methods); |
427 | | |
428 | | /// Number of attachment points on this glyph |
429 | 0 | pub fn point_count(&self) -> u16 { |
430 | 0 | let range = self.point_count_byte_range(); |
431 | 0 | self.data.read_at(range.start).ok().unwrap() |
432 | 0 | } |
433 | | |
434 | | /// Array of contour point indices -in increasing numerical order |
435 | 0 | pub fn point_indices(&self) -> &'a [BigEndian<u16>] { |
436 | 0 | let range = self.point_indices_byte_range(); |
437 | 0 | self.data.read_array(range).ok().unwrap_or_default() |
438 | 0 | } |
439 | | |
440 | 0 | pub fn point_count_byte_range(&self) -> Range<usize> { |
441 | 0 | let start = 0; |
442 | 0 | start..start + u16::RAW_BYTE_LEN |
443 | 0 | } |
444 | | |
445 | 0 | pub fn point_indices_byte_range(&self) -> Range<usize> { |
446 | 0 | let point_count = self.point_count(); |
447 | 0 | let start = self.point_count_byte_range().end; |
448 | 0 | start..start + (point_count as usize).saturating_mul(u16::RAW_BYTE_LEN) |
449 | 0 | } |
450 | | } |
451 | | |
452 | | #[cfg(feature = "experimental_traverse")] |
453 | | impl<'a> SomeTable<'a> for AttachPoint<'a> { |
454 | | fn type_name(&self) -> &str { |
455 | | "AttachPoint" |
456 | | } |
457 | | fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
458 | | match idx { |
459 | | 0usize => Some(Field::new("point_count", self.point_count())), |
460 | | 1usize => Some(Field::new("point_indices", self.point_indices())), |
461 | | _ => None, |
462 | | } |
463 | | } |
464 | | } |
465 | | |
466 | | #[cfg(feature = "experimental_traverse")] |
467 | | #[allow(clippy::needless_lifetimes)] |
468 | | impl<'a> std::fmt::Debug for AttachPoint<'a> { |
469 | | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
470 | | (self as &dyn SomeTable<'a>).fmt(f) |
471 | | } |
472 | | } |
473 | | |
474 | | impl<'a> MinByteRange<'a> for LigCaretList<'a> { |
475 | 0 | fn min_byte_range(&self) -> Range<usize> { |
476 | 0 | 0..self.lig_glyph_offsets_byte_range().end |
477 | 0 | } |
478 | 0 | fn min_table_bytes(&self) -> &'a [u8] { |
479 | 0 | let range = self.min_byte_range(); |
480 | 0 | self.data.as_bytes().get(range).unwrap_or_default() |
481 | 0 | } |
482 | | } |
483 | | |
484 | | impl<'a> FontRead<'a> for LigCaretList<'a> { |
485 | 0 | fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
486 | | #[allow(clippy::absurd_extreme_comparisons)] |
487 | 0 | if data.len() < Self::MIN_SIZE { |
488 | 0 | return Err(ReadError::OutOfBounds); |
489 | 0 | } |
490 | 0 | Ok(Self { data }) |
491 | 0 | } |
492 | | } |
493 | | |
494 | | /// [Ligature Caret List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#ligature-caret-list-table) |
495 | | #[derive(Clone)] |
496 | | pub struct LigCaretList<'a> { |
497 | | data: FontData<'a>, |
498 | | } |
499 | | |
500 | | #[allow(clippy::needless_lifetimes)] |
501 | | impl<'a> LigCaretList<'a> { |
502 | | pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); |
503 | | basic_table_impls!(impl_the_methods); |
504 | | |
505 | | /// Offset to Coverage table - from beginning of LigCaretList table |
506 | 0 | pub fn coverage_offset(&self) -> Offset16 { |
507 | 0 | let range = self.coverage_offset_byte_range(); |
508 | 0 | self.data.read_at(range.start).ok().unwrap() |
509 | 0 | } |
510 | | |
511 | | /// Attempt to resolve [`coverage_offset`][Self::coverage_offset]. |
512 | 0 | pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> { |
513 | 0 | let data = self.data; |
514 | 0 | self.coverage_offset().resolve(data) |
515 | 0 | } |
516 | | |
517 | | /// Number of ligature glyphs |
518 | 0 | pub fn lig_glyph_count(&self) -> u16 { |
519 | 0 | let range = self.lig_glyph_count_byte_range(); |
520 | 0 | self.data.read_at(range.start).ok().unwrap() |
521 | 0 | } |
522 | | |
523 | | /// Array of offsets to LigGlyph tables, from beginning of |
524 | | /// LigCaretList table —in Coverage Index order |
525 | 0 | pub fn lig_glyph_offsets(&self) -> &'a [BigEndian<Offset16>] { |
526 | 0 | let range = self.lig_glyph_offsets_byte_range(); |
527 | 0 | self.data.read_array(range).ok().unwrap_or_default() |
528 | 0 | } |
529 | | |
530 | | /// A dynamically resolving wrapper for [`lig_glyph_offsets`][Self::lig_glyph_offsets]. |
531 | 0 | pub fn lig_glyphs(&self) -> ArrayOfOffsets<'a, LigGlyph<'a>, Offset16> { |
532 | 0 | let data = self.data; |
533 | 0 | let offsets = self.lig_glyph_offsets(); |
534 | 0 | ArrayOfOffsets::new(offsets, data, ()) |
535 | 0 | } |
536 | | |
537 | 0 | pub fn coverage_offset_byte_range(&self) -> Range<usize> { |
538 | 0 | let start = 0; |
539 | 0 | start..start + Offset16::RAW_BYTE_LEN |
540 | 0 | } |
541 | | |
542 | 0 | pub fn lig_glyph_count_byte_range(&self) -> Range<usize> { |
543 | 0 | let start = self.coverage_offset_byte_range().end; |
544 | 0 | start..start + u16::RAW_BYTE_LEN |
545 | 0 | } |
546 | | |
547 | 0 | pub fn lig_glyph_offsets_byte_range(&self) -> Range<usize> { |
548 | 0 | let lig_glyph_count = self.lig_glyph_count(); |
549 | 0 | let start = self.lig_glyph_count_byte_range().end; |
550 | 0 | start..start + (lig_glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN) |
551 | 0 | } |
552 | | } |
553 | | |
554 | | #[cfg(feature = "experimental_traverse")] |
555 | | impl<'a> SomeTable<'a> for LigCaretList<'a> { |
556 | | fn type_name(&self) -> &str { |
557 | | "LigCaretList" |
558 | | } |
559 | | fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
560 | | match idx { |
561 | | 0usize => Some(Field::new( |
562 | | "coverage_offset", |
563 | | FieldType::offset(self.coverage_offset(), self.coverage()), |
564 | | )), |
565 | | 1usize => Some(Field::new("lig_glyph_count", self.lig_glyph_count())), |
566 | | 2usize => Some({ |
567 | | let data = self.data; |
568 | | Field::new( |
569 | | "lig_glyph_offsets", |
570 | | FieldType::array_of_offsets( |
571 | | better_type_name::<LigGlyph>(), |
572 | | self.lig_glyph_offsets(), |
573 | | move |off| { |
574 | | let target = off.get().resolve::<LigGlyph>(data); |
575 | | FieldType::offset(off.get(), target) |
576 | | }, |
577 | | ), |
578 | | ) |
579 | | }), |
580 | | _ => None, |
581 | | } |
582 | | } |
583 | | } |
584 | | |
585 | | #[cfg(feature = "experimental_traverse")] |
586 | | #[allow(clippy::needless_lifetimes)] |
587 | | impl<'a> std::fmt::Debug for LigCaretList<'a> { |
588 | | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
589 | | (self as &dyn SomeTable<'a>).fmt(f) |
590 | | } |
591 | | } |
592 | | |
593 | | impl<'a> MinByteRange<'a> for LigGlyph<'a> { |
594 | 0 | fn min_byte_range(&self) -> Range<usize> { |
595 | 0 | 0..self.caret_value_offsets_byte_range().end |
596 | 0 | } |
597 | 0 | fn min_table_bytes(&self) -> &'a [u8] { |
598 | 0 | let range = self.min_byte_range(); |
599 | 0 | self.data.as_bytes().get(range).unwrap_or_default() |
600 | 0 | } |
601 | | } |
602 | | |
603 | | impl<'a> FontRead<'a> for LigGlyph<'a> { |
604 | 0 | fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
605 | | #[allow(clippy::absurd_extreme_comparisons)] |
606 | 0 | if data.len() < Self::MIN_SIZE { |
607 | 0 | return Err(ReadError::OutOfBounds); |
608 | 0 | } |
609 | 0 | Ok(Self { data }) |
610 | 0 | } |
611 | | } |
612 | | |
613 | | /// [Ligature Glyph Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#ligature-glyph-table) |
614 | | #[derive(Clone)] |
615 | | pub struct LigGlyph<'a> { |
616 | | data: FontData<'a>, |
617 | | } |
618 | | |
619 | | #[allow(clippy::needless_lifetimes)] |
620 | | impl<'a> LigGlyph<'a> { |
621 | | pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; |
622 | | basic_table_impls!(impl_the_methods); |
623 | | |
624 | | /// Number of CaretValue tables for this ligature (components - 1) |
625 | 0 | pub fn caret_count(&self) -> u16 { |
626 | 0 | let range = self.caret_count_byte_range(); |
627 | 0 | self.data.read_at(range.start).ok().unwrap() |
628 | 0 | } |
629 | | |
630 | | /// Array of offsets to CaretValue tables, from beginning of |
631 | | /// LigGlyph table — in increasing coordinate order |
632 | 0 | pub fn caret_value_offsets(&self) -> &'a [BigEndian<Offset16>] { |
633 | 0 | let range = self.caret_value_offsets_byte_range(); |
634 | 0 | self.data.read_array(range).ok().unwrap_or_default() |
635 | 0 | } |
636 | | |
637 | | /// A dynamically resolving wrapper for [`caret_value_offsets`][Self::caret_value_offsets]. |
638 | 0 | pub fn caret_values(&self) -> ArrayOfOffsets<'a, CaretValue<'a>, Offset16> { |
639 | 0 | let data = self.data; |
640 | 0 | let offsets = self.caret_value_offsets(); |
641 | 0 | ArrayOfOffsets::new(offsets, data, ()) |
642 | 0 | } |
643 | | |
644 | 0 | pub fn caret_count_byte_range(&self) -> Range<usize> { |
645 | 0 | let start = 0; |
646 | 0 | start..start + u16::RAW_BYTE_LEN |
647 | 0 | } |
648 | | |
649 | 0 | pub fn caret_value_offsets_byte_range(&self) -> Range<usize> { |
650 | 0 | let caret_count = self.caret_count(); |
651 | 0 | let start = self.caret_count_byte_range().end; |
652 | 0 | start..start + (caret_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN) |
653 | 0 | } |
654 | | } |
655 | | |
656 | | #[cfg(feature = "experimental_traverse")] |
657 | | impl<'a> SomeTable<'a> for LigGlyph<'a> { |
658 | | fn type_name(&self) -> &str { |
659 | | "LigGlyph" |
660 | | } |
661 | | fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
662 | | match idx { |
663 | | 0usize => Some(Field::new("caret_count", self.caret_count())), |
664 | | 1usize => Some({ |
665 | | let data = self.data; |
666 | | Field::new( |
667 | | "caret_value_offsets", |
668 | | FieldType::array_of_offsets( |
669 | | better_type_name::<CaretValue>(), |
670 | | self.caret_value_offsets(), |
671 | | move |off| { |
672 | | let target = off.get().resolve::<CaretValue>(data); |
673 | | FieldType::offset(off.get(), target) |
674 | | }, |
675 | | ), |
676 | | ) |
677 | | }), |
678 | | _ => None, |
679 | | } |
680 | | } |
681 | | } |
682 | | |
683 | | #[cfg(feature = "experimental_traverse")] |
684 | | #[allow(clippy::needless_lifetimes)] |
685 | | impl<'a> std::fmt::Debug for LigGlyph<'a> { |
686 | | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
687 | | (self as &dyn SomeTable<'a>).fmt(f) |
688 | | } |
689 | | } |
690 | | |
691 | | /// [Caret Value Tables](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caret-value-tables) |
692 | | #[derive(Clone)] |
693 | | pub enum CaretValue<'a> { |
694 | | Format1(CaretValueFormat1<'a>), |
695 | | Format2(CaretValueFormat2<'a>), |
696 | | Format3(CaretValueFormat3<'a>), |
697 | | } |
698 | | |
699 | | impl<'a> CaretValue<'a> { |
700 | | ///Return the `FontData` used to resolve offsets for this table. |
701 | 0 | pub fn offset_data(&self) -> FontData<'a> { |
702 | 0 | match self { |
703 | 0 | Self::Format1(item) => item.offset_data(), |
704 | 0 | Self::Format2(item) => item.offset_data(), |
705 | 0 | Self::Format3(item) => item.offset_data(), |
706 | | } |
707 | 0 | } |
708 | | |
709 | | /// Format identifier: format = 1 |
710 | 0 | pub fn caret_value_format(&self) -> u16 { |
711 | 0 | match self { |
712 | 0 | Self::Format1(item) => item.caret_value_format(), |
713 | 0 | Self::Format2(item) => item.caret_value_format(), |
714 | 0 | Self::Format3(item) => item.caret_value_format(), |
715 | | } |
716 | 0 | } |
717 | | } |
718 | | |
719 | | impl<'a> FontRead<'a> for CaretValue<'a> { |
720 | 0 | fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
721 | 0 | let format: u16 = data.read_at(0usize)?; |
722 | 0 | match format { |
723 | 0 | CaretValueFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), |
724 | 0 | CaretValueFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), |
725 | 0 | CaretValueFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)), |
726 | 0 | other => Err(ReadError::InvalidFormat(other.into())), |
727 | | } |
728 | 0 | } |
729 | | } |
730 | | |
731 | | impl<'a> MinByteRange<'a> for CaretValue<'a> { |
732 | 0 | fn min_byte_range(&self) -> Range<usize> { |
733 | 0 | match self { |
734 | 0 | Self::Format1(item) => item.min_byte_range(), |
735 | 0 | Self::Format2(item) => item.min_byte_range(), |
736 | 0 | Self::Format3(item) => item.min_byte_range(), |
737 | | } |
738 | 0 | } |
739 | 0 | fn min_table_bytes(&self) -> &'a [u8] { |
740 | 0 | match self { |
741 | 0 | Self::Format1(item) => item.min_table_bytes(), |
742 | 0 | Self::Format2(item) => item.min_table_bytes(), |
743 | 0 | Self::Format3(item) => item.min_table_bytes(), |
744 | | } |
745 | 0 | } |
746 | | } |
747 | | |
748 | | #[cfg(feature = "experimental_traverse")] |
749 | | impl<'a> CaretValue<'a> { |
750 | | fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> { |
751 | | match self { |
752 | | Self::Format1(table) => table, |
753 | | Self::Format2(table) => table, |
754 | | Self::Format3(table) => table, |
755 | | } |
756 | | } |
757 | | } |
758 | | |
759 | | #[cfg(feature = "experimental_traverse")] |
760 | | impl std::fmt::Debug for CaretValue<'_> { |
761 | | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
762 | | self.dyn_inner().fmt(f) |
763 | | } |
764 | | } |
765 | | |
766 | | #[cfg(feature = "experimental_traverse")] |
767 | | impl<'a> SomeTable<'a> for CaretValue<'a> { |
768 | | fn type_name(&self) -> &str { |
769 | | self.dyn_inner().type_name() |
770 | | } |
771 | | fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
772 | | self.dyn_inner().get_field(idx) |
773 | | } |
774 | | } |
775 | | |
776 | | impl Format<u16> for CaretValueFormat1<'_> { |
777 | | const FORMAT: u16 = 1; |
778 | | } |
779 | | |
780 | | impl<'a> MinByteRange<'a> for CaretValueFormat1<'a> { |
781 | 0 | fn min_byte_range(&self) -> Range<usize> { |
782 | 0 | 0..self.coordinate_byte_range().end |
783 | 0 | } |
784 | 0 | fn min_table_bytes(&self) -> &'a [u8] { |
785 | 0 | let range = self.min_byte_range(); |
786 | 0 | self.data.as_bytes().get(range).unwrap_or_default() |
787 | 0 | } |
788 | | } |
789 | | |
790 | | impl<'a> FontRead<'a> for CaretValueFormat1<'a> { |
791 | 0 | fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
792 | | #[allow(clippy::absurd_extreme_comparisons)] |
793 | 0 | if data.len() < Self::MIN_SIZE { |
794 | 0 | return Err(ReadError::OutOfBounds); |
795 | 0 | } |
796 | 0 | Ok(Self { data }) |
797 | 0 | } |
798 | | } |
799 | | |
800 | | /// [CaretValue Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caretvalue-format-1) |
801 | | #[derive(Clone)] |
802 | | pub struct CaretValueFormat1<'a> { |
803 | | data: FontData<'a>, |
804 | | } |
805 | | |
806 | | #[allow(clippy::needless_lifetimes)] |
807 | | impl<'a> CaretValueFormat1<'a> { |
808 | | pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN); |
809 | | basic_table_impls!(impl_the_methods); |
810 | | |
811 | | /// Format identifier: format = 1 |
812 | 0 | pub fn caret_value_format(&self) -> u16 { |
813 | 0 | let range = self.caret_value_format_byte_range(); |
814 | 0 | self.data.read_at(range.start).ok().unwrap() |
815 | 0 | } |
816 | | |
817 | | /// X or Y value, in design units |
818 | 0 | pub fn coordinate(&self) -> i16 { |
819 | 0 | let range = self.coordinate_byte_range(); |
820 | 0 | self.data.read_at(range.start).ok().unwrap() |
821 | 0 | } |
822 | | |
823 | 0 | pub fn caret_value_format_byte_range(&self) -> Range<usize> { |
824 | 0 | let start = 0; |
825 | 0 | start..start + u16::RAW_BYTE_LEN |
826 | 0 | } |
827 | | |
828 | 0 | pub fn coordinate_byte_range(&self) -> Range<usize> { |
829 | 0 | let start = self.caret_value_format_byte_range().end; |
830 | 0 | start..start + i16::RAW_BYTE_LEN |
831 | 0 | } |
832 | | } |
833 | | |
834 | | #[cfg(feature = "experimental_traverse")] |
835 | | impl<'a> SomeTable<'a> for CaretValueFormat1<'a> { |
836 | | fn type_name(&self) -> &str { |
837 | | "CaretValueFormat1" |
838 | | } |
839 | | fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
840 | | match idx { |
841 | | 0usize => Some(Field::new("caret_value_format", self.caret_value_format())), |
842 | | 1usize => Some(Field::new("coordinate", self.coordinate())), |
843 | | _ => None, |
844 | | } |
845 | | } |
846 | | } |
847 | | |
848 | | #[cfg(feature = "experimental_traverse")] |
849 | | #[allow(clippy::needless_lifetimes)] |
850 | | impl<'a> std::fmt::Debug for CaretValueFormat1<'a> { |
851 | | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
852 | | (self as &dyn SomeTable<'a>).fmt(f) |
853 | | } |
854 | | } |
855 | | |
856 | | impl Format<u16> for CaretValueFormat2<'_> { |
857 | | const FORMAT: u16 = 2; |
858 | | } |
859 | | |
860 | | impl<'a> MinByteRange<'a> for CaretValueFormat2<'a> { |
861 | 0 | fn min_byte_range(&self) -> Range<usize> { |
862 | 0 | 0..self.caret_value_point_index_byte_range().end |
863 | 0 | } |
864 | 0 | fn min_table_bytes(&self) -> &'a [u8] { |
865 | 0 | let range = self.min_byte_range(); |
866 | 0 | self.data.as_bytes().get(range).unwrap_or_default() |
867 | 0 | } |
868 | | } |
869 | | |
870 | | impl<'a> FontRead<'a> for CaretValueFormat2<'a> { |
871 | 0 | fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
872 | | #[allow(clippy::absurd_extreme_comparisons)] |
873 | 0 | if data.len() < Self::MIN_SIZE { |
874 | 0 | return Err(ReadError::OutOfBounds); |
875 | 0 | } |
876 | 0 | Ok(Self { data }) |
877 | 0 | } |
878 | | } |
879 | | |
880 | | /// [CaretValue Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caretvalue-format-2) |
881 | | #[derive(Clone)] |
882 | | pub struct CaretValueFormat2<'a> { |
883 | | data: FontData<'a>, |
884 | | } |
885 | | |
886 | | #[allow(clippy::needless_lifetimes)] |
887 | | impl<'a> CaretValueFormat2<'a> { |
888 | | pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); |
889 | | basic_table_impls!(impl_the_methods); |
890 | | |
891 | | /// Format identifier: format = 2 |
892 | 0 | pub fn caret_value_format(&self) -> u16 { |
893 | 0 | let range = self.caret_value_format_byte_range(); |
894 | 0 | self.data.read_at(range.start).ok().unwrap() |
895 | 0 | } |
896 | | |
897 | | /// Contour point index on glyph |
898 | 0 | pub fn caret_value_point_index(&self) -> u16 { |
899 | 0 | let range = self.caret_value_point_index_byte_range(); |
900 | 0 | self.data.read_at(range.start).ok().unwrap() |
901 | 0 | } |
902 | | |
903 | 0 | pub fn caret_value_format_byte_range(&self) -> Range<usize> { |
904 | 0 | let start = 0; |
905 | 0 | start..start + u16::RAW_BYTE_LEN |
906 | 0 | } |
907 | | |
908 | 0 | pub fn caret_value_point_index_byte_range(&self) -> Range<usize> { |
909 | 0 | let start = self.caret_value_format_byte_range().end; |
910 | 0 | start..start + u16::RAW_BYTE_LEN |
911 | 0 | } |
912 | | } |
913 | | |
914 | | #[cfg(feature = "experimental_traverse")] |
915 | | impl<'a> SomeTable<'a> for CaretValueFormat2<'a> { |
916 | | fn type_name(&self) -> &str { |
917 | | "CaretValueFormat2" |
918 | | } |
919 | | fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
920 | | match idx { |
921 | | 0usize => Some(Field::new("caret_value_format", self.caret_value_format())), |
922 | | 1usize => Some(Field::new( |
923 | | "caret_value_point_index", |
924 | | self.caret_value_point_index(), |
925 | | )), |
926 | | _ => None, |
927 | | } |
928 | | } |
929 | | } |
930 | | |
931 | | #[cfg(feature = "experimental_traverse")] |
932 | | #[allow(clippy::needless_lifetimes)] |
933 | | impl<'a> std::fmt::Debug for CaretValueFormat2<'a> { |
934 | | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
935 | | (self as &dyn SomeTable<'a>).fmt(f) |
936 | | } |
937 | | } |
938 | | |
939 | | impl Format<u16> for CaretValueFormat3<'_> { |
940 | | const FORMAT: u16 = 3; |
941 | | } |
942 | | |
943 | | impl<'a> MinByteRange<'a> for CaretValueFormat3<'a> { |
944 | 0 | fn min_byte_range(&self) -> Range<usize> { |
945 | 0 | 0..self.device_offset_byte_range().end |
946 | 0 | } |
947 | 0 | fn min_table_bytes(&self) -> &'a [u8] { |
948 | 0 | let range = self.min_byte_range(); |
949 | 0 | self.data.as_bytes().get(range).unwrap_or_default() |
950 | 0 | } |
951 | | } |
952 | | |
953 | | impl<'a> FontRead<'a> for CaretValueFormat3<'a> { |
954 | 0 | fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
955 | | #[allow(clippy::absurd_extreme_comparisons)] |
956 | 0 | if data.len() < Self::MIN_SIZE { |
957 | 0 | return Err(ReadError::OutOfBounds); |
958 | 0 | } |
959 | 0 | Ok(Self { data }) |
960 | 0 | } |
961 | | } |
962 | | |
963 | | /// [CaretValue Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caretvalue-format-3) |
964 | | #[derive(Clone)] |
965 | | pub struct CaretValueFormat3<'a> { |
966 | | data: FontData<'a>, |
967 | | } |
968 | | |
969 | | #[allow(clippy::needless_lifetimes)] |
970 | | impl<'a> CaretValueFormat3<'a> { |
971 | | pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN); |
972 | | basic_table_impls!(impl_the_methods); |
973 | | |
974 | | /// Format identifier-format = 3 |
975 | 0 | pub fn caret_value_format(&self) -> u16 { |
976 | 0 | let range = self.caret_value_format_byte_range(); |
977 | 0 | self.data.read_at(range.start).ok().unwrap() |
978 | 0 | } |
979 | | |
980 | | /// X or Y value, in design units |
981 | 0 | pub fn coordinate(&self) -> i16 { |
982 | 0 | let range = self.coordinate_byte_range(); |
983 | 0 | self.data.read_at(range.start).ok().unwrap() |
984 | 0 | } |
985 | | |
986 | | /// Offset to Device table (non-variable font) / Variation Index |
987 | | /// table (variable font) for X or Y value-from beginning of |
988 | | /// CaretValue table |
989 | 0 | pub fn device_offset(&self) -> Offset16 { |
990 | 0 | let range = self.device_offset_byte_range(); |
991 | 0 | self.data.read_at(range.start).ok().unwrap() |
992 | 0 | } |
993 | | |
994 | | /// Attempt to resolve [`device_offset`][Self::device_offset]. |
995 | 0 | pub fn device(&self) -> Result<DeviceOrVariationIndex<'a>, ReadError> { |
996 | 0 | let data = self.data; |
997 | 0 | self.device_offset().resolve(data) |
998 | 0 | } |
999 | | |
1000 | 0 | pub fn caret_value_format_byte_range(&self) -> Range<usize> { |
1001 | 0 | let start = 0; |
1002 | 0 | start..start + u16::RAW_BYTE_LEN |
1003 | 0 | } |
1004 | | |
1005 | 0 | pub fn coordinate_byte_range(&self) -> Range<usize> { |
1006 | 0 | let start = self.caret_value_format_byte_range().end; |
1007 | 0 | start..start + i16::RAW_BYTE_LEN |
1008 | 0 | } |
1009 | | |
1010 | 0 | pub fn device_offset_byte_range(&self) -> Range<usize> { |
1011 | 0 | let start = self.coordinate_byte_range().end; |
1012 | 0 | start..start + Offset16::RAW_BYTE_LEN |
1013 | 0 | } |
1014 | | } |
1015 | | |
1016 | | #[cfg(feature = "experimental_traverse")] |
1017 | | impl<'a> SomeTable<'a> for CaretValueFormat3<'a> { |
1018 | | fn type_name(&self) -> &str { |
1019 | | "CaretValueFormat3" |
1020 | | } |
1021 | | fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
1022 | | match idx { |
1023 | | 0usize => Some(Field::new("caret_value_format", self.caret_value_format())), |
1024 | | 1usize => Some(Field::new("coordinate", self.coordinate())), |
1025 | | 2usize => Some(Field::new( |
1026 | | "device_offset", |
1027 | | FieldType::offset(self.device_offset(), self.device()), |
1028 | | )), |
1029 | | _ => None, |
1030 | | } |
1031 | | } |
1032 | | } |
1033 | | |
1034 | | #[cfg(feature = "experimental_traverse")] |
1035 | | #[allow(clippy::needless_lifetimes)] |
1036 | | impl<'a> std::fmt::Debug for CaretValueFormat3<'a> { |
1037 | | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
1038 | | (self as &dyn SomeTable<'a>).fmt(f) |
1039 | | } |
1040 | | } |
1041 | | |
1042 | | impl Format<u16> for MarkGlyphSets<'_> { |
1043 | | const FORMAT: u16 = 1; |
1044 | | } |
1045 | | |
1046 | | impl<'a> MinByteRange<'a> for MarkGlyphSets<'a> { |
1047 | 0 | fn min_byte_range(&self) -> Range<usize> { |
1048 | 0 | 0..self.coverage_offsets_byte_range().end |
1049 | 0 | } |
1050 | 0 | fn min_table_bytes(&self) -> &'a [u8] { |
1051 | 0 | let range = self.min_byte_range(); |
1052 | 0 | self.data.as_bytes().get(range).unwrap_or_default() |
1053 | 0 | } |
1054 | | } |
1055 | | |
1056 | | impl<'a> FontRead<'a> for MarkGlyphSets<'a> { |
1057 | 0 | fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
1058 | | #[allow(clippy::absurd_extreme_comparisons)] |
1059 | 0 | if data.len() < Self::MIN_SIZE { |
1060 | 0 | return Err(ReadError::OutOfBounds); |
1061 | 0 | } |
1062 | 0 | Ok(Self { data }) |
1063 | 0 | } |
1064 | | } |
1065 | | |
1066 | | /// [Mark Glyph Sets Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#mark-glyph-sets-table) |
1067 | | #[derive(Clone)] |
1068 | | pub struct MarkGlyphSets<'a> { |
1069 | | data: FontData<'a>, |
1070 | | } |
1071 | | |
1072 | | #[allow(clippy::needless_lifetimes)] |
1073 | | impl<'a> MarkGlyphSets<'a> { |
1074 | | pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); |
1075 | | basic_table_impls!(impl_the_methods); |
1076 | | |
1077 | | /// Format identifier == 1 |
1078 | 0 | pub fn format(&self) -> u16 { |
1079 | 0 | let range = self.format_byte_range(); |
1080 | 0 | self.data.read_at(range.start).ok().unwrap() |
1081 | 0 | } |
1082 | | |
1083 | | /// Number of mark glyph sets defined |
1084 | 0 | pub fn mark_glyph_set_count(&self) -> u16 { |
1085 | 0 | let range = self.mark_glyph_set_count_byte_range(); |
1086 | 0 | self.data.read_at(range.start).ok().unwrap() |
1087 | 0 | } |
1088 | | |
1089 | | /// Array of offsets to mark glyph set coverage tables, from the |
1090 | | /// start of the MarkGlyphSets table. |
1091 | 0 | pub fn coverage_offsets(&self) -> &'a [BigEndian<Offset32>] { |
1092 | 0 | let range = self.coverage_offsets_byte_range(); |
1093 | 0 | self.data.read_array(range).ok().unwrap_or_default() |
1094 | 0 | } |
1095 | | |
1096 | | /// A dynamically resolving wrapper for [`coverage_offsets`][Self::coverage_offsets]. |
1097 | 0 | pub fn coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset32> { |
1098 | 0 | let data = self.data; |
1099 | 0 | let offsets = self.coverage_offsets(); |
1100 | 0 | ArrayOfOffsets::new(offsets, data, ()) |
1101 | 0 | } |
1102 | | |
1103 | 0 | pub fn format_byte_range(&self) -> Range<usize> { |
1104 | 0 | let start = 0; |
1105 | 0 | start..start + u16::RAW_BYTE_LEN |
1106 | 0 | } |
1107 | | |
1108 | 0 | pub fn mark_glyph_set_count_byte_range(&self) -> Range<usize> { |
1109 | 0 | let start = self.format_byte_range().end; |
1110 | 0 | start..start + u16::RAW_BYTE_LEN |
1111 | 0 | } |
1112 | | |
1113 | 0 | pub fn coverage_offsets_byte_range(&self) -> Range<usize> { |
1114 | 0 | let mark_glyph_set_count = self.mark_glyph_set_count(); |
1115 | 0 | let start = self.mark_glyph_set_count_byte_range().end; |
1116 | 0 | start..start + (mark_glyph_set_count as usize).saturating_mul(Offset32::RAW_BYTE_LEN) |
1117 | 0 | } |
1118 | | } |
1119 | | |
1120 | | #[cfg(feature = "experimental_traverse")] |
1121 | | impl<'a> SomeTable<'a> for MarkGlyphSets<'a> { |
1122 | | fn type_name(&self) -> &str { |
1123 | | "MarkGlyphSets" |
1124 | | } |
1125 | | fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
1126 | | match idx { |
1127 | | 0usize => Some(Field::new("format", self.format())), |
1128 | | 1usize => Some(Field::new( |
1129 | | "mark_glyph_set_count", |
1130 | | self.mark_glyph_set_count(), |
1131 | | )), |
1132 | | 2usize => Some({ |
1133 | | let data = self.data; |
1134 | | Field::new( |
1135 | | "coverage_offsets", |
1136 | | FieldType::array_of_offsets( |
1137 | | better_type_name::<CoverageTable>(), |
1138 | | self.coverage_offsets(), |
1139 | | move |off| { |
1140 | | let target = off.get().resolve::<CoverageTable>(data); |
1141 | | FieldType::offset(off.get(), target) |
1142 | | }, |
1143 | | ), |
1144 | | ) |
1145 | | }), |
1146 | | _ => None, |
1147 | | } |
1148 | | } |
1149 | | } |
1150 | | |
1151 | | #[cfg(feature = "experimental_traverse")] |
1152 | | #[allow(clippy::needless_lifetimes)] |
1153 | | impl<'a> std::fmt::Debug for MarkGlyphSets<'a> { |
1154 | | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
1155 | | (self as &dyn SomeTable<'a>).fmt(f) |
1156 | | } |
1157 | | } |