[cairo] pixman box filtering code prototype
Jeff Muizelaar
jeff at infidigm.net
Thu May 21 13:23:33 PDT 2009
On Mon, Nov 17, 2008 at 06:05:34PM -0500, Jeff Muizelaar wrote:
> On Mon, Nov 17, 2008 at 06:00:03PM -0500, Jeff Muizelaar wrote:
> > I've attached a rough cut of what this could look like.
>
> Note: The new code is in pixman-rescale-mult.c
Here's a new version. It adds a lanczos downscaler and a bunch
of correctness fixes. It's basically feature complete and I plan on
cleaning it up enough to commit soon.
-Jeff
-------------- next part --------------
diff --git a/configure.ac b/configure.ac
index c555f25..f08fcd3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -106,6 +106,13 @@ if test "x$GCC" = "xyes"; then
*) CFLAGS="$CFLAGS -Wall" ;;
esac fi changequote([,])dnl
+changequote(,)dnl
+if test "x$GCC" = "xyes"; then
+ case " $CFLAGS " in
+ *[\ \ ]-Wdeclaration-after-statement[\ \ ]*) ;;
+ *) CFLAGS="$CFLAGS" ;;
+ esac fi changequote([,])dnl
+
AC_PATH_PROG(PERL, perl, no)
if test "x$PERL" = xno; then
AC_MSG_ERROR([Perl is required to build pixman.])
diff --git a/pixman/Makefile.am b/pixman/Makefile.am
index b55daa0..19b531c 100644
--- a/pixman/Makefile.am
+++ b/pixman/Makefile.am
@@ -33,6 +33,10 @@ libpixman_1_la_SOURCES = \
pixman-trap.c \
pixman-compute-region.c \
pixman-timer.c \
+ pixman-rescale-box.c \
+ pixman-rescale-mult.c \
+ pixman-rescale-mult-old.c \
+ pixman-rescale-lanczos.c \
pixman-matrix.c
libpixmanincludedir = $(includedir)/pixman-1/
diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index 9d62f4a..4697130 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -453,6 +453,14 @@ pixman_image_set_source_clipping (pixman_image_t *image,
image_property_changed (image);
}
+PIXMAN_EXPORT pixman_bool_t
+pixman_image_has_source_clipping (pixman_image_t *image)
+{
+ image_common_t *common = &image->common;
+
+ return common->src_clip != &common->full_region;
+}
+
/* Unlike all the other property setters, this function does not
* copy the content of indexed. Doing this copying is simply
* way, way too expensive.
diff --git a/pixman/pixman-pict.c b/pixman/pixman-pict.c
index b22785b..09a5762 100644
--- a/pixman/pixman-pict.c
+++ b/pixman/pixman-pict.c
@@ -37,6 +37,7 @@
#include "pixman-arm-simd.h"
#include "pixman-arm-neon.h"
#include "pixman-combine32.h"
+#include "pixman-rescale.h"
static void
fbCompositeSrcScaleNearest (pixman_op_t op,
@@ -412,6 +413,95 @@ pixman_optimize_operator(pixman_op_t op, pixman_image_t *pSrc, pixman_image_t *p
}
+pixman_image_t *create_downscaled_image(pixman_image_t *img, int scaled_width, int scaled_height)
+{
+ pixman_image_t *new_src = pixman_image_create_bits (PIXMAN_a8r8g8b8,
+ scaled_width, scaled_height, NULL, scaled_width * sizeof(uint32_t*) // XXX: should this come from someplace else
+ );
+ if (!new_src)
+ goto fail;
+
+ if (downscale_lanczos_filter(img, img->bits.width, img->bits.height,
+ scaled_width, scaled_height,
+ 0, 0,
+ scaled_width, scaled_height,
+ img->bits.bits, img->bits.rowstride*sizeof(uint32_t),
+ new_src->bits.bits, new_src->bits.rowstride*sizeof(uint32_t)))
+ goto resize_fail;
+
+ pixman_image_set_filter (new_src, img->common.filter,
+ img->common.filter_params,
+ img->common.n_filter_params);
+
+ pixman_image_set_repeat (new_src, img->common.repeat);
+
+ pixman_transform_t new_transform = *(img->common.transform);
+//#define unscaled_debug
+#ifdef unscaled_debug
+ printf("%x %x %x, %x %x %x\n",
+ new_transform.matrix[0][0],
+ new_transform.matrix[0][1],
+ new_transform.matrix[0][2],
+ new_transform.matrix[1][0],
+ new_transform.matrix[1][1],
+ new_transform.matrix[1][2]);
+#endif
+ pixman_fixed_t scale_x, scale_y;
+ pixman_fixed_t applied_scale_x, applied_scale_y;
+ applied_scale_x = div_fixed(img->bits.width, scaled_width);
+ applied_scale_y = div_fixed(img->bits.height, scaled_height);
+ pixman_extract_scale (&new_transform, &scale_x, &scale_y);
+ //printf("%x %x, %x %x\n", scale_x, applied_scale_x, scale_y, applied_scale_y);
+ pixman_transform_unscale (&new_transform, applied_scale_x, applied_scale_y);
+#define unscaled_debug 0
+#if unscaled_debug
+ printf("%x %x %x, %x %x %x\n",
+ new_transform.matrix[0][0],
+ new_transform.matrix[0][1],
+ new_transform.matrix[0][2],
+ new_transform.matrix[1][0],
+ new_transform.matrix[1][1],
+ new_transform.matrix[1][2]);
+#endif
+ pixman_image_set_transform (new_src, &new_transform);
+ return new_src;
+
+resize_fail:
+ pixman_image_unref(new_src);
+fail:
+ return NULL;
+}
+
+static pixman_bool_t
+is_translation_only(pixman_transform_t *transform) {
+ pixman_fixed_t (*matrix)[3] = transform->matrix;
+ return matrix[0][0] == pixman_fixed_1 &&
+ matrix[1][1] == pixman_fixed_1 &&
+ matrix[0][1] == 0 &&
+ matrix[1][0] == 0 &&
+ matrix[2][0] == 0 &&
+ matrix[2][1] == 0 &&
+ matrix[2][2] == pixman_fixed_1;
+}
+
+static void
+simplify_translation(pixman_image_t *img, int16_t *offset_x, int16_t *offset_y)
+{
+ if (is_translation_only(img->common.transform)) {
+ pixman_fixed_t (*matrix)[3] = img->common.transform->matrix;
+ if ((matrix[0][2] & 0xffff) == 0 && (matrix[1][2] & 0xffff) == 0) {
+ int shift_x = pixman_fixed_to_int(matrix[0][2]);
+ int shift_y = pixman_fixed_to_int(matrix[1][2]);
+ *offset_x += shift_x;
+ *offset_y += shift_y;
+ pixman_transform_t new = *img->common.transform;
+ new.matrix[0][2] = 0;
+ new.matrix[1][2] = 0;
+ pixman_image_set_transform(img, &new);
+ }
+ }
+}
+
#if defined(USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
/*
@@ -430,6 +520,7 @@ pixman_optimize_operator(pixman_op_t op, pixman_image_t *pSrc, pixman_image_t *p
* See https://bugs.freedesktop.org/show_bug.cgi?id=15693
*/
+
__attribute__((__force_align_arg_pointer__))
#endif
PIXMAN_EXPORT void
@@ -453,6 +544,8 @@ pixman_image_composite (pixman_op_t op,
pixman_bool_t srcAlphaMap = pSrc->common.alpha_map != NULL;
pixman_bool_t maskAlphaMap = FALSE;
pixman_bool_t dstAlphaMap = pDst->common.alpha_map != NULL;
+ pixman_bool_t downscaled = FALSE;
+ pixman_bool_t downscaledMask = FALSE;
CompositeFunc func = NULL;
#ifdef USE_MMX
@@ -474,6 +567,24 @@ pixman_image_composite (pixman_op_t op,
srcTransform = FALSE;
}
+
+ if (srcTransform && pSrc->type == BITS) {
+ int scaled_width;
+ int scaled_height;
+ pixman_get_scaled_size(pSrc->common.transform,
+ pSrc->bits.width, pSrc->bits.height,
+ &scaled_width, &scaled_height);
+ //printf("%d %d: %d %d\n", pSrc->bits.width, pSrc->bits.height, scaled_width, scaled_height);
+ if (scaled_width < pSrc->bits.width || scaled_height < pSrc->bits.height) {
+ //printf("downscale\n");
+ pSrc = create_downscaled_image(pSrc, scaled_width, scaled_height);
+ if (!pSrc)
+ return;
+ srcTransform = pSrc->common.transform != NULL;
+ downscaled = TRUE;
+ }
+ }
+
if (pMask && pMask->type == BITS)
{
maskRepeat = pMask->common.repeat == PIXMAN_REPEAT_NORMAL;
@@ -490,8 +601,78 @@ pixman_image_composite (pixman_op_t op,
{
maskTransform = FALSE;
}
+ if (maskTransform) {
+ int scaled_width;
+ int scaled_height;
+ pixman_get_scaled_size(pMask->common.transform,
+ pMask->bits.width, pMask->bits.height,
+ &scaled_width, &scaled_height);
+ //printf("%d %d: %d %d\n", pSrc->bits.width, pSrc->bits.height, scaled_width, scaled_height);
+ if (scaled_width < pMask->bits.width || scaled_height < pMask->bits.height) {
+ //printf("downscale\n");
+ pMask = create_downscaled_image(pMask, scaled_width, scaled_height);
+ if (!pMask)
+ return;
+ maskTransform = pMask->common.transform != NULL;
+ downscaledMask = TRUE;
+ }
+ }
+ }
+
+ if (pSrc->type == BITS && pSrc->common.transform) {
+ simplify_translation(pSrc, &xSrc, &ySrc);
+ srcTransform = pSrc->common.transform != NULL;
}
+ if (pMask && pMask->type == BITS && pMask->common.transform) {
+ simplify_translation(pMask, &xMask, &yMask);
+ maskTransform = pMask->common.transform != NULL;
+ }
+
+#if 0
+ if (((pSrc->type == BITS && pSrc->common.transform) || (pMask && pMask->type == BITS && pMask->common.transform))) {
+ pixman_fixed_t (*matrix)[3];
+ if (pSrc->common.transform) {
+ matrix = pSrc->common.transform->matrix;
+ } else {
+ matrix = pMask->common.transform->matrix;
+ }
+ if (matrix[0][0] == pixman_fixed_1 &&
+ matrix[1][1] == pixman_fixed_1 &&
+ matrix[0][1] == 0 &&
+ matrix[1][0] == 0 &&
+ matrix[2][0] == 0 &&
+ matrix[2][1] == 0 &&
+ matrix[2][2] == pixman_fixed_1) {
+ if ((matrix[0][2] & 0xffff) == 0 && (matrix[1][2] & 0xffff) == 0) {
+ int shift_x = pixman_fixed_to_int(matrix[0][2]);
+ int shift_y = pixman_fixed_to_int(matrix[1][2]);
+ xSrc += shift_x;
+ ySrc += shift_y;
+ xMask += shift_x;
+ yMask += shift_y;
+
+ pixman_transform_t new = *pSrc->common.transform;
+ new.matrix[0][2] = 0;
+ new.matrix[1][2] = 0;
+ if (pMask && pMask->common.transform) {
+ pixman_image_set_transform(pSrc, &new);
+ maskTransform = pMask->common.transform != NULL;
+ }
+ pixman_image_set_transform(pSrc, &new);
+ srcTransform = pSrc->common.transform != NULL;
+ } else {
+ printf("non integer trans: %x %x\n", matrix[0][2], matrix[1][2]);
+ }
+ } else {
+ printf("non integer scale\n");
+ }
+ } else {
+ printf("trans: %p\n", pSrc->common.transform);
+ }
+#endif
+ srcRepeat = pSrc->type == BITS && pSrc->common.repeat == PIXMAN_REPEAT_NORMAL;
+
/*
* Check if we can replace our operator by a simpler one if the src or dest are opaque
* The output operator should be mathematically equivalent to the source.
@@ -637,6 +818,10 @@ pixman_image_composite (pixman_op_t op,
pixman_walk_composite_region (op, pSrc, pMask, pDst, xSrc, ySrc,
xMask, yMask, xDst, yDst, width, height,
srcRepeat, maskRepeat, func);
+ if (downscaled)
+ pixman_image_unref(pSrc);
+ if (downscaledMask)
+ pixman_image_unref(pMask);
}
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 927a1c4..7e0e276 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -810,6 +810,17 @@ pixman_rasterize_edges_accessors (pixman_image_t *image,
pixman_bool_t
pixman_image_is_opaque(pixman_image_t *image);
+void
+pixman_transform_unscale (pixman_transform_t *transform,
+ int height, int width);
+void
+pixman_get_scaled_size (pixman_transform_t *transform,
+ int height, int width,
+ int *scaled_height, int *scaled_width);
+
+void
+pixman_extract_scale (pixman_transform_t *transform,
+ int *scale_x, int *scale_y);
pixman_bool_t
pixman_image_can_get_solid (pixman_image_t *image);
@@ -893,4 +904,45 @@ void pixman_timer_register (PixmanTimer *timer);
#endif /* PIXMAN_TIMING */
+/**
+ * mul_fixed:
+ * @a: first number to multiply in fixed-point 16.16 format
+ * @b: second number to multiply in fixed-point 16.16 format
+ *
+ * Author : Frederic Plourde
+ **/
+static inline pixman_fixed_t
+mul_fixed (pixman_fixed_t a, pixman_fixed_t b)
+{
+ int64_t r = (int64_t)a * (int64_t)b;
+ return ( pixman_fixed_t )( r >> 16 );
+}
+
+/**
+ * div_fixed:
+ * @a: dividend in fixed-point 16.16 format
+ * @b: divisor in fixed-point 16.16 format
+ *
+ * Author : Frederic Plourde
+ **/
+static inline pixman_fixed_t
+div_fixed (pixman_fixed_t a, pixman_fixed_t b)
+{
+ int64_t div;
+
+ int64_t a_64 = ((int64_t)a) << 32 ;
+ int64_t b_64 = ((int64_t)b) << 16 ;
+
+ div = a_64 / b_64;
+
+ return (pixman_fixed_t)div;
+}
+
+static inline pixman_fixed_t
+square_fixed (pixman_fixed_t a)
+{
+ return mul_fixed(a,a);
+}
+
+
#endif /* PIXMAN_PRIVATE_H */
diff --git a/pixman/pixman-rescale-box.c b/pixman/pixman-rescale-box.c
new file mode 100644
index 0000000..de45228
--- /dev/null
+++ b/pixman/pixman-rescale-box.c
@@ -0,0 +1,409 @@
+/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
+/*
+ * 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.
+ *
+ * Author: Jeff Muizelaar, Mozilla Corp.
+ *
+ * Based on the code from "Fast Bitmap Strecthing" by Tomas M?ller
+ *
+ * Scaling code from Graphics Gems book III
+ * http://www.acm.org/pubs/tog/GraphicsGems/gemsiii/fastBitmap.c
+ *
+ * License states - "All code here can be used without restrictions."
+ * http://www.acm.org/pubs/tog/GraphicsGems/
+ *
+ * Also inspired by Mozilla's gfx/src/imgScaler.c by
+ * Tim Rowley <tor at cs.brown.edu>
+ */
+
+/* The approach is inspired by Bresenham's line drawing algorithm
+ * A similar approach is used by SDL in its blitting code
+ * although they do have some intrastructure for dynamically
+ * generating code for a particular scaling.
+ *
+ * A more clever approach is used in Evas. It creates table of row indices
+ * and a table of column indices that map the destination coordinates
+ * to source pixels. This approach avoids having an additional conditional
+ * branch inside of the inner loop at the cost of having to precompute and
+ * access these tables.
+ *
+ * -- Jeff Muizelaar (July 2008) */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include "pixman-private.h"
+#include "pixman-rescale.h"
+#define abs(a) (a) > 0 ? (a) : -(a)
+#define sign(x) ((x)>0 ? 1:-1)
+
+void fetch_scanline(void *closure, int y, uint32_t *scanline)
+{
+ pixman_image_t *pict = closure;
+ if (!pixman_image_has_source_clipping(pict)) {
+ fetchProc32 fetch = ACCESS(pixman_fetchProcForPicture32)(pict);
+ fetch(pict, 0, y, pict->bits.width, scanline);
+ } else {
+ int x;
+ bits_image_t *bits = &pict->bits;
+ fetchPixelProc32 fetch = ACCESS(pixman_fetchPixelProcForPicture32)(bits);
+ for (x=0; x<bits->width; x++) {
+ if (pixman_region32_contains_point (bits->common.src_clip, x, y,NULL))
+ scanline[x] = fetch (bits, x, y);
+ else
+ scanline[x] = 0;
+ }
+ }
+}
+
+
+/*
+When box filtering with an integer sized box we only ever have two box sizes.
+Proof:
+ Assume w1 > w2.
+ r = w1/w2
+
+ The size of the two boxes is
+ r1 = ceil(r), r2 = floor(r)
+
+ we want to find non-negative integers p and q such that:
+ w1 = p*r1 + q*r2
+
+ if r1 == r2 then
+ r is an integer and thus w2 evenly divides w1
+ therefor p = w2 and q = 0
+ otherwise r1 != r2 and
+ r1 = r2 + 1
+ w1 = p*(r2 + 1) + q * r2
+ = p*r2 + q*r2 + p
+ = (p + q)*r2 + p
+
+ we then choose a value of p such that:
+ w1 = r2*w2 + p
+ thus p = w1 mod r2 XXX: this wrong...
+ = w1 mod w2
+ and q = w2 - p which is > 0 because
+ p = w1 mod w2
+
+ subing into:
+ (p + q)*r2 + p
+ gives:
+ w1 = (p + w2 - p)*r2 + p
+ w1 = w2*r2 + w1 mod r2
+
+*/
+
+
+/* we can index on the bottom bit of the divisor.
+ *
+ * we could also do a multiply per pixel and accumulate precision
+*/
+/**********************************************************
+ Stretches a horizontal source line onto a horizontal
+ destination line. Used by RectStretch.
+**********************************************************/
+void downsample_row_box_filter(
+ int n,
+ uint32_t *src, uint32_t *dest,
+ long dx2, long e, long src_dx)
+{
+ int di = 0;
+ int divs[2];
+ int div = src_dx/dx2;
+ divs[div & 1] = (1<<24)/div;
+ div += 1;
+ divs[div & 1] = (1<<24)/div;
+ while (n--) {
+ uint32_t a = 0;
+ uint32_t r = 0;
+ uint32_t g = 0;
+ uint32_t b = 0;
+ int count = 1;
+ a = (*src >> 24) & 0xff;
+ r = (*src >> 16) & 0xff;
+ g = (*src >> 8) & 0xff;
+ b = (*src >> 0) & 0xff;
+ e -= dx2;
+ src++;
+ while (e > 0) {
+ e -= dx2;
+ a += (*src >> 24) & 0xff;
+ r += (*src >> 16) & 0xff;
+ g += (*src >> 8) & 0xff;
+ b += (*src >> 0) & 0xff;
+ count++;
+ src++;
+ }
+#if 1
+ int div = divs[count & 1];
+
+ a = (a * div + 0x10000) >> 24;
+ r = (r * div + 0x10000) >> 24;
+ g = (g * div + 0x10000) >> 24;
+ b = (b * div + 0x10000) >> 24;
+
+ //XXX counts seem high...
+#else
+ a /= count;
+ r /= count;
+ g /= count;
+ b /= count;
+#endif
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+
+ e += src_dx;
+ }
+}
+
+void downsample_row_box_filter_sse2(
+ int n,
+ uint32_t *src, uint32_t *dest,
+ long dx2, long e, long src_dx)
+{
+#if 0
+ while (n--) {
+ uint32_t a = 0;
+ uint32_t r = 0;
+ uint32_t g = 0;
+ uint32_t b = 0;
+ int count = 1;
+ a = (*src >> 24) & 0xff;
+ r = (*src >> 16) & 0xff;
+ g = (*src >> 8) & 0xff;
+ b = (*src >> 0) & 0xff;
+ while (e > 0) {
+ e -= dx2;
+ a += (*src >> 24) & 0xff;
+ r += (*src >> 16) & 0xff;
+ g += (*src >> 8) & 0xff;
+ b += (*src >> 0) & 0xff;
+ count++;
+ src++;
+ }
+ //XXX counts seem high...
+ a /= count;
+ r /= count;
+ g /= count;
+ b /= count;
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+
+ e += src_dx;
+ }
+#endif
+
+}
+
+
+void downsample_columns_box_filter(
+ int n,
+ int columns,
+ uint32_t *src, uint32_t *dest)
+{
+ int stride = n;
+ int div = (1<<24)/columns;
+ while (n--) {
+ uint32_t a = 0;
+ uint32_t r = 0;
+ uint32_t g = 0;
+ uint32_t b = 0;
+ int h;
+ uint32_t *column_src = src;
+ a = (*column_src >> 24) & 0xff;
+ r = (*column_src >> 16) & 0xff;
+ g = (*column_src >> 8) & 0xff;
+ b = (*column_src >> 0) & 0xff;
+ for (h=1; h<columns; h++) {
+ a += (*column_src >> 24) & 0xff;
+ r += (*column_src >> 16) & 0xff;
+ g += (*column_src >> 8) & 0xff;
+ b += (*column_src >> 0) & 0xff;
+ column_src += stride;
+ }
+#if 1
+ a = (a * div + 0x10000) >> 24;
+ r = (r * div + 0x10000) >> 24;
+ g = (g * div + 0x10000) >> 24;
+ b = (b * div + 0x10000) >> 24;
+#else
+ a /= columns;
+ r /= columns;
+ g /= columns ;
+ b /= columns;
+#endif
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+ src++;
+ }
+}
+
+/**********************************************************
+ RectStretch enlarges or diminishes a source rectangle of
+ a bitmap to a destination rectangle. The source
+ rectangle is selected by the two points (xs1,ys1) and
+ (xs2,ys2), and the destination rectangle by (xd1,yd1) and
+ (xd2,yd2). Since readability of source-code is wanted,
+ some optimizations have been left out for the reader:
+ It's possible to read one line at a time, by first
+ stretching in x-direction and then stretching that bitmap
+ in y-direction.
+ Entry:
+ xs1,ys1 - first point of source rectangle
+ xs2,ys2 - second point of source rectangle
+ xd1,yd1 - first point of destination rectangle
+ xd2,yd2 - second point of destination rectangle
+**********************************************************/
+/* startColumn, startRow specify the index of the first source pixel from the source image.
+ * width and height specify the number of source pixels to be drawn
+ *
+ * origWidth, origHeight, scaledWidth and scaledHeight specify the scaling exactly
+ *
+ * x_center and y_center specify the offset within a pixel from which to start drawing
+ * they are, of course, specified in destination space
+ */
+#define ROUND
+//XXX:
+PIXMAN_EXPORT
+int downscale_box_filter(pixman_image_t *pict, unsigned origWidth, unsigned origHeight,
+ signed scaledWidth, signed scaledHeight,
+ uint16_t startColumn, uint16_t startRow,
+ uint16_t width, uint16_t height,
+ uint32_t *src, int srcStride,
+ uint32_t *dest, int dstStride)
+{
+ // printf("%d %d %d %d\n", scaledWidth, scaledHeight, origWidth, origHeight);
+ long xs2, ys2, xd2, yd2;
+ long yd1 = 0, ys1 = 0;
+ long xd1 = 0, xs1 = 0;
+ xs2 = origWidth ;
+ ys2 = origHeight ;
+ //xd2 = abs(scaledWidth) - 1;
+ xd2 = abs(scaledWidth) ;
+ yd2 = abs(scaledHeight) ;
+ long e,d,dx2;
+ short sy;
+ long dest_dy = abs(yd2);
+ long src_dy = abs(ys2);
+ if (scaledHeight < 0) {
+ ys1 = origHeight - ((src_dy<<1)+dest_dy)/(dest_dy << 1); // e = dy*2 - dx
+ sy = -1;
+ }
+ e = (src_dy<<1)-dest_dy; // e = dy*2 - dx
+ dx2 = dest_dy<<1; // dx2 = dx *2
+ src_dy <<= 1; // dy *= 2
+
+ long dest_dx,src_dx,ex,dx2x;
+ short src_sx;
+ dest_dx = abs(xd2);
+ src_dx = abs(xs2);
+ int src_direction = 1;
+#ifdef ROUND
+ ex = (src_dx<<1)-dest_dx;
+ dx2x = dest_dx<<1; // multiplying by 2 is for rounding purposes
+ src_dx <<= 1;
+#else
+ dx2x = dest_dx;
+ ex = src_dx - dest_dx;
+#endif
+
+ /* Compute the src_offset and associated error value:
+ * There are two ways to do this: */
+ /* 1: Directly */
+ int nsrc_offset = (src_dx*startColumn + dest_dx)*src_sx/(dest_dx*2);
+ long nex = (src_dx*startColumn + dest_dx)%(dest_dx*2) - dest_dx*2 + src_dx;
+ /* 2. Iteratively */
+ int src_offset = 0;
+ for (d = 0; d < startColumn; d++) {
+ //XXX: should be 'ex > 0'
+ while (ex > 0) {
+ src_offset += src_sx;
+ ex -= dx2x;
+ }
+ ex += src_dx;
+ }
+#if 0
+ if (nex != ex) {
+ printf("e: %d %d: %d %d %d\n", ex, nex, src_dx, startColumn, dest_dx);
+ assert(nex == ex);
+ }
+ if (nsrc_offset != src_offset) {
+ printf("off: %d %d: %d %d %d\n", src_offset, nsrc_offset, src_dx, startColumn, dest_dx);
+ assert(nsrc_offset == src_offset);
+ }
+
+#endif
+ //printf("src_offset %d %d %d\n", src_offset, nsrc_offset, ex);
+
+ src += src_offset;
+
+ /* we need to allocate enough room for ceil(src_height/dest_height) scanlines */
+ //XXX: I suppose we should check whether this will succeed
+ uint32_t *temp_buf = pixman_malloc_abc ((origHeight + scaledHeight-1)/scaledHeight, scaledWidth, sizeof(uint32_t));
+ if (!temp_buf)
+ return -1;
+
+ uint32_t *scanline = pixman_malloc_abc (origWidth, 1, sizeof(uint32_t));
+
+ int x = 0;
+ int y = 0;
+ /* seek to the begining */
+ for (d = 0; d < startRow; d++)
+ {
+ while (e > 0)
+ {
+ e -= dx2;
+ y++;
+ }
+ e += src_dy;
+ }
+
+ for (d = startRow; d < startRow + height; d++)
+ {
+ int columns = 0;
+ while (e > 0)
+ {
+ fetch_scanline(pict, y, scanline);
+ //XXX: we could turn these multiplications into additions
+ downsample_row_box_filter(width, scanline, temp_buf + width * columns,
+ dx2x, ex, src_dx);
+
+ ys1 ++;
+ e -= dx2;
+ columns++;
+ y++;
+ }
+ downsample_columns_box_filter(width, columns, temp_buf, dest + (yd1 - startRow)*dstStride/4);
+ yd1 += 1;
+ e += src_dy;
+ }
+ free(scanline);
+ free(temp_buf);
+ return 0;
+}
+
diff --git a/pixman/pixman-rescale-lanczos.c b/pixman/pixman-rescale-lanczos.c
new file mode 100644
index 0000000..596b192
--- /dev/null
+++ b/pixman/pixman-rescale-lanczos.c
@@ -0,0 +1,480 @@
+/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
+/*
+ * Copyright ? 2009 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.
+ *
+ * Author: Jeff Muizelaar, Mozilla Corp.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include "pixman-private.h"
+#include "pixman-rescale.h"
+#define abs(a) (a) > 0 ? (a) : -(a)
+#define sign(x) ((x)>0 ? 1:-1)
+
+static void fetch_scanline(void *closure, int y, uint32_t *scanline)
+{
+ pixman_image_t *pict = closure;
+ bits_image_t *bits = &pict->bits;
+ if (y > pict->bits.height-1)
+ y = pict->bits.height-1;
+ if (!pixman_image_has_source_clipping(pict)) {
+ fetchProc32 fetch = ACCESS(pixman_fetchProcForPicture32)(bits);
+ fetch(bits, 0, y, pict->bits.width, scanline);
+ } else {
+ int x;
+ fetchPixelProc32 fetch = ACCESS(pixman_fetchPixelProcForPicture32)(bits);
+ for (x=0; x<bits->width; x++) {
+ if (pixman_region32_contains_point (bits->common.src_clip, x, y,NULL))
+ scanline[x] = fetch (bits, x, y);
+ else
+ scanline[x] = 0;
+ }
+ }
+}
+
+#define FILTER_SHIFT 14
+#define LANCZOS_LOBES 2
+
+/* contains the filter for each destination pixel */
+struct filter {
+ int count; // filter size
+ int16_t *values; // filter coefficients
+ int offset; // offset
+};
+
+#include <pmmintrin.h>
+#include <emmintrin.h>
+static int clamp(int a)
+{
+ if (a > 255)
+ return 255;
+ if (a < 0)
+ return 0;
+ return a;
+}
+
+
+static void downsample_row_convolve_sse2(
+ int n,
+ uint32_t *src, uint32_t *dest,
+ struct filter *filter, int src_size)
+{
+ int pixel = 0;
+ while (n--) {
+ int i;
+ __m128i accum = _mm_setzero_si128();
+ __m128i zero = _mm_setzero_si128();
+ for (i=0; i<filter[pixel].count; i++) {
+ __m128i v_src = _mm_cvtsi32_si128(src[filter[pixel].offset + i]);
+ v_src = _mm_unpacklo_epi16(_mm_unpacklo_epi8(v_src, zero), zero);
+
+ __m128i coeff = _mm_cvtsi32_si128(filter[pixel].values[i]);
+ /* duplicate the filter coefficient */
+ coeff = _mm_shuffle_epi32(coeff, _MM_SHUFFLE(0, 0, 0, 0));
+
+ /* multiply and accumulate the result:
+ * 0000vvvv_0000vvvv_0000vvvv_0000vvvv * 000000aa_000000rr_000000gg_000000bb */
+ __m128i result = _mm_madd_epi16(v_src, coeff);
+ accum = _mm_add_epi32(accum, result);
+ }
+
+ /* scale the accumulator down */
+ accum = _mm_srai_epi32(accum, FILTER_SHIFT);
+
+ /* pack 000000aa_000000rr_000000gg_000000bb -> 00000000_00000000_00000000_aarrggbb */
+ accum = _mm_packs_epi32(accum, accum);
+
+ //XXX: this should be need to saturate properly but doesn't seem to make a difference
+ accum = _mm_max_epi16(accum, zero);
+
+ accum = _mm_packus_epi16(accum, accum);
+
+ *dest = _mm_cvtsi128_si32(accum);
+ dest++;
+ pixel++;
+ }
+}
+
+static void downsample_row_convolve(
+ int n,
+ uint32_t *src, uint32_t *dest,
+ struct filter *filter, int src_size)
+{
+ int pixel = 0;
+ while (n--) {
+ int32_t a = 0;
+ int32_t r = 0;
+ int32_t g = 0;
+ int32_t b = 0;
+ int i;
+
+ for (i=0; i<filter[pixel].count; i++) {
+ a += ((src[filter[pixel].offset + i] >> 24) & 0xff) * filter[pixel].values[i];
+ r += ((src[filter[pixel].offset + i] >> 16) & 0xff) * filter[pixel].values[i];
+ g += ((src[filter[pixel].offset + i] >> 8) & 0xff) * filter[pixel].values[i];
+ b += ((src[filter[pixel].offset + i] >> 0) & 0xff) * filter[pixel].values[i];
+ }
+ a >>= FILTER_SHIFT;
+ r >>= FILTER_SHIFT;
+ g >>= FILTER_SHIFT;
+ b >>= FILTER_SHIFT;
+
+ a = clamp(a);
+ r = clamp(r);
+ g = clamp(g);
+ b = clamp(b);
+
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+ pixel++;
+ }
+}
+
+/* instead of src1, src2 we could pass:
+ * ring_buf,
+ * start_index,
+ * ring_buf_length,
+ * filter_length */
+static void downsample_columns_convolve(
+ int n,
+ uint32_t *src1, int src1_length,
+ uint32_t *src2, int src2_length,
+ uint32_t *dest,
+ int16_t *filter, int filter_length)
+{
+ assert(src1_length+src2_length == filter_length);
+ assert(src1_length >= 0);
+ assert(src2_length >= 0);
+ int stride = n;
+ while (n--) {
+ int32_t a = 0;
+ int32_t r = 0;
+ int32_t g = 0;
+ int32_t b = 0;
+ int i;
+ uint32_t *column_src;
+ column_src = src1;
+ if (src1_length == 0)
+ column_src = src2;
+
+ /* we do the accumulation in two steps because the source lines are in a ring buffer
+ * so won't be contiguous */
+ column_src = src1;
+ for (i=0; i<src1_length; i++) { /* loop till the end of the ring buffer */
+ a += ((*column_src >> 24) & 0xff) * filter[i];
+ r += ((*column_src >> 16) & 0xff) * filter[i];
+ g += ((*column_src >> 8) & 0xff) * filter[i];
+ b += ((*column_src >> 0) & 0xff) * filter[i];
+ column_src += stride;
+ }
+
+ /* accumulate the remaining samples starting at the begining of the ring buffer */
+ column_src = src2;
+ for (; i<filter_length; i++) {
+ a += ((*column_src >> 24) & 0xff) * filter[i];
+ r += ((*column_src >> 16) & 0xff) * filter[i];
+ g += ((*column_src >> 8) & 0xff) * filter[i];
+ b += ((*column_src >> 0) & 0xff) * filter[i];
+ column_src += stride;
+ }
+ a >>= FILTER_SHIFT;
+ r >>= FILTER_SHIFT;
+ g >>= FILTER_SHIFT;
+ b >>= FILTER_SHIFT;
+
+ a = clamp(a);
+ r = clamp(r);
+ g = clamp(g);
+ b = clamp(b);
+ a = 0xff;
+
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+ src1++;
+ src2++;
+ }
+}
+
+#include <float.h>
+
+// Evaluates the Lanczos filter of the given filter size window for the given
+// position.
+//
+// |filter_size| is the width of the filter (the "window"), outside of which
+// the value of the function is 0. Inside of the window, the value is the
+// normalized sinc function:
+// lanczos(x) = sinc(x) * sinc(x / filter_size);
+// where
+// sinc(x) = sin(pi*x) / (pi*x);
+#include <math.h>
+float eval_lanczos(int filter_size, float x) {
+ if (x <= -filter_size || x >= filter_size)
+ return 0.0f; // Outside of the window.
+ if (x > -FLT_EPSILON &&
+ x < FLT_EPSILON)
+ return 1.0f; // Special case the discontinuity at the origin.
+ float xpi = x * (M_PI);
+ return (sin(xpi) / xpi) * // sinc(x)
+ sin(xpi / filter_size) / (xpi / filter_size); // sinc(x/filter_size)
+}
+
+/* dealing with the edges:
+ some options:
+ we could always have approximately the same number of samples in the filter and just pad the image out
+ chromium seems to truncate the filter though...
+ I don't really have a good reason to choose either approach...
+ one way to get an idea is to see what other implementation do.
+ - it looks like quartz pads
+ - chromium truncates the filter
+ - opera pads
+*/
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+int floor_int(float a)
+{
+ return floor(a);
+}
+
+int ceil_int(float a)
+{
+ return ceil(a);
+}
+int float_to_fixed(float a)
+{
+ return a * (1 << FILTER_SHIFT);
+}
+
+/* this method does not do source clipping */
+struct filter *compute_lanczos_filter(int dest_subset_lo, int dest_subset_size, int src_size, float scale)
+{
+ // this is half the number of pixels that the filter uses in filter space
+ int dest_support = LANCZOS_LOBES;
+ float src_support = dest_support / scale;
+
+ /* look at ResizeFilter::ResizeFilter() and ::ComputerFilters() */
+ /* we need to compute a set of filters for each pixel */
+ /* filter width */
+ int i;
+ struct filter *filter = malloc(dest_subset_size * sizeof(struct filter));
+ int max_filter_size = ceil_int(src_support * 2) - floor_int(src_support * -2) + 1;
+ float *filter_values = malloc(max_filter_size * sizeof(float));
+ int dest_subset_hi = dest_subset_lo + dest_subset_size; // [lo, hi)
+
+
+ // When we're doing a magnification, the scale will be larger than one. This
+ // means the destination pixels are much smaller than the source pixels, and
+ // that the range covered by the filter won't necessarily cover any source
+ // pixel boundaries. Therefore, we use these clamped values (max of 1) for
+ // some computations.
+ float clamped_scale = min(1., scale);
+
+ // Speed up the divisions below by turning them into multiplies.
+ float inv_scale = 1. / scale;
+
+ // Loop over all pixels in the output range. We will generate one set of
+ // filter values for each one. Those values will tell us how to blend the
+ // source pixels to compute the destination pixel.
+ int dest_subset_i;
+ int pixel = 0;
+ for (dest_subset_i = dest_subset_lo; dest_subset_i < dest_subset_hi; dest_subset_i++, pixel++) {
+
+ float src_pixel = dest_subset_i * inv_scale;
+
+ int src_begin = max(0, floor_int(src_pixel - src_support));
+ assert(src_begin >= 0);
+ int src_end = min(src_size - 1, ceil_int(src_pixel + src_support));
+
+ // Compute the unnormalized filter value at each location of the source
+ // it covers.
+ float filter_sum = 0.; // sum of the filter values for normalizing
+ int filter_size = 0;
+ int cur_filter_pixel;
+ int j = 0;
+ for (cur_filter_pixel = src_begin; cur_filter_pixel <= src_end;
+ cur_filter_pixel++) {
+ // Distance from the center of the filter, this is the filter coordinate
+ // in source space.
+ float src_filter_pos = cur_filter_pixel - src_pixel;
+
+ // Since the filter really exists in dest space, map it there.
+ float dest_filter_pos = src_filter_pos * clamped_scale;
+
+ // Compute the filter value at that location.
+ float filter_value = eval_lanczos(LANCZOS_LOBES, dest_filter_pos);
+ filter_sum += filter_value;
+ filter_values[j] = filter_value;
+
+ filter_size++;
+ j++;
+ }
+ if (src_end < src_begin) {
+ printf("%d %d %d (%d %d - %d)\n", src_end, src_begin, dest_subset_i, dest_subset_lo, dest_subset_hi, dest_subset_size);
+ assert(src_end >= src_begin);
+ }
+ if (filter_size > max_filter_size) {
+ printf("%f %f\n", 1./scale, (1. / scale) * src_support * 2 + 1); //XXX is this correct?
+ printf("%d %d\n", filter_size, max_filter_size);
+ assert(filter_size <= max_filter_size);
+ }
+
+ //XXX: we should avoid doing malloc here
+ int16_t *fixed_filter_values = malloc(filter_size * sizeof(int16_t));
+
+ // the filter must be normalized so that we don't affect the brightness of
+ // the iamge. Convert to normalized fixed point
+ // XXX: It might be better if we didn't have to do this in a separate pass
+ int16_t fixed_sum = 0; // XXX: should we use a regular int here?
+ for (i=0; i<filter_size; i++) {
+ int16_t cur_fixed = float_to_fixed(filter_values[i] / filter_sum);
+ //printf("%d\n", cur_fixed);
+ fixed_sum += cur_fixed;
+ fixed_filter_values[i] = cur_fixed;
+ }
+ //printf("sum = %d\n", fixed_sum);
+
+ // The conversion to fixed point will leave some rounding errors, which
+ // we add back in to avoid affecting the brightness of the image. We
+ // arbitrarily add this to the center of the filter array (this won't always
+ // be the center of the filter function since it could get clipped on the
+ // edges, but it doesn't matter enough to worry about that case).
+ int16_t leftovers = float_to_fixed(1.0f) - fixed_sum;
+ fixed_filter_values[filter_size / 2] += leftovers;
+
+ filter[pixel].values = fixed_filter_values;
+ filter[pixel].count = filter_size;
+ filter[pixel].offset = src_begin;
+ assert(filter[pixel].offset >= 0);
+ assert(filter[pixel].offset + filter[pixel].count - 1 < src_size);
+ }
+ free(filter_values);
+ return filter;
+}
+
+// startColumn and startRow are in destination space
+PIXMAN_EXPORT
+int downscale_lanczos_filter(pixman_image_t *pict, unsigned origWidth, unsigned origHeight,
+ signed scaledWidth, signed scaledHeight,
+ uint16_t startColumn, uint16_t startRow,
+ uint16_t width, uint16_t height,
+ uint32_t *src, int srcStride,
+ uint32_t *dest, int dstStride)
+{
+ assert(startColumn + width <= scaledWidth);
+ assert(startRow + height <= scaledHeight);
+ // printf("%d %d %d %d\n", scaledWidth, scaledHeight, origWidth, origHeight);
+ int yd1 = 0;
+ int d;
+
+ //XXX: check what this actually needs to be
+ int lanczos_src = LANCZOS_LOBES * 2;
+
+ //XXX: this duplicates code in compute_lanczos_filter
+ int dest_support = LANCZOS_LOBES;
+ float src_support = dest_support / ((float)scaledHeight/origHeight);
+
+ int max_filter_size = ceil_int(src_support * 2) - floor_int(src_support * -2) + 1;
+
+ int ring_buf_size = max_filter_size;
+ uint32_t *ring_buf = pixman_malloc_abc (ring_buf_size, scaledWidth, sizeof(uint32_t));
+ if (!ring_buf)
+ return -1;
+
+ //XXX: I suppose we should check whether this will succeed
+ uint32_t *scanline = pixman_malloc_abc (origWidth, 1, sizeof(uint32_t));
+
+ struct filter *x_filter = compute_lanczos_filter(startColumn, width, origWidth, (float)scaledWidth/origWidth);
+ struct filter *y_filter = compute_lanczos_filter(startRow, height, origHeight, (float)scaledHeight/origHeight);
+
+ int index = 0;
+ int next_x_row = 0;
+ int filter_index = 0;
+ for (d = startRow; d < startRow + height; d++, filter_index++)
+ {
+ int filter_length = y_filter[filter_index].count;
+ int filter_size = y_filter[filter_index].count;
+ int filter_offset = y_filter[filter_index].offset;
+ assert(filter_offset >= 0);
+ /* read and downsample the rows needed to downsample the next column */
+ while (next_x_row < filter_offset + filter_length) {
+ fetch_scanline(pict, index, scanline);
+ downsample_row_convolve_sse2(width, scanline, ring_buf + width * (index % ring_buf_size), x_filter, origWidth);
+ //downsample_row_convolve(width, scanline, ring_buf + width * (index % ring_buf_size), x_filter, origWidth);
+ index++;
+ next_x_row++;
+ //XXX: when index overflows this becomes bad: i.e. 0 % 5 != 8 % 5
+ }
+
+ int src1_index = filter_offset % ring_buf_size;
+ assert(src1_index >= 0);
+ uint32_t *src1 = ring_buf + width * src1_index;
+ assert(filter_size <= ring_buf_size);
+ int src1_size = min((ring_buf_size - src1_index), filter_size);
+ assert(src1_size >= 0);
+ int src2_size = filter_size - src1_size;
+ assert(filter_size >= src1_size);
+ uint32_t *src2 = ring_buf; // src2 is always at the same location
+ downsample_columns_convolve(width, src1, src1_size, src2, src2_size, dest + (yd1 - startRow)*dstStride/4, y_filter[filter_index].values, y_filter[filter_index].count);
+ yd1++;
+ }
+ free(ring_buf);
+ free(scanline);
+ int i;
+ for (i=0; i<width; i++)
+ free(x_filter[i].values);
+ for (i=0; i<height; i++)
+ free(y_filter[i].values);
+ free(x_filter);
+ free(y_filter);
+ return 0;
+}
+
+#if 0
+ // rearrange filter coefficients in the order of the ring buffer?
+ // or we could just filter in the order of the ring buffer
+ i = 0;
+ j = start;
+ while (n) {
+ result += sample[j] * coeff[i];
+ if (j > size)
+ j = 0;
+ i++;
+ j++;
+ }
+
+ // or rearranging the coeffs gives us
+ while (n) {
+ result += sample[i + sample*width] * coeff[i];
+ }
+ /* it also lets us move in a more orderly fashion through memory */
+ /* however I can't think of any way to get the samples to always be contiguous */
+
+ // it would be interesting to see how doing the multiplication by row and then summing all the rows compared to doing
+ // everything column wise. I expect the memory bandwidth of doing so could make things slower
+#endif
+
diff --git a/pixman/pixman-rescale-mult-old.c b/pixman/pixman-rescale-mult-old.c
new file mode 100644
index 0000000..bc27821
--- /dev/null
+++ b/pixman/pixman-rescale-mult-old.c
@@ -0,0 +1,286 @@
+/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
+/*
+ * Copyright ? 2009 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.
+ *
+ * Author: Jeff Muizelaar, Mozilla Corp.
+ */
+
+/* This implements a box filter that supports non-integer box sizes */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include "pixman-private.h"
+#include "pixman-rescale.h"
+#define abs(a) (a) > 0 ? (a) : -(a)
+#define sign(x) ((x)>0 ? 1:-1)
+
+static void fetch_scanline(void *closure, int y, uint32_t *scanline)
+{
+ pixman_image_t *pict = closure;
+ bits_image_t *bits = &pict->bits;
+ if (y > pict->bits.height-1)
+ y = pict->bits.height-1;
+ if (!pixman_image_has_source_clipping(pict)) {
+ fetchProc32 fetch = ACCESS(pixman_fetchProcForPicture32)(bits);
+ fetch(bits, 0, y, pict->bits.width, scanline);
+ } else {
+ int x;
+ fetchPixelProc32 fetch = ACCESS(pixman_fetchPixelProcForPicture32)(bits);
+ for (x=0; x<bits->width; x++) {
+ if (pixman_region32_contains_point (bits->common.src_clip, x, y,NULL))
+ scanline[x] = fetch (bits, x, y);
+ else
+ scanline[x] = 0;
+ }
+ }
+}
+
+/* we work in fixed point where 1. == 1 << 24 */
+#define FIXED_SHIFT 24
+
+static void downsample_row_box_filter(
+ int n,
+ uint32_t *src, uint32_t *dest,
+ int coverage[], int pixel_coverage)
+{
+ /* we need an array of the pixel contribution of each destination pixel on the boundaries.
+ * we invert the value to get the value on the other size of the box */
+ /*
+
+ value = a * contribution * 1/box_size
+ value += a * 1/box_size
+ value += a * 1/box_size
+ value += a * 1/box_size
+ value += a * (1 - contribution) * 1/box_size
+ a * (1/box_size - contribution * 1/box_size)
+
+ box size is constant
+
+
+ value = a * contribtion_a * 1/box_size + b * contribution_b * 1/box_size
+ contribution_b = (1 - contribution_a)
+ = (1 - contribution_a_next)
+ */
+
+ /* box size = ceil(src_width/dest_width) */
+
+ int x = 0;
+ while (n--) {
+ uint32_t a = 0;
+ uint32_t r = 0;
+ uint32_t g = 0;
+ uint32_t b = 0;
+ int box = 1 << FIXED_SHIFT;
+ int start_coverage = coverage[x];
+ a = ((*src >> 24) & 0xff) * start_coverage;
+ r = ((*src >> 16) & 0xff) * start_coverage;
+ g = ((*src >> 8) & 0xff) * start_coverage;
+ b = ((*src >> 0) & 0xff) * start_coverage;
+ src++;
+ x++;
+ box -= start_coverage;
+ while (box >= pixel_coverage) {
+ a += ((*src >> 24) & 0xff) * pixel_coverage;
+ r += ((*src >> 16) & 0xff) * pixel_coverage;
+ g += ((*src >> 8) & 0xff) * pixel_coverage;
+ b += ((*src >> 0) & 0xff) * pixel_coverage;
+ src++;
+ x++;
+
+ box -= pixel_coverage;
+ }
+ /* multiply by whatever is leftover
+ * this ensures that we don't bias down.
+ * i.e. start_coverage + n*pixel_coverage + box == 1 << 24 */
+ if (box > 0) {
+ a += ((*src >> 24) & 0xff) * box;
+ r += ((*src >> 16) & 0xff) * box;
+ g += ((*src >> 8) & 0xff) * box;
+ b += ((*src >> 0) & 0xff) * box;
+ }
+
+ a >>= FIXED_SHIFT;
+ r >>= FIXED_SHIFT;
+ g >>= FIXED_SHIFT;
+ b >>= FIXED_SHIFT;
+
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+ }
+}
+
+static void downsample_columns_box_filter(
+ int n,
+ int start_coverage,
+ int pixel_coverage,
+ uint32_t *src, uint32_t *dest)
+{
+ int stride = n;
+ while (n--) {
+ uint32_t a = 0;
+ uint32_t r = 0;
+ uint32_t g = 0;
+ uint32_t b = 0;
+ uint32_t *column_src = src;
+ int box = 1 << FIXED_SHIFT;
+ a = ((*column_src >> 24) & 0xff) * start_coverage;
+ r = ((*column_src >> 16) & 0xff) * start_coverage;
+ g = ((*column_src >> 8) & 0xff) * start_coverage;
+ b = ((*column_src >> 0) & 0xff) * start_coverage;
+ column_src += stride;
+ box -= start_coverage;
+ while (box >= pixel_coverage) {
+ a += ((*column_src >> 24) & 0xff) * pixel_coverage;
+ r += ((*column_src >> 16) & 0xff) * pixel_coverage;
+ g += ((*column_src >> 8) & 0xff) * pixel_coverage;
+ b += ((*column_src >> 0) & 0xff) * pixel_coverage;
+ column_src += stride;
+ box -= pixel_coverage;
+ }
+ if (box > 0) {
+ a += ((*column_src >> 24) & 0xff) * box;
+ r += ((*column_src >> 16) & 0xff) * box;
+ g += ((*column_src >> 8) & 0xff) * box;
+ b += ((*column_src >> 0) & 0xff) * box;
+ }
+ a >>= FIXED_SHIFT;
+ r >>= FIXED_SHIFT;
+ g >>= FIXED_SHIFT;
+ b >>= FIXED_SHIFT;
+
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+ src++;
+ }
+}
+
+#if 1
+int compute_coverage(int coverage[], int src_length, int dest_length) {
+ int i;
+ /* num = src_length/dest_length
+ total = sum(pixel) / num
+
+ pixel * 1/num == pixel * dest_length / src_length
+ */
+ int full = 1<<24;
+ /* the average contribution of each source pixel */
+ int ratio = ((1 << 24)*(long long int)dest_length)/src_length;
+ int finished = ((1 << 24)*(long long int)dest_length) - (((1 << 24)*(long long int)dest_length)/src_length)*src_length;
+ int p=0;
+ int p2;
+ int remainder = full;
+ /* because ((1 << 24)*(long long int)dest_length) won't always be divisible by src_length
+ * we'll need someplace to put the other bits.
+ *
+ * We want to ensure a + n*ratio < 1<<24
+ *
+ * 1<<24
+ * */
+ for (i=0; i<src_length; i++) {
+ if (remainder < ratio) {
+ p = ratio - remainder;
+ remainder = full - p;
+ } else {
+ p = ratio;
+ remainder -= ratio;
+ }
+
+ if ((((i+1)*ratio) % full) < ratio) {
+ p2 = (((i+1)*ratio) % full);
+ } else {
+ p2 = ratio;
+ }
+
+ //printf("%d %d %d %d %d\n", i, p, remainder, (i+1)*ratio, p2);
+ //assert(p == p2);
+
+ coverage[i] = p;
+ }
+ //assert(remainder == 0);
+ return ratio;
+}
+#endif
+
+
+PIXMAN_EXPORT
+int downscale_box_mult_old_filter(pixman_image_t *pict, unsigned origWidth, unsigned origHeight,
+ signed scaledWidth, signed scaledHeight,
+ uint16_t startColumn, uint16_t startRow,
+ uint16_t width, uint16_t height,
+ uint32_t *src, int srcStride,
+ uint32_t *dest, int dstStride)
+{
+ // printf("%d %d %d %d\n", scaledWidth, scaledHeight, origWidth, origHeight);
+ int yd1 = 0;
+ int d;
+
+ /* we need to allocate enough room for ceil(src_height/dest_height) scanlines */
+ uint32_t *temp_buf = pixman_malloc_abc ((origHeight + scaledHeight-1)/scaledHeight, scaledWidth, sizeof(uint32_t));
+ if (!temp_buf)
+ return -1;
+
+ //XXX: I suppose we should check whether this will succeed
+ uint32_t *scanline = pixman_malloc_abc (origWidth, 1, sizeof(uint32_t));
+
+ int *x_coverage = pixman_malloc_abc (origWidth, 1, sizeof(int));
+ int *y_coverage = pixman_malloc_abc (origHeight, 1, sizeof(int));
+ int pixel_coverage_x = compute_coverage(x_coverage, origWidth, scaledWidth);
+ int pixel_coverage_y = compute_coverage(y_coverage, origHeight, scaledHeight);
+
+ int y = 0;
+ for (d = 0; d < startRow + height; d++)
+ {
+ int columns = 0;
+ int box = 1 << FIXED_SHIFT;
+ int start_coverage_y = y_coverage[y];
+ fetch_scanline(pict, y, scanline);
+ downsample_row_box_filter(width, scanline, temp_buf + width * columns,
+ x_coverage, pixel_coverage_x);
+ columns++;
+ y++;
+ box -= start_coverage_y;
+
+ while (box >= pixel_coverage_y) {
+ fetch_scanline(pict, y, scanline);
+ downsample_row_box_filter(width, scanline, temp_buf + width * columns,
+ x_coverage, pixel_coverage_x);
+ columns++;
+ y++;
+ box -= pixel_coverage_y;
+ }
+ if (box > 0) {
+ fetch_scanline(pict, y, scanline);
+ downsample_row_box_filter(width, scanline, temp_buf + width * columns,
+ x_coverage, pixel_coverage_x);
+ columns++;
+ }
+ downsample_columns_box_filter(width, start_coverage_y, pixel_coverage_y, temp_buf, dest + (yd1 - startRow)*dstStride/4);
+ yd1++;
+ }
+ free(temp_buf);
+ return 0;
+}
diff --git a/pixman/pixman-rescale-mult.c b/pixman/pixman-rescale-mult.c
new file mode 100644
index 0000000..b023afd
--- /dev/null
+++ b/pixman/pixman-rescale-mult.c
@@ -0,0 +1,335 @@
+/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
+/*
+ * Copyright ? 2009 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.
+ *
+ * Author: Jeff Muizelaar, Mozilla Corp.
+ */
+
+/* This implements a box filter that supports non-integer box sizes */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include "pixman-private.h"
+#include "pixman-rescale.h"
+#define abs(a) (a) > 0 ? (a) : -(a)
+#define sign(x) ((x)>0 ? 1:-1)
+
+static void fetch_scanline(void *closure, int y, uint32_t *scanline)
+{
+ pixman_image_t *pict = closure;
+ bits_image_t *bits = &pict->bits;
+ if (y > pict->bits.height-1)
+ y = pict->bits.height-1;
+ if (!pixman_image_has_source_clipping(pict)) {
+ fetchProc32 fetch = ACCESS(pixman_fetchProcForPicture32)(bits);
+ fetch(bits, 0, y, pict->bits.width, scanline);
+ } else {
+ int x;
+ fetchPixelProc32 fetch = ACCESS(pixman_fetchPixelProcForPicture32)(bits);
+ for (x=0; x<bits->width; x++) {
+ if (pixman_region32_contains_point (bits->common.src_clip, x, y,NULL))
+ scanline[x] = fetch (bits, x, y);
+ else
+ scanline[x] = 0;
+ }
+ }
+}
+
+/* we work in fixed point where 1. == 1 << 24 */
+#define FIXED_SHIFT 24
+
+static void downsample_row_box_filter(
+ int start,
+ int width,
+ uint32_t *src, uint32_t *dest,
+ int coverage[], int pixel_coverage)
+{
+ /* we need an array of the pixel contribution of each destination pixel on the boundaries.
+ * we invert the value to get the value on the other size of the box */
+ /*
+
+ value = a * contribution * 1/box_size
+ value += a * 1/box_size
+ value += a * 1/box_size
+ value += a * 1/box_size
+ value += a * (1 - contribution) * 1/box_size
+ a * (1/box_size - contribution * 1/box_size)
+
+ box size is constant
+
+
+ value = a * contribtion_a * 1/box_size + b * contribution_b * 1/box_size
+ contribution_b = (1 - contribution_a)
+ = (1 - contribution_a_next)
+ */
+
+ /* box size = ceil(src_width/dest_width) */
+ int x = 0;
+ while (x < start) {
+ int box = 1 << FIXED_SHIFT;
+ int start_coverage = coverage[x];
+ box -= start_coverage;
+ src++;
+ while (box >= pixel_coverage) {
+ src++;
+ box -= pixel_coverage;
+ }
+ x++;
+ }
+
+ while (x < start + width) {
+ uint32_t a = 0;
+ uint32_t r = 0;
+ uint32_t g = 0;
+ uint32_t b = 0;
+ int box = 1 << FIXED_SHIFT;
+ int start_coverage = coverage[x];
+ a = ((*src >> 24) & 0xff) * start_coverage;
+ r = ((*src >> 16) & 0xff) * start_coverage;
+ g = ((*src >> 8) & 0xff) * start_coverage;
+ b = ((*src >> 0) & 0xff) * start_coverage;
+ src++;
+ x++;
+ box -= start_coverage;
+ while (box >= pixel_coverage) {
+ a += ((*src >> 24) & 0xff) * pixel_coverage;
+ r += ((*src >> 16) & 0xff) * pixel_coverage;
+ g += ((*src >> 8) & 0xff) * pixel_coverage;
+ b += ((*src >> 0) & 0xff) * pixel_coverage;
+ src++;
+
+ box -= pixel_coverage;
+ }
+ /* multiply by whatever is leftover
+ * this ensures that we don't bias down.
+ * i.e. start_coverage + n*pixel_coverage + box == 1 << 24 */
+ if (box > 0) {
+ a += ((*src >> 24) & 0xff) * box;
+ r += ((*src >> 16) & 0xff) * box;
+ g += ((*src >> 8) & 0xff) * box;
+ b += ((*src >> 0) & 0xff) * box;
+ }
+
+ a >>= FIXED_SHIFT;
+ r >>= FIXED_SHIFT;
+ g >>= FIXED_SHIFT;
+ b >>= FIXED_SHIFT;
+
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+ }
+}
+
+static void downsample_columns_box_filter(
+ int n,
+ int start_coverage,
+ int pixel_coverage,
+ uint32_t *src, uint32_t *dest)
+{
+ int stride = n;
+ while (n--) {
+ uint32_t a = 0;
+ uint32_t r = 0;
+ uint32_t g = 0;
+ uint32_t b = 0;
+ uint32_t *column_src = src;
+ int box = 1 << FIXED_SHIFT;
+ a = ((*column_src >> 24) & 0xff) * start_coverage;
+ r = ((*column_src >> 16) & 0xff) * start_coverage;
+ g = ((*column_src >> 8) & 0xff) * start_coverage;
+ b = ((*column_src >> 0) & 0xff) * start_coverage;
+ column_src += stride;
+ box -= start_coverage;
+ while (box >= pixel_coverage) {
+ a += ((*column_src >> 24) & 0xff) * pixel_coverage;
+ r += ((*column_src >> 16) & 0xff) * pixel_coverage;
+ g += ((*column_src >> 8) & 0xff) * pixel_coverage;
+ b += ((*column_src >> 0) & 0xff) * pixel_coverage;
+ column_src += stride;
+ box -= pixel_coverage;
+ }
+ if (box > 0) {
+ a += ((*column_src >> 24) & 0xff) * box;
+ r += ((*column_src >> 16) & 0xff) * box;
+ g += ((*column_src >> 8) & 0xff) * box;
+ b += ((*column_src >> 0) & 0xff) * box;
+ }
+ a >>= FIXED_SHIFT;
+ r >>= FIXED_SHIFT;
+ g >>= FIXED_SHIFT;
+ b >>= FIXED_SHIFT;
+
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+ src++;
+ }
+}
+
+#include <math.h>
+static int compute_coverage(int coverage[], int src_length, int dest_length) {
+ int i;
+ /* num = src_length/dest_length
+ total = sum(pixel) / num
+
+ pixel * 1/num == pixel * dest_length / src_length
+ */
+ /* the average contribution of each source pixel */
+ int ratio = ((1 << 24)*(long long int)dest_length)/src_length;
+ /* because ((1 << 24)*(long long int)dest_length) won't always be divisible by src_length
+ * we'll need someplace to put the other bits.
+ *
+ * We want to ensure a + n*ratio < 1<<24
+ *
+ * 1<<24
+ * */
+ printf("%d %d\n", src_length, dest_length);
+ double scale=(double)src_length/dest_length;
+ int y = 0;
+ for (i=0; i<dest_length; i++) {
+ float left_side = i*scale;
+ float right_side = (i+1)*scale;
+ float right_fract = right_side - floor(right_side);
+ float left_fract = ceil(left_side) - left_side;
+ assert(right_fract <= 1);
+ int count = floor(right_side) - ceil(left_side);
+ int coeff_est = (1<<24)*(left_fract)/src_length;
+ if (coeff_est == 0) {
+ coeff_est = ratio;
+ }
+ int overage = ratio*(right_fract);
+ if (left_fract == 0.)
+ count--;
+ int coeff = (1<<24) - (count * ratio + overage);
+ //printf("y: %d, %f %d %d %d-%d %f %f-%f %d\n", y, scale, ratio, i, coeff, coeff_est, right_fract, left_side, right_side, overage);
+ //if (coeff < coeff_est)
+ // coeff = coeff_est;
+ assert(coeff >= 0);
+ int box = 1<<24;
+ box -= coeff;
+ y++;
+ while (box >= ratio) {
+ box -= ratio;
+ y++;
+ }
+ if (y != floor(right_side)) {
+ printf("y: %d, right_side: %f\n",y, right_side);
+ assert(y == floor(right_side));
+ }
+ if (y == src_length) {
+ printf("box: %d\n", box);
+ assert(box <= 1);
+ //coeff += box;
+ }
+ coverage[i] = coeff;
+
+ }
+ printf("y: %d src_length: %d\n", y, src_length);
+ assert(y == src_length);
+ return ratio;
+}
+
+PIXMAN_EXPORT
+int downscale_box_mult_filter(pixman_image_t *pict, unsigned origWidth, unsigned origHeight,
+ signed scaledWidth, signed scaledHeight,
+ uint16_t startColumn, uint16_t startRow,
+ uint16_t width, uint16_t height,
+ uint32_t *src, int srcStride,
+ uint32_t *dest, int dstStride)
+{
+ // printf("%d %d %d %d\n", scaledWidth, scaledHeight, origWidth, origHeight);
+ int yd1 = 0;
+ int d;
+
+ assert(width + startColumn <= scaledWidth);
+ /* we need to allocate enough room for ceil(src_height/dest_height)+1 scanlines */
+ uint32_t *temp_buf = pixman_malloc_abc ((origHeight + scaledHeight-1)/scaledHeight+1, width, sizeof(uint32_t));
+ if (!temp_buf)
+ return -1;
+
+ //XXX: I suppose we should check whether this will succeed
+ uint32_t *scanline = pixman_malloc_abc (origWidth, 1, sizeof(uint32_t));
+
+ int *x_coverage = pixman_malloc_abc (origWidth, 1, sizeof(int));
+ int *y_coverage = pixman_malloc_abc (origHeight, 1, sizeof(int));
+ int pixel_coverage_x = compute_coverage(x_coverage, origWidth, scaledWidth);
+ int pixel_coverage_y = compute_coverage(y_coverage, origHeight, scaledHeight);
+
+ int y = 0;
+ for (d = 0; d<startRow; d++) {
+ int box = 1 << FIXED_SHIFT;
+ int start_coverage_y = y_coverage[d];
+ box -= start_coverage_y;
+ y++;
+ while (box >= pixel_coverage_y) {
+ box -= pixel_coverage_y;
+ y++;
+ }
+ }
+ for (d = startRow; d < startRow + height; d++)
+ {
+ int columns = 0;
+ int box = 1 << FIXED_SHIFT;
+ int start_coverage_y = y_coverage[d];
+ fetch_scanline(pict, y, scanline);
+ downsample_row_box_filter(startColumn, width, scanline, temp_buf + width * columns,
+ x_coverage, pixel_coverage_x);
+ columns++;
+ y++;
+ box -= start_coverage_y;
+
+ while (box >= pixel_coverage_y) {
+ fetch_scanline(pict, y, scanline);
+ downsample_row_box_filter(startColumn, width, scanline, temp_buf + width * columns,
+ x_coverage, pixel_coverage_x);
+ columns++;
+ y++;
+ box -= pixel_coverage_y;
+ }
+ if (box > 0) {
+ fetch_scanline(pict, y, scanline);
+ downsample_row_box_filter(startColumn, width, scanline, temp_buf + width * columns,
+ x_coverage, pixel_coverage_x);
+ columns++;
+ }
+ downsample_columns_box_filter(width, start_coverage_y, pixel_coverage_y, temp_buf, dest + (yd1 - startRow)*dstStride/4);
+ yd1++;
+ if (width*columns > ((origHeight + scaledHeight-1)/scaledHeight+1) * width) {
+ printf("%d %d\n", origHeight, scaledHeight);
+ printf("%d %d\n", columns, (origHeight + scaledHeight-1)/scaledHeight);
+ assert(width*columns <= (origHeight + scaledHeight-1)/scaledHeight * width);
+ }
+ }
+ if (y > origHeight) {
+ printf("%d %d\n", y, origHeight);
+ assert(y<=origHeight);
+ }
+ free(scanline);
+ free(x_coverage);
+ free(y_coverage);
+ free(temp_buf);
+ return 0;
+}
diff --git a/pixman/pixman-rescale.h b/pixman/pixman-rescale.h
new file mode 100644
index 0000000..e2f5685
--- /dev/null
+++ b/pixman/pixman-rescale.h
@@ -0,0 +1,21 @@
+int downscale_box_filter(
+ pixman_image_t *pict, unsigned origWidth, unsigned origHeight,
+ signed scaledWidth, signed scaledHeight,
+ uint16_t startColumn, uint16_t startRow,
+ uint16_t width, uint16_t height,
+ uint32_t *src, int srcStride,
+ uint32_t *dest, int dstStride);
+
+int downscale_box_mult2_filter( pixman_image_t *pict, unsigned origWidth, unsigned origHeight,
+ signed scaledWidth, signed scaledHeight,
+ uint16_t startColumn, uint16_t startRow,
+ uint16_t width, uint16_t height,
+ uint32_t *src, int srcStride,
+ uint32_t *dest, int dstStride);
+
+int downscale_lanczos_filter( pixman_image_t *pict, unsigned origWidth, unsigned origHeight,
+ signed scaledWidth, signed scaledHeight,
+ uint16_t startColumn, uint16_t startRow,
+ uint16_t width, uint16_t height,
+ uint32_t *src, int srcStride,
+ uint32_t *dest, int dstStride);
diff --git a/pixman/pixman-utils.c b/pixman/pixman-utils.c
index cdf0220..9266655 100644
--- a/pixman/pixman-utils.c
+++ b/pixman/pixman-utils.c
@@ -26,11 +26,278 @@
#endif
#include <stdlib.h>
+#include <math.h>
#include "pixman-private.h"
#include "pixman-mmx.h"
#include "pixman-sse2.h"
+#if 0
+pixman_fixed_inverse(pixman_fixed_t a)
+{
+ /* are there any value that don't have an inverse?
+ * yes. lots */
+}
+#endif
+
+/**
+ * sqrt_fixed:
+ * @x: number to sqrt in fixed-point 16.16 format
+ *
+ * This code is inspired by Ken Turkowski's fixed-point sqrt.
+ * http://www.worldserver.com/turk/computergraphics/FixedSqrt.pdf
+ *
+ * Author : Frederic Plourde
+ **/
+pixman_fixed_t
+sqrt_fixed (pixman_fixed_t x)
+{
+ const pixman_fixed_t pixman_fixed_095 = 0x0000F333;
+ const pixman_fixed_t pixman_fixed_sqrt_2 = 0x00016A0A;
+ int32_t y = x;
+ int32_t a = 0;
+
+ if (y <= 0)
+ {
+ return 0;
+ }
+ else if (y > pixman_fixed_1)
+ {
+ while (y & 0xFFFF0000)
+ {
+ y >>= 1;
+ a++;
+ }
+ }
+ else
+ {
+ while (!(y & 0xFFFF0000))
+ {
+ y <<= 1;
+ a--;
+ }
+ y >>= 1;
+ a++;
+ }
+
+ y = (pixman_fixed_095 + y) >> 1;
+
+ if (a & 0x00000001) // a is odd
+ {
+ a = a >> 1;
+
+ if (a > 0)
+ {
+ y = mul_fixed(mul_fixed(y, pixman_fixed_1 << a), pixman_fixed_sqrt_2);
+ }
+ else
+ {
+ y = mul_fixed(mul_fixed(y, pixman_fixed_1 >> -a), pixman_fixed_sqrt_2);
+ }
+ }
+ else // a is even
+ {
+ a = a >> 1;
+
+ if (a > 0)
+ {
+ y = mul_fixed(y, pixman_fixed_1 << a);
+ }
+ else
+ {
+ y = mul_fixed(y, pixman_fixed_1 >> -a);
+ }
+ }
+
+ // Iterate two times to improve accuracy.
+ // One of the below two lines may be removed to
+ // increase speed but at the cost of reduced accuracy.
+ y = (y + div_fixed(x, y)) >> 1;
+ y = (y + div_fixed(x, y)) >> 1;
+
+ return y;
+}
+
+void
+pixman_transform_unscale (pixman_transform_t *transform,
+ pixman_fixed_t xscale, pixman_fixed_t yscale)
+{
+ /*
+ we want to multiply the transform by the inverse of the following scaled
+ transform:
+
+ | xscale 0 0 |^-1 | 1/xscale 0 0 |
+ | 0 yscale 0 | == | 0 1/yscale 0 |
+ | 0 0 1 | | 0 0 1 |
+
+ multiplying with the transform matrix gives:
+
+ | 1/xscale 0 0 | | a b c | | a/xscale b/xscale c/xscale |
+ | 0 1/yscale 0 | * | d e f | = | d/yscale e/yscale f/yscale |
+ | 0 0 1 | | g h i | | g h i |
+
+ we perform this transformation directly to take advantage of the
+ increased accuracy */
+ transform->matrix[0][0] = div_fixed(transform->matrix[0][0], xscale);
+ transform->matrix[0][1] = div_fixed(transform->matrix[0][1], xscale);
+ transform->matrix[0][2] = div_fixed(transform->matrix[0][2], xscale);
+
+ transform->matrix[1][0] = div_fixed(transform->matrix[1][0], yscale);
+ transform->matrix[1][1] = div_fixed(transform->matrix[1][1], yscale);
+ transform->matrix[1][2] = div_fixed(transform->matrix[1][2], yscale);
+}
+
+void
+pixman_extract_scale (pixman_transform_t *transform,
+ int *scale_x, int *scale_y)
+{
+ pixman_fixed_t (*matrix)[3] = transform->matrix;
+ pixman_bool_t affine = matrix[2][0] == 0 && matrix[2][1] == 0 && matrix[2][2] == pixman_fixed_1;
+ if (affine) {
+#ifdef FIXED
+ *scale_x = sqrt_fixed(square_fixed(width) *(square_fixed(matrix[0][0]) + square_fixed(matrix[1][0])));
+ *scale_y = sqrt_fixed(square_fixed(height)*(square_fixed(matrix[0][1]) + square_fixed(matrix[1][1])));
+#else
+ double a = pixman_fixed_to_double(matrix[0][0]);
+ double b = pixman_fixed_to_double(matrix[0][1]);
+ double c = pixman_fixed_to_double(matrix[1][0]);
+ double d = pixman_fixed_to_double(matrix[1][1]);
+
+ *scale_x = pixman_double_to_fixed(sqrt(a*a + c*c));
+ *scale_y = pixman_double_to_fixed(sqrt(b*b + d*d));
+
+#endif
+ } else {
+#if 0
+ /*
+ / 2 2 2 \1/2
+ | width ((d w - y0 f) (c w - y0 e)) |
+ |-------------------------------------------------------|
+ | 2 |
+ \ (a d w - a y0 f - c b w + c x0 f + e b y0 - e x0 d) /
+
+ / 2 2 2 \1/2
+ | height ((b w - x0 f) (a w - x0 e)) |
+ |-------------------------------------------------------|
+ | 2 |
+ \ (a d w - a y0 f - c b w + c x0 f + e b y0 - e x0 d) /
+
+
+ */
+ /* this isn't too nice and hasn't been tested at all. floating point is used to help readability */
+ double a = matrix[0][0];
+ double b = matrix[0][1];
+ double x0 = matrix[0][2];
+ double c = matrix[1][0];
+ double d = matrix[1][1];
+ double y0 = matrix[1][2];
+ double e = matrix[2][0];
+ double f = matrix[2][1];
+ double w = matrix[2][2];
+
+ double det = (a*d*w - a*y0*f - c*b*w + c*x0*f + e*b*y0 - e*x0*d);
+ double topx = (pow(d*w - y0*f, 2.)+pow(c*w - y0*e, 2.))*width*width;
+ double topy = (pow(b*w - x0*f, 2.)+pow(a*w - x0*e, 2.))*height*height;
+ double distx = sqrt(topx/(det*det));
+ double disty = sqrt(topy/(det*det));
+ *scaled_width = pixman_double_to_fixed(distx);
+ *scaled_height = pixman_double_to_fixed(disty);
+#endif
+ }
+}
+
+
+//XXX: could be called pixman_get_scaled_size()...
+void
+PIXMAN_EXPORT pixman_get_scaled_size (pixman_transform_t *transform,
+ int width, int height,
+ int *scaled_width, int *scaled_height)
+{
+ pixman_fixed_t (*matrix)[3] = transform->matrix;
+/*
+ / 2 2 2 \1/2
+ |width (d + c )|
+ distx := |----------------|
+ | 2 |
+ \ (a d - c b) /
+
+ / 2 2 2 \1/2
+ |height (b + a )|
+ disty := |-----------------|
+ | 2 |
+ \ (a d - c b) /
+ / \1/2
+ |width? (d? + c?)|
+ distx := |----------------|
+ \ (a d - c b)? /
+
+ ? height? (b? + a?) ? ?
+ disty := ? -------------------?
+ ? (a d - c b)? ?
+*/
+ pixman_bool_t affine = matrix[2][0] == 0 && matrix[2][1] == 0 && matrix[2][2] == pixman_fixed_1;
+ if (affine) {
+#if fixed
+ pixman_fixed_t det = mul_fixed(matrix[0][0],matrix[1][1]) - mul_fixed(matrix[0][1],matrix[1][0]);
+
+ pixman_fixed_t topx = square_fixed(width) *(square_fixed(matrix[1][1]) + square_fixed(matrix[1][0]));
+ pixman_fixed_t topy = square_fixed(height)*(square_fixed(matrix[0][0]) + square_fixed(matrix[0][1]));
+
+ *scaled_width = sqrt_fixed(div_fixed(topx, square_fixed(det)));
+ *scaled_height = sqrt_fixed(div_fixed(topy, square_fixed(det)));
+#else
+ double a = pixman_fixed_to_double(matrix[0][0]);
+ double b = pixman_fixed_to_double(matrix[0][1]);
+ double c = pixman_fixed_to_double(matrix[1][0]);
+ double d = pixman_fixed_to_double(matrix[1][1]);
+
+ double det = (a*d - c*b);
+ double topx = (d*d + c*c)*width*width;
+ double topy = (b*b + a*a)*height*height;
+ double distx = sqrt(topx/(det*det));
+ double disty = sqrt(topy/(det*det));
+ //printf("%f %f\n", distx, disty);
+ *scaled_width = round(distx);
+ *scaled_height = round(disty);
+#endif
+
+ } else {
+ /*
+ / 2 2 2 \1/2
+ | width ((d w - y0 f) (c w - y0 e)) |
+ |-------------------------------------------------------|
+ | 2 |
+ \ (a d w - a y0 f - c b w + c x0 f + e b y0 - e x0 d) /
+
+ / 2 2 2 \1/2
+ | height ((b w - x0 f) (a w - x0 e)) |
+ |-------------------------------------------------------|
+ | 2 |
+ \ (a d w - a y0 f - c b w + c x0 f + e b y0 - e x0 d) /
+
+
+ */
+ /* this isn't too nice and hasn't been tested at all. floating point is used to help readability */
+ double a = matrix[0][0];
+ double b = matrix[0][1];
+ double x0 = matrix[0][2];
+ double c = matrix[1][0];
+ double d = matrix[1][1];
+ double y0 = matrix[1][2];
+ double e = matrix[2][0];
+ double f = matrix[2][1];
+ double w = matrix[2][2];
+
+ double det = (a*d*w - a*y0*f - c*b*w + c*x0*f + e*b*y0 - e*x0*d);
+ double topx = (pow(d*w - y0*f, 2.)+pow(c*w - y0*e, 2.))*width*width;
+ double topy = (pow(b*w - x0*f, 2.)+pow(a*w - x0*e, 2.))*height*height;
+ double distx = sqrt(topx/(det*det));
+ double disty = sqrt(topy/(det*det));
+ *scaled_width = pixman_double_to_fixed(distx);
+ *scaled_height = pixman_double_to_fixed(disty);
+ }
+}
+
#if defined(USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
__attribute__((__force_align_arg_pointer__))
#endif
diff --git a/pixman/pixman.h b/pixman/pixman.h
index 7ae425c..ccc2abb 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -765,6 +765,7 @@ pixman_bool_t pixman_image_set_filter (pixman_image_t
int n_filter_params);
void pixman_image_set_source_clipping (pixman_image_t *image,
pixman_bool_t source_clipping);
+pixman_bool_t pixman_image_has_source_clipping (pixman_image_t *image);
void pixman_image_set_alpha_map (pixman_image_t *image,
pixman_image_t *alpha_map,
int16_t x,
diff --git a/test/Makefile.am b/test/Makefile.am
index cb8a5ef..a284922 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -4,6 +4,9 @@ INCLUDES = -I$(top_srcdir)/pixman -I$(top_builddir)/pixman
TESTPROGRAMS = \
region-test \
scaling-test \
+ extract-scale \
+ rescale-test \
+ scale-out-test \
fetch-test \
trap-crasher
@@ -11,6 +14,9 @@ fetch_test_LDADD = $(TEST_LDADD)
region_test_LDADD = $(TEST_LDADD)
scaling_test_LDADD = $(TEST_LDADD)
trap_crasher_LDADD = $(TEST_LDADD)
+extract_scale_LDADD = $(TEST_LDADD)
+rescale_test_LDADD = $(TEST_LDADD)
+scale_out_test_LDADD = $(TEST_LDADD)
# GTK using test programs
diff --git a/test/minpng.h b/test/minpng.h
new file mode 100644
index 0000000..c6b9cfb
--- /dev/null
+++ b/test/minpng.h
@@ -0,0 +1,251 @@
+/*
+ * Copyright ? 2009 Jeff Muizelaar
+ *
+ * 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 Jeff Muizelaar not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Jeff Muizelaar makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * JEFF MUIZELAAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL JEFF MUIZELAAR
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+/* PNG specification Annex D */
+
+/* Table of CRCs of all 8-bit messages. */
+unsigned long crc_table[256];
+
+/* Flag: has the table been computed? Initially false. */
+int crc_table_computed = 0;
+
+/* Make the table for a fast CRC. */
+void make_crc_table(void)
+{
+ unsigned long c;
+ int n, k;
+
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long) n;
+ for (k = 0; k < 8; k++) {
+ if (c & 1)
+ c = 0xedb88320L ^ (c >> 1);
+ else
+ c = c >> 1;
+ }
+ crc_table[n] = c;
+ }
+ crc_table_computed = 1;
+}
+
+
+/* Update a running CRC with the bytes buf[0..len-1]--the CRC
+ should be initialized to all 1's, and the transmitted value
+ is the 1's complement of the final running CRC (see the
+ crc() routine below). */
+
+unsigned long update_crc(unsigned long crc, unsigned char *buf,
+ int len)
+{
+ unsigned long c = crc;
+ int n;
+
+ if (!crc_table_computed)
+ make_crc_table();
+ for (n = 0; n < len; n++) {
+ c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
+ }
+ return c;
+}
+
+/* Return the CRC of the bytes buf[0..len-1]. */
+unsigned long crc(unsigned char *buf, int len)
+{
+ return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
+}
+
+char *write_be32(char *buf, int a)
+{
+ buf[0] = (a>>24) & 0xff;
+ buf[1] = (a>>16) & 0xff;
+ buf[2] = (a>>8) & 0xff;
+ buf[3] = (a>>0) & 0xff;
+ return &buf[4];
+}
+
+struct buf
+{
+ char *data;
+ int len;
+};
+
+struct buf chunk(char *type, struct buf q)
+{
+ struct buf b;
+ char *t = malloc(4 + 4 + len + 4);
+ char *chunk;
+ b.data = t;
+ len = q.len;
+ t = write_be32(t, len);
+ chunk = t;
+
+ t[0] = type[0]; t[1] = type[1]; t[2] = type[2]; t[3] = type[3];
+ t = &t[4];
+
+ memcpy(t, q.data, len);
+ t += q.len;
+ free(q.data);
+
+ t = write_be32(t, crc((unsigned char *)chunk, len + 4));
+
+ b.len = 4 + 4 + len + 4;
+ return b;
+}
+
+struct buf buf_cat_str(struct buf b, char *d, int len)
+{
+ struct buf r;
+ r.data = realloc(b.data, b.len + len);
+ memcpy(r.data + b.len, d, len);
+ r.len = b.len + len;
+ return r;
+}
+
+struct buf buf_cat_str_argb(struct buf b, char *d, int len)
+{
+ struct buf r;
+ r.data = realloc(b.data, b.len + len);
+ char *dest = r.data + b.len;
+ unsigned int *src = (unsigned int *)d;
+ r.len = b.len + len;
+ while (len) {
+ char alpha = (*src >> 24) & 0xff;
+ char red = (*src >> 16) & 0xff;
+ char green = (*src >> 8) & 0xff;
+ char blue = (*src >> 0) & 0xff;
+ *dest++ = red;
+ *dest++ = green;
+ *dest++ = blue;
+ *dest++ = alpha;
+ len-=4;
+ src++;
+ }
+ return r;
+}
+
+struct buf buf_cat(struct buf b, struct buf c)
+{
+ return buf_cat_str(b, c.data, c.len);
+}
+
+struct buf be32(int a)
+{
+ struct buf r;
+ r.data = malloc(4);
+ r.len = 4;
+ write_be32(r.data, a);
+ return r;
+}
+
+#define MOD_ADLER 65521
+/* From Wikipedia */
+uint32_t adler32(uint8_t *data, size_t len) /* data: Pointer to the data to be summed; len is in bytes */
+{
+ uint32_t a = 1, b = 0;
+
+ while (len != 0)
+ {
+ a = (a + *data++) % MOD_ADLER;
+ b = (b + a) % MOD_ADLER;
+
+ len--;
+ }
+
+ return (b << 16) | a;
+}
+
+/* 16bit length in little endian followed by
+ * ones compliment of length in little endian */
+struct buf zlib_block_length(int length)
+{
+ struct buf r;
+ r.data = malloc(4);
+ r.len = 4;
+ r.data[0] = length & 0xff;
+ r.data[1] = (length >> 8) & 0xff;
+ length = ~length;
+ r.data[2] = length & 0xff;
+ r.data[3] = (length >> 8) & 0xff;
+ return r;
+}
+
+/* inspired by "A use for uncompressed PNGs"
+ * http://drj11.wordpress.com/2007/11/20/a-use-for-uncompressed-pngs/
+ * by David Jones */
+struct buf make_png(char *d, int width, int height)
+{
+ struct buf r = {};
+ char predictor[] = {0x0};
+ char zlib_prefix[] = {0x78,0x9c};
+ char zlib_final_block_prefix[] = {0x01};
+ char zlib_block_prefix[] = {0x00};
+ char hdr_tail[] = {0x08,0x06,0x00,0x00,0x00};
+ char png_start[] = {0x89,'P','N','G','\r','\n',0x1A,'\n'};
+ r = buf_cat_str(r, png_start, sizeof(png_start));
+ struct buf ihdr = {};
+ int block_length = (width*4 + 1);
+ assert(block_length <= 65535);
+ ihdr = buf_cat(ihdr, be32(width));
+ ihdr = buf_cat(ihdr, be32(height));
+ ihdr = buf_cat_str(ihdr, hdr_tail, sizeof(hdr_tail));
+
+ r = buf_cat(r, chunk("IHDR", ihdr));
+
+ struct buf idat = {};
+ struct buf data = {};
+ idat = buf_cat_str(idat, zlib_prefix, sizeof(zlib_prefix));
+
+ int i;
+ for (i=0; i<height; i++) {
+ if (i == height - 1)
+ idat = buf_cat_str(idat, zlib_final_block_prefix, sizeof(zlib_final_block_prefix));
+ else
+ idat = buf_cat_str(idat, zlib_block_prefix, sizeof(zlib_block_prefix));
+
+ idat = buf_cat(idat, zlib_block_length(block_length));
+ data = buf_cat_str(data, predictor, sizeof(predictor));
+ idat = buf_cat_str(idat, predictor, sizeof(predictor));
+ data = buf_cat_str_argb(data, d, width * 4);
+ idat = buf_cat_str_argb(idat, d, width * 4);
+ d += width*4;
+ }
+ idat = buf_cat(idat, be32(adler32((unsigned char *)data.data, data.len)));
+
+ r = buf_cat(r, chunk("IDAT", idat));
+
+ struct buf iend = {};
+ r = buf_cat(r, chunk("IEND", iend));
+ return r;
+}
+
+
+void write_png(const char *name, char *d, int width, int height) {
+ FILE *f = fopen(name, "w+");
+ struct buf png = make_png(d, width, height);
+ fwrite(png.data, png.len, 1, f);
+ fclose(f);
+}
diff --git a/test/rescale-test.c b/test/rescale-test.c
new file mode 100644
index 0000000..8fddb64
--- /dev/null
+++ b/test/rescale-test.c
@@ -0,0 +1,123 @@
+#include <stdlib.h>
+#include <time.h>
+#include <stdio.h>
+#include <sched.h>
+#include <sys/time.h>
+#include <math.h>
+
+#include "pixman.h"
+#include "eng.h"
+#include "minpng.h"
+
+int downscale_lanczos_filter(pixman_image_t *pict, unsigned origWidth, unsigned origHeight,
+ signed scaledWidth, signed scaledHeight,
+ uint16_t startColumn, uint16_t startRow,
+ uint16_t width, uint16_t height,
+ uint32_t *src, int srcStride,
+ uint32_t *dest, int dstStride);
+
+#define WIDTH 400
+#define HEIGHT 400
+
+int randint(int min, int max)
+{
+ int q = min + random() % (max-min+1);
+ assert(q >= min);
+ assert(q <= max);
+}
+
+int main()
+{
+ uint32_t *src = malloc (WIDTH * HEIGHT * 4);
+ uint32_t *dest = malloc (WIDTH * HEIGHT * 4);
+ pixman_image_t *src_img;
+ pixman_image_t *dest_img;
+ int i, j;
+
+ for (i = 0; i < WIDTH * HEIGHT; ++i)
+ src[i] = 0xff7f0000; /* red */
+
+ for (i = 0; i < WIDTH * HEIGHT; ++i)
+ dest[i] = 0xff0000ff; /* blue */
+
+ int orig_width = WIDTH;
+ int orig_height = HEIGHT;
+ src_img = pixman_image_create_bits (PIXMAN_a8r8g8b8,
+ //WIDTH, HEIGHT,
+ orig_width, orig_height,
+ src,
+ WIDTH * 4);
+
+ dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8,
+ WIDTH, HEIGHT,
+ dest,
+ WIDTH * 4);
+
+ int k;
+ for (k=0; k<900; k++) {
+ int scaled_width = randint(1, WIDTH);
+ int scaled_height = randint(1, HEIGHT);
+ int x = randint(0, scaled_width-1);
+ int y = randint(0, scaled_height-1);
+ // keep these above 0 for now
+ int width = randint(1, scaled_width - x);
+ int height = randint(1, scaled_height - y);
+ //printf("%d %d\n", width, height);
+ //printf("%d %d\n", scaled_width, scaled_height);
+ //printf("%d %d\n", x, y);
+ downscale_lanczos_filter(src_img,
+ orig_width, orig_height,
+ scaled_width, scaled_height,
+ x, y,
+ width, height,
+ src, orig_width * 4,
+ dest, WIDTH * 4);
+
+ //write_png("1.png", dest, WIDTH, HEIGHT);
+ int lan_sum = sum(dest, WIDTH * HEIGHT * 4);
+ //printf("%x\n", lan_sum);
+
+ for (i = 0; i < WIDTH * HEIGHT; ++i)
+ dest[i] = 0xff0000ff; /* blue */
+#if 0
+int downscale_box_filter(pixman_image_t *pict, unsigned origWidth, unsigned origHeight,
+ signed scaledWidth, signed scaledHeight,
+ uint16_t startColumn, uint16_t startRow,
+ uint16_t width, uint16_t height,
+ uint32_t *src, int srcStride,
+ uint32_t *dest, int dstStride)
+#endif
+ downscale_box_filter(src_img,
+ orig_width, orig_height,
+ scaled_width, scaled_height,
+ x, y,
+ width, height,
+ src, orig_width * 4,
+ dest, WIDTH * 4);
+
+ int box_sum = sum(dest, WIDTH * HEIGHT * 4);
+ //printf("%x\n", box_sum);
+ //write_png("2.png", dest, WIDTH, HEIGHT);
+
+ for (i = 0; i < WIDTH * HEIGHT; ++i)
+ dest[i] = 0xff0000ff; /* blue */
+
+ downscale_box_mult_filter(src_img,
+ orig_width, orig_height,
+ scaled_width, scaled_height,
+ x, y,
+ width, height,
+ src, orig_width * 4,
+ dest, WIDTH * 4);
+
+ int mult_sum = sum(dest, WIDTH * HEIGHT * 4);
+ //printf("%x\n", mult_sum);
+ //write_png("3.png", dest, WIDTH, HEIGHT);
+ for (i = 0; i < WIDTH * HEIGHT; ++i)
+ dest[i] = 0xff0000ff; /* blue */
+
+ assert(mult_sum == lan_sum && box_sum == lan_sum);
+
+ }
+
+}
diff --git a/test/scale-out-test.c b/test/scale-out-test.c
new file mode 100644
index 0000000..881d27e
--- /dev/null
+++ b/test/scale-out-test.c
@@ -0,0 +1,139 @@
+#include <stdlib.h>
+#include <time.h>
+#include <stdio.h>
+#include <sched.h>
+#include <sys/time.h>
+#include <math.h>
+
+#include "pixman.h"
+#include "eng.h"
+#include "minpng.h"
+
+int downscale_lanczos_filter(pixman_image_t *pict, unsigned origWidth, unsigned origHeight,
+ signed scaledWidth, signed scaledHeight,
+ uint16_t startColumn, uint16_t startRow,
+ uint16_t width, uint16_t height,
+ uint32_t *src, int srcStride,
+ uint32_t *dest, int dstStride);
+
+#define WIDTH 400
+#define HEIGHT 400
+
+int randint(int min, int max)
+{
+ int q = min + random() % (max-min+1);
+ assert(q >= min);
+ assert(q <= max);
+}
+
+//#include "in.h"
+extern char input[];
+int main()
+{
+ uint32_t *src = malloc (WIDTH * HEIGHT * 4);
+ uint32_t *dest = malloc (WIDTH * HEIGHT * 4);
+ pixman_image_t *src_img;
+ pixman_image_t *dest_img;
+ int i, j;
+
+ for (i = 0; i < WIDTH * HEIGHT; ++i)
+ src[i] = 0xff7f0000; /* red */
+
+ for (i = 0; i < WIDTH * HEIGHT; ++i)
+ dest[i] = 0xff0000ff; /* blue */
+
+ int orig_width = 1024;
+ int orig_height = 768;
+ src_img = pixman_image_create_bits (PIXMAN_a8r8g8b8,
+ //WIDTH, HEIGHT,
+ orig_width, orig_height,
+ input,
+ orig_width * 4);
+
+ dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8,
+ WIDTH, HEIGHT,
+ dest,
+ WIDTH * 4);
+
+ int k;
+ int scaled_width = 200;
+ int scaled_height = 200;
+ int x = 0;
+ int y = 0;
+ // keep these above 0 for now
+ int width = scaled_width;
+ int height = scaled_height;
+ //printf("%d %d\n", width, height);
+ //printf("%d %d\n", scaled_width, scaled_height);
+ //printf("%d %d\n", x, y);
+ clock_t start, end;
+ start = clock();
+ downscale_lanczos_filter(src_img,
+ orig_width, orig_height,
+ scaled_width, scaled_height,
+ x, y,
+ width, height,
+ src, orig_width * 4,
+ dest, WIDTH * 4);
+ end = clock();
+ printf("t: %d\n", end - start);
+
+ write_png("1.png", dest, WIDTH, HEIGHT);
+ int lan_sum = sum(dest, WIDTH * HEIGHT * 4);
+ printf("%x\n", lan_sum);
+
+ for (i = 0; i < WIDTH * HEIGHT; ++i)
+ dest[i] = 0xff0000ff; /* blue */
+#if 0
+int downscale_box_filter(pixman_image_t *pict, unsigned origWidth, unsigned origHeight,
+ signed scaledWidth, signed scaledHeight,
+ uint16_t startColumn, uint16_t startRow,
+ uint16_t width, uint16_t height,
+ uint32_t *src, int srcStride,
+ uint32_t *dest, int dstStride)
+#endif
+ start = clock();
+ downscale_box_filter(src_img,
+ orig_width, orig_height,
+ scaled_width, scaled_height,
+ x, y,
+ width, height,
+ src, orig_width * 4,
+ dest, WIDTH * 4);
+ end = clock();
+ printf("t: %d\n", end - start);
+
+ int box_sum = sum(dest, WIDTH * HEIGHT * 4);
+ printf("%x\n", box_sum);
+ write_png("2.png", dest, WIDTH, HEIGHT);
+
+ for (i = 0; i < WIDTH * HEIGHT; ++i)
+ dest[i] = 0xff0000ff; /* blue */
+
+ start = clock();
+ downscale_box_mult_filter(src_img,
+ orig_width, orig_height,
+ scaled_width, scaled_height,
+ x, y,
+ width, height,
+ src, orig_width * 4,
+ dest, WIDTH * 4);
+ end = clock();
+ printf("t: %d\n", end - start);
+ int mult_sum = sum(dest, WIDTH * HEIGHT * 4);
+ printf("%x\n", mult_sum);
+ write_png("3.png", dest, WIDTH, HEIGHT);
+
+ start = clock();
+ downscale_box_mult_old_filter(src_img,
+ orig_width, orig_height,
+ scaled_width, scaled_height,
+ x, y,
+ width, height,
+ src, orig_width * 4,
+ dest, WIDTH * 4);
+ end = clock();
+ printf("t: %d\n", end - start);
+
+
+}
More information about the cairo
mailing list