//! `OS/2` — OS/2 and Windows Metrics table. //! //! Contains font-wide metrics used for line spacing, weight classification, //! and typographic alignment. //! Reference: use crate::font::parse::Reader; use crate::font::FontError; /// Parsed `OS/2` table. #[derive(Debug)] pub struct Os2Table { /// Table version (0–5). pub version: u16, /// Average weighted advance width of lowercase letters and space. pub x_avg_char_width: i16, /// Visual weight class (100–900). pub us_weight_class: u16, /// Visual width class (1–9). pub us_width_class: u16, /// Font embedding licensing rights. pub fs_type: u16, /// Typographic ascender. pub s_typo_ascender: i16, /// Typographic descender (typically negative). pub s_typo_descender: i16, /// Typographic line gap. pub s_typo_line_gap: i16, /// Strikeout stroke size in font design units. pub y_strikeout_size: i16, /// Strikeout stroke position above baseline. pub y_strikeout_position: i16, /// Subscript vertical offset. pub y_subscript_y_offset: i16, /// Superscript vertical offset. pub y_superscript_y_offset: i16, /// Height of lowercase 'x' (version >= 2, else 0). pub sx_height: i16, /// Height of uppercase letters (version >= 2, else 0). pub s_cap_height: i16, } impl Os2Table { /// Parse the `OS/2` table from raw bytes. pub fn parse(data: &[u8]) -> Result { let r = Reader::new(data); // Minimum OS/2 table is 78 bytes (version 0). if r.len() < 78 { return Err(FontError::MalformedTable("OS/2: too short")); } let version = r.u16(0)?; let x_avg_char_width = r.i16(2)?; let us_weight_class = r.u16(4)?; let us_width_class = r.u16(6)?; let fs_type = r.u16(8)?; // Subscript/superscript offsets: offsets 14 and 18 respectively // ySubscriptXSize(10), ySubscriptYSize(12), ySubscriptXOffset(14) let y_subscript_y_offset = r.i16(16)?; // ySuperscriptXSize(18), ySuperscriptYSize(20), ySuperscriptXOffset(22) let y_superscript_y_offset = r.i16(24)?; let y_strikeout_size = r.i16(26)?; let y_strikeout_position = r.i16(28)?; // sTypoAscender is at offset 68, sTypoDescender at 70, sTypoLineGap at 72 let s_typo_ascender = r.i16(68)?; let s_typo_descender = r.i16(70)?; let s_typo_line_gap = r.i16(72)?; // sxHeight and sCapHeight are available in version >= 2 at offsets 86 and 88. let (sx_height, s_cap_height) = if version >= 2 && r.len() >= 96 { (r.i16(86)?, r.i16(88)?) } else { (0, 0) }; Ok(Os2Table { version, x_avg_char_width, us_weight_class, us_width_class, fs_type, s_typo_ascender, s_typo_descender, s_typo_line_gap, y_strikeout_size, y_strikeout_position, y_subscript_y_offset, y_superscript_y_offset, sx_height, s_cap_height, }) } }