1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for Fvar<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.instance_size_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 Fvar<'_> {
19 const TAG: Tag = Tag::new(b"fvar");
21}
22
23impl ReadArgs for Fvar<'_> {
24 type Args = ();
25}
26
27impl<'a> FontRead<'a> for Fvar<'a> {
28 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
29 #[allow(clippy::absurd_extreme_comparisons)]
30 if data.len() < Self::MIN_SIZE {
31 return Err(ReadError::OutOfBounds);
32 }
33 Ok(Self { data })
34 }
35}
36
37#[derive(Clone)]
39pub struct Fvar<'a> {
40 data: FontData<'a>,
41}
42
43#[allow(clippy::needless_lifetimes)]
44impl<'a> Fvar<'a> {
45 pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN
46 + Offset16::RAW_BYTE_LEN
47 + u16::RAW_BYTE_LEN
48 + u16::RAW_BYTE_LEN
49 + u16::RAW_BYTE_LEN
50 + u16::RAW_BYTE_LEN
51 + u16::RAW_BYTE_LEN);
52 basic_table_impls!(impl_the_methods);
53
54 pub fn version(&self) -> MajorMinor {
57 let range = self.version_byte_range();
58 self.data.read_at(range.start).ok().unwrap()
59 }
60
61 pub fn axis_instance_arrays_offset(&self) -> Offset16 {
64 let range = self.axis_instance_arrays_offset_byte_range();
65 self.data.read_at(range.start).ok().unwrap()
66 }
67
68 pub fn axis_instance_arrays(&self) -> Result<AxisInstanceArrays<'a>, ReadError> {
70 let data = self.data;
71 let args = (
72 self.axis_count(),
73 self.instance_count(),
74 self.instance_size(),
75 );
76 self.axis_instance_arrays_offset()
77 .resolve_with_args(data, args)
78 }
79
80 pub fn axis_count(&self) -> u16 {
82 let range = self.axis_count_byte_range();
83 self.data.read_at(range.start).ok().unwrap()
84 }
85
86 pub fn axis_size(&self) -> u16 {
88 let range = self.axis_size_byte_range();
89 self.data.read_at(range.start).ok().unwrap()
90 }
91
92 pub fn instance_count(&self) -> u16 {
94 let range = self.instance_count_byte_range();
95 self.data.read_at(range.start).ok().unwrap()
96 }
97
98 pub fn instance_size(&self) -> u16 {
100 let range = self.instance_size_byte_range();
101 self.data.read_at(range.start).ok().unwrap()
102 }
103
104 pub fn version_byte_range(&self) -> Range<usize> {
105 let start = 0;
106 let end = start + MajorMinor::RAW_BYTE_LEN;
107 start..end
108 }
109
110 pub fn axis_instance_arrays_offset_byte_range(&self) -> Range<usize> {
111 let start = self.version_byte_range().end;
112 let end = start + Offset16::RAW_BYTE_LEN;
113 start..end
114 }
115
116 pub fn _reserved_byte_range(&self) -> Range<usize> {
117 let start = self.axis_instance_arrays_offset_byte_range().end;
118 let end = start + u16::RAW_BYTE_LEN;
119 start..end
120 }
121
122 pub fn axis_count_byte_range(&self) -> Range<usize> {
123 let start = self._reserved_byte_range().end;
124 let end = start + u16::RAW_BYTE_LEN;
125 start..end
126 }
127
128 pub fn axis_size_byte_range(&self) -> Range<usize> {
129 let start = self.axis_count_byte_range().end;
130 let end = start + u16::RAW_BYTE_LEN;
131 start..end
132 }
133
134 pub fn instance_count_byte_range(&self) -> Range<usize> {
135 let start = self.axis_size_byte_range().end;
136 let end = start + u16::RAW_BYTE_LEN;
137 start..end
138 }
139
140 pub fn instance_size_byte_range(&self) -> Range<usize> {
141 let start = self.instance_count_byte_range().end;
142 let end = start + u16::RAW_BYTE_LEN;
143 start..end
144 }
145}
146
147const _: () = assert!(FontData::default_data_long_enough(Fvar::MIN_SIZE));
148
149impl Default for Fvar<'_> {
150 fn default() -> Self {
151 Self {
152 data: FontData::default_table_data(),
153 }
154 }
155}
156
157#[cfg(feature = "experimental_traverse")]
158impl<'a> SomeTable<'a> for Fvar<'a> {
159 fn type_name(&self) -> &str {
160 "Fvar"
161 }
162 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
163 match idx {
164 0usize => Some(Field::new("version", self.version())),
165 1usize => Some(Field::new(
166 "axis_instance_arrays_offset",
167 FieldType::offset(
168 self.axis_instance_arrays_offset(),
169 self.axis_instance_arrays(),
170 ),
171 )),
172 2usize => Some(Field::new("axis_count", self.axis_count())),
173 3usize => Some(Field::new("axis_size", self.axis_size())),
174 4usize => Some(Field::new("instance_count", self.instance_count())),
175 5usize => Some(Field::new("instance_size", self.instance_size())),
176 _ => None,
177 }
178 }
179}
180
181#[cfg(feature = "experimental_traverse")]
182#[allow(clippy::needless_lifetimes)]
183impl<'a> std::fmt::Debug for Fvar<'a> {
184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185 (self as &dyn SomeTable<'a>).fmt(f)
186 }
187}
188
189impl<'a> MinByteRange<'a> for AxisInstanceArrays<'a> {
190 fn min_byte_range(&self) -> Range<usize> {
191 0..self.instances_byte_range().end
192 }
193 fn min_table_bytes(&self) -> &'a [u8] {
194 let range = self.min_byte_range();
195 self.data.as_bytes().get(range).unwrap_or_default()
196 }
197}
198
199impl ReadArgs for AxisInstanceArrays<'_> {
200 type Args = (u16, u16, u16);
201}
202
203impl<'a> FontRead<'a> for AxisInstanceArrays<'a> {
204 fn read_with_args(data: FontData<'a>, args: (u16, u16, u16)) -> Result<Self, ReadError> {
205 let (axis_count, instance_count, instance_size) = args;
206
207 #[allow(clippy::absurd_extreme_comparisons)]
208 if data.len() < Self::MIN_SIZE {
209 return Err(ReadError::OutOfBounds);
210 }
211 Ok(Self {
212 data,
213 axis_count,
214 instance_count,
215 instance_size,
216 })
217 }
218}
219
220impl<'a> AxisInstanceArrays<'a> {
221 pub fn read(
226 data: FontData<'a>,
227 axis_count: u16,
228 instance_count: u16,
229 instance_size: u16,
230 ) -> Result<Self, ReadError> {
231 let args = (axis_count, instance_count, instance_size);
232 Self::read_with_args(data, args)
233 }
234}
235
236#[derive(Clone)]
238pub struct AxisInstanceArrays<'a> {
239 data: FontData<'a>,
240 axis_count: u16,
241 instance_count: u16,
242 instance_size: u16,
243}
244
245#[allow(clippy::needless_lifetimes)]
246impl<'a> AxisInstanceArrays<'a> {
247 pub const MIN_SIZE: usize = 0;
248 basic_table_impls!(impl_the_methods);
249
250 pub fn axes(&self) -> &'a [VariationAxisRecord] {
252 let range = self.axes_byte_range();
253 self.data.read_array(range).ok().unwrap_or_default()
254 }
255
256 pub fn instances(&self) -> ComputedArray<'a, InstanceRecord<'a>> {
258 let range = self.instances_byte_range();
259 self.data
260 .read_with_args(range, (self.axis_count(), self.instance_size()))
261 .unwrap_or_default()
262 }
263
264 pub(crate) fn axis_count(&self) -> u16 {
265 self.axis_count
266 }
267
268 pub(crate) fn instance_count(&self) -> u16 {
269 self.instance_count
270 }
271
272 pub(crate) fn instance_size(&self) -> u16 {
273 self.instance_size
274 }
275
276 pub fn axes_byte_range(&self) -> Range<usize> {
277 let axis_count = self.axis_count();
278 let start = 0;
279 let end = start
280 + (transforms::to_usize(axis_count)).saturating_mul(VariationAxisRecord::RAW_BYTE_LEN);
281 start..end
282 }
283
284 pub fn instances_byte_range(&self) -> Range<usize> {
285 let instance_count = self.instance_count();
286 let start = self.axes_byte_range().end;
287 let end = start
288 + (transforms::to_usize(instance_count)).saturating_mul(
289 <InstanceRecord as ComputeSize>::compute_size((
290 self.axis_count(),
291 self.instance_size(),
292 ))
293 .unwrap_or(0),
294 );
295 start..end
296 }
297}
298
299#[allow(clippy::absurd_extreme_comparisons)]
300const _: () = assert!(FontData::default_data_long_enough(
301 AxisInstanceArrays::MIN_SIZE
302));
303
304impl Default for AxisInstanceArrays<'_> {
305 fn default() -> Self {
306 Self {
307 data: FontData::default_table_data(),
308 axis_count: Default::default(),
309 instance_count: Default::default(),
310 instance_size: Default::default(),
311 }
312 }
313}
314
315#[cfg(feature = "experimental_traverse")]
316impl<'a> SomeTable<'a> for AxisInstanceArrays<'a> {
317 fn type_name(&self) -> &str {
318 "AxisInstanceArrays"
319 }
320 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
321 match idx {
322 0usize => Some(Field::new(
323 "axes",
324 traversal::FieldType::array_of_records(
325 stringify!(VariationAxisRecord),
326 self.axes(),
327 self.offset_data(),
328 ),
329 )),
330 1usize => Some(Field::new(
331 "instances",
332 traversal::FieldType::computed_array(
333 "InstanceRecord",
334 self.instances(),
335 self.offset_data(),
336 ),
337 )),
338 _ => None,
339 }
340 }
341}
342
343#[cfg(feature = "experimental_traverse")]
344#[allow(clippy::needless_lifetimes)]
345impl<'a> std::fmt::Debug for AxisInstanceArrays<'a> {
346 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
347 (self as &dyn SomeTable<'a>).fmt(f)
348 }
349}
350
351#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
353#[repr(C)]
354#[repr(packed)]
355pub struct VariationAxisRecord {
356 pub axis_tag: BigEndian<Tag>,
358 pub min_value: BigEndian<Fixed>,
360 pub default_value: BigEndian<Fixed>,
362 pub max_value: BigEndian<Fixed>,
364 pub flags: BigEndian<u16>,
366 pub axis_name_id: BigEndian<NameId>,
368}
369
370impl VariationAxisRecord {
371 pub fn axis_tag(&self) -> Tag {
373 self.axis_tag.get()
374 }
375
376 pub fn min_value(&self) -> Fixed {
378 self.min_value.get()
379 }
380
381 pub fn default_value(&self) -> Fixed {
383 self.default_value.get()
384 }
385
386 pub fn max_value(&self) -> Fixed {
388 self.max_value.get()
389 }
390
391 pub fn flags(&self) -> u16 {
393 self.flags.get()
394 }
395
396 pub fn axis_name_id(&self) -> NameId {
398 self.axis_name_id.get()
399 }
400}
401
402impl FixedSize for VariationAxisRecord {
403 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN
404 + Fixed::RAW_BYTE_LEN
405 + Fixed::RAW_BYTE_LEN
406 + Fixed::RAW_BYTE_LEN
407 + u16::RAW_BYTE_LEN
408 + NameId::RAW_BYTE_LEN;
409}
410
411#[cfg(feature = "experimental_traverse")]
412impl<'a> SomeRecord<'a> for VariationAxisRecord {
413 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
414 RecordResolver {
415 name: "VariationAxisRecord",
416 get_field: Box::new(move |idx, _data| match idx {
417 0usize => Some(Field::new("axis_tag", self.axis_tag())),
418 1usize => Some(Field::new("min_value", self.min_value())),
419 2usize => Some(Field::new("default_value", self.default_value())),
420 3usize => Some(Field::new("max_value", self.max_value())),
421 4usize => Some(Field::new("flags", self.flags())),
422 5usize => Some(Field::new("axis_name_id", self.axis_name_id())),
423 _ => None,
424 }),
425 data,
426 }
427 }
428}