diff --git a/crates/layout/src/table.rs b/crates/layout/src/table.rs index d31967af2..1a1f5e5b9 100644 --- a/crates/layout/src/table.rs +++ b/crates/layout/src/table.rs @@ -1144,8 +1144,10 @@ fn column_content(ctx: &mut Ctx, t: &Table, style: Option<&TableStyleProps>, dep } spanning.extend(row_gaps(row, g).map(|(g, span, w)| (g, span, (w, w)))); } + // The grid's width once: counting it walks every row, and there can be a spanning cell in each. + let ncols = t.cols(); for (g, span, need) in spanning { - let Some(cs) = cols.get_mut(g..(g + span).min(t.cols())) else { continue }; + let Some(cs) = cols.get_mut(g..g.saturating_add(span).min(ncols)) else { continue }; let n = cs.len().max(1) as f32; let (have_lo, have_hi) = cs.iter().fold((0.0, 0.0), |(l, h), c| (l + c.0, h + c.1)); for c in cs { diff --git a/crates/layout/src/tests_linear.rs b/crates/layout/src/tests_linear.rs index fa26b2200..58542956e 100644 --- a/crates/layout/src/tests_linear.rs +++ b/crates/layout/src/tests_linear.rs @@ -92,3 +92,21 @@ fn line_carets_match_x_of() { } } +/// Finding 3: autofitting a table counted its grid's columns again for every spanning cell. +#[test] +fn autofit_tables_with_a_spanning_cell_in_every_row_lay_out_in_linear_time() { + let doc = |n: usize| { + let mut t = Table::new(n, 3, 468.0); + for row in &mut t.rows { + row.cells.truncate(2); + if let Some(c) = row.cells.first_mut() { + c.props.span = 2; + } + } + let mut d = Document::from_text("x"); + d.insert_block(StoryRef::Body, &Path::top(0), Block::Table(t)).unwrap(); + d + }; + assert_linear("spanning cells", layout_time_ratio(doc, 400, &LayoutOptions::default())); +} +