[cairo-commit] 7 commits - src/cairo.c src/cairo-color.c src/cairo-gl-glyphs.c src/cairo-gl-private.h src/cairo-gl-surface.c src/cairo-gstate.c src/cairo-image-surface.c test/Makefile.sources test/zero-mask.c test/zero-mask.ref.png test/zero-mask.rgb24.ref.png

Benjamin Otte company at kemper.freedesktop.org
Thu May 13 03:14:23 PDT 2010


 src/cairo-color.c            |   10 +-
 src/cairo-gl-glyphs.c        |   36 +------
 src/cairo-gl-private.h       |    1 
 src/cairo-gl-surface.c       |    4 
 src/cairo-gstate.c           |   15 +++
 src/cairo-image-surface.c    |    2 
 src/cairo.c                  |    3 
 test/Makefile.sources        |    3 
 test/zero-mask.c             |  199 +++++++++++++++++++++++++++++++++++++++++++
 test/zero-mask.ref.png       |binary
 test/zero-mask.rgb24.ref.png |binary
 11 files changed, 239 insertions(+), 34 deletions(-)

New commits:
commit c69143e3f9c95ab3937a7efb8e4de170c4edb648
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 12 21:14:36 2010 +0200

    gl: Don't keep a temporary surface in the device
    
    We get circular references that way.
    If it turns out later such a cache is critical, we'll need to invent a
    way to avoid circling references. For now, just pretend it's not
    important.

diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index f283f56..217f4fb 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -672,32 +672,13 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t	*dst,
 	return status;
 
     /* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
-    mask = NULL;
-    if (ctx->glyphs_temporary_mask) {
-	if (glyph_extents->width  <= ctx->glyphs_temporary_mask->width &&
-	    glyph_extents->height <= ctx->glyphs_temporary_mask->height)
-	{
-	    status = _cairo_gl_surface_clear (ctx->glyphs_temporary_mask);
-	    if (unlikely (status)) {
-		_cairo_gl_context_release (ctx);
-		return status;
-	    }
-
-	    mask = &ctx->glyphs_temporary_mask->base;
-	} else {
-	    cairo_surface_destroy (&ctx->glyphs_temporary_mask->base);
-	    ctx->glyphs_temporary_mask = NULL;
-	}
-    }
-    if (mask == NULL) {
-	mask = cairo_gl_surface_create (dst->base.device,
-					CAIRO_CONTENT_COLOR_ALPHA,
-					glyph_extents->width,
-					glyph_extents->height);
-	if (unlikely (mask->status)) {
-	    _cairo_gl_context_release (ctx);
-	    return mask->status;
-	}
+    mask = cairo_gl_surface_create (dst->base.device,
+                                    CAIRO_CONTENT_COLOR_ALPHA,
+                                    glyph_extents->width,
+                                    glyph_extents->height);
+    if (unlikely (mask->status)) {
+        _cairo_gl_context_release (ctx);
+        return mask->status;
     }
 
     for (i = 0; i < num_glyphs; i++) {
@@ -730,8 +711,7 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t	*dst,
 	*remaining_glyphs = num_glyphs;
     }
 
-    if (ctx->glyphs_temporary_mask == NULL)
-	ctx->glyphs_temporary_mask = (cairo_gl_surface_t *) mask;
+    cairo_surface_destroy (mask);
 
     _cairo_gl_context_release (ctx);
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 15e5466..83836e7 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -135,7 +135,6 @@ typedef struct _cairo_gl_context {
 					[CAIRO_GL_SHADER_IN_COUNT];
 
     cairo_gl_surface_t *current_target;
-    cairo_gl_surface_t *glyphs_temporary_mask;
     cairo_gl_glyph_cache_t glyph_cache[2];
     cairo_list_t fonts;
 
commit ec1ca17b71b41159ea8754d42954863b62623536
Author: Benjamin Otte <otte at redhat.com>
Date:   Thu May 13 12:07:53 2010 +0200

    gl: Don't create 0x0 surfaces
    
    We get a very annoyed libGL if we try to create 0x0 textures, so we
    return an image surface instead.
    
    Tested by the zero-mask test.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 27fc02c..eb2e91b 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -535,6 +535,10 @@ _cairo_gl_surface_create_similar (void		 *abstract_surface,
     cairo_gl_context_t *ctx;
     cairo_status_t status;
 
+    if (width < 1 || height < 1)
+        return cairo_image_surface_create (_cairo_format_from_content (content),
+                                           width, height);
+
     status = _cairo_gl_context_acquire (surface->device, &ctx);
     if (unlikely (status))
 	return _cairo_surface_create_in_error (status);
commit 108e3f5031fc16843197382af78af299b19ef290
Author: Benjamin Otte <otte at redhat.com>
Date:   Thu May 13 12:01:39 2010 +0200

    Use a solid color for 0xN and Nx0 surfaces
    
    This gets around the need to check for 0-sized surfaces in the backends.

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 0012558..459df3b 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -860,7 +860,22 @@ _cairo_gstate_copy_pattern (cairo_pattern_t *pattern,
      */
     switch (original->type) {
     case CAIRO_PATTERN_TYPE_SOLID:
+	break;
+
     case CAIRO_PATTERN_TYPE_SURFACE:
+        {
+            cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) original;
+            cairo_rectangle_int_t extents;
+
+            if (_cairo_surface_get_extents (surface->surface, &extents) &&
+                (extents.width == 0 || extents.height == 0)) {
+                _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
+                                           CAIRO_COLOR_TRANSPARENT,
+                                           surface->surface->content);
+
+                return;
+            }
+        }
 	break;
 
     case CAIRO_PATTERN_TYPE_LINEAR:
