work
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 14 Jan 2025 17:59:09 +0000 (09:59 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 14 Jan 2025 17:59:09 +0000 (09:59 -0800)
rust/pspp/src/output/render.rs

index 6a8752cde33f0644e660766552bf105f245d97d9..5057a6bb364fbcf9ec0ed8491c266cb7f3f767af 100644 (file)
@@ -334,7 +334,7 @@ impl Page {
 
         // Calculate minimum and maximum widths of cells that do not span
         // multiple columns.
-        let mut columns = [vec![0; n.x()], vec![0; n.x()]];
+        let mut unspanned_columns = [vec![0; n.x()], vec![0; n.x()]];
         for cell in table.cells().filter(|cell| cell.col_span() == 1) {
             let mut w = device.measure_cell_width(cell.inner());
             if device.params().px_size.is_some() {
@@ -356,22 +356,14 @@ impl Page {
 
             let x = cell.coord[X];
             for i in 0..2 {
-                if columns[i][x] < w[i] {
-                    columns[i][x] = w[i];
+                if unspanned_columns[i][x] < w[i] {
+                    unspanned_columns[i][x] = w[i];
                 }
             }
         }
 
         // Distribute widths of spanned columns.
-        let mut columns = columns.map(|widths| {
-            widths
-                .into_iter()
-                .map(|width| Row {
-                    unspanned: width,
-                    width,
-                })
-                .collect::<Vec<_>>()
-        });
+        let mut columns = unspanned_columns.clone();
         for cell in table.cells().filter(|cell| cell.col_span() > 1) {
             let rect = cell.rect();
 
@@ -379,6 +371,7 @@ impl Page {
             for i in 0..2 {
                 distribute_spanned_width(
                     w[i],
+                    &unspanned_columns[i][rect[X].clone()],
                     &mut columns[i][rect[X].clone()],
                     &rules[X][rect[X].start..rect[X].end + 1],
                 );
@@ -386,7 +379,12 @@ impl Page {
         }
         if min_width > 0 {
             for i in 0..2 {
-                distribute_spanned_width(min_width, columns[i].as_mut_slice(), &rules[X]);
+                distribute_spanned_width(
+                    min_width,
+                    &unspanned_columns[i],
+                    &mut columns[i],
+                    &rules[X],
+                );
             }
         }
 
@@ -394,8 +392,8 @@ impl Page {
         // to exceed the maximum width.  This bollixes our interpolation
         // algorithm later, so fix it up.
         for i in 0..n.x() {
-            if columns[0][i].width > columns[1][i].width {
-                columns[1][i].width = columns[0][i].width;
+            if columns[0][i] > columns[1][i] {
+                columns[1][i] = columns[0][i];
             }
         }
 
@@ -403,7 +401,7 @@ impl Page {
         let rule_widths = rules[X].iter().copied().sum::<usize>();
         let table_widths = columns
             .iter()
-            .map(|row| row.iter().map(|row| row.width).sum::<usize>() + rule_widths)
+            .map(|row| row.iter().sum::<usize>() + rule_widths)
             .collect::<SmallVec<[usize; 2]>>();
 
         let cp_x = if table_widths[1] <= device.params().size[X] {
@@ -413,7 +411,6 @@ impl Page {
             // Fits with minimum widths, so distribute the leftover space.
             //Self::new_with_interpolated_widths()
             Self::interpolate_row_widths(
-                &table,
                 device.params(),
                 &columns[0],
                 &columns[1],
@@ -428,27 +425,28 @@ impl Page {
         };
 
         // Calculate heights of cells that do not span multiple rows.
-        let mut rows = vec![Row::default(); n[Y]];
+        let mut unspanned_rows = vec![0; n[Y]];
         for cell in table.cells().filter(|cell| cell.row_span() == 1) {
             let rect = cell.rect();
 
             let w = joined_width(&cp_x, rect[X].clone());
             let h = device.measure_cell_height(cell.inner(), w);
 
-            let row = &mut rows[cell.coord.y()];
-            if h > row.unspanned {
-                row.unspanned = h;
-                row.width = h;
+            let row = &mut unspanned_rows[cell.coord.y()];
+            if h > *row {
+                *row = h;
             }
         }
 
         // Distribute heights of spanned rows.
+        let mut rows = unspanned_rows.clone();
         for cell in table.cells().filter(|cell| cell.row_span() > 1) {
             let rect = cell.rect();
             let w = joined_width(&cp_x, rect[X].clone());
             let h = device.measure_cell_height(cell.inner(), w);
             distribute_spanned_width(
                 h,
+                &unspanned_rows[rect[Y].clone()],
                 &mut rows[rect[Y].clone()],
                 &rules[Y][rect[Y].start..rect[Y].end + 1],
             );
@@ -492,14 +490,14 @@ impl Page {
         vec
     }
 
-    fn use_row_widths(rows: &[Row], rules: &[usize]) -> Vec<usize> {
+    fn use_row_widths(rows: &[usize], rules: &[usize]) -> Vec<usize> {
         debug_assert_eq!(rows.len() + 1, rules.len());
         let mut cp = Vec::with_capacity(2 * (rows.len()) + 1);
 
         cp.push(0);
         for (rule, row) in rules.iter().zip(rows.iter()) {
             cp.push(*rule);
-            cp.push(row.width);
+            cp.push(*row);
         }
         cp.push(*rules.last().unwrap());
 
@@ -507,10 +505,9 @@ impl Page {
     }
 
     fn interpolate_row_widths(
-        table: &Table,
         params: &Params,
-        rows_min: &[Row],
-        rows_max: &[Row],
+        rows_min: &[usize],
+        rows_max: &[usize],
         w_min: usize,
         w_max: usize,
         rules: &[usize],
@@ -520,15 +517,13 @@ impl Page {
         let mut w = wanted / 2;
         let rows_mid = rows_min
             .iter()
-            .zip(rows_max.iter())
+            .copied()
+            .zip(rows_max.iter().copied())
             .map(|(min, max)| {
-                w += avail * (max.width - min.width);
+                w += avail * (max - min);
                 let extra = w / wanted;
                 w -= extra * wanted;
-                Row {
-                    width: min.width + extra,
-                    unspanned: 0,
-                }
+                min + extra
             })
             .collect::<Vec<_>>();
         return Self::use_row_widths(&rows_mid, rules);
@@ -773,18 +768,24 @@ struct Map {
 /// width, plus the width of the rule on the left, plus the width of the rule on
 /// the right.  That way each rule contributes to both the cell on its left and
 /// on its right.)
-fn distribute_spanned_width(width: usize, rows: &mut [Row], rules: &[usize]) {
-    debug_assert!(rows.len() >= 2);
-    debug_assert!(rules.len() == rows.len() + 1);
-
-    let n = rows.len();
-    let total_unspanned = rows.iter().map(|row| row.unspanned).sum::<usize>()
-        + (&rules[1..n - 1]).iter().copied().sum::<usize>();
+fn distribute_spanned_width(
+    width: usize,
+    unspanned: &[usize],
+    spanned: &mut [usize],
+    rules: &[usize],
+) {
+    let n = unspanned.len();
+    debug_assert!(n >= 2);
+    debug_assert_eq!(spanned.len(), n);
+    debug_assert_eq!(rules.len(), n + 1);
+
+    let total_unspanned =
+        unspanned.iter().sum::<usize>() + (&rules[1..n - 1]).iter().copied().sum::<usize>();
     if total_unspanned >= width {
         return;
     }
 
-    let d0 = rows.len();
+    let d0 = n;
     let d1 = 2 * total_unspanned.max(1);
     let d = if total_unspanned > 0 {
         d0 * d1 * 2
@@ -795,8 +796,8 @@ fn distribute_spanned_width(width: usize, rows: &mut [Row], rules: &[usize]) {
     for x in 0..n {
         w += width * d1;
         if total_unspanned > 0 {
-            let mut unspanned = rows[x].unspanned * 2;
-            if x < n - 1 {
+            let mut unspanned = unspanned[x] * 2;
+            if x + 1 < n {
                 unspanned += rules[x + 1];
             }
             if x > 0 {
@@ -804,22 +805,11 @@ fn distribute_spanned_width(width: usize, rows: &mut [Row], rules: &[usize]) {
             }
             w += width * unspanned * d0;
         }
-        rows[x].width = max(rows[x].width, w / d);
-        w = w.checked_sub(rows[x].width * d).unwrap();
+        spanned[x] = max(spanned[x], w / d);
+        w = w.checked_sub(spanned[x] * d).unwrap();
     }
 }
 
-/// Row or column dimension.
-#[derive(Clone, Default)]
-struct Row {
-    /// Width without considering rows (or columns) that span more than one row
-    /// (or column).
-    unspanned: usize,
-
-    /// Width take spanned rows (or columns) into consideration.
-    width: usize,
-}
-
 /// Returns the width of the rule in `table` that is at offset `z` along axis
 /// `a`, if rendered on `device`.
 fn measure_rule(table: &Table, device: &dyn Device, a: Axis2, z: usize) -> usize {