Files
another-boids-in-rust/vendor/ttf-parser-0.20.0/src/tables/trak.rs

182 lines
4.6 KiB
Rust

//! A [Tracking Table](
//! https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html) implementation.
use crate::parser::{Fixed, FromData, LazyArray16, Offset, Offset16, Offset32, Stream};
#[derive(Clone, Copy, Debug)]
struct TrackTableRecord {
value: Fixed,
name_id: u16,
offset: Offset16, // Offset from start of the table.
}
impl FromData for TrackTableRecord {
const SIZE: usize = 8;
#[inline]
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(TrackTableRecord {
value: s.read::<Fixed>()?,
name_id: s.read::<u16>()?,
offset: s.read::<Offset16>()?,
})
}
}
/// A single track.
#[derive(Clone, Copy, Debug)]
pub struct Track<'a> {
/// A track value.
pub value: f32,
/// The `name` table index for the track's name.
pub name_index: u16,
/// A list of tracking values for each size.
pub values: LazyArray16<'a, i16>,
}
/// A list of tracks.
#[derive(Clone, Copy, Default, Debug)]
pub struct Tracks<'a> {
data: &'a [u8], // the whole table
records: LazyArray16<'a, TrackTableRecord>,
sizes_count: u16,
}
impl<'a> Tracks<'a> {
/// Returns a track at index.
pub fn get(&self, index: u16) -> Option<Track<'a>> {
let record = self.records.get(index)?;
let mut s = Stream::new(self.data.get(record.offset.to_usize()..)?);
Some(Track {
value: record.value.0,
values: s.read_array16::<i16>(self.sizes_count)?,
name_index: record.name_id,
})
}
/// Returns the number of tracks.
pub fn len(&self) -> u16 {
self.records.len()
}
/// Checks if there are any tracks.
pub fn is_empty(&self) -> bool {
self.records.is_empty()
}
}
impl<'a> IntoIterator for Tracks<'a> {
type Item = Track<'a>;
type IntoIter = TracksIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
TracksIter {
tracks: self,
index: 0,
}
}
}
/// An iterator over [`Tracks`].
#[allow(missing_debug_implementations)]
pub struct TracksIter<'a> {
tracks: Tracks<'a>,
index: u16,
}
impl<'a> Iterator for TracksIter<'a> {
type Item = Track<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.tracks.len() {
self.index += 1;
self.tracks.get(self.index - 1)
} else {
None
}
}
}
/// A track data.
#[derive(Clone, Copy, Default, Debug)]
pub struct TrackData<'a> {
/// A list of tracks.
pub tracks: Tracks<'a>,
/// A list of sizes.
pub sizes: LazyArray16<'a, Fixed>,
}
impl<'a> TrackData<'a> {
fn parse(offset: usize, data: &'a [u8]) -> Option<Self> {
let mut s = Stream::new_at(data, offset)?;
let tracks_count = s.read::<u16>()?;
let sizes_count = s.read::<u16>()?;
let size_table_offset = s.read::<Offset32>()?; // Offset from start of the table.
let tracks = Tracks {
data,
records: s.read_array16::<TrackTableRecord>(tracks_count)?,
sizes_count,
};
// TODO: Isn't the size table is directly after the tracks table?!
// Why we need an offset then?
let sizes = {
let mut s = Stream::new_at(data, size_table_offset.to_usize())?;
s.read_array16::<Fixed>(sizes_count)?
};
Some(TrackData { tracks, sizes })
}
}
/// A [Tracking Table](
/// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html).
#[derive(Clone, Copy, Debug)]
pub struct Table<'a> {
/// Horizontal track data.
pub horizontal: TrackData<'a>,
/// Vertical track data.
pub vertical: TrackData<'a>,
}
impl<'a> Table<'a> {
/// Parses a table from raw data.
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 format = s.read::<u16>()?;
if format != 0 {
return None;
}
let hor_offset = s.read::<Option<Offset16>>()?;
let ver_offset = s.read::<Option<Offset16>>()?;
s.skip::<u16>(); // reserved
let horizontal = if let Some(offset) = hor_offset {
TrackData::parse(offset.to_usize(), data)?
} else {
TrackData::default()
};
let vertical = if let Some(offset) = ver_offset {
TrackData::parse(offset.to_usize(), data)?
} else {
TrackData::default()
};
Some(Table {
horizontal,
vertical,
})
}
}