From: Ben Pfaff Date: Sat, 13 Sep 2014 17:24:59 +0000 (-0700) Subject: render: Introduce render_pager to factor out code from drivers. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pspp;a=commitdiff_plain;h=00e10850124d68e722d9fba5b8c9467fff6863a3 render: Introduce render_pager to factor out code from drivers. The render_break abstraction requires quite a bit of assistance from drivers. By introducing a high-level render_pager abstraction we factor out a bit of common code. Future refinements will allow putting more and more functional in the common "render" interface. --- diff --git a/src/output/ascii.c b/src/output/ascii.c index 251e22d443..48cad0f234 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -424,7 +424,7 @@ ascii_output_table_item (struct ascii_driver *a, const char *caption = table_item_get_caption (table_item); struct render_params params; struct render_page *page; - struct render_break x_break; + struct render_pager *p; int caption_height; int i; @@ -463,54 +463,45 @@ ascii_output_table_item (struct ascii_driver *a, return; page = render_page_create (¶ms, table_item_get_table (table_item)); - for (render_break_init (&x_break, page, H); - render_break_has_next (&x_break); ) + p = render_pager_create (page); + while (render_pager_has_next (p)) { - struct render_page *x_slice; - struct render_break y_break; - - x_slice = render_break_next (&x_break, a->width); - for (render_break_init (&y_break, x_slice, V); - render_break_has_next (&y_break); ) + int space = a->length - (a->y + (a->y > 0) + caption_height); + struct render_page *slice = render_pager_next (p, space); + if (!slice) { - struct render_page *y_slice; - int space; - - if (a->y > 0) - a->y++; - - space = a->length - a->y - caption_height; - if (render_break_next_size (&y_break) > space) + assert (a->y > 0); + ascii_close_page (a); + if (!ascii_open_page (a)) { - assert (a->y > 0); - ascii_close_page (a); - if (!ascii_open_page (a)) - return; - continue; + render_pager_destroy (p); + return; } + continue; + } - y_slice = render_break_next (&y_break, space); - if (caption_height) - { - struct table_cell cell; - int bb[TABLE_N_AXES][2]; - - ascii_init_caption_cell (caption, &cell); - bb[H][0] = 0; - bb[H][1] = a->width; - bb[V][0] = 0; - bb[V][1] = caption_height; - ascii_draw_cell (a, &cell, bb, bb); - a->y += caption_height; - caption_height = 0; - } - render_page_draw (y_slice); - a->y += render_page_get_size (y_slice, V); - render_page_unref (y_slice); + if (a->y > 0) + a->y++; + + if (caption_height) + { + struct table_cell cell; + int bb[TABLE_N_AXES][2]; + + ascii_init_caption_cell (caption, &cell); + bb[H][0] = 0; + bb[H][1] = a->width; + bb[V][0] = 0; + bb[V][1] = caption_height; + ascii_draw_cell (a, &cell, bb, bb); + a->y += caption_height; + caption_height = 0; } - render_break_destroy (&y_break); + render_page_draw (slice); + a->y += render_page_get_size (slice, V); + render_page_unref (slice); } - render_break_destroy (&x_break); + render_pager_destroy (p); } static void diff --git a/src/output/cairo.c b/src/output/cairo.c index 1c03db84fb..87bca8cb44 100644 --- a/src/output/cairo.c +++ b/src/output/cairo.c @@ -1436,8 +1436,7 @@ struct xr_table_state { struct xr_render_fsm fsm; struct table_item *table_item; - struct render_break x_break; - struct render_break y_break; + struct render_pager *p; int caption_height; }; @@ -1446,31 +1445,17 @@ xr_table_render (struct xr_render_fsm *fsm, struct xr_driver *xr) { struct xr_table_state *ts = UP_CAST (fsm, struct xr_table_state, fsm); - for (;;) + while (render_pager_has_next (ts->p)) { - struct render_page *y_slice; - int space; + int space = xr->length - xr->y - ts->caption_height; + struct render_page *slice = render_pager_next (ts->p, space); - while (!render_break_has_next (&ts->y_break)) - { - struct render_page *x_slice; - - render_break_destroy (&ts->y_break); - if (!render_break_has_next (&ts->x_break)) - return false; - - x_slice = render_break_next (&ts->x_break, xr->width); - render_break_init (&ts->y_break, x_slice, V); - } - - space = xr->length - xr->y; - if (render_break_next_size (&ts->y_break) > space) + if (!slice) { assert (xr->y > 0); return true; } - y_slice = render_break_next (&ts->y_break, space); if (ts->caption_height) { if (xr->cairo) @@ -1482,10 +1467,11 @@ xr_table_render (struct xr_render_fsm *fsm, struct xr_driver *xr) } if (xr->cairo) - render_page_draw (y_slice); - xr->y += render_page_get_size (y_slice, V); - render_page_unref (y_slice); + render_page_draw (slice); + xr->y += render_page_get_size (slice, V); + render_page_unref (slice); } + return false; } static void @@ -1494,8 +1480,7 @@ xr_table_destroy (struct xr_render_fsm *fsm) struct xr_table_state *ts = UP_CAST (fsm, struct xr_table_state, fsm); table_item_unref (ts->table_item); - render_break_destroy (&ts->x_break); - render_break_destroy (&ts->y_break); + render_pager_destroy (ts->p); free (ts); } @@ -1518,8 +1503,7 @@ xr_render_table (struct xr_driver *xr, const struct table_item *table_item) &caption_width, &ts->caption_height); xr->params->size[V] = xr->length - ts->caption_height; - render_break_init (&ts->x_break, page, H); - render_break_init_empty (&ts->y_break); + ts->p = render_pager_create (page); return &ts->fsm; } diff --git a/src/output/render.c b/src/output/render.c index 503d5f692d..e1cec909f8 100644 --- a/src/output/render.c +++ b/src/output/render.c @@ -1059,6 +1059,16 @@ render_page_draw_region (const struct render_page *page, /* Breaking up tables to fit on a page. */ +/* An iterator for breaking render_pages into smaller chunks. */ +struct render_break + { + struct render_page *page; /* Page being broken up. */ + enum table_axis axis; /* Axis along which 'page' is being broken. */ + int z; /* Next cell along 'axis'. */ + int pixel; /* Pixel offset within cell 'z' (usually 0). */ + int hw; /* Width of headers of 'page' along 'axis'. */ + }; + static int needed_size (const struct render_break *, int cell); static bool cell_is_breakable (const struct render_break *, int cell); static struct render_page *render_page_select (const struct render_page *, @@ -1070,7 +1080,7 @@ static struct render_page *render_page_select (const struct render_page *, Ownership of PAGE is transferred to B. The caller must use render_page_ref() if it needs to keep a copy of PAGE. */ -void +static void render_break_init (struct render_break *b, struct render_page *page, enum table_axis axis) { @@ -1083,7 +1093,7 @@ render_break_init (struct render_break *b, struct render_page *page, /* Initializes B as a render_break structure for which render_break_has_next() always returns false. */ -void +static void render_break_init_empty (struct render_break *b) { b->page = NULL; @@ -1094,7 +1104,7 @@ render_break_init_empty (struct render_break *b) } /* Frees B and unrefs the render_page that it owns. */ -void +static void render_break_destroy (struct render_break *b) { if (b != NULL) @@ -1106,7 +1116,7 @@ render_break_destroy (struct render_break *b) /* Returns true if B still has cells that are yet to be returned, false if all of B's page has been processed. */ -bool +static bool render_break_has_next (const struct render_break *b) { const struct render_page *page = b->page; @@ -1115,25 +1125,12 @@ render_break_has_next (const struct render_break *b) return page != NULL && b->z < page->n[axis] - page->h[axis][1]; } -/* Returns the minimum SIZE argument that, if passed to render_break_next(), - will avoid a null return value (if cells are still left). */ -int -render_break_next_size (const struct render_break *b) -{ - const struct render_page *page = b->page; - enum table_axis axis = b->axis; - - return (!render_break_has_next (b) ? 0 - : !cell_is_breakable (b, b->z) ? needed_size (b, b->z + 1) - : b->hw + page->params->font_size[axis]); -} - /* Returns a new render_page that is up to SIZE pixels wide along B's axis. Returns a null pointer if B has already been completely broken up, or if SIZE is too small to reasonably render any cells. The latter will never happen if SIZE is at least as large as the page size passed to render_page_create() along B's axis. */ -struct render_page * +static struct render_page * render_break_next (struct render_break *b, int size) { const struct render_page *page = b->page; @@ -1299,6 +1296,78 @@ cell_is_breakable (const struct render_break *b, int cell) return cell_width (page, axis, cell) >= page->params->min_break[axis]; } +/* render_pager. */ + +struct render_pager + { + int width; + struct render_break x_break; + struct render_break y_break; + }; + +/* Creates and returns a new render_pager for breaking PAGE into smaller + chunks. Takes ownership of PAGE. */ +struct render_pager * +render_pager_create (struct render_page *page) +{ + struct render_pager *p = xmalloc (sizeof *p); + p->width = page->params->size[H]; + render_break_init (&p->x_break, page, H); + render_break_init_empty (&p->y_break); + return p; +} + +/* Destroys P. */ +void +render_pager_destroy (struct render_pager *p) +{ + if (p) + { + render_break_destroy (&p->x_break); + render_break_destroy (&p->y_break); + free (p); + } +} + +/* Returns true if P has content remaining to render, false if rendering is + done. */ +bool +render_pager_has_next (const struct render_pager *p_) +{ + struct render_pager *p = CONST_CAST (struct render_pager *, p_); + + while (!render_break_has_next (&p->y_break)) + { + render_break_destroy (&p->y_break); + if (render_break_has_next (&p->x_break)) + { + struct render_page *x_slice; + + x_slice = render_break_next (&p->x_break, p->width); + render_break_init (&p->y_break, x_slice, V); + } + else + { + render_break_init_empty (&p->y_break); + return false; + } + } + return true; +} + +/* Returns the next render_page from P to render in a space that has vertical + size SPACE and the horizontal size as specified in render_params passed to + render_page_create(). The caller takes ownership of the returned + render_page. If no content remains to render, or if SPACE is too small to + render anything, returns NULL. */ +struct render_page * +render_pager_next (struct render_pager *p, int space) +{ + return (render_pager_has_next (p) + ? render_break_next (&p->y_break, space) + : NULL); +} + /* render_page_select() and helpers. */ struct render_page_selection diff --git a/src/output/render.h b/src/output/render.h index f2ded79d6c..eed29e8512 100644 --- a/src/output/render.h +++ b/src/output/render.h @@ -101,7 +101,7 @@ struct render_params /* A "page" of content that is ready to be rendered. A page's size is not limited to the size passed in as part of render_params. - Use render_break (see below) to break a too-big render_page into smaller + Use render_pager (see below) to break a render_page into smaller render_pages that will fit in the available space. */ struct render_page *render_page_create (const struct render_params *, const struct table *); @@ -117,22 +117,11 @@ void render_page_draw_region (const struct render_page *, int render_page_get_best_breakpoint (const struct render_page *, int height); /* An iterator for breaking render_pages into smaller chunks. */ -struct render_break - { - struct render_page *page; /* Page being broken up. */ - enum table_axis axis; /* Axis along which 'page' is being broken. */ - int z; /* Next cell along 'axis'. */ - int pixel; /* Pixel offset within cell 'z' (usually 0). */ - int hw; /* Width of headers of 'page' along 'axis'. */ - }; -void render_break_init (struct render_break *, struct render_page *, - enum table_axis); -void render_break_init_empty (struct render_break *); -void render_break_destroy (struct render_break *); +struct render_pager *render_pager_create (struct render_page *); +void render_pager_destroy (struct render_pager *); -bool render_break_has_next (const struct render_break *); -int render_break_next_size (const struct render_break *); -struct render_page *render_break_next (struct render_break *, int size); +bool render_pager_has_next (const struct render_pager *); +struct render_page *render_pager_next (struct render_pager *, int height); #endif /* output/render.h */