Add _cairo_pdf_operators_flush()

The optimizations planned for pdf-operators will mean that it will no
longer emit complete operations on each call to
fill/stroke/show_glyphs. For example a call to _show_glyphs() may not
finish the text operation to allow a subsequent call to _show_glyphs()
to be merged into the same text object.

A flush function is required to force pdf_operators to complete the
current operation before the pdf surface can emit any pdf operators.
This commit is contained in:
Adrian Johnson 2008-06-03 20:55:03 +09:30
parent e1bc97a7e5
commit fd42b74a4f
4 changed files with 142 additions and 15 deletions

View file

@ -63,7 +63,7 @@ _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *cairo_to_pdf,
cairo_scaled_font_subsets_t *font_subsets);
cairo_private void
cairo_private cairo_status_t
_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators);
cairo_private void
@ -80,6 +80,9 @@ cairo_private void
_cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *cairo_to_pdf);
cairo_private cairo_int_status_t
_cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators);
cairo_private cairo_int_status_t
_cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,

View file

@ -60,9 +60,10 @@ _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
pdf_operators->use_font_subset_closure = NULL;
}
void
cairo_status_t
_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators)
{
return _cairo_pdf_operators_flush (pdf_operators);
}
void
@ -74,6 +75,10 @@ _cairo_pdf_operators_set_font_subsets_callback (cairo_pdf_operators_t *pdf
pdf_operators->use_font_subset_closure = closure;
}
/* Change the output stream to a different stream.
* _cairo_pdf_operators_flush() should always be called before calling
* this function.
*/
void
_cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream)
@ -88,6 +93,23 @@ _cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operato
pdf_operators->cairo_to_pdf = *cairo_to_pdf;
}
/* Finish writing out any pending commands to the stream. This
* function must be called by the surface before emitting anything
* into the PDF stream.
*
* pdf_operators may leave the emitted PDF for some operations
* unfinished in case subsequent operations can be merged. This
* function will finish off any incomplete operation so the stream
* will be in a state where the surface may emit it's own PDF
* operations (eg changing patterns).
*
*/
cairo_int_status_t
_cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators)
{
return CAIRO_STATUS_SUCCESS;
}
/* A word wrap stream can be used as a filter to do word wrapping on
* top of an existing output stream. The word wrapping is quite
* simple, using isspace to determine characters that separate

View file

@ -904,6 +904,10 @@ _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
if (! surface->pdf_stream.active)
return CAIRO_STATUS_SUCCESS;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
if (surface->pdf_stream.compressed) {
status = _cairo_output_stream_destroy (surface->output);
surface->output = surface->pdf_stream.old_output;
@ -1045,6 +1049,10 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
assert (surface->pdf_stream.active == FALSE);
assert (surface->group_stream.active == TRUE);
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
if (surface->compress_content) {
status = _cairo_output_stream_destroy (surface->group_stream.stream);
surface->group_stream.stream = NULL;
@ -1128,6 +1136,10 @@ _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
assert (surface->pdf_stream.active == TRUE);
assert (surface->group_stream.active == FALSE);
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output, "Q\n");
status = _cairo_pdf_surface_close_stream (surface);
if (status)
@ -1193,7 +1205,10 @@ _cairo_pdf_surface_finish (void *abstract_surface)
"%%%%EOF\n",
offset);
_cairo_pdf_operators_fini (&surface->pdf_operators);
status2 = _cairo_pdf_operators_fini (&surface->pdf_operators);
/* pdf_operators has already been flushed when the last stream was
* closed so we should never be writing anything here. */
assert(status2 == CAIRO_STATUS_SUCCESS);
/* close any active streams still open due to fatal errors */
status2 = _cairo_pdf_surface_close_stream (surface);
@ -2577,6 +2592,10 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
cairo_bool_t is_solid_color = FALSE;
cairo_color_t *solid_color;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
@ -2646,12 +2665,21 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
return _cairo_output_stream_get_status (surface->output);
}
static void
static cairo_int_status_t
_cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface)
{
if (surface->select_pattern_gstate_saved)
cairo_int_status_t status;
if (surface->select_pattern_gstate_saved) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output, "Q\n");
}
surface->select_pattern_gstate_saved = FALSE;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@ -2700,8 +2728,13 @@ _cairo_pdf_surface_intersect_clip_path (void *abstract_surface,
cairo_antialias_t antialias)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_int_status_t status;
if (path == NULL) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output, "Q q\n");
return CAIRO_STATUS_SUCCESS;
}
@ -3759,7 +3792,9 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
"0 0 %f %f re f\n",
surface->width, surface->height);
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
status = _cairo_pdf_surface_close_group (surface, &mask_group);
@ -3812,7 +3847,9 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
"0 0 %f %f re f\n",
surface->width, surface->height);
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
status = _cairo_pdf_surface_close_group (surface, NULL);
@ -3910,7 +3947,10 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
status = _cairo_pdf_surface_close_group (surface, NULL);
_cairo_pdf_surface_set_size_internal (surface,
@ -4297,6 +4337,10 @@ _cairo_pdf_surface_paint (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4310,7 +4354,9 @@ _cairo_pdf_surface_paint (void *abstract_surface,
"0 0 %f %f re f\n",
surface->width, surface->height);
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);
@ -4373,6 +4419,10 @@ _cairo_pdf_surface_mask (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
group->group_res.id,
@ -4441,6 +4491,10 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4458,7 +4512,9 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);
@ -4525,6 +4581,10 @@ _cairo_pdf_surface_fill (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4540,7 +4600,9 @@ _cairo_pdf_surface_fill (void *abstract_surface,
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);
@ -4627,7 +4689,9 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
return _cairo_output_stream_get_status (surface->output);
}
@ -4689,6 +4753,10 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4705,7 +4773,9 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);

View file

@ -1327,19 +1327,30 @@ _cairo_ps_surface_start_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
static void
static cairo_int_status_t
_cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
{
cairo_int_status_t status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->stream,
"Q\n");
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_ps_surface_show_page (void *abstract_surface)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_int_status_t status;
_cairo_ps_surface_end_page (surface);
status = _cairo_ps_surface_end_page (surface);
if (status)
return status;
_cairo_output_stream_printf (surface->stream, "showpage\n");
@ -2078,6 +2089,10 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->stream,
" Q\n");
surface->content = old_content;
@ -2835,6 +2850,10 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
* different pattern. */
cairo_status_t status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
_cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
@ -2875,6 +2894,7 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
cairo_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
@ -2885,6 +2905,10 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
#endif
if (path == NULL) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (stream, "Q q\n");
return CAIRO_STATUS_SUCCESS;
}
@ -2948,6 +2972,10 @@ _cairo_ps_surface_paint (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_NONE ||
source->extend == CAIRO_EXTEND_PAD))
@ -3040,6 +3068,10 @@ _cairo_ps_surface_fill (void *abstract_surface,
(source->extend == CAIRO_EXTEND_NONE ||
source->extend == CAIRO_EXTEND_PAD))
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->stream, "q\n");
status = _cairo_pdf_operators_clip (&surface->pdf_operators,