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 start..start + MajorMinor::RAW_BYTE_LEN
103 }
104
105 pub fn axis_instance_arrays_offset_byte_range(&self) -> Range<usize> {
106 let start = self.version_byte_range().end;
107 start..start + Offset16::RAW_BYTE_LEN
108 }
109
110 pub fn _reserved_byte_range(&self) -> Range<usize> {
111 let start = self.axis_instance_arrays_offset_byte_range().end;
112 start..start + u16::RAW_BYTE_LEN
113 }
114
115 pub fn axis_count_byte_range(&self) -> Range<usize> {
116 let start = self._reserved_byte_range().end;
117 start..start + u16::RAW_BYTE_LEN
118 }
119
120 pub fn axis_size_byte_range(&self) -> Range<usize> {
121 let start = self.axis_count_byte_range().end;
122 start..start + u16::RAW_BYTE_LEN
123 }
124
125 pub fn instance_count_byte_range(&self) -> Range<usize> {
126 let start = self.axis_size_byte_range().end;
127 start..start + u16::RAW_BYTE_LEN
128 }
129
130 pub fn instance_size_byte_range(&self) -> Range<usize> {
131 let start = self.instance_count_byte_range().end;
132 start..start + u16::RAW_BYTE_LEN
133 }
134}
135
136#[cfg(feature = "experimental_traverse")]
137impl<'a> SomeTable<'a> for Fvar<'a> {
138 fn type_name(&self) -> &str {
139 "Fvar"
140 }
141 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
142 match idx {
143 0usize => Some(Field::new("version", self.version())),
144 1usize => Some(Field::new(
145 "axis_instance_arrays_offset",
146 FieldType::offset(
147 self.axis_instance_arrays_offset(),
148 self.axis_instance_arrays(),
149 ),
150 )),
151 2usize => Some(Field::new("axis_count", self.axis_count())),
152 3usize => Some(Field::new("axis_size", self.axis_size())),
153 4usize => Some(Field::new("instance_count", self.instance_count())),
154 5usize => Some(Field::new("instance_size", self.instance_size())),
155 _ => None,
156 }
157 }
158}
159
160#[cfg(feature = "experimental_traverse")]
161#[allow(clippy::needless_lifetimes)]
162impl<'a> std::fmt::Debug for Fvar<'a> {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 (self as &dyn SomeTable<'a>).fmt(f)
165 }
166}
167
168impl<'a> MinByteRange<'a> for AxisInstanceArrays<'a> {
169 fn min_byte_range(&self) -> Range<usize> {
170 0..self.instances_byte_range().end
171 }
172 fn min_table_bytes(&self) -> &'a [u8] {
173 let range = self.min_byte_range();
174 self.data.as_bytes().get(range).unwrap_or_default()
175 }
176}
177
178impl ReadArgs for AxisInstanceArrays<'_> {
179 type Args = (u16, u16, u16);
180}
181
182impl<'a> FontReadWithArgs<'a> for AxisInstanceArrays<'a> {
183 fn read_with_args(data: FontData<'a>, args: &(u16, u16, u16)) -> Result<Self, ReadError> {
184 let (axis_count, instance_count, instance_size) = *args;
185
186 #[allow(clippy::absurd_extreme_comparisons)]
187 if data.len() < Self::MIN_SIZE {
188 return Err(ReadError::OutOfBounds);
189 }
190 Ok(Self {
191 data,
192 axis_count,
193 instance_count,
194 instance_size,
195 })
196 }
197}
198
199impl<'a> AxisInstanceArrays<'a> {
200 pub fn read(
205 data: FontData<'a>,
206 axis_count: u16,
207 instance_count: u16,
208 instance_size: u16,
209 ) -> Result<Self, ReadError> {
210 let args = (axis_count, instance_count, instance_size);
211 Self::read_with_args(data, &args)
212 }
213}
214
215#[derive(Clone)]
217pub struct AxisInstanceArrays<'a> {
218 data: FontData<'a>,
219 axis_count: u16,
220 instance_count: u16,
221 instance_size: u16,
222}
223
224#[allow(clippy::needless_lifetimes)]
225impl<'a> AxisInstanceArrays<'a> {
226 pub const MIN_SIZE: usize = 0;
227 basic_table_impls!(impl_the_methods);
228
229 pub fn axes(&self) -> &'a [VariationAxisRecord] {
231 let range = self.axes_byte_range();
232 self.data.read_array(range).ok().unwrap_or_default()
233 }
234
235 pub fn instances(&self) -> ComputedArray<'a, InstanceRecord<'a>> {
237 let range = self.instances_byte_range();
238 self.data
239 .read_with_args(range, &(self.axis_count(), self.instance_size()))
240 .unwrap_or_default()
241 }
242
243 pub(crate) fn axis_count(&self) -> u16 {
244 self.axis_count
245 }
246
247 pub(crate) fn instance_count(&self) -> u16 {
248 self.instance_count
249 }
250
251 pub(crate) fn instance_size(&self) -> u16 {
252 self.instance_size
253 }
254
255 pub fn axes_byte_range(&self) -> Range<usize> {
256 let axis_count = self.axis_count();
257 let start = 0;
258 start..start + (axis_count as usize).saturating_mul(VariationAxisRecord::RAW_BYTE_LEN)
259 }
260
261 pub fn instances_byte_range(&self) -> Range<usize> {
262 let instance_count = self.instance_count();
263 let start = self.axes_byte_range().end;
264 start
265 ..start
266 + (instance_count as usize).saturating_mul(
267 <InstanceRecord as ComputeSize>::compute_size(&(
268 self.axis_count(),
269 self.instance_size(),
270 ))
271 .unwrap_or(0),
272 )
273 }
274}
275
276#[cfg(feature = "experimental_traverse")]
277impl<'a> SomeTable<'a> for AxisInstanceArrays<'a> {
278 fn type_name(&self) -> &str {
279 "AxisInstanceArrays"
280 }
281 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
282 match idx {
283 0usize => Some(Field::new(
284 "axes",
285 traversal::FieldType::array_of_records(
286 stringify!(VariationAxisRecord),
287 self.axes(),
288 self.offset_data(),
289 ),
290 )),
291 1usize => Some(Field::new(
292 "instances",
293 traversal::FieldType::computed_array(
294 "InstanceRecord",
295 self.instances(),
296 self.offset_data(),
297 ),
298 )),
299 _ => None,
300 }
301 }
302}
303
304#[cfg(feature = "experimental_traverse")]
305#[allow(clippy::needless_lifetimes)]
306impl<'a> std::fmt::Debug for AxisInstanceArrays<'a> {
307 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
308 (self as &dyn SomeTable<'a>).fmt(f)
309 }
310}
311
312#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
314#[repr(C)]
315#[repr(packed)]
316pub struct VariationAxisRecord {
317 pub axis_tag: BigEndian<Tag>,
319 pub min_value: BigEndian<Fixed>,
321 pub default_value: BigEndian<Fixed>,
323 pub max_value: BigEndian<Fixed>,
325 pub flags: BigEndian<u16>,
327 pub axis_name_id: BigEndian<NameId>,
329}
330
331impl VariationAxisRecord {
332 pub fn axis_tag(&self) -> Tag {
334 self.axis_tag.get()
335 }
336
337 pub fn min_value(&self) -> Fixed {
339 self.min_value.get()
340 }
341
342 pub fn default_value(&self) -> Fixed {
344 self.default_value.get()
345 }
346
347 pub fn max_value(&self) -> Fixed {
349 self.max_value.get()
350 }
351
352 pub fn flags(&self) -> u16 {
354 self.flags.get()
355 }
356
357 pub fn axis_name_id(&self) -> NameId {
359 self.axis_name_id.get()
360 }
361}
362
363impl FixedSize for VariationAxisRecord {
364 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN
365 + Fixed::RAW_BYTE_LEN
366 + Fixed::RAW_BYTE_LEN
367 + Fixed::RAW_BYTE_LEN
368 + u16::RAW_BYTE_LEN
369 + NameId::RAW_BYTE_LEN;
370}
371
372#[cfg(feature = "experimental_traverse")]
373impl<'a> SomeRecord<'a> for VariationAxisRecord {
374 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
375 RecordResolver {
376 name: "VariationAxisRecord",
377 get_field: Box::new(move |idx, _data| match idx {
378 0usize => Some(Field::new("axis_tag", self.axis_tag())),
379 1usize => Some(Field::new("min_value", self.min_value())),
380 2usize => Some(Field::new("default_value", self.default_value())),
381 3usize => Some(Field::new("max_value", self.max_value())),
382 4usize => Some(Field::new("flags", self.flags())),
383 5usize => Some(Field::new("axis_name_id", self.axis_name_id())),
384 _ => None,
385 }),
386 data,
387 }
388 }
389}