commit 18c963824ebbb0e7054e682ecb5664a282a58552
Author: Benjamin Otte <otte at redhat.com>
Date:   Thu May 13 11:56:22 2010 +0200

    Make _cairo_color_equal() work for unmultiplied colors, too
    
    Color stop colors are unmultiplied, and we use it there.

diff --git a/src/cairo-color.c b/src/cairo-color.c
index ddba5ca..9483c8b 100644
--- a/src/cairo-color.c
+++ b/src/cairo-color.c
@@ -162,6 +162,7 @@ _cairo_color_get_rgba_premultiplied (cairo_color_t *color,
     *alpha = color->alpha;
 }
 
+/* NB: This function works both for unmultiplied and premultiplied colors */
 cairo_bool_t
 _cairo_color_equal (const cairo_color_t *color_a,
 	            const cairo_color_t *color_b)
@@ -169,10 +170,15 @@ _cairo_color_equal (const cairo_color_t *color_a,
     if (color_a == color_b)
 	return TRUE;
 
+    if (color_a->alpha_short != color_b->alpha_short)
+        return FALSE;
+
+    if (color_a->alpha_short == 0)
+        return TRUE;
+
     return color_a->red_short   == color_b->red_short   &&
            color_a->green_short == color_b->green_short &&
-           color_a->blue_short  == color_b->blue_short  &&
-           color_a->alpha_short == color_b->alpha_short;
+           color_a->blue_short  == color_b->blue_short;
 }
 
 cairo_bool_t
