[cairo] [PATCH] [API] Support component-alpha.

Chris Wilson chris at chris-wilson.co.uk
Wed Oct 14 16:47:09 PDT 2009


Within our code base we carried a few hacks to utilize the component
alpha capabilities of pixman, whilst not supporting the concept for our
own masks. Thus we were setting it upon the pixman_image_t that we
passed around through code that was blissfully unaware and indeed the
component-alpha property was forgotten (e.g. upgrading glyph masks).

The real issue is that without explicit support that a pattern carries
subpixel masking information, that information is lost when using that
pattern with composite. Again we can look at the example of compositing
a sub-pixel glyph mask onto a remote xlib surface for further failure.

So we need component-alpha support on patterns internally, so present
the same power to the users as well. For indeed, they may well be
dreaming of demonstrating sub-pixel geometry masks...

[This patch is hastily written and requires testing.]
---
 src/cairo-ft-font.c              |    5 ---
 src/cairo-gl-surface.c           |   45 ++++++++++++++++++++---------
 src/cairo-gstate.c               |    7 +---
 src/cairo-image-surface.c        |   58 ++++++++++++++++++++++++++++----------
 src/cairo-pattern.c              |   56 ++++++++++++++++++++++++++++++++++--
 src/cairo-scaled-font.c          |   11 ++++---
 src/cairo-types-private.h        |    1 +
 src/cairo-win32-font.c           |   10 ++----
 src/cairo-xlib-surface-private.h |    1 +
 src/cairo-xlib-surface.c         |   43 +++++++++++++++++++++++-----
 src/cairo.h                      |   22 ++++++++++++++
 src/cairoint.h                   |    1 +
 12 files changed, 198 insertions(+), 62 deletions(-)

diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 1c5edc1..02ab6cc 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -803,7 +803,6 @@ _get_bitmap_surface (FT_Bitmap		     *bitmap,
     int width, height, stride;
     unsigned char *data;
     int format = CAIRO_FORMAT_A8;
-    cairo_bool_t subpixel = FALSE;
 
     width = bitmap->width;
     height = bitmap->rows;
@@ -971,7 +970,6 @@ _get_bitmap_surface (FT_Bitmap		     *bitmap,
 	    data = data_rgba;
 	    stride = stride_rgba;
 	    format = CAIRO_FORMAT_ARGB32;
-	    subpixel = TRUE;
 	    break;
 	}
 	}
@@ -994,9 +992,6 @@ _get_bitmap_surface (FT_Bitmap		     *bitmap,
 	return (*surface)->base.status;
     }
 
-    if (subpixel)
-	pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE);
-
     _cairo_image_surface_assume_ownership_of_data ((*surface));
 
     _cairo_debug_check_image_surface_is_defined (&(*surface)->base);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 8ebfbc0..39c8fcc 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1342,20 +1342,37 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	    _cairo_gl_set_texture_surface (1, setup.mask.operand.texture.tex,
 					   mask_attributes);
 
-	    /* IN: dst.argb = src.argb * mask.aaaa */
-	    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
-
-	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
-	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+	    if (mask_attributes.component_alpha == CAIRO_SINGLE_ALPHA) {
+		/* IN: dst.argb = src.argb * mask.aaaa */
+		glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+		glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+		glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
+		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
+		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+	    } else {
+		/* IN: dst.argb = src.argb * mask.argb */
+		glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+		glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+		glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
+		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+	    }
 	    break;
 	}
     }
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 6f58bcf..98e2205 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -999,12 +999,9 @@ _cairo_gstate_mask (cairo_gstate_t  *gstate,
     _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
     _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
 
-    /* XXX: This optimization assumes that there is no color
-     * information in mask, so this will need to change if we
-     * support RENDER-style 4-channel masks.
-     */
     if (source_pattern.type == CAIRO_PATTERN_TYPE_SOLID &&
-	mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID)
+	mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID &&
+	mask_pattern.base.component_alpha == CAIRO_SINGLE_ALPHA)
     {
 	cairo_color_t combined;
 
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 49ce7a5..06d9f3e 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -927,33 +927,61 @@ _cairo_image_surface_set_filter (cairo_image_surface_t *surface,
 }
 
 static cairo_status_t
-_cairo_image_surface_set_attributes (cairo_image_surface_t      *surface,
-				     cairo_surface_attributes_t *attributes,
-				     double xc, double yc)
+_cairo_image_surface_set_extend (cairo_image_surface_t *surface,
+				 cairo_extend_t extend)
 {
-    cairo_int_status_t status;
-
-    status = _cairo_image_surface_set_matrix (surface, &attributes->matrix,
-					      xc, yc);
-    if (unlikely (status))
-	return status;
+    pixman_repeat_t pixman_repeat;
 
-    switch (attributes->extend) {
+    switch (extend) {
     case CAIRO_EXTEND_NONE:
-        pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_NONE);
+	pixman_repeat = PIXMAN_REPEAT_NONE;
 	break;
     case CAIRO_EXTEND_REPEAT:
-        pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_NORMAL);
+	pixman_repeat = PIXMAN_REPEAT_NORMAL;
 	break;
     case CAIRO_EXTEND_REFLECT:
-        pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_REFLECT);
+	pixman_repeat = PIXMAN_REPEAT_REFLECT;
 	break;
     case CAIRO_EXTEND_PAD:
-        pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_PAD);
+	pixman_repeat = PIXMAN_REPEAT_PAD;
 	break;
     }
 
