[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

pixman: Changes to 'upstream-experimental'



 COPYING                          |   80 +--
 configure.ac                     |   58 ++
 pixman/pixman-arm-common.h       |   64 ++
 pixman/pixman-arm-neon-asm.S     |  626 +++++++++++++++++++++++-----
 pixman/pixman-arm-neon-asm.h     |  221 +++++++++-
 pixman/pixman-arm-neon.c         |   77 +++
 pixman/pixman-arm-simd-asm.S     |   70 +++
 pixman/pixman-arm-simd.c         |   11 
 pixman/pixman-bits-image.c       |  416 +++++++++++++++---
 pixman/pixman-combine.c.template |   30 +
 pixman/pixman-compiler.h         |    3 
 pixman/pixman-conical-gradient.c |   62 +-
 pixman/pixman-cpu.c              |    9 
 pixman/pixman-fast-path.c        |  149 +++++-
 pixman/pixman-fast-path.h        |   26 -
 pixman/pixman-general.c          |  294 ++++++-------
 pixman/pixman-image.c            |  167 +------
 pixman/pixman-implementation.c   |   81 +++
 pixman/pixman-linear-gradient.c  |  116 +++--
 pixman/pixman-matrix.c           |    3 
 pixman/pixman-mmx.c              |   26 -
 pixman/pixman-private.h          |  184 +++++---
 pixman/pixman-radial-gradient.c  |   83 ++-
 pixman/pixman-solid-fill.c       |   75 +--
 pixman/pixman-sse2.c             |  111 ++---
 pixman/pixman-utils.c            |    6 
 pixman/pixman.c                  |   97 ----
 pixman/pixman.h                  |   22 -
 pixman/solaris-hwcap.mapfile     |    2 
 test/Makefile.am                 |   43 +
 test/alphamap.c                  |   11 
 test/blitters-test.c             |   57 --
 test/composite.c                 |   56 +-
 test/gradient-crash-test.c       |  123 +++--
 test/pdf-op-test.c               |   84 +++
 test/radial-test.c               |  198 +++++++++
 test/stress-test.c               |  855 +++++++++++++++++++++++++++++++++++++++
 test/utils.c                     |   89 +++-
 test/utils.h                     |   19 
 test/window-test.c               |  173 -------
 40 files changed, 3603 insertions(+), 1274 deletions(-)

New commits:
commit 4e56cec5649b7e122ccfc815b4ff45611953afce
Author: Søren Sandmann Pedersen <ssp@redhat.com>
Date:   Wed Jan 19 07:38:24 2011 -0500

    Pre-release version bump to 0.21.4

diff --git a/configure.ac b/configure.ac
index 6552f12..b2ecbba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -54,7 +54,7 @@ AC_PREREQ([2.57])
 
 m4_define([pixman_major], 0)
 m4_define([pixman_minor], 21)
-m4_define([pixman_micro], 3)
+m4_define([pixman_micro], 4)
 
 m4_define([pixman_version],[pixman_major.pixman_minor.pixman_micro])
 

commit 1d7195dd6c68eab73d063f37de3a9331446111d4
Author: Søren Sandmann Pedersen <ssp@redhat.com>
Date:   Mon Jan 17 14:12:20 2011 -0500

    Fix dangling-pointer bug in bits_image_fetch_bilinear_no_repeat_8888().
    
    The mask_bits variable is only declared in a limited scope, so the
    pointer to it becomes invalid instantly. Somehow this didn't actually
    trigger any bugs, but Brent Fulgham reported that Bounds Checker was
    complaining about it.
    
    Fix the bug by moving mask_bits to the function scope.

diff --git a/pixman/pixman-bits-image.c b/pixman/pixman-bits-image.c
index 98a2b6d..a865d71 100644
--- a/pixman/pixman-bits-image.c
+++ b/pixman/pixman-bits-image.c
@@ -295,6 +295,7 @@ bits_image_fetch_bilinear_no_repeat_8888 (pixman_image_t * ima,
     uint32_t *bottom_row;
     uint32_t *end;
     uint32_t zero[2] = { 0, 0 };
+    uint32_t one = 1;
     int y, y1, y2;
     int disty;
     int mask_inc;
@@ -360,10 +361,8 @@ bits_image_fetch_bilinear_no_repeat_8888 (pixman_image_t * ima,
      */
     if (!mask)
     {
-	uint32_t mask_bits = 1;
-
         mask_inc = 0;
-        mask = &mask_bits;
+        mask = &one;
     }
     else
     {

commit 2ac4ae1ae253f7c2efedab036a677dac2f9c9eed
Author: Andrea Canciani <ranma42@gmail.com>
Date:   Wed Jan 12 17:43:40 2011 +0100

    Add a test for radial gradients
    
    radial-test is a port of the radial-gradient test from the cairo test
    suite. It has been modified so that some pixels have 0 in both the a
    and b coefficients of the quadratic equation solved by the rasterizer,
    to expose a division by zero in the original implementation.

diff --git a/test/Makefile.am b/test/Makefile.am
index 71e5353..8d8471d 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -92,6 +92,7 @@ TESTPROGRAMS_GTK =		\
 	clip-in			\
 	composite-test		\
 	gradient-test		\
+	radial-test		\
 	alpha-test		\
 	screen-test		\
 	convolution-test	\
@@ -102,6 +103,9 @@ INCLUDES += $(GTK_CFLAGS)
 gradient_test_LDADD = $(GTK_LDADD)
 gradient_test_SOURCES = gradient-test.c $(GTK_UTILS)
 
+radial_test_LDADD = $(GTK_LDADD)
+radial_test_SOURCES = radial-test.c utils.c utils.h $(GTK_UTILS)
+
 alpha_test_LDADD = $(GTK_LDADD)
 alpha_test_SOURCES = alpha-test.c $(GTK_UTILS)
 
diff --git a/test/radial-test.c b/test/radial-test.c
new file mode 100644
index 0000000..5d716c3
--- /dev/null
+++ b/test/radial-test.c
@@ -0,0 +1,198 @@
+#include "utils.h"
+#include "gtk-utils.h"
+
+#define NUM_GRADIENTS 7
+#define NUM_STOPS 3
+#define NUM_REPEAT 4
+#define SIZE 128
+#define WIDTH (SIZE * NUM_GRADIENTS)
+#define HEIGHT (SIZE * NUM_REPEAT)
+
+/*
+ * We want to test all the possible relative positions of the start
+ * and end circle:
+ *
+ *  - The start circle can be smaller/equal/bigger than the end
+ *    circle. A radial gradient can be classified in one of these
+ *    three cases depending on the sign of dr.
+ *
+ *  - The smaller circle can be completely inside/internally
+ *    tangent/outside (at least in part) of the bigger circle. This
+ *    classification is the same as the one which can be computed by
+ *    examining the sign of a = (dx^2 + dy^2 - dr^2).
+ *
+ *  - If the two circles have the same size, neither can be inside or
+ *    internally tangent
+ *
+ * This test draws radial gradients whose circles always have the same
+ * centers (0, 0) and (1, 0), but with different radiuses. From left
+ * to right:
+ *
+ * - Small start circle completely inside the end circle
+ *     0.25 -> 1.75; dr =  1.5 > 0; a = 1 - 1.50^2 < 0
+ *
+ * - Small start circle internally tangent to the end circle
+ *     0.50 -> 1.50; dr =  1.0 > 0; a = 1 - 1.00^2 = 0
+ *
+ * - Small start circle outside of the end circle
+ *     0.50 -> 1.00; dr =  0.5 > 0; a = 1 - 0.50^2 > 0
+ *
+ * - Start circle with the same size as the end circle
+ *     1.00 -> 1.00; dr =  0.0 = 0; a = 1 - 0.00^2 > 0
+ *
+ * - Small end circle outside of the start circle
+ *     1.00 -> 0.50; dr = -0.5 > 0; a = 1 - 0.50^2 > 0
+ *
+ * - Small end circle internally tangent to the start circle
+ *     1.50 -> 0.50; dr = -1.0 > 0; a = 1 - 1.00^2 = 0
+ *
+ * - Small end circle completely inside the start circle
+ *     1.75 -> 0.25; dr = -1.5 > 0; a = 1 - 1.50^2 < 0
+ *
+ */
+
+const static double radiuses[NUM_GRADIENTS] = {
+    0.25,
+    0.50,
+    0.50,
+    1.00,
+    1.00,
+    1.50,
+    1.75
+};
+
+#define double_to_color(x)					\
+    (((uint32_t) ((x)*65536)) - (((uint32_t) ((x)*65536)) >> 16))
+
+#define PIXMAN_STOP(offset,r,g,b,a)		\
+    { pixman_double_to_fixed (offset),		\
+	{					\
+	double_to_color (r),			\
+	double_to_color (g),			\
+	double_to_color (b),			\
+	double_to_color (a)			\
+	}					\
+    }
+
+static const pixman_gradient_stop_t stops[NUM_STOPS] = {
+    PIXMAN_STOP (0.0,        1, 0, 0, 0.75),
+    PIXMAN_STOP (0.70710678, 0, 1, 0, 0),
+    PIXMAN_STOP (1.0,        0, 0, 1, 1)
+};
+
+static pixman_image_t *
+create_radial (int index)
+{
+    pixman_point_fixed_t p0, p1;
+    pixman_fixed_t r0, r1;
+    double x0, x1, radius0, radius1, left, right, center;
+
+    x0 = 0;
+    x1 = 1;
+    radius0 = radiuses[index];
+    radius1 = radiuses[NUM_GRADIENTS - index - 1];
+
+    /* center the gradient */
+    left = MIN (x0 - radius0, x1 - radius1);
+    right = MAX (x0 + radius0, x1 + radius1);
+    center = (left + right) * 0.5;
+    x0 -= center;
+    x1 -= center;
+
+    /* scale to make it fit within a 1x1 rect centered in (0,0) */
+    x0 *= 0.25;
+    x1 *= 0.25;
+    radius0 *= 0.25;
+    radius1 *= 0.25;
+
+    p0.x = pixman_double_to_fixed (x0);
+    p0.y = pixman_double_to_fixed (0);
+
+    p1.x = pixman_double_to_fixed (x1);
+    p1.y = pixman_double_to_fixed (0);
+
+    r0 = pixman_double_to_fixed (radius0);
+    r1 = pixman_double_to_fixed (radius1);
+
+    return pixman_image_create_radial_gradient (&p0, &p1,
+						r0, r1,
+						stops, NUM_STOPS);
+}
+
+static const pixman_repeat_t repeat[NUM_REPEAT] = {
+    PIXMAN_REPEAT_NONE,
+    PIXMAN_REPEAT_NORMAL,
+    PIXMAN_REPEAT_REFLECT,
+    PIXMAN_REPEAT_PAD
+};
+
+int
+main (int argc, char **argv)
+{
+    pixman_transform_t transform;
+    pixman_image_t *src_img, *dest_img;
+    int i, j;
+
+    enable_fp_exceptions ();
+
+    dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8,
+					 WIDTH, HEIGHT,
+					 NULL, 0);
+
+    pixman_transform_init_identity (&transform);
+
+    /*
+     * The create_radial() function returns gradients centered in the
+     * origin and whose interesting part fits a 1x1 square. We want to
+     * paint these gradients on a SIZExSIZE square and to make things
+     * easier we want the origin in the top-left corner of the square
+     * we want to see.
+     */
+    pixman_transform_translate (NULL, &transform,
+				pixman_double_to_fixed (0.5),
+				pixman_double_to_fixed (0.5));
+
+    pixman_transform_scale (NULL, &transform,
+			    pixman_double_to_fixed (SIZE),
+			    pixman_double_to_fixed (SIZE));
+
+    /*
+     * Gradients are evaluated at the center of each pixel, so we need
+     * to translate by half a pixel to trigger some interesting
+     * cornercases. In particular, the original implementation of PDF
+     * radial gradients tried to divide by 0 when using this transform
+     * on the "tangent circles" cases.
+     */
+    pixman_transform_translate (NULL, &transform,
+				pixman_double_to_fixed (0.5),
+				pixman_double_to_fixed (0.5));
+
+    for (i = 0; i < NUM_GRADIENTS; i++)
+    {
+	src_img = create_radial (i);
+	pixman_image_set_transform (src_img, &transform);
+
+	for (j = 0; j < NUM_REPEAT; j++)
+	{
+	    pixman_image_set_repeat (src_img, repeat[j]);
+
+	    pixman_image_composite32 (PIXMAN_OP_OVER,
+				      src_img,
+				      NULL,
+				      dest_img,
+				      0, 0,
+				      0, 0,
+				      i * SIZE, j * SIZE,
+				      SIZE, SIZE);
+
+	}
+
+	pixman_image_unref (src_img);
+    }
+
+    show_image (dest_img);
+
+    pixman_image_unref (dest_img);
+
+    return 0;
+}

commit 7f4eabbeec92e55fd8f812c0e5d8568eacbb633d
Author: Søren Sandmann Pedersen <ssp@redhat.com>
Date:   Sun Dec 12 07:34:42 2010 -0500

    Fix destination fetching
    
    When fetching from destinations, we need to ignore transformations,
    repeat and filtering. Currently we don't ignore them, which means all
    kinds of bad things can happen.
    
    This bug fixes this problem by directly calling the scanline fetchers
    for destinations instead of going through the full
    get_scanline_32/64().

diff --git a/pixman/pixman-bits-image.c b/pixman/pixman-bits-image.c
index 8cabfdc..98a2b6d 100644
--- a/pixman/pixman-bits-image.c
+++ b/pixman/pixman-bits-image.c
@@ -1377,8 +1377,22 @@ _pixman_bits_image_src_iter_init (pixman_image_t *image,
 static uint32_t *
 dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 {
-    iter->image->bits.get_scanline_32 (
-	iter->image, iter->x, iter->y, iter->width, iter->buffer, mask);
+    pixman_image_t *image  = iter->image;
+    int             x      = iter->x;
+    int             y      = iter->y;
+    int             width  = iter->width;
+    uint32_t *	    buffer = iter->buffer;
+
+    image->bits.fetch_scanline_32 (image, x, y, width, buffer, mask);
+    if (image->common.alpha_map)
+    {
+	x -= image->common.alpha_origin_x;
+	y -= image->common.alpha_origin_y;
+
+	image->common.alpha_map->fetch_scanline_32 (
+	    (pixman_image_t *)image->common.alpha_map,
+	    x, y, width, buffer, mask);
+    }
 
     return iter->buffer;
 }
@@ -1386,8 +1400,22 @@ dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 static uint32_t *
 dest_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
 {
-    iter->image->bits.get_scanline_64 (
-	iter->image, iter->x, iter->y, iter->width, iter->buffer, mask);
+    bits_image_t *  image  = &iter->image->bits;
+    int             x      = iter->x;
+    int             y      = iter->y;
+    int             width  = iter->width;
+    uint32_t *	    buffer = iter->buffer;
+
+    image->fetch_scanline_64 (
+	(pixman_image_t *)image, x, y, width, buffer, mask);
+    if (image->common.alpha_map)
+    {
+	x -= image->common.alpha_origin_x;
+	y -= image->common.alpha_origin_y;
+
+	image->common.alpha_map->fetch_scanline_64 (
+	    (pixman_image_t *)image->common.alpha_map, x, y, width, buffer, mask);
+    }
 
     return iter->buffer;
 }

commit 9489c2e04a5361fe19a89a0da9d7be28436c0a4b
Author: Søren Sandmann Pedersen <ssp@redhat.com>
Date:   Sun Dec 12 09:19:13 2010 -0500

    Turn on testing for destination transformation

diff --git a/test/alphamap.c b/test/alphamap.c
index 9fb8969..554b309 100644
--- a/test/alphamap.c
+++ b/test/alphamap.c
@@ -165,20 +165,17 @@ run_test (int s, int d, int sa, int da, int soff, int doff)
     orig_dst = create_image (df, daf, doff, doff);
     dst = create_image (df, daf, doff, doff);
 
-    /* Transformations on destinations should be ignored, so just set some
-     * random one.
+    /* Transformations, repeats and filters on destinations should be ignored,
+     * so just set some random ones.
      */
     pixman_transform_init_identity (&t1);
     pixman_transform_scale (&t1, NULL, pixman_int_to_fixed (100), pixman_int_to_fixed (11));
     pixman_transform_rotate (&t1, NULL, pixman_double_to_fixed (0.5), pixman_double_to_fixed (0.11));
     pixman_transform_translate (&t1, NULL, pixman_int_to_fixed (11), pixman_int_to_fixed (17));
 
-#if 0
-    /* Unfortunately, this is actually broken at the moment, so we can't
-     * actually turn it on
-     */
     pixman_image_set_transform (dst, &t1);
-#endif
+    pixman_image_set_filter (dst, PIXMAN_FILTER_BILINEAR, NULL, 0);
+    pixman_image_set_repeat (dst, PIXMAN_REPEAT_REFLECT);
 
     pixman_image_composite (PIXMAN_OP_SRC, orig_dst, NULL, dst,
 			    0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);

commit fffeda703e40ced90ec5ad6d6cd37a44294d3fe4
Author: Søren Sandmann Pedersen <ssp@redhat.com>
Date:   Sat Dec 11 08:10:04 2010 -0500

    Skip fetching pixels when possible
    
    Add two new iterator flags, ITER_IGNORE_ALPHA and ITER_IGNORE_RGB that
    are set when the alpha and rgb values are not needed. If both are set,
    then we can skip fetching entirely and just use
    _pixman_iter_get_scanline_noop.

diff --git a/pixman/pixman-bits-image.c b/pixman/pixman-bits-image.c
index 8d4e4f5..8cabfdc 100644
--- a/pixman/pixman-bits-image.c
+++ b/pixman/pixman-bits-image.c
@@ -1466,7 +1466,16 @@ _pixman_bits_image_dest_iter_init (pixman_image_t *image,
 	}
 	else
 	{
-	    iter->get_scanline = dest_get_scanline_narrow;
+	    if ((flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ==
+		(ITER_IGNORE_RGB | ITER_IGNORE_ALPHA))
+	    {
+		iter->get_scanline = _pixman_iter_get_scanline_noop;
+	    }
+	    else
+	    {
+		iter->get_scanline = dest_get_scanline_narrow;
+	    }
+
 	    iter->write_back = dest_write_back_narrow;
 	}
     }
diff --git a/pixman/pixman-general.c b/pixman/pixman-general.c
index e7a7283..16ea3a4 100644
--- a/pixman/pixman-general.c
+++ b/pixman/pixman-general.c
@@ -107,6 +107,34 @@ general_dest_iter_init (pixman_implementation_t *imp,
     }
 }
 
+typedef struct op_info_t op_info_t;
+struct op_info_t
+{
+    uint8_t src, dst;
+};
+
+#define ITER_IGNORE_BOTH						\
+    (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB | ITER_LOCALIZED_ALPHA)
+
+static const op_info_t op_flags[PIXMAN_N_OPERATORS] =
+{
+    /* Src                   Dst                   */
+    { ITER_IGNORE_BOTH,      ITER_IGNORE_BOTH      }, /* CLEAR */
+    { ITER_LOCALIZED_ALPHA,  ITER_IGNORE_BOTH      }, /* SRC */
+    { ITER_IGNORE_BOTH,      ITER_LOCALIZED_ALPHA  }, /* DST */
+    { 0,                     ITER_LOCALIZED_ALPHA  }, /* OVER */
+    { ITER_LOCALIZED_ALPHA,  0                     }, /* OVER_REVERSE */
+    { ITER_LOCALIZED_ALPHA,  ITER_IGNORE_RGB       }, /* IN */
+    { ITER_IGNORE_RGB,       ITER_LOCALIZED_ALPHA  }, /* IN_REVERSE */
+    { ITER_LOCALIZED_ALPHA,  ITER_IGNORE_RGB       }, /* OUT */
+    { ITER_IGNORE_RGB,       ITER_LOCALIZED_ALPHA  }, /* OUT_REVERSE */
+    { 0,                     0                     }, /* ATOP */
+    { 0,                     0                     }, /* ATOP_REVERSE */
+    { 0,                     0                     }, /* XOR */
+    { ITER_LOCALIZED_ALPHA,  ITER_LOCALIZED_ALPHA  }, /* ADD */
+    { 0,                     0                     }, /* SATURATE */
+};
+
 #define SCANLINE_BUFFER_LENGTH 8192
 
 static void
@@ -130,7 +158,7 @@ general_composite_rect  (pixman_implementation_t *imp,
     pixman_iter_t src_iter, mask_iter, dest_iter;
     pixman_combine_32_func_t compose;
     pixman_bool_t component_alpha;
-    iter_flags_t narrow, dest_flags;
+    iter_flags_t narrow, src_flags;
     int Bpp;
     int i;
 
@@ -159,39 +187,39 @@ general_composite_rect  (pixman_implementation_t *imp,
     mask_buffer = src_buffer + width * Bpp;
     dest_buffer = mask_buffer + width * Bpp;
 
+    /* src iter */
+    src_flags = narrow | op_flags[op].src;
+
     _pixman_implementation_src_iter_init (imp->toplevel, &src_iter, src,
 					  src_x, src_y, width, height,
-					  src_buffer, narrow);
-
-    _pixman_implementation_src_iter_init (imp->toplevel, &mask_iter, mask,
-					  mask_x, mask_y, width, height,
-					  mask_buffer, narrow);
-
-    if (op == PIXMAN_OP_CLEAR		||
-	op == PIXMAN_OP_SRC		||
-	op == PIXMAN_OP_DST		||
-	op == PIXMAN_OP_OVER		||
-	op == PIXMAN_OP_IN_REVERSE	||
-	op == PIXMAN_OP_OUT_REVERSE	||
-	op == PIXMAN_OP_ADD)
-    {
-	dest_flags = narrow | ITER_LOCALIZED_ALPHA;
-    }
-    else
+					  src_buffer, src_flags);
+
+    /* mask iter */
+    if ((src_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) ==
+	(ITER_IGNORE_ALPHA | ITER_IGNORE_RGB))
     {
-	dest_flags = narrow;
+	/* If it doesn't matter what the source is, then it doesn't matter
+	 * what the mask is
+	 */
+	mask = NULL;
     }
 
-    _pixman_implementation_dest_iter_init (imp->toplevel, &dest_iter, dest,
-					   dest_x, dest_y, width, height,
-					   dest_buffer, dest_flags);
-
     component_alpha =
         mask                            &&
         mask->common.type == BITS       &&
         mask->common.component_alpha    &&
         PIXMAN_FORMAT_RGB (mask->bits.format);
 
+    _pixman_implementation_src_iter_init (
+	imp->toplevel, &mask_iter, mask, mask_x, mask_y, width, height,
+	mask_buffer, narrow | (component_alpha? 0 : ITER_IGNORE_RGB));
+
+    /* dest iter */
+    _pixman_implementation_dest_iter_init (imp->toplevel, &dest_iter, dest,
+					   dest_x, dest_y, width, height,
+					   dest_buffer,
+					   narrow | op_flags[op].dst);
+
     if (narrow)
     {
 	if (component_alpha)
diff --git a/pixman/pixman-implementation.c b/pixman/pixman-implementation.c
index e633432..adaf9c6 100644
--- a/pixman/pixman-implementation.c
+++ b/pixman/pixman-implementation.c
@@ -278,6 +278,11 @@ _pixman_implementation_src_iter_init (pixman_implementation_t	*imp,
     {
 	iter->get_scanline = get_scanline_null;
     }
+    else if ((flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) ==
+	     (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB))
+    {
+	iter->get_scanline = _pixman_iter_get_scanline_noop;
+    }
     else
     {
 	(*imp->src_iter_init) (
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 0aeae2e..1662d2c 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -202,7 +202,9 @@ typedef enum
      * we can treat it as if it were ARGB, which means in some cases we can
      * avoid copying it to a temporary buffer.
      */
-    ITER_LOCALIZED_ALPHA =	(1 << 1)
+    ITER_LOCALIZED_ALPHA =	(1 << 1),
+    ITER_IGNORE_ALPHA =		(1 << 2),
+    ITER_IGNORE_RGB =		(1 << 3)
 } iter_flags_t;
 
 struct pixman_iter_t

commit 3e635d6491d883304662aff3c72558dc9065f1f1
Author: Søren Sandmann Pedersen <ssp@redhat.com>
Date:   Fri Dec 10 16:55:55 2010 -0500

    Add direct-write optimization back
    
    Introduce a new ITER_LOCALIZED_ALPHA flag that indicates that the
    alpha value computed is used only for the alpha channel of the output;
    it doesn't affect the RGB channels.
    
    Then in pixman-bits-image.c, if a destination is either a8r8g8b8 or
    x8r8g8b8 with localized alpha, the iterator will return a pointer
    directly into the image.

diff --git a/pixman/pixman-bits-image.c b/pixman/pixman-bits-image.c
index 983e23c..8d4e4f5 100644
--- a/pixman/pixman-bits-image.c
+++ b/pixman/pixman-bits-image.c
@@ -1438,6 +1438,12 @@ dest_write_back_wide (pixman_iter_t *iter)
     iter->y++;
 }
 
+static void
+dest_write_back_direct (pixman_iter_t *iter)
+{
+    iter->buffer += iter->image->bits.rowstride;
+}
+
 void
 _pixman_bits_image_dest_iter_init (pixman_image_t *image,
 				   pixman_iter_t *iter,
@@ -1446,8 +1452,23 @@ _pixman_bits_image_dest_iter_init (pixman_image_t *image,
 {
     if (flags & ITER_NARROW)
     {
-	iter->get_scanline = dest_get_scanline_narrow;
-	iter->write_back = dest_write_back_narrow;
+	if (((image->common.flags &
+	      (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_NO_ACCESSORS)) ==
+	     (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_NO_ACCESSORS)) &&
+	    (image->bits.format == PIXMAN_a8r8g8b8	||
+	     (image->bits.format == PIXMAN_x8r8g8b8	&&
+	      (flags & ITER_LOCALIZED_ALPHA))))
+	{
+	    iter->buffer = image->bits.bits + y * image->bits.rowstride + x;
+
+	    iter->get_scanline = _pixman_iter_get_scanline_noop;
+	    iter->write_back = dest_write_back_direct;
+	}
+	else
+	{
+	    iter->get_scanline = dest_get_scanline_narrow;
+	    iter->write_back = dest_write_back_narrow;
+	}
     }
     else
     {
diff --git a/pixman/pixman-general.c b/pixman/pixman-general.c
index e2f1dc3..e7a7283 100644
--- a/pixman/pixman-general.c
+++ b/pixman/pixman-general.c
@@ -130,7 +130,7 @@ general_composite_rect  (pixman_implementation_t *imp,
     pixman_iter_t src_iter, mask_iter, dest_iter;
     pixman_combine_32_func_t compose;
     pixman_bool_t component_alpha;
-    iter_flags_t narrow;
+    iter_flags_t narrow, dest_flags;
     int Bpp;
     int i;
 
@@ -167,9 +167,24 @@ general_composite_rect  (pixman_implementation_t *imp,
 					  mask_x, mask_y, width, height,
 					  mask_buffer, narrow);
 
+    if (op == PIXMAN_OP_CLEAR		||
+	op == PIXMAN_OP_SRC		||
+	op == PIXMAN_OP_DST		||
+	op == PIXMAN_OP_OVER		||
+	op == PIXMAN_OP_IN_REVERSE	||
+	op == PIXMAN_OP_OUT_REVERSE	||
+	op == PIXMAN_OP_ADD)
+    {
+	dest_flags = narrow | ITER_LOCALIZED_ALPHA;
+    }
+    else
+    {
+	dest_flags = narrow;
+    }
+
     _pixman_implementation_dest_iter_init (imp->toplevel, &dest_iter, dest,
 					   dest_x, dest_y, width, height,
-					   dest_buffer, narrow);
+					   dest_buffer, dest_flags);
 
     component_alpha =
         mask                            &&
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index c3321e1..0aeae2e 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -185,7 +185,24 @@ union pixman_image
 typedef struct pixman_iter_t pixman_iter_t;
 typedef enum
 {
-    ITER_NARROW	= (1 << 0),
+    ITER_NARROW =		(1 << 0),
+
+    /* "Localized alpha" is when the alpha channel is used only to compute
+     * the alpha value of the destination. This means that the computation
+     * of the RGB values of the result is independent of the alpha value.
+     *
+     * For example, the OVER operator has localized alpha for the
+     * destination, because the RGB values of the result can be computed
+     * without knowing the destination alpha. Similarly, ADD has localized
+     * alpha for both source and destination because the RGB values of the
+     * result can be computed without knowing the alpha value of source or
+     * destination.
+     *
+     * When he destination is xRGB, this is useful knowledge, because then
+     * we can treat it as if it were ARGB, which means in some cases we can
+     * avoid copying it to a temporary buffer.
+     */
+    ITER_LOCALIZED_ALPHA =	(1 << 1)
 } iter_flags_t;
 
 struct pixman_iter_t

commit 0f1a5c4a27d34dcf4525dc38fcb48c14f653e828
Author: Søren Sandmann Pedersen <ssp@redhat.com>
Date:   Fri Dec 10 15:18:48 2010 -0500

    Get rid of the classify methods
    
    They are not used anymore, and the linear gradient is now doing the
    optimization in a different way.

diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index 1aa9de1..a72299b 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -72,7 +72,6 @@ _pixman_image_allocate (void)
 	common->alpha_map = NULL;
 	common->component_alpha = FALSE;
 	common->ref_count = 1;
-	common->classify = NULL;
 	common->property_changed = NULL;
 	common->client_clip = FALSE;
 	common->destroy_func = NULL;
@@ -83,19 +82,6 @@ _pixman_image_allocate (void)
     return image;
 }
 
-source_image_class_t
-_pixman_image_classify (pixman_image_t *image,
-                        int             x,
-                        int             y,
-                        int             width,
-                        int             height)
-{
-    if (image->common.classify)
-	return image->common.classify (image, x, y, width, height);
-    else
-	return SOURCE_IMAGE_CLASS_UNKNOWN;
-}
-
 static void
 image_property_changed (pixman_image_t *image)
 {
diff --git a/pixman/pixman-linear-gradient.c b/pixman/pixman-linear-gradient.c
index 66d37ab..07303fc 100644
--- a/pixman/pixman-linear-gradient.c
+++ b/pixman/pixman-linear-gradient.c
@@ -31,21 +31,18 @@
 #include <stdlib.h>
 #include "pixman-private.h"
 
-static source_image_class_t
-linear_gradient_classify (pixman_image_t *image,
-                          int             x,
-                          int             y,
-                          int             width,
-                          int             height)
+static pixman_bool_t
+linear_gradient_is_horizontal (pixman_image_t *image,
+			       int             x,
+			       int             y,
+			       int             width,
+			       int             height)
 {
     linear_gradient_t *linear = (linear_gradient_t *)image;
     pixman_vector_t v;
     pixman_fixed_32_32_t l;
     pixman_fixed_48_16_t dx, dy;
     double inc;
-    source_image_class_t class;
-
-    class = SOURCE_IMAGE_CLASS_UNKNOWN;
 
     if (image->common.transform)
     {
@@ -54,7 +51,7 @@ linear_gradient_classify (pixman_image_t *image,
 	    image->common.transform->matrix[2][1] != 0 ||
 	    image->common.transform->matrix[2][2] == 0)
 	{
-	    return class;
+	    return FALSE;
 	}
 
 	v.vector[0] = image->common.transform->matrix[0][1];
@@ -74,7 +71,7 @@ linear_gradient_classify (pixman_image_t *image,
     l = dx * dx + dy * dy;
 
     if (l == 0)
-	return class;	
+	return FALSE;
 
     /*
      * compute how much the input of the gradient walked changes
@@ -86,9 +83,9 @@ linear_gradient_classify (pixman_image_t *image,
 
     /* check that casting to integer would result in 0 */
     if (-1 < inc && inc < 1)
-	class = SOURCE_IMAGE_CLASS_HORIZONTAL;
+	return TRUE;
 
-    return class;
+    return FALSE;
 }
 
 static uint32_t *
@@ -245,8 +242,7 @@ _pixman_linear_gradient_iter_init (pixman_image_t *image,
 				   uint8_t        *buffer,
 				   iter_flags_t    flags)
 {
-    if (linear_gradient_classify (image, x, y, width, height) ==
-	SOURCE_IMAGE_CLASS_HORIZONTAL)
+    if (linear_gradient_is_horizontal (image, x, y, width, height))
     {
 	if (flags & ITER_NARROW)
 	    linear_get_scanline_narrow (iter, NULL);
@@ -290,7 +286,6 @@ pixman_image_create_linear_gradient (pixman_point_fixed_t *        p1,
     linear->p2 = *p2;
 
     image->type = LINEAR;
-    image->common.classify = linear_gradient_classify;
 
     return image;
 }
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index d7c7a62..c3321e1 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -60,17 +60,6 @@ typedef enum
     SOLID
 } image_type_t;
 
-typedef enum
-{
-    SOURCE_IMAGE_CLASS_UNKNOWN,
-    SOURCE_IMAGE_CLASS_HORIZONTAL,
-} source_image_class_t;
-
-typedef source_image_class_t (*classify_func_t) (pixman_image_t *image,
-						int             x,
-						int             y,
-						int             width,
-						int             height);
 typedef void (*property_changed_func_t) (pixman_image_t *image);
 
 struct image_common
@@ -95,7 +84,6 @@ struct image_common
     int                         alpha_origin_x;
     int                         alpha_origin_y;
     pixman_bool_t               component_alpha;
-    classify_func_t             classify;
     property_changed_func_t     property_changed;
 
     pixman_image_destroy_func_t destroy_func;
@@ -249,13 +237,6 @@ _pixman_conical_gradient_iter_init (pixman_image_t *image,
 				    int x, int y, int width, int height,
 				    uint8_t *buffer, iter_flags_t flags);
 
-source_image_class_t
-_pixman_image_classify (pixman_image_t *image,
-                        int             x,
-                        int             y,
-                        int             width,
-                        int             height);
-
 pixman_image_t *
 _pixman_image_allocate (void);
 
diff --git a/pixman/pixman-solid-fill.c b/pixman/pixman-solid-fill.c
index a431d74..67681f2 100644
--- a/pixman/pixman-solid-fill.c
+++ b/pixman/pixman-solid-fill.c
@@ -26,16 +26,6 @@
 #endif
 #include "pixman-private.h"
 
-static source_image_class_t
-solid_fill_classify (pixman_image_t *image,
-                     int             x,
-                     int             y,
-                     int             width,
-                     int             height)
-{
-    return SOURCE_IMAGE_CLASS_HORIZONTAL;
-}
-
 void
 _pixman_solid_fill_iter_init (pixman_image_t *image,
 			      pixman_iter_t  *iter,
@@ -97,8 +87,6 @@ pixman_image_create_solid_fill (pixman_color_t *color)
     img->solid.color_32 = color_to_uint32 (color);
     img->solid.color_64 = color_to_uint64 (color);
 
-    img->common.classify = solid_fill_classify;
-
     return img;
 }
 

commit b66cabb88488413c4787845c7da67901dc988ee6
Author: Søren Sandmann Pedersen <ssp@redhat.com>
Date:   Fri Dec 10 15:14:24 2010 -0500

    Linear: Optimize for horizontal gradients
    
    If the gradient is horizontal, we can reuse the same scanline over and
    over. Add support for this optimization to
    _pixman_linear_gradient_iter_init().

diff --git a/pixman/pixman-linear-gradient.c b/pixman/pixman-linear-gradient.c
index c657243..66d37ab 100644
--- a/pixman/pixman-linear-gradient.c
+++ b/pixman/pixman-linear-gradient.c
@@ -245,10 +245,23 @@ _pixman_linear_gradient_iter_init (pixman_image_t *image,
 				   uint8_t        *buffer,
 				   iter_flags_t    flags)
 {
-    if (flags & ITER_NARROW)
-	iter->get_scanline = linear_get_scanline_narrow;
+    if (linear_gradient_classify (image, x, y, width, height) ==
+	SOURCE_IMAGE_CLASS_HORIZONTAL)
+    {
+	if (flags & ITER_NARROW)
+	    linear_get_scanline_narrow (iter, NULL);
+	else
+	    linear_get_scanline_wide (iter, NULL);
+
+	iter->get_scanline = _pixman_iter_get_scanline_noop;
+    }
     else
-	iter->get_scanline = linear_get_scanline_wide;
+    {
+	if (flags & ITER_NARROW)
+	    iter->get_scanline = linear_get_scanline_narrow;
+	else
+	    iter->get_scanline = linear_get_scanline_wide;
+    }
 }
 
 PIXMAN_EXPORT pixman_image_t *

commit cf14189c6993e42ae71977a4a4061417941ffee8
Author: Søren Sandmann Pedersen <ssp@redhat.com>
Date:   Fri Dec 10 14:59:20 2010 -0500

    Consolidate the various get_scanline_32() into get_scanline_narrow()
    
    The separate get_scanline_32() functions in solid, linear, radial and
    conical images are no longer necessary because all access to these
    images now go through iterators.

diff --git a/pixman/pixman-conical-gradient.c b/pixman/pixman-conical-gradient.c
index d43b454..9d7d2e8 100644
--- a/pixman/pixman-conical-gradient.c
+++ b/pixman/pixman-conical-gradient.c
@@ -50,14 +50,15 @@ coordinates_to_parameter (double x, double y, double angle)
 				      */


Reply to: