From 933040005343d87414f14c48c90dfaa92110dc0a Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 29 May 2010 14:16:14 -0700 Subject: [PATCH] gui: Speed up rendering of large tables that are only partly visible. --- src/output/cairo.c | 8 ++- src/output/cairo.h | 3 +- src/output/render.c | 93 +++++++++++++++++++++++++++--- src/output/render.h | 2 + src/ui/gui/psppire-output-window.c | 3 +- 5 files changed, 98 insertions(+), 11 deletions(-) diff --git a/src/output/cairo.c b/src/output/cairo.c index 68c3eb81a0..896f3d5fe7 100644 --- a/src/output/cairo.c +++ b/src/output/cairo.c @@ -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); diff --git a/src/output/cairo.h b/src/output/cairo.h index 77889d11aa..fd9c7b9204 100644 --- a/src/output/cairo.h +++ b/src/output/cairo.h @@ -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. diff --git a/src/output/render.c b/src/output/render.c index 1b92b8bb5e..450d5de7ef 100644 --- a/src/output/render.c +++ b/src/output/render.c @@ -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); +} /* Breaking up tables to fit on a page. */ diff --git a/src/output/render.h b/src/output/render.h index af779843b9..f6035cf0ab 100644 --- a/src/output/render.h +++ b/src/output/render.h @@ -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); /* An iterator for breaking render_pages into smaller chunks. */ struct render_break diff --git a/src/ui/gui/psppire-output-window.c b/src/ui/gui/psppire-output-window.c index 5aba7c90fe..b2ea1103ea 100644 --- a/src/ui/gui/psppire-output-window.c +++ b/src/ui/gui/psppire-output-window.c @@ -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; -- 2.30.2