[PATCH] [API] Support component-alpha.

View: New views
6 Messages — Rating Filter:   Alert me  

[PATCH] [API] Support component-alpha.

by Chris Wilson-11 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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

_______________________________________________
cairo mailing list
cairo@...
http://lists.cairographics.org/mailman/listinfo/cairo

Re: [PATCH] [API] Support component-alpha.

by Soeren Sandmann-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Chris Wilson <chris@...> writes:

> 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...

Would this be expected to be useful for gradients, or would it be
considered some crazy thing you could set if you knew what you were
doing?

I could sort of see a gradient from say

        (ffff, ffee, ffdd)

to

        (0022, 0011, 0000)

being interesting as a component alpha mask, but the documentation for
the proposed API implies that no filtering or gamma correction would
takes place, which would result in color errors. And expecting users
to compute pixel values from a gradient is not really in the spirit of
cairo.


Soren
_______________________________________________
cairo mailing list
cairo@...
http://lists.cairographics.org/mailman/listinfo/cairo

Re: [PATCH] [API] Support component-alpha.

by Chris Wilson-11 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Excerpts from Soeren Sandmann's message of Tue Oct 20 14:46:51 +0100 2009:
> Chris Wilson <chris@...> writes:
>
> > 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...
>
> Would this be expected to be useful for gradients, or would it be
> considered some crazy thing you could set if you knew what you were
> doing?

Your right in that the principal use case is to allow sub-pixel surface
masks to be supplied. I can see gradients being interesting as well, but
the scenarios I can envisage for using gradients all seem to imply that
the user needs to supply the complete sub-pixel mask anyway. I'm probably
just not being imaginative enough.
 

> I could sort of see a gradient from say
>
>         (ffff, ffee, ffdd)
>
> to
>
>         (0022, 0011, 0000)
>
> being interesting as a component alpha mask, but the documentation for
> the proposed API implies that no filtering or gamma correction would
> takes place, which would result in color errors. And expecting users
> to compute pixel values from a gradient is not really in the spirit of
> cairo.

Hmm, I can appreciate that using a per-component mask complicates
everything, but how does this actually differ from cairo/pixman
currently for normal gradients?

At the moment there are a few bugs in Cairo where a per-component glyph
mask is being generated, but that information is not being passed along
to the rasteriser (the most obvious example is fallback glyph rendering
for xlib). The question simply becomes: can we define how per-component
alpha masks are supposed to operate and so be exported to users?
-ickle
--
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
cairo mailing list
cairo@...
http://lists.cairographics.org/mailman/listinfo/cairo

Re: [PATCH] [API] Support component-alpha.

by Soeren Sandmann-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Chris Wilson <chris@...> writes:

> Hmm, I can appreciate that using a per-component mask complicates
> everything, but how does this actually differ from cairo/pixman
> currently for normal gradients?
>
> At the moment there are a few bugs in Cairo where a per-component glyph
> mask is being generated, but that information is not being passed along
> to the rasteriser (the most obvious example is fallback glyph rendering
> for xlib). The question simply becomes: can we define how per-component
> alpha masks are supposed to operate and so be exported to users?

Well, there are two subtly different concepts in play here:

1. The concept of a 'three times horizontally supersampled image'

2. The concept of 'values to be presented to an output device'

It seems to me that (1) is the only thing a user can really be
expected to provide, because while (2) can be computed from (1), to do
a good job of it, you have to know about device characteristics and
human vision, then apply appropriate filtering and correction. You
also need to control which color space compositing takes place in.

If the component_alpha pattern property uses interpretation (2), then
we are effectively asking users to use their understanding of cairo
internals to compute something quite non-trivial.

In principle, component alpha could be supported as a property on
surfaces that says "when rendering to this surface, assume that it
will eventually be displayed on a subpixel-capable
monitor". Gradients, fonts and geometry rendered to such a surface
would then be supersampled and filtered appropriately by cairo.

A "supersampled" property on image patterns would then indicate that
the image was horizontally supersampled three times. Rendering could
make use of this information any way it wanted to. The property would
be ignored for gradients, just as filters are currently ignored.

I'm not really arguing for or against the proposed API, just trying to
make sure it has well-defined semantics.


Soren
_______________________________________________
cairo mailing list
cairo@...
http://lists.cairographics.org/mailman/listinfo/cairo

Re: [PATCH] [API] Support component-alpha.

by Chris Wilson-11 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Excerpts from Soeren Sandmann's message of Tue Oct 20 16:29:05 +0100 2009:

> Well, there are two subtly different concepts in play here:
>
> 1. The concept of a 'three times horizontally supersampled image'
>
> 2. The concept of 'values to be presented to an output device'
>
> It seems to me that (1) is the only thing a user can really be
> expected to provide, because while (2) can be computed from (1), to do
> a good job of it, you have to know about device characteristics and
> human vision, then apply appropriate filtering and correction. You
> also need to control which color space compositing takes place in.
>
> If the component_alpha pattern property uses interpretation (2), then
> we are effectively asking users to use their understanding of cairo
> internals to compute something quite non-trivial.

Hmm, I was approaching this from the "how can I generate sub-pixel
geometry masks to perform CAIRO_ANTIALIAS_SUBPIXEL with Render". Which
as you point out requires the knowledge (as provided by Render) of the
sub-pixel layout. That knowledge can only be sanely handled internally,
as it is meaningless for the rest of cairo and indeed is out of scope.

Ok, I'm convinced that the antialias property that we currently expose
on the context (hence target surface) is the way to go here and that
exposing per-component alpha is insane.
-ickle
--
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
cairo mailing list
cairo@...
http://lists.cairographics.org/mailman/listinfo/cairo

Re: [PATCH] [API] Support component-alpha.

by Soeren Sandmann-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Chris Wilson <chris@...> writes:

> Excerpts from Soeren Sandmann's message of Tue Oct 20 16:29:05 +0100 2009:
> > Well, there are two subtly different concepts in play here:
> >
> > 1. The concept of a 'three times horizontally supersampled image'
> >
> > 2. The concept of 'values to be presented to an output device'
> >
> > It seems to me that (1) is the only thing a user can really be
> > expected to provide, because while (2) can be computed from (1), to do
> > a good job of it, you have to know about device characteristics and
> > human vision, then apply appropriate filtering and correction. You
> > also need to control which color space compositing takes place in.
> >
> > If the component_alpha pattern property uses interpretation (2), then
> > we are effectively asking users to use their understanding of cairo
> > internals to compute something quite non-trivial.
>
> Hmm, I was approaching this from the "how can I generate sub-pixel
> geometry masks to perform CAIRO_ANTIALIAS_SUBPIXEL with Render". Which
> as you point out requires the knowledge (as provided by Render) of the
> sub-pixel layout. That knowledge can only be sanely handled internally,
> as it is meaningless for the rest of cairo and indeed is out of scope.
>
> Ok, I'm convinced that the antialias property that we currently expose
> on the context (hence target surface) is the way to go here and that
> exposing per-component alpha is insane.

If some day cairo starts making more use of subpixels, it might make
sense to allow the user to provide oversampled images in the sense of
(1) above. That is, images with three times the normal horizontal
resolution. Internally, cairo could then use this extra resolution to
generate subpixels with the appropriate filtering etc.


Soren
_______________________________________________
cairo mailing list
cairo@...
http://lists.cairographics.org/mailman/listinfo/cairo