//! Font metadata for the embedded UI fonts. //! //! The packs carry sfnt fonts (`\x00\x01\x00\x00` TrueType, `OTTO` OpenType/CFF) //! and TrueType Collections (`ttcf`). We only need light metadata to *present* //! them — family name, face count, glyph count — which `ttf-parser` extracts //! safely (malformed input yields `None`, never a panic). The raw bytes are //! handed to egui separately for a live sample. use ttf_parser::{fonts_in_collection, name_id, Face}; /// Light font metadata for the viewer. #[derive(Debug, Clone, PartialEq)] pub struct FontInfo { /// "TrueType", "OpenType (CFF)", or "TrueType Collection". pub kind: &'static str, /// Family / full name (best-effort; empty if the name table is unreadable). pub family: String, /// Number of faces (1 for a plain sfnt, N for a `ttcf` collection). pub faces: u32, /// Glyph count of the first face. pub glyphs: u16, } /// Whether `bytes` starts with a recognized font signature. pub fn is_font(bytes: &[u8]) -> bool { matches!( bytes.get(0..4), Some(b"\x00\x01\x00\x00") | Some(b"OTTO") | Some(b"true") | Some(b"ttcf") ) } /// Extract light metadata, or `None` if the font can't be parsed. pub fn parse_info(bytes: &[u8]) -> Option { let is_collection = bytes.get(0..4) == Some(b"ttcf"); let faces = fonts_in_collection(bytes).unwrap_or(1).max(1); // Face 0 gives the representative family + glyph count. let face = Face::parse(bytes, 0).ok()?; let glyphs = face.number_of_glyphs(); let kind = if is_collection { "TrueType Collection" } else if bytes.get(0..4) == Some(b"OTTO") { "OpenType (CFF)" } else { "TrueType" }; // Prefer the typographic/full family name; fall back to any readable name. let family = face .names() .into_iter() .filter(|n| n.name_id == name_id::FULL_NAME || n.name_id == name_id::FAMILY) .find_map(|n| n.to_string()) .or_else(|| face.names().into_iter().find_map(|n| n.to_string())) .unwrap_or_default(); Some(FontInfo { kind, family, faces, glyphs, }) }