diff --git a/src/fontinfo.rs b/src/fontinfo.rs
index e39a4fa4..2377ec49 100644
--- a/src/fontinfo.rs
+++ b/src/fontinfo.rs
@@ -1724,6 +1724,16 @@ mod tests {
assert_eq!(font_info.open_type_os2_vendor_id, Some("LTTR".into()));
}
+ #[test]
+ fn fontinfo_empty_guideline_name() {
+ let path = "testdata/fontinfo_empty_guideline_name.plist";
+ let font_info: FontInfo = plist::from_file(path).expect("failed to load fontinfo");
+ let guidelines = font_info.guidelines.expect("guidelines should be present");
+ assert_eq!(guidelines.len(), 2);
+ assert_eq!(guidelines[0].name, None);
+ assert_eq!(guidelines[1].name, Some(Name::new_raw("ascender")));
+ }
+
#[test]
fn fontinfo2() {
let path = "testdata/fontinfotest.ufo/fontinfo.plist";
diff --git a/src/glyph/parse.rs b/src/glyph/parse.rs
index a4e51879..54afc24c 100644
--- a/src/glyph/parse.rs
+++ b/src/glyph/parse.rs
@@ -504,6 +504,9 @@ impl GlifParser {
}
angle = Some(angle_value);
}
+ // The name is optional, and some real-world fonts write it as
+ // an explicit empty string; treat that as no name.
+ b"name" if value.is_empty() => (),
b"name" => name = Some(Name::new(&value).map_err(|_| ErrorKind::InvalidName)?),
b"color" => color = Some(value.parse().map_err(|_| ErrorKind::BadColor)?),
b"identifier" => {
diff --git a/src/glyph/tests.rs b/src/glyph/tests.rs
index 73e2c750..71f7da15 100644
--- a/src/glyph/tests.rs
+++ b/src/glyph/tests.rs
@@ -253,6 +253,19 @@ fn guidelines() {
assert_eq!(glyph.width, 364.);
}
+#[test]
+fn empty_guideline_name() {
+ let data = r#"
+
+
+
+
+"#;
+ let glyph = parse_glyph(data.as_bytes()).unwrap();
+ assert_eq!(glyph.guidelines.len(), 1);
+ assert_eq!(glyph.guidelines[0].name, None);
+}
+
#[test]
#[should_panic(expected = "MissingClose")]
fn missing_close() {
diff --git a/src/guideline.rs b/src/guideline.rs
index 41ba50e0..b5dadec5 100644
--- a/src/guideline.rs
+++ b/src/guideline.rs
@@ -94,11 +94,24 @@ struct RawGuideline {
x: Option,
y: Option,
angle: Option,
+ #[serde(default, deserialize_with = "deserialize_optional_name")]
name: Option,
color: Option,
identifier: Option,
}
+// The name is optional, and some real-world fonts write it as an explicit
+// empty string; treat that as no name instead of failing the load.
+fn deserialize_optional_name<'de, D>(deserializer: D) -> Result