fix(docx): inspect textbox style for v-text-anchor and handle case-insensitivity

This commit is contained in:
Divyanshu Gupta
2026-10-16 03:05:52 +05:30
parent 86adfd34eb
commit 8711f5cfd1
2 changed files with 36 additions and 6 deletions
+10 -6
View File
@@ -1437,14 +1437,18 @@ impl Reader<'_> {
}
part.body.inset = (inset != wordcraft_doc::TEXT_BOX_INSET).then_some(inset);
// Resize shape to fit text (DrawingML's `a:spAutoFit`).
let fit = vml_style(tb.attr("style").unwrap_or(""), "mso-fit-shape-to-text");
let fit = vml_style(tb.attr("style").unwrap_or(""), "mso-fit-shape-to-text")
.or_else(|| vml_style(style, "mso-fit-shape-to-text"));
part.body.auto_fit = fit.is_some_and(|v| v.eq_ignore_ascii_case("t") || v.eq_ignore_ascii_case("true"));
// Where the text sits between the box's top and bottom (DrawingML's `anchor`).
if let Some(a) = vml_style(style, "v-text-anchor") {
part.body.anchor = match a {
a if a.starts_with("middle") => wordcraft_doc::props::VAlign::Center,
a if a.starts_with("bottom") => wordcraft_doc::props::VAlign::Bottom,
_ => wordcraft_doc::props::VAlign::Top,
if let Some(a) = vml_style(tb.attr("style").unwrap_or(""), "v-text-anchor").or_else(|| vml_style(style, "v-text-anchor")) {
let al = a.trim().to_ascii_lowercase();
part.body.anchor = if al.starts_with("middle") || al == "center" {
wordcraft_doc::props::VAlign::Center
} else if al.starts_with("bottom") {
wordcraft_doc::props::VAlign::Bottom
} else {
wordcraft_doc::props::VAlign::Top
};
}
}
+26
View File
@@ -2830,3 +2830,29 @@ fn row_table_borders_round_trip() {
let again = wordcraft_docx::read(&saved).unwrap();
assert_eq!(d.body, again.body);
}
#[test]
fn vml_textbox_style_anchor_and_fit() {
let body = r#"<w:p>
<w:r>
<w:pict>
<v:rect style="width:100pt;height:50pt">
<v:textbox style="v-text-anchor:Middle;mso-fit-shape-to-text:True">
<w:txbxContent>
<w:p><w:r><w:t>Centered text</w:t></w:r></w:p>
</w:txbxContent>
</v:textbox>
</v:rect>
</w:pict>
</w:r>
</w:p>"#;
let doc = wordcraft_docx::read(&docx(body, &[], &[])).unwrap();
let p = doc.body.first().unwrap().as_para().unwrap();
let story_id = match p.objects.first() {
Some(InlineObject::Shape { story: Some(id), .. }) => *id,
o => panic!("expected shape with story, got {o:?}"),
};
let tb = doc.parts.get(&story_id).unwrap();
assert_eq!(tb.body.anchor, wordcraft_doc::props::VAlign::Center);
assert!(tb.body.auto_fit);
}