gui: Speed up rendering of large tables that are only partly visible.
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 29 May 2010 21:16:14 +0000 (14:16 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sat, 29 May 2010 21:16:14 +0000 (14:16 -0700)
src/output/cairo.c
src/output/cairo.h
src/output/render.c
src/output/render.h
src/ui/gui/psppire-output-window.c

index 68c3eb81a0f96e54b9ef89da8dd86b5c41a3c290..896f3d5fe7cdc2a62fa561f3776d7625b9cbb37d 100644 (file)
@@ -1002,8 +1002,11 @@ xr_rendering_measure (struct xr_rendering *r, int *w, int *h)
     }
 }
 
+/* Draws onto CR at least the region of R that is enclosed in (X,Y)-(X+W,Y+H),
+   and possibly some additional parts. */
 void
-xr_rendering_draw (struct xr_rendering *r, cairo_t *cr)
+xr_rendering_draw (struct xr_rendering *r, cairo_t *cr,
+                   int x, int y, int w, int h)
 {
   if (r->chart == NULL)
     {
@@ -1011,7 +1014,8 @@ xr_rendering_draw (struct xr_rendering *r, cairo_t *cr)
 
       xr_set_cairo (xr, cr);
       xr->y = 0;
-      render_page_draw (r->page);
+      render_page_draw_region (r->page,
+                               x * 1024, y * 1024, w * 1024, h * 1024);
     }
   else
     xr_draw_chart (r->chart, cr, 0, 0, CHART_WIDTH, CHART_HEIGHT);
index 77889d11aa9158b055d79db98bf285f8e847b91f..fd9c7b920472429412880303a32b0de9afc7005d 100644 (file)
@@ -38,7 +38,8 @@ struct xr_rendering *xr_rendering_create (struct xr_driver *,
                                           const struct output_item *,
                                           cairo_t *);
 void xr_rendering_measure (struct xr_rendering *, int *w, int *h);
-void xr_rendering_draw (struct xr_rendering *, cairo_t *);
+void xr_rendering_draw (struct xr_rendering *, cairo_t *,
+                        int x, int y, int w, int h);
 
 /* Functions for rendering a series of output items to a series of Cairo
    contexts, with pagination, possibly including headers.
index 1b92b8bb5ee22d73f7c4c2b1c35d730b4a6cb3eb..450d5de7ef241b8f43caaa116c2c64ad870dc382 100644 (file)
@@ -902,15 +902,15 @@ render_cell (const struct render_page *page, const struct table_cell *cell)
   page->params->draw_cell (page->params->aux, cell, bb, clip);
 }
 
-/* Renders PAGE, by calling the 'draw_line' and 'draw_cell' functions from the
-   render_params provided to render_page_create(). */
-void
-render_page_draw (const struct render_page *page)
+/* Draws the cells of PAGE indicated in BB. */
+static void
+render_page_draw_cells (const struct render_page *page,
+                        int bb[TABLE_N_AXES][2])
 {
   int x, y;
 
-  for (y = 0; y <= page->n[V] * 2; y++)
-    for (x = 0; x <= page->n[H] * 2; )
+  for (y = bb[V][0]; y < bb[V][1]; y++)
+    for (x = bb[H][0]; x < bb[H][1]; )
       if (is_rule (x) || is_rule (y))
         {
           int d[TABLE_N_AXES];
@@ -924,12 +924,91 @@ render_page_draw (const struct render_page *page)
           struct table_cell cell;
 
           table_get_cell (page->table, x / 2, y / 2, &cell);
-          if (y / 2 == cell.d[V][0])
+          if (y == bb[V][0] || y / 2 == cell.d[V][0])
             render_cell (page, &cell);
           x = rule_ofs (cell.d[H][1]);
           table_cell_free (&cell);
         }
 }
+
+/* Renders PAGE, by calling the 'draw_line' and 'draw_cell' functions from the
+   render_params provided to render_page_create(). */
+void
+render_page_draw (const struct render_page *page)
+{
+  int bb[TABLE_N_AXES][2];
+
+  bb[H][0] = 0;
+  bb[H][1] = page->n[H] * 2 + 1;
+  bb[V][0] = 0;
+  bb[V][1] = page->n[V] * 2 + 1;
+
+  render_page_draw_cells (page, bb);
+}
+
+/* Returns the greatest value i, 0 <= i < n, such that cp[i] <= x0. */
+static int
+get_clip_min_extent (int x0, const int cp[], int n)
+{
+  int low, high, best;
+
+  low = 0;
+  high = n;
+  best = 0;
+  while (low < high)
+    {
+      int middle = low + (high - low) / 2;
+
+      if (cp[middle] <= x0)
+        {
+          best = middle;
+          low = middle + 1;
+        }
+      else
+        high = middle;
+    }
+
+  return best;
+}
+
+/* Returns the least value i, 0 <= i < n, such that cp[i + 1] >= x1. */
+static int
+get_clip_max_extent (int x1, const int cp[], int n)
+{
+  int low, high, best;
+
+  low = 0;
+  high = n;
+  best = n;
+  while (low < high)
+    {
+      int middle = low + (high - low) / 2;
+
+      if (cp[middle] >= x1)
+        best = high = middle;
+      else
+        low = middle + 1;
+    }
+
+  return best;
+}
+
+/* Renders the cells of PAGE that intersect (X,Y)-(X+W,Y+H), by calling the
+   'draw_line' and 'draw_cell' functions from the render_params provided to
+   render_page_create(). */
+void
+render_page_draw_region (const struct render_page *page,
+                         int x, int y, int w, int h)
+{
+  int bb[TABLE_N_AXES][2];
+
+  bb[H][0] = get_clip_min_extent (x, page->cp[H], page->n[H] * 2 + 1);
+  bb[H][1] = get_clip_max_extent (x + w, page->cp[H], page->n[H] * 2 + 1);
+  bb[V][0] = get_clip_min_extent (y, page->cp[V], page->n[V] * 2 + 1);
+  bb[V][1] = get_clip_max_extent (y + h, page->cp[V], page->n[V] * 2 + 1);
+
+  render_page_draw_cells (page, bb);
+}
 \f
 /* Breaking up tables to fit on a page. */
 
index af779843b9209195cc5cab8c77acff87a5bf9224..f6035cf0ab52fae1c16c55d9acdc383bf3be4a02 100644 (file)
@@ -93,6 +93,8 @@ void render_page_unref (struct render_page *);
 
 int render_page_get_size (const struct render_page *, enum table_axis);
 void render_page_draw (const struct render_page *);
+void render_page_draw_region (const struct render_page *,
+                              int x, int y, int w, int h);
 \f
 /* An iterator for breaking render_pages into smaller chunks. */
 struct render_break
index 5aba7c90fe857538e6a7825f285ddf3efb0e691f..b2ea1103ea4c5eecfe77449560933e0c9182e4bd 100644 (file)
@@ -168,7 +168,8 @@ expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
   cairo_t *cr;
 
   cr = gdk_cairo_create (widget->window);
-  xr_rendering_draw (r, cr);
+  xr_rendering_draw (r, cr, event->area.x, event->area.y,
+                     event->area.width, event->area.height);
   cairo_destroy (cr);
 
   return TRUE;