diff --git a/src/glyph/parse.rs b/src/glyph/parse.rs
index 90264529..42f8641c 100644
--- a/src/glyph/parse.rs
+++ b/src/glyph/parse.rs
@@ -122,6 +122,12 @@ impl<'names> GlifParser<'names> {
}
self.glyph.load_object_libs()?;
+
+ let mut seen_codepoints = HashSet::new();
+ let deduplicated_codepoints =
+ self.glyph.codepoints.iter().filter(|c| seen_codepoints.insert(**c)).cloned().collect();
+ self.glyph.codepoints = deduplicated_codepoints;
+
Ok(self.glyph)
}
diff --git a/src/glyph/serialize.rs b/src/glyph/serialize.rs
index e64de211..6e09b6ad 100644
--- a/src/glyph/serialize.rs
+++ b/src/glyph/serialize.rs
@@ -1,6 +1,9 @@
//! Writing out .glif files
-use std::io::{Cursor, Write};
+use std::{
+ collections::HashSet,
+ io::{Cursor, Write},
+};
use quick_xml::{
events::{BytesEnd, BytesStart, BytesText, Event},
@@ -59,8 +62,11 @@ impl Glyph {
start.push_attribute(("format", "2"));
writer.write_event(Event::Start(start)).map_err(GlifWriteError::Xml)?;
+ let mut seen_codepoints = HashSet::new();
for codepoint in &self.codepoints {
- writer.write_event(char_to_event(*codepoint)).map_err(GlifWriteError::Xml)?;
+ if seen_codepoints.insert(codepoint) {
+ writer.write_event(char_to_event(*codepoint)).map_err(GlifWriteError::Xml)?;
+ }
}
// Skip serializing advance if both values are zero, infinite, subnormal, or NaN.
diff --git a/src/glyph/tests.rs b/src/glyph/tests.rs
index efa23d57..e7e1b177 100644
--- a/src/glyph/tests.rs
+++ b/src/glyph/tests.rs
@@ -868,3 +868,30 @@ fn has_component_with_base() {
assert!(glyph.has_component_with_base("dieresis"));
assert!(!glyph.has_component_with_base("Z"));
}
+
+#[test]
+fn deduplicate_unicodes() {
+ let data = r#"
+
+
+
+
+
+
+
+"#;
+ let mut glyph = parse_glyph(data.as_bytes()).unwrap();
+ assert_eq!(glyph.codepoints, vec!['e', 'f', 'g']);
+
+ glyph.codepoints = vec!['e', 'f', 'e', 'g'];
+ let data2 = glyph.encode_xml().unwrap();
+ let data2 = std::str::from_utf8(&data2).unwrap();
+ let data2_expected = r#"
+
+
+
+
+
+"#;
+ assert_eq!(data2, data2_expected);
+}