work on monolithic rendering
[pspp] / src / output / render.c
index aae6f7901fc8c76131554f1cd7ec56479e4f04af..32e6f4513710dbd8696a296e207d7362b24b717f 100644 (file)
@@ -480,25 +480,27 @@ measure_rule (const struct render_params *params, const struct table *table,
 }
 
 /* Allocates and returns a new render_page using PARAMS and TABLE.  Allocates
-   space for rendering a table with dimensions given in N.  The caller must
-   initialize most of the members itself. */
+   space for rendering a table with dimensions given in N, headers in H, and
+   content in R.  The caller must initialize most of the members itself. */
 static struct render_page *
 render_page_allocate__ (const struct render_params *params,
-                        struct table *table, int n[TABLE_N_AXES])
+                        struct table *table,
+                        const int n[TABLE_N_AXES],
+                        const int h[TABLE_N_AXES],
+                        const int r[TABLE_N_AXES][2])
 {
   struct render_page *page = xmalloc (sizeof *page);
-  page->params = params;
-  page->table = table;
-  page->ref_cnt = 1;
-  page->n[H] = n[H];
-  page->n[V] = n[V];
-
-  for (int i = 0; i < TABLE_N_AXES; i++)
-    page->cp[i] = xcalloc ((2 * n[i] + 2) , sizeof *page->cp[i]);
-
-  hmap_init (&page->overflows);
-  memset (page->is_edge_cutoff, 0, sizeof page->is_edge_cutoff);
-
+  *page = (struct render_page) {
+    .params = params,
+    .table = table,
+    .ref_cnt = 1,
+    .n = { [H] = n[H], [V] = n[V] },
+    .h = { [H] = h[H], [V] = h[V] },
+    .r = { [H] = { r[H][0], r[H][1] }, [V] = { r[V][0], r[V][1] } },
+    .cp = { [H] = xcalloc (2 * n[H] + 2, sizeof *page->cp[H]),
+            [V] = xcalloc (2 * n[V] + 2, sizeof *page->cp[V]) },
+    .overflows = HMAP_INITIALIZER (page->overflows),
+  };
   return page;
 }
 
@@ -508,14 +510,15 @@ render_page_allocate__ (const struct render_params *params,
 static struct render_page *
 render_page_allocate (const struct render_params *params, struct table *table)
 {
-  struct render_page *page = render_page_allocate__ (params, table, table->n);
+  int h[TABLE_N_AXES];
+  int r[TABLE_N_AXES][2];
   for (enum table_axis a = 0; a < TABLE_N_AXES; a++)
     {
-      page->h[a] = table->h[a];
-      page->r[a][0] = table->h[a];
-      page->r[a][1] = table->n[a];
+      h[a] = table->h[a];
+      r[a][0] = table->h[a];
+      r[a][1] = table->n[a];
     }
-  return page;
+  return render_page_allocate__ (params, table, table->n, h, r);
 }
 
 /* Allocates and returns a new render_page for PARAMS and TABLE, initializing
@@ -638,6 +641,12 @@ render_get_cell (const struct render_page *page, int x, int y,
       cell->d[a][0] = MAX (cell->d[a][0], m->p0);
       cell->d[a][1] = MIN (cell->d[a][1], m->p0 + m->n);
     }
+
+  if (cell->options & TABLE_CELL_FULL_WIDTH)
+    {
+      cell->d[H][0] = 0;
+      cell->d[H][1] = page->n[H];
+    }
 }
 
 /* Creates and returns a new render_page for rendering TABLE on a device
@@ -1410,30 +1419,16 @@ struct render_pager
     const struct render_params *params;
     double scale;
 
-    /* An array of "render_page"s to be rendered, in order, vertically.  There
-       may be up to 5 pages, for the pivot table's title, layers, body,
-       captions, and footnotes. */
-    struct render_page *pages[5];
-    size_t n_pages;
+    struct render_page *page;
 
-    size_t cur_page;
     struct render_break x_break;
     struct render_break y_break;
   };
 
-static void
-render_pager_add_table (struct render_pager *p, struct table *table,
-                        int min_width)
-{
-  if (table)
-    p->pages[p->n_pages++] = render_page_create (p->params, table, min_width);
-}
-
 static void
 render_pager_start_page (struct render_pager *p)
 {
-  render_break_init (&p->x_break, render_page_ref (p->pages[p->cur_page++]),
-                     H);
+  render_break_init (&p->x_break, render_page_ref (p->page), H);
   render_break_init_empty (&p->y_break);
 }
 
