use crate::ceil_div_u16;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct GlyphId(pub u16);
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct GlyphMetrics {
pub w: u8, pub h: u8, pub yoff: u8, pub left: i8, pub advance: i16,
pub(crate) offset: u32, }
impl GlyphMetrics {
#[inline]
pub(crate) fn decode(data: &[u8], offset: usize) -> Option<Self> {
if offset + 6 > data.len() {
return None;
}
let bits = (data[offset] as u64)
| ((data[offset + 1] as u64) << 8)
| ((data[offset + 2] as u64) << 16)
| ((data[offset + 3] as u64) << 24)
| ((data[offset + 4] as u64) << 32)
| ((data[offset + 5] as u64) << 40);
let w = ((bits >> 0) & 0x7F) as u8;
let h = ((bits >> 7) & 0x7F) as u8;
let yoff = ((bits >> 14) & 0x7F) as u8;
let advd5 = ((bits >> 21) & 0x1F) as u8; let left4 = ((bits >> 26) & 0x0F) as u8; let off18 = ((bits >> 30) & 0x3FFFF) as u32;
let adv_delta = sign_extend_5(advd5) as i16;
let advance = (w as i16) + adv_delta;
let left = sign_extend_4(left4);
Some(Self { w, h, yoff, left, offset: off18, advance })
}
}
pub(crate) struct GlyphPixels<'a> {
slab: &'a [u8], bpr: usize, w: u16,
remaining_total: usize, remaining_in_row: u16, row: u16, byte_index: usize, use_high: bool, cur: u8, }
impl<'a> GlyphPixels<'a> {
#[inline(always)]
pub(crate) fn new(slab: &'a [u8], metrics: GlyphMetrics) -> Self {
Self {
slab,
bpr: ceil_div_u16(metrics.w as u16, 2) as usize,
w: metrics.w as u16,
remaining_total: (metrics.w as usize).saturating_mul(metrics.h as usize),
remaining_in_row: 0,
row: 0,
byte_index: 0,
use_high: false,
cur: 0,
}
}
}
impl<'a> Iterator for GlyphPixels<'a> {
type Item = u8; #[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.remaining_total == 0 {
return None;
}
if self.remaining_in_row == 0 {
let base = (self.row as usize) * self.bpr;
self.row += 1;
self.remaining_in_row = self.w;
self.byte_index = base;
self.use_high = false;
self.cur = unsafe { *self.slab.get_unchecked(self.byte_index) };
}
let shift = (self.use_high as u8 as u32) * 4;
let nib = ((self.cur as u32) >> shift) as u8 & 0x0F;
let alpha = nib << 4;
self.remaining_total -= 1;
self.remaining_in_row -= 1;
if self.use_high {
self.use_high = false;
self.byte_index += 1;
if self.remaining_in_row > 0 {
self.cur = unsafe { *self.slab.get_unchecked(self.byte_index) };
}
} else {
if self.remaining_in_row > 0 {
self.use_high = true;
}
}
Some(alpha)
}
}
#[inline]
fn sign_extend_5(v: u8) -> i8 {
((v as i8) << 3) >> 3
}
#[inline]
fn sign_extend_4(v: u8) -> i8 {
((v as i8) << 4) >> 4
}