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..start + (axis_count as usize).saturating_mul(VariationAxisRecord::RAW_BYTE_LEN)
269 }
270
271 pub fn instances_byte_range(&self) -> Range<usize> {
272 let instance_count = self.instance_count();
273 let start = self.axes_byte_range().end;
274 start
275 ..start
276 + (instance_count as usize).saturating_mul(
277 <InstanceRecord as ComputeSize>::compute_size(&(
278 self.axis_count(),
279 self.instance_size(),
280 ))
281 .unwrap_or(0),
282 )
283 }
284}
285
286#[allow(clippy::absurd_extreme_comparisons)]
287const _: () = assert!(FontData::default_data_long_enough(
288 AxisInstanceArrays::MIN_SIZE
289));
290
291impl Default for AxisInstanceArrays<'_> {
292 fn default() -> Self {
293 Self {
294 data: FontData::default_table_data(),
295 axis_count: Default::default(),
296 instance_count: Default::default(),
297 instance_size: Default::default(),
298 }
299 }
300}
301
302#[cfg(feature = "experimental_traverse")]
303impl<'a> SomeTable<'a> for AxisInstanceArrays<'a> {
304 fn type_name(&self) -> &str {
305 "AxisInstanceArrays"
306 }
307 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
308 match idx {
309 0usize => Some(Field::new(
310 "axes",
311 traversal::FieldType::array_of_records(
312 stringify!(VariationAxisRecord),
313 self.axes(),
314 self.offset_data(),
315 ),
316 )),
317 1usize => Some(Field::new(
318 "instances",
319 traversal::FieldType::computed_array(
320 "InstanceRecord",
321 self.instances(),
322 self.offset_data(),
323 ),
324 )),
325 _ => None,
326 }
327 }
328}
329
330#[cfg(feature = "experimental_traverse")]
331#[allow(clippy::needless_lifetimes)]
332impl<'a> std::fmt::Debug for AxisInstanceArrays<'a> {
333 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
334 (self as &dyn SomeTable<'a>).fmt(f)
335 }
336}
337
338#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
340#[repr(C)]
341#[repr(packed)]
342pub struct VariationAxisRecord {
343 pub axis_tag: BigEndian<Tag>,
345 pub min_value: BigEndian<Fixed>,
347 pub default_value: BigEndian<Fixed>,
349 pub max_value: BigEndian<Fixed>,
351 pub flags: BigEndian<u16>,
353 pub axis_name_id: BigEndian<NameId>,
355}
356
357impl VariationAxisRecord {
358 pub fn axis_tag(&self) -> Tag {
360 self.axis_tag.get()
361 }
362
363 pub fn min_value(&self) -> Fixed {
365 self.min_value.get()
366 }
367
368 pub fn default_value(&self) -> Fixed {
370 self.default_value.get()
371 }
372
373 pub fn max_value(&self) -> Fixed {
375 self.max_value.get()
376 }
377
378 pub fn flags(&self) -> u16 {
380 self.flags.get()
381 }
382
383 pub fn axis_name_id(&self) -> NameId {
385 self.axis_name_id.get()
386 }
387}
388
389impl FixedSize for VariationAxisRecord {
390 const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN
391 + Fixed::RAW_BYTE_LEN
392 + Fixed::RAW_BYTE_LEN
393 + Fixed::RAW_BYTE_LEN
394 + u16::RAW_BYTE_LEN
395 + NameId::RAW_BYTE_LEN;
396}
397
398#[cfg(feature = "experimental_traverse")]
399impl<'a> SomeRecord<'a> for VariationAxisRecord {
400 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
401 RecordResolver {
402 name: "VariationAxisRecord",
403 get_field: Box::new(move |idx, _data| match idx {
404 0usize => Some(Field::new("axis_tag", self.axis_tag())),
405 1usize => Some(Field::new("min_value", self.min_value())),
406 2usize => Some(Field::new("default_value", self.default_value())),
407 3usize => Some(Field::new("max_value", self.max_value())),
408 4usize => Some(Field::new("flags", self.flags())),
409 5usize => Some(Field::new("axis_name_id", self.axis_name_id())),
410 _ => None,
411 }),
412 data,
413 }
414 }
415}