work (breaks tests)
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 6 Jan 2026 19:18:09 +0000 (11:18 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 6 Jan 2026 19:18:09 +0000 (11:18 -0800)
rust/pspp/src/output/drivers/cairo/fsm.rs
rust/pspp/src/output/drivers/text.rs
rust/pspp/src/output/render.rs

index 0fb0c668d96591088e935ad1ac1b1be23996c1b1..5e5738d6ac2333b99a3372d58d9b7640bfbb7128 100644 (file)
@@ -553,7 +553,7 @@ impl Device for CairoDevice<'_> {
         todo!()
     }
 
-    fn draw_line(&mut self, bb: Rect2, styles: EnumMap<Axis2, [BorderStyle; 2]>) {
+    fn draw_line(&mut self, bb: Rect2, styles: EnumMap<Axis2, [BorderStyle; 2]>, _bg: Color) {
         let x0 = bb[Axis2::X].start;
         let y0 = bb[Axis2::Y].start;
         let x3 = bb[Axis2::X].end;
index 855a87c94043a89777e0939bfa43d2bacdfbbc43..5b778246ca581aa1b38c059e82cdb026d17660a7 100644 (file)
@@ -30,7 +30,8 @@ use unicode_linebreak::{BreakOpportunity, linebreaks};
 use unicode_width::UnicodeWidthStr;
 
 use crate::output::{
-    Itemlike, drivers::text::text_line::Attribute, render::Extreme, table::DrawCell,
+    Itemlike, drivers::text::text_line::Attribute, pivot::look::Color, render::Extreme,
+    table::DrawCell,
 };
 
 use crate::output::{
@@ -650,7 +651,7 @@ impl Device for TextRenderer {
         unreachable!()
     }
 
-    fn draw_line(&mut self, bb: Rect2, styles: EnumMap<Axis2, [BorderStyle; 2]>) {
+    fn draw_line(&mut self, bb: Rect2, styles: EnumMap<Axis2, [BorderStyle; 2]>, bg: Color) {
         use Axis2::*;
         let x = bb[X].start.max(0)..bb[X].end.min(self.width);
         let y = bb[Y].start.max(0)..bb[Y].end;
@@ -665,9 +666,25 @@ impl Device for TextRenderer {
             b: styles[X][1].stroke.into(),
         };
         let c = self.box_chars[lines];
+        let attribute = self.emphasis.is_some().then(|| {
+            let mut fg = Color::BLACK;
+            for styles in styles.values() {
+                for style in styles {
+                    if style.stroke != Stroke::None {
+                        fg = style.color;
+                        break;
+                    }
+                }
+            }
+            Attribute {
+                fg,
+                bg,
+                ..Attribute::default()
+            }
+        });
         for y in y {
             self.get_line(y as usize)
-                .put_multiple(x.start as usize, c, x.len(), None);
+                .put_multiple(x.start as usize, c, x.len(), attribute);
         }
     }
 
@@ -683,6 +700,22 @@ impl Device for TextRenderer {
         let text = display.to_string();
         let horz_align = cell.horz_align(&display);
 
+        let attribute = self
+            .emphasis
+            .is_some()
+            .then(|| Attribute::for_style(cell.font_style));
+
+        if let Some(attribute) = attribute {
+            for y in bb[Y].clone() {
+                self.get_line(y as usize).put_multiple(
+                    bb[X].start as usize,
+                    ' ',
+                    bb[X].len(),
+                    Some(attribute),
+                );
+            }
+        }
+
         use Axis2::*;
         let breaks = new_line_breaks(&text, bb[X].len());
         for (text, y) in breaks.zip(bb[Y].start + valign_offset..bb[Y].end) {
@@ -700,10 +733,6 @@ impl Device for TextRenderer {
                 continue;
             };
 
-            let attribute = self
-                .emphasis
-                .is_some()
-                .then(|| Attribute::for_style(cell.font_style));
             self.get_line(y as usize).put(x as usize, &text, attribute);
         }
     }
index 2f0509e055e1095513897775e9cdb001ef3b8585..301eb0186acce5ad65aa4d514af5dd14bb29bab3 100644 (file)
@@ -24,6 +24,7 @@ use itertools::{Itertools, interleave};
 use num::Integer;
 use smallvec::SmallVec;
 
+use crate::output::pivot::look::Color;
 use crate::output::{
     pivot::{
         Axis2, Coord2, PivotTable, Rect2,
@@ -138,7 +139,7 @@ pub trait Device {
     /// `styles[Axis2::X][1]`: style of line from bottom of `bb` to its center.
     /// `styles[Axis2::Y][0]`: style of line from left of `bb` to its center.
     /// `styles[Axis2::Y][1]`: style of line from right of `bb` to its center.
-    fn draw_line(&mut self, bb: Rect2, styles: EnumMap<Axis2, [BorderStyle; 2]>);
+    fn draw_line(&mut self, bb: Rect2, styles: EnumMap<Axis2, [BorderStyle; 2]>, bg: Color);
 
     /// Draws `cell` within bounding box `bb`.  `clip` is the same as `bb` (the
     /// common case) or a subregion enclosed by `bb`.  In the latter case only
@@ -647,12 +648,29 @@ impl Page {
                     continue;
                 }
 
-                self.draw_rule(device, ofs, CellPos { x, y }, bb);
+                let bg = if !self.table.table.is_empty() {
+                    let x = (x / 2).min(self.table.n().x - 1);
+                    let y = (y / 2).min(self.table.n().y - 1);
+                    let cell = self.table.table.get(CellPos::new(x, y));
+                    let area = cell.inner().area;
+                    self.table.table.areas[area].font_style.bg
+                } else {
+                    Color::WHITE
+                };
+
+                self.draw_rule(device, ofs, CellPos { x, y }, bb, bg);
             }
         }
     }
 
-    fn draw_rule(&self, device: &mut dyn Device, ofs: Coord2, coord: CellPos, bb: Rect2) {
+    fn draw_rule(
+        &self,
+        device: &mut dyn Device,
+        ofs: Coord2,
+        coord: CellPos,
+        bb: Rect2,
+        bg: Color,
+    ) {
         const NO_BORDER: BorderStyle = BorderStyle::none();
         let styles = EnumMap::from_fn(|a: Axis2| {
             let b = !a;
@@ -680,12 +698,7 @@ impl Page {
             }
         });
 
-        if !styles
-            .values()
-            .all(|border| border.iter().all(BorderStyle::is_none))
-        {
-            device.draw_line(bb.translate(ofs), styles);
-        }
+        device.draw_line(bb.translate(ofs), styles, bg);
     }
 
     fn get_rule(&self, a: Axis2, coord: CellPos) -> BorderStyle {