diff --git a/crates/xlsx/src/drawing.rs b/crates/xlsx/src/drawing.rs index 8cd1d353c..ebda1e8f3 100644 --- a/crates/xlsx/src/drawing.rs +++ b/crates/xlsx/src/drawing.rs @@ -221,8 +221,9 @@ fn read_shape(obj: &El, anchor: Anchor) -> Option { 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(""); } s.push_str(""); - 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\"", diff --git a/crates/xlsx/src/tests/shape_text_rtl.rs b/crates/xlsx/src/tests/shape_text_rtl.rs index 0b9e5b10b..0ec5944bb 100644 --- a/crates/xlsx/src/tests/shape_text_rtl.rs +++ b/crates/xlsx/src/tests/shape_text_rtl.rs @@ -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#""#, "") + .replace(r#"prst="rect""#, r#"prst="ellipse""#) + .replace(r#"anchor="t"/>"#, r#"anchor="t">"#); + 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); +}