From 707df96e509909c1aa5ec095320bbe29b25828dc Mon Sep 17 00:00:00 2001 From: rsheeter Date: Tue, 6 Feb 2024 14:05:06 -0800 Subject: [PATCH] Try to make field matching in fontra match better. Don't reinvent chunks. --- fontra2fontir/src/fontra.rs | 54 ++++++++++++++++++++++++++----------- fontra2fontir/src/toir.rs | 18 ++++++------- 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/fontra2fontir/src/fontra.rs b/fontra2fontir/src/fontra.rs index 8c5e7d696..9a166a0e9 100644 --- a/fontra2fontir/src/fontra.rs +++ b/fontra2fontir/src/fontra.rs @@ -4,6 +4,7 @@ use std::{ collections::{BTreeMap, HashMap}, + fmt::Display, fs, path::{Path, PathBuf}, }; @@ -13,6 +14,24 @@ use fontir::error::Error; use serde::Deserialize; use write_fonts::types::Tag; +#[derive(Debug, Clone, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) struct AxisName(pub(crate) String); + +impl Display for AxisName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.0.as_str()) + } +} + +#[derive(Debug, Clone, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) struct LayerName(pub(crate) String); + +impl Display for LayerName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.0.as_str()) + } +} + const SEPARATOR_CHAR: char = '^'; fn is_reserved_char(c: char) -> bool { @@ -63,13 +82,12 @@ const BASE_32_CHARS: [char; 32] = [ /// Matches fn string_to_filename(string: &str, suffix: &str) -> String { let string_bytes = string.as_bytes(); - let mut code_digits: Vec<_> = (0..string_bytes.len()) - .step_by(5) - .map(|i| { + let mut code_digits: Vec<_> = string_bytes + .chunks(5) + .map(|chunk| { let mut digit = 0; let mut bit = 1; - let string = string.as_bytes(); - for byte in string[i..(i + 5).min(string.len())].iter() { + for byte in chunk { if byte.is_ascii_uppercase() { digit |= bit } @@ -140,7 +158,7 @@ impl FontraFontData { #[derive(Debug, Clone, Deserialize)] pub(crate) struct FontraAxis { - pub(crate) name: String, + pub(crate) name: AxisName, pub(crate) tag: Tag, #[serde(default)] pub(crate) hidden: bool, @@ -165,7 +183,7 @@ pub(crate) struct FontraGlyph { #[serde(default)] pub(crate) axes: Vec, pub(crate) sources: Vec, - pub(crate) layers: BTreeMap, + pub(crate) layers: BTreeMap, } /// An axis specific to a glyph meant to be used as a variable component @@ -189,9 +207,9 @@ pub(crate) struct FontraGlyphAxis { pub(crate) struct FontraSource { pub(crate) name: String, #[serde(rename = "layerName")] - pub(crate) layer_name: String, + pub(crate) layer_name: LayerName, #[serde(default)] - pub(crate) location: HashMap, + pub(crate) location: HashMap, // TODO: locationBase #[serde(default)] pub(crate) inactive: bool, @@ -351,7 +369,7 @@ mod tests { .iter() .map(|a| { ( - a.name.as_str(), + a.name.0.as_str(), a.tag, a.min_value, a.default_value, @@ -418,7 +436,10 @@ mod tests { let glyph = read_test_glyph("minimal.fontra", ".notdef"); assert_eq!(GlyphName::new(".notdef"), glyph.name, "{glyph:#?}"); assert_eq!( - 1000.0, glyph.layers["foreground"].glyph.x_advance, + 1000.0, + glyph.layers[&LayerName("foreground".into())] + .glyph + .x_advance, "{glyph:#?}" ); } @@ -443,9 +464,12 @@ mod tests { fn read_simple_contours() { let glyph = read_test_glyph("2glyphs.fontra", "u20089"); assert_eq!(GlyphName::new("u20089"), glyph.name, "{glyph:#?}"); - let mut layer_names: Vec<_> = glyph.layers.keys().map(|n| n.as_str()).collect(); + let mut layer_names: Vec<_> = glyph.layers.keys().cloned().collect(); layer_names.sort(); - assert_eq!(vec!["foreground", "wght=1"], layer_names); + assert_eq!( + vec![LayerName("foreground".into()), LayerName("wght=1".into())], + layer_names + ); assert_eq!( HashSet::from([10, 11]), glyph @@ -455,7 +479,7 @@ mod tests { .collect::>(), "{glyph:#?}" ); - let contour = glyph.layers["foreground"] + let contour = glyph.layers[&LayerName("foreground".into())] .glyph .path .contours @@ -484,7 +508,7 @@ mod tests { .glyph .components .iter() - .map(|c| (n.clone(), c.name.clone()))) + .map(|c| (n.to_string(), c.name.clone()))) .collect::>(), ); } diff --git a/fontra2fontir/src/toir.rs b/fontra2fontir/src/toir.rs index 26906bb67..3dd0c149c 100644 --- a/fontra2fontir/src/toir.rs +++ b/fontra2fontir/src/toir.rs @@ -14,7 +14,7 @@ use kurbo::BezPath; use log::trace; use write_fonts::types::Tag; -use crate::fontra::{FontraContour, FontraFontData, FontraGlyph, FontraPoint, PointType}; +use crate::fontra::{AxisName, FontraContour, FontraFontData, FontraGlyph, FontraPoint, PointType}; pub(crate) fn to_ir_static_metadata( font_data: &FontraFontData, @@ -61,7 +61,7 @@ pub(crate) fn to_ir_static_metadata( Ok(Axis { tag: a.tag, - name: a.name.clone(), + name: a.name.to_string(), hidden: a.hidden, min, default, @@ -86,7 +86,7 @@ pub(crate) fn to_ir_static_metadata( /// #[allow(dead_code)] // TEMPORARY fn to_ir_glyph( - global_axes: HashMap<&str, Tag>, + global_axes: HashMap, codepoints: HashSet, fontra_glyph: &FontraGlyph, ) -> Result { @@ -99,7 +99,7 @@ fn to_ir_glyph( let layer_locations: HashMap<_, _> = fontra_glyph .sources .iter() - .map(|s| (s.layer_name.as_str(), &s.location)) + .map(|s| (&s.layer_name, &s.location)) .collect(); let mut instances = HashMap::new(); @@ -109,15 +109,15 @@ fn to_ir_glyph( todo!("Support local axes"); } - let Some(location) = layer_locations.get(layer_name.as_str()) else { - return Err(WorkError::NoSourceForName(layer_name.clone())); + let Some(location) = layer_locations.get(layer_name) else { + return Err(WorkError::NoSourceForName(layer_name.to_string())); }; let global_location: NormalizedLocation = global_axes .iter() .map(|(name, tag)| { ( *tag, - NormalizedCoord::new(location.get(*name).copied().unwrap_or_default() as f32), + NormalizedCoord::new(location.get(name).copied().unwrap_or_default() as f32), ) }) .collect(); @@ -230,7 +230,7 @@ mod tests { use write_fonts::types::Tag; use crate::{ - fontra::{FontraFontData, FontraGlyph}, + fontra::{AxisName, FontraFontData, FontraGlyph}, test::testdata_dir, toir::to_ir_static_metadata, }; @@ -300,7 +300,7 @@ mod tests { let glyph_file = testdata_dir().join("2glyphs.fontra/glyphs/u20089.json"); let fontra_glyph = FontraGlyph::from_file(&glyph_file).unwrap(); let glyph = to_ir_glyph( - HashMap::from([("Weight", Tag::new(b"wght"))]), + HashMap::from([(AxisName("Weight".into()), Tag::new(b"wght"))]), Default::default(), &fontra_glyph, )