-    status = _cairo_image_surface_set_filter (surface, attributes->filter);
+    pixman_image_set_repeat (surface->pixman_image, pixman_repeat);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_surface_set_component_alpha (cairo_image_surface_t *surface,
+					  cairo_component_alpha_t ca)
+{
+    pixman_image_set_component_alpha (surface->pixman_image,
+				      ca != CAIRO_SINGLE_ALPHA);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_surface_set_attributes (cairo_image_surface_t      *surface,
+				     cairo_surface_attributes_t *attributes,
+				     double xc, double yc)
+{
+    cairo_int_status_t status;
+
+    status = _cairo_image_surface_set_matrix (surface, &attributes->matrix,
+					      xc, yc);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_image_surface_set_filter (surface, attributes->extend);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_image_surface_set_extend (surface, attributes->extend);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_image_surface_set_component_alpha (surface,
+						       attributes->component_alpha);
     if (unlikely (status))
 	return status;
 
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 1888d83..7a8e8b0 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -130,6 +130,8 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
 
     pattern->filter    = CAIRO_FILTER_DEFAULT;
 
+    pattern->component_alpha = CAIRO_SINGLE_ALPHA;
+
     cairo_matrix_init_identity (&pattern->matrix);
 }
 
@@ -1523,6 +1525,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
 	attr->matrix = matrix;
 	attr->extend = pattern->base.extend;
 	attr->filter = CAIRO_FILTER_NEAREST;
+	attr->component_alpha = pattern->base.component_alpha;
 
 	*out = &image->base;
 
@@ -1619,6 +1622,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
     cairo_matrix_init_identity (&attr->matrix);
     attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
     attr->filter = CAIRO_FILTER_NEAREST;
+    attr->component_alpha = pattern->base.component_alpha;
 
     return status;
 }
@@ -1763,6 +1767,7 @@ NOCACHE:
     cairo_matrix_init_identity (&attribs->matrix);
     attribs->extend = CAIRO_EXTEND_REPEAT;
     attribs->filter = CAIRO_FILTER_NEAREST;
+    attribs->component_alpha = pattern->base.component_alpha;
 
     status = CAIRO_STATUS_SUCCESS;
 
@@ -1849,6 +1854,9 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
 {
     const cairo_pattern_union_t *pattern;
 
+    if (abstract_pattern->component_alpha)
+	return FALSE;
+
     pattern = (cairo_pattern_union_t *) abstract_pattern;
     switch (pattern->base.type) {
     case CAIRO_PATTERN_TYPE_SOLID:
@@ -1958,6 +1966,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t   *pat
     attr->matrix = pattern->base.matrix;
     attr->extend = pattern->base.extend;
     attr->filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
+    attr->component_alpha = pattern->base.component_alpha;
 
     attr->x_offset = attr->y_offset = tx = ty = 0;
     if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
@@ -2378,11 +2387,10 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t	    *src,
     /* If src and mask are both solid, then the mask alpha can be
      * combined into src and mask can be ignored. */
 
-    /* XXX: This optimization assumes that there is no color
-     * information in mask, so this will need to change when we
-     * support RENDER-style 4-channel masks. */
     if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
-	mask && mask->type == CAIRO_PATTERN_TYPE_SOLID)
+	mask &&
+	mask->component_alpha == CAIRO_SINGLE_ALPHA &&
+	mask->type == CAIRO_PATTERN_TYPE_SOLID)
     {
 	cairo_color_t combined;
 	cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
@@ -2648,6 +2656,8 @@ _cairo_pattern_hash (const cairo_pattern_t *pattern)
 				  &pattern->filter, sizeof (pattern->filter));
 	hash = _cairo_hash_bytes (hash,
 				  &pattern->extend, sizeof (pattern->extend));