@@ -1447,26 +1442,24 @@ render_pager_create (const struct render_params *params,
   if (!layer_indexes)
     layer_indexes = pt->current_layer;
 
-  struct table *title, *layers, *body, *caption, *footnotes;
-  pivot_output (pt, layer_indexes, params->printing,
-                &title, &layers, &body, &caption, &footnotes, NULL, NULL);
+  struct table *table = pivot_output_monolithic (pt, layer_indexes,
+                                                 params->printing);
 
-  /* Figure out the width of the body of the table.  Use this to determine the
-     base scale. */
-  struct render_page *body_page = render_page_create (params, body, 0);
-  int body_width = table_width (body_page, H);
+  /* Measure the table width and use it to determine the base scale. */
+  struct render_page *page = render_page_create (params, table, 0);
+  int width = table_width (page, H);
   double scale = 1.0;
-  if (body_width > params->size[H])
+  if (width > params->size[H])
     {
       if (pt->look->shrink_to_fit[H] && params->ops->scale)
-        scale = params->size[H] / (double) body_width;
+        scale = params->size[H] / (double) width;
       else
         {
           struct render_break b;
-          render_break_init (&b, render_page_ref (body_page), H);
+          render_break_init (&b, render_page_ref (page), H);
           struct render_page *subpage
             = render_break_next (&b, params->size[H]);
-          body_width = subpage ? subpage->cp[H][2 * subpage->n[H] + 1] : 0;
+          width = subpage ? subpage->cp[H][2 * subpage->n[H] + 1] : 0;
           render_page_unref (subpage);
           render_break_destroy (&b);
         }
@@ -1474,13 +1467,7 @@ render_pager_create (const struct render_params *params,
 
   /* Create the pager. */
   struct render_pager *p = xmalloc (sizeof *p);
-  *p = (struct render_pager) { .params = params, .scale = scale };
-  render_pager_add_table (p, title, body_width);
-  render_pager_add_table (p, layers, body_width);
-  p->pages[p->n_pages++] = body_page;
-  render_pager_add_table (p, caption, 0);
-  render_pager_add_table (p, footnotes, 0);
-  assert (p->n_pages <= sizeof p->pages / sizeof *p->pages);
+  *p = (struct render_pager) { .params = params, .scale = scale, .page = page };
 
   /* If we're shrinking tables to fit the page length, then adjust the scale
      factor.
@@ -1492,11 +1479,9 @@ render_pager_create (const struct render_params *params,
      necessary would require an iterative search. */
   if (pt->look->shrink_to_fit[V] && params->ops->scale)
     {
-      int total_height = 0;
-      for (size_t i = 0; i < p->n_pages; i++)
-        total_height += table_width (p->pages[i], V);
-      if (total_height * p->scale >= params->size[V])
-        p->scale *= params->size[V] / (double) total_height;
+      double height = table_width (p->page, V);
+      if (height * p->scale >= params->size[V])
+        p->scale *= params->size[V] / height;
     }
 
   render_pager_start_page (p);
@@ -1512,8 +1497,7 @@ render_pager_destroy (struct render_pager *p)
     {
       render_break_destroy (&p->x_break);
       render_break_destroy (&p->y_break);
-      for (size_t i = 0; i < p->n_pages; i++)
-        render_page_unref (p->pages[i]);
+      render_page_unref (p->page);
       free (p);
     }
 }
@@ -1531,13 +1515,9 @@ render_pager_has_next (const struct render_pager *p_)
       if (!render_break_has_next (&p->x_break))
         {
           render_break_destroy (&p->x_break);
-          if (p->cur_page >= p->n_pages)
-            {
-              render_break_init_empty (&p->x_break);
-              render_break_init_empty (&p->y_break);
-              return false;
-            }
-          render_pager_start_page (p);
+          render_break_init_empty (&p->x_break);
+          render_break_init_empty (&p->y_break);
+          return false;
         }
       else
         render_break_init (
@@ -1563,22 +1543,17 @@ render_pager_draw_next (struct render_pager *p, int space)
     }
 
   int ofs[TABLE_N_AXES] = { 0, 0 };
-  size_t start_page = SIZE_MAX;
 
-  while (render_pager_has_next (p))
+  if (render_pager_has_next (p))
     {
-      if (start_page == p->cur_page)
-        break;
-      start_page = p->cur_page;
-
       struct render_page *page
         = render_break_next (&p->y_break, space - ofs[V]);
-      if (!page)
-        break;
-
-      render_page_draw (page, ofs);
-      ofs[V] += render_page_get_size (page, V);
-      render_page_unref (page);
+      if (page)
+        {
+          render_page_draw (page, ofs);
+          ofs[V] += render_page_get_size (page, V);
+          render_page_unref (page);
+        }
     }
 
   if (p->scale != 1.0)
@@ -1606,18 +1581,14 @@ render_pager_draw_region (const struct render_pager *p,
 
   clip[H][0] = x;
   clip[H][1] = x + w;
-  for (size_t i = 0; i < p->n_pages; i++)
-    {
-      const struct render_page *page = p->pages[i];
-      int size = render_page_get_size (page, V);
+  int size = render_page_get_size (p->page, V);
 
-      clip[V][0] = MAX (y, ofs[V]) - ofs[V];
-      clip[V][1] = MIN (y + h, ofs[V] + size) - ofs[V];
-      if (clip[V][1] > clip[V][0])
-        render_page_draw_region (page, ofs, clip);
+  clip[V][0] = MAX (y, ofs[V]) - ofs[V];
+  clip[V][1] = MIN (y + h, ofs[V] + size) - ofs[V];
+  if (clip[V][1] > clip[V][0])
+    render_page_draw_region (p->page, ofs, clip);
 
-      ofs[V] += size;
-    }
+  ofs[V] += size;
 }
 
 /* Returns the size of P's content along AXIS; i.e. the content's width if AXIS
@@ -1625,32 +1596,16 @@ render_pager_draw_region (const struct render_pager *p,
 int
 render_pager_get_size (const struct render_pager *p, enum table_axis axis)
 {
-  int size = 0;
-
-  for (size_t i = 0; i < p->n_pages; i++)
-    {
-      int subsize = render_page_get_size (p->pages[i], axis);
-      size = axis == H ? MAX (size, subsize) : size + subsize;
-    }
-
-  return size;
+  return render_page_get_size (p->page, axis);
 }
 
 int
 render_pager_get_best_breakpoint (const struct render_pager *p, int height)
 {
-  int y = 0;
-  size_t i;
-
-  for (i = 0; i < p->n_pages; i++)
-    {
-      int size = render_page_get_size (p->pages[i], V);
-      if (y + size >= height)
-        return render_page_get_best_breakpoint (p->pages[i], height - y) + y;
-      y += size;
-    }
-
-  return height;
+  int size = render_page_get_size (p->page, V);
+  return (size < height
+          ? height
+          : render_page_get_best_breakpoint (p->page, height));
 }
 \f
 /* render_page_select() and helpers. */
@@ -1707,18 +1662,21 @@ render_page_select (const struct render_page *page, enum table_axis axis,
 
   /* Allocate subpage. */
   int trim[2] = { z0 - page->h[a], page->n[a] - z1 };
+
   int n[TABLE_N_AXES] = { [H] = page->n[H], [V] = page->n[V] };
   n[a] -= trim[0] + trim[1];
-  struct render_page *subpage = render_page_allocate__ (
-    page->params, table_ref (page->table), n);
+
+  int r[TABLE_N_AXES][2];
   for (enum table_axis k = 0; k < TABLE_N_AXES; k++)
     {
-      subpage->h[k] = page->h[k];
-      subpage->r[k][0] = page->r[k][0];
-      subpage->r[k][1] = page->r[k][1];
+      r[k][0] = page->r[k][0];
+      r[k][1] = page->r[k][1];
     }
-  subpage->r[a][0] += trim[0];
-  subpage->r[a][1] -= trim[1];
+  r[a][0] += trim[0];
+  r[a][1] -= trim[1];
+
+  struct render_page *subpage = render_page_allocate__ (
+    page->params, table_ref (page->table), n, page->h, r);
 
   /* An edge is cut off if it was cut off in PAGE or if we're trimming pixels
      off that side of the page and there are no headers. */