use std::fmt::{ Debug, Formatter, Result as FmtResult }; use bytemuck::{ Zeroable, Pod }; use super::ReadError; use super::core::*; #[derive(Clone, Copy, Zeroable, Pod)] #[repr(transparent)] pub struct LongVerticalMetric([u8; 4]); impl<'a> RandomAccess<'a> for &'a LongVerticalMetric { fn bytes(&self) -> &'a [u8] { &self.0 } } impl LongVerticalMetric { pub fn advance_height(&self) -> u16 { self.uint16(0) } pub fn top_side_bearing(&self) -> i16 { self.int16(2) } } impl Debug for LongVerticalMetric { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("LongVerticalMetric") .field("advance_height", &self.advance_height()) .field("top_side_bearing", &self.top_side_bearing()) .finish() } } #[derive(Clone, Copy)] pub struct VerticalMetric { pub advance_height: u16, pub top_side_bearing: i16, } impl From<&LongVerticalMetric> for VerticalMetric { fn from(value: &LongVerticalMetric) -> Self { Self { advance_height: value.advance_height(), top_side_bearing: value.top_side_bearing(), } } } impl From for VerticalMetric { fn from(value: LongVerticalMetric) -> Self { Self { advance_height: value.advance_height(), top_side_bearing: value.top_side_bearing(), } } } impl Debug for VerticalMetric { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("VerticalMetric") .field("advance_height", &self.advance_height) .field("top_side_bearing", &self.top_side_bearing) .finish() } } #[derive(Clone, Copy)] pub struct VerticalMetricsTable<'a> { number_of_vmetrics: u16, remaining_count: u16, data: &'a [u8], } impl<'a> RandomAccess<'a> for VerticalMetricsTable<'a> { fn bytes(&self) -> &'a [u8] { self.data } } impl<'a> VerticalMetricsTable<'a> { pub fn long_vertical_metrics(&self) -> &'a [LongVerticalMetric] { self.array(0, self.number_of_vmetrics as usize) } pub fn remaining_top_side_bearings(&self) -> I16Array<'a> { self.int16_array(self.number_of_vmetrics as usize * 4, self.remaining_count as usize) } pub fn default_advance_height(&self) -> Option { self.long_vertical_metrics().last().map(LongVerticalMetric::advance_height) } pub fn get(&self, glyph_index: u16) -> VerticalMetric { if glyph_index < self.number_of_vmetrics { let long_hor = &self.long_vertical_metrics()[glyph_index as usize]; VerticalMetric::from(long_hor) } else { let advance_height = self.default_advance_height().unwrap_or_default(); let top_side_bearing = self.remaining_top_side_bearings().get(glyph_index as usize - self.number_of_vmetrics as usize); VerticalMetric { advance_height, top_side_bearing } } } pub fn iter(&self) -> impl ExactSizeIterator + '_ { (0..self.number_of_vmetrics + self.remaining_count).map(|i| self.get(i)) } } impl<'a> Debug for VerticalMetricsTable<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.iter()) .finish() } } impl<'a> VerticalMetricsTable<'a> { pub fn try_from(data: &'a [u8], number_of_vmetrics: u16, num_glyphs: u16) -> Result { let remaining_count = num_glyphs - number_of_vmetrics; if data.len() < number_of_vmetrics as usize * 4 + remaining_count as usize * 2 { return Err(ReadError::UnexpectedEof); } Ok(VerticalMetricsTable { number_of_vmetrics, remaining_count, data }) } }