Add a start_page function to the paginated_surface_backend.

This allows for any surface using the paginated_surface backend to
easily do stuff at the beginning of each page, (such as writing out
any per-page header necessary).

This replaces some of the per-page state tracking that the PS surface
was doing, (though it still has some left for its optimization of
CLEAR on a blank page).
This commit is contained in:
Carl Worth 2006-04-14 14:46:59 -07:00
parent 687802cca6
commit 8d3a800b82
5 changed files with 112 additions and 47 deletions

View file

@ -44,11 +44,67 @@ typedef enum {
} cairo_paginated_mode_t;
typedef struct _cairo_paginated_surface_backend {
/* Optional. Will be called once for each page.
*
* NOTE: With respect to the order of drawing operations as seen
* by the target, this call will occur before any drawing
* operations for the relevant page. However, with respect to the
* function calls as made by the user, this call will be *after*
* any drawing operations for the page, (that is, it will occur
* during the user's call to cairo_show_page or cairo_copy_page).
*/
cairo_int_status_t
(*start_page) (void *surface);
/* Required. Will be called twice for each page, once with an
* argument of CAIRO_PAGINATED_MODE_ANALYZE and once with
* CAIRO_PAGINATED_MODE_RENDER. See more details in the
* documentation for _cairo_paginated_surface_create below.
*/
void
(*set_paginated_mode) (void *surface,
cairo_paginated_mode_t mode);
(*set_paginated_mode) (void *surface,
cairo_paginated_mode_t mode);
} cairo_paginated_surface_backend_t;
/* A cairo_paginated_surface provides a very convenient wrapper that
* is well-suited for doing the analysis common to most surfaces that
* have paginated output, (that is, things directed at printers, or
* for saving content in files such as PostScript or PDF files).
*
* What the paginated surface does is first save all drawing
* operations for a page into a meta-surface. Then when the user calls
* cairo_show_page, the paginated surface performs the following
* sequence of operations (using the backend functions passed to
* cairo_paginated_surface_create):
*
* 1. Calls start_page (if non NULL). At this point, it is appropriate
* for the target to emit any page-specific header information into
* its output.
*
* 2. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_ANALYZE
*
* 3. Replays the meta-surface to the target surface, (with an
* analysis surface inserted between which watches the return value
* from each operation). This analysis stage is used to decide which
* operations will require fallbacks.
*
* 4. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_RENDER
*
* 5. Replays a subset of the meta-surface operations to the target surface
*
* 6. Replays the remaining operations to an image surface, sets an
* appropriate clip on the target, then paints the resulting image
* surface to the target.
*
* So, the target will see drawing operations during two separate
* stages, (ANALYZE and RENDER). During the ANALYZE phase the target
* should not actually perform any rendering, (for example, if
* performing output to a file, no output should be generated during
* this stage). Instead the drawing functions simply need to return
* CAIRO_STATUS_SUCCESS or CAIRO_INT_STATUS_UNSUPPORTED to indicate
* whether rendering would be supported. And it should do this as
* quickly as possible.
*/
cairo_private cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,

View file

@ -266,11 +266,25 @@ _paint_page (cairo_paginated_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_start_page (cairo_paginated_surface_t *surface)
{
if (! surface->backend->start_page)
return CAIRO_STATUS_SUCCESS;
return (surface->backend->start_page) (surface->target);
}
static cairo_int_status_t
_cairo_paginated_surface_copy_page (void *abstract_surface)
{
cairo_status_t status;
cairo_paginated_surface_t *surface = abstract_surface;
status = _start_page (surface);
if (status)
return status;
_paint_page (surface);
/* XXX: It might make sense to add some suport here for calling
@ -289,8 +303,13 @@ _cairo_paginated_surface_copy_page (void *abstract_surface)
static cairo_int_status_t
_cairo_paginated_surface_show_page (void *abstract_surface)
{
cairo_status_t status;
cairo_paginated_surface_t *surface = abstract_surface;
status = _start_page (surface);
if (status)
return status;
_paint_page (surface);
_cairo_surface_show_page (surface->target);

View file

@ -2134,5 +2134,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
};
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend = {
NULL, /* start_page */
_cairo_pdf_surface_set_paginated_mode
};

View file

@ -96,7 +96,7 @@ typedef struct cairo_ps_surface {
double x_dpi;
double y_dpi;
cairo_bool_t need_start_page;
cairo_bool_t page_is_blank;
int num_pages;
cairo_paginated_mode_t paginated_mode;
@ -574,7 +574,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->y_dpi = PS_SURFACE_DPI_DEFAULT;
surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
surface->need_start_page = TRUE;
surface->page_is_blank = TRUE;
surface->num_pages = 0;
return _cairo_paginated_surface_create (&surface->base,
@ -842,9 +842,11 @@ _cairo_ps_surface_finish (void *abstract_surface)
return status;
}
static void
_cairo_ps_surface_start_page (cairo_ps_surface_t *surface)
static cairo_int_status_t
_cairo_ps_surface_start_page (void *abstract_surface)
{
cairo_ps_surface_t *surface = abstract_surface;
/* Increment before print so page numbers start at 1. */
surface->num_pages++;
_cairo_output_stream_printf (surface->stream,
@ -858,7 +860,7 @@ _cairo_ps_surface_start_page (cairo_ps_surface_t *surface)
1.0/surface->base.device_x_scale,
-1.0/surface->base.device_y_scale);
surface->need_start_page = FALSE;
return _cairo_output_stream_get_status (surface->stream);
}
static void
@ -866,8 +868,6 @@ _cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
{
_cairo_output_stream_printf (surface->stream,
"grestore\n");
surface->need_start_page = TRUE;
}
static cairo_int_status_t
@ -891,8 +891,6 @@ _cairo_ps_surface_show_page (void *abstract_surface)
_cairo_output_stream_printf (surface->stream, "showpage\n");
surface->need_start_page = TRUE;
return CAIRO_STATUS_SUCCESS;
}
@ -1062,11 +1060,6 @@ operation_supported (cairo_ps_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern)
{
/* As a special-case, (see all drawing operations below), we
* optimize away any erasing where nothing has been drawn yet. */
if (surface->need_start_page && op == CAIRO_OPERATOR_CLEAR)
return TRUE;
if (! pattern_supported (pattern))
return FALSE;
@ -1460,9 +1453,6 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
if (surface->need_start_page)
_cairo_ps_surface_start_page (surface);
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_intersect_clip_path\n");
@ -1528,6 +1518,12 @@ _cairo_ps_surface_paint (void *abstract_surface,
cairo_output_stream_t *stream = surface->stream;
cairo_ps_surface_path_info_t info;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
@ -1541,13 +1537,6 @@ _cairo_ps_surface_paint (void *abstract_surface,
assert (pattern_operation_supported (op, source));
*/
if (surface->need_start_page) {
/* Optimize away erasing of nothing. */
if (op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
_cairo_ps_surface_start_page (surface);
}
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_paint\n");
@ -1613,18 +1602,17 @@ _cairo_ps_surface_stroke (void *abstract_surface,
cairo_int_status_t status;
cairo_ps_surface_path_info_t info;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
assert (operation_supported (surface, op, source));
if (surface->need_start_page) {
/* Optimize away erasing of nothing. */
if (op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
_cairo_ps_surface_start_page (surface);
}
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_stroke\n");
@ -1693,18 +1681,17 @@ _cairo_ps_surface_fill (void *abstract_surface,
cairo_ps_surface_path_info_t info;
const char *ps_operator;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
assert (operation_supported (surface, op, source));
if (surface->need_start_page) {
/* Optimize away erasing of nothing. */
if (op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
_cairo_ps_surface_start_page (surface);
}
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_fill\n");
@ -1763,18 +1750,17 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
cairo_ps_font_t *ps_font;
cairo_ps_glyph_t *ps_glyph;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
assert (operation_supported (surface, op, source));
if (surface->need_start_page) {
/* Optimize away erasing of nothing. */
if (op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
_cairo_ps_surface_start_page (surface);
}
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_show_glyphs\n");
status = _cairo_ps_font_find (surface, scaled_font, &ps_font);
@ -1828,6 +1814,7 @@ _cairo_ps_surface_set_paginated_mode (void *abstract_surface,
cairo_ps_surface_t *surface = abstract_surface;
surface->paginated_mode = paginated_mode;
surface->page_is_blank = TRUE;
}
static const cairo_surface_backend_t cairo_ps_surface_backend = {
@ -1865,5 +1852,6 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
};
static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend = {
_cairo_ps_surface_start_page,
_cairo_ps_surface_set_paginated_mode
};

View file

@ -279,5 +279,6 @@ static const cairo_surface_backend_t test_paginated_surface_backend = {
};
static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend = {
NULL, /* start_page */
_test_paginated_surface_set_paginated_mode
};