mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 04:08:13 +02:00
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:
parent
687802cca6
commit
8d3a800b82
5 changed files with 112 additions and 47 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue