work on cairo driver
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 24 Apr 2025 16:28:05 +0000 (09:28 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 24 Apr 2025 16:28:05 +0000 (09:28 -0700)
rust/Cargo.lock
rust/pspp/Cargo.toml
rust/pspp/src/output/cairo/fsm.rs
rust/pspp/src/output/cairo/mod.rs
rust/pspp/src/output/cairo/pager.rs [new file with mode: 0644]
rust/pspp/src/output/mod.rs
rust/pspp/src/output/pivot/mod.rs
rust/pspp/src/output/pivot/test.rs
src/output/cairo-pager.c

index 625ffceed7bcc25e13017d78b1c3dcb1231fcf1f..691a5fa37e53f35b0e38ff96b9b1aa282277f43b 100644 (file)
@@ -26,6 +26,12 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "aliasable"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
+
 [[package]]
 name = "android-tzdata"
 version = "0.1.1"
@@ -312,7 +318,7 @@ version = "4.5.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
 dependencies = [
- "heck",
+ "heck 0.5.0",
  "proc-macro2",
  "quote",
  "syn 2.0.87",
@@ -688,7 +694,7 @@ version = "0.20.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68"
 dependencies = [
- "heck",
+ "heck 0.5.0",
  "proc-macro-crate",
  "proc-macro2",
  "quote",
@@ -722,6 +728,12 @@ version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
 [[package]]
 name = "heck"
 version = "0.5.0"
@@ -1051,6 +1063,30 @@ dependencies = [
  "num-traits",
 ]
 
+[[package]]
+name = "ouroboros"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59"
+dependencies = [
+ "aliasable",
+ "ouroboros_macro",
+ "static_assertions",
+]
+
+[[package]]
+name = "ouroboros_macro"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2",
+ "proc-macro2-diagnostics",
+ "quote",
+ "syn 2.0.87",
+]
+
 [[package]]
 name = "owo-colors"
 version = "3.5.0"
@@ -1216,6 +1252,19 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "proc-macro2-diagnostics"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+ "version_check",
+ "yansi",
+]
+
 [[package]]
 name = "pspp"
 version = "1.0.0"
@@ -1249,6 +1298,7 @@ dependencies = [
  "num-derive",
  "num-traits",
  "ordered-float",
+ "ouroboros",
  "pango",
  "pangocairo",
  "pspp-derive",
@@ -1516,6 +1566,12 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
 [[package]]
 name = "strsim"
 version = "0.11.1"
@@ -1551,7 +1607,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005"
 dependencies = [
  "cfg-expr",
- "heck",
+ "heck 0.5.0",
  "pkg-config",
  "toml",
  "version-compare",
@@ -2141,6 +2197,12 @@ dependencies = [
  "bitflags 2.6.0",
 ]
 
+[[package]]
+name = "yansi"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
+
 [[package]]
 name = "zerocopy"
 version = "0.8.24"
index 3dc3a805cd398224a7572c7fb7888320a9b061ba..d28b866d54751180c70c7ac22161839a9eff50f3 100644 (file)
@@ -45,6 +45,7 @@ derive_more = { version = "2.0.1", features = ["debug"] }
 cairo-rs = { version = "0.20.7", features = ["ps", "png", "pdf", "svg"] }
 pango = "0.20.9"
 pangocairo = "0.20.7"
+ouroboros = "0.18.5"
 
 [target.'cfg(windows)'.dependencies]
 windows-sys = { version = "0.48.0", features = ["Win32_Globalization"] }
index d4d12d9fa9f5dbe82227ef9c29e71afb6d274a09..c8009dfb3bfa48bcdda0529a8c4696a5d6f90c9c 100644 (file)
@@ -1,6 +1,6 @@
 use std::{cmp::min, f64::consts::PI, fmt::Write, ops::DerefMut, sync::Arc};
 
-use cairo::{Context, Surface};
+use cairo::Context;
 use enum_map::{enum_map, EnumMap};
 use itertools::Itertools;
 use pango::{
@@ -10,9 +10,11 @@ use pango::{
 use pangocairo::functions::show_layout;
 use smallvec::{smallvec, SmallVec};
 
+use crate::output::cairo::{horz_align_to_pango, px_to_xr, xr_to_pt};
 use crate::output::pivot::{Axis2, BorderStyle, Coord2, FontStyle, HorzAlign, Rect2, Stroke};
-use crate::output::render::{Device, DrawCell, Extreme, Params};
+use crate::output::render::{Device, DrawCell, Extreme, Pager, Params};
 use crate::output::{pivot::Color, table::Content};
+use crate::output::{Details, Item};
 
 /// Width of an ordinary line.
 const LINE_WIDTH: usize = LINE_SPACE / 2;
@@ -20,19 +22,6 @@ const LINE_WIDTH: usize = LINE_SPACE / 2;
 /// Space between double lines.
 const LINE_SPACE: usize = SCALE as usize;
 
-/// Conversion from 1/96" units ("pixels") to Cairo/Pango units.
-fn px_to_xr(x: usize) -> usize {
-    x * 3 * (SCALE as usize * 72 / 96) / 3
-}
-
-fn xr_to_pt(x: usize) -> f64 {
-    x as f64 / SCALE as f64
-}
-
-fn xr_to_pango(x: usize) -> usize {
-    x
-}
-
 /// Conversion from 1/96" units ("pixels") to Cairo/Pango units.
 fn pxf_to_xr(x: f64) -> usize {
     (x * (SCALE as f64 * 72.0 / 96.0)).round() as usize
@@ -78,12 +67,18 @@ impl CairoFsmStyle {
 pub struct CairoFsm {
     style: Arc<CairoFsmStyle>,
     params: Params,
-    context: Context,
+    item: Arc<Item>,
+    layer_iterator: Option<Box<dyn Iterator<Item = SmallVec<[usize; 4]>>>>,
+    pager: Option<Pager>,
 }
 
 impl CairoFsm {
-    pub fn new(style: Arc<CairoFsmStyle>, printing: bool, surface: &Surface) -> Self {
-        let context = Context::new(surface).unwrap();
+    pub fn new(
+        style: Arc<CairoFsmStyle>,
+        printing: bool,
+        context: Context,
+        item: Arc<Item>,
+    ) -> Self {
         let params = Params {
             size: style.size,
             font_size: {
@@ -111,14 +106,122 @@ impl CairoFsm {
             can_adjust_break: false, // XXX
             can_scale: true,
         };
+        let device = CairoDevice {
+            style: &style,
+            params: &params,
+            context: &context,
+        };
+        match &item.details {
+            Details::Table(pivot_table) => {
+                let mut layer_iterator = pivot_table.layers(printing);
+                let layer_indexes = layer_iterator.next();
+                (
+                    layer_iterator,
+                    Some(Pager::new(
+                        &device,
+                        pivot_table,
+                        layer_indexes.as_ref().map(|indexes| indexes.as_slice()),
+                    )),
+                );
+            }
+            _ => (),
+        };
         Self {
             style,
             params,
+            item,
+            layer_iterator: None,
+            pager: None,
+        }
+    }
+
+    pub fn draw_slice(&mut self, context: Context, space: usize) {
+        debug_assert!(self.params.printing);
+
+        context.save().unwrap();
+        match &self.item.details {
+            Details::Table(_) => self.draw_table(&context, space),
+            _ => todo!(),
+        };
+        context.restore().unwrap();
+    }
+
+    fn draw_table(&mut self, context: &Context, space: usize) -> usize {
+        let Details::Table(pivot_table) = &self.item.details else {
+            unreachable!()
+        };
+        let mut device = CairoDevice {
+            style: &self.style,
+            params: &self.params,
             context,
+        };
+        let mut used = self.pager.as_mut().unwrap().draw_next(&mut device, space);
+        if !self.pager.as_mut().unwrap().has_next(&device) {
+            match self.layer_iterator.as_mut().unwrap().next() {
+                Some(layer_indexes) => {
+                    self.pager = Some(Pager::new(
+                        &device,
+                        pivot_table,
+                        Some(layer_indexes.as_slice()),
+                    ));
+                    if pivot_table.look.paginate_layers {
+                        used = space;
+                    } else {
+                        used += self.style.object_spacing;
+                    }
+                }
+                _ => {
+                    self.pager = None;
+                }
+            }
         }
+        used.min(space)
+    }
+}
+
+fn xr_clip(context: &Context, clip: &Rect2) {
+    if clip[Axis2::X].end != usize::MAX || clip[Axis2::Y].end != usize::MAX {
+        let x0 = xr_to_pt(clip[Axis2::X].start);
+        let y0 = xr_to_pt(clip[Axis2::Y].start);
+        let x1 = xr_to_pt(clip[Axis2::X].end);
+        let y1 = xr_to_pt(clip[Axis2::Y].end);
+        context.rectangle(x0, y0, x1 - x0, y1 - y0);
+        context.clip();
     }
+}
+
+fn xr_set_color(context: &Context, color: &Color) {
+    fn as_frac(x: u8) -> f64 {
+        x as f64 / 255.0
+    }
+
+    context.set_source_rgba(
+        as_frac(color.r),
+        as_frac(color.g),
+        as_frac(color.b),
+        as_frac(color.alpha),
+    );
+}
+
+fn xr_fill_rectangle(context: &Context, rectangle: Rect2) {
+    context.new_path();
+    context.set_line_width(xr_to_pt(LINE_WIDTH));
+
+    let x0 = xr_to_pt(rectangle[Axis2::X].start);
+    let y0 = xr_to_pt(rectangle[Axis2::Y].start);
+    let width = xr_to_pt(rectangle[Axis2::X].len());
+    let height = xr_to_pt(rectangle[Axis2::Y].len());
+    context.rectangle(x0, y0, width, height);
+    let _ = context.fill();
+}
 
-    //pub fn render(&mut self, table: &PivotTable) {}
+fn margin(cell: &DrawCell, axis: Axis2) -> usize {
+    px_to_xr(
+        cell.style.cell_style.margins[axis]
+            .iter()
+            .sum::<i32>()
+            .max(0) as usize,
+    )
 }
 
 pub fn parse_font_style(font_style: &FontStyle) -> FontDescription {
@@ -181,7 +284,13 @@ fn avoid_decimal_split(mut s: String) -> String {
     s
 }
 
-impl CairoFsm {
+struct CairoDevice<'a> {
+    style: &'a CairoFsmStyle,
+    params: &'a Params,
+    context: &'a Context,
+}
+
+impl CairoDevice<'_> {
     fn layout_cell(&self, cell: &DrawCell, mut bb: Rect2, clip: &Rect2) -> Coord2 {
         // XXX rotation
         //let h = if cell.rotate { Axis2::Y } else { Axis2::X };
@@ -304,15 +413,11 @@ impl CairoFsm {
 
         layout.set_attributes(attrs.as_ref());
         layout.set_text(&body);
-        layout.set_alignment(match horz_align {
-            HorzAlign::Right | HorzAlign::Decimal { .. } => pango::Alignment::Right,
-            HorzAlign::Left => pango::Alignment::Left,
-            HorzAlign::Center => pango::Alignment::Center,
-        });
+        layout.set_alignment(horz_align_to_pango(horz_align));
         if bb[Axis2::X].end == usize::MAX {
             layout.set_width(-1);
         } else {
-            layout.set_width(xr_to_pango(bb[Axis2::X].len()) as i32);
+            layout.set_width(bb[Axis2::X].len() as i32);
         }
 
         let size = layout.size();
@@ -373,52 +478,7 @@ impl CairoFsm {
     }
 }
 
-fn xr_clip(context: &Context, clip: &Rect2) {
-    if clip[Axis2::X].end != usize::MAX || clip[Axis2::Y].end != usize::MAX {
-        let x0 = xr_to_pt(clip[Axis2::X].start);
-        let y0 = xr_to_pt(clip[Axis2::Y].start);
-        let x1 = xr_to_pt(clip[Axis2::X].end);
-        let y1 = xr_to_pt(clip[Axis2::Y].end);
-        context.rectangle(x0, y0, x1 - x0, y1 - y0);
-        context.clip();
-    }
-}
-
-fn xr_set_color(context: &Context, color: &Color) {
-    fn as_frac(x: u8) -> f64 {
-        x as f64 / 255.0
-    }
-
-    context.set_source_rgba(
-        as_frac(color.r),
-        as_frac(color.g),
-        as_frac(color.b),
-        as_frac(color.alpha),
-    );
-}
-
-fn xr_fill_rectangle(context: &Context, rectangle: Rect2) {
-    context.new_path();
-    context.set_line_width(xr_to_pt(LINE_WIDTH));
-
-    let x0 = xr_to_pt(rectangle[Axis2::X].start);
-    let y0 = xr_to_pt(rectangle[Axis2::Y].start);
-    let width = xr_to_pt(rectangle[Axis2::X].len());
-    let height = xr_to_pt(rectangle[Axis2::Y].len());
-    context.rectangle(x0, y0, width, height);
-    let _ = context.fill();
-}
-
-fn margin(cell: &DrawCell, axis: Axis2) -> usize {
-    px_to_xr(
-        cell.style.cell_style.margins[axis]
-            .iter()
-            .sum::<i32>()
-            .max(0) as usize,
-    )
-}
-
-impl Device for CairoFsm {
+impl Device for CairoDevice<'_> {
     fn params(&self) -> &Params {
         &self.params
     }
index 5649ca9a6878f421009912194f45ab9d2bd1f51e..d8531c35c38708815c2fd4f1f59745979ef7647e 100644 (file)
@@ -1,6 +1,6 @@
 use std::{borrow::Cow, path::Path, sync::Arc};
 
-use cairo::PdfSurface;
+use cairo::{Context, PdfSurface};
 use enum_map::enum_map;
 use pango::SCALE;
 
@@ -8,13 +8,14 @@ use crate::output::{
     cairo::fsm::{parse_font_style, CairoFsm, CairoFsmStyle},
     driver::Driver,
     page::Setup,
-    pivot::{Color, Coord2, FontStyle},
+    pivot::{Color, Coord2, FontStyle, HorzAlign},
     Item,
 };
 
 use super::pivot::Axis2;
 
 pub mod fsm;
+pub mod pager;
 
 pub struct CairoDriver {
     renderer: CairoFsm,
@@ -58,8 +59,10 @@ impl CairoDriver {
             path,
         )
         .unwrap();
-        let renderer = CairoFsm::new(Arc::new(style), false, &surface);
-        Self { renderer }
+        let context = Context::new(surface).unwrap();
+        Self {
+            renderer: todo!(), //CairoFsm::new(style, true, context, item)),
+        }
     }
 }
 
@@ -83,6 +86,23 @@ impl Driver for CairoDriver {
     }
 }
 
+/// Conversion from 1/96" units ("pixels") to Cairo/Pango units.
+fn px_to_xr(x: usize) -> usize {
+    x * 3 * (SCALE as usize * 72 / 96) / 3
+}
+
+fn xr_to_pt(x: usize) -> f64 {
+    x as f64 / SCALE as f64
+}
+
+fn horz_align_to_pango(horz_align: HorzAlign) -> pango::Alignment {
+    match horz_align {
+        HorzAlign::Right | HorzAlign::Decimal { .. } => pango::Alignment::Right,
+        HorzAlign::Left => pango::Alignment::Left,
+        HorzAlign::Center => pango::Alignment::Center,
+    }
+}
+
 #[cfg(test)]
 mod test {
     use crate::output::cairo::CairoDriver;
diff --git a/rust/pspp/src/output/cairo/pager.rs b/rust/pspp/src/output/cairo/pager.rs
new file mode 100644 (file)
index 0000000..e7f649d
--- /dev/null
@@ -0,0 +1,93 @@
+use std::sync::Arc;
+
+use cairo::{Context, RecordingSurface};
+use enum_map::EnumMap;
+use pango::{FontDescription, Layout};
+
+use crate::output::{
+    cairo::{fsm::CairoFsmStyle, horz_align_to_pango, xr_to_pt},
+    page::Heading,
+    pivot::Axis2,
+    OwnedItemCursor,
+};
+
+pub struct CairoPageStyle {
+    pub margins: EnumMap<Axis2, [usize; 2]>,
+    pub headings: [Heading; 2],
+    pub initial_page_number: i32,
+}
+
+pub struct CairoPager {
+    page_style: Arc<CairoPageStyle>,
+    fsm_style: Arc<CairoFsmStyle>,
+    page_index: i32,
+    heading_heights: [usize; 2],
+    iter: Option<OwnedItemCursor>,
+}
+
+impl CairoPager {
+    fn new(page_style: Arc<CairoPageStyle>, fsm_style: Arc<CairoFsmStyle>) -> Self {
+        Self {
+            heading_heights: measure_headings(&page_style, &fsm_style),
+            page_style,
+            fsm_style,
+            page_index: 0,
+            iter: None,
+        }
+    }
+}
+
+fn measure_headings(page_style: &CairoPageStyle, fsm_style: &CairoFsmStyle) -> [usize; 2] {
+    let surface = RecordingSurface::create(cairo::Content::Color, None).unwrap();
+    let context = Context::new(&surface).unwrap();
+
+    let mut heading_heights = Vec::with_capacity(2);
+    for heading in &page_style.headings {
+        let mut height = render_heading(
+            &context,
+            &fsm_style.font,
+            heading,
+            -1,
+            fsm_style.size[Axis2::X],
+            0,
+            fsm_style.font_resolution,
+        );
+        if height > 0 {
+            height += fsm_style.object_spacing;
+        }
+        heading_heights.push(height);
+    }
+    heading_heights.try_into().unwrap()
+}
+
+fn render_heading(
+    context: &Context,
+    font: &FontDescription,
+    heading: &Heading,
+    page_number: i32,
+    width: usize,
+    base_y: usize,
+    font_resolution: f64,
+) -> usize {
+    let pangocairo_context = pangocairo::functions::create_context(context);
+    pangocairo::functions::context_set_resolution(&pangocairo_context, font_resolution);
+    let layout = Layout::new(&pangocairo_context);
+    layout.set_font_description(Some(font));
+
+    let mut y = 0;
+    for paragraph in &heading.0 {
+        // XXX substitute heading variables
+        layout.set_markup(&paragraph.markup);
+
+        layout.set_alignment(horz_align_to_pango(paragraph.horz_align));
+        layout.set_width(width as i32);
+
+        context.save().unwrap();
+        context.translate(0.0, xr_to_pt(width));
+        pangocairo::functions::show_layout(context, &layout);
+        context.restore().unwrap();
+
+        y += layout.height() as usize;
+    }
+    y
+}
index e2c194fccec1cf09107602d94cf35a388f0e87d2..0e28b544f7431747f1074e4b47b39d190c34b6c2 100644 (file)
@@ -95,3 +95,75 @@ pub enum TextType {
     /// Other logging.
     Log,
 }
+
+pub struct ItemCursor<'a> {
+    cur: Option<&'a Item>,
+    stack: Vec<&'a [Arc<Item>]>,
+}
+
+impl<'a> ItemCursor<'a> {
+    pub fn new(start: &'a Item) -> Self {
+        Self {
+            cur: Some(start),
+            stack: Vec::new(),
+        }
+    }
+
+    pub fn cur(&self) -> Option<&Item> {
+        self.cur
+    }
+
+    fn next_children(&mut self, children: &'a [Arc<Item>]) {
+        if children.len() > 1 {
+            self.stack.push(&children[1..]);
+        }
+        self.cur = Some(&children[0]);
+    }
+
+    pub fn next(&mut self) {
+        if let Some(cur) = self.cur {
+            match &cur.details {
+                Details::Group(children) if !children.is_empty() => {
+                    self.next_children(children.as_slice());
+                }
+                _ => {
+                    if let Some(children) = self.stack.pop() {
+                        self.next_children(children);
+                    } else {
+                        self.cur = None;
+                    }
+                }
+            }
+        }
+    }
+}
+
+#[ouroboros::self_referencing]
+struct OwnedItemCursorInner {
+    root: Arc<Item>,
+    #[borrows(root)]
+    #[covariant]
+    cursor: ItemCursor<'this>,
+}
+
+struct OwnedItemCursor(OwnedItemCursorInner);
+
+impl OwnedItemCursor {
+    pub fn new(item: Arc<Item>) -> Self {
+        Self(
+            OwnedItemCursorInnerBuilder {
+                root: item,
+                cursor_builder: |root| ItemCursor::new(root),
+            }
+            .build(),
+        )
+    }
+
+    pub fn cur(&self) -> Option<&Item> {
+        self.0.with_cursor(|cursor| cursor.cur)
+    }
+
+    pub fn next(&mut self) {
+        self.0.with_cursor_mut(|cursor| cursor.next())
+    }
+}
index b1b4a55b49fa623e518c4ab5248ffe3b9b00b16c..c00f2cb574adc9575b07c54c9473bf08770b66d3 100644 (file)
@@ -1431,7 +1431,7 @@ impl PivotTable {
     ///   will visit all values of the layer axis.
     ///
     /// - Otherwise, the iterator will just visit `self.current_layer`.
-    pub fn layers(&self, print: bool) -> Box<dyn Iterator<Item = SmallVec<[usize; 4]>> + '_> {
+    pub fn layers(&self, print: bool) -> Box<dyn Iterator<Item = SmallVec<[usize; 4]>>> {
         if print && self.look.print_all_layers {
             Box::new(self.axis_values(Axis3::Z))
         } else {
index 9bf93f61956d5f7b01159b23273d698e18163a9d..ad022a55549d8dc65310db5cbb3f67747e3d74ea 100644 (file)
@@ -2,11 +2,16 @@ use std::sync::Arc;
 
 use enum_map::EnumMap;
 
-use crate::output::{cairo::CairoDriver, pivot::{
-    Area, Axis2, Border, BorderStyle, Class, Color, Dimension, Footnote, FootnoteMarkerPosition,
-    FootnoteMarkerType, Footnotes, Group, HeadingRegion, LabelPosition, Look, PivotTable,
-    RowColBorder, Stroke,
-}};
+use crate::output::{
+    cairo::CairoDriver,
+    driver::Driver,
+    pivot::{
+        Area, Axis2, Border, BorderStyle, Class, Color, Dimension, Footnote,
+        FootnoteMarkerPosition, FootnoteMarkerType, Footnotes, Group, HeadingRegion, LabelPosition,
+        Look, PivotTable, RowColBorder, Stroke,
+    },
+    Details, Item,
+};
 
 use super::{Axis3, Value};
 
@@ -59,7 +64,9 @@ Columns
 
 fn d1_pdf() {
     let pt = d1("Columns", Axis3::X);
-    let cairo = CairoDriver::new("d1.pdf");
+    let mut cairo = CairoDriver::new("d1.pdf");
+    let item = Arc::new(Item::new(Details::Table(Box::new(pt))));
+    cairo.write(&item);
 }
 
 #[test]
index 1dbffd8270aa37d3bee3deffadae794fedb14ffb..a52d0b095aeb4a4b793b97178104dd3f2b27df5f 100644 (file)
@@ -246,7 +246,7 @@ void
 xr_pager_destroy (struct xr_pager *p)
 {
   if (p)
-    {
+    {x
       free (p->nodes);
 
       xr_page_style_unref (p->page_style);