summaryrefslogtreecommitdiffstats
path: root/src/gui/painting/qimagescale.cpp
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/gui/painting/qimagescale.cpp
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/gui/painting/qimagescale.cpp')
-rw-r--r--src/gui/painting/qimagescale.cpp1031
1 files changed, 1031 insertions, 0 deletions
diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp
new file mode 100644
index 0000000000..87df7976bf
--- /dev/null
+++ b/src/gui/painting/qimagescale.cpp
@@ -0,0 +1,1031 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <private/qimagescale_p.h>
+#include <private/qdrawhelper_p.h>
+
+#include "qimage.h"
+#include "qcolor.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QImageScale {
+ struct QImageScaleInfo;
+}
+
+typedef void (*qt_qimageScaleFunc)(QImageScale::QImageScaleInfo *isi, unsigned int *dest,
+ int dxx, int dyy, int dx, int dy, int dw,
+ int dh, int dow, int sow);
+
+static void qt_qimageScaleAARGB(QImageScale::QImageScaleInfo *isi, unsigned int *dest,
+ int dxx, int dyy, int dx, int dy, int dw,
+ int dh, int dow, int sow);
+
+static void qt_qimageScaleAARGBA(QImageScale::QImageScaleInfo *isi, unsigned int *dest,
+ int dxx, int dyy, int dx, int dy, int dw,
+ int dh, int dow, int sow);
+
+qt_qimageScaleFunc qt_qimageScaleArgb = qt_qimageScaleAARGBA;
+qt_qimageScaleFunc qt_qimageScaleRgb = qt_qimageScaleAARGB;
+
+
+/*
+ * Copyright (C) 2004, 2005 Daniel M. Duley
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* OTHER CREDITS:
+ *
+ * This is the normal smoothscale method, based on Imlib2's smoothscale.
+ *
+ * Originally I took the algorithm used in NetPBM and Qt and added MMX/3dnow
+ * optimizations. It ran in about 1/2 the time as Qt. Then I ported Imlib's
+ * C algorithm and it ran at about the same speed as my MMX optimized one...
+ * Finally I ported Imlib's MMX version and it ran in less than half the
+ * time as my MMX algorithm, (taking only a quarter of the time Qt does).
+ * After further optimization it seems to run at around 1/6th.
+ *
+ * Changes include formatting, namespaces and other C++'ings, removal of old
+ * #ifdef'ed code, and removal of unneeded border calculation code.
+ *
+ * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code
+ * is by Willem Monsuwe <willem@stack.nl>. All other modifications are
+ * (C) Daniel M. Duley.
+ */
+
+
+namespace QImageScale {
+ struct QImageScaleInfo {
+ int *xpoints;
+ unsigned int **ypoints;
+ int *xapoints, *yapoints;
+ int xup_yup;
+ };
+
+ unsigned int** qimageCalcYPoints(unsigned int *src, int sw, int sh,
+ int dh);
+ int* qimageCalcXPoints(int sw, int dw);
+ int* qimageCalcApoints(int s, int d, int up);
+ QImageScaleInfo* qimageFreeScaleInfo(QImageScaleInfo *isi);
+ QImageScaleInfo *qimageCalcScaleInfo(const QImage &img, int sw, int sh,
+ int dw, int dh, char aa);
+}
+
+using namespace QImageScale;
+
+//
+// Code ported from Imlib...
+//
+
+// FIXME: replace with qRed, etc... These work on pointers to pixels, not
+// pixel values
+#define A_VAL(p) (qAlpha(*p))
+#define R_VAL(p) (qRed(*p))
+#define G_VAL(p) (qGreen(*p))
+#define B_VAL(p) (qBlue(*p))
+
+#define INV_XAP (256 - xapoints[x])
+#define XAP (xapoints[x])
+#define INV_YAP (256 - yapoints[dyy + y])
+#define YAP (yapoints[dyy + y])
+
+unsigned int** QImageScale::qimageCalcYPoints(unsigned int *src,
+ int sw, int sh, int dh)
+{
+ unsigned int **p;
+ int i, j = 0;
+ int val, inc, rv = 0;
+
+ if(dh < 0){
+ dh = -dh;
+ rv = 1;
+ }
+ p = new unsigned int* [dh+1];
+
+ int up = qAbs(dh) >= sh;
+ val = up ? 0x8000 * sh / dh - 0x8000 : 0;
+ inc = (sh << 16) / dh;
+ for(i = 0; i < dh; i++){
+ p[j++] = src + qMax(0, val >> 16) * sw;
+ val += inc;
+ }
+ if(rv){
+ for(i = dh / 2; --i >= 0; ){
+ unsigned int *tmp = p[i];
+ p[i] = p[dh - i - 1];
+ p[dh - i - 1] = tmp;
+ }
+ }
+ return(p);
+}
+
+int* QImageScale::qimageCalcXPoints(int sw, int dw)
+{
+ int *p, i, j = 0;
+ int val, inc, rv = 0;
+
+ if(dw < 0){
+ dw = -dw;
+ rv = 1;
+ }
+ p = new int[dw+1];
+
+ int up = qAbs(dw) >= sw;
+ val = up ? 0x8000 * sw / dw - 0x8000 : 0;
+ inc = (sw << 16) / dw;
+ for(i = 0; i < dw; i++){
+ p[j++] = qMax(0, val >> 16);
+ val += inc;
+ }
+
+ if(rv){
+ for(i = dw / 2; --i >= 0; ){
+ int tmp = p[i];
+ p[i] = p[dw - i - 1];
+ p[dw - i - 1] = tmp;
+ }
+ }
+ return(p);
+}
+
+int* QImageScale::qimageCalcApoints(int s, int d, int up)
+{
+ int *p, i, j = 0, rv = 0;
+
+ if(d < 0){
+ rv = 1;
+ d = -d;
+ }
+ p = new int[d];
+
+ /* scaling up */
+ if(up){
+ int val, inc;
+
+ val = 0x8000 * s / d - 0x8000;
+ inc = (s << 16) / d;
+ for(i = 0; i < d; i++){
+ int pos = val >> 16;
+ if (pos < 0)
+ p[j++] = 0;
+ else if (pos >= (s - 1))
+ p[j++] = 0;
+ else
+ p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00);
+ val += inc;
+ }
+ }
+ /* scaling down */
+ else{
+ int val, inc, ap, Cp;
+ val = 0;
+ inc = (s << 16) / d;
+ Cp = ((d << 14) / s) + 1;
+ for(i = 0; i < d; i++){
+ ap = ((0x100 - ((val >> 8) & 0xff)) * Cp) >> 8;
+ p[j] = ap | (Cp << 16);
+ j++;
+ val += inc;
+ }
+ }
+ if(rv){
+ int tmp;
+ for(i = d / 2; --i >= 0; ){
+ tmp = p[i];
+ p[i] = p[d - i - 1];
+ p[d - i - 1] = tmp;
+ }
+ }
+ return(p);
+}
+
+QImageScaleInfo* QImageScale::qimageFreeScaleInfo(QImageScaleInfo *isi)
+{
+ if(isi){
+ delete[] isi->xpoints;
+ delete[] isi->ypoints;
+ delete[] isi->xapoints;
+ delete[] isi->yapoints;
+ delete isi;
+ }
+ return 0;
+}
+
+QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img,
+ int sw, int sh,
+ int dw, int dh, char aa)
+{
+ QImageScaleInfo *isi;
+ int scw, sch;
+
+ scw = dw * qlonglong(img.width()) / sw;
+ sch = dh * qlonglong(img.height()) / sh;
+
+ isi = new QImageScaleInfo;
+ if(!isi)
+ return 0;
+ memset(isi, 0, sizeof(QImageScaleInfo));
+
+ isi->xup_yup = (qAbs(dw) >= sw) + ((qAbs(dh) >= sh) << 1);
+
+ isi->xpoints = qimageCalcXPoints(img.width(), scw);
+ if(!isi->xpoints)
+ return(qimageFreeScaleInfo(isi));
+ isi->ypoints = qimageCalcYPoints((unsigned int *)img.scanLine(0),
+ img.bytesPerLine() / 4, img.height(), sch);
+ if (!isi->ypoints)
+ return(qimageFreeScaleInfo(isi));
+ if(aa) {
+ isi->xapoints = qimageCalcApoints(img.width(), scw, isi->xup_yup & 1);
+ if(!isi->xapoints)
+ return(qimageFreeScaleInfo(isi));
+ isi->yapoints = qimageCalcApoints(img.height(), sch, isi->xup_yup & 2);
+ if(!isi->yapoints)
+ return(qimageFreeScaleInfo(isi));
+ }
+ return(isi);
+}
+
+/* FIXME: NEED to optimize ScaleAARGBA - currently its "ok" but needs work*/
+
+/* scale by area sampling */
+static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest,
+ int dxx, int dyy, int dx, int dy, int dw,
+ int dh, int dow, int sow)
+{
+ unsigned int *sptr, *dptr;
+ int x, y, end;
+ unsigned int **ypoints = isi->ypoints;
+ int *xpoints = isi->xpoints;
+ int *xapoints = isi->xapoints;
+ int *yapoints = isi->yapoints;
+
+ end = dxx + dw;
+ /* scaling up both ways */
+ if(isi->xup_yup == 3){
+ /* go through every scanline in the output buffer */
+ for(y = 0; y < dh; y++){
+ /* calculate the source line we'll scan from */
+ dptr = dest + dx + ((y + dy) * dow);
+ sptr = ypoints[dyy + y];
+ if(YAP > 0){
+ for(x = dxx; x < end; x++){
+ int r, g, b, a;
+ int rr, gg, bb, aa;
+ unsigned int *pix;
+
+ if(XAP > 0){
+ pix = ypoints[dyy + y] + xpoints[x];
+ r = R_VAL(pix) * INV_XAP;
+ g = G_VAL(pix) * INV_XAP;
+ b = B_VAL(pix) * INV_XAP;
+ a = A_VAL(pix) * INV_XAP;
+ pix++;
+ r += R_VAL(pix) * XAP;
+ g += G_VAL(pix) * XAP;
+ b += B_VAL(pix) * XAP;
+ a += A_VAL(pix) * XAP;
+ pix += sow;
+ rr = R_VAL(pix) * XAP;
+ gg = G_VAL(pix) * XAP;
+ bb = B_VAL(pix) * XAP;
+ aa = A_VAL(pix) * XAP;
+ pix--;
+ rr += R_VAL(pix) * INV_XAP;
+ gg += G_VAL(pix) * INV_XAP;
+ bb += B_VAL(pix) * INV_XAP;
+ aa += A_VAL(pix) * INV_XAP;
+ r = ((rr * YAP) + (r * INV_YAP)) >> 16;
+ g = ((gg * YAP) + (g * INV_YAP)) >> 16;
+ b = ((bb * YAP) + (b * INV_YAP)) >> 16;
+ a = ((aa * YAP) + (a * INV_YAP)) >> 16;
+ *dptr++ = qRgba(r, g, b, a);
+ }
+ else{
+ pix = ypoints[dyy + y] + xpoints[x];
+ r = R_VAL(pix) * INV_YAP;
+ g = G_VAL(pix) * INV_YAP;
+ b = B_VAL(pix) * INV_YAP;
+ a = A_VAL(pix) * INV_YAP;
+ pix += sow;
+ r += R_VAL(pix) * YAP;
+ g += G_VAL(pix) * YAP;
+ b += B_VAL(pix) * YAP;
+ a += A_VAL(pix) * YAP;
+ r >>= 8;
+ g >>= 8;
+ b >>= 8;
+ a >>= 8;
+ *dptr++ = qRgba(r, g, b, a);
+ }
+ }
+ }
+ else{
+ for(x = dxx; x < end; x++){
+ int r, g, b, a;
+ unsigned int *pix;
+
+ if(XAP > 0){
+ pix = ypoints[dyy + y] + xpoints[x];
+ r = R_VAL(pix) * INV_XAP;
+ g = G_VAL(pix) * INV_XAP;
+ b = B_VAL(pix) * INV_XAP;
+ a = A_VAL(pix) * INV_XAP;
+ pix++;
+ r += R_VAL(pix) * XAP;
+ g += G_VAL(pix) * XAP;
+ b += B_VAL(pix) * XAP;
+ a += A_VAL(pix) * XAP;
+ r >>= 8;
+ g >>= 8;
+ b >>= 8;
+ a >>= 8;
+ *dptr++ = qRgba(r, g, b, a);
+ }
+ else
+ *dptr++ = sptr[xpoints[x] ];
+ }
+ }
+ }
+ }
+ /* if we're scaling down vertically */
+ else if(isi->xup_yup == 1){
+ /*\ 'Correct' version, with math units prepared for MMXification \*/
+ int Cy, j;
+ unsigned int *pix;
+ int r, g, b, a, rr, gg, bb, aa;
+ int yap;
+
+ /* go through every scanline in the output buffer */
+ for(y = 0; y < dh; y++){
+ Cy = YAP >> 16;
+ yap = YAP & 0xffff;
+
+ dptr = dest + dx + ((y + dy) * dow);
+ for(x = dxx; x < end; x++){
+ pix = ypoints[dyy + y] + xpoints[x];
+ r = R_VAL(pix) * yap;
+ g = G_VAL(pix) * yap;
+ b = B_VAL(pix) * yap;
+ a = A_VAL(pix) * yap;
+ for(j = (1 << 14) - yap; j > Cy; j -= Cy){
+ pix += sow;
+ r += R_VAL(pix) * Cy;
+ g += G_VAL(pix) * Cy;
+ b += B_VAL(pix) * Cy;
+ a += A_VAL(pix) * Cy;
+ }
+ if(j > 0){
+ pix += sow;
+ r += R_VAL(pix) * j;
+ g += G_VAL(pix) * j;
+ b += B_VAL(pix) * j;
+ a += A_VAL(pix) * j;
+ }
+ if(XAP > 0){
+ pix = ypoints[dyy + y] + xpoints[x] + 1;
+ rr = R_VAL(pix) * yap;
+ gg = G_VAL(pix) * yap;
+ bb = B_VAL(pix) * yap;
+ aa = A_VAL(pix) * yap;
+ for(j = (1 << 14) - yap; j > Cy; j -= Cy){
+ pix += sow;
+ rr += R_VAL(pix) * Cy;
+ gg += G_VAL(pix) * Cy;
+ bb += B_VAL(pix) * Cy;
+ aa += A_VAL(pix) * Cy;
+ }
+ if(j > 0){
+ pix += sow;
+ rr += R_VAL(pix) * j;
+ gg += G_VAL(pix) * j;
+ bb += B_VAL(pix) * j;
+ aa += A_VAL(pix) * j;
+ }
+ r = r * INV_XAP;
+ g = g * INV_XAP;
+ b = b * INV_XAP;
+ a = a * INV_XAP;
+ r = (r + ((rr * XAP))) >> 12;
+ g = (g + ((gg * XAP))) >> 12;
+ b = (b + ((bb * XAP))) >> 12;
+ a = (a + ((aa * XAP))) >> 12;
+ }
+ else{
+ r >>= 4;
+ g >>= 4;
+ b >>= 4;
+ a >>= 4;
+ }
+ *dptr = qRgba(r >> 10, g >> 10, b >> 10, a >> 10);
+ dptr++;
+ }
+ }
+ }
+ /* if we're scaling down horizontally */
+ else if(isi->xup_yup == 2){
+ /*\ 'Correct' version, with math units prepared for MMXification \*/
+ int Cx, j;
+ unsigned int *pix;
+ int r, g, b, a, rr, gg, bb, aa;
+ int xap;
+
+ /* go through every scanline in the output buffer */
+ for(y = 0; y < dh; y++){
+ dptr = dest + dx + ((y + dy) * dow);
+ for(x = dxx; x < end; x++){
+ Cx = XAP >> 16;
+ xap = XAP & 0xffff;
+
+ pix = ypoints[dyy + y] + xpoints[x];
+ r = R_VAL(pix) * xap;
+ g = G_VAL(pix) * xap;
+ b = B_VAL(pix) * xap;
+ a = A_VAL(pix) * xap;
+ for(j = (1 << 14) - xap; j > Cx; j -= Cx){
+ pix++;
+ r += R_VAL(pix) * Cx;
+ g += G_VAL(pix) * Cx;
+ b += B_VAL(pix) * Cx;
+ a += A_VAL(pix) * Cx;
+ }
+ if(j > 0){
+ pix++;
+ r += R_VAL(pix) * j;
+ g += G_VAL(pix) * j;
+ b += B_VAL(pix) * j;
+ a += A_VAL(pix) * j;
+ }
+ if(YAP > 0){
+ pix = ypoints[dyy + y] + xpoints[x] + sow;
+ rr = R_VAL(pix) * xap;
+ gg = G_VAL(pix) * xap;
+ bb = B_VAL(pix) * xap;
+ aa = A_VAL(pix) * xap;
+ for(j = (1 << 14) - xap; j > Cx; j -= Cx){
+ pix++;
+ rr += R_VAL(pix) * Cx;
+ gg += G_VAL(pix) * Cx;
+ bb += B_VAL(pix) * Cx;
+ aa += A_VAL(pix) * Cx;
+ }
+ if(j > 0){
+ pix++;
+ rr += R_VAL(pix) * j;
+ gg += G_VAL(pix) * j;
+ bb += B_VAL(pix) * j;
+ aa += A_VAL(pix) * j;
+ }
+ r = r * INV_YAP;
+ g = g * INV_YAP;
+ b = b * INV_YAP;
+ a = a * INV_YAP;
+ r = (r + ((rr * YAP))) >> 12;
+ g = (g + ((gg * YAP))) >> 12;
+ b = (b + ((bb * YAP))) >> 12;
+ a = (a + ((aa * YAP))) >> 12;
+ }
+ else{
+ r >>= 4;
+ g >>= 4;
+ b >>= 4;
+ a >>= 4;
+ }
+ *dptr = qRgba(r >> 10, g >> 10, b >> 10, a >> 10);
+ dptr++;
+ }
+ }
+ }
+ /* if we're scaling down horizontally & vertically */
+ else{
+ /*\ 'Correct' version, with math units prepared for MMXification:
+ |*| The operation 'b = (b * c) >> 16' translates to pmulhw,
+ |*| so the operation 'b = (b * c) >> d' would translate to
+ |*| psllw (16 - d), %mmb; pmulh %mmc, %mmb
+ \*/
+ int Cx, Cy, i, j;
+ unsigned int *pix;
+ int a, r, g, b, ax, rx, gx, bx;
+ int xap, yap;
+
+ for(y = 0; y < dh; y++){
+ Cy = YAP >> 16;
+ yap = YAP & 0xffff;
+
+ dptr = dest + dx + ((y + dy) * dow);
+ for(x = dxx; x < end; x++){
+ Cx = XAP >> 16;
+ xap = XAP & 0xffff;
+
+ sptr = ypoints[dyy + y] + xpoints[x];
+ pix = sptr;
+ sptr += sow;
+ rx = R_VAL(pix) * xap;
+ gx = G_VAL(pix) * xap;
+ bx = B_VAL(pix) * xap;
+ ax = A_VAL(pix) * xap;
+
+ pix++;
+ for(i = (1 << 14) - xap; i > Cx; i -= Cx){
+ rx += R_VAL(pix) * Cx;
+ gx += G_VAL(pix) * Cx;
+ bx += B_VAL(pix) * Cx;
+ ax += A_VAL(pix) * Cx;
+ pix++;
+ }
+ if(i > 0){
+ rx += R_VAL(pix) * i;
+ gx += G_VAL(pix) * i;
+ bx += B_VAL(pix) * i;
+ ax += A_VAL(pix) * i;
+ }
+
+ r = (rx >> 5) * yap;
+ g = (gx >> 5) * yap;
+ b = (bx >> 5) * yap;
+ a = (ax >> 5) * yap;
+
+ for(j = (1 << 14) - yap; j > Cy; j -= Cy){
+ pix = sptr;
+ sptr += sow;
+ rx = R_VAL(pix) * xap;
+ gx = G_VAL(pix) * xap;
+ bx = B_VAL(pix) * xap;
+ ax = A_VAL(pix) * xap;
+ pix++;
+ for(i = (1 << 14) - xap; i > Cx; i -= Cx){
+ rx += R_VAL(pix) * Cx;
+ gx += G_VAL(pix) * Cx;
+ bx += B_VAL(pix) * Cx;
+ ax += A_VAL(pix) * Cx;
+ pix++;
+ }
+ if(i > 0){
+ rx += R_VAL(pix) * i;
+ gx += G_VAL(pix) * i;
+ bx += B_VAL(pix) * i;
+ ax += A_VAL(pix) * i;
+ }
+
+ r += (rx >> 5) * Cy;
+ g += (gx >> 5) * Cy;
+ b += (bx >> 5) * Cy;
+ a += (ax >> 5) * Cy;
+ }
+ if(j > 0){
+ pix = sptr;
+ sptr += sow;
+ rx = R_VAL(pix) * xap;
+ gx = G_VAL(pix) * xap;
+ bx = B_VAL(pix) * xap;
+ ax = A_VAL(pix) * xap;
+ pix++;
+ for(i = (1 << 14) - xap; i > Cx; i -= Cx){
+ rx += R_VAL(pix) * Cx;
+ gx += G_VAL(pix) * Cx;
+ bx += B_VAL(pix) * Cx;
+ ax += A_VAL(pix) * Cx;
+ pix++;
+ }
+ if(i > 0){
+ rx += R_VAL(pix) * i;
+ gx += G_VAL(pix) * i;
+ bx += B_VAL(pix) * i;
+ ax += A_VAL(pix) * i;
+ }
+
+ r += (rx >> 5) * j;
+ g += (gx >> 5) * j;
+ b += (bx >> 5) * j;
+ a += (ax >> 5) * j;
+ }
+
+ *dptr = qRgba(r >> 23, g >> 23, b >> 23, a >> 23);
+ dptr++;
+ }
+ }
+ }
+}
+
+/* scale by area sampling - IGNORE the ALPHA byte*/
+static void qt_qimageScaleAARGB(QImageScaleInfo *isi, unsigned int *dest,
+ int dxx, int dyy, int dx, int dy, int dw,
+ int dh, int dow, int sow)
+{
+ unsigned int *sptr, *dptr;
+ int x, y, end;
+ unsigned int **ypoints = isi->ypoints;
+ int *xpoints = isi->xpoints;
+ int *xapoints = isi->xapoints;
+ int *yapoints = isi->yapoints;
+
+ end = dxx + dw;
+ /* scaling up both ways */
+ if(isi->xup_yup == 3){
+ /* go through every scanline in the output buffer */
+ for(y = 0; y < dh; y++){
+ /* calculate the source line we'll scan from */
+ dptr = dest + dx + ((y + dy) * dow);
+ sptr = ypoints[dyy + y];
+ if(YAP > 0){
+ for(x = dxx; x < end; x++){
+ int r = 0, g = 0, b = 0;
+ int rr = 0, gg = 0, bb = 0;
+ unsigned int *pix;
+
+ if(XAP > 0){
+ pix = ypoints[dyy + y] + xpoints[x];
+ r = R_VAL(pix) * INV_XAP;
+ g = G_VAL(pix) * INV_XAP;
+ b = B_VAL(pix) * INV_XAP;
+ pix++;
+ r += R_VAL(pix) * XAP;
+ g += G_VAL(pix) * XAP;
+ b += B_VAL(pix) * XAP;
+ pix += sow;
+ rr = R_VAL(pix) * XAP;
+ gg = G_VAL(pix) * XAP;
+ bb = B_VAL(pix) * XAP;
+ pix --;
+ rr += R_VAL(pix) * INV_XAP;
+ gg += G_VAL(pix) * INV_XAP;
+ bb += B_VAL(pix) * INV_XAP;
+ r = ((rr * YAP) + (r * INV_YAP)) >> 16;
+ g = ((gg * YAP) + (g * INV_YAP)) >> 16;
+ b = ((bb * YAP) + (b * INV_YAP)) >> 16;
+ *dptr++ = qRgba(r, g, b, 0xff);
+ }
+ else{
+ pix = ypoints[dyy + y] + xpoints[x];
+ r = R_VAL(pix) * INV_YAP;
+ g = G_VAL(pix) * INV_YAP;
+ b = B_VAL(pix) * INV_YAP;
+ pix += sow;
+ r += R_VAL(pix) * YAP;
+ g += G_VAL(pix) * YAP;
+ b += B_VAL(pix) * YAP;
+ r >>= 8;
+ g >>= 8;
+ b >>= 8;
+ *dptr++ = qRgba(r, g, b, 0xff);
+ }
+ }
+ }
+ else{
+ for(x = dxx; x < end; x++){
+ int r = 0, g = 0, b = 0;
+ unsigned int *pix;
+
+ if(XAP > 0){
+ pix = ypoints[dyy + y] + xpoints[x];
+ r = R_VAL(pix) * INV_XAP;
+ g = G_VAL(pix) * INV_XAP;
+ b = B_VAL(pix) * INV_XAP;
+ pix++;
+ r += R_VAL(pix) * XAP;
+ g += G_VAL(pix) * XAP;
+ b += B_VAL(pix) * XAP;
+ r >>= 8;
+ g >>= 8;
+ b >>= 8;
+ *dptr++ = qRgba(r, g, b, 0xff);
+ }
+ else
+ *dptr++ = sptr[xpoints[x] ];
+ }
+ }
+ }
+ }
+ /* if we're scaling down vertically */
+ else if(isi->xup_yup == 1){
+ /*\ 'Correct' version, with math units prepared for MMXification \*/
+ int Cy, j;
+ unsigned int *pix;
+ int r, g, b, rr, gg, bb;
+ int yap;
+
+ /* go through every scanline in the output buffer */
+ for(y = 0; y < dh; y++){
+ Cy = YAP >> 16;
+ yap = YAP & 0xffff;
+
+ dptr = dest + dx + ((y + dy) * dow);
+ for(x = dxx; x < end; x++){
+ pix = ypoints[dyy + y] + xpoints[x];
+ r = R_VAL(pix) * yap;
+ g = G_VAL(pix) * yap;
+ b = B_VAL(pix) * yap;
+ pix += sow;
+ for(j = (1 << 14) - yap; j > Cy; j -= Cy){
+ r += R_VAL(pix) * Cy;
+ g += G_VAL(pix) * Cy;
+ b += B_VAL(pix) * Cy;
+ pix += sow;
+ }
+ if(j > 0){
+ r += R_VAL(pix) * j;
+ g += G_VAL(pix) * j;
+ b += B_VAL(pix) * j;
+ }
+ if(XAP > 0){
+ pix = ypoints[dyy + y] + xpoints[x] + 1;
+ rr = R_VAL(pix) * yap;
+ gg = G_VAL(pix) * yap;
+ bb = B_VAL(pix) * yap;
+ pix += sow;
+ for(j = (1 << 14) - yap; j > Cy; j -= Cy){
+ rr += R_VAL(pix) * Cy;
+ gg += G_VAL(pix) * Cy;
+ bb += B_VAL(pix) * Cy;
+ pix += sow;
+ }
+ if(j > 0){
+ rr += R_VAL(pix) * j;
+ gg += G_VAL(pix) * j;
+ bb += B_VAL(pix) * j;
+ }
+ r = r * INV_XAP;
+ g = g * INV_XAP;
+ b = b * INV_XAP;
+ r = (r + ((rr * XAP))) >> 12;
+ g = (g + ((gg * XAP))) >> 12;
+ b = (b + ((bb * XAP))) >> 12;
+ }
+ else{
+ r >>= 4;
+ g >>= 4;
+ b >>= 4;
+ }
+ *dptr = qRgba(r >> 10, g >> 10, b >> 10, 0xff);
+ dptr++;
+ }
+ }
+ }
+ /* if we're scaling down horizontally */
+ else if(isi->xup_yup == 2){
+ /*\ 'Correct' version, with math units prepared for MMXification \*/
+ int Cx, j;
+ unsigned int *pix;
+ int r, g, b, rr, gg, bb;
+ int xap;
+
+ /* go through every scanline in the output buffer */
+ for(y = 0; y < dh; y++){
+ dptr = dest + dx + ((y + dy) * dow);
+ for(x = dxx; x < end; x++){
+ Cx = XAP >> 16;
+ xap = XAP & 0xffff;
+
+ pix = ypoints[dyy + y] + xpoints[x];
+ r = R_VAL(pix) * xap;
+ g = G_VAL(pix) * xap;
+ b = B_VAL(pix) * xap;
+ pix++;
+ for(j = (1 << 14) - xap; j > Cx; j -= Cx){
+ r += R_VAL(pix) * Cx;
+ g += G_VAL(pix) * Cx;
+ b += B_VAL(pix) * Cx;
+ pix++;
+ }
+ if(j > 0){
+ r += R_VAL(pix) * j;
+ g += G_VAL(pix) * j;
+ b += B_VAL(pix) * j;
+ }
+ if(YAP > 0){
+ pix = ypoints[dyy + y] + xpoints[x] + sow;
+ rr = R_VAL(pix) * xap;
+ gg = G_VAL(pix) * xap;
+ bb = B_VAL(pix) * xap;
+ pix++;
+ for(j = (1 << 14) - xap; j > Cx; j -= Cx){
+ rr += R_VAL(pix) * Cx;
+ gg += G_VAL(pix) * Cx;
+ bb += B_VAL(pix) * Cx;
+ pix++;
+ }
+ if(j > 0){
+ rr += R_VAL(pix) * j;
+ gg += G_VAL(pix) * j;
+ bb += B_VAL(pix) * j;
+ }
+ r = r * INV_YAP;
+ g = g * INV_YAP;
+ b = b * INV_YAP;
+ r = (r + ((rr * YAP))) >> 12;
+ g = (g + ((gg * YAP))) >> 12;
+ b = (b + ((bb * YAP))) >> 12;
+ }
+ else{
+ r >>= 4;
+ g >>= 4;
+ b >>= 4;
+ }
+ *dptr = qRgba(r >> 10, g >> 10, b >> 10, 0xff);
+ dptr++;
+ }
+ }
+ }
+ /* fully optimized (i think) - onyl change of algorithm can help */
+ /* if we're scaling down horizontally & vertically */
+ else{
+ /*\ 'Correct' version, with math units prepared for MMXification \*/
+ int Cx, Cy, i, j;
+ unsigned int *pix;
+ int r, g, b, rx, gx, bx;
+ int xap, yap;
+
+ for(y = 0; y < dh; y++){
+ Cy = YAP >> 16;
+ yap = YAP & 0xffff;
+
+ dptr = dest + dx + ((y + dy) * dow);
+ for(x = dxx; x < end; x++){
+ Cx = XAP >> 16;
+ xap = XAP & 0xffff;
+
+ sptr = ypoints[dyy + y] + xpoints[x];
+ pix = sptr;
+ sptr += sow;
+ rx = R_VAL(pix) * xap;
+ gx = G_VAL(pix) * xap;
+ bx = B_VAL(pix) * xap;
+ pix++;
+ for(i = (1 << 14) - xap; i > Cx; i -= Cx){
+ rx += R_VAL(pix) * Cx;
+ gx += G_VAL(pix) * Cx;
+ bx += B_VAL(pix) * Cx;
+ pix++;
+ }
+ if(i > 0){
+ rx += R_VAL(pix) * i;
+ gx += G_VAL(pix) * i;
+ bx += B_VAL(pix) * i;
+ }
+
+ r = (rx >> 5) * yap;
+ g = (gx >> 5) * yap;
+ b = (bx >> 5) * yap;
+
+ for(j = (1 << 14) - yap; j > Cy; j -= Cy){
+ pix = sptr;
+ sptr += sow;
+ rx = R_VAL(pix) * xap;
+ gx = G_VAL(pix) * xap;
+ bx = B_VAL(pix) * xap;
+ pix++;
+ for(i = (1 << 14) - xap; i > Cx; i -= Cx){
+ rx += R_VAL(pix) * Cx;
+ gx += G_VAL(pix) * Cx;
+ bx += B_VAL(pix) * Cx;
+ pix++;
+ }
+ if(i > 0){
+ rx += R_VAL(pix) * i;
+ gx += G_VAL(pix) * i;
+ bx += B_VAL(pix) * i;
+ }
+
+ r += (rx >> 5) * Cy;
+ g += (gx >> 5) * Cy;
+ b += (bx >> 5) * Cy;
+ }
+ if(j > 0){
+ pix = sptr;
+ sptr += sow;
+ rx = R_VAL(pix) * xap;
+ gx = G_VAL(pix) * xap;
+ bx = B_VAL(pix) * xap;
+ pix++;
+ for(i = (1 << 14) - xap; i > Cx; i -= Cx){
+ rx += R_VAL(pix) * Cx;
+ gx += G_VAL(pix) * Cx;
+ bx += B_VAL(pix) * Cx;
+ pix++;
+ }
+ if(i > 0){
+ rx += R_VAL(pix) * i;
+ gx += G_VAL(pix) * i;
+ bx += B_VAL(pix) * i;
+ }
+
+ r += (rx >> 5) * j;
+ g += (gx >> 5) * j;
+ b += (bx >> 5) * j;
+ }
+
+ *dptr = qRgb(r >> 23, g >> 23, b >> 23);
+ dptr++;
+ }
+ }
+ }
+}
+
+#if 0
+static void qt_qimageScaleAARGBASetup(QImageScaleInfo *isi, unsigned int *dest,
+ int dxx, int dyy, int dx, int dy, int dw,
+ int dh, int dow, int sow)
+{
+ qInitDrawhelperAsm();
+ qt_qimageScaleAARGBA(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow);
+}
+
+static void qt_qimageScaleAARGBSetup(QImageScaleInfo *isi, unsigned int *dest,
+ int dxx, int dyy, int dx, int dy, int dw,
+ int dh, int dow, int sow)
+{
+ qInitDrawhelperAsm();
+ qt_qimageScaleAARGB(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow);
+}
+#endif
+
+QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
+{
+ QImage buffer;
+ if (src.isNull() || dw <= 0 || dh <= 0)
+ return buffer;
+
+ int w = src.width();
+ int h = src.height();
+ QImageScaleInfo *scaleinfo =
+ qimageCalcScaleInfo(src, w, h, dw, dh, true);
+ if (!scaleinfo)
+ return buffer;
+
+ buffer = QImage(dw, dh, src.format());
+ if (buffer.isNull()) {
+ qWarning("QImage: out of memory, returning null");
+ qimageFreeScaleInfo(scaleinfo);
+ return QImage();
+ }
+
+ if (src.format() == QImage::Format_ARGB32_Premultiplied)
+ qt_qimageScaleArgb(scaleinfo, (unsigned int *)buffer.scanLine(0),
+ 0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4);
+ else
+ qt_qimageScaleRgb(scaleinfo, (unsigned int *)buffer.scanLine(0),
+ 0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4);
+
+ qimageFreeScaleInfo(scaleinfo);
+ return buffer;
+}
+
+QT_END_NAMESPACE