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 LongHorizontalMetric([u8; 4]); impl<'a> RandomAccess<'a> for &'a LongHorizontalMetric { fn bytes(&self) -> &'a [u8] { &self.0 } } impl LongHorizontalMetric { pub fn advance_width(&self) -> u16 { self.uint16(0) } pub fn left_side_bearing(&self) -> i16 { self.int16(2) } } impl Debug for LongHorizontalMetric { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("LongHorizontalMetric") .field("advance_width", &self.advance_width()) .field("left_side_bearing", &self.left_side_bearing()) .finish() } } #[derive(Clone, Copy)] pub struct HorizontalMetric { pub advance_width: u16, pub left_side_bearing: i16, } impl From<&LongHorizontalMetric> for HorizontalMetric { fn from(value: &LongHorizontalMetric) -> Self { Self { advance_width: value.advance_width(), left_side_bearing: value.left_side_bearing(), } } } impl From for HorizontalMetric { fn from(value: LongHorizontalMetric) -> Self { Self { advance_width: value.advance_width(), left_side_bearing: value.left_side_bearing(), } } } impl Debug for HorizontalMetric { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("HorizontalMetric") .field("advance_width", &self.advance_width) .field("left_side_bearing", &self.left_side_bearing) .finish() } } #[derive(Clone, Copy)] pub struct HorizontalMetricsTable<'a> { number_of_hmetrics: u16, remaining_count: u16, data: &'a [u8], } impl<'a> RandomAccess<'a> for HorizontalMetricsTable<'a> { fn bytes(&self) -> &'a [u8] { self.data } } impl<'a> HorizontalMetricsTable<'a> { pub fn long_horizontal_metrics(&self) -> &'a [LongHorizontalMetric] { self.array(0, self.number_of_hmetrics as usize) } pub fn remaining_left_side_bearings(&self) -> I16Array<'a> { self.int16_array(self.number_of_hmetrics as usize * 4, self.remaining_count as usize) } pub fn default_advance_width(&self) -> Option { self.long_horizontal_metrics().last().map(LongHorizontalMetric::advance_width) } pub fn get(&self, glyph_index: u16) -> HorizontalMetric { if glyph_index < self.number_of_hmetrics { let long_hor = &self.long_horizontal_metrics()[glyph_index as usize]; HorizontalMetric::from(long_hor) } else { let advance_width = self.default_advance_width().unwrap_or_default(); let left_side_bearing = self.remaining_left_side_bearings().get(glyph_index as usize - self.number_of_hmetrics as usize); HorizontalMetric { advance_width, left_side_bearing } } } pub fn iter(&self) -> impl ExactSizeIterator + '_ { (0..self.number_of_hmetrics + self.remaining_count).map(|i| self.get(i)) } } impl<'a> Debug for HorizontalMetricsTable<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.iter()) .finish() } } impl<'a> HorizontalMetricsTable<'a> { pub fn try_from(data: &'a [u8], number_of_hmetrics: u16, num_glyphs: u16) -> Result { let remaining_count = num_glyphs - number_of_hmetrics; if data.len() < number_of_hmetrics as usize * 4 + remaining_count as usize * 2 { return Err(ReadError::UnexpectedEof); } Ok(HorizontalMetricsTable { number_of_hmetrics, remaining_count, data }) } }