From 6f5c02b75d397e75c077beb809b538f3477c0136 Mon Sep 17 00:00:00 2001 From: Colin Rofls Date: Thu, 21 Nov 2024 18:18:27 -0500 Subject: [PATCH] [glyphs] Clean up custom params We're going to need to support a bunch of of these, and it was becoming hard to keep track of what was being handled and what wasn't. This moves all the custom params (at the font level) into a new CustomFontParameters struct. It also reduces boilerplate when these are used in glyphs2fontir. The ultimate goal here is to do smarter parsing of these custom paramaters in such a way as to be able to warn if there are any we aren't handling. --- glyphs-reader/src/font.rs | 197 ++++++++++++------------- glyphs-reader/src/lib.rs | 4 +- glyphs2fontir/src/source.rs | 280 +++++++++--------------------------- 3 files changed, 160 insertions(+), 321 deletions(-) diff --git a/glyphs-reader/src/font.rs b/glyphs-reader/src/font.rs index 19203e7d..255fb652 100644 --- a/glyphs-reader/src/font.rs +++ b/glyphs-reader/src/font.rs @@ -41,12 +41,9 @@ pub struct AxisUserToDesignMap(Vec<(OrderedFloat, OrderedFloat)>); /// A tidied up font from a plist. /// /// Normalized representation of Glyphs 2/3 content -#[derive(Debug, PartialEq, Hash)] +#[derive(Debug, Default, PartialEq, Hash)] pub struct Font { pub units_per_em: u16, - pub fs_type: Option, - pub use_typo_metrics: Option, - pub has_wws_names: Option, pub axes: Vec, pub masters: Vec, pub default_master_idx: usize, @@ -65,6 +62,15 @@ pub struct Font { // master id => { (name or class, name or class) => adjustment } pub kerning_ltr: Kerning, + pub custom_parameters: FontCustomParameters, +} + +/// Custom parameter options that can be set on a glyphs font +#[derive(Clone, Debug, PartialEq, Hash, Default)] +pub struct FontCustomParameters { + pub use_typo_metrics: Option, + pub fs_type: Option, + pub has_wws_names: Option, pub typo_ascender: Option, pub typo_descender: Option, pub typo_line_gap: Option, @@ -85,7 +91,6 @@ pub struct Font { pub superscript_x_size: Option, pub superscript_y_offset: Option, pub superscript_y_size: Option, - pub unicode_range_bits: Option>, pub codepage_range_bits: Option>, pub panose: Option>, @@ -330,7 +335,7 @@ struct RawFont { properties: Vec, #[fromplist(alt_name = "kerning")] kerning_LTR: Kerning, - custom_parameters: CustomParameters, + custom_parameters: RawCustomParameters, numbers: Vec, } @@ -342,9 +347,59 @@ struct NumberName { // we use a vec of tuples instead of a map because there can be multiple // values for the same name (e.g. 'Virtual Master') #[derive(Clone, Default, Debug, PartialEq, Eq, Hash)] -pub(crate) struct CustomParameters(Vec<(String, CustomParameterValue)>); +pub(crate) struct RawCustomParameters(Vec<(String, CustomParameterValue)>); + +impl RawCustomParameters { + /// convert into the parsed params for a top-level font + fn to_font_params(&self) -> Result { + let fs_type = self + .fs_type() + .map(|bits| bits.iter().map(|bit| 1 << bit).sum()); + + let unicode_range_bits = self + .unicode_range() + .map(|bits| bits.iter().map(|b| *b as u32).collect()); + + let codepage_range_bits = self + .codepage_range() + .map(|bits| { + bits.iter() + .map(|b| codepage_range_bit(*b as u32)) + .collect::>() + }) + .transpose()?; + + let panose = self.panose().cloned(); + Ok(FontCustomParameters { + use_typo_metrics: self.bool("Use Typo Metrics"), + has_wws_names: self.bool("Has WWS Names"), + typo_ascender: self.int("typoAscender"), + typo_descender: self.int("typoDescender"), + typo_line_gap: self.int("typoLineGap"), + win_ascent: self.int("winAscent"), + win_descent: self.int("winDescent"), + hhea_ascender: self.int("hheaAscender"), + hhea_descender: self.int("hheaDescender"), + hhea_line_gap: self.int("hheaLineGap"), + underline_thickness: self.float("underlineThickness"), + underline_position: self.float("underlinePosition"), + strikeout_position: self.int("strikeoutPosition"), + strikeout_size: self.int("strikeoutSize"), + subscript_x_offset: self.int("subscriptXOffset"), + subscript_x_size: self.int("subscriptXSize"), + subscript_y_offset: self.int("subscriptYOffset"), + subscript_y_size: self.int("subscriptYSize"), + superscript_x_offset: self.int("superscriptXOffset"), + superscript_x_size: self.int("superscriptXSize"), + superscript_y_offset: self.int("superscriptYOffset"), + superscript_y_size: self.int("superscriptYSize"), + fs_type, + unicode_range_bits, + codepage_range_bits, + panose, + }) + } -impl CustomParameters { /// Get the first parameter with the given name, or `None` if not found. fn get(&self, name: &str) -> Option<&CustomParameterValue> { self.0.iter().find_map(|(n, v)| (n == name).then_some(v)) @@ -467,7 +522,7 @@ enum CustomParameterValue { } /// Hand-parse these because they take multiple shapes -impl FromPlist for CustomParameters { +impl FromPlist for RawCustomParameters { fn parse(tokenizer: &mut Tokenizer<'_>) -> Result { use crate::plist::Error; let mut params = Vec::new(); @@ -607,7 +662,7 @@ impl FromPlist for CustomParameters { } // the close paren broke the loop, don't consume here - Ok(CustomParameters(params)) + Ok(RawCustomParameters(params)) } } @@ -966,7 +1021,7 @@ struct RawFontMaster { alignment_zones: Vec, // v2 - custom_parameters: CustomParameters, + custom_parameters: RawCustomParameters, number_values: Vec>, #[fromplist(ignore)] @@ -2309,29 +2364,7 @@ impl TryFrom for Font { let radix = if from.is_v2() { 16 } else { 10 }; let glyph_order = parse_glyph_order(&from); - let use_typo_metrics = from.custom_parameters.bool("Use Typo Metrics"); - let has_wws_names = from.custom_parameters.bool("Has WWS Names"); - let typo_ascender = from.custom_parameters.int("typoAscender"); - let typo_descender = from.custom_parameters.int("typoDescender"); - let typo_line_gap = from.custom_parameters.int("typoLineGap"); - let win_ascent = from.custom_parameters.int("winAscent"); - let win_descent = from.custom_parameters.int("winDescent"); - let hhea_ascender = from.custom_parameters.int("hheaAscender"); - let hhea_descender = from.custom_parameters.int("hheaDescender"); - let hhea_line_gap = from.custom_parameters.int("hheaLineGap"); - let underline_thickness = from.custom_parameters.float("underlineThickness"); - let underline_position = from.custom_parameters.float("underlinePosition"); - let strikeout_position = from.custom_parameters.int("strikeoutPosition"); - let strikeout_size = from.custom_parameters.int("strikeoutSize"); - let subscript_x_offset = from.custom_parameters.int("subscriptXOffset"); - let subscript_x_size = from.custom_parameters.int("subscriptXSize"); - let subscript_y_offset = from.custom_parameters.int("subscriptYOffset"); - let subscript_y_size = from.custom_parameters.int("subscriptYSize"); - let superscript_x_offset = from.custom_parameters.int("superscriptXOffset"); - let superscript_x_size = from.custom_parameters.int("superscriptXSize"); - let superscript_y_offset = from.custom_parameters.int("superscriptYOffset"); - let superscript_y_size = from.custom_parameters.int("superscriptYSize"); - + let custom_parameters = from.custom_parameters.to_font_params()?; let axes = from.axes.clone(); let instances: Vec<_> = from .instances @@ -2361,33 +2394,9 @@ impl TryFrom for Font { features.push(feature.raw_feature_to_feature()?); } - let Some(units_per_em) = from.units_per_em else { - return Err(Error::NoUnitsPerEm); - }; + let units_per_em = from.units_per_em.ok_or(Error::NoUnitsPerEm)?; let units_per_em = units_per_em.try_into().map_err(Error::InvalidUpem)?; - let fs_type = from - .custom_parameters - .fs_type() - .map(|bits| bits.iter().map(|bit| 1 << bit).sum()); - - let unicode_range_bits = from - .custom_parameters - .unicode_range() - .map(|bits| bits.iter().map(|b| *b as u32).collect()); - - let codepage_range_bits = from - .custom_parameters - .codepage_range() - .map(|bits| { - bits.iter() - .map(|b| codepage_range_bit(*b as u32)) - .collect::>() - }) - .transpose()?; - - let panose = from.custom_parameters.panose().cloned(); - let mut names = BTreeMap::new(); for name in from.properties { if name.value.is_some() { @@ -2494,9 +2503,6 @@ impl TryFrom for Font { Ok(Font { units_per_em, - fs_type, - use_typo_metrics, - has_wws_names, axes, masters, default_master_idx, @@ -2511,29 +2517,7 @@ impl TryFrom for Font { version_minor: from.versionMinor.unwrap_or_default() as u32, date: from.date, kerning_ltr: from.kerning_LTR, - typo_ascender, - typo_descender, - typo_line_gap, - win_ascent, - win_descent, - hhea_ascender, - hhea_descender, - hhea_line_gap, - underline_thickness, - underline_position, - strikeout_position, - strikeout_size, - subscript_x_offset, - subscript_x_size, - subscript_y_offset, - subscript_y_size, - superscript_x_offset, - superscript_x_size, - superscript_y_offset, - superscript_y_size, - unicode_range_bits, - codepage_range_bits, - panose, + custom_parameters, }) } } @@ -3357,16 +3341,15 @@ mod tests { #[test] fn read_os2_flags_default_set() { let font = Font::load(&glyphs2_dir().join("WghtVar.glyphs")).unwrap(); - assert_eq!( - (Some(true), Some(true)), - (font.use_typo_metrics, font.has_wws_names) - ); + assert_eq!(font.custom_parameters.use_typo_metrics, Some(true)); + assert_eq!(font.custom_parameters.has_wws_names, Some(true)); } #[test] fn read_os2_flags_default_unset() { let font = Font::load(&glyphs2_dir().join("WghtVar_OS2.glyphs")).unwrap(); - assert_eq!((None, None), (font.use_typo_metrics, font.has_wws_names)); + assert_eq!(font.custom_parameters.use_typo_metrics, None); + assert_eq!(font.custom_parameters.has_wws_names, None); } #[test] @@ -3473,19 +3456,19 @@ mod tests { #[test] fn read_fstype_none() { let font = Font::load(&glyphs3_dir().join("infinity.glyphs")).unwrap(); - assert!(font.fs_type.is_none()); + assert!(font.custom_parameters.fs_type.is_none()); } #[test] fn read_fstype_zero() { let font = Font::load(&glyphs3_dir().join("fstype_0x0000.glyphs")).unwrap(); - assert_eq!(Some(0), font.fs_type); + assert_eq!(Some(0), font.custom_parameters.fs_type); } #[test] fn read_fstype_bits() { let font = Font::load(&glyphs3_dir().join("fstype_0x0104.glyphs")).unwrap(); - assert_eq!(Some(0x104), font.fs_type); + assert_eq!(Some(0x104), font.custom_parameters.fs_type); } #[test] @@ -3571,7 +3554,7 @@ mod tests { fn custom_params_disable() { let font = Font::load(&glyphs3_dir().join("custom_param_disable.glyphs")).unwrap(); - assert!(font.fs_type.is_none()) + assert!(font.custom_parameters.fs_type.is_none()) } #[test] @@ -3591,15 +3574,21 @@ mod tests { fn read_font_metrics() { let font = Font::load(&glyphs3_dir().join("GlobalMetrics_font_customParameters.glyphs")).unwrap(); - assert_eq!(Some(950), font.typo_ascender); - assert_eq!(Some(-350), font.typo_descender); - assert_eq!(Some(0), font.typo_line_gap); - assert_eq!(Some(950), font.hhea_ascender); - assert_eq!(Some(-350), font.hhea_descender); - assert_eq!(Some(0), font.hhea_line_gap); - assert_eq!(Some(1185), font.win_ascent); - assert_eq!(Some(420), font.win_descent); - assert_eq!(Some(OrderedFloat(42_f64)), font.underline_thickness); - assert_eq!(Some(OrderedFloat(-300_f64)), font.underline_position); + assert_eq!(Some(950), font.custom_parameters.typo_ascender); + assert_eq!(Some(-350), font.custom_parameters.typo_descender); + assert_eq!(Some(0), font.custom_parameters.typo_line_gap); + assert_eq!(Some(950), font.custom_parameters.hhea_ascender); + assert_eq!(Some(-350), font.custom_parameters.hhea_descender); + assert_eq!(Some(0), font.custom_parameters.hhea_line_gap); + assert_eq!(Some(1185), font.custom_parameters.win_ascent); + assert_eq!(Some(420), font.custom_parameters.win_descent); + assert_eq!( + Some(OrderedFloat(42_f64)), + font.custom_parameters.underline_thickness + ); + assert_eq!( + Some(OrderedFloat(-300_f64)), + font.custom_parameters.underline_position + ); } } diff --git a/glyphs-reader/src/lib.rs b/glyphs-reader/src/lib.rs index 9b3c1b69..26f16572 100644 --- a/glyphs-reader/src/lib.rs +++ b/glyphs-reader/src/lib.rs @@ -9,7 +9,7 @@ mod plist; mod propagate_anchors; pub use font::{ - Axis, Component, FeatureSnippet, Font, FontMaster, Glyph, InstanceType, Layer, Node, NodeType, - Path, Shape, + Axis, Component, FeatureSnippet, Font, FontCustomParameters, FontMaster, Glyph, InstanceType, + Layer, Node, NodeType, Path, Shape, }; pub use plist::Plist; diff --git a/glyphs2fontir/src/source.rs b/glyphs2fontir/src/source.rs index 3f2aa7ae..d3bfce9f 100644 --- a/glyphs2fontir/src/source.rs +++ b/glyphs2fontir/src/source.rs @@ -27,7 +27,7 @@ use fontir::{ }; use glyphs_reader::{ glyphdata::{Category, Subcategory}, - Font, InstanceType, + Font, FontCustomParameters, InstanceType, }; use ordered_float::OrderedFloat; use smol_str::SmolStr; @@ -90,46 +90,14 @@ impl GlyphsIrSource { // Explicitly field by field so if we add more compiler will force us to update here let font = Font { units_per_em: font.units_per_em, - fs_type: font.fs_type, - use_typo_metrics: font.use_typo_metrics, - has_wws_names: font.has_wws_names, axes: font.axes.clone(), masters: font.masters.clone(), default_master_idx: font.default_master_idx, - glyphs: Default::default(), - glyph_order: Default::default(), axis_mappings: font.axis_mappings.clone(), - virtual_masters: Default::default(), - features: Default::default(), - names: Default::default(), instances: font.instances.clone(), - version_major: Default::default(), - version_minor: Default::default(), date: None, - kerning_ltr: Default::default(), - typo_ascender: font.typo_ascender, - typo_descender: font.typo_descender, - typo_line_gap: font.typo_line_gap, - win_ascent: font.win_ascent, - win_descent: font.win_descent, - hhea_ascender: font.hhea_ascender, - hhea_descender: font.hhea_descender, - hhea_line_gap: font.hhea_line_gap, - underline_thickness: font.underline_thickness, - underline_position: font.underline_position, - strikeout_position: font.strikeout_position, - strikeout_size: font.strikeout_size, - subscript_x_offset: font.subscript_x_offset, - subscript_x_size: font.subscript_x_size, - subscript_y_offset: font.subscript_y_offset, - subscript_y_size: font.subscript_y_size, - superscript_x_offset: font.superscript_x_offset, - superscript_x_size: font.superscript_x_size, - superscript_y_offset: font.superscript_y_offset, - superscript_y_size: font.superscript_y_size, - unicode_range_bits: font.unicode_range_bits.clone(), - codepage_range_bits: font.codepage_range_bits.clone(), - panose: font.panose.clone(), + custom_parameters: font.custom_parameters.clone(), + ..Default::default() }; state.track_memory("/font_master".to_string(), &font)?; Ok(state) @@ -142,9 +110,6 @@ impl GlyphsIrSource { // Explicitly field by field so if we add more compiler will force us to update here let font = Font { units_per_em: font.units_per_em, - fs_type: None, - use_typo_metrics: font.use_typo_metrics, - has_wws_names: None, axes: font.axes.clone(), masters: font.masters.clone(), default_master_idx: font.default_master_idx, @@ -159,29 +124,14 @@ impl GlyphsIrSource { version_minor: Default::default(), date: None, kerning_ltr: font.kerning_ltr.clone(), - typo_ascender: font.typo_ascender, - typo_descender: font.typo_descender, - typo_line_gap: font.typo_line_gap, - win_ascent: font.win_ascent, - win_descent: font.win_descent, - hhea_ascender: font.hhea_ascender, - hhea_descender: font.hhea_descender, - hhea_line_gap: font.hhea_line_gap, - underline_thickness: font.underline_thickness, - underline_position: font.underline_position, - strikeout_position: font.strikeout_position, - strikeout_size: font.strikeout_size, - subscript_x_offset: font.subscript_x_offset, - subscript_x_size: font.subscript_x_size, - subscript_y_offset: font.subscript_y_offset, - subscript_y_size: font.subscript_y_size, - superscript_x_offset: font.superscript_x_offset, - superscript_x_size: font.superscript_x_size, - superscript_y_offset: font.superscript_y_offset, - superscript_y_size: font.superscript_y_size, - unicode_range_bits: None, - codepage_range_bits: None, - panose: None, + custom_parameters: FontCustomParameters { + unicode_range_bits: None, + codepage_range_bits: None, + panose: None, + fs_type: None, + has_wws_names: None, + ..font.custom_parameters.clone() + }, }; state.track_memory("/font_master".to_string(), &font)?; Ok(state) @@ -412,10 +362,10 @@ impl Work for StaticMetadataWork { let number_values = get_number_values(font_info, font); - let selection_flags = match font.use_typo_metrics.unwrap_or_default() { + let selection_flags = match font.custom_parameters.use_typo_metrics.unwrap_or_default() { true => SelectionFlags::USE_TYPO_METRICS, false => SelectionFlags::empty(), - } | match font.has_wws_names.unwrap_or_default() { + } | match font.custom_parameters.has_wws_names.unwrap_or_default() { true => SelectionFlags::WWS, false => SelectionFlags::empty(), } | @@ -455,18 +405,20 @@ impl Work for StaticMetadataWork { } // Default per - static_metadata.misc.fs_type = font.fs_type.or(Some(1 << 3)); + static_metadata.misc.fs_type = font.custom_parameters.fs_type.or(Some(1 << 3)); static_metadata.misc.unicode_range_bits = font + .custom_parameters .unicode_range_bits .as_ref() .map(|bits| bits.iter().copied().collect()); static_metadata.misc.codepage_range_bits = font + .custom_parameters .codepage_range_bits .as_ref() .map(|bits| bits.iter().copied().collect()); - if let Some(raw_panose) = font.panose.as_ref() { + if let Some(raw_panose) = font.custom_parameters.panose.as_ref() { let mut bytes = [0u8; 10]; bytes .iter_mut() @@ -598,166 +550,64 @@ impl Work for GlobalMetricWork { metrics.set_if_some(GlobalMetric::CapHeight, pos.clone(), Some(cap_height)); metrics.set_if_some(GlobalMetric::XHeight, pos.clone(), Some(x_height)); - metrics.set_if_some( - GlobalMetric::Os2TypoAscender, - pos.clone(), - master - .typo_ascender - .or(font.typo_ascender) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::Os2TypoDescender, - pos.clone(), - master - .typo_descender - .or(font.typo_descender) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::Os2TypoLineGap, - pos.clone(), - master - .typo_line_gap - .or(font.typo_line_gap) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::Os2WinAscent, - pos.clone(), - master.win_ascent.or(font.win_ascent).map(|v| v as f64), - ); // Some .glyphs files have a negative win descent so abs() + // we don't use the macro here because of the special abs() logic metrics.set_if_some( GlobalMetric::Os2WinDescent, pos.clone(), master .win_descent - .or(font.win_descent) + .or(font.custom_parameters.win_descent) .map(|v| v.abs() as f64), ); - metrics.set_if_some( - GlobalMetric::StrikeoutPosition, - pos.clone(), - master - .strikeout_position - .or(font.strikeout_position) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::StrikeoutSize, - pos.clone(), - master - .strikeout_size - .or(font.strikeout_size) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::SubscriptXOffset, - pos.clone(), - master - .subscript_x_offset - .or(font.subscript_x_offset) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::SubscriptXSize, - pos.clone(), - master - .subscript_x_size - .or(font.subscript_x_size) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::SubscriptYOffset, - pos.clone(), - master - .subscript_y_offset - .or(font.subscript_y_offset) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::SubscriptYSize, - pos.clone(), - master - .subscript_y_size - .or(font.subscript_y_size) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::SuperscriptXOffset, - pos.clone(), - master - .superscript_x_offset - .or(font.superscript_x_offset) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::SuperscriptXSize, - pos.clone(), - master - .superscript_x_size - .or(font.superscript_x_size) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::SuperscriptYOffset, - pos.clone(), - master - .superscript_y_offset - .or(font.superscript_y_offset) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::SuperscriptYSize, - pos.clone(), - master - .superscript_y_size - .or(font.superscript_y_size) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::HheaAscender, - pos.clone(), - master - .hhea_ascender - .or(font.hhea_ascender) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::HheaDescender, - pos.clone(), - master - .hhea_descender - .or(font.hhea_descender) - .map(|v| v as f64), - ); - metrics.set_if_some( - GlobalMetric::HheaLineGap, - pos.clone(), - master - .hhea_line_gap - .or(font.hhea_line_gap) - .map(|v| v as f64), - ); + + macro_rules! set_metric { + // the most common pattern + ($variant:ident, $field_name:ident) => { + set_metric!( + $variant, + master + .$field_name + .or(font.custom_parameters.$field_name) + .map(|v| v as f64) + ) + }; + // a few fields have a manual default though + ($variant:ident, $field_name:ident, $fallback:literal) => { + set_metric!( + $variant, + master + .$field_name + .or(font.custom_parameters.$field_name) + .or(Some($fallback.into())) + ) + }; + // base case, both branches above resolve to this + ($variant:ident, $getter:expr ) => { + metrics.set_if_some(GlobalMetric::$variant, pos.clone(), $getter) + }; + } + set_metric!(Os2TypoAscender, typo_ascender); + set_metric!(Os2TypoDescender, typo_descender); + set_metric!(Os2TypoLineGap, typo_line_gap); + set_metric!(Os2WinAscent, win_ascent); + set_metric!(StrikeoutPosition, strikeout_position); + set_metric!(StrikeoutSize, strikeout_size); + set_metric!(SubscriptXOffset, subscript_x_offset); + set_metric!(SubscriptXSize, subscript_x_size); + set_metric!(SubscriptYOffset, subscript_y_offset); + set_metric!(SubscriptYSize, subscript_y_size); + set_metric!(SuperscriptXOffset, superscript_x_offset); + set_metric!(SuperscriptXSize, superscript_x_size); + set_metric!(SuperscriptYOffset, superscript_y_offset); + set_metric!(SuperscriptYSize, superscript_y_size); + set_metric!(HheaAscender, hhea_ascender); + set_metric!(HheaDescender, hhea_descender); + set_metric!(HheaLineGap, hhea_line_gap); // 50.0 is the Glyphs default - metrics.set_if_some( - GlobalMetric::UnderlineThickness, - pos.clone(), - master - .underline_thickness - .or(font.underline_thickness) - .or(Some(OrderedFloat(50.0))), - ); + set_metric!(UnderlineThickness, underline_thickness, 50.0); // -100.0 is the Glyphs default - metrics.set_if_some( - GlobalMetric::UnderlinePosition, - pos.clone(), - master - .underline_position - .or(font.underline_position) - .or(Some(OrderedFloat(-100.0))), - ); + set_metric!(UnderlinePosition, underline_position, -100.0); metrics.populate_defaults( pos,