commit 7bd8d0db1f4ac448c93d6d342726f64a0d6300e3
Author: Benjamin Otte <otte at redhat.com>
Date:   Thu May 13 11:23:33 2010 +0200

    image: Fix wholly unbounded fixup
    
    Tested by zero-mask test.

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index b98d108..4e2388c 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -1662,7 +1662,7 @@ _cairo_image_surface_fixup_unbounded (cairo_image_surface_t *dst,
                                       width, height);
 	} else {
             pixman_color_t color = { 0, };
-            pixman_box32_t box = { x, y, width, height };
+            pixman_box32_t box = { x, y, x + width, y + height };
 
             if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
 					   dst->pixman_image,
commit 8aa50b5a7873b8317d0593105497607dbb2fae1d
Author: Benjamin Otte <otte at redhat.com>
Date:   Thu May 13 10:27:37 2010 +0200

    cairo_paint_with_alpha(cr, 0.0) is only a noop when bounded by mask

diff --git a/src/cairo.c b/src/cairo.c
index 0070f98..7ddfd84 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -2139,7 +2139,8 @@ cairo_paint_with_alpha (cairo_t *cr,
 	return;
     }
 
-    if (CAIRO_ALPHA_IS_ZERO (alpha)) {
+    if (CAIRO_ALPHA_IS_ZERO (alpha) &&
+        _cairo_operator_bounded_by_mask (cr->gstate->op)) {
 	return;
     }
 
commit ee32dfb3de035e73cb8c2073c0826daf244e3845
Author: Benjamin Otte <otte at redhat.com>
Date:   Thu May 13 10:04:49 2010 +0200

    test: Add a test for various zero mask operations

diff --git a/test/Makefile.sources b/test/Makefile.sources
index 1464516..cf03fcc 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -269,7 +269,8 @@ test_sources = \
 	user-font-rescale.c				\
 	xcomposite-projection.c				\
 	xlib-expose-event.c 				\
-	zero-alpha.c
+	zero-alpha.c					\
+	zero-mask.c
 
 pthread_test_sources =					\
 	pthread-same-source.c				\
diff --git a/test/zero-mask.c b/test/zero-mask.c
new file mode 100644
index 0000000..b1458b3
--- /dev/null
+++ b/test/zero-mask.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright © 2010 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Benjamin Otte <otte at gnome.org>
+ */
+
+#include "cairo-test.h"
+
+#define RECT 10
+#define SPACE 5
+
+static void
+paint_with_alpha (cairo_t *cr)
+{
+    cairo_paint_with_alpha (cr, 0.0);
+}
+
+static void
+mask_with_solid (cairo_t *cr)
+{
+    cairo_pattern_t *pattern = cairo_pattern_create_rgba (1, 0, 0, 0);
+
+    cairo_mask (cr, pattern);
+    
+    cairo_pattern_destroy (pattern);
+}
+
+static void
+mask_with_empty_gradient (cairo_t *cr)
+{
+    cairo_pattern_t *pattern = cairo_pattern_create_linear (1, 2, 3, 4);
+
+    cairo_mask (cr, pattern);
+    
+    cairo_pattern_destroy (pattern);
+}
+
+static void
+mask_with_gradient (cairo_t *cr)
+{
+    cairo_pattern_t *pattern = cairo_pattern_create_radial (1, 2, 3, 4, 5, 6);
+
+    cairo_pattern_add_color_stop_rgba (pattern, 0, 1, 0, 0, 0);
+    cairo_pattern_add_color_stop_rgba (pattern, 0, 0, 0, 1, 0);
+
+    cairo_mask (cr, pattern);
+    
+    cairo_pattern_destroy (pattern);
+}
+
+static void
+mask_with_surface (cairo_t *cr)
+{
+    cairo_surface_t *surface = cairo_surface_create_similar (cairo_get_target (cr),
+                                                             CAIRO_CONTENT_COLOR_ALPHA,
+                                                             RECT,
+                                                             RECT);
+
+    cairo_mask_surface (cr, surface, 0, 0);
+    
+    cairo_surface_destroy (surface);
+}
+
+static void
+mask_with_alpha_surface (cairo_t *cr)
+{
+    cairo_surface_t *surface = cairo_surface_create_similar (cairo_get_target (cr),
+                                                             CAIRO_CONTENT_ALPHA,
+                                                             RECT / 2,
+                                                             RECT / 2);
+    cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
+    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT);
+
+    cairo_mask (cr, pattern);
+    
+    cairo_pattern_destroy (pattern);
+    cairo_surface_destroy (surface);
+}
+
+static void
+mask_with_nonclear_surface (cairo_t *cr)
+{
+    static unsigned char data[8 * 4] = { 0, };
+    cairo_surface_t *surface = cairo_image_surface_create_for_data (data,
+                                                                    CAIRO_FORMAT_A1,
+                                                                    16, 8, 4);
+
+    cairo_mask_surface (cr, surface, 0, 0);
+    
+    cairo_surface_destroy (surface);
+}
+
+static void
+mask_with_0x0_surface (cairo_t *cr)
+{
+    cairo_surface_t *surface = cairo_surface_create_similar (cairo_get_target (cr),
+                                                             CAIRO_CONTENT_COLOR_ALPHA,
+                                                             0, 0);
+
+    cairo_mask_surface (cr, surface, 0, 0);
+    
+    cairo_surface_destroy (surface);
+}
+
+static void
+mask_with_extend_none (cairo_t *cr)
+{
+    cairo_surface_t *surface = cairo_surface_create_similar (cairo_get_target (cr),
+                                                             CAIRO_CONTENT_COLOR_ALPHA,
+                                                             RECT,
+                                                             RECT);
+
+    cairo_mask_surface (cr, surface, 2 * RECT, 2 * RECT);
+    
+    cairo_surface_destroy (surface);
+}
+
+#define ARRAY_LENGTH(array) (sizeof (array) / sizeof ((array)[0]))
+
+typedef void (* mask_func_t) (cairo_t *);
+
+mask_func_t mask_funcs[] = {
+  paint_with_alpha,
+  mask_with_solid,
+  mask_with_empty_gradient,
+  mask_with_gradient,
+  mask_with_surface,
+  mask_with_alpha_surface,
+  mask_with_nonclear_surface,
+  mask_with_0x0_surface,
+  mask_with_extend_none
+};
+
+cairo_operator_t operators[] = {
+  CAIRO_OPERATOR_CLEAR,
+  CAIRO_OPERATOR_SOURCE,
+  CAIRO_OPERATOR_OVER,
+  CAIRO_OPERATOR_IN,
+  CAIRO_OPERATOR_DEST_ATOP,
+  CAIRO_OPERATOR_SATURATE,
+  CAIRO_OPERATOR_MULTIPLY
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    unsigned int i, op;
+
+    /* 565-compatible gray background */
+    cairo_set_source_rgb (cr, 0.51613, 0.55555, 0.51613);
+    cairo_paint (cr);
+
+    cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); /* green */
+    /* mask with zero-alpha in several ways */
+
+    cairo_translate (cr, SPACE, SPACE);
+
+    for (op = 0; op < ARRAY_LENGTH (operators); op++) {
+        cairo_set_operator (cr, operators[op]);
+        
+        for (i = 0; i < ARRAY_LENGTH (mask_funcs); i++) {
+            cairo_save (cr);
+            cairo_translate (cr, i * (RECT + SPACE), op * (RECT + SPACE));
+            cairo_rectangle (cr, 0, 0, RECT, RECT);
+            cairo_clip (cr);
+            mask_funcs[i] (cr);
+            cairo_restore (cr);
+        }
+    }
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (zero_mask,
+	    "Testing that masking with zero alpha works",
+	    "alpha, mask", /* keywords */
+	    NULL, /* requirements */
+	    SPACE + (RECT + SPACE) * ARRAY_LENGTH (mask_funcs),
+	    SPACE + (RECT + SPACE) * ARRAY_LENGTH (operators),
+	    NULL, draw)
diff --git a/test/zero-mask.ref.png b/test/zero-mask.ref.png
new file mode 100644
index 0000000..ffae8d9
Binary files /dev/null and b/test/zero-mask.ref.png differ
diff --git a/test/zero-mask.rgb24.ref.png b/test/zero-mask.rgb24.ref.png
new file mode 100644
index 0000000..263c3d1
Binary files /dev/null and b/test/zero-mask.rgb24.ref.png differ


More information about the cairo-commit mailing list