From 249d5fe515ddb864582ec711106461c0e03ffe77 Mon Sep 17 00:00:00 2001 From: jdierkes Date: Wed, 26 Apr 2023 11:22:35 +0200 Subject: [PATCH] Fix grid-cell misalignment bug (#963) (#978) Having a table span multiple pages can cause an alignment bug in the table itself. If the first region in a cell in a grid row is empty, all other cells in this row will skip the first region. A misalignment bug can occur, since the calculation of all region sizes happen before the skip. The overall size allocated for the content of a cell with multiple regions and content in the first region thus is too little. Fixes #963 --- library/src/layout/grid.rs | 81 ++++++++++++++++++++++--------------- tests/ref/bugs/grid-2.png | Bin 10830 -> 12871 bytes tests/typ/bugs/grid-2.typ | 4 +- 3 files changed, 52 insertions(+), 33 deletions(-) diff --git a/library/src/layout/grid.rs b/library/src/layout/grid.rs index 63183e1df..acfee8a27 100644 --- a/library/src/layout/grid.rs +++ b/library/src/layout/grid.rs @@ -450,33 +450,15 @@ impl<'a, 'v> GridLayouter<'a, 'v> { /// Layout a row with automatic height. Such a row may break across multiple /// regions. fn layout_auto_row(&mut self, y: usize) -> SourceResult<()> { - let mut resolved: Vec = vec![]; - let mut skip = false; - - // Determine the size for each region of the row. - for (x, &rcol) in self.rcols.iter().enumerate() { - if let Some(cell) = self.cell(x, y) { - let mut pod = self.regions; - pod.size.x = rcol; - - let frames = cell.measure(self.vt, self.styles, pod)?.into_frames(); - if let [first, rest @ ..] = frames.as_slice() { - skip |= - first.is_empty() && rest.iter().any(|frame| !frame.is_empty()); - } - - // For each region, we want to know the maximum height any - // column requires. - let mut sizes = frames.iter().map(|frame| frame.height()); - for (target, size) in resolved.iter_mut().zip(&mut sizes) { - target.set_max(size); - } - - // New heights are maximal by virtue of being new. Note that - // this extend only uses the rest of the sizes iterator. - resolved.extend(sizes); + // Determine the size for each region of the row. If the first region + // ends up empty for some column, skip the region and remeasure. + let mut resolved = match self.measure_auto_row(y, true)? { + Some(resolved) => resolved, + None => { + self.finish_region()?; + self.measure_auto_row(y, false)?.unwrap() } - } + }; // Nothing to layout. if resolved.is_empty() { @@ -490,12 +472,6 @@ impl<'a, 'v> GridLayouter<'a, 'v> { return Ok(()); } - // Skip the first region if it's empty for some cell. - if skip && !self.regions.in_last() { - self.finish_region()?; - resolved.remove(0); - } - // Expand all but the last region. // Skip the first region if the space is eaten up by an fr row. let len = resolved.len(); @@ -521,6 +497,47 @@ impl<'a, 'v> GridLayouter<'a, 'v> { Ok(()) } + /// Measure the regions sizes of an auto row. The option is always `Some(_)` + /// if `can_skip` is false. + fn measure_auto_row( + &mut self, + y: usize, + can_skip: bool, + ) -> SourceResult>> { + let mut resolved: Vec = vec![]; + + for (x, &rcol) in self.rcols.iter().enumerate() { + if let Some(cell) = self.cell(x, y) { + let mut pod = self.regions; + pod.size.x = rcol; + + let frames = cell.measure(self.vt, self.styles, pod)?.into_frames(); + + // Skip the first region if one cell in it is empty. Then, + // remeasure. + if let [first, rest @ ..] = frames.as_slice() { + if can_skip + && first.is_empty() + && rest.iter().any(|frame| !frame.is_empty()) + { + return Ok(None); + } + } + + let mut sizes = frames.iter().map(|frame| frame.height()); + for (target, size) in resolved.iter_mut().zip(&mut sizes) { + target.set_max(size); + } + + // New heights are maximal by virtue of being new. Note that + // this extend only uses the rest of the sizes iterator. + resolved.extend(sizes); + } + } + + Ok(Some(resolved)) + } + /// Layout a row with relative height. Such a row cannot break across /// multiple regions, but it may force a region break. fn layout_relative_row(&mut self, v: Rel, y: usize) -> SourceResult<()> { diff --git a/tests/ref/bugs/grid-2.png b/tests/ref/bugs/grid-2.png index ec2bd660dff683872c2d0de093083c28d56f67b7..571604134ee9fd2bb994357ef44005b9b1793c5b 100644 GIT binary patch literal 12871 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 b-Tk;sWqV@WF7XKeq9#RIRhhEqh>!mRlPM2u literal 10830 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

<~A3S*Ai-0y} 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