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