+	hash = _cairo_hash_bytes (hash,
+				  &pattern->component_alpha, sizeof (pattern->component_alpha));
     }
 
     switch (pattern->type) {
@@ -2799,6 +2809,9 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
     if (a->type != b->type)
 	return FALSE;
 
+    if (a->component_alpha != b->component_alpha)
+	return FALSE;
+
     if (a->type != CAIRO_PATTERN_TYPE_SOLID) {
 	if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
 	    return FALSE;
@@ -3079,6 +3092,41 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
     return CAIRO_STATUS_SUCCESS;
 }
 
+/**
+ * cairo_pattern_set_component_alpha:
+ * @pattern: a #cairo_pattern_t
+ * @value: Enable use of per-component alpha mask?
+ *
+ * When used as a mask a pattern with content CAIRO_CONTENT_COLOR,
+ * i.e. a pattern with red, green, blue components as well as an
+ * alpha component (which may be implicitly 1) the value used for the
+ * mask may either be per-component or the single alpha value.
+ *
+ * The default is to use the single alpha channel for masking. Using
+ * per-component alpha may be used in conjunction with sub-pixel
+ * antialiasing to improve clarity on pixellated displays, e.g. LCDs.
+ *
+ * Since: 1.10
+ **/
+void
+cairo_pattern_set_component_alpha (cairo_pattern_t *pattern,
+				   cairo_component_alpha_t ca)
+{
+    if (unlikely (pattern->status))
+	return;
+
+    pattern->component_alpha = ca;
+}
+
+cairo_component_alpha_t
+cairo_pattern_get_component_alpha (cairo_pattern_t *pattern)
+{
+    if (unlikely (pattern->status))
+	return CAIRO_SINGLE_ALPHA;
+
+    return pattern->component_alpha;
+}
+
 void
 _cairo_pattern_reset_static_data (void)
 {
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 48451a6..357ce46 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -2170,6 +2170,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t	*scaled_font,
 	    }
 
 	    _cairo_pattern_init_for_surface (&mask_pattern, mask);
+	    if (mask_format == CAIRO_FORMAT_ARGB32)
+		mask_pattern.base.component_alpha = CAIRO_COMPONENT_ALPHA;
 
 	    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
 					       &white_pattern.base,
@@ -2204,6 +2206,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t	*scaled_font,
 
 	    _cairo_pattern_init_for_surface (&glyph_pattern,
 					     &glyph_surface->base);
+	    if (mask_format == CAIRO_FORMAT_ARGB32)
+		glyph_pattern.base.component_alpha = CAIRO_COMPONENT_ALPHA;
 
 	    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
 					       &white_pattern.base,
@@ -2223,12 +2227,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t	*scaled_font,
 	}
     }
 
-    /* XXX ComponentAlpha needs to be a cairo pattern property! */
-    if (mask_format == CAIRO_FORMAT_ARGB32) {
-	pixman_image_set_component_alpha (((cairo_image_surface_t*) mask)->
-					  pixman_image, TRUE);
-    }
     _cairo_pattern_init_for_surface (&mask_pattern, mask);
