Skip to content

Commit

Permalink
[glyphs] Handle additional custom params
Browse files Browse the repository at this point in the history
Specifically openTypeHeadLowestRecPPEM, and the various hhea & vhea
caret properties.

(vhea isn't handled yet, but we can at least parse it now in preparation)
  • Loading branch information
cmyr committed Nov 26, 2024
1 parent 23146c9 commit 298ae0d
Show file tree
Hide file tree
Showing 3 changed files with 252 additions and 2 deletions.
54 changes: 52 additions & 2 deletions glyphs-reader/src/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ pub struct CustomParameters {
pub codepage_range_bits: Option<BTreeSet<u32>>,
pub panose: Option<Vec<i64>>,

pub lowest_rec_ppem: Option<i64>,
pub hhea_caret_slope_run: Option<i64>,
pub hhea_caret_slope_rise: Option<i64>,
pub hhea_caret_offset: Option<i64>,
pub vhea_caret_slope_run: Option<i64>,
pub vhea_caret_slope_rise: Option<i64>,
pub vhea_caret_offset: Option<i64>,
// these fields are parsed via the config, but are stored
// in the top-level `Font` struct
pub virtual_masters: Option<Vec<BTreeMap<String, OrderedFloat<f64>>>>,
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -570,14 +585,48 @@ 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:?}'"),
},
"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);
Expand Down Expand Up @@ -2266,6 +2315,7 @@ impl TryFrom<RawFont> 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
Expand Down
21 changes: 21 additions & 0 deletions glyphs2fontir/src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,9 @@ impl Work<Context, WorkId, Error> 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
Expand Down Expand Up @@ -607,6 +610,9 @@ impl Work<Context, WorkId, Error> 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 <https://github.com/googlefonts/glyphsLib/blob/9d5828d874110c42dfc5f542db8eb84f88641eb5/Lib/glyphsLib/builder/custom_params.py#L1136-L1156>
set_metric!(UnderlineThickness, underline_thickness, 50.0);
// -100.0 is the Glyphs default <https://github.com/googlefonts/glyphsLib/blob/9d5828d874110c42dfc5f542db8eb84f88641eb5/Lib/glyphsLib/builder/custom_params.py#L1136-L1156>
Expand Down Expand Up @@ -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.);
}
}
179 changes: 179 additions & 0 deletions resources/testdata/glyphs3/UnusualCustomParams.glyphs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
{
.appVersion = "3260";
.formatVersion = 3;
DisplayStrings = (
""
);
customParameters = (
{
name = openTypeHeadFlags;
value = (
0
);
},
{
name = openTypeHeadLowestRecPPEM;
value = 7;
},
{
name = openTypeHheaCaretOffset;
value = 2;
},
{
name = openTypeHheaCaretSlopeRise;
value = 1;
},
{
name = openTypeHheaCaretSlopeRun;
value = 5;
},
);
date = "2022-04-17 11:15:57 +0000";
familyName = UnusualParams;
fontMaster = (
{
customParameters = (
);
id = master01;
metricValues = (
{
pos = 800;
},
{
pos = 700;
},
{
pos = 500;
},
{
},
{
pos = -200;
},
{
}
);
name = Regular;
}
);
glyphs = (
{
glyphname = space;
layers = (
{
layerId = master01;
width = 600;
}
);
unicode = 32;
}
);
instances = (
{
instanceInterpolations = {
master01 = 1;
};
name = Regular;
properties = (
{
key = postscriptFontName;
value = "NotoFangsongKSSRotated-Regular";
}
);
}
);
metrics = (
{
type = ascender;
},
{
type = "cap height";
},
{
type = "x-height";
},
{
type = baseline;
},
{
type = descender;
},
{
type = "italic angle";
}
);
properties = (
{
key = copyrights;
values = (
{
language = dflt;
value = "Copyright 2022 Google LLC. All Rights Reserved.";
}
);
},
{
key = designers;
values = (
{
language = dflt;
value = me;
}
);
},
{
key = familyNames;
values = (
{
language = dflt;
value = "";
}
);
},
{
key = licenses;
values = (
{
language = dflt;
value = "This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: https://scripts.sil.org/OFL";
}
);
},
{
key = manufacturers;
values = (
{
language = dflt;
value = myself;
}
);
},
{
key = sampleTexts;
values = (
{
language = dflt;
value = "";
}
);
},
{
key = trademarks;
values = (
{
language = dflt;
value = "";
}
);
}
);
settings = {
disablesNiceNames = 1;
};
unitsPerEm = 1000;
userData = {
UFOFormat = 3;
};
versionMajor = 1;
versionMinor = 0;
}

0 comments on commit 298ae0d

Please sign in to comment.