From 0b335660c4da56fc8d0a678fcdfb99faec233b22 Mon Sep 17 00:00:00 2001 From: Colin Rofls Date: Tue, 26 Nov 2024 12:16:02 -0500 Subject: [PATCH] [glyphs] Handle additional custom params Specifically openTypeHeadLowestRecPPEM, and the various hhea & vhea caret properties. (vhea isn't handled yet, but we can at least parse it now in preparation) --- glyphs-reader/src/font.rs | 54 +++++++++++++++++++++++++++++++++++-- glyphs2fontir/src/source.rs | 21 +++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/glyphs-reader/src/font.rs b/glyphs-reader/src/font.rs index d5df88c6..86900fe2 100644 --- a/glyphs-reader/src/font.rs +++ b/glyphs-reader/src/font.rs @@ -95,6 +95,13 @@ pub struct CustomParameters { pub codepage_range_bits: Option>, pub panose: Option>, + pub lowest_rec_ppem: Option, + pub hhea_caret_slope_run: Option, + pub hhea_caret_slope_rise: Option, + pub hhea_caret_offset: Option, + pub vhea_caret_slope_run: Option, + pub vhea_caret_slope_rise: Option, + pub vhea_caret_offset: Option, // these fields are parsed via the config, but are stored // in the top-level `Font` struct pub virtual_masters: Option>>>, @@ -520,7 +527,15 @@ impl RawCustomParameters { { macro_rules! add_and_report_issues { ($field:ident, $converter:path) => {{ - let value = $converter(value); + add_and_report_issues!($field, $converter(value)) + }}; + + ($field:ident, $converter:path, into) => {{ + add_and_report_issues!($field, $converter(value).map(Into::into)) + }}; + + ($field:ident, $value_expr:expr) => {{ + let value = $value_expr; if value.is_none() { log::warn!("failed to parse param for '{}'", stringify!($field)); @@ -570,6 +585,40 @@ impl RawCustomParameters { "codePageRanges" => { add_and_report_issues!(codepage_range_bits, Plist::as_codepage_bits) } + // these values are not listed in the glyphs.app UI, but exist + // in some fonts. Maybe only fonts converted to glyphs format + // from something else? + "openTypeHeadLowestRecPPEM" => { + add_and_report_issues!(lowest_rec_ppem, Plist::as_i64) + } + "openTypeHheaCaretSlopeRun" => { + add_and_report_issues!(hhea_caret_slope_run, Plist::as_i64) + } + "openTypeHheaCaretSlopeRise" => { + add_and_report_issues!(hhea_caret_slope_rise, Plist::as_i64) + } + "openTypeHheaCaretOffset" => { + add_and_report_issues!(hhea_caret_offset, Plist::as_i64) + } + "openTypeVheaCaretSlopeRun" => { + add_and_report_issues!(vhea_caret_slope_run, Plist::as_i64) + } + "openTypeVheaCaretSlopeRise" => { + add_and_report_issues!(vhea_caret_slope_rise, Plist::as_i64) + } + "openTypeVheaCaretOffset" => { + add_and_report_issues!(vhea_caret_offset, Plist::as_i64) + } + // these might need to be handled? they're in the same list as + // the items above: + // https://github.com/googlefonts/glyphsLib/blob/74c63244fdb/Lib/glyphsLib/builder/custom_params.py#L429 + "openTypeNameUniqueID" + | "openTypeNameVersion" + | "openTypeOS2FamilyClass" + | "openTypeHeadFlags" => { + log::warn!("unhandled custom param '{name}'") + } + "Virtual Master" => match value.as_virtual_master() { Some(val) => virtual_masters.push(val), None => log::warn!("failed to parse virtual master '{value:?}'"), @@ -577,7 +626,7 @@ impl RawCustomParameters { "panose" => panose = value.as_vec_of_ints(), "openTypeOS2Panose" => panose_old = value.as_vec_of_ints(), "glyphOrder" => add_and_report_issues!(glyph_order, Plist::as_vec_of_string), - _ => log::warn!("unhandled custom parameter '{name}'"), + _ => log::warn!("unknown custom parameter '{name}'"), } } params.panose = panose.or(panose_old); @@ -2266,6 +2315,7 @@ impl TryFrom for Font { let mut custom_parameters = from.custom_parameters.cook()?; let glyph_order = make_glyph_order(&from.glyphs, custom_parameters.glyph_order.take()); + let axes = from.axes.clone(); let instances: Vec<_> = from .instances diff --git a/glyphs2fontir/src/source.rs b/glyphs2fontir/src/source.rs index e531464b..2ab206fd 100644 --- a/glyphs2fontir/src/source.rs +++ b/glyphs2fontir/src/source.rs @@ -429,6 +429,9 @@ impl Work for StaticMetadataWork { static_metadata.misc.version_major = font.version_major; static_metadata.misc.version_minor = font.version_minor; + if let Some(lowest_rec_ppm) = font.custom_parameters.lowest_rec_ppem { + static_metadata.misc.lowest_rec_ppm = lowest_rec_ppm as _; + } static_metadata.misc.created = font .date @@ -607,6 +610,9 @@ impl Work for GlobalMetricWork { set_metric!(HheaAscender, hhea_ascender); set_metric!(HheaDescender, hhea_descender); set_metric!(HheaLineGap, hhea_line_gap); + set_metric!(CaretSlopeRun, hhea_caret_slope_run); + set_metric!(CaretSlopeRise, hhea_caret_slope_rise); + set_metric!(CaretOffset, hhea_caret_offset); // 50.0 is the Glyphs default set_metric!(UnderlineThickness, underline_thickness, 50.0); // -100.0 is the Glyphs default @@ -1846,4 +1852,19 @@ mod tests { context.static_metadata.get().misc.panose ); } + + #[test] + fn capture_unsual_params() { + // both parameters; value under short name should be preferred + let (_, context) = build_static_metadata(glyphs3_dir().join("UnusualCustomParams.glyphs")); + let meta = context.static_metadata.get(); + assert_eq!(meta.misc.lowest_rec_ppm, 7); + + // some of these end up as metrics: + let (_, context) = build_global_metrics(glyphs3_dir().join("UnusualCustomParams.glyphs")); + let metrics = context.global_metrics.get(); + assert_eq!(unique_value(&metrics, GlobalMetric::CaretOffset), 2.); + assert_eq!(unique_value(&metrics, GlobalMetric::CaretSlopeRise), 1.); + assert_eq!(unique_value(&metrics, GlobalMetric::CaretSlopeRun), 5.); + } }