diff --git a/fontbe/src/os2.rs b/fontbe/src/os2.rs index be53ed984..30753b10c 100644 --- a/fontbe/src/os2.rs +++ b/fontbe/src/os2.rs @@ -824,6 +824,7 @@ impl Work<Context, AnyWorkId, Error> for Os2Work { let codepoints = codepoints(context); let mut os2 = Os2 { + fs_type: static_metadata.misc.fs_type.unwrap_or_default(), ach_vend_id: static_metadata.misc.vendor_id, fs_selection: static_metadata.misc.selection_flags, x_avg_char_width: x_avg_char_width(context)?, diff --git a/fontc/src/lib.rs b/fontc/src/lib.rs index dcc4b6eb9..8a5eeb282 100644 --- a/fontc/src/lib.rs +++ b/fontc/src/lib.rs @@ -2432,4 +2432,27 @@ mod tests { fn compile_obeys_no_export_designspace() { assert_noexport("designspace_from_glyphs/WghtVar_NoExport.designspace"); } + + fn assert_fs_type(source: &str, expected_fs_type: u16) { + let temp_dir = tempdir().unwrap(); + let build_dir = temp_dir.path(); + compile(Args::for_test(build_dir, source)); + + let font_file = build_dir.join("font.ttf"); + let buf = fs::read(font_file).unwrap(); + let font = FontRef::new(&buf).unwrap(); + let os2 = font.os2().unwrap(); + + assert_eq!(expected_fs_type, os2.fs_type()); + } + + #[test] + fn default_fs_type_glyphs() { + assert_fs_type("glyphs3/WghtVar.glyphs", 1 << 3); + } + + #[test] + fn default_fs_type_designspace() { + assert_fs_type("designspace_from_glyphs/WghtVar.designspace", 1 << 2); + } } diff --git a/fontir/src/ir.rs b/fontir/src/ir.rs index 256f99a2f..014adae4e 100644 --- a/fontir/src/ir.rs +++ b/fontir/src/ir.rs @@ -82,6 +82,9 @@ pub struct StaticMetadata { #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(from = "MiscSerdeRepr", into = "MiscSerdeRepr")] pub struct MiscMetadata { + /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fstype> + pub fs_type: Option<u16>, + /// See <https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fsselection> pub selection_flags: SelectionFlags, @@ -285,6 +288,7 @@ impl StaticMetadata { default_location, postscript_names, misc: MiscMetadata { + fs_type: None, // default is, sigh, inconsistent across source formats selection_flags: Default::default(), vendor_id: DEFAULT_VENDOR_ID_TAG, underline_thickness: 0.0.into(), @@ -1566,6 +1570,7 @@ mod tests { ]), postscript_names: HashMap::from([("lhs".into(), "rhs".into())]), misc: MiscMetadata { + fs_type: None, selection_flags: SelectionFlags::default(), vendor_id: Tag::from_be_bytes(*b"DUCK"), underline_thickness: 0.15.into(), diff --git a/fontir/src/serde.rs b/fontir/src/serde.rs index 428c16378..2f781f0a7 100644 --- a/fontir/src/serde.rs +++ b/fontir/src/serde.rs @@ -161,6 +161,7 @@ impl From<KerningSerdeRepr> for Kerning { #[derive(Serialize, Deserialize, Debug, Clone)] pub(crate) struct MiscSerdeRepr { + pub fs_type: Option<u16>, pub selection_flags: u16, pub vendor_id: Tag, pub underline_thickness: f32, @@ -175,6 +176,7 @@ pub(crate) struct MiscSerdeRepr { impl From<MiscSerdeRepr> for MiscMetadata { fn from(from: MiscSerdeRepr) -> Self { MiscMetadata { + fs_type: from.fs_type, selection_flags: SelectionFlags::from_bits_truncate(from.selection_flags), vendor_id: from.vendor_id, underline_thickness: from.underline_thickness.into(), @@ -191,6 +193,7 @@ impl From<MiscSerdeRepr> for MiscMetadata { impl From<MiscMetadata> for MiscSerdeRepr { fn from(from: MiscMetadata) -> Self { MiscSerdeRepr { + fs_type: from.fs_type, selection_flags: from.selection_flags.bits(), vendor_id: from.vendor_id, underline_thickness: from.underline_thickness.into(), diff --git a/glyphs2fontir/src/source.rs b/glyphs2fontir/src/source.rs index 5a33c441b..6753bb68e 100644 --- a/glyphs2fontir/src/source.rs +++ b/glyphs2fontir/src/source.rs @@ -358,6 +358,10 @@ impl Work<Context, WorkId, WorkError> for StaticMetadataWork { static_metadata.misc.vendor_id = Tag::from_str(vendor_id).map_err(WorkError::InvalidTag)?; } + + // <https://github.com/googlefonts/glyphsLib/blob/cb8a4a914b0a33431f0a77f474bf57eec2f19bcc/Lib/glyphsLib/builder/custom_params.py#L1117-L1119> + static_metadata.misc.fs_type = Some(1 << 3); + // <https://github.com/googlefonts/glyphsLib/blob/main/Lib/glyphsLib/builder/custom_params.py#L1116-L1125> static_metadata.misc.underline_thickness = 50.0.into(); static_metadata.misc.underline_position = (-100.0).into(); diff --git a/ufo2fontir/src/source.rs b/ufo2fontir/src/source.rs index ad247caf3..0c298d618 100644 --- a/ufo2fontir/src/source.rs +++ b/ufo2fontir/src/source.rs @@ -839,6 +839,9 @@ impl Work<Context, WorkId, WorkError> for StaticMetadataWork { Tag::from_str(vendor_id).map_err(WorkError::InvalidTag)?; } + // <https://github.com/googlefonts/glyphsLib/blob/cb8a4a914b0a33431f0a77f474bf57eec2f19bcc/Lib/glyphsLib/builder/custom_params.py#L1117-L1119> + static_metadata.misc.fs_type = Some(1 << 2); + // <https://github.com/googlefonts/ufo2ft/blob/main/Lib/ufo2ft/fontInfoData.py#L313-L322> static_metadata.misc.underline_thickness = font_info_at_default .postscript_underline_thickness