[cairo] pixman box filtering code prototype
Jeff Muizelaar
jeff at infidigm.net
Mon Nov 17 15:00:03 PST 2008
On Wed, Nov 05, 2008 at 04:52:03PM -0500, Jeff Muizelaar wrote:
> On Tue, Nov 04, 2008 at 05:37:51PM -0500, Jeff Muizelaar wrote:
> > Here's an update. It should be basically correct at this time (although
> > it doesn't filter masks yet...). It still needs cleanup and
> > optimization.
>
> And another update. This version is pretty much feature complete and I
> gave it a basic run through with firefox. (there's still a rounding
> problem...).
>
> I've also done some quick performance tests compared to the current
> bilinear downscaling:
> scale:.8 speed: 2x faster
> scale:.4 speed: a little faster
> scale:.2 speed: slower
>
> The speed gains currently come at a cost. The image quality when scaling
> between 1. and .5 is lower than the current filtering because we use a
> combination of two integer box sizes which causes some blockiness. It's
> possible to fix this by using a non-integer box-filter but that will
> probably have a performance impact.
I've attached a rough cut of what this could look like.
-Jeff
-------------- next part --------------
diff --git a/pixman/Makefile.am b/pixman/Makefile.am
index 6d5a643..4110c56 100644
--- a/pixman/Makefile.am
+++ b/pixman/Makefile.am
@@ -26,6 +26,8 @@ libpixman_1_la_SOURCES = \
pixman-edge-imp.h \
pixman-trap.c \
pixman-compute-region.c \
+ pixman-rescale-box.c \
+ pixman-rescale-mult.c \
pixman-timer.c
libpixmanincludedir = $(includedir)/pixman-1/
diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index e80c479..3c7526d 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -518,6 +518,14 @@ pixman_image_set_source_clipping (pixman_image_t *image,
common->src_clip = &common->full_region;
}
+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 e2fd235..aaefcce 100644
--- a/pixman/pixman-pict.c
+++ b/pixman/pixman-pict.c
@@ -36,6 +36,7 @@
#include "pixman-sse2.h"
#include "pixman-arm-simd.h"
#include "pixman-combine32.h"
+#include "pixman-rescale-box.h"
#define FbFullMask(n) ((n) == 32 ? (uint32_t)-1 : ((((uint32_t) 1) << n) - 1))
@@ -1766,6 +1767,59 @@ 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_box_mult_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_extract_scale (&new_transform, &scale_x, &scale_y);
+ pixman_transform_unscale (&new_transform, scale_x, scale_y);
+#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;
+}
#if defined(USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
/*
@@ -1784,6 +1838,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
@@ -1807,6 +1862,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
@@ -1828,6 +1885,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;
@@ -1844,7 +1919,66 @@ 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;
+ }
+ }
+ }
+
+ pixman_bool_t shared_transform = FALSE;
+ if (pMask && pMask->type == BITS && pMask->common.transform && pSrc->type == BITS && pSrc->common.transform) {
+ shared_transform = memcmp (pMask->common.transform, pSrc->common.transform, sizeof (pixman_transform_t)) == 0;
+ }
+ pixman_fixed_t (*matrix)[3] = pSrc->common.transform->matrix;
+ if (shared_transform && ((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: %x %x\n", matrix[0][2], matrix[1][2]);
+ }
+ }
}
+ 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
@@ -1962,6 +2096,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 1380fa3..872d385 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -718,6 +718,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);
@@ -801,4 +812,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..8222984
--- /dev/null
+++ b/pixman/pixman-rescale-box.c
@@ -0,0 +1,396 @@
+/* -*- 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-box.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:
+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;
+ for (d = 0; 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(temp_buf);
+ return 0;
+}
+
diff --git a/pixman/pixman-rescale-box.h b/pixman/pixman-rescale-box.h
new file mode 100644
index 0000000..584c2d7
--- /dev/null
+++ b/pixman/pixman-rescale-box.h
@@ -0,0 +1,6 @@
+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);
diff --git a/pixman/pixman-rescale-mult.c b/pixman/pixman-rescale-mult.c
new file mode 100644
index 0000000..767f15a
--- /dev/null
+++ b/pixman/pixman-rescale-mult.c
@@ -0,0 +1,319 @@
+/* -*- 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-box.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;
+ if (y > pict->bits.height-1)
+ y = pict->bits.height-1;
+ 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;
+ }
+ }
+}
+
+
+/**********************************************************
+ Stretches a horizontal source line onto a horizontal
+ destination line. Used by RectStretch.
+**********************************************************/
+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 i;
+ int box = 1 << 24;
+ 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 */
+ if (box > 0) {
+ a += ((*src >> 24) & 0xff) * box;
+ r += ((*src >> 16) & 0xff) * box;
+ g += ((*src >> 8) & 0xff) * box;
+ b += ((*src >> 0) & 0xff) * box;
+ }
+
+ a >>= 24;
+ r >>= 24;
+ g >>= 24;
+ b >>= 24;
+
+ *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;
+ int i;
+ uint32_t *column_src = src;
+ int box = 1 << 24;
+ 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 >>= 24;
+ r >>= 24;
+ g >>= 24;
+ b >>= 24;
+
+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
+ dest++;
+ src++;
+ }
+}
+
+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;
+ int ratio = ((1 << 24)/(long long int)src_length)*dest_length;
+ int p=0;
+ int remainder = full;
+ for (i=0; i<src_length; i++) {
+ if (remainder < ratio) {
+ p = ratio - remainder;
+ remainder = full - p;
+ } else {
+ p = ratio;
+ remainder -= ratio;
+ }
+ coverage[i] = p;
+ }
+ return ratio;
+}
+
+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);
+ 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
+
+ /* 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 x = 0;
+ int y = 0;
+ for (d = 0; d < startRow + height; d++)
+ {
+ int columns = 0;
+ int box = 1 << 24;
+ 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-transformed.c b/pixman/pixman-transformed.c
index 983ff1f..55cf4a8 100644
--- a/pixman/pixman-transformed.c
+++ b/pixman/pixman-transformed.c
@@ -59,7 +59,7 @@ typedef FASTCALL uint32_t (*fetchFromRegionProc)(bits_image_t *pict, int x, int
* for is when src_clip is false. Since inside_bounds is statically known,
* the last part of the if statement will normally be optimized away.
*/
-static force_inline uint32_t
+static inline uint32_t
do_fetch (bits_image_t *pict, int x, int y, fetchPixelProc32 fetch,
pixman_bool_t src_clip,
pixman_bool_t inside_bounds)
@@ -87,155 +87,343 @@ do_fetch (bits_image_t *pict, int x, int y, fetchPixelProc32 fetch,
/*
* Fetching Algorithms
*/
-static inline uint32_t
-fetch_nearest (bits_image_t *pict,
- fetchPixelProc32 fetch,
- pixman_bool_t affine,
- pixman_repeat_t repeat,
- pixman_bool_t has_src_clip,
- const pixman_vector_t *v)
+static void
+fbFetchTransformed_Nearest_Normal(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
{
- if (!v->vector[2])
+ fetchPixelProc32 fetch;
+ pixman_bool_t src_clip;
+ int x, y, i;
+
+ /* initialize the two function pointers */
+ fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
+
+ src_clip = pict->common.src_clip != &(pict->common.full_region);
+
+ for ( i = 0; i < width; ++i)
{
- return 0;
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2])
+ {
+ *(buffer + i) = 0;
+ }
+ else
+ {
+ if (!affine)
+ {
+ y = MOD(DIV(v.vector[1],v.vector[2]), pict->height);
+ x = MOD(DIV(v.vector[0],v.vector[2]), pict->width);
+ }
+ else
+ {
+ y = MOD(v.vector[1]>>16, pict->height);
+ x = MOD(v.vector[0]>>16, pict->width);
+ }
+
+ *(buffer + i) = do_fetch (pict, x, y, fetch, src_clip, TRUE);
+ }
+ }
+
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
}
- else
+}
+
+static void
+fbFetchTransformed_Nearest_Pad(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+ pixman_bool_t src_clip;
+ fetchPixelProc32 fetch;
+ int x, y, i;
+
+ /* initialize the two function pointers */
+ fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
+
+ src_clip = pict->common.src_clip != &(pict->common.full_region);
+
+ for (i = 0; i < width; ++i)
{
- int x, y;
- pixman_bool_t inside_bounds;
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2])
+ {
+ *(buffer + i) = 0;
+ }
+ else
+ {
+ if (!affine)
+ {
+ y = CLIP(DIV(v.vector[1], v.vector[2]), 0, pict->height-1);
+ x = CLIP(DIV(v.vector[0], v.vector[2]), 0, pict->width-1);
+ }
+ else
+ {
+ y = CLIP(v.vector[1]>>16, 0, pict->height-1);
+ x = CLIP(v.vector[0]>>16, 0, pict->width-1);
+ }
- if (!affine)
- {
- x = DIV(v->vector[0], v->vector[2]);
- y = DIV(v->vector[1], v->vector[2]);
- }
- else
- {
- x = v->vector[0]>>16;
- y = v->vector[1]>>16;
- }
+ *(buffer + i) = do_fetch (pict, x, y, fetch, src_clip, TRUE);
+ }
+ }
- switch (repeat)
- {
- case PIXMAN_REPEAT_NORMAL:
- x = MOD (x, pict->width);
- y = MOD (y, pict->height);
- inside_bounds = TRUE;
- break;
-
- case PIXMAN_REPEAT_PAD:
- x = CLIP (x, 0, pict->width-1);
- y = CLIP (y, 0, pict->height-1);
- inside_bounds = TRUE;
- break;
-
- case PIXMAN_REPEAT_REFLECT: /* FIXME: this should be implemented for images */
- case PIXMAN_REPEAT_NONE:
- inside_bounds = FALSE;
- break;
-
- default:
- return 0;
- }
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
+ }
+}
+
+static void
+fbFetchTransformed_Nearest_General(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+ fetchPixelProc32 fetch;
+ pixman_bool_t src_clip;
+ int x, y, i;
+
+ fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
+
+ src_clip = pict->common.src_clip != &(pict->common.full_region);
- return do_fetch (pict, x, y, fetch, has_src_clip, inside_bounds);
+ for (i = 0; i < width; ++i) {
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2]) {
+ *(buffer + i) = 0;
+ } else {
+ if (!affine) {
+ y = DIV(v.vector[1],v.vector[2]);
+ x = DIV(v.vector[0],v.vector[2]);
+ } else {
+ y = v.vector[1]>>16;
+ x = v.vector[0]>>16;
+ }
+
+ *(buffer + i) = do_fetch (pict, x, y, fetch, src_clip, FALSE);
+ }
+ }
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
}
}
-static inline uint32_t
-fetch_bilinear (bits_image_t *pict,
- fetchPixelProc32 fetch,
- pixman_bool_t affine,
- pixman_repeat_t repeat,
- pixman_bool_t has_src_clip,
- const pixman_vector_t *v)
+static void
+fbFetchTransformed_Bilinear_Normal(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
{
- if (!v->vector[2])
- {
- return 0;
+ pixman_bool_t src_clip;
+ fetchPixelProc32 fetch;
+ int i;
+
+ fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
+
+ src_clip = pict->common.src_clip != &(pict->common.full_region);
+
+ for (i = 0; i < width; ++i) {
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2]) {
+ *(buffer + i) = 0;
+ } else {
+ int x1, x2, y1, y2, distx, idistx, disty, idisty;
+ uint32_t tl, tr, bl, br, r;
+ uint32_t ft, fb;
+
+ if (!affine) {
+ pixman_fixed_48_16_t div;
+ div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
+ x1 = div >> 16;
+ distx = ((pixman_fixed_t)div >> 8) & 0xff;
+ div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
+ y1 = div >> 16;
+ disty = ((pixman_fixed_t)div >> 8) & 0xff;
+ } else {
+ x1 = v.vector[0] >> 16;
+ distx = (v.vector[0] >> 8) & 0xff;
+ y1 = v.vector[1] >> 16;
+ disty = (v.vector[1] >> 8) & 0xff;
+ }
+ x2 = x1 + 1;
+ y2 = y1 + 1;
+
+ idistx = 256 - distx;
+ idisty = 256 - disty;
+
+ x1 = MOD (x1, pict->width);
+ x2 = MOD (x2, pict->width);
+ y1 = MOD (y1, pict->height);
+ y2 = MOD (y2, pict->height);
+
+ tl = do_fetch (pict, x1, y1, fetch, src_clip, TRUE);
+ tr = do_fetch (pict, x2, y1, fetch, src_clip, TRUE);
+ bl = do_fetch (pict, x1, y2, fetch, src_clip, TRUE);
+ br = do_fetch (pict, x2, y2, fetch, src_clip, TRUE);
+
+ ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
+ fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
+ r = (((ft * idisty + fb * disty) >> 16) & 0xff);
+ ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
+ fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
+ r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
+ ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
+ fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
+ r |= (((ft * idisty + fb * disty)) & 0xff0000);
+ ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
+ fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
+ r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
+ *(buffer + i) = r;
+ }
+ }
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
}
- else
+}
+
+static void
+fbFetchTransformed_Bilinear_Pad(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+ pixman_bool_t src_clip;
+ fetchPixelProc32 fetch;
+ int i;
+
+ /* initialize the two function pointers */
+ fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
+
+ src_clip = pict->common.src_clip != &(pict->common.full_region);
+
+ for (i = 0; i < width; ++i) {
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2]) {
+ *(buffer + i) = 0;
+ } else {
+ int x1, x2, y1, y2, distx, idistx, disty, idisty;
+ uint32_t tl, tr, bl, br, r;
+ uint32_t ft, fb;
+
+ if (!affine) {
+ pixman_fixed_48_16_t div;
+ div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
+ x1 = div >> 16;
+ distx = ((pixman_fixed_t)div >> 8) & 0xff;
+ div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
+ y1 = div >> 16;
+ disty = ((pixman_fixed_t)div >> 8) & 0xff;
+ } else {
+ x1 = v.vector[0] >> 16;
+ distx = (v.vector[0] >> 8) & 0xff;
+ y1 = v.vector[1] >> 16;
+ disty = (v.vector[1] >> 8) & 0xff;
+ }
+ x2 = x1 + 1;
+ y2 = y1 + 1;
+
+ idistx = 256 - distx;
+ idisty = 256 - disty;
+
+ x1 = CLIP (x1, 0, pict->width-1);
+ x2 = CLIP (x2, 0, pict->width-1);
+ y1 = CLIP (y1, 0, pict->height-1);
+ y2 = CLIP (y2, 0, pict->height-1);
+
+ tl = do_fetch(pict, x1, y1, fetch, src_clip, TRUE);
+ tr = do_fetch(pict, x2, y1, fetch, src_clip, TRUE);
+ bl = do_fetch(pict, x1, y2, fetch, src_clip, TRUE);
+ br = do_fetch(pict, x2, y2, fetch, src_clip, TRUE);
+
+ ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
+ fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
+ r = (((ft * idisty + fb * disty) >> 16) & 0xff);
+ ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
+ fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
+ r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
+ ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
+ fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
+ r |= (((ft * idisty + fb * disty)) & 0xff0000);
+ ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
+ fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
+ r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
+ *(buffer + i) = r;
+ }
+ }
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
+ }
+}
+
+static void
+fbFetchTransformed_Bilinear_General(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+{
+ pixman_bool_t src_clip;
+ fetchPixelProc32 fetch;
+ int i;
+
+ /* initialize the two function pointers */
+ fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
+
+ src_clip = pict->common.src_clip != &(pict->common.full_region);
+
+ for (i = 0; i < width; ++i)
{
- int x1, x2, y1, y2, distx, idistx, disty, idisty;
- uint32_t tl, tr, bl, br, r;
- uint32_t ft, fb;
- pixman_bool_t inside_bounds;
-
- if (!affine)
- {
- pixman_fixed_48_16_t div;
- div = ((pixman_fixed_48_16_t)v->vector[0] << 16)/v->vector[2];
- x1 = div >> 16;
- distx = ((pixman_fixed_t)div >> 8) & 0xff;
- div = ((pixman_fixed_48_16_t)v->vector[1] << 16)/v->vector[2];
- y1 = div >> 16;
- disty = ((pixman_fixed_t)div >> 8) & 0xff;
- }
- else
- {
- x1 = v->vector[0] >> 16;
- distx = (v->vector[0] >> 8) & 0xff;
- y1 = v->vector[1] >> 16;
- disty = (v->vector[1] >> 8) & 0xff;
- }
- x2 = x1 + 1;
- y2 = y1 + 1;
-
- idistx = 256 - distx;
- idisty = 256 - disty;
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2]) {
+ *(buffer + i) = 0;
+ } else {
+ int x1, x2, y1, y2, distx, idistx, disty, idisty;
+ uint32_t tl, tr, bl, br, r;
+ uint32_t ft, fb;
- switch (repeat)
- {
- case PIXMAN_REPEAT_NORMAL:
- x1 = MOD (x1, pict->width);
- x2 = MOD (x2, pict->width);
- y1 = MOD (y1, pict->height);
- y2 = MOD (y2, pict->height);
- inside_bounds = TRUE;
- break;
-
- case PIXMAN_REPEAT_PAD:
- x1 = CLIP (x1, 0, pict->width-1);
- x2 = CLIP (x2, 0, pict->width-1);
- y1 = CLIP (y1, 0, pict->height-1);
- y2 = CLIP (y2, 0, pict->height-1);
- inside_bounds = TRUE;
- break;
-
- case PIXMAN_REPEAT_REFLECT: /* FIXME: this should be implemented for images */
- case PIXMAN_REPEAT_NONE:
- inside_bounds = FALSE;
- break;
-
- default:
- return 0;
- }
-
- tl = do_fetch(pict, x1, y1, fetch, has_src_clip, inside_bounds);
- tr = do_fetch(pict, x2, y1, fetch, has_src_clip, inside_bounds);
- bl = do_fetch(pict, x1, y2, fetch, has_src_clip, inside_bounds);
- br = do_fetch(pict, x2, y2, fetch, has_src_clip, inside_bounds);
-
- ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
- fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
- r = (((ft * idisty + fb * disty) >> 16) & 0xff);
- ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
- fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
- r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
- ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
- fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
- r |= (((ft * idisty + fb * disty)) & 0xff0000);
- ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
- fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
- r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
-
- return r;
+ if (!affine) {
+ pixman_fixed_48_16_t div;
+ div = ((pixman_fixed_48_16_t)v.vector[0] << 16)/v.vector[2];
+ x1 = div >> 16;
+ distx = ((pixman_fixed_t)div >> 8) & 0xff;
+ div = ((pixman_fixed_48_16_t)v.vector[1] << 16)/v.vector[2];
+ y1 = div >> 16;
+ disty = ((pixman_fixed_t)div >> 8) & 0xff;
+ } else {
+ x1 = v.vector[0] >> 16;
+ distx = (v.vector[0] >> 8) & 0xff;
+ y1 = v.vector[1] >> 16;
+ disty = (v.vector[1] >> 8) & 0xff;
+ }
+ x2 = x1 + 1;
+ y2 = y1 + 1;
+
+ idistx = 256 - distx;
+ idisty = 256 - disty;
+
+ tl = do_fetch(pict, x1, y1, fetch, src_clip, FALSE);
+ tr = do_fetch(pict, x2, y1, fetch, src_clip, FALSE);
+ bl = do_fetch(pict, x1, y2, fetch, src_clip, FALSE);
+ br = do_fetch(pict, x2, y2, fetch, src_clip, FALSE);
+
+ ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
+ fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
+ r = (((ft * idisty + fb * disty) >> 16) & 0xff);
+ ft = FbGet8(tl,8) * idistx + FbGet8(tr,8) * distx;
+ fb = FbGet8(bl,8) * idistx + FbGet8(br,8) * distx;
+ r |= (((ft * idisty + fb * disty) >> 8) & 0xff00);
+ ft = FbGet8(tl,16) * idistx + FbGet8(tr,16) * distx;
+ fb = FbGet8(bl,16) * idistx + FbGet8(br,16) * distx;
+ r |= (((ft * idisty + fb * disty)) & 0xff0000);
+ ft = FbGet8(tl,24) * idistx + FbGet8(tr,24) * distx;
+ fb = FbGet8(bl,24) * idistx + FbGet8(br,24) * distx;
+ r |= (((ft * idisty + fb * disty) << 8) & 0xff000000);
+ *(buffer + i) = r;
+ }
+ }
+
+ v.vector[0] += unit.vector[0];
+ v.vector[1] += unit.vector[1];
+ v.vector[2] += unit.vector[2];
}
}
static void
-fbFetchTransformed_Convolution(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits,
- pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
+fbFetchTransformed_Convolution(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
{
fetchPixelProc32 fetch;
int i;
@@ -367,13 +555,20 @@ ACCESS(fbFetchTransformed)(bits_image_t * pict, int x, int y, int width,
/* when using convolution filters or PIXMAN_REPEAT_PAD one might get here without a transform */
if (pict->common.transform)
{
- if (!pixman_transform_point_3d (pict->common.transform, &v))
- return;
- unit.vector[0] = pict->common.transform->matrix[0][0];
- unit.vector[1] = pict->common.transform->matrix[1][0];
- unit.vector[2] = pict->common.transform->matrix[2][0];
- affine = (v.vector[2] == pixman_fixed_1 && unit.vector[2] == 0);
+ pixman_transform_t transform = *pict->common.transform;
+#if 0
+ if (pict->downscaled) {
+ pict->downscale_width;
+ pict->downscale_height;
+ }
+#endif
+ if (!pixman_transform_point_3d (&transform, &v))
+ return;
+ unit.vector[0] = transform.matrix[0][0];
+ unit.vector[1] = transform.matrix[1][0];
+ unit.vector[2] = transform.matrix[2][0];
+ affine = v.vector[2] == pixman_fixed_1 && unit.vector[2] == 0;
}
else
{
@@ -383,57 +578,46 @@ ACCESS(fbFetchTransformed)(bits_image_t * pict, int x, int y, int width,
}
/* This allows filtering code to pretend that pixels are located at integer coordinates */
+ adjust (&v, &unit, -(pixman_fixed_1 / 2));
+
if (pict->common.filter == PIXMAN_FILTER_NEAREST || pict->common.filter == PIXMAN_FILTER_FAST)
{
- fetchPixelProc32 fetch;
- pixman_bool_t src_clip;
- int i;
-
/* Round down to closest integer, ensuring that 0.5 rounds to 0, not 1 */
- adjust (&v, &unit, - pixman_fixed_e);
-
- fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
-
- src_clip = pict->common.src_clip != &(pict->common.full_region);
+ adjust (&v, &unit, pixman_fixed_1 / 2 - pixman_fixed_e);
- for ( i = 0; i < width; ++i)
- {
- if (!mask || mask[i] & maskBits)
- *(buffer + i) = fetch_nearest (pict, fetch, affine, pict->common.repeat, src_clip, &v);
-
- v.vector[0] += unit.vector[0];
- v.vector[1] += unit.vector[1];
- v.vector[2] += unit.vector[2];
- }
- }
- else if (pict->common.filter == PIXMAN_FILTER_BILINEAR ||
+ if (pict->common.repeat == PIXMAN_REPEAT_NORMAL)
+ {
+ fbFetchTransformed_Nearest_Normal(pict, width, buffer, mask, maskBits, affine, v, unit);
+ }
+ else if (pict->common.repeat == PIXMAN_REPEAT_PAD)
+ {
+ fbFetchTransformed_Nearest_Pad(pict, width, buffer, mask, maskBits, affine, v, unit);
+ }
+ else
+ {
+ fbFetchTransformed_Nearest_General(pict, width, buffer, mask, maskBits, affine, v, unit);
+ }
+ } else if (pict->common.filter == PIXMAN_FILTER_BILINEAR ||
pict->common.filter == PIXMAN_FILTER_GOOD ||
pict->common.filter == PIXMAN_FILTER_BEST)
{
- pixman_bool_t src_clip;
- fetchPixelProc32 fetch;
- int i;
-
- /* Let the bilinear code pretend that pixels fall on integer coordinaters */
- adjust (&v, &unit, -(pixman_fixed_1 / 2));
-
- fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
- src_clip = pict->common.src_clip != &(pict->common.full_region);
-
- for (i = 0; i < width; ++i)
- {
- if (!mask || mask[i] & maskBits)
- *(buffer + i) = fetch_bilinear (pict, fetch, affine, pict->common.repeat, src_clip, &v);
-
- v.vector[0] += unit.vector[0];
- v.vector[1] += unit.vector[1];
- v.vector[2] += unit.vector[2];
- }
+ if (pict->common.repeat == PIXMAN_REPEAT_NORMAL)
+ {
+ fbFetchTransformed_Bilinear_Normal(pict, width, buffer, mask, maskBits, affine, v, unit);
+ }
+ else if (pict->common.repeat == PIXMAN_REPEAT_PAD)
+ {
+ fbFetchTransformed_Bilinear_Pad(pict, width, buffer, mask, maskBits, affine, v, unit);
+ }
+ else
+ {
+ fbFetchTransformed_Bilinear_General(pict, width, buffer, mask, maskBits, affine, v, unit);
+ }
}
else if (pict->common.filter == PIXMAN_FILTER_CONVOLUTION)
{
/* Round to closest integer, ensuring that 0.5 rounds to 0, not 1 */
- adjust (&v, &unit, - pixman_fixed_e);
+ adjust (&v, &unit, pixman_fixed_1 / 2 - pixman_fixed_e);
fbFetchTransformed_Convolution(pict, width, buffer, mask, maskBits, affine, v, unit);
}
diff --git a/pixman/pixman-utils.c b/pixman/pixman-utils.c
index adb3e20..740bfd3 100644
--- a/pixman/pixman-utils.c
+++ b/pixman/pixman-utils.c
@@ -26,6 +26,7 @@
#endif
#include <stdlib.h>
+#include <math.h>
#include "pixman-private.h"
#include "pixman-mmx.h"
@@ -63,6 +64,272 @@ pixman_transform_point_3d (pixman_transform_t *transform,
return TRUE;
}
+#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 26ed0cb..093eebe 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -615,6 +615,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 33e2200..e1b1fbf 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -4,6 +4,7 @@ TESTPROGRAMS = \
composite-test \
gradient-test \
region-test \
+ extract-scale \
fetch-test
noinst_PROGRAMS = $(TESTPROGRAMS)
@@ -16,4 +17,19 @@ fetch_test_LDADD = $(top_builddir)/pixman/libpixman-1.la
region_test_LDADD = $(top_builddir)/pixman/libpixman-1.la
clip_test_LDADD = $(top_builddir)/pixman/libpixman-1.la $(GTK_LIBS)
+else
+
+TESTPROGRAMS = \
+ region-test \
+ extract-scale \
+ fetch-test
+
+noinst_PROGRAMS = $(TESTPROGRAMS)
+
+INCLUDES = -I$(top_srcdir)/pixman -I$(top_builddir)/pixman
+
+fetch_test_LDADD = $(top_builddir)/pixman/libpixman-1.la
+extract_scale_LDADD = $(top_builddir)/pixman/libpixman-1.la
+region_test_LDADD = $(top_builddir)/pixman/libpixman-1.la
endif
+
More information about the cairo
mailing list