diff --git a/crates/svg/src/export.rs b/crates/svg/src/export.rs index 45e9438d0..08f0794af 100644 --- a/crates/svg/src/export.rs +++ b/crates/svg/src/export.rs @@ -134,11 +134,12 @@ fn write(doc: &Document, opts: &ExportOptions, native: Option<&[u8]>, id_prefix: out.push_str(&format!("{nl}")); } // An artboard exported on its own is named after it (#3544), else after the document. - let board = opts.artboard.filter(|_| opts.artboard_title).and_then(|i| doc.artboards.get(i)).map(|a| a.name.as_str()); - let title = board.filter(|n| !n.trim().is_empty()).unwrap_or(&doc.title); + // A name that is blank once the characters XML can't hold are dropped falls back too. + let board = opts.artboard.filter(|_| opts.artboard_title).and_then(|i| doc.artboards.get(i)).map(|a| xml_text(&a.name)); + let title = board.filter(|n| !n.trim().is_empty()).unwrap_or_else(|| xml_text(&doc.title)); if !title.is_empty() { out.push_str(&w.indent(1)); - out.push_str(&format!("{}{nl}", xml_text(title))); + out.push_str(&format!("{title}{nl}")); } // File Info's description. if !doc.metadata.description.trim().is_empty() { diff --git a/crates/svg/tests/title_control_chars.rs b/crates/svg/tests/title_control_chars.rs index 90c3d8c34..9057d8439 100644 --- a/crates/svg/tests/title_control_chars.rs +++ b/crates/svg/tests/title_control_chars.rs @@ -51,4 +51,7 @@ fn an_artboard_exported_alone_is_titled_after_it() { // An unnamed artboard falls back to the document's title. d.artboards[1].name = " ".into(); assert_eq!(title(&d, alone(Some(1))).as_deref(), Some("Icons")); + // So does one whose only characters can't appear in XML. + d.artboards[1].name = "\u{1}\u{2}".into(); + assert_eq!(title(&d, alone(Some(1))).as_deref(), Some("Icons")); }