Pptx: a table naming no style reads as the table grid style

A table whose tblPr names no tableStyleId drew without any lines.
PowerPoint draws such a table with thin dark grid lines (as its "No Style,
Table Grid"); observed on a synthetic deck with and without the explicit
"No Style, No Grid" GUID. Such tables now read as the grid style.

Wild synthetic set: tables with cell margins/fills/styles 4.80 -> 2.82,
11.28 -> 10.15, 6.86 -> 3.16.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas 2026-10-13 06:39:06 -04:00
parent bf877411fb
commit 754841aaa4
2 changed files with 36 additions and 1 deletions

View File

@ -436,7 +436,9 @@ fn smartart(imp: &mut Imp, part: &Part, gd: &El, frame: &Shape, depth: usize) ->
}
fn table(imp: &mut Imp, part: &Part, tbl: &El) -> Table {
let mut t = Table { style: "none".into(), first_row: false, band_row: false, ..Default::default() };
// A table naming no style is drawn by PowerPoint with thin dark grid lines ("No Style, Table
// Grid"), not without lines.
let mut t = Table { style: "grid".into(), first_row: false, band_row: false, ..Default::default() };
if let Some(pr) = tbl.child("tblPr") {
t.background = pr.elements().find(|e| e.local().ends_with("Fill") && e.local() != "noFill").and_then(|f| dml::fill_el(imp, part, f));
t.first_row = pr.bool("firstRow").unwrap_or(false);

View File

@ -170,3 +170,36 @@ fn a_gradient_tile_rect_is_read_and_round_trips() {
let s = q.slides[0].shapes.iter().find(|s| s.name == "Corner").expect("shape");
assert!(matches!(&s.fill, Some(Fill::Gradient(g)) if g.tile == [-1.0, -1.0, 0.0, 0.0]), "{:?}", s.fill);
}
#[test]
fn a_table_naming_no_style_is_drawn_with_the_table_grid() {
let mut p = defaults::new_presentation(None);
let id = ShapeId(p.alloc_id());
let first = p.slides[0].id;
let mut t = deckcraft_model::Table::new(2, 2, 200.0, 40.0);
t.style = "none".into();
p.slide_mut(first).expect("slide").shapes.push(Shape {
id,
name: "Grid".into(),
xfrm: Some(Xfrm::new(10.0, 10.0, 200.0, 80.0)),
kind: deckcraft_model::ShapeKind::Table(t),
..Default::default()
});
let bytes = deckcraft_pptx::export(&p).expect("export");
let style = |bytes: &[u8]| {
let q = deckcraft_pptx::import(bytes).expect("import");
let s = q.slides[0].shapes.iter().find(|s| s.name == "Grid").expect("shape").clone();
match s.kind {
deckcraft_model::ShapeKind::Table(t) => t.style,
other => panic!("{other:?}"),
}
};
// Written with its style, it reads back as written.
assert_eq!(style(&bytes), "none");
// Without a:tableStyleId PowerPoint draws thin dark grid lines.
let bare = edit_slides(&bytes, |x| {
let (Some(a), Some(b)) = (x.find("<a:tableStyleId>"), x.find("</a:tableStyleId>")) else { return x };
format!("{}{}", &x[..a], &x[b + "</a:tableStyleId>".len()..])
});
assert_eq!(style(&bare), "grid");
}