[cairo-commit] src/cairo-pattern.c src/cairo-pattern-private.h src/cairo-pdf-surface.c src/cairo-pdf-surface-private.h
Adrian Johnson
ajohnson at kemper.freedesktop.org
Mon Oct 23 20:32:26 UTC 2017
src/cairo-pattern-private.h | 5 ++
src/cairo-pattern.c | 53 ++++++++++++++++++++++++++++
src/cairo-pdf-surface-private.h | 1
src/cairo-pdf-surface.c | 74 +++++++++++++++++++++++++++++++---------
4 files changed, 117 insertions(+), 16 deletions(-)
New commits:
commit 378e8e2f59a109a40da8e40893652a4c003a4dc7
Author: Adrian Johnson <ajohnson at redneon.com>
Date: Tue Oct 24 07:01:14 2017 +1030
pdf: set ca/CA instead of using an smask when the mask has constant alpha
diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h
index ad7e2e77..98f3be03 100644
--- a/src/cairo-pattern-private.h
+++ b/src/cairo-pattern-private.h
@@ -256,6 +256,11 @@ _cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient,
const cairo_rectangle_int_t *extents,
cairo_color_t *color);
+cairo_bool_t
+_cairo_pattern_is_constant_alpha (const cairo_pattern_t *abstract_pattern,
+ const cairo_rectangle_int_t *extents,
+ double *alpha);
+
cairo_private void
_cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient,
double max_value,
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 7c2d5d31..11637fca 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -3134,6 +3134,59 @@ _cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient,
return TRUE;
}
+/**
+ * _cairo_pattern_is_constant_alpha:
+ *
+ * Convenience function to determine whether a pattern has constant
+ * alpha within the given extents. In this case the alpha argument is
+ * initialized to the alpha within the extents.
+ *
+ * Return value: %TRUE if the pattern has constant alpha.
+ **/
+cairo_bool_t
+_cairo_pattern_is_constant_alpha (const cairo_pattern_t *abstract_pattern,
+ const cairo_rectangle_int_t *extents,
+ double *alpha)
+{
+ const cairo_pattern_union_t *pattern;
+ cairo_color_t color;
+
+ if (_cairo_pattern_is_clear (abstract_pattern)) {
+ *alpha = 0.0;
+ return TRUE;
+ }
+
+ if (_cairo_pattern_is_opaque (abstract_pattern, extents)) {
+ *alpha = 1.0;
+ return TRUE;
+ }
+
+ pattern = (cairo_pattern_union_t *) abstract_pattern;
+ switch (pattern->base.type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ *alpha = pattern->solid.color.alpha;
+ return TRUE;
+
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ if (_cairo_gradient_pattern_is_solid (&pattern->gradient.base, extents, &color)) {
+ *alpha = color.alpha;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+ /* TODO: need to test these as well */
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+ case CAIRO_PATTERN_TYPE_MESH:
+ return FALSE;
+ }
+
+ ASSERT_NOT_REACHED;
+ return FALSE;
+}
+
static cairo_bool_t
_mesh_is_clear (const cairo_mesh_pattern_t *mesh)
{
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 98f0cfdd..75d5259c 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -76,6 +76,7 @@ typedef struct _cairo_pdf_source_surface_entry {
cairo_bool_t interpolate;
cairo_bool_t stencil_mask;
cairo_bool_t smask;
+ cairo_bool_t need_transp_group;
cairo_pdf_resource_t surface_res;
cairo_pdf_resource_t smask_res;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index fa40bc30..d0bb953a 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1456,6 +1456,7 @@ _get_source_surface_extents (cairo_surface_t *source,
* @filter: [in] filter type of the source pattern
* @stencil_mask: [in] if true, the surface will be written to the PDF as an /ImageMask
* @smask: [in] if true, only the alpha channel will be written (images only)
+ * @need_transp_group: [in] if true and an XObject is used, make it a Transparency group
* @extents: [in] extents of the operation that is using this source
* @smask_res: [in] if not NULL, the image written will specify this resource as the smask for
* the image (images only)
@@ -1482,6 +1483,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
cairo_filter_t filter,
cairo_bool_t stencil_mask,
cairo_bool_t smask,
+ cairo_bool_t need_transp_group,
const cairo_rectangle_int_t *extents,
cairo_pdf_resource_t *smask_res,
cairo_pdf_source_surface_entry_t **pdf_source,
@@ -1600,6 +1602,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
surface_entry->interpolate = interpolate;
surface_entry->stencil_mask = stencil_mask;
surface_entry->smask = smask;
+ surface_entry->need_transp_group = need_transp_group;
surface_entry->unique_id_length = unique_id_length;
surface_entry->unique_id = unique_id;
if (smask_res)
@@ -2467,6 +2470,7 @@ _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surfa
source->filter,
FALSE, /* stencil mask */
FALSE, /* smask */
+ FALSE, /* need_transp_group */
extents,
NULL, /* smask_res */
pdf_source,
@@ -3388,12 +3392,16 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
}
/* We can optimize away the transparency group allowing the viewer
- * to replay the group in place when all operators are OVER and the
- * recording contains only opaque and/or clear alpha.
+ * to replay the group in place when:
+ * - ca/CA when painting this groups is 1.0 (need_transp_group is FALSE),
+ * - all operators are OVER, and
+ * - the recording contains only opaque and/or clear alpha.
*/
- transparency_group = !(pdf_source->hash_entry->operator == CAIRO_OPERATOR_OVER &&
+ transparency_group = pdf_source->hash_entry->need_transp_group ||
+ !(pdf_source->hash_entry->operator == CAIRO_OPERATOR_OVER &&
_cairo_recording_surface_has_only_bilevel_alpha (recording) &&
_cairo_recording_surface_has_only_op_over (recording));
+
status = _cairo_pdf_surface_open_content_stream (surface, &bbox, &pdf_source->hash_entry->surface_res,
TRUE, transparency_group);
if (unlikely (status))
@@ -3481,6 +3489,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
pattern->filter,
FALSE, /* stencil mask */
FALSE, /* smask */
+ FALSE, /* need_transp_group */
&pdf_pattern->extents,
NULL, /* smask_res */
&pdf_source,
@@ -4622,12 +4631,13 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_rectangle_int_t *extents,
+ double alpha,
cairo_pdf_resource_t *smask_res,
cairo_bool_t stencil_mask)
{
cairo_matrix_t cairo_p2d, pdf_p2d;
cairo_int_status_t status;
- int alpha;
+ int alpha_id;
double x_offset;
double y_offset;
cairo_pdf_source_surface_entry_t *pdf_source;
@@ -4651,6 +4661,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
source->filter,
stencil_mask,
FALSE, /* smask */
+ alpha != 1.0, /* need_transp_group */
extents,
smask_res,
&pdf_source,
@@ -4686,7 +4697,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
_cairo_output_stream_printf (surface->output, " cm\n");
}
- status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
+ status = _cairo_pdf_surface_add_alpha (surface, alpha, &alpha_id);
if (unlikely (status))
return status;
@@ -4697,7 +4708,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
} else {
_cairo_output_stream_printf (surface->output,
"/a%d gs /x%d Do\n",
- alpha,
+ alpha_id,
pdf_source->surface_res.id);
}
@@ -4708,12 +4719,13 @@ static cairo_int_status_t
_cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ double alpha)
{
cairo_pdf_resource_t shading_res, gstate_res;
cairo_matrix_t pat_to_pdf;
cairo_int_status_t status;
- int alpha;
+ int alpha_id;
status = _cairo_pdf_surface_add_pdf_shading (surface, source,
op, extents,
@@ -4752,13 +4764,13 @@ _cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t *surface,
gstate_res.id,
shading_res.id);
} else {
- status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
+ status = _cairo_pdf_surface_add_alpha (surface, alpha, &alpha_id);
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
"/a%d gs /sh%d sh\n",
- alpha,
+ alpha_id,
shading_res.id);
}
@@ -4770,6 +4782,7 @@ _cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_rectangle_int_t *extents,
+ double alpha,
cairo_bool_t mask)
{
switch (source->type) {
@@ -4779,6 +4792,7 @@ _cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t *surface,
op,
source,
extents,
+ alpha,
NULL,
mask);
case CAIRO_PATTERN_TYPE_LINEAR:
@@ -4787,7 +4801,8 @@ _cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t *surface,
return _cairo_pdf_surface_paint_gradient (surface,
op,
source,
- extents);
+ extents,
+ alpha);
case CAIRO_PATTERN_TYPE_SOLID:
default:
@@ -6436,7 +6451,8 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
CAIRO_OPERATOR_OVER,
group->mask,
&group->extents,
- FALSE);
+ 1.0, /* alpha */
+ FALSE); /* mask */
if (unlikely (status))
return status;
@@ -6512,7 +6528,8 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
CAIRO_OPERATOR_OVER,
group->source,
&group->extents,
- FALSE);
+ 1.0, /* alpha */
+ FALSE); /* mask */
if (unlikely (status))
return status;
@@ -7262,6 +7279,7 @@ _cairo_pdf_surface_emit_combined_smask (cairo_pdf_surface_t *surface,
source->filter,
FALSE, /* stencil mask */
TRUE, /* smask */
+ FALSE, /* need_transp_group */
extents,
NULL, /* smask_res */
&pdf_source,
@@ -7278,6 +7296,7 @@ _cairo_pdf_surface_emit_combined_smask (cairo_pdf_surface_t *surface,
_cairo_output_stream_printf (surface->output, "q\n");
status = _cairo_pdf_surface_paint_surface_pattern (surface, op, source, extents,
+ 1.0, /* alpha */
need_smask ? &pdf_source->surface_res : NULL,
FALSE);
if (unlikely (status))
@@ -7341,7 +7360,7 @@ _cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t *surface,
return status;
_cairo_output_stream_printf (surface->output, "q\n");
- status = _cairo_pdf_surface_paint_surface_pattern (surface, op, mask, extents, NULL, TRUE);
+ status = _cairo_pdf_surface_paint_surface_pattern (surface, op, mask, extents, 1.0, NULL, TRUE);
if (unlikely (status))
return status;
@@ -7424,7 +7443,8 @@ _cairo_pdf_surface_paint (void *abstract_surface,
op,
source,
&extents.bounded,
- FALSE);
+ 1.0, /* alpha */
+ FALSE); /* mask */
if (unlikely (status))
goto cleanup;
@@ -7512,6 +7532,7 @@ _cairo_pdf_surface_mask (void *abstract_surface,
cairo_int_status_t status;
cairo_rectangle_int_t r;
cairo_box_t box;
+ double alpha;
status = _cairo_composite_rectangles_init_for_mask (&extents,
&surface->base,
@@ -7592,6 +7613,26 @@ _cairo_pdf_surface_mask (void *abstract_surface,
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto cleanup;
+ /* Check if we can set ca/CA instead of an smask. We could handle
+ * other source patterns as well but for now this is the easiest,
+ * and most common, case to handle. */
+ if (_cairo_pattern_is_constant_alpha (mask, &extents.bounded, &alpha) &&
+ _can_paint_pattern (source)) {
+ _cairo_output_stream_printf (surface->output, "q\n");
+ status = _cairo_pdf_surface_paint_pattern (surface,
+ op,
+ source,
+ &extents.bounded,
+ alpha,
+ FALSE); /* mask */
+ if (unlikely (status))
+ goto cleanup;
+
+ _cairo_output_stream_printf (surface->output, "Q\n");
+ _cairo_composite_rectangles_fini (&extents);
+ return _cairo_output_stream_get_status (surface->output);
+ }
+
group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded);
if (unlikely (group == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -7869,7 +7910,8 @@ _cairo_pdf_surface_fill (void *abstract_surface,
op,
source,
&extents.bounded,
- FALSE);
+ 1.0, /* alpha */
+ FALSE); /* mask */
if (unlikely (status))
goto cleanup;
More information about the cairo-commit
mailing list