use super::parse_prelude::*;
pub const FVAR: Tag = Tag::new(b"fvar");
#[derive(Copy, Clone)]
pub struct Fvar<'a> {
data: Buffer<'a>,
axis_offset: u16,
num_axes: u16,
axis_size: u16,
num_instances: u16,
instance_size: u16,
}
impl<'a> Fvar<'a> {
pub fn new(data: &'a [u8]) -> Self {
let data = Buffer::new(data);
let axis_offset = data.read_or_default::<u16>(4);
let num_axes = data.read_or_default::<u16>(8);
let axis_size = data.read_or_default::<u16>(10);
let num_instances = data.read_or_default::<u16>(12);
let instance_size = data.read_or_default::<u16>(14);
Self {
data,
axis_offset,
num_axes,
axis_size,
num_instances,
instance_size,
}
}
pub fn major_version(&self) -> u16 {
self.data.read(0).unwrap_or(0)
}
pub fn minor_version(&self) -> u16 {
self.data.read(2).unwrap_or(0)
}
pub fn num_axes(&self) -> u16 {
self.num_axes
}
pub fn axis(&self, index: u16) -> Option<Axis> {
if index >= self.num_axes {
return None;
}
let b = &self.data;
let base = self.axis_offset as usize;
let offset = base + index as usize * self.axis_size as usize;
let tag = b.read_tag(offset)?;
let min_value = Fixed(b.read::<i32>(offset + 4)?);
let default_value = Fixed(b.read::<i32>(offset + 8)?);
let max_value = Fixed(b.read::<i32>(offset + 12)?);
let flags = b.read::<u16>(offset + 16)?;
let name_id = b.read::<u16>(offset + 18)?;
Some(Axis {
index,
tag,
name_id,
flags,
min_value,
default_value,
max_value,
})
}
pub fn axes(&'a self) -> impl Iterator<Item = Axis> + 'a + Clone {
(0..self.num_axes()).filter_map(move |index| self.axis(index))
}
pub fn num_instances(&self) -> u16 {
self.num_instances
}
pub fn instance(&self, index: u16) -> Option<Instance<'a>> {
if index >= self.num_instances {
return None;
}
let b = &self.data;
let base = self.axis_offset as usize + (self.num_axes as usize * self.axis_size as usize);
let offset = base + index as usize * self.instance_size as usize;
let subfamily_name_id = b.read_u16(offset)?;
let flags = b.read_u16(offset + 2)?;
let coords = b.read_slice::<Fixed>(offset + 4, self.num_axes as usize)?;
let ps_name_offset = 4 + self.num_axes as usize * 4;
let postscript_name_id = if ps_name_offset == self.instance_size as usize - 2 {
b.read_u16(ps_name_offset)
} else {
None
};
Some(Instance {
index,
subfamily_name_id,
flags,
coords,
postscript_name_id,
})
}
pub fn instances(&'a self) -> impl Iterator<Item = Instance<'a>> + 'a + Clone {
(0..self.num_instances()).filter_map(move |index| self.instance(index))
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct Axis {
pub index: u16,
pub tag: Tag,
pub name_id: u16,
pub flags: u16,
pub min_value: Fixed,
pub default_value: Fixed,
pub max_value: Fixed,
}
impl Axis {
pub fn is_hidden(&self) -> bool {
self.flags & 1 != 0
}
pub fn normalize(&self, mut value: Fixed) -> Fixed {
use core::cmp::Ordering::*;
if value < self.min_value {
value = self.min_value;
} else if value > self.max_value {
value = self.max_value;
}
value = match value.cmp(&self.default_value) {
Less => -((self.default_value - value) / (self.default_value - self.min_value)),
Greater => (value - self.default_value) / (self.max_value - self.default_value),
Equal => Fixed(0),
};
value.min(Fixed::ONE).max(-Fixed::ONE)
}
}
#[derive(Copy, Clone)]
pub struct Instance<'a> {
pub index: u16,
pub subfamily_name_id: u16,
pub flags: u16,
pub coords: Slice<'a, Fixed>,
pub postscript_name_id: Option<u16>,
}