From d6d9f7382da3748e1577f494a86ffcb79553a0e6 Mon Sep 17 00:00:00 2001 From: Colin Rofls Date: Tue, 3 Dec 2024 10:57:58 -0500 Subject: [PATCH] Compile meta from ufo sources --- fontir/src/ir.rs | 2 +- .../testdata/MetaTable.ufo/fontinfo.plist | 38 ++++++++++++ .../MetaTable.ufo/glyphs/contents.plist | 6 ++ .../MetaTable.ufo/layercontents.plist | 10 +++ resources/testdata/MetaTable.ufo/lib.plist | 19 ++++++ .../testdata/MetaTable.ufo/metainfo.plist | 10 +++ ufo2fontir/src/source.rs | 61 ++++++++++++++++++- 7 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 resources/testdata/MetaTable.ufo/fontinfo.plist create mode 100644 resources/testdata/MetaTable.ufo/glyphs/contents.plist create mode 100644 resources/testdata/MetaTable.ufo/layercontents.plist create mode 100644 resources/testdata/MetaTable.ufo/lib.plist create mode 100644 resources/testdata/MetaTable.ufo/metainfo.plist diff --git a/fontir/src/ir.rs b/fontir/src/ir.rs index 741649f92..cc32e9e17 100644 --- a/fontir/src/ir.rs +++ b/fontir/src/ir.rs @@ -193,7 +193,7 @@ impl Panose { /// /// [meta]: https://learn.microsoft.com/en-us/typography/opentype/spec/meta /// [dlng slng]: https://learn.microsoft.com/en-us/typography/opentype/spec/meta#dlng-and-slng-design-and-supported-languages -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] pub struct MetaTableValues { /// ScriptLangTags for the design languages pub dlng: Vec, diff --git a/resources/testdata/MetaTable.ufo/fontinfo.plist b/resources/testdata/MetaTable.ufo/fontinfo.plist new file mode 100644 index 000000000..e75e8de16 --- /dev/null +++ b/resources/testdata/MetaTable.ufo/fontinfo.plist @@ -0,0 +1,38 @@ + + + + + unitsPerEm + 1000 + familyName + Duck Duck + styleName + Regular + openTypeOS2VendorID + RODS + ascender + 737 + capHeight + 702 + descender + -42 + xHeight + 501 + openTypeOS2TypoAscender + 1193 + openTypeOS2TypoDescender + -289 + openTypeOS2TypoLineGap + 42 + openTypeOS2WinAscent + 1325 + openTypeOS2WinDescent + 377 + openTypeHheaAscender + 1194 + openTypeHheaDescender + -290 + openTypeHheaLineGap + 43 + + diff --git a/resources/testdata/MetaTable.ufo/glyphs/contents.plist b/resources/testdata/MetaTable.ufo/glyphs/contents.plist new file mode 100644 index 000000000..1607a9e33 --- /dev/null +++ b/resources/testdata/MetaTable.ufo/glyphs/contents.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/testdata/MetaTable.ufo/layercontents.plist b/resources/testdata/MetaTable.ufo/layercontents.plist new file mode 100644 index 000000000..b9c1a4f27 --- /dev/null +++ b/resources/testdata/MetaTable.ufo/layercontents.plist @@ -0,0 +1,10 @@ + + + + + + public.default + glyphs + + + diff --git a/resources/testdata/MetaTable.ufo/lib.plist b/resources/testdata/MetaTable.ufo/lib.plist new file mode 100644 index 000000000..10454c716 --- /dev/null +++ b/resources/testdata/MetaTable.ufo/lib.plist @@ -0,0 +1,19 @@ + + + + + public.openTypeMeta + + dlng + + en-latn + fr-latn + nl-Latn + + slng + + Latn,Cyrl + + + + diff --git a/resources/testdata/MetaTable.ufo/metainfo.plist b/resources/testdata/MetaTable.ufo/metainfo.plist new file mode 100644 index 000000000..7b8b34ac6 --- /dev/null +++ b/resources/testdata/MetaTable.ufo/metainfo.plist @@ -0,0 +1,10 @@ + + + + + creator + com.github.fonttools.ufoLib + formatVersion + 3 + + diff --git a/ufo2fontir/src/source.rs b/ufo2fontir/src/source.rs index 2ee6e2aa1..76401a6bf 100644 --- a/ufo2fontir/src/source.rs +++ b/ufo2fontir/src/source.rs @@ -15,8 +15,8 @@ use fontir::{ error::{BadSource, BadSourceKind, Error}, ir::{ AnchorBuilder, FeaturesSource, GdefCategories, GlobalMetric, GlobalMetrics, GlyphOrder, - KernGroup, KernSide, KerningGroups, KerningInstance, NameBuilder, NameKey, NamedInstance, - Panose, PostscriptNames, StaticMetadata, DEFAULT_VENDOR_ID, + KernGroup, KernSide, KerningGroups, KerningInstance, MetaTableValues, NameBuilder, NameKey, + NamedInstance, Panose, PostscriptNames, StaticMetadata, DEFAULT_VENDOR_ID, }, orchestration::{Context, Flags, IrWork, WorkId}, source::{Input, Source}, @@ -1019,6 +1019,10 @@ impl Work for StaticMetadataWork { try_parse_date(font_info_at_default.open_type_head_created.as_ref()) .or(static_metadata.misc.created); + static_metadata.misc.meta_table = lib_plist + .get("public.openTypeMeta") + .and_then(parse_meta_table_values); + context.preliminary_glyph_order.set(glyph_order); context.static_metadata.set(static_metadata); Ok(()) @@ -1030,6 +1034,39 @@ fn is_glyph_only(source: &norad::designspace::Source) -> bool { source.layer.is_some() } +fn parse_meta_table_values(plist: &plist::Value) -> Option { + let plist = plist.as_dictionary()?; + let mut ret = MetaTableValues::default(); + for (key, value) in plist { + match key.as_str() { + "dlng" => ret.dlng = parse_meta_scriptlangtags(value).map(Into::into).collect(), + "slng" => ret.slng = parse_meta_scriptlangtags(value).map(Into::into).collect(), + other => log::warn!("unhandled meta table tag '{other}'"), + } + } + if ret.dlng.len() + ret.slng.len() > 0 { + Some(ret) + } else { + None + } +} + +fn parse_meta_scriptlangtags(plist: &plist::Value) -> impl Iterator { + plist + .as_array() + .into_iter() + .flatten() + .filter_map(|val| val.as_string()) + // although the spec[1] says that this should be an array of strs and each + // str should be a scriptlangtag, in practice[2] it seems like it often + // ends up stored as a single comma-separated list of scriptlangtag + // + // 1: https://unifiedfontobject.org/versions/ufo3/lib.plist/#publicopentypemeta + // 2: https://github.com/aaronbell/LxgwWenkaiTC/blob/fe7a4b88e91a02c097d69ba/sources/LXGWWenKaiTC-Regular.ufo/lib.plist#L1798-L1808 + .flat_map(|s| s.split(',')) + .map(str::trim) +} + fn set_default_underline_pos( metrics: &mut GlobalMetrics, location: &NormalizedLocation, @@ -2375,4 +2412,24 @@ mod tests { let expected: Panose = [2_u8, 11, 5, 2, 4, 5, 4, 2, 2, 4].into(); assert_eq!(Some(expected), static_metadata.misc.panose); } + + #[test] + fn parse_meta_table_values() { + let (_, context) = build_static_metadata("MetaTable.ufo", default_test_flags()); + let static_meta = context.static_metadata.get(); + let meta_table = static_meta.misc.meta_table.as_ref().unwrap(); + assert_eq!(meta_table.dlng, ["en-latn", "fr-latn", "nl-Latn"]); + assert_eq!(meta_table.slng, ["Latn", "Cyrl"]); + } + + #[test] + fn ignore_empty_meta_table_values() { + let mut plist = plist::Dictionary::new(); + plist.insert( + "public.openTypeMeta".into(), + plist::Value::Array(Default::default()), + ); + + assert!(super::parse_meta_table_values(&plist::Value::Dictionary(plist)).is_none()) + } }