src/gui/painting/qimagescale.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/painting/qimagescale.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1031 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 optimise 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