use std::collections::{BTreeMap, HashSet};
use crate::{language::Language, reporter::Reporter, GlyphId, ResultCode};
use rustybuzz::Face;
pub struct Checker<'a> {
pub face: Face<'a>,
pub glyph_names: Vec<String>,
pub features: HashSet<String>,
pub cmap: BTreeMap<u32, GlyphId>,
reversed_cmap: BTreeMap<GlyphId, u32>,
}
impl<'a> Checker<'a> {
#[cfg(feature = "skrifa")]
pub fn new(data: &'a [u8]) -> Result<Self, skrifa::raw::ReadError> {
use skrifa::{FontRef, MetadataProvider};
let font = FontRef::new(data)?;
Ok(Self::from_parts(
Face::from_slice(data, 0).expect("could not parse the font"),
crate::font::glyph_names(&font)?,
crate::font::feature_tags(&font)?,
font.charmap()
.mappings()
.map(|(character, glyph)| (character, glyph.to_u32()))
.collect(),
))
}
pub fn from_parts(
face: Face<'a>,
glyph_names: Vec<String>,
features: HashSet<String>,
cmap: BTreeMap<u32, GlyphId>,
) -> Self {
let reversed_cmap = cmap.iter().map(|(k, v)| (*v, *k)).collect();
Self {
face,
glyph_names,
features,
cmap,
reversed_cmap,
}
}
pub fn codepoint_for(&self, gid: GlyphId) -> Option<u32> {
self.reversed_cmap.get(&gid).copied()
}
pub fn check(&self, language: &Language) -> Reporter {
let mut results = Reporter::default();
for check_object in language.checks.iter() {
let checkresult = check_object.execute(self);
let status = checkresult.status;
results.add(checkresult);
if status == ResultCode::StopNow {
break;
}
}
results
}
}