//! `hmtx` — Horizontal Metrics table. //! //! Contains per-glyph horizontal metrics (advance width + left side bearing). //! Reference: use crate::font::parse::Reader; use crate::font::FontError; /// Parsed `hmtx` table. /// /// Both `advances` and `lsbs` are indexed by glyph ID and have exactly /// `num_glyphs` entries. #[derive(Debug)] pub struct HmtxTable { /// Advance widths for each glyph (in font units). pub advances: Vec, /// Left side bearings for each glyph (in font units). pub lsbs: Vec, } impl HmtxTable { /// Parse the `hmtx` table from raw bytes. /// /// `num_long_hor_metrics` comes from `hhea`, `num_glyphs` from `maxp`. pub fn parse( data: &[u8], num_long_hor_metrics: u16, num_glyphs: u16, ) -> Result { let r = Reader::new(data); let n_long = num_long_hor_metrics as usize; let n_glyphs = num_glyphs as usize; let mut advances = Vec::with_capacity(n_glyphs); let mut lsbs = Vec::with_capacity(n_glyphs); // First n_long entries are (advance_width: u16, lsb: i16) pairs. for i in 0..n_long { let offset = i * 4; advances.push(r.u16(offset)?); lsbs.push(r.i16(offset + 2)?); } // Remaining glyphs share the last advance width, but have individual lsbs. let last_advance = advances.last().copied().unwrap_or(0); let remaining = n_glyphs.saturating_sub(n_long); let lsb_offset = n_long * 4; for i in 0..remaining { advances.push(last_advance); lsbs.push(r.i16(lsb_offset + i * 2)?); } Ok(HmtxTable { advances, lsbs }) } }