Skip to content

Commit a8f9b2f

Browse files
committed
More lenient parsing of glyph points
Specifically if an off-curve point has the 'smooth' attribute set, we will now log a warning instead of returning an error.
1 parent 7145ef5 commit a8f9b2f

4 files changed

Lines changed: 31 additions & 10 deletions

File tree

src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,8 @@ pub enum ErrorKind {
536536
/// Has an unexpected move definition.
537537
UnexpectedMove,
538538
/// Has an unexpected smooth definition.
539+
//TODO: no longer used, can be removed next non-patch release
540+
#[deprecated(since = "0.18.2", note = "unused, will be removed")]
539541
UnexpectedSmooth,
540542
/// Has an unexpected element definition.
541543
UnexpectedElement,
@@ -606,6 +608,7 @@ impl std::fmt::Display for ErrorKind {
606608
UnexpectedMove => {
607609
write!(f, "unexpected move point, can only occur at start of contour")
608610
}
611+
#[allow(deprecated)]
609612
UnexpectedSmooth => write!(f, "unexpected smooth attribute on an off-curve point"),
610613
UnexpectedElement => write!(f, "unexpected element"),
611614
UnexpectedAttribute => write!(f, "unexpected attribute"),

src/glyph/builder.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ impl OutlineBuilder {
6565
///
6666
/// Errors when:
6767
/// 1. [`Self::begin_path`] wasn't called first.
68-
/// 2. the point is an off-curve with the smooth attribute set.
69-
/// 3. the point sequence is forbidden by the specification.
68+
/// 2. the point sequence is forbidden by the specification.
69+
///
70+
/// If an off-curve point has the smooth attribute set, it is logged and ignored.
7071
///
7172
/// On error, it won't add any part of the point, but you can try again with a new
7273
/// and improved point.
@@ -93,9 +94,6 @@ impl OutlineBuilder {
9394
}
9495
}
9596
PointType::OffCurve => {
96-
if smooth {
97-
return Err(ErrorKind::UnexpectedSmooth);
98-
}
9997
*number_of_offcurves = number_of_offcurves.saturating_add(1);
10098
}
10199
PointType::QCurve => *number_of_offcurves = 0,

src/glyph/parse.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub(crate) struct GlifParser<'names> {
3030
glyph: Glyph,
3131
version: Version,
3232
seen_identifiers: HashSet<Identifier>,
33+
has_warned_for_smooth_point: bool,
3334
/// Optional set of glyph names to be reused between glyphs.
3435
names: Option<&'names NameList>,
3536
}
@@ -47,7 +48,13 @@ impl<'names> GlifParser<'names> {
4748

4849
let (name, version) = start(&mut reader, &mut buf, names)?;
4950
let glyph = Glyph::new_impl(name);
50-
let parser = GlifParser { glyph, seen_identifiers: Default::default(), names, version };
51+
let parser = GlifParser {
52+
glyph,
53+
seen_identifiers: Default::default(),
54+
names,
55+
version,
56+
has_warned_for_smooth_point: false,
57+
};
5158
parser.parse_body(&mut reader, xml, &mut buf)
5259
}
5360

@@ -325,7 +332,7 @@ impl<'names> GlifParser<'names> {
325332
// Instead of failing to parse these files, we prefer to just skip the dicts.
326333
self.glyph.lib = dict;
327334
}
328-
Err(e) => log::info!("glyph {} contains invalid lib: '{e}'", self.glyph.name),
335+
Err(e) => log::info!("glyph '{}' {e}", self.glyph.name),
329336
}
330337

331338
Ok(())
@@ -386,6 +393,16 @@ impl<'names> GlifParser<'names> {
386393

387394
match (x, y) {
388395
(Some(x), Some(y)) => {
396+
if typ == PointType::OffCurve && smooth {
397+
if !self.has_warned_for_smooth_point {
398+
log::info!(
399+
"glyph '{}' has off-curve point with 'smooth' attribute set",
400+
self.glyph.name
401+
);
402+
}
403+
self.has_warned_for_smooth_point = true;
404+
smooth = false;
405+
}
389406
outline_builder.add_point((x, y), typ, smooth, name, identifier)?;
390407
Ok(())
391408
}

src/glyph/tests.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,9 @@ fn unexpected_move() {
454454
}
455455

456456
#[test]
457-
#[should_panic(expected = "UnexpectedSmooth")]
458-
fn unexpected_smooth() {
457+
fn offcurve_smooth_is_ignored() {
458+
// smooth="yes" on an off-curve point is invalid per the spec but we log and ignore it
459+
// rather than returning an error.
459460
let data = r#"
460461
<?xml version="1.0" encoding="UTF-8"?>
461462
<glyph name="period" format="2">
@@ -468,7 +469,9 @@ fn unexpected_smooth() {
468469
</outline>
469470
</glyph>
470471
"#;
471-
let _ = parse_glyph(data.as_bytes()).unwrap();
472+
let glyph = parse_glyph(data.as_bytes()).unwrap();
473+
let contour = &glyph.contours[0];
474+
assert!(!contour.points[0].smooth);
472475
}
473476

474477
#[test]

0 commit comments

Comments
 (0)