use bytes::{Buf, BufMut};
use crate::{
compute_checksum,
error::{WuffErr, bail_if, bail_with_msg_if},
};
pub struct HmtxData {
num_glyphs: u16,
num_hmetrics: u16,
advance_widths: Vec<u16>,
lsbs: Vec<i16>,
}
pub(crate) fn decode_hmtx_table(
input: &mut impl Buf,
num_glyphs: u16,
num_hmetrics: u16,
x_mins: &[i16],
) -> Result<HmtxData, WuffErr> {
let hmtx_flags: u8 = input.try_get_u8()?;
let has_proportional_lsbs: bool = (hmtx_flags & 1) == 0;
let has_monospace_lsbs: bool = (hmtx_flags & 2) == 0;
bail_with_msg_if!(
(hmtx_flags & 0xFC) != 0,
"Illegal hmtx flags; bits 2-7 must be 0"
);
bail_if!(has_proportional_lsbs && has_monospace_lsbs);
assert!(x_mins.len() == num_glyphs as usize);
bail_if!(num_hmetrics > num_glyphs);
bail_if!(num_hmetrics < 1);
let mut advance_widths: Vec<u16> = Vec::with_capacity(num_hmetrics as usize);
for _ in 0..num_hmetrics {
advance_widths.push(input.try_get_u16()?);
}
let mut lsbs: Vec<i16> = Vec::with_capacity(num_glyphs as usize);
for i in 0..num_hmetrics {
lsbs.push(match has_proportional_lsbs {
true => input.try_get_i16()?,
false => x_mins[i as usize],
});
}
for i in num_hmetrics..num_glyphs {
lsbs.push(match has_monospace_lsbs {
true => input.try_get_i16()?,
false => x_mins[i as usize],
});
}
Ok(HmtxData {
num_glyphs,
num_hmetrics,
advance_widths,
lsbs,
})
}
pub(crate) fn generate_hmtx_table(hmtx_data: &HmtxData) -> Result<Vec<u8>, WuffErr> {
let num_glyphs = hmtx_data.num_glyphs as usize;
let num_hmetrics = hmtx_data.num_hmetrics as usize;
let hmtx_output_size: usize = 2 * num_glyphs + 2 * num_hmetrics;
let mut hmtx_table: Vec<u8> = Vec::with_capacity(hmtx_output_size);
for i in 0..num_glyphs {
if i < num_hmetrics {
hmtx_table.put_u16(hmtx_data.advance_widths[i]);
}
hmtx_table.put_i16(hmtx_data.lsbs[i]);
}
Ok(hmtx_table)
}