From a664376a354a6d0b6cc395f8697559ca4b0a373c Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 18 Dec 2025 17:02:10 -0800 Subject: [PATCH] rendering fixes --- rust/pspp/src/output.rs | 35 ++++++++++++------- rust/pspp/src/output/drivers/cairo/fsm.rs | 7 +++- rust/pspp/src/output/pivot/output.rs | 42 +++++++++++------------ rust/pspp/src/output/render.rs | 4 ++- rust/pspp/src/spv/read/css.rs | 2 ++ rust/pspp/src/spv/read/html.rs | 4 ++- rust/pspp/src/spv/read/light.rs | 8 ++--- 7 files changed, 61 insertions(+), 41 deletions(-) diff --git a/rust/pspp/src/output.rs b/rust/pspp/src/output.rs index 3133d61695..d0b29c3aab 100644 --- a/rust/pspp/src/output.rs +++ b/rust/pspp/src/output.rs @@ -139,7 +139,7 @@ impl Item { /// This always returns true for headings because their contents are always /// shown (although headings can be collapsed in an outline view). pub fn is_shown(&self) -> bool { - self.details.kind() == ItemKind::Heading || self.show + self.details.is_heading() || self.show } } @@ -556,21 +556,30 @@ impl ItemCursor { } pub fn next(&mut self) { - let Some(cur) = self.cur.take() else { - return; - }; - if let Some(first_child) = cur.details.children().first() { - self.cur = Some(first_child.clone()); - self.stack.push((cur, 1)); - } else { - while let Some((item, index)) = self.stack.pop() { - if let Some(child) = item.details.children().get(index) { - self.cur = Some(child.clone()); - self.stack.push((item, index + 1)); - return; + fn inner(this: &mut ItemCursor) { + let Some(cur) = this.cur.take() else { + return; + }; + if let Some(first_child) = cur.details.children().first() { + this.cur = Some(first_child.clone()); + this.stack.push((cur, 1)); + } else { + while let Some((item, index)) = this.stack.pop() { + if let Some(child) = item.details.children().get(index) { + this.cur = Some(child.clone()); + this.stack.push((item, index + 1)); + return; + } } } } + + inner(self); + while let Some(cur) = &self.cur + && !cur.is_shown() + { + inner(self); + } } // Returns the label for the heading with the given `level` in the stack diff --git a/rust/pspp/src/output/drivers/cairo/fsm.rs b/rust/pspp/src/output/drivers/cairo/fsm.rs index 88def4fcdf..165e304c11 100644 --- a/rust/pspp/src/output/drivers/cairo/fsm.rs +++ b/rust/pspp/src/output/drivers/cairo/fsm.rs @@ -31,7 +31,7 @@ use crate::{ Details, Item, drivers::cairo::{px_to_xr, xr_to_pt}, pivot::{ - Axis2, Coord2, Rect2, + Axis2, Coord2, PivotTable, Rect2, look::{BorderStyle, Color, FontStyle, HorzAlign, Stroke}, }, render::{Device, Extreme, Pager, Params}, @@ -136,6 +136,11 @@ impl CairoFsm { params: ¶ms, context, }; + let item = if let Some(text) = item.details.as_text() { + Arc::new(Item::new(PivotTable::from(dbg!(text).clone()))) + } else { + item + }; let (layer_iterator, pager) = match &item.details { Details::Table(pivot_table) => { let mut layer_iterator = pivot_table.layers(printing); diff --git a/rust/pspp/src/output/pivot/output.rs b/rust/pspp/src/output/pivot/output.rs index 6b36ececc1..00e1e71457 100644 --- a/rust/pspp/src/output/pivot/output.rs +++ b/rust/pspp/src/output/pivot/output.rs @@ -170,6 +170,27 @@ impl PivotTable { } fn borders(&self, printing: bool) -> EnumMap { + fn resolve_border_style( + border: Border, + borders: &EnumMap, + show_grid_lines: bool, + ) -> BorderStyle { + let style = borders[border]; + if style.stroke != Stroke::None { + style + } else { + let style = borders[border.fallback()]; + if style.stroke != Stroke::None || !show_grid_lines { + style + } else { + BorderStyle { + stroke: Stroke::Dashed, + color: Color::BLACK, + } + } + } + } + EnumMap::from_fn(|border| { resolve_border_style( border, @@ -694,24 +715,3 @@ impl<'a> Headings<'a> { } } } - -fn resolve_border_style( - border: Border, - borders: &EnumMap, - show_grid_lines: bool, -) -> BorderStyle { - let style = borders[border]; - if style.stroke != Stroke::None { - style - } else { - let style = borders[border.fallback()]; - if style.stroke != Stroke::None || !show_grid_lines { - style - } else { - BorderStyle { - stroke: Stroke::Dashed, - color: Color::BLACK, - } - } - } -} diff --git a/rust/pspp/src/output/render.rs b/rust/pspp/src/output/render.rs index 6fb039923f..be194a7dcf 100644 --- a/rust/pspp/src/output/render.rs +++ b/rust/pspp/src/output/render.rs @@ -965,7 +965,9 @@ impl Break { for c in 0..self.page.table.n()[self.axis] { let position = cp[c * 2 + 3]; if position > range.end { - if self.page.table.cell_width(self.axis, c) >= device.params().min_break[self.axis] + if c == 0 + || self.page.table.cell_width(self.axis, c) + >= device.params().min_break[self.axis] { // XXX various way to choose a better breakpoint return (range.end, range.end); diff --git a/rust/pspp/src/spv/read/css.rs b/rust/pspp/src/spv/read/css.rs index a6c04997b4..abd7712d19 100644 --- a/rust/pspp/src/spv/read/css.rs +++ b/rust/pspp/src/spv/read/css.rs @@ -137,6 +137,8 @@ impl Style { "text-decoration" => Some((Style::Underline, value == "underline")), "font-family" => Some((Style::Face(value.into()), true)), "font-size" => value + .strip_suffix("pt") + .unwrap_or(&value) .parse::() .ok() .map(|size| (Style::Size(size as f64 * 0.75), true)), diff --git a/rust/pspp/src/spv/read/html.rs b/rust/pspp/src/spv/read/html.rs index cbed0ddc07..f334ecc95a 100644 --- a/rust/pspp/src/spv/read/html.rs +++ b/rust/pspp/src/spv/read/html.rs @@ -732,7 +732,9 @@ fn parse_nodes(nodes: &[Node]) -> Markup { Markup::Text(unescape(&text).unwrap_or(Cow::from(text)).into_owned()), ); } - Node::Element(br) if br.name.eq_ignore_ascii_case("br") => { + // SPSS often starts paragraphs with an initial `
` that it + // ignores, but it does honor `
`. So weird. + Node::Element(br) if br.name == "br" => { add_markup(&mut retval, Markup::Text('\n'.into())); } Node::Element(element) => { diff --git a/rust/pspp/src/spv/read/light.rs b/rust/pspp/src/spv/read/light.rs index aa9194aa3e..321255a997 100644 --- a/rust/pspp/src/spv/read/light.rs +++ b/rust/pspp/src/spv/read/light.rs @@ -574,13 +574,13 @@ impl Border { 9 => look::Border::DataLeft, 10 => look::Border::DataLeft, 11 => look::Border::Dimension(RowColBorder(HeadingRegion::Rows, Axis2::X)), - 12 => look::Border::Dimension(RowColBorder(HeadingRegion::Rows, Axis2::X)), + 12 => look::Border::Dimension(RowColBorder(HeadingRegion::Rows, Axis2::Y)), 13 => look::Border::Dimension(RowColBorder(HeadingRegion::Columns, Axis2::X)), - 14 => look::Border::Dimension(RowColBorder(HeadingRegion::Columns, Axis2::X)), + 14 => look::Border::Dimension(RowColBorder(HeadingRegion::Columns, Axis2::Y)), 15 => look::Border::Category(RowColBorder(HeadingRegion::Rows, Axis2::X)), - 16 => look::Border::Category(RowColBorder(HeadingRegion::Rows, Axis2::X)), + 16 => look::Border::Category(RowColBorder(HeadingRegion::Rows, Axis2::Y)), 17 => look::Border::Category(RowColBorder(HeadingRegion::Columns, Axis2::X)), - 18 => look::Border::Category(RowColBorder(HeadingRegion::Columns, Axis2::X)), + 18 => look::Border::Category(RowColBorder(HeadingRegion::Columns, Axis2::Y)), _ => return None, }; -- 2.30.2