summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2010-03-26 18:31:58 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2010-03-26 18:31:58 -0400
commitc36a619145a3d18cdc2686fbe8e22f3d5376d7b8 (patch)
treea93a8628f42e80d69d9378e5a9f4c66e1d64725a
parent57c9cb83267b5baeaaf46ac7c2c3b8ba728c0092 (diff)
Add completely untested fast path for radial gradientsradial-fast
-rw-r--r--pixman/pixman-fast-path.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/pixman/pixman-fast-path.c b/pixman/pixman-fast-path.c
index bf5b298c..b6d0159d 100644
--- a/pixman/pixman-fast-path.c
+++ b/pixman/pixman-fast-path.c
@@ -28,6 +28,7 @@
#endif
#include <string.h>
#include <stdlib.h>
+#include <math.h>
#include "pixman-private.h"
#include "pixman-combine32.h"
@@ -1748,6 +1749,108 @@ fast_composite_scaled_nearest (pixman_implementation_t *imp,
}
}
+static void
+fast_composite_over_radial_8_8888 (pixman_implementation_t *imp,
+ pixman_op_t op,
+ pixman_image_t * src_image,
+ pixman_image_t * mask_image,
+ pixman_image_t * dst_image,
+ int32_t src_x,
+ int32_t src_y,
+ int32_t mask_x,
+ int32_t mask_y,
+ int32_t dest_x,
+ int32_t dest_y,
+ int32_t width,
+ int32_t height)
+{
+ pixman_gradient_walker_t walker;
+ gradient_t *gradient = &(src_image->gradient);
+ uint32_t * dst_line, *dst;
+ uint8_t * mask_line, *mask;
+ int dst_stride;
+ int mask_stride;
+ uint32_t w;
+ radial_gradient_t *radial = (radial_gradient_t *)src_image;
+ int i, j;
+
+ double cx = 1.;
+ double cy = 0.;
+
+ PIXMAN_IMAGE_GET_LINE (dst_image, dest_x, dest_y, uint32_t,
+ dst_stride, dst_line, 1);
+ PIXMAN_IMAGE_GET_LINE (mask_image, 0, mask_y, uint8_t,
+ mask_stride, mask_line, 1);
+
+ _pixman_gradient_walker_init (&walker, gradient, src_image->common.repeat);
+
+ double r1 = radial->c1.radius / 65536.;
+ double r1sq = r1 * r1;
+ double A = radial->A;
+ double invA = -65536. / (2. * A);
+ double A4 = -4. * A;
+ pixman_bool_t invert = A * radial->dr < 0;
+
+ for (j = dest_y; j < dest_y + height; ++j)
+ {
+ dst = dst_line;
+ dst_line += dst_stride;
+ mask = mask_line;
+ mask_line += mask_stride;
+ w = width;
+ double ry = j + 0.5;
+ double rx = dest_x + 0.5;
+ double pdx = rx - radial->c1.x / 65536.;
+ double pdy = ry - radial->c1.y / 65536.;
+ double B = -2. * (pdx*radial->cdx + pdy*radial->cdy + r1*radial->dr);
+ double cB = -2. * (cx*radial->cdx + cy*radial->cdy);
+
+ for (i = dest_x; i < dest_x + width; ++i)
+ {
+ uint32_t m = *mask;
+
+ if (m)
+ {
+ pixman_fixed_48_16_t t;
+ uint32_t s, sa, d;
+ double det = B * B + A4 * (pdx * pdx + pdy * pdy - r1sq);
+ if (det <= 0.)
+ t = (pixman_fixed_48_16_t) (B * invA);
+ else if (invert)
+ t = (pixman_fixed_48_16_t) ((B + sqrt (det)) * invA);
+ else
+ t = (pixman_fixed_48_16_t) ((B - sqrt (det)) * invA);
+
+ s = _pixman_gradient_walker_pixel (&walker, t);
+
+ UN8x4_MUL_UN8 (s, m);
+
+ sa = s >> 24;
+
+ if (sa == 0xff)
+ {
+ *dst = s;
+ }
+ else
+ {
+ d = *dst;
+ sa = ~sa;
+
+ UN8x4_MUL_UN8_ADD_UN8x4 (d, sa, s);
+
+ *dst = d;
+ }
+ }
+
+ pdx += cx;
+ pdy += cy;
+ B += cB;
+ dst++;
+ mask++;
+ }
+ }
+}
+
static const pixman_fast_path_t c_fast_paths[] =
{
PIXMAN_STD_FAST_PATH (OVER, solid, a8, r5g6b5, fast_composite_over_n_8_0565),
@@ -1878,6 +1981,15 @@ static const pixman_fast_path_t c_fast_paths[] =
NEAREST_FAST_PATH (OVER, x8b8g8r8, a8b8g8r8),
NEAREST_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8),
+ { PIXMAN_OP_OVER,
+ PIXMAN_radial, ( FAST_PATH_ID_TRANSFORM |
+ FAST_PATH_NO_ACCESSORS |
+ FAST_PATH_NO_WIDE_FORMAT),
+ PIXMAN_a8, ( _FAST_PATH_STANDARD_FLAGS ),
+ PIXMAN_a8r8g8b8, ( FAST_PATH_STD_DEST_FLAGS ),
+ fast_composite_over_radial_8_8888
+ },
+
{ PIXMAN_OP_NONE },
};