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<LongHorizontalMetric> 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<u16> {
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<Item = HorizontalMetric> + '_ {
(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<Self, ReadError> {
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 })
}
}