use core::num::NonZeroU16;
use crate::parser::{f32_bound, Fixed, FromData, LazyArray16, Offset, Offset16, Stream};
use crate::{NormalizedCoordinate, Tag};
#[repr(C)]
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct VariationAxis {
pub tag: Tag,
pub min_value: f32,
pub def_value: f32,
pub max_value: f32,
pub name_id: u16,
pub hidden: bool,
}
impl FromData for VariationAxis {
const SIZE: usize = 20;
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
let tag = s.read::<Tag>()?;
let min_value = s.read::<Fixed>()?;
let def_value = s.read::<Fixed>()?;
let max_value = s.read::<Fixed>()?;
let flags = s.read::<u16>()?;
let name_id = s.read::<u16>()?;
Some(VariationAxis {
tag,
min_value: def_value.0.min(min_value.0),
def_value: def_value.0,
max_value: def_value.0.max(max_value.0),
name_id,
hidden: (flags >> 3) & 1 == 1,
})
}
}
impl VariationAxis {
pub(crate) fn normalized_value(&self, mut v: f32) -> NormalizedCoordinate {
v = f32_bound(self.min_value, v, self.max_value);
if v == self.def_value {
v = 0.0;
} else if v < self.def_value {
v = (v - self.def_value) / (self.def_value - self.min_value);
} else {
v = (v - self.def_value) / (self.max_value - self.def_value);
}
NormalizedCoordinate::from(v)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
pub axes: LazyArray16<'a, VariationAxis>,
}
impl<'a> Table<'a> {
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new(data);
let version = s.read::<u32>()?;
if version != 0x00010000 {
return None;
}
let axes_array_offset = s.read::<Offset16>()?;
s.skip::<u16>(); let axis_count = s.read::<u16>()?;
let axis_count = NonZeroU16::new(axis_count)?;
let mut s = Stream::new_at(data, axes_array_offset.to_usize())?;
let axes = s.read_array16::<VariationAxis>(axis_count.get())?;
Some(Table { axes })
}
}