[cairo] Semantics of zero sized surfaces?

Jeff Muizelaar jeff at infidigm.net
Wed Nov 12 15:15:27 PST 2008


We recently ran into the crashes with zero sized surfaces in Firefox.
While investigating the problem it became clear that the semantics
of drawing zero sized surfaces are not well defined.

I've attached a test case that exercises zero sized surfaces. Currently
it causes some crashes, so I've attached a fix that fixes them in a low
impact way by ensuring the minimum surface we create is 1x1. However,
drawing a 1x1 surfaces doesn't necessarily produce the result you'd
expect when you create a 0x0 surface.

Are there any thoughts about what we should do here? If not, I'll just
land the crashes fixes and the test case to document the current
semantics.

-Jeff
-------------- next part --------------
commit 18ea4da8e0130ca5e5fb377517ec1b2df427d95a
Author: Jeff Muizelaar <jmuizelaar at mozilla.com>
Date:   Wed Nov 12 09:12:30 2008 -0500

    zerosized

diff --git a/test/Makefile.am b/test/Makefile.am
index 131ed60..d5ec77c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -194,7 +194,8 @@ test_sources = \
 	user-font-mask.c				\
 	user-font-proxy.c				\
 	user-font-rescale.c				\
-	zero-alpha.c
+	zero-alpha.c					\
+	zero-sized-surface.c
 
 # Then we have a collection of tests that are only run if certain
 # features are compiled into cairo
diff --git a/test/zero-sized-surface.c b/test/zero-sized-surface.c
new file mode 100644
index 0000000..30a0540
--- /dev/null
+++ b/test/zero-sized-surface.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright ? 2008 Mozilla Corporation
+ *
+ * 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
+ * Mozilla Corporation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Mozilla Corporation makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION 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.
+ *
+ * Authors: Jeff Muizelaar <jeff at infidigm.net>
+ */
+
+
+#include "cairo-test.h"
+
+#define SIZE 100
+
+static void
+draw_squares (cairo_t *cr, cairo_pattern_t *pattern)
+{
+    cairo_save (cr);
+    cairo_rectangle (cr, 0, 0, 10, 10);
+    cairo_clip (cr);
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    cairo_save (cr);
+    cairo_rectangle (cr, 10, 0, 10, 10);
+    cairo_clip (cr);
+    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT);
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    cairo_save (cr);
+    cairo_rectangle (cr, 20, 0, 10, 10);
+    cairo_clip (cr);
+    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    cairo_save (cr);
+    cairo_rectangle (cr, 30, 0, 10, 10);
+    cairo_clip (cr);
+    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+    cairo_paint (cr);
+    cairo_restore (cr);
+}
+
+void draw_surface (cairo_t *cr, cairo_surface_t *surface)
+{
+    /* fill the zero sized surface with blue */
+    cairo_t *surface_cr = cairo_create (surface);
+    cairo_set_source_rgb (surface_cr, 0., 0., 1.);
+    cairo_paint (surface_cr);
+    cairo_destroy (surface_cr);
+
+    cairo_pattern_t *pattern = cairo_pattern_create_for_surface(surface);
+    cairo_set_source (cr, pattern);
+
+    draw_squares (cr, pattern);
+
+    cairo_translate (cr, 0, 10);
+    cairo_set_source (cr, pattern);
+
+    /* zero sized IN with repeat NONE should give empty space */
+    cairo_set_operator (cr, CAIRO_OPERATOR_IN);
+    draw_squares (cr, pattern);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    /* paint the background green */
+    cairo_set_source_rgb (cr, 0., 1., 0.);
+    cairo_paint (cr);
+
+    /* setup a transform to make thing more interesting */
+    cairo_scale (cr, 0.5, 0.5);
+
+    /* One would expect that drawing results should be the same regardless
+     * of the content type. Currently, this isn't the case. */
+    /* The closest surface that often makes sense is a 1x1 image surface equal
+     * to transparent black, however it might make sense to have a special
+     * EMPTY surface type that is used for the 0x0 case */
+    cairo_surface_t *surface;
+    surface = cairo_surface_create_similar (cairo_get_target (cr),
+                                            CAIRO_CONTENT_COLOR_ALPHA,
+                                            0, 0);
+    draw_surface (cr, surface);
+    cairo_surface_destroy (surface);
+
+    cairo_translate (cr, 0, 10);
+
+    /* what's interesting is that a zero sized RGB24 surface should also draw nothing */
+    surface = cairo_surface_create_similar (cairo_get_target (cr),
+                                            CAIRO_CONTENT_COLOR,
+                                            0, 0);
+    draw_surface (cr, surface);
+    cairo_surface_destroy (surface);
+
+    cairo_translate (cr, 0, 10);
+
+    surface = cairo_surface_create_similar (cairo_get_target (cr),
+                                            CAIRO_CONTENT_ALPHA,
+                                            0, 0);
+    draw_surface (cr, surface);
+    cairo_surface_destroy (surface);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (zero_sized_surface,
+	    "Test drawing with a zero sized surface",
+	    "zero, surface, transform, extend, pad", /* keywords */
+	    NULL, /* requirements */
+	    SIZE, SIZE,
+	    NULL, draw)
-------------- next part --------------
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 0efdb7a..faebe5f 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -324,7 +324,7 @@ _cairo_image_surface_create_with_pixman_format (unsigned char		*data,
     cairo_surface_t *surface;
     pixman_image_t *pixman_image;
 
-    pixman_image = pixman_image_create_bits (pixman_format, width, height,
+    pixman_image = pixman_image_create_bits (pixman_format, width ? width : 1, height ? height : 1,
 					     (uint32_t *) data, stride);
 
     if (pixman_image == NULL)
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 12c2ccc..d4bef9d 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -677,7 +677,8 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 
 	pixmap = XCreatePixmap (surface->dpy,
 				surface->drawable,
-				extents.width, extents.height,
+				extents.width <= 0 ? 1 : extents.width,
+				extents.height <= 0 ? 1 : extents.height,
 				surface->depth);
 	if (pixmap) {
 	    XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc,


More information about the cairo mailing list