+    if (mask_format == CAIRO_FORMAT_ARGB32)
+	mask_pattern.base.component_alpha = CAIRO_COMPONENT_ALPHA;
 
     status = _cairo_surface_composite (op, pattern, &mask_pattern.base,
 				       surface,
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 068c261..0e216f3 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -350,6 +350,7 @@ struct _cairo_pattern {
     cairo_matrix_t		matrix;
     cairo_filter_t		filter;
     cairo_extend_t		extend;
+    cairo_component_alpha_t	component_alpha;
 };
 
 struct _cairo_solid_pattern {
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 71bad77..8e9e44d 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -1438,10 +1438,6 @@ _cairo_win32_scaled_font_show_glyphs (void			*abstract_font,
 		_invert_argb32_mask (tmp_surface);
 
 	    mask_surface = &tmp_surface->base;
-
-	    /* XXX: Hacky, should expose this in cairo_image_surface */
-	    pixman_image_set_component_alpha (((cairo_image_surface_t *)tmp_surface->image)->pixman_image, TRUE);
-
 	} else {
 	    mask_surface = _compute_a8_mask (tmp_surface);
 	    cairo_surface_destroy (&tmp_surface->base);
@@ -1455,6 +1451,10 @@ _cairo_win32_scaled_font_show_glyphs (void			*abstract_font,
 	 * destination
 	 */
 	_cairo_pattern_init_for_surface (&mask, mask_surface);
+	cairo_surface_destroy (mask_surface);
+
+	if (scaled_font->quality == CLEARTYPE_QUALITY) {
+	    mask.base.component_alpha = CAIRO_COMPONENT_ALPHA;
 
 	status = _cairo_surface_composite (op, pattern,
 					   &mask.base,
@@ -1467,8 +1467,6 @@ _cairo_win32_scaled_font_show_glyphs (void			*abstract_font,
 
 	_cairo_pattern_fini (&mask.base);
 
-	cairo_surface_destroy (mask_surface);
-
 	return status;
     }
 }
diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h
index 92107e7..b40ee59 100644
--- a/src/cairo-xlib-surface-private.h
+++ b/src/cairo-xlib-surface-private.h
@@ -95,6 +95,7 @@ struct _cairo_xlib_surface {
     XRenderPictFormat *xrender_format;
     cairo_filter_t filter;
     cairo_extend_t extend;
+    cairo_component_alpha_t component_alpha;
     XTransform xtransform;
 
     uint32_t a_mask;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index f3ebc9d..91e4113 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1549,11 +1549,11 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
 }
 
 static cairo_status_t
-_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface,
-				cairo_extend_t extend)
+_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t	*surface,
+				cairo_extend_t		 extend,
+				unsigned long		*mask,
+				XRenderPictureAttributes *pa)
 {
-    XRenderPictureAttributes pa;
-    unsigned long	     mask;
     int repeat;
 
     if (surface->extend == extend)
@@ -1583,12 +1583,26 @@ _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    mask = CPRepeat;
-    pa.repeat = repeat;
+    *mask |= CPRepeat;
+    pa->repeat = repeat;
 
-    XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
     surface->extend = extend;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xlib_surface_set_component_alpha (cairo_xlib_surface_t *surface,
+					 cairo_component_alpha_t ca,
+					 unsigned long		*mask,
+					 XRenderPictureAttributes *pa)
+{
+    if (surface->component_alpha == ca)
+	return CAIRO_STATUS_SUCCESS;
 
+    *mask |= CPComponentAlpha;
+    pa->component_alpha = !! ca;
+
+    surface->component_alpha = ca;
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1599,6 +1613,8 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t	    *surface,
 				    double			     yc)
 {
     cairo_int_status_t status;
+    XRenderPictureAttributes pa;
+    unsigned long mask = 0;
 
     _cairo_xlib_surface_ensure_src_picture (surface);
 
@@ -1607,7 +1623,14 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t	    *surface,
     if (unlikely (status))
 	return status;
 
-    status = _cairo_xlib_surface_set_repeat (surface, attributes->extend);
+    status = _cairo_xlib_surface_set_repeat (surface, attributes->extend,
+					     &mask, &pa);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_xlib_surface_set_component_alpha (surface,
+						      attributes->component_alpha,
+						      &mask, &pa);
     if (unlikely (status))
 	return status;
 
@@ -1615,6 +1638,9 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t	    *surface,
     if (unlikely (status))
 	return status;
 
+    if (mask)
+	XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -2969,6 +2995,7 @@ found:
     surface->depth = depth;
     surface->filter = CAIRO_FILTER_NEAREST;
     surface->extend = CAIRO_EXTEND_NONE;
+    surface->component_alpha = CAIRO_SINGLE_ALPHA;
     surface->xtransform = identity;
 
     surface->clip_region = NULL;
diff --git a/src/cairo.h b/src/cairo.h
index c239dea..a91c824 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -2374,6 +2374,28 @@ cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter);
 cairo_public cairo_filter_t
 cairo_pattern_get_filter (cairo_pattern_t *pattern);
 
+/**
+ * cairo_component_alpha_t:
+ * @CAIRO_SINGLE_ALPHA: Use the alpha component when masking
+ * @CAIRO_COMPONENT_ALPHA: Use the component value when masking
+ *
+ * #cairo_component_alpha_t is used to indicate which channel to use
+ * when masking with the pattern.  See cairo_pattern_set_component_alpha()
+ * for how this affects masking with a particular pattern.
+ */
+typedef enum cairo_component_alpha {
+    CAIRO_SINGLE_ALPHA = 0,
+    CAIRO_COMPONENT_ALPHA,
+} cairo_component_alpha_t;
+
+cairo_public void
+cairo_pattern_set_component_alpha (cairo_pattern_t *pattern,
+				   cairo_component_alpha_t ca);
+
+cairo_public cairo_component_alpha_t
+cairo_pattern_get_component_alpha (cairo_pattern_t *pattern);
+
+
 cairo_public cairo_status_t
 cairo_pattern_get_rgba (cairo_pattern_t *pattern,
 			double *red, double *green,
diff --git a/src/cairoint.h b/src/cairoint.h
index 8706488..464cf33 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -874,6 +874,7 @@ typedef struct _cairo_surface_attributes {
     cairo_matrix_t matrix;
     cairo_extend_t extend;
     cairo_filter_t filter;
+    cairo_component_alpha_t component_alpha;
     int		   x_offset;
     int		   y_offset;
     void	   *extra;
-- 
1.6.4.3



More information about the cairo mailing list