WordArt xlsx: only the textNoShape marker reads as WordArt, an empty WordArt keeps its body

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
vangel76
2026-11-05 04:25:50 +01:00
co-authored by Claude Sonnet 5.5
parent 6a22a3b357
commit 2a9a21d41c
2 changed files with 26 additions and 3 deletions
+5 -3
View File
@@ -221,8 +221,9 @@ fn read_shape(obj: &El, anchor: Anchor) -> Option<Shape> {
let tx_box = obj.path(&["nvSpPr", "cNvSpPr"]).is_some_and(|c| c.flag("txBox", false));
let ln = sp.child("ln");
let arrow = ln.is_some_and(|l| l.child("tailEnd").or_else(|| l.child("headEnd")).is_some_and(|t| t.attr("type").is_some_and(|v| v != "none")));
// WordArt: a text body carrying a text warp (`a:bodyPr/a:prstTxWarp`).
let word_art = obj.path(&["txBody", "bodyPr", "prstTxWarp"]).is_some();
// WordArt: our marker, a text body with the non-warping text warp `textNoShape`. Any other warp
// (Excel puts one on ordinary filled shapes too) leaves the shape what its geometry says.
let word_art = obj.path(&["txBody", "bodyPr", "prstTxWarp"]).is_some_and(|w| w.attr("prst") == Some("textNoShape"));
let kind = match prst {
_ if word_art => ShapeKind::WordArt,
_ if tx_box => ShapeKind::TextBox,
@@ -554,7 +555,8 @@ pub fn write_drawing(sheet: &Sheet, theme: &Theme, objs: &[Obj<'_>]) -> String {
s.push_str("</a:ln>");
}
s.push_str("</xdr:spPr>");
if !sh.text.is_empty() {
// A WordArt with no text still writes its body, which carries the WordArt marker.
if !sh.text.is_empty() || sh.kind == ShapeKind::WordArt {
let f = &sh.format;
let anchor = match f.anchor {
Some(ShapeTextAnchor::Top) => " anchor=\"t\"",
+21
View File
@@ -100,3 +100,24 @@ fn word_art_keeps_right_to_left_paragraphs() {
assert_eq!(shape.format.align, Some(ShapeTextAlign::Right));
assert_eq!(shape.text, "مرحبا\nبالعالم");
}
#[test]
fn word_art_with_empty_text_keeps_its_kind() {
let mut wb = text_box("", ShapeFormat::default());
wb.sheet_mut(0).unwrap().shapes[0].kind = ShapeKind::WordArt;
let (reopened, _) = read_xlsx(&write_xlsx(&wb).unwrap()).unwrap();
assert_eq!(reopened.sheet(0).unwrap().shapes[0].kind, ShapeKind::WordArt);
}
#[test]
fn a_text_warp_on_a_filled_ellipse_does_not_make_it_word_art() {
let drawing = ARABIC_TEXT_BOX
.replace(r#"<xdr:cNvSpPr txBox="1"/>"#, "<xdr:cNvSpPr/>")
.replace(r#"prst="rect""#, r#"prst="ellipse""#)
.replace(r#"anchor="t"/>"#, r#"anchor="t"><a:prstTxWarp prst="textTriangle"><a:avLst/></a:prstTxWarp></a:bodyPr>"#);
let wb = read_drawing(&drawing);
assert_eq!(wb.sheet(0).unwrap().shapes[0].kind, ShapeKind::Ellipse);
// The marker the writer uses still reads back as WordArt.
let marked = drawing.replace("textTriangle", "textNoShape");
assert_eq!(read_drawing(&marked).sheet(0).unwrap().shapes[0].kind, ShapeKind::WordArt);
}