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
136const _: () = assert!(FontData::default_data_long_enough(Fvar::MIN_SIZE));
137
138impl Default for Fvar<'_> {
139 fn default() -> Self {
140 Self {
141 data: FontData::default_table_data(),
142 }
143 }
144}
145
146#[cfg(feature = "experimental_traverse")]
147impl<'a> SomeTable<'a> for Fvar<'a> {
148 fn type_name(&self) -> &str {
149 "Fvar"
150 }
151 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
152 match idx {
153 0usize => Some(Field::new("version", self.version())),
154 1usize => Some(Field::new(
155 "axis_instance_arrays_offset",
156 FieldType::offset(
157 self.axis_instance_arrays_offset(),
158 self.axis_instance_arrays(),
159 ),
160 )),
161 2usize => Some(Field::new("axis_count", self.axis_count())),
162 3usize => Some(Field::new("axis_size", self.axis_size())),
163 4usize => Some(Field::new("instance_count", self.instance_count())),
164 5usize => Some(Field::new("instance_size", self.instance_size())),
165 _ => None,
166 }
167 }
168}
169
170#[cfg(feature = "experimental_traverse")]
171#[allow(clippy::needless_lifetimes)]
172impl<'a> std::fmt::Debug for Fvar<'a> {
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174 (self as &dyn SomeTable<'a>).fmt(f)
175 }
176}
177
178impl<'a> MinByteRange<'a> for AxisInstanceArrays<'a> {
179 fn min_byte_range(&self) -> Range<usize> {
180 0..self.instances_byte_range().end
181 }
182 fn min_table_bytes(&self) -> &'a [u8] {
183 let range = self.min_byte_range();
184 self.data.as_bytes().get(range).unwrap_or_default()
185 }
186}
187
188impl ReadArgs for AxisInstanceArrays<'_> {
189 type Args = (u16, u16, u16);
190}
191
192impl<'a> FontReadWithArgs<'a> for AxisInstanceArrays<'a> {
193 fn read_with_args(data: FontData<'a>, args: &(u16, u16, u16)) -> Result<Self, ReadError> {
194 let (axis_count, instance_count, instance_size) = *args;
195
196 #[allow(clippy::absurd_extreme_comparisons)]
197 if data.len() < Self::MIN_SIZE {
198 return Err(ReadError::OutOfBounds);
199 }
200 Ok(Self {
201 data,
202 axis_count,
203 instance_count,
204 instance_size,
205 })
206 }
207}
208
209impl<'a> AxisInstanceArrays<'a> {
210 pub fn read(
215 data: FontData<'a>,
216 axis_count: u16,
217 instance_count: u16,
218 instance_size: u16,
219 ) -> Result<Self, ReadError> {
220 let args = (axis_count, instance_count, instance_size);
221 Self::read_with_args(data, &args)
222 }
223}
224
225#[derive(Clone)]
227pub struct AxisInstanceArrays<'a> {
228 data: FontData<'a>,
229 axis_count: u16,
230 instance_count: u16,
231 instance_size: u16,
232}
233
234#[allow(clippy::needless_lifetimes)]
235impl<'a> AxisInstanceArrays<'a> {
236 pub const MIN_SIZE: usize = 0;
237 basic_table_impls!(impl_the_methods);
238
239 pub fn axes(&self) -> &'a [VariationAxisRecord] {
241 let range = self.axes_byte_range();
242 self.data.read_array(range).ok().unwrap_or_default()
243 }
244
245 pub fn instances(&self) -> ComputedArray<'a, InstanceRecord<'a>> {
247 let range = self.instances_byte_range();
248 self.data
249 .read_with_args(range, &(self.axis_count(), self.instance_size()))
250 .unwrap_or_default()
251 }
252
253 pub(crate) fn axis_count(&self) -> u16 {
254 self.axis_count
255 }
256
257 pub(crate) fn instance_count(&self) -> u16 {
258 self.instance_count
259 }
260
261 pub(crate) fn instance_size(&self) -> u16 {
262 self.instance_size
263 }
264
265 pub fn axes_byte_range(&self) -> Range<usize> {
266 let axis_count = self.axis_count();
267 let start = 0;
268 start
269 ..start
270 + (transforms::to_usize(axis_count))
271 .saturating_mul(VariationAxisRecord::RAW_BYTE_LEN)
272 }
273
274 pub fn instances_byte_range(&self) -> Range<usize> {
275 let instance_count = self.instance_count();
276 let start = self.axes_byte_range().end;
277 start
278 ..start
279 + (transforms::to_usize(instance_count)).saturating_mul(
280 <InstanceRecord as ComputeSize>::compute_size(&(
281 self.axis_count(),
282 self.instance_size(),
283 ))
284 .unwrap_or(0),
285 )
286 }
287}
288
289#[allow(clippy::absurd_extreme_comparisons)]
290const _: () = assert!(FontData::default_data_long_enough(
291 AxisInstanceArrays::MIN_SIZE
292));
293
294impl Default for AxisInstanceArrays<'_> {
295 fn default() -> Self {
296 Self {
297 data: FontData::default_table_data(),
298 axis_count: Default::default(),
299 instance_count: Default::default(),
300 instance_size: Default::default(),
301 }
302 }
303}
304
305#[cfg(feature = "experimental_traverse")]
306impl<'a> SomeTable<'a> for AxisInstanceArrays<'a> {
307 fn type_name(&self) -> &str {
308 "AxisInstanceArrays"
309 }
310 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
311 match idx {
312 0usize => Some(Field::new(
313 "axes",
314 traversal::FieldType::array_of_records(
315 stringify!(VariationAxisRecord),
316 self.axes(),
317 self.offset_data(),
318 ),
319 )),
320 1usize => Some(Field::new(
321 "instances",
322 traversal::FieldType::computed_array(
323 "InstanceRecord",
324 self.instances(),
325 self.offset_data(),
326 ),
327 )),
328 _ => None,
329 }
330 }
331}
332
333#[cfg(feature = "experimental_traverse")]
334#[allow(clippy::needless_lifetimes)]
335impl<'a> std::fmt::Debug for AxisInstanceArrays<'a> {
336 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
337 (self as &dyn SomeTable<'a>).fmt(f)
338 }
339}
340
341#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
343#[repr(C)]
344#[repr(packed)]
345pub struct VariationAxisRecord {
346 pub axis_tag: BigEndian<Tag>,
348 pub min_value: BigEndian<Fixed>,
350 pub default_value: BigEndian<Fixed>,
352 pub max_value: BigEndian<Fixed>,
354 pub flags: BigEndian<u16>,
356 pub axis_name_id: BigEndian<NameId>,
358}
359
360impl VariationAxisRecord {
361 pub fn axis_tag(&self) -> Tag {
363 self.axis_tag.get()
364 }
365
366 pub fn min_value(&self) -> Fixed {
368 self.min_value.get()
369 }
370
371 pub fn default_value(&self) -> Fixed {
373 self.default_value.get()
374 }
375
376 pub fn max_value(&self) -> Fixed {
378 self.max_value.get()
379 }
380
381 pub fn flags(&self) -> u16 {
383 self.flags.get()
384 }
385
386 pub fn axis_name_id(&self) -> NameId {
388 self.axis_name_id.get()
389 }
390}
391
392impl FixedSize for VariationAxisRecord {
393 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN
394 + Fixed::RAW_BYTE_LEN
395 + Fixed::RAW_BYTE_LEN
396 + Fixed::RAW_BYTE_LEN
397 + u16::RAW_BYTE_LEN
398 + NameId::RAW_BYTE_LEN;
399}
400
401#[cfg(feature = "experimental_traverse")]
402impl<'a> SomeRecord<'a> for VariationAxisRecord {
403 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
404 RecordResolver {
405 name: "VariationAxisRecord",
406 get_field: Box::new(move |idx, _data| match idx {
407 0usize => Some(Field::new("axis_tag", self.axis_tag())),
408 1usize => Some(Field::new("min_value", self.min_value())),
409 2usize => Some(Field::new("default_value", self.default_value())),
410 3usize => Some(Field::new("max_value", self.max_value())),
411 4usize => Some(Field::new("flags", self.flags())),
412 5usize => Some(Field::new("axis_name_id", self.axis_name_id())),
413 _ => None,
414 }),
415 data,
416 }
417 }
418}