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