summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2011-12-06 20:46:49 +1030
committerAdrian Johnson <ajohnson@redneon.com>2011-12-06 20:46:49 +1030
commit79f430e7ada4384390dc03caab2af0ffc1603885 (patch)
treee99997bf73512d55cfb197362e1e0f74eb7795cd
parentdee48f0dcadf96e88872894a1cef280905cd255f (diff)
pdf: avoid using pdf patterns to paint/fill opaque linear/radial gradients
Patterns are slower and use more memory to print. For painting and filling we can use the shading operator to draw gradients.
-rw-r--r--src/cairo-pdf-surface-private.h2
-rw-r--r--src/cairo-pdf-surface.c237
2 files changed, 205 insertions, 34 deletions
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 08620e6b2..1e174fe16 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -60,6 +60,7 @@ typedef struct _cairo_pdf_group_resources {
cairo_array_t alphas;
cairo_array_t smasks;
cairo_array_t patterns;
+ cairo_array_t shadings;
cairo_array_t xobjects;
cairo_array_t fonts;
} cairo_pdf_group_resources_t;
@@ -89,6 +90,7 @@ typedef struct _cairo_pdf_pattern {
cairo_pattern_t *pattern;
cairo_pdf_resource_t pattern_res;
cairo_pdf_resource_t gstate_res;
+ cairo_bool_t is_shading;
} cairo_pdf_pattern_t;
typedef enum _cairo_pdf_operation {
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index f61638ccd..5d3e3af0b 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -715,6 +715,7 @@ _cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res)
_cairo_array_init (&res->alphas, sizeof (double));
_cairo_array_init (&res->smasks, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&res->patterns, sizeof (cairo_pdf_resource_t));
+ _cairo_array_init (&res->shadings, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&res->xobjects, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&res->fonts, sizeof (cairo_pdf_font_t));
}
@@ -725,6 +726,7 @@ _cairo_pdf_group_resources_fini (cairo_pdf_group_resources_t *res)
_cairo_array_fini (&res->alphas);
_cairo_array_fini (&res->smasks);
_cairo_array_fini (&res->patterns);
+ _cairo_array_fini (&res->shadings);
_cairo_array_fini (&res->xobjects);
_cairo_array_fini (&res->fonts);
}
@@ -740,6 +742,7 @@ _cairo_pdf_group_resources_clear (cairo_pdf_group_resources_t *res)
_cairo_array_truncate (&res->alphas, 0);
_cairo_array_truncate (&res->smasks, 0);
_cairo_array_truncate (&res->patterns, 0);
+ _cairo_array_truncate (&res->shadings, 0);
_cairo_array_truncate (&res->xobjects, 0);
_cairo_array_truncate (&res->fonts, 0);
}
@@ -796,6 +799,14 @@ _cairo_pdf_surface_add_pattern (cairo_pdf_surface_t *surface,
}
static cairo_status_t
+_cairo_pdf_surface_add_shading (cairo_pdf_surface_t *surface,
+ cairo_pdf_resource_t shading)
+{
+ return _cairo_array_append (&(surface->resources.shadings), &shading);
+}
+
+
+static cairo_status_t
_cairo_pdf_surface_add_xobject (cairo_pdf_surface_t *surface,
cairo_pdf_resource_t xobject)
{
@@ -908,7 +919,7 @@ _cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t *surface,
{
int num_alphas, num_smasks, num_resources, i;
double alpha;
- cairo_pdf_resource_t *smask, *pattern, *xobject;
+ cairo_pdf_resource_t *smask, *pattern, *shading, *xobject;
cairo_pdf_font_t *font;
_cairo_output_stream_printf (surface->output, "<<\n");
@@ -960,6 +971,21 @@ _cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t *surface,
" >>\n");
}
+ num_resources = _cairo_array_num_elements (&res->shadings);
+ if (num_resources > 0) {
+ _cairo_output_stream_printf (surface->output,
+ " /Shading <<");
+ for (i = 0; i < num_resources; i++) {
+ shading = _cairo_array_index (&res->shadings, i);
+ _cairo_output_stream_printf (surface->output,
+ " /sh%d %d 0 R",
+ shading->id, shading->id);
+ }
+
+ _cairo_output_stream_printf (surface->output,
+ " >>\n");
+ }
+
num_resources = _cairo_array_num_elements (&res->xobjects);
if (num_resources > 0) {
_cairo_output_stream_printf (surface->output,
@@ -1282,15 +1308,18 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
}
static cairo_status_t
-_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
- const cairo_pattern_t *pattern,
- const cairo_rectangle_int_t *extents,
- cairo_pdf_resource_t *pattern_res,
- cairo_pdf_resource_t *gstate_res)
+_cairo_pdf_surface_add_pdf_pattern_or_shading (cairo_pdf_surface_t *surface,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ cairo_bool_t is_shading,
+ cairo_pdf_resource_t *pattern_res,
+ cairo_pdf_resource_t *gstate_res)
{
cairo_pdf_pattern_t pdf_pattern;
cairo_status_t status;
+ pdf_pattern.is_shading = is_shading;
+
/* Solid colors are emitted into the content stream */
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
pattern_res->id = 0;
@@ -1363,6 +1392,36 @@ _get_bbox_from_extents (double surface_height,
}
static cairo_status_t
+_cairo_pdf_surface_add_pdf_shading (cairo_pdf_surface_t *surface,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ cairo_pdf_resource_t *shading_res,
+ cairo_pdf_resource_t *gstate_res)
+{
+ return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface,
+ pattern,
+ extents,
+ TRUE,
+ shading_res,
+ gstate_res);
+}
+
+static cairo_status_t
+_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ cairo_pdf_resource_t *pattern_res,
+ cairo_pdf_resource_t *gstate_res)
+{
+ return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface,
+ pattern,
+ extents,
+ FALSE,
+ pattern_res,
+ gstate_res);
+}
+
+static cairo_status_t
_cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface,
cairo_pdf_resource_t *resource,
cairo_bool_t compressed,
@@ -3270,15 +3329,19 @@ _cairo_pdf_surface_output_gradient (cairo_pdf_surface_t *surface,
cairo_pdf_resource_t color_function)
{
_cairo_output_stream_printf (surface->output,
- "%d 0 obj\n"
- "<< /Type /Pattern\n"
- " /PatternType 2\n"
- " /Matrix [ %f %f %f %f %f %f ]\n"
- " /Shading\n",
- pattern_resource.id,
- pat_to_pdf->xx, pat_to_pdf->yx,
- pat_to_pdf->xy, pat_to_pdf->yy,
- pat_to_pdf->x0, pat_to_pdf->y0);
+ "%d 0 obj\n",
+ pattern_resource.id);
+
+ if (!pdf_pattern->is_shading) {
+ _cairo_output_stream_printf (surface->output,
+ "<< /Type /Pattern\n"
+ " /PatternType 2\n"
+ " /Matrix [ %f %f %f %f %f %f ]\n"
+ " /Shading\n",
+ pat_to_pdf->xx, pat_to_pdf->yx,
+ pat_to_pdf->xy, pat_to_pdf->yy,
+ pat_to_pdf->x0, pat_to_pdf->y0);
+ }
if (pdf_pattern->pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
_cairo_output_stream_printf (surface->output,
@@ -3314,10 +3377,14 @@ _cairo_pdf_surface_output_gradient (cairo_pdf_surface_t *surface,
_cairo_output_stream_printf (surface->output,
" /Function %d 0 R\n"
- " >>\n"
- ">>\n"
- "endobj\n",
+ " >>\n",
color_function.id);
+
+ if (!pdf_pattern->is_shading) {
+ _cairo_output_stream_printf (surface->output,
+ ">>\n"
+ "endobj\n");
+ }
}
static cairo_status_t
@@ -3741,6 +3808,114 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
}
static cairo_status_t
+_cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t *surface,
+ const cairo_pattern_t *source,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_pdf_resource_t shading_res, gstate_res;
+ cairo_matrix_t pat_to_pdf;
+ cairo_status_t status;
+ int alpha;
+
+ status = _cairo_pdf_surface_add_pdf_shading (surface, source,
+ extents,
+ &shading_res, &gstate_res);
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+ return CAIRO_STATUS_SUCCESS;
+ if (unlikely (status))
+ return status;
+
+ assert (gstate_res.id == 0);
+
+ pat_to_pdf = source->matrix;
+ status = cairo_matrix_invert (&pat_to_pdf);
+ /* cairo_pattern_set_matrix ensures the matrix is invertible */
+ assert (status == CAIRO_STATUS_SUCCESS);
+ cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf);
+
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ if (unlikely (status))
+ return status;
+
+ if (! _cairo_matrix_is_identity (&pat_to_pdf)) {
+ _cairo_output_stream_printf (surface->output,
+ "%f %f %f %f %f %f cm\n",
+ pat_to_pdf.xx, pat_to_pdf.yx,
+ pat_to_pdf.xy, pat_to_pdf.yy,
+ pat_to_pdf.x0, pat_to_pdf.y0);
+ }
+
+ status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_pdf_surface_add_shading (surface, shading_res);
+ if (unlikely (status))
+ return status;
+
+
+ _cairo_output_stream_printf (surface->output,
+ "/a%d gs /sh%d sh\n",
+ alpha,
+ shading_res.id);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t *surface,
+ const cairo_pattern_t *source,
+ const cairo_rectangle_int_t *extents,
+ cairo_bool_t mask)
+{
+ switch (source->type) {
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return _cairo_pdf_surface_paint_surface_pattern (surface,
+ (cairo_surface_pattern_t *)source,
+ extents,
+ mask);
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ case CAIRO_PATTERN_TYPE_MESH:
+ return _cairo_pdf_surface_paint_gradient (surface,
+ source,
+ extents);
+
+ case CAIRO_PATTERN_TYPE_SOLID:
+ default:
+ ASSERT_NOT_REACHED;
+ return CAIRO_STATUS_SUCCESS;
+ }
+}
+
+static cairo_bool_t
+_can_paint_pattern (const cairo_pattern_t *pattern)
+{
+ double min_alpha;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return FALSE;
+
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return (pattern->extend == CAIRO_EXTEND_NONE ||
+ pattern->extend == CAIRO_EXTEND_PAD);
+
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ _cairo_pattern_alpha_range (pattern, &min_alpha, NULL);
+ return CAIRO_ALPHA_IS_OPAQUE (min_alpha);
+
+ case CAIRO_PATTERN_TYPE_MESH:
+ return FALSE;
+
+ default:
+ ASSERT_NOT_REACHED;
+ return FALSE;
+ }
+}
+
+static cairo_status_t
_cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface,
cairo_operator_t op)
{
@@ -6041,15 +6216,12 @@ _cairo_pdf_surface_paint (void *abstract_surface,
if (unlikely (status))
goto cleanup;
- if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
- (source->extend == CAIRO_EXTEND_NONE ||
- source->extend == CAIRO_EXTEND_PAD))
- {
+ if (_can_paint_pattern (source)) {
_cairo_output_stream_printf (surface->output, "q\n");
- status = _cairo_pdf_surface_paint_surface_pattern (surface,
- (cairo_surface_pattern_t *) source,
- &extents.bounded,
- FALSE);
+ status = _cairo_pdf_surface_paint_pattern (surface,
+ source,
+ &extents.bounded,
+ FALSE);
if (unlikely (status))
goto cleanup;
@@ -6458,10 +6630,7 @@ _cairo_pdf_surface_fill (void *abstract_surface,
if (unlikely (status))
goto cleanup;
- if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
- (source->extend == CAIRO_EXTEND_NONE ||
- source->extend == CAIRO_EXTEND_PAD))
- {
+ if (_can_paint_pattern (source)) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
goto cleanup;
@@ -6473,10 +6642,10 @@ _cairo_pdf_surface_fill (void *abstract_surface,
if (unlikely (status))
goto cleanup;
- status = _cairo_pdf_surface_paint_surface_pattern (surface,
- (cairo_surface_pattern_t *) source,
- &extents.bounded,
- FALSE);
+ status = _cairo_pdf_surface_paint_pattern (surface,
+ source,
+ &extents.bounded,
+ FALSE);
if (unlikely (status))
goto cleanup;