src/gui/painting/qdrawhelper.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <private/qdrawhelper_p.h>
       
    43 #include <private/qpaintengine_raster_p.h>
       
    44 #include <private/qpainter_p.h>
       
    45 #include <private/qdrawhelper_x86_p.h>
       
    46 #include <private/qdrawhelper_armv6_p.h>
       
    47 #include <private/qmath_p.h>
       
    48 #include <qmath.h>
       
    49 
       
    50 QT_BEGIN_NAMESPACE
       
    51 
       
    52 
       
    53 #define MASK(src, a) src = BYTE_MUL(src, a)
       
    54 
       
    55 #if defined(Q_OS_IRIX) && defined(Q_CC_GNU) && __GNUC__ == 3 && __GNUC__ < 4 && QT_POINTER_SIZE == 8
       
    56 #define Q_IRIX_GCC3_3_WORKAROUND
       
    57 //
       
    58 // work around http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14484
       
    59 //
       
    60 static uint gccBug(uint value) __attribute__((noinline));
       
    61 static uint gccBug(uint value)
       
    62 {
       
    63     return value;
       
    64 }
       
    65 #endif
       
    66 
       
    67 /*
       
    68   constants and structures
       
    69 */
       
    70 
       
    71 static const int fixed_scale = 1 << 16;
       
    72 static const int half_point = 1 << 15;
       
    73 static const int buffer_size = 2048;
       
    74 
       
    75 struct LinearGradientValues
       
    76 {
       
    77     qreal dx;
       
    78     qreal dy;
       
    79     qreal l;
       
    80     qreal off;
       
    81 };
       
    82 
       
    83 struct RadialGradientValues
       
    84 {
       
    85     qreal dx;
       
    86     qreal dy;
       
    87     qreal a;
       
    88 };
       
    89 
       
    90 struct Operator;
       
    91 typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
       
    92 typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length);
       
    93 typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
       
    94 
       
    95 
       
    96 struct Operator
       
    97 {
       
    98     QPainter::CompositionMode mode;
       
    99     DestFetchProc dest_fetch;
       
   100     DestStoreProc dest_store;
       
   101     SourceFetchProc src_fetch;
       
   102     CompositionFunctionSolid funcSolid;
       
   103     CompositionFunction func;
       
   104     union {
       
   105         LinearGradientValues linear;
       
   106         RadialGradientValues radial;
       
   107 //        TextureValues texture;
       
   108     };
       
   109 };
       
   110 
       
   111 /*
       
   112   Destination fetch. This is simple as we don't have to do bounds checks or
       
   113   transformations
       
   114 */
       
   115 
       
   116 static uint * QT_FASTCALL destFetchMono(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
       
   117 {
       
   118     uchar *data = (uchar *)rasterBuffer->scanLine(y);
       
   119     uint *start = buffer;
       
   120     const uint *end = buffer + length;
       
   121     while (buffer < end) {
       
   122         *buffer = data[x>>3] & (0x80 >> (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
       
   123         ++buffer;
       
   124         ++x;
       
   125     }
       
   126     return start;
       
   127 }
       
   128 
       
   129 static uint * QT_FASTCALL destFetchMonoLsb(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
       
   130 {
       
   131     uchar *data = (uchar *)rasterBuffer->scanLine(y);
       
   132     uint *start = buffer;
       
   133     const uint *end = buffer + length;
       
   134     while (buffer < end) {
       
   135         *buffer = data[x>>3] & (0x1 << (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
       
   136         ++buffer;
       
   137         ++x;
       
   138     }
       
   139     return start;
       
   140 }
       
   141 
       
   142 static uint * QT_FASTCALL destFetchARGB32(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
       
   143 {
       
   144     const uint *data = (const uint *)rasterBuffer->scanLine(y) + x;
       
   145     for (int i = 0; i < length; ++i)
       
   146         buffer[i] = PREMUL(data[i]);
       
   147     return buffer;
       
   148 }
       
   149 
       
   150 static uint * QT_FASTCALL destFetchARGB32P(uint *, QRasterBuffer *rasterBuffer, int x, int y, int)
       
   151 {
       
   152     return (uint *)rasterBuffer->scanLine(y) + x;
       
   153 }
       
   154 
       
   155 static uint * QT_FASTCALL destFetchRGB16(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
       
   156 {
       
   157     const ushort *data = (const ushort *)rasterBuffer->scanLine(y) + x;
       
   158     for (int i = 0; i < length; ++i)
       
   159         buffer[i] = qConvertRgb16To32(data[i]);
       
   160     return buffer;
       
   161 }
       
   162 
       
   163 template <class DST>
       
   164 Q_STATIC_TEMPLATE_FUNCTION uint * QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer,
       
   165                                     int x, int y, int length)
       
   166 {
       
   167     const DST *src = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
       
   168     quint32 *dest = reinterpret_cast<quint32*>(buffer);
       
   169     while (length--)
       
   170         *dest++ = *src++;
       
   171     return buffer;
       
   172 }
       
   173 
       
   174 # define SPANFUNC_POINTER_DESTFETCH(Arg) destFetch<Arg>
       
   175 
       
   176 static const DestFetchProc destFetchProc[QImage::NImageFormats] =
       
   177 {
       
   178     0, // Format_Invalid
       
   179     destFetchMono, // Format_Mono,
       
   180     destFetchMonoLsb, // Format_MonoLSB
       
   181     0, // Format_Indexed8
       
   182     destFetchARGB32P, // Format_RGB32
       
   183     destFetchARGB32, // Format_ARGB32,
       
   184     destFetchARGB32P, // Format_ARGB32_Premultiplied
       
   185     destFetchRGB16,   // Format_RGB16
       
   186     SPANFUNC_POINTER_DESTFETCH(qargb8565), // Format_ARGB8565_Premultiplied
       
   187     SPANFUNC_POINTER_DESTFETCH(qrgb666),   // Format_RGB666
       
   188     SPANFUNC_POINTER_DESTFETCH(qargb6666), // Format_ARGB6666_Premultiplied
       
   189     SPANFUNC_POINTER_DESTFETCH(qrgb555),   // Format_RGB555
       
   190     SPANFUNC_POINTER_DESTFETCH(qargb8555), // Format_ARGB8555_Premultiplied
       
   191     SPANFUNC_POINTER_DESTFETCH(qrgb888),   // Format_RGB888
       
   192     SPANFUNC_POINTER_DESTFETCH(qrgb444),   // Format_RGB444
       
   193     SPANFUNC_POINTER_DESTFETCH(qargb4444)  // Format_ARGB4444_Premultiplied
       
   194 };
       
   195 
       
   196 /*
       
   197    Returns the color in the mono destination color table
       
   198    that is the "nearest" to /color/.
       
   199 */
       
   200 static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
       
   201 {
       
   202     QRgb color_0 = PREMUL(rbuf->destColor0);
       
   203     QRgb color_1 = PREMUL(rbuf->destColor1);
       
   204     color = PREMUL(color);
       
   205 
       
   206     int r = qRed(color);
       
   207     int g = qGreen(color);
       
   208     int b = qBlue(color);
       
   209     int rx, gx, bx;
       
   210     int dist_0, dist_1;
       
   211 
       
   212     rx = r - qRed(color_0);
       
   213     gx = g - qGreen(color_0);
       
   214     bx = b - qBlue(color_0);
       
   215     dist_0 = rx*rx + gx*gx + bx*bx;
       
   216 
       
   217     rx = r - qRed(color_1);
       
   218     gx = g - qGreen(color_1);
       
   219     bx = b - qBlue(color_1);
       
   220     dist_1 = rx*rx + gx*gx + bx*bx;
       
   221 
       
   222     if (dist_0 < dist_1)
       
   223         return color_0;
       
   224     return color_1;
       
   225 }
       
   226 
       
   227 /*
       
   228   Destination store.
       
   229 */
       
   230 
       
   231 static void QT_FASTCALL destStoreMono(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
       
   232 {
       
   233     uchar *data = (uchar *)rasterBuffer->scanLine(y);
       
   234     if (rasterBuffer->monoDestinationWithClut) {
       
   235         for (int i = 0; i < length; ++i) {
       
   236             if (buffer[i] == rasterBuffer->destColor0) {
       
   237                 data[x >> 3] &= ~(0x80 >> (x & 7));
       
   238             } else if (buffer[i] == rasterBuffer->destColor1) {
       
   239                 data[x >> 3] |= 0x80 >> (x & 7);
       
   240             } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
       
   241                 data[x >> 3] &= ~(0x80 >> (x & 7));
       
   242             } else {
       
   243                 data[x >> 3] |= 0x80 >> (x & 7);
       
   244             }
       
   245             ++x;
       
   246         }
       
   247     } else {
       
   248         for (int i = 0; i < length; ++i) {
       
   249             if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
       
   250                 data[x >> 3] |= 0x80 >> (x & 7);
       
   251             else
       
   252                 data[x >> 3] &= ~(0x80 >> (x & 7));
       
   253             ++x;
       
   254         }
       
   255     }
       
   256 }
       
   257 
       
   258 static void QT_FASTCALL destStoreMonoLsb(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
       
   259 {
       
   260     uchar *data = (uchar *)rasterBuffer->scanLine(y);
       
   261     if (rasterBuffer->monoDestinationWithClut) {
       
   262         for (int i = 0; i < length; ++i) {
       
   263             if (buffer[i] == rasterBuffer->destColor0) {
       
   264                 data[x >> 3] &= ~(1 << (x & 7));
       
   265             } else if (buffer[i] == rasterBuffer->destColor1) {
       
   266                 data[x >> 3] |= 1 << (x & 7);
       
   267             } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
       
   268                 data[x >> 3] &= ~(1 << (x & 7));
       
   269             } else {
       
   270                 data[x >> 3] |= 1 << (x & 7);
       
   271             }
       
   272             ++x;
       
   273         }
       
   274     } else {
       
   275         for (int i = 0; i < length; ++i) {
       
   276             if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
       
   277                 data[x >> 3] |= 1 << (x & 7);
       
   278             else
       
   279                 data[x >> 3] &= ~(1 << (x & 7));
       
   280             ++x;
       
   281         }
       
   282     }
       
   283 }
       
   284 
       
   285 static void QT_FASTCALL destStoreARGB32(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
       
   286 {
       
   287     uint *data = (uint *)rasterBuffer->scanLine(y) + x;
       
   288     for (int i = 0; i < length; ++i) {
       
   289         int p = buffer[i];
       
   290         int alpha = qAlpha(p);
       
   291         if (alpha == 255)
       
   292             data[i] = p;
       
   293         else if (alpha == 0)
       
   294             data[i] = 0;
       
   295         else {
       
   296             int inv_alpha = 0xff0000/qAlpha(buffer[i]);
       
   297             data[i] = (p & 0xff000000)
       
   298                       | ((qRed(p)*inv_alpha) & 0xff0000)
       
   299                       | (((qGreen(p)*inv_alpha) >> 8) & 0xff00)
       
   300                       | ((qBlue(p)*inv_alpha) >> 16);
       
   301         }
       
   302     }
       
   303 }
       
   304 
       
   305 static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
       
   306 {
       
   307     quint16 *data = (quint16*)rasterBuffer->scanLine(y) + x;
       
   308     qt_memconvert<quint16, quint32>(data, buffer, length);
       
   309 }
       
   310 
       
   311 template <class DST>
       
   312 Q_STATIC_TEMPLATE_FUNCTION void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer,
       
   313                                   int x, int y,
       
   314                                   const uint *buffer, int length)
       
   315 {
       
   316     DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
       
   317     const quint32p *src = reinterpret_cast<const quint32p*>(buffer);
       
   318     while (length--)
       
   319         *dest++ = DST(*src++);
       
   320 }
       
   321 
       
   322 # define SPANFUNC_POINTER_DESTSTORE(DEST) destStore<DEST>
       
   323 
       
   324 static const DestStoreProc destStoreProc[QImage::NImageFormats] =
       
   325 {
       
   326     0, // Format_Invalid
       
   327     destStoreMono, // Format_Mono,
       
   328     destStoreMonoLsb, // Format_MonoLSB
       
   329     0, // Format_Indexed8
       
   330     0, // Format_RGB32
       
   331     destStoreARGB32, // Format_ARGB32,
       
   332     0, // Format_ARGB32_Premultiplied
       
   333     destStoreRGB16, // Format_RGB16
       
   334     SPANFUNC_POINTER_DESTSTORE(qargb8565), // Format_ARGB8565_Premultiplied
       
   335     SPANFUNC_POINTER_DESTSTORE(qrgb666),   // Format_RGB666
       
   336     SPANFUNC_POINTER_DESTSTORE(qargb6666), // Format_ARGB6666_Premultiplied
       
   337     SPANFUNC_POINTER_DESTSTORE(qrgb555),   // Format_RGB555
       
   338     SPANFUNC_POINTER_DESTSTORE(qargb8555), // Format_ARGB8555_Premultiplied
       
   339     SPANFUNC_POINTER_DESTSTORE(qrgb888),   // Format_RGB888
       
   340     SPANFUNC_POINTER_DESTSTORE(qrgb444),   // Format_RGB444
       
   341     SPANFUNC_POINTER_DESTSTORE(qargb4444)  // Format_ARGB4444_Premultiplied
       
   342 };
       
   343 
       
   344 /*
       
   345   Source fetches
       
   346 
       
   347   This is a bit more complicated, as we need several fetch routines for every surface type
       
   348 
       
   349   We need 5 fetch methods per surface type:
       
   350   untransformed
       
   351   transformed (tiled and not tiled)
       
   352   transformed bilinear (tiled and not tiled)
       
   353 
       
   354   We don't need bounds checks for untransformed, but we need them for the other ones.
       
   355 
       
   356   The generic implementation does pixel by pixel fetches
       
   357 */
       
   358 
       
   359 template <QImage::Format format>
       
   360 Q_STATIC_TEMPLATE_FUNCTION uint QT_FASTCALL qt_fetchPixel(const uchar *scanLine, int x, const QVector<QRgb> *rgb);
       
   361 
       
   362 template<>
       
   363 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   364 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Mono>(const uchar *scanLine,
       
   365                                                  int x, const QVector<QRgb> *rgb)
       
   366 {
       
   367     bool pixel = scanLine[x>>3] & (0x80 >> (x & 7));
       
   368     if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
       
   369     return pixel ? 0xff000000 : 0xffffffff;
       
   370 }
       
   371 
       
   372 template<>
       
   373 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   374 uint QT_FASTCALL qt_fetchPixel<QImage::Format_MonoLSB>(const uchar *scanLine,
       
   375                                                     int x, const QVector<QRgb> *rgb)
       
   376 {
       
   377     bool pixel = scanLine[x>>3] & (0x1 << (x & 7));
       
   378     if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
       
   379     return pixel ? 0xff000000 : 0xffffffff;
       
   380 }
       
   381 
       
   382 template<>
       
   383 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   384 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Indexed8>(const uchar *scanLine,
       
   385                                                      int x, const QVector<QRgb> *rgb)
       
   386 {
       
   387     return PREMUL(rgb->at(scanLine[x]));
       
   388 }
       
   389 
       
   390 template<>
       
   391 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   392 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32>(const uchar *scanLine,
       
   393                                                    int x, const QVector<QRgb> *)
       
   394 {
       
   395     return PREMUL(((const uint *)scanLine)[x]);
       
   396 }
       
   397 
       
   398 template<>
       
   399 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   400 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32_Premultiplied>(const uchar *scanLine,
       
   401                                                                  int x, const QVector<QRgb> *)
       
   402 {
       
   403     return ((const uint *)scanLine)[x];
       
   404 }
       
   405 
       
   406 template<>
       
   407 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   408 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB16>(const uchar *scanLine,
       
   409                                                   int x, const QVector<QRgb> *)
       
   410 {
       
   411     return qConvertRgb16To32(((const ushort *)scanLine)[x]);
       
   412 }
       
   413 
       
   414 template<>
       
   415 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   416 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8565_Premultiplied>(const uchar *scanLine,
       
   417                                                      int x,
       
   418                                                      const QVector<QRgb> *)
       
   419 {
       
   420     const qargb8565 color = reinterpret_cast<const qargb8565*>(scanLine)[x];
       
   421     return qt_colorConvert<quint32, qargb8565>(color, 0);
       
   422 }
       
   423 
       
   424 template<>
       
   425 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   426 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB666>(const uchar *scanLine,
       
   427                                                    int x,
       
   428                                                    const QVector<QRgb> *)
       
   429 {
       
   430     const qrgb666 color = reinterpret_cast<const qrgb666*>(scanLine)[x];
       
   431     return qt_colorConvert<quint32, qrgb666>(color, 0);
       
   432 }
       
   433 
       
   434 template<>
       
   435 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   436 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB6666_Premultiplied>(const uchar *scanLine,
       
   437                                                    int x,
       
   438                                                    const QVector<QRgb> *)
       
   439 {
       
   440     const qargb6666 color = reinterpret_cast<const qargb6666*>(scanLine)[x];
       
   441     return qt_colorConvert<quint32, qargb6666>(color, 0);
       
   442 }
       
   443 
       
   444 template<>
       
   445 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   446 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB555>(const uchar *scanLine,
       
   447                                                    int x,
       
   448                                                    const QVector<QRgb> *)
       
   449 {
       
   450     const qrgb555 color = reinterpret_cast<const qrgb555*>(scanLine)[x];
       
   451     return qt_colorConvert<quint32, qrgb555>(color, 0);
       
   452 }
       
   453 
       
   454 template<>
       
   455 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   456 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8555_Premultiplied>(const uchar *scanLine,
       
   457                                                      int x,
       
   458                                                      const QVector<QRgb> *)
       
   459 {
       
   460     const qargb8555 color = reinterpret_cast<const qargb8555*>(scanLine)[x];
       
   461     return qt_colorConvert<quint32, qargb8555>(color, 0);
       
   462 }
       
   463 
       
   464 template<>
       
   465 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   466 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB888>(const uchar *scanLine,
       
   467                                                    int x,
       
   468                                                    const QVector<QRgb> *)
       
   469 {
       
   470     const qrgb888 color = reinterpret_cast<const qrgb888*>(scanLine)[x];
       
   471     return qt_colorConvert<quint32, qrgb888>(color, 0);
       
   472 }
       
   473 
       
   474 template<>
       
   475 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   476 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB444>(const uchar *scanLine,
       
   477                                                    int x,
       
   478                                                    const QVector<QRgb> *)
       
   479 {
       
   480     const qrgb444 color = reinterpret_cast<const qrgb444*>(scanLine)[x];
       
   481     return qt_colorConvert<quint32, qrgb444>(color, 0);
       
   482 }
       
   483 
       
   484 template<>
       
   485 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   486 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB4444_Premultiplied>(const uchar *scanLine,
       
   487                                                      int x,
       
   488                                                      const QVector<QRgb> *)
       
   489 {
       
   490     const qargb4444 color = reinterpret_cast<const qargb4444*>(scanLine)[x];
       
   491     return qt_colorConvert<quint32, qargb4444>(color, 0);
       
   492 }
       
   493 
       
   494 template<>
       
   495 Q_STATIC_TEMPLATE_SPECIALIZATION
       
   496 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Invalid>(const uchar *,
       
   497                                                      int ,
       
   498                                                      const QVector<QRgb> *)
       
   499 {
       
   500     return 0;
       
   501 }
       
   502 
       
   503 typedef uint (QT_FASTCALL *FetchPixelProc)(const uchar *scanLine, int x, const QVector<QRgb> *);
       
   504 
       
   505 #define SPANFUNC_POINTER_FETCHPIXEL(Arg) qt_fetchPixel<QImage::Arg>
       
   506 
       
   507 
       
   508 static const FetchPixelProc fetchPixelProc[QImage::NImageFormats] =
       
   509 {
       
   510     0,
       
   511     SPANFUNC_POINTER_FETCHPIXEL(Format_Mono),
       
   512     SPANFUNC_POINTER_FETCHPIXEL(Format_MonoLSB),
       
   513     SPANFUNC_POINTER_FETCHPIXEL(Format_Indexed8),
       
   514     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
       
   515     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32),
       
   516     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
       
   517     SPANFUNC_POINTER_FETCHPIXEL(Format_RGB16),
       
   518     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8565_Premultiplied),
       
   519     SPANFUNC_POINTER_FETCHPIXEL(Format_RGB666),
       
   520     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB6666_Premultiplied),
       
   521     SPANFUNC_POINTER_FETCHPIXEL(Format_RGB555),
       
   522     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8555_Premultiplied),
       
   523     SPANFUNC_POINTER_FETCHPIXEL(Format_RGB888),
       
   524     SPANFUNC_POINTER_FETCHPIXEL(Format_RGB444),
       
   525     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB4444_Premultiplied)
       
   526 };
       
   527 
       
   528 enum TextureBlendType {
       
   529     BlendUntransformed,
       
   530     BlendTiled,
       
   531     BlendTransformed,
       
   532     BlendTransformedTiled,
       
   533     BlendTransformedBilinear,
       
   534     BlendTransformedBilinearTiled,
       
   535     NBlendTypes
       
   536 };
       
   537 
       
   538 template <QImage::Format format>
       
   539 Q_STATIC_TEMPLATE_FUNCTION const uint * QT_FASTCALL qt_fetchUntransformed(uint *buffer, const Operator *, const QSpanData *data,
       
   540                                              int y, int x, int length)
       
   541 {
       
   542     const uchar *scanLine = data->texture.scanLine(y);
       
   543     for (int i = 0; i < length; ++i)
       
   544         buffer[i] = qt_fetchPixel<format>(scanLine, x + i, data->texture.colorTable);
       
   545     return buffer;
       
   546 }
       
   547 
       
   548 template <>
       
   549 Q_STATIC_TEMPLATE_SPECIALIZATION const uint * QT_FASTCALL
       
   550 qt_fetchUntransformed<QImage::Format_ARGB32_Premultiplied>(uint *, const Operator *,
       
   551                                                          const QSpanData *data,
       
   552                                                          int y, int x, int)
       
   553 {
       
   554     const uchar *scanLine = data->texture.scanLine(y);
       
   555     return ((const uint *)scanLine) + x;
       
   556 }
       
   557 
       
   558 template<TextureBlendType blendType>  /* either BlendTransformed or BlendTransformedTiled */
       
   559 Q_STATIC_TEMPLATE_FUNCTION
       
   560 const uint * QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data,
       
   561                                                          int y, int x, int length)
       
   562 {
       
   563     FetchPixelProc fetch = fetchPixelProc[data->texture.format];
       
   564 
       
   565     int image_width = data->texture.width;
       
   566     int image_height = data->texture.height;
       
   567 
       
   568     const qreal cx = x + 0.5;
       
   569     const qreal cy = y + 0.5;
       
   570 
       
   571     const uint *end = buffer + length;
       
   572     uint *b = buffer;
       
   573     if (data->fast_matrix) {
       
   574         // The increment pr x in the scanline
       
   575         int fdx = (int)(data->m11 * fixed_scale);
       
   576         int fdy = (int)(data->m12 * fixed_scale);
       
   577 
       
   578         int fx = int((data->m21 * cy
       
   579                       + data->m11 * cx + data->dx) * fixed_scale);
       
   580         int fy = int((data->m22 * cy
       
   581                       + data->m12 * cx + data->dy) * fixed_scale);
       
   582 
       
   583         while (b < end) {
       
   584             int px = fx >> 16;
       
   585             int py = fy >> 16;
       
   586 
       
   587             if (blendType == BlendTransformedTiled) {
       
   588                 px %= image_width;
       
   589                 py %= image_height;
       
   590                 if (px < 0) px += image_width;
       
   591                 if (py < 0) py += image_height;
       
   592 
       
   593                 const uchar *scanLine = data->texture.scanLine(py);
       
   594                 *b = fetch(scanLine, px, data->texture.colorTable);
       
   595             } else {
       
   596                 if ((px < 0) || (px >= image_width)
       
   597                     || (py < 0) || (py >= image_height)) {
       
   598                     *b = uint(0);
       
   599                 } else {
       
   600                     const uchar *scanLine = data->texture.scanLine(py);
       
   601                     *b = fetch(scanLine, px, data->texture.colorTable);
       
   602                 }
       
   603             }
       
   604             fx += fdx;
       
   605             fy += fdy;
       
   606             ++b;
       
   607         }
       
   608     } else {
       
   609         const qreal fdx = data->m11;
       
   610         const qreal fdy = data->m12;
       
   611         const qreal fdw = data->m13;
       
   612 
       
   613         qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
       
   614         qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
       
   615         qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
       
   616 
       
   617         while (b < end) {
       
   618             const qreal iw = fw == 0 ? 1 : 1 / fw;
       
   619             const qreal tx = fx * iw;
       
   620             const qreal ty = fy * iw;
       
   621             int px = int(tx) - (tx < 0);
       
   622             int py = int(ty) - (ty < 0);
       
   623 
       
   624             if (blendType == BlendTransformedTiled) {
       
   625                 px %= image_width;
       
   626                 py %= image_height;
       
   627                 if (px < 0) px += image_width;
       
   628                 if (py < 0) py += image_height;
       
   629 
       
   630                 const uchar *scanLine = data->texture.scanLine(py);
       
   631                 *b = fetch(scanLine, px, data->texture.colorTable);
       
   632             } else {
       
   633                 if ((px < 0) || (px >= image_width)
       
   634                     || (py < 0) || (py >= image_height)) {
       
   635                     *b = uint(0);
       
   636                 } else {
       
   637                     const uchar *scanLine = data->texture.scanLine(py);
       
   638                     *b = fetch(scanLine, px, data->texture.colorTable);
       
   639                 }
       
   640             }
       
   641             fx += fdx;
       
   642             fy += fdy;
       
   643             fw += fdw;
       
   644             //force increment to avoid /0
       
   645             if (!fw) {
       
   646                 fw += fdw;
       
   647             }
       
   648             ++b;
       
   649         }
       
   650     }
       
   651 
       
   652     return buffer;
       
   653 }
       
   654 
       
   655 template<TextureBlendType blendType, QImage::Format format> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
       
   656 Q_STATIC_TEMPLATE_FUNCTION
       
   657 const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *, const QSpanData *data,
       
   658                                                   int y, int x, int length)
       
   659 {
       
   660 #ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
       
   661     FetchPixelProc fetch;
       
   662     if (format != QImage::Format_Invalid)
       
   663         fetch = qt_fetchPixel<format>;
       
   664     else
       
   665         fetch = fetchPixelProc[data->texture.format];
       
   666 #else
       
   667     FetchPixelProc fetch = (format != QImage::Format_Invalid) ? FetchPixelProc(qt_fetchPixel<format>) : fetchPixelProc[data->texture.format];
       
   668 #endif
       
   669 
       
   670     int image_width = data->texture.width;
       
   671     int image_height = data->texture.height;
       
   672 
       
   673     const qreal cx = x + 0.5;
       
   674     const qreal cy = y + 0.5;
       
   675 
       
   676     const uint *end = buffer + length;
       
   677     uint *b = buffer;
       
   678     if (data->fast_matrix) {
       
   679         // The increment pr x in the scanline
       
   680         int fdx = (int)(data->m11 * fixed_scale);
       
   681         int fdy = (int)(data->m12 * fixed_scale);
       
   682 
       
   683         int fx = int((data->m21 * cy
       
   684                       + data->m11 * cx + data->dx) * fixed_scale);
       
   685         int fy = int((data->m22 * cy
       
   686                       + data->m12 * cx + data->dy) * fixed_scale);
       
   687 
       
   688         fx -= half_point;
       
   689         fy -= half_point;
       
   690         while (b < end) {
       
   691             int x1 = (fx >> 16);
       
   692             int x2 = x1 + 1;
       
   693             int y1 = (fy >> 16);
       
   694             int y2 = y1 + 1;
       
   695 
       
   696             int distx = ((fx - (x1 << 16)) >> 8);
       
   697             int disty = ((fy - (y1 << 16)) >> 8);
       
   698             int idistx = 256 - distx;
       
   699             int idisty = 256 - disty;
       
   700 
       
   701             if (blendType == BlendTransformedBilinearTiled) {
       
   702                 x1 %= image_width;
       
   703                 x2 %= image_width;
       
   704                 y1 %= image_height;
       
   705                 y2 %= image_height;
       
   706 
       
   707                 if (x1 < 0) x1 += image_width;
       
   708                 if (x2 < 0) x2 += image_width;
       
   709                 if (y1 < 0) y1 += image_height;
       
   710                 if (y2 < 0) y2 += image_height;
       
   711 
       
   712                 Q_ASSERT(x1 >= 0 && x1 < image_width);
       
   713                 Q_ASSERT(x2 >= 0 && x2 < image_width);
       
   714                 Q_ASSERT(y1 >= 0 && y1 < image_height);
       
   715                 Q_ASSERT(y2 >= 0 && y2 < image_height);
       
   716             } else {
       
   717                 x1 = qBound(0, x1, image_width - 1);
       
   718                 x2 = qBound(0, x2, image_width - 1);
       
   719                 y1 = qBound(0, y1, image_height - 1);
       
   720                 y2 = qBound(0, y2, image_height - 1);
       
   721             }
       
   722 
       
   723             const uchar *s1 = data->texture.scanLine(y1);
       
   724             const uchar *s2 = data->texture.scanLine(y2);
       
   725 
       
   726             uint tl = fetch(s1, x1, data->texture.colorTable);
       
   727             uint tr = fetch(s1, x2, data->texture.colorTable);
       
   728             uint bl = fetch(s2, x1, data->texture.colorTable);
       
   729             uint br = fetch(s2, x2, data->texture.colorTable);
       
   730 
       
   731             uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
       
   732             uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
       
   733             *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
       
   734 
       
   735             fx += fdx;
       
   736             fy += fdy;
       
   737             ++b;
       
   738         }
       
   739     } else {
       
   740         const qreal fdx = data->m11;
       
   741         const qreal fdy = data->m12;
       
   742         const qreal fdw = data->m13;
       
   743 
       
   744         qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
       
   745         qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
       
   746         qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
       
   747 
       
   748         while (b < end) {
       
   749             const qreal iw = fw == 0 ? 1 : 1 / fw;
       
   750             const qreal px = fx * iw - 0.5;
       
   751             const qreal py = fy * iw - 0.5;
       
   752 
       
   753             int x1 = int(px) - (px < 0);
       
   754             int x2 = x1 + 1;
       
   755             int y1 = int(py) - (py < 0);
       
   756             int y2 = y1 + 1;
       
   757 
       
   758             int distx = int((px - x1) * 256);
       
   759             int disty = int((py - y1) * 256);
       
   760             int idistx = 256 - distx;
       
   761             int idisty = 256 - disty;
       
   762 
       
   763             if (blendType == BlendTransformedBilinearTiled) {
       
   764                 x1 %= image_width;
       
   765                 x2 %= image_width;
       
   766                 y1 %= image_height;
       
   767                 y2 %= image_height;
       
   768 
       
   769                 if (x1 < 0) x1 += image_width;
       
   770                 if (x2 < 0) x2 += image_width;
       
   771                 if (y1 < 0) y1 += image_height;
       
   772                 if (y2 < 0) y2 += image_height;
       
   773 
       
   774                 Q_ASSERT(x1 >= 0 && x1 < image_width);
       
   775                 Q_ASSERT(x2 >= 0 && x2 < image_width);
       
   776                 Q_ASSERT(y1 >= 0 && y1 < image_height);
       
   777                 Q_ASSERT(y2 >= 0 && y2 < image_height);
       
   778             } else {
       
   779                 x1 = qBound(0, x1, image_width - 1);
       
   780                 x2 = qBound(0, x2, image_width - 1);
       
   781                 y1 = qBound(0, y1, image_height - 1);
       
   782                 y2 = qBound(0, y2, image_height - 1);
       
   783             }
       
   784 
       
   785             const uchar *s1 = data->texture.scanLine(y1);
       
   786             const uchar *s2 = data->texture.scanLine(y2);
       
   787 
       
   788             uint tl = fetch(s1, x1, data->texture.colorTable);
       
   789             uint tr = fetch(s1, x2, data->texture.colorTable);
       
   790             uint bl = fetch(s2, x1, data->texture.colorTable);
       
   791             uint br = fetch(s2, x2, data->texture.colorTable);
       
   792 
       
   793             uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
       
   794             uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
       
   795             *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
       
   796 
       
   797             fx += fdx;
       
   798             fy += fdy;
       
   799             fw += fdw;
       
   800             //force increment to avoid /0
       
   801             if (!fw) {
       
   802                 fw += fdw;
       
   803             }
       
   804             ++b;
       
   805         }
       
   806     }
       
   807 
       
   808     return buffer;
       
   809 }
       
   810 
       
   811 #define SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Arg) qt_fetchUntransformed<QImage::Arg>
       
   812 
       
   813 static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = {
       
   814     // Untransformed
       
   815     {
       
   816         0, // Invalid
       
   817         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono),   // Mono
       
   818         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB),   // MonoLsb
       
   819         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8),   // Indexed8
       
   820         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied),   // RGB32
       
   821         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32),   // ARGB32
       
   822         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied),   // ARGB32_Premultiplied
       
   823         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16),   // RGB16
       
   824         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
       
   825         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666),  // RGB666
       
   826         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
       
   827         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555),  // RGB555
       
   828         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
       
   829         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888),  // RGB888
       
   830         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444),  // RGB444
       
   831         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
       
   832     },
       
   833     // Tiled
       
   834     {
       
   835         0, // Invalid
       
   836         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono),   // Mono
       
   837         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB),   // MonoLsb
       
   838         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8),   // Indexed8
       
   839         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied),   // RGB32
       
   840         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32),   // ARGB32
       
   841         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied),   // ARGB32_Premultiplied
       
   842         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16),   // RGB16
       
   843         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
       
   844         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666),  // RGB666
       
   845         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
       
   846         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555),  // RGB555
       
   847         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
       
   848         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888),  // RGB888
       
   849         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444),  // RGB444
       
   850         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
       
   851     },
       
   852     // Transformed
       
   853     {
       
   854         0, // Invalid
       
   855         fetchTransformed<BlendTransformed>,   // Mono
       
   856         fetchTransformed<BlendTransformed>,   // MonoLsb
       
   857         fetchTransformed<BlendTransformed>,   // Indexed8
       
   858         fetchTransformed<BlendTransformed>,   // RGB32
       
   859         fetchTransformed<BlendTransformed>,   // ARGB32
       
   860         fetchTransformed<BlendTransformed>,   // ARGB32_Premultiplied
       
   861         fetchTransformed<BlendTransformed>,   // RGB16
       
   862         fetchTransformed<BlendTransformed>,   // ARGB8565_Premultiplied
       
   863         fetchTransformed<BlendTransformed>,   // RGB666
       
   864         fetchTransformed<BlendTransformed>,   // ARGB6666_Premultiplied
       
   865         fetchTransformed<BlendTransformed>,   // RGB555
       
   866         fetchTransformed<BlendTransformed>,   // ARGB8555_Premultiplied
       
   867         fetchTransformed<BlendTransformed>,   // RGB888
       
   868         fetchTransformed<BlendTransformed>,   // RGB444
       
   869         fetchTransformed<BlendTransformed>,   // ARGB4444_Premultiplied
       
   870     },
       
   871     {
       
   872         0, // TransformedTiled
       
   873         fetchTransformed<BlendTransformedTiled>,   // Mono
       
   874         fetchTransformed<BlendTransformedTiled>,   // MonoLsb
       
   875         fetchTransformed<BlendTransformedTiled>,   // Indexed8
       
   876         fetchTransformed<BlendTransformedTiled>,   // RGB32
       
   877         fetchTransformed<BlendTransformedTiled>,   // ARGB32
       
   878         fetchTransformed<BlendTransformedTiled>,   // ARGB32_Premultiplied
       
   879         fetchTransformed<BlendTransformedTiled>,   // RGB16
       
   880         fetchTransformed<BlendTransformedTiled>,   // ARGB8565_Premultiplied
       
   881         fetchTransformed<BlendTransformedTiled>,   // RGB666
       
   882         fetchTransformed<BlendTransformedTiled>,   // ARGB6666_Premultiplied
       
   883         fetchTransformed<BlendTransformedTiled>,   // RGB555
       
   884         fetchTransformed<BlendTransformedTiled>,   // ARGB8555_Premultiplied
       
   885         fetchTransformed<BlendTransformedTiled>,   // RGB888
       
   886         fetchTransformed<BlendTransformedTiled>,   // RGB444
       
   887         fetchTransformed<BlendTransformedTiled>,   // ARGB4444_Premultiplied
       
   888     },
       
   889     {
       
   890         0, // Bilinear
       
   891         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // Mono
       
   892         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // MonoLsb
       
   893         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // Indexed8
       
   894         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>,   // RGB32
       
   895         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32>,   // ARGB32
       
   896         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>,   // ARGB32_Premultiplied
       
   897         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // RGB16
       
   898         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // ARGB8565_Premultiplied
       
   899         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // RGB666
       
   900         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // ARGB6666_Premultiplied
       
   901         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // RGB555
       
   902         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // ARGB8555_Premultiplied
       
   903         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // RGB888
       
   904         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // RGB444
       
   905         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>    // ARGB4444_Premultiplied
       
   906     },
       
   907     {
       
   908         0, // BilinearTiled
       
   909         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // Mono
       
   910         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // MonoLsb
       
   911         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // Indexed8
       
   912         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>,   // RGB32
       
   913         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32>,   // ARGB32
       
   914         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>,   // ARGB32_Premultiplied
       
   915         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // RGB16
       
   916         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // ARGB8565_Premultiplied
       
   917         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // RGB666
       
   918         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // ARGB6666_Premultiplied
       
   919         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // RGB555
       
   920         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // ARGB8555_Premultiplied
       
   921         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // RGB888
       
   922         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // RGB444
       
   923         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>    // ARGB4444_Premultiplied
       
   924     },
       
   925 };
       
   926 
       
   927 
       
   928 static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos)
       
   929 {
       
   930     int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + 0.5);
       
   931 
       
   932   // calculate the actual offset.
       
   933     if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
       
   934         if (data->spread == QGradient::RepeatSpread) {
       
   935             ipos = ipos % GRADIENT_STOPTABLE_SIZE;
       
   936             ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
       
   937 
       
   938         } else if (data->spread == QGradient::ReflectSpread) {
       
   939             const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
       
   940             ipos = ipos % limit;
       
   941             ipos = ipos < 0 ? limit + ipos : ipos;
       
   942             ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
       
   943 
       
   944         } else {
       
   945             if (ipos < 0) ipos = 0;
       
   946             else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
       
   947         }
       
   948     }
       
   949 
       
   950     Q_ASSERT(ipos >= 0);
       
   951     Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
       
   952 
       
   953     return data->colorTable[ipos];
       
   954 }
       
   955 
       
   956 #define FIXPT_BITS 8
       
   957 #define FIXPT_SIZE (1<<FIXPT_BITS)
       
   958 
       
   959 static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
       
   960 {
       
   961     int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
       
   962 
       
   963     // calculate the actual offset.
       
   964     if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
       
   965         if (data->spread == QGradient::RepeatSpread) {
       
   966             ipos = ipos % GRADIENT_STOPTABLE_SIZE;
       
   967             ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
       
   968 
       
   969         } else if (data->spread == QGradient::ReflectSpread) {
       
   970             const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
       
   971             ipos = ipos % limit;
       
   972             ipos = ipos < 0 ? limit + ipos : ipos;
       
   973             ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
       
   974 
       
   975         } else {
       
   976             if (ipos < 0) ipos = 0;
       
   977             else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
       
   978         }
       
   979     }
       
   980 
       
   981     Q_ASSERT(ipos >= 0);
       
   982     Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
       
   983 
       
   984     return data->colorTable[ipos];
       
   985 }
       
   986 
       
   987 static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
       
   988 {
       
   989     v->dx = data->gradient.linear.end.x - data->gradient.linear.origin.x;
       
   990     v->dy = data->gradient.linear.end.y - data->gradient.linear.origin.y;
       
   991     v->l = v->dx * v->dx + v->dy * v->dy;
       
   992     v->off = 0;
       
   993     if (v->l != 0) {
       
   994         v->dx /= v->l;
       
   995         v->dy /= v->l;
       
   996         v->off = -v->dx * data->gradient.linear.origin.x - v->dy * data->gradient.linear.origin.y;
       
   997     }
       
   998 }
       
   999 
       
  1000 static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator *op, const QSpanData *data,
       
  1001                                                     int y, int x, int length)
       
  1002 {
       
  1003     const uint *b = buffer;
       
  1004     qreal t, inc;
       
  1005 
       
  1006     bool affine = true;
       
  1007     qreal rx=0, ry=0;
       
  1008     if (op->linear.l == 0) {
       
  1009         t = inc = 0;
       
  1010     } else {
       
  1011         rx = data->m21 * (y + 0.5) + data->m11 * (x + 0.5) + data->dx;
       
  1012         ry = data->m22 * (y + 0.5) + data->m12 * (x + 0.5) + data->dy;
       
  1013         t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off;
       
  1014         inc = op->linear.dx * data->m11 + op->linear.dy * data->m12;
       
  1015         affine = !data->m13 && !data->m23;
       
  1016 
       
  1017         if (affine) {
       
  1018             t *= (GRADIENT_STOPTABLE_SIZE - 1);
       
  1019             inc *= (GRADIENT_STOPTABLE_SIZE - 1);
       
  1020         }
       
  1021     }
       
  1022 
       
  1023     const uint *end = buffer + length;
       
  1024     if (affine) {
       
  1025         if (inc > -1e-5 && inc < 1e-5) {
       
  1026             QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE)));
       
  1027         } else {
       
  1028             if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) &&
       
  1029                 t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) {
       
  1030                 // we can use fixed point math
       
  1031                 int t_fixed = int(t * FIXPT_SIZE);
       
  1032                 int inc_fixed = int(inc * FIXPT_SIZE);
       
  1033                 while (buffer < end) {
       
  1034                     *buffer = qt_gradient_pixel_fixed(&data->gradient, t_fixed);
       
  1035                     t_fixed += inc_fixed;
       
  1036                     ++buffer;
       
  1037                 }
       
  1038             } else {
       
  1039                 // we have to fall back to float math
       
  1040                 while (buffer < end) {
       
  1041                     *buffer = qt_gradient_pixel(&data->gradient, t/GRADIENT_STOPTABLE_SIZE);
       
  1042                     t += inc;
       
  1043                     ++buffer;
       
  1044                 }
       
  1045             }
       
  1046         }
       
  1047     } else { // fall back to float math here as well
       
  1048         qreal rw = data->m23 * (y + 0.5) + data->m13 * (x + 0.5) + data->m33;
       
  1049         while (buffer < end) {
       
  1050             qreal x = rx/rw;
       
  1051             qreal y = ry/rw;
       
  1052             t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off;
       
  1053 
       
  1054             *buffer = qt_gradient_pixel(&data->gradient, t);
       
  1055             rx += data->m11;
       
  1056             ry += data->m12;
       
  1057             rw += data->m13;
       
  1058             if (!rw) {
       
  1059                 rw += data->m13;
       
  1060             }
       
  1061             ++buffer;
       
  1062         }
       
  1063     }
       
  1064 
       
  1065     return b;
       
  1066 }
       
  1067 
       
  1068 static inline qreal determinant(qreal a, qreal b, qreal c)
       
  1069 {
       
  1070     return (b * b) - (4 * a * c);
       
  1071 }
       
  1072 
       
  1073 // function to evaluate real roots
       
  1074 static inline qreal realRoots(qreal a, qreal b, qreal detSqrt)
       
  1075 {
       
  1076     return (-b + detSqrt)/(2 * a);
       
  1077 }
       
  1078 
       
  1079 static inline qreal qSafeSqrt(qreal x)
       
  1080 {
       
  1081     return x > 0 ? qSqrt(x) : 0;
       
  1082 }
       
  1083 
       
  1084 static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
       
  1085 {
       
  1086     v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x;
       
  1087     v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y;
       
  1088     v->a = data->gradient.radial.radius*data->gradient.radial.radius - v->dx*v->dx - v->dy*v->dy;
       
  1089 }
       
  1090 
       
  1091 static const uint * QT_FASTCALL fetchRadialGradient(uint *buffer, const Operator *op, const QSpanData *data,
       
  1092                                                     int y, int x, int length)
       
  1093 {
       
  1094     const uint *b = buffer;
       
  1095     qreal rx = data->m21 * (y + 0.5)
       
  1096                + data->dx + data->m11 * (x + 0.5);
       
  1097     qreal ry = data->m22 * (y + 0.5)
       
  1098                + data->dy + data->m12 * (x + 0.5);
       
  1099     bool affine = !data->m13 && !data->m23;
       
  1100     //qreal r  = data->gradient.radial.radius;
       
  1101 
       
  1102     const uint *end = buffer + length;
       
  1103     if (affine) {
       
  1104         rx -= data->gradient.radial.focal.x;
       
  1105         ry -= data->gradient.radial.focal.y;
       
  1106 
       
  1107         qreal inv_a = 1 / qreal(2 * op->radial.a);
       
  1108 
       
  1109         const qreal delta_rx = data->m11;
       
  1110         const qreal delta_ry = data->m12;
       
  1111 
       
  1112         qreal b = 2*(rx * op->radial.dx + ry * op->radial.dy);
       
  1113         qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy);
       
  1114         const qreal b_delta_b = 2 * b * delta_b;
       
  1115         const qreal delta_b_delta_b = 2 * delta_b * delta_b;
       
  1116 
       
  1117         const qreal bb = b * b;
       
  1118         const qreal delta_bb = delta_b * delta_b;
       
  1119 
       
  1120         b *= inv_a;
       
  1121         delta_b *= inv_a;
       
  1122 
       
  1123         const qreal rxrxryry = rx * rx + ry * ry;
       
  1124         const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry;
       
  1125         const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry);
       
  1126         const qreal delta_rx_plus_ry = 2 * delta_rxrxryry;
       
  1127 
       
  1128         inv_a *= inv_a;
       
  1129 
       
  1130         qreal det = (bb + 4 * op->radial.a * rxrxryry) * inv_a;
       
  1131         qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a;
       
  1132         const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a;
       
  1133 
       
  1134         while (buffer < end) {
       
  1135             *buffer = qt_gradient_pixel(&data->gradient, qSafeSqrt(det) - b);
       
  1136 
       
  1137             det += delta_det;
       
  1138             delta_det += delta_delta_det;
       
  1139             b += delta_b;
       
  1140 
       
  1141             ++buffer;
       
  1142         }
       
  1143     } else {
       
  1144         qreal rw = data->m23 * (y + 0.5)
       
  1145                    + data->m33 + data->m13 * (x + 0.5);
       
  1146         if (!rw)
       
  1147             rw = 1;
       
  1148         while (buffer < end) {
       
  1149             qreal gx = rx/rw - data->gradient.radial.focal.x;
       
  1150             qreal gy = ry/rw - data->gradient.radial.focal.y;
       
  1151             qreal b  = 2*(gx*op->radial.dx + gy*op->radial.dy);
       
  1152             qreal det = determinant(op->radial.a, b , -(gx*gx + gy*gy));
       
  1153             qreal s = realRoots(op->radial.a, b, qSafeSqrt(det));
       
  1154 
       
  1155             *buffer = qt_gradient_pixel(&data->gradient, s);
       
  1156 
       
  1157             rx += data->m11;
       
  1158             ry += data->m12;
       
  1159             rw += data->m13;
       
  1160             if (!rw) {
       
  1161                 rw += data->m13;
       
  1162             }
       
  1163             ++buffer;
       
  1164         }
       
  1165     }
       
  1166 
       
  1167     return b;
       
  1168 }
       
  1169 
       
  1170 static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operator *, const QSpanData *data,
       
  1171                                                      int y, int x, int length)
       
  1172 {
       
  1173     const uint *b = buffer;
       
  1174     qreal rx = data->m21 * (y + 0.5)
       
  1175                + data->dx + data->m11 * (x + 0.5);
       
  1176     qreal ry = data->m22 * (y + 0.5)
       
  1177                + data->dy + data->m12 * (x + 0.5);
       
  1178     bool affine = !data->m13 && !data->m23;
       
  1179 
       
  1180     const uint *end = buffer + length;
       
  1181     if (affine) {
       
  1182         rx -= data->gradient.conical.center.x;
       
  1183         ry -= data->gradient.conical.center.y;
       
  1184         while (buffer < end) {
       
  1185             qreal angle = atan2(ry, rx) + data->gradient.conical.angle;
       
  1186 
       
  1187             *buffer = qt_gradient_pixel(&data->gradient, 1 - angle / (2*Q_PI));
       
  1188 
       
  1189             rx += data->m11;
       
  1190             ry += data->m12;
       
  1191             ++buffer;
       
  1192         }
       
  1193     } else {
       
  1194         qreal rw = data->m23 * (y + 0.5)
       
  1195                    + data->m33 + data->m13 * (x + 0.5);
       
  1196         if (!rw)
       
  1197             rw = 1;
       
  1198         while (buffer < end) {
       
  1199             qreal angle = atan2(ry/rw - data->gradient.conical.center.x,
       
  1200                                 rx/rw - data->gradient.conical.center.y)
       
  1201                           + data->gradient.conical.angle;
       
  1202 
       
  1203             *buffer = qt_gradient_pixel(&data->gradient, 1. - angle / (2*Q_PI));
       
  1204 
       
  1205             rx += data->m11;
       
  1206             ry += data->m12;
       
  1207             rw += data->m13;
       
  1208             if (!rw) {
       
  1209                 rw += data->m13;
       
  1210             }
       
  1211             ++buffer;
       
  1212         }
       
  1213     }
       
  1214     return b;
       
  1215 }
       
  1216 
       
  1217 #if defined(Q_CC_RVCT)
       
  1218 // Force ARM code generation for comp_func_* -methods
       
  1219 #  pragma push
       
  1220 #  pragma arm
       
  1221 #  if defined(QT_HAVE_ARMV6)
       
  1222 static __forceinline void preload(const uint *start)
       
  1223 {
       
  1224     asm( "pld [start]" );
       
  1225 }
       
  1226 static const uint L2CacheLineLength = 32;
       
  1227 static const uint L2CacheLineLengthInInts = L2CacheLineLength/sizeof(uint);
       
  1228 #    define PRELOAD_INIT(x) preload(x);
       
  1229 #    define PRELOAD_INIT2(x,y) PRELOAD_INIT(x) PRELOAD_INIT(y)
       
  1230 #    define PRELOAD_COND(x) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts);
       
  1231 // Two consecutive preloads stall, so space them out a bit by using different modulus.
       
  1232 #    define PRELOAD_COND2(x,y) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); \
       
  1233          if (((uint)&y[i])%L2CacheLineLength == 16) preload(&y[i] + L2CacheLineLengthInInts);
       
  1234 #  endif // QT_HAVE_ARMV6
       
  1235 #endif // Q_CC_RVCT
       
  1236 
       
  1237 #if !defined(Q_CC_RVCT) || !defined(QT_HAVE_ARMV6)
       
  1238 #    define PRELOAD_INIT(x)
       
  1239 #    define PRELOAD_INIT2(x,y)
       
  1240 #    define PRELOAD_COND(x)
       
  1241 #    define PRELOAD_COND2(x,y)
       
  1242 #endif
       
  1243 
       
  1244 /* The constant alpha factor describes an alpha factor that gets applied
       
  1245    to the result of the composition operation combining it with the destination.
       
  1246 
       
  1247    The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1.
       
  1248    we get the unmodified operation
       
  1249 
       
  1250    result = src op dest
       
  1251    dest = result * const_alpha + dest * (1. - const_alpha)
       
  1252 
       
  1253    This means that in the comments below, the first line is the const_alpha==255 case, the
       
  1254    second line the general one.
       
  1255 
       
  1256    In the lines below:
       
  1257    s == src, sa == alpha(src), sia = 1 - alpha(src)
       
  1258    d == dest, da == alpha(dest), dia = 1 - alpha(dest)
       
  1259    ca = const_alpha, cia = 1 - const_alpha
       
  1260 
       
  1261    The methods exist in two variants. One where we have a constant source, the other
       
  1262    where the source is an array of pixels.
       
  1263 */
       
  1264 
       
  1265 /*
       
  1266   result = 0
       
  1267   d = d * cia
       
  1268 */
       
  1269 static void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
       
  1270 {
       
  1271     if (const_alpha == 255) {
       
  1272         QT_MEMFILL_UINT(dest, length, 0);
       
  1273     } else {
       
  1274         int ialpha = 255 - const_alpha;
       
  1275         PRELOAD_INIT(dest)
       
  1276         for (int i = 0; i < length; ++i) {
       
  1277             PRELOAD_COND(dest)
       
  1278             dest[i] = BYTE_MUL(dest[i], ialpha);
       
  1279         }
       
  1280     }
       
  1281 }
       
  1282 
       
  1283 static void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
       
  1284 {
       
  1285     if (const_alpha == 255) {
       
  1286         QT_MEMFILL_UINT(dest, length, 0);
       
  1287     } else {
       
  1288         int ialpha = 255 - const_alpha;
       
  1289         PRELOAD_INIT(dest)
       
  1290         for (int i = 0; i < length; ++i) {
       
  1291             PRELOAD_COND(dest)
       
  1292             dest[i] = BYTE_MUL(dest[i], ialpha);
       
  1293         }
       
  1294     }
       
  1295 }
       
  1296 
       
  1297 /*
       
  1298   result = s
       
  1299   dest = s * ca + d * cia
       
  1300 */
       
  1301 static void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha)
       
  1302 {
       
  1303     if (const_alpha == 255) {
       
  1304         QT_MEMFILL_UINT(dest, length, color);
       
  1305     } else {
       
  1306         int ialpha = 255 - const_alpha;
       
  1307         color = BYTE_MUL(color, const_alpha);
       
  1308         PRELOAD_INIT(dest)
       
  1309         for (int i = 0; i < length; ++i) {
       
  1310             PRELOAD_COND(dest)
       
  1311             dest[i] = color + BYTE_MUL(dest[i], ialpha);
       
  1312         }
       
  1313     }
       
  1314 }
       
  1315 
       
  1316 static void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length, uint const_alpha)
       
  1317 {
       
  1318     if (const_alpha == 255) {
       
  1319         ::memcpy(dest, src, length * sizeof(uint));
       
  1320     } else {
       
  1321         int ialpha = 255 - const_alpha;
       
  1322         PRELOAD_INIT2(dest, src)
       
  1323         for (int i = 0; i < length; ++i) {
       
  1324             PRELOAD_COND2(dest, src)
       
  1325             dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha);
       
  1326         }
       
  1327     }
       
  1328 }
       
  1329 
       
  1330 static void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
       
  1331 {
       
  1332 }
       
  1333 
       
  1334 static void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint)
       
  1335 {
       
  1336 }
       
  1337 
       
  1338 /*
       
  1339   result = s + d * sia
       
  1340   dest = (s + d * sia) * ca + d * cia
       
  1341        = s * ca + d * (sia * ca + cia)
       
  1342        = s * ca + d * (1 - sa*ca)
       
  1343 */
       
  1344 static void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha)
       
  1345 {
       
  1346     if ((const_alpha & qAlpha(color)) == 255) {
       
  1347         QT_MEMFILL_UINT(dest, length, color);
       
  1348     } else {
       
  1349         if (const_alpha != 255)
       
  1350             color = BYTE_MUL(color, const_alpha);
       
  1351         PRELOAD_INIT(dest)
       
  1352         for (int i = 0; i < length; ++i) {
       
  1353             PRELOAD_COND(dest)
       
  1354             dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color));
       
  1355         }
       
  1356     }
       
  1357 }
       
  1358 
       
  1359 static void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha)
       
  1360 {
       
  1361     PRELOAD_INIT2(dest, src)
       
  1362     if (const_alpha == 255) {
       
  1363         for (int i = 0; i < length; ++i) {
       
  1364             PRELOAD_COND2(dest, src)
       
  1365             uint s = src[i];
       
  1366             dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
       
  1367         }
       
  1368     } else {
       
  1369         for (int i = 0; i < length; ++i) {
       
  1370             PRELOAD_COND2(dest, src)
       
  1371             uint s = BYTE_MUL(src[i], const_alpha);
       
  1372             dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
       
  1373         }
       
  1374     }
       
  1375 }
       
  1376 
       
  1377 /*
       
  1378   result = d + s * dia
       
  1379   dest = (d + s * dia) * ca + d * cia
       
  1380        = d + s * dia * ca
       
  1381 */
       
  1382 static void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha)
       
  1383 {
       
  1384     if (const_alpha != 255)
       
  1385         color = BYTE_MUL(color, const_alpha);
       
  1386     PRELOAD_INIT(dest)
       
  1387     for (int i = 0; i < length; ++i) {
       
  1388         PRELOAD_COND(dest)
       
  1389         uint d = dest[i];
       
  1390         dest[i] = d + BYTE_MUL(color, qAlpha(~d));
       
  1391     }
       
  1392 }
       
  1393 
       
  1394 static void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha)
       
  1395 {
       
  1396     PRELOAD_INIT2(dest, src)
       
  1397     if (const_alpha == 255) {
       
  1398         for (int i = 0; i < length; ++i) {
       
  1399             PRELOAD_COND2(dest, src)
       
  1400             uint d = dest[i];
       
  1401             dest[i] = d + BYTE_MUL(src[i], qAlpha(~d));
       
  1402         }
       
  1403     } else {
       
  1404         for (int i = 0; i < length; ++i) {
       
  1405             PRELOAD_COND2(dest, src)
       
  1406             uint d = dest[i];
       
  1407             uint s = BYTE_MUL(src[i], const_alpha);
       
  1408             dest[i] = d + BYTE_MUL(s, qAlpha(~d));
       
  1409         }
       
  1410     }
       
  1411 }
       
  1412 
       
  1413 /*
       
  1414   result = s * da
       
  1415   dest = s * da * ca + d * cia
       
  1416 */
       
  1417 static void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha)
       
  1418 {
       
  1419     PRELOAD_INIT(dest)
       
  1420     if (const_alpha == 255) {
       
  1421         for (int i = 0; i < length; ++i) {
       
  1422             PRELOAD_COND(dest)
       
  1423             dest[i] = BYTE_MUL(color, qAlpha(dest[i]));
       
  1424         }
       
  1425     } else {
       
  1426         color = BYTE_MUL(color, const_alpha);
       
  1427         uint cia = 255 - const_alpha;
       
  1428         for (int i = 0; i < length; ++i) {
       
  1429             PRELOAD_COND(dest)
       
  1430             uint d = dest[i];
       
  1431             dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia);
       
  1432         }
       
  1433     }
       
  1434 }
       
  1435 
       
  1436 static void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha)
       
  1437 {
       
  1438     PRELOAD_INIT2(dest, src)
       
  1439     if (const_alpha == 255) {
       
  1440         for (int i = 0; i < length; ++i) {
       
  1441             PRELOAD_COND2(dest, src)
       
  1442             dest[i] = BYTE_MUL(src[i], qAlpha(dest[i]));
       
  1443         }
       
  1444     } else {
       
  1445         uint cia = 255 - const_alpha;
       
  1446         for (int i = 0; i < length; ++i) {
       
  1447             PRELOAD_COND2(dest, src)
       
  1448             uint d = dest[i];
       
  1449             uint s = BYTE_MUL(src[i], const_alpha);
       
  1450             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia);
       
  1451         }
       
  1452     }
       
  1453 }
       
  1454 
       
  1455 /*
       
  1456   result = d * sa
       
  1457   dest = d * sa * ca + d * cia
       
  1458        = d * (sa * ca + cia)
       
  1459 */
       
  1460 static void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha)
       
  1461 {
       
  1462     uint a = qAlpha(color);
       
  1463     if (const_alpha != 255) {
       
  1464         a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
       
  1465     }
       
  1466     PRELOAD_INIT(dest)
       
  1467     for (int i = 0; i < length; ++i) {
       
  1468         PRELOAD_COND(dest)
       
  1469         dest[i] = BYTE_MUL(dest[i], a);
       
  1470     }
       
  1471 }
       
  1472 
       
  1473 static void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha)
       
  1474 {
       
  1475     PRELOAD_INIT2(dest, src)
       
  1476     if (const_alpha == 255) {
       
  1477         for (int i = 0; i < length; ++i) {
       
  1478             PRELOAD_COND2(dest, src)
       
  1479             dest[i] = BYTE_MUL(dest[i], qAlpha(src[i]));
       
  1480         }
       
  1481     } else {
       
  1482         int cia = 255 - const_alpha;
       
  1483         for (int i = 0; i < length; ++i) {
       
  1484             PRELOAD_COND2(dest, src)
       
  1485             uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia;
       
  1486             dest[i] = BYTE_MUL(dest[i], a);
       
  1487         }
       
  1488     }
       
  1489 }
       
  1490 
       
  1491 /*
       
  1492   result = s * dia
       
  1493   dest = s * dia * ca + d * cia
       
  1494 */
       
  1495 
       
  1496 static void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha)
       
  1497 {
       
  1498     PRELOAD_INIT(dest)
       
  1499     if (const_alpha == 255) {
       
  1500         for (int i = 0; i < length; ++i) {
       
  1501             PRELOAD_COND(dest)
       
  1502             dest[i] = BYTE_MUL(color, qAlpha(~dest[i]));
       
  1503         }
       
  1504     } else {
       
  1505         color = BYTE_MUL(color, const_alpha);
       
  1506         int cia = 255 - const_alpha;
       
  1507         for (int i = 0; i < length; ++i) {
       
  1508             PRELOAD_COND(dest)
       
  1509             uint d = dest[i];
       
  1510             dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia);
       
  1511         }
       
  1512     }
       
  1513 }
       
  1514 
       
  1515 static void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha)
       
  1516 {
       
  1517     PRELOAD_INIT2(dest, src)
       
  1518     if (const_alpha == 255) {
       
  1519         for (int i = 0; i < length; ++i) {
       
  1520             PRELOAD_COND2(dest, src)
       
  1521             dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i]));
       
  1522         }
       
  1523     } else {
       
  1524         int cia = 255 - const_alpha;
       
  1525         for (int i = 0; i < length; ++i) {
       
  1526             PRELOAD_COND2(dest, src)
       
  1527             uint s = BYTE_MUL(src[i], const_alpha);
       
  1528             uint d = dest[i];
       
  1529             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia);
       
  1530         }
       
  1531     }
       
  1532 }
       
  1533 
       
  1534 /*
       
  1535   result = d * sia
       
  1536   dest = d * sia * ca + d * cia
       
  1537        = d * (sia * ca + cia)
       
  1538 */
       
  1539 static void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha)
       
  1540 {
       
  1541     uint a = qAlpha(~color);
       
  1542     if (const_alpha != 255)
       
  1543         a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
       
  1544     PRELOAD_INIT(dest)
       
  1545     for (int i = 0; i < length; ++i) {
       
  1546         PRELOAD_COND(dest)
       
  1547         dest[i] = BYTE_MUL(dest[i], a);
       
  1548     }
       
  1549 }
       
  1550 
       
  1551 static void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha)
       
  1552 {
       
  1553     PRELOAD_INIT2(dest, src)
       
  1554     if (const_alpha == 255) {
       
  1555         for (int i = 0; i < length; ++i) {
       
  1556             PRELOAD_COND2(dest, src)
       
  1557             dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i]));
       
  1558         }
       
  1559     } else {
       
  1560         int cia = 255 - const_alpha;
       
  1561         for (int i = 0; i < length; ++i) {
       
  1562             PRELOAD_COND2(dest, src)
       
  1563             uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia;
       
  1564             dest[i] = BYTE_MUL(dest[i], sia);
       
  1565         }
       
  1566     }
       
  1567 }
       
  1568 
       
  1569 /*
       
  1570   result = s*da + d*sia
       
  1571   dest = s*da*ca + d*sia*ca + d *cia
       
  1572        = s*ca * da + d * (sia*ca + cia)
       
  1573        = s*ca * da + d * (1 - sa*ca)
       
  1574 */
       
  1575 static void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha)
       
  1576 {
       
  1577     if (const_alpha != 255) {
       
  1578         color = BYTE_MUL(color, const_alpha);
       
  1579     }
       
  1580     uint sia = qAlpha(~color);
       
  1581     PRELOAD_INIT(dest)
       
  1582     for (int i = 0; i < length; ++i) {
       
  1583         PRELOAD_COND(dest)
       
  1584         dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia);
       
  1585     }
       
  1586 }
       
  1587 
       
  1588 static void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha)
       
  1589 {
       
  1590     PRELOAD_INIT2(dest, src)
       
  1591     if (const_alpha == 255) {
       
  1592         for (int i = 0; i < length; ++i) {
       
  1593             PRELOAD_COND2(dest, src)
       
  1594             uint s = src[i];
       
  1595             uint d = dest[i];
       
  1596             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
       
  1597         }
       
  1598     } else {
       
  1599         for (int i = 0; i < length; ++i) {
       
  1600             PRELOAD_COND2(dest, src)
       
  1601             uint s = BYTE_MUL(src[i], const_alpha);
       
  1602             uint d = dest[i];
       
  1603             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
       
  1604         }
       
  1605     }
       
  1606 }
       
  1607 
       
  1608 /*
       
  1609   result = d*sa + s*dia
       
  1610   dest = d*sa*ca + s*dia*ca + d *cia
       
  1611        = s*ca * dia + d * (sa*ca + cia)
       
  1612 */
       
  1613 static void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha)
       
  1614 {
       
  1615     uint a = qAlpha(color);
       
  1616     if (const_alpha != 255) {
       
  1617         color = BYTE_MUL(color, const_alpha);
       
  1618         a = qAlpha(color) + 255 - const_alpha;
       
  1619     }
       
  1620     PRELOAD_INIT(dest)
       
  1621     for (int i = 0; i < length; ++i) {
       
  1622         PRELOAD_COND(dest)
       
  1623         uint d = dest[i];
       
  1624         dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d));
       
  1625     }
       
  1626 }
       
  1627 
       
  1628 static void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha)
       
  1629 {
       
  1630     PRELOAD_INIT2(dest, src)
       
  1631     if (const_alpha == 255) {
       
  1632         for (int i = 0; i < length; ++i) {
       
  1633             PRELOAD_COND2(dest, src)
       
  1634             uint s = src[i];
       
  1635             uint d = dest[i];
       
  1636             dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d));
       
  1637         }
       
  1638     } else {
       
  1639         int cia = 255 - const_alpha;
       
  1640         for (int i = 0; i < length; ++i) {
       
  1641             PRELOAD_COND2(dest, src)
       
  1642             uint s = BYTE_MUL(src[i], const_alpha);
       
  1643             uint d = dest[i];
       
  1644             uint a = qAlpha(s) + cia;
       
  1645             dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d));
       
  1646         }
       
  1647     }
       
  1648 }
       
  1649 
       
  1650 /*
       
  1651   result = d*sia + s*dia
       
  1652   dest = d*sia*ca + s*dia*ca + d *cia
       
  1653        = s*ca * dia + d * (sia*ca + cia)
       
  1654        = s*ca * dia + d * (1 - sa*ca)
       
  1655 */
       
  1656 static void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha)
       
  1657 {
       
  1658     if (const_alpha != 255)
       
  1659         color = BYTE_MUL(color, const_alpha);
       
  1660     uint sia = qAlpha(~color);
       
  1661 
       
  1662     PRELOAD_INIT(dest)
       
  1663     for (int i = 0; i < length; ++i) {
       
  1664         PRELOAD_COND(dest)
       
  1665         uint d = dest[i];
       
  1666         dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia);
       
  1667     }
       
  1668 }
       
  1669 
       
  1670 static void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha)
       
  1671 {
       
  1672     PRELOAD_INIT2(dest, src)
       
  1673     if (const_alpha == 255) {
       
  1674         for (int i = 0; i < length; ++i) {
       
  1675             PRELOAD_COND2(dest, src)
       
  1676             uint d = dest[i];
       
  1677             uint s = src[i];
       
  1678             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
       
  1679         }
       
  1680     } else {
       
  1681         for (int i = 0; i < length; ++i) {
       
  1682             PRELOAD_COND2(dest, src)
       
  1683             uint d = dest[i];
       
  1684             uint s = BYTE_MUL(src[i], const_alpha);
       
  1685             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
       
  1686         }
       
  1687     }
       
  1688 }
       
  1689 
       
  1690 static const uint AMASK = 0xff000000;
       
  1691 static const uint RMASK = 0x00ff0000;
       
  1692 static const uint GMASK = 0x0000ff00;
       
  1693 static const uint BMASK = 0x000000ff;
       
  1694 
       
  1695 struct QFullCoverage {
       
  1696     inline void store(uint *dest, const uint src) const
       
  1697     {
       
  1698         *dest = src;
       
  1699     }
       
  1700 };
       
  1701 
       
  1702 struct QPartialCoverage {
       
  1703     inline QPartialCoverage(uint const_alpha)
       
  1704         : ca(const_alpha)
       
  1705         , ica(255 - const_alpha)
       
  1706     {
       
  1707     }
       
  1708 
       
  1709     inline void store(uint *dest, const uint src) const
       
  1710     {
       
  1711         *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
       
  1712     }
       
  1713 
       
  1714 private:
       
  1715     const uint ca;
       
  1716     const uint ica;
       
  1717 };
       
  1718 
       
  1719 static inline int mix_alpha(int da, int sa)
       
  1720 {
       
  1721     return 255 - ((255 - sa) * (255 - da) >> 8);
       
  1722 }
       
  1723 
       
  1724 /*
       
  1725     Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
       
  1726          = Sca + Dca
       
  1727 */
       
  1728 template <typename T>
       
  1729 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage)
       
  1730 {
       
  1731     uint s = color;
       
  1732 
       
  1733     PRELOAD_INIT(dest)
       
  1734     for (int i = 0; i < length; ++i) {
       
  1735         PRELOAD_COND(dest)
       
  1736         uint d = dest[i];
       
  1737 #define MIX(mask) (qMin(((qint64(s)&mask) + (qint64(d)&mask)), qint64(mask)))
       
  1738         d = (MIX(AMASK) | MIX(RMASK) | MIX(GMASK) | MIX(BMASK));
       
  1739 #undef MIX
       
  1740         coverage.store(&dest[i], d);
       
  1741     }
       
  1742 }
       
  1743 
       
  1744 static void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha)
       
  1745 {
       
  1746     if (const_alpha == 255)
       
  1747         comp_func_solid_Plus_impl(dest, length, color, QFullCoverage());
       
  1748     else
       
  1749         comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  1750 }
       
  1751 
       
  1752 template <typename T>
       
  1753 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  1754 {
       
  1755     PRELOAD_INIT2(dest, src)
       
  1756     for (int i = 0; i < length; ++i) {
       
  1757         PRELOAD_COND2(dest, src)
       
  1758         uint d = dest[i];
       
  1759         uint s = src[i];
       
  1760 
       
  1761 #define MIX(mask) (qMin(((qint64(s)&mask) + (qint64(d)&mask)), qint64(mask)))
       
  1762         d = (MIX(AMASK) | MIX(RMASK) | MIX(GMASK) | MIX(BMASK));
       
  1763 #undef MIX
       
  1764 
       
  1765         coverage.store(&dest[i], d);
       
  1766     }
       
  1767 }
       
  1768 
       
  1769 static void QT_FASTCALL comp_func_Plus(uint *dest, const uint *src, int length, uint const_alpha)
       
  1770 {
       
  1771     if (const_alpha == 255)
       
  1772         comp_func_Plus_impl(dest, src, length, QFullCoverage());
       
  1773     else
       
  1774         comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  1775 }
       
  1776 
       
  1777 /*
       
  1778     Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
       
  1779 */
       
  1780 static inline int multiply_op(int dst, int src, int da, int sa)
       
  1781 {
       
  1782     return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa));
       
  1783 }
       
  1784 
       
  1785 template <typename T>
       
  1786 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage)
       
  1787 {
       
  1788     int sa = qAlpha(color);
       
  1789     int sr = qRed(color);
       
  1790     int sg = qGreen(color);
       
  1791     int sb = qBlue(color);
       
  1792 
       
  1793     PRELOAD_INIT(dest)
       
  1794     for (int i = 0; i < length; ++i) {
       
  1795         PRELOAD_COND(dest)
       
  1796         uint d = dest[i];
       
  1797         int da = qAlpha(d);
       
  1798 
       
  1799 #define OP(a, b) multiply_op(a, b, da, sa)
       
  1800         int r = OP(  qRed(d), sr);
       
  1801         int b = OP( qBlue(d), sb);
       
  1802         int g = OP(qGreen(d), sg);
       
  1803         int a = mix_alpha(da, sa);
       
  1804 #undef OP
       
  1805 
       
  1806         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  1807     }
       
  1808 }
       
  1809 
       
  1810 static void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha)
       
  1811 {
       
  1812     if (const_alpha == 255)
       
  1813         comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
       
  1814     else
       
  1815         comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  1816 }
       
  1817 
       
  1818 template <typename T>
       
  1819 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  1820 {
       
  1821     PRELOAD_INIT2(dest, src)
       
  1822     for (int i = 0; i < length; ++i) {
       
  1823         PRELOAD_COND2(dest, src)
       
  1824         uint d = dest[i];
       
  1825         uint s = src[i];
       
  1826 
       
  1827         int da = qAlpha(d);
       
  1828         int sa = qAlpha(s);
       
  1829 
       
  1830 #define OP(a, b) multiply_op(a, b, da, sa)
       
  1831         int r = OP(  qRed(d),   qRed(s));
       
  1832         int b = OP( qBlue(d),  qBlue(s));
       
  1833         int g = OP(qGreen(d), qGreen(s));
       
  1834         int a = mix_alpha(da, sa);
       
  1835 #undef OP
       
  1836 
       
  1837         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  1838     }
       
  1839 }
       
  1840 
       
  1841 static void QT_FASTCALL comp_func_Multiply(uint *dest, const uint *src, int length, uint const_alpha)
       
  1842 {
       
  1843     if (const_alpha == 255)
       
  1844         comp_func_Multiply_impl(dest, src, length, QFullCoverage());
       
  1845     else
       
  1846         comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  1847 }
       
  1848 
       
  1849 /*
       
  1850     Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
       
  1851          = Sca + Dca - Sca.Dca
       
  1852 */
       
  1853 template <typename T>
       
  1854 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage)
       
  1855 {
       
  1856     int sa = qAlpha(color);
       
  1857     int sr = qRed(color);
       
  1858     int sg = qGreen(color);
       
  1859     int sb = qBlue(color);
       
  1860 
       
  1861     PRELOAD_INIT(dest)
       
  1862     for (int i = 0; i < length; ++i) {
       
  1863         PRELOAD_COND(dest)
       
  1864         uint d = dest[i];
       
  1865         int da = qAlpha(d);
       
  1866 
       
  1867 #define OP(a, b) 255 - qt_div_255((255-a) * (255-b))
       
  1868         int r = OP(  qRed(d), sr);
       
  1869         int b = OP( qBlue(d), sb);
       
  1870         int g = OP(qGreen(d), sg);
       
  1871         int a = mix_alpha(da, sa);
       
  1872 #undef OP
       
  1873 
       
  1874         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  1875     }
       
  1876 }
       
  1877 
       
  1878 static void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha)
       
  1879 {
       
  1880     if (const_alpha == 255)
       
  1881         comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
       
  1882     else
       
  1883         comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  1884 }
       
  1885 
       
  1886 template <typename T>
       
  1887 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  1888 {
       
  1889     PRELOAD_INIT2(dest, src)
       
  1890     for (int i = 0; i < length; ++i) {
       
  1891         PRELOAD_COND2(dest, src)
       
  1892         uint d = dest[i];
       
  1893         uint s = src[i];
       
  1894 
       
  1895         int da = qAlpha(d);
       
  1896         int sa = qAlpha(s);
       
  1897 
       
  1898 #define OP(a, b) 255 - (((255-a) * (255-b)) >> 8)
       
  1899         int r = OP(  qRed(d),   qRed(s));
       
  1900         int b = OP( qBlue(d),  qBlue(s));
       
  1901         int g = OP(qGreen(d), qGreen(s));
       
  1902         int a = mix_alpha(da, sa);
       
  1903 #undef OP
       
  1904 
       
  1905         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  1906     }
       
  1907 }
       
  1908 
       
  1909 static void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha)
       
  1910 {
       
  1911     if (const_alpha == 255)
       
  1912         comp_func_Screen_impl(dest, src, length, QFullCoverage());
       
  1913     else
       
  1914         comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  1915 }
       
  1916 
       
  1917 /*
       
  1918     if 2.Dca < Da
       
  1919         Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
       
  1920     otherwise
       
  1921         Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
       
  1922 */
       
  1923 static inline int overlay_op(int dst, int src, int da, int sa)
       
  1924 {
       
  1925     const int temp = src * (255 - da) + dst * (255 - sa);
       
  1926     if (2 * dst < da)
       
  1927         return qt_div_255(2 * src * dst + temp);
       
  1928     else
       
  1929         return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
       
  1930 }
       
  1931 
       
  1932 template <typename T>
       
  1933 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage)
       
  1934 {
       
  1935     int sa = qAlpha(color);
       
  1936     int sr = qRed(color);
       
  1937     int sg = qGreen(color);
       
  1938     int sb = qBlue(color);
       
  1939 
       
  1940     PRELOAD_INIT(dest)
       
  1941     for (int i = 0; i < length; ++i) {
       
  1942         PRELOAD_COND(dest)
       
  1943         uint d = dest[i];
       
  1944         int da = qAlpha(d);
       
  1945 
       
  1946 #define OP(a, b) overlay_op(a, b, da, sa)
       
  1947         int r = OP(  qRed(d), sr);
       
  1948         int b = OP( qBlue(d), sb);
       
  1949         int g = OP(qGreen(d), sg);
       
  1950         int a = mix_alpha(da, sa);
       
  1951 #undef OP
       
  1952 
       
  1953         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  1954     }
       
  1955 }
       
  1956 
       
  1957 static void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha)
       
  1958 {
       
  1959     if (const_alpha == 255)
       
  1960         comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
       
  1961     else
       
  1962         comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  1963 }
       
  1964 
       
  1965 template <typename T>
       
  1966 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  1967 {
       
  1968     PRELOAD_INIT2(dest, src)
       
  1969     for (int i = 0; i < length; ++i) {
       
  1970         PRELOAD_COND2(dest, src)
       
  1971         uint d = dest[i];
       
  1972         uint s = src[i];
       
  1973 
       
  1974         int da = qAlpha(d);
       
  1975         int sa = qAlpha(s);
       
  1976 
       
  1977 #define OP(a, b) overlay_op(a, b, da, sa)
       
  1978         int r = OP(  qRed(d),   qRed(s));
       
  1979         int b = OP( qBlue(d),  qBlue(s));
       
  1980         int g = OP(qGreen(d), qGreen(s));
       
  1981         int a = mix_alpha(da, sa);
       
  1982 #undef OP
       
  1983 
       
  1984         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  1985     }
       
  1986 }
       
  1987 
       
  1988 static void QT_FASTCALL comp_func_Overlay(uint *dest, const uint *src, int length, uint const_alpha)
       
  1989 {
       
  1990     if (const_alpha == 255)
       
  1991         comp_func_Overlay_impl(dest, src, length, QFullCoverage());
       
  1992     else
       
  1993         comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  1994 }
       
  1995 
       
  1996 /*
       
  1997     Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
       
  1998     Da'  = Sa + Da - Sa.Da
       
  1999 */
       
  2000 static inline int darken_op(int dst, int src, int da, int sa)
       
  2001 {
       
  2002     return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
       
  2003 }
       
  2004 
       
  2005 template <typename T>
       
  2006 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage)
       
  2007 {
       
  2008     int sa = qAlpha(color);
       
  2009     int sr = qRed(color);
       
  2010     int sg = qGreen(color);
       
  2011     int sb = qBlue(color);
       
  2012 
       
  2013     PRELOAD_INIT(dest)
       
  2014     for (int i = 0; i < length; ++i) {
       
  2015         PRELOAD_COND(dest)
       
  2016         uint d = dest[i];
       
  2017         int da = qAlpha(d);
       
  2018 
       
  2019 #define OP(a, b) darken_op(a, b, da, sa)
       
  2020         int r =  OP(  qRed(d), sr);
       
  2021         int b =  OP( qBlue(d), sb);
       
  2022         int g =  OP(qGreen(d), sg);
       
  2023         int a = mix_alpha(da, sa);
       
  2024 #undef OP
       
  2025 
       
  2026         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2027     }
       
  2028 }
       
  2029 
       
  2030 static void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha)
       
  2031 {
       
  2032     if (const_alpha == 255)
       
  2033         comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
       
  2034     else
       
  2035         comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  2036 }
       
  2037 
       
  2038 template <typename T>
       
  2039 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  2040 {
       
  2041     PRELOAD_INIT2(dest, src)
       
  2042     for (int i = 0; i < length; ++i) {
       
  2043         PRELOAD_COND2(dest, src)
       
  2044         uint d = dest[i];
       
  2045         uint s = src[i];
       
  2046 
       
  2047         int da = qAlpha(d);
       
  2048         int sa = qAlpha(s);
       
  2049 
       
  2050 #define OP(a, b) darken_op(a, b, da, sa)
       
  2051         int r = OP(  qRed(d),   qRed(s));
       
  2052         int b = OP( qBlue(d),  qBlue(s));
       
  2053         int g = OP(qGreen(d), qGreen(s));
       
  2054         int a = mix_alpha(da, sa);
       
  2055 #undef OP
       
  2056 
       
  2057         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2058     }
       
  2059 }
       
  2060 
       
  2061 static void QT_FASTCALL comp_func_Darken(uint *dest, const uint *src, int length, uint const_alpha)
       
  2062 {
       
  2063     if (const_alpha == 255)
       
  2064         comp_func_Darken_impl(dest, src, length, QFullCoverage());
       
  2065     else
       
  2066         comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  2067 }
       
  2068 
       
  2069 /*
       
  2070    Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
       
  2071    Da'  = Sa + Da - Sa.Da
       
  2072 */
       
  2073 static inline int lighten_op(int dst, int src, int da, int sa)
       
  2074 {
       
  2075     return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
       
  2076 }
       
  2077 
       
  2078 template <typename T>
       
  2079 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage)
       
  2080 {
       
  2081     int sa = qAlpha(color);
       
  2082     int sr = qRed(color);
       
  2083     int sg = qGreen(color);
       
  2084     int sb = qBlue(color);
       
  2085 
       
  2086     PRELOAD_INIT(dest)
       
  2087     for (int i = 0; i < length; ++i) {
       
  2088         PRELOAD_COND(dest)
       
  2089         uint d = dest[i];
       
  2090         int da = qAlpha(d);
       
  2091 
       
  2092 #define OP(a, b) lighten_op(a, b, da, sa)
       
  2093         int r =  OP(  qRed(d), sr);
       
  2094         int b =  OP( qBlue(d), sb);
       
  2095         int g =  OP(qGreen(d), sg);
       
  2096         int a = mix_alpha(da, sa);
       
  2097 #undef OP
       
  2098 
       
  2099         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2100     }
       
  2101 }
       
  2102 
       
  2103 static void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha)
       
  2104 {
       
  2105     if (const_alpha == 255)
       
  2106         comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
       
  2107     else
       
  2108         comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  2109 }
       
  2110 
       
  2111 template <typename T>
       
  2112 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  2113 {
       
  2114     PRELOAD_INIT2(dest, src)
       
  2115     for (int i = 0; i < length; ++i) {
       
  2116         PRELOAD_COND2(dest, src)
       
  2117         uint d = dest[i];
       
  2118         uint s = src[i];
       
  2119 
       
  2120         int da = qAlpha(d);
       
  2121         int sa = qAlpha(s);
       
  2122 
       
  2123 #define OP(a, b) lighten_op(a, b, da, sa)
       
  2124         int r = OP(  qRed(d),   qRed(s));
       
  2125         int b = OP( qBlue(d),  qBlue(s));
       
  2126         int g = OP(qGreen(d), qGreen(s));
       
  2127         int a = mix_alpha(da, sa);
       
  2128 #undef OP
       
  2129 
       
  2130         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2131     }
       
  2132 }
       
  2133 
       
  2134 static void QT_FASTCALL comp_func_Lighten(uint *dest, const uint *src, int length, uint const_alpha)
       
  2135 {
       
  2136     if (const_alpha == 255)
       
  2137         comp_func_Lighten_impl(dest, src, length, QFullCoverage());
       
  2138     else
       
  2139         comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  2140 }
       
  2141 
       
  2142 /*
       
  2143    if Sca.Da + Dca.Sa >= Sa.Da
       
  2144        Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
       
  2145    otherwise
       
  2146        Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
       
  2147 */
       
  2148 static inline int color_dodge_op(int dst, int src, int da, int sa)
       
  2149 {
       
  2150     const int sa_da = sa * da;
       
  2151     const int dst_sa = dst * sa;
       
  2152     const int src_da = src * da;
       
  2153 
       
  2154     const int temp = src * (255 - da) + dst * (255 - sa);
       
  2155     if (src_da + dst_sa >= sa_da)
       
  2156         return qt_div_255(sa_da + temp);
       
  2157     else
       
  2158         return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp);
       
  2159 }
       
  2160 
       
  2161 template <typename T>
       
  2162 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage)
       
  2163 {
       
  2164     int sa = qAlpha(color);
       
  2165     int sr = qRed(color);
       
  2166     int sg = qGreen(color);
       
  2167     int sb = qBlue(color);
       
  2168 
       
  2169     PRELOAD_INIT(dest)
       
  2170     for (int i = 0; i < length; ++i) {
       
  2171         PRELOAD_COND(dest)
       
  2172         uint d = dest[i];
       
  2173         int da = qAlpha(d);
       
  2174 
       
  2175 #define OP(a,b) color_dodge_op(a, b, da, sa)
       
  2176         int r = OP(  qRed(d), sr);
       
  2177         int b = OP( qBlue(d), sb);
       
  2178         int g = OP(qGreen(d), sg);
       
  2179         int a = mix_alpha(da, sa);
       
  2180 #undef OP
       
  2181 
       
  2182         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2183     }
       
  2184 }
       
  2185 
       
  2186 static void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha)
       
  2187 {
       
  2188     if (const_alpha == 255)
       
  2189         comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
       
  2190     else
       
  2191         comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  2192 }
       
  2193 
       
  2194 template <typename T>
       
  2195 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  2196 {
       
  2197     PRELOAD_INIT2(dest, src)
       
  2198     for (int i = 0; i < length; ++i) {
       
  2199         PRELOAD_COND2(dest, src)
       
  2200         uint d = dest[i];
       
  2201         uint s = src[i];
       
  2202 
       
  2203         int da = qAlpha(d);
       
  2204         int sa = qAlpha(s);
       
  2205 
       
  2206 #define OP(a, b) color_dodge_op(a, b, da, sa)
       
  2207         int r = OP(  qRed(d),   qRed(s));
       
  2208         int b = OP( qBlue(d),  qBlue(s));
       
  2209         int g = OP(qGreen(d), qGreen(s));
       
  2210         int a = mix_alpha(da, sa);
       
  2211 #undef OP
       
  2212 
       
  2213         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2214     }
       
  2215 }
       
  2216 
       
  2217 static void QT_FASTCALL comp_func_ColorDodge(uint *dest, const uint *src, int length, uint const_alpha)
       
  2218 {
       
  2219     if (const_alpha == 255)
       
  2220         comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
       
  2221     else
       
  2222         comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  2223 }
       
  2224 
       
  2225 /*
       
  2226    if Sca.Da + Dca.Sa <= Sa.Da
       
  2227        Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
       
  2228    otherwise
       
  2229        Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
       
  2230 */
       
  2231 static inline int color_burn_op(int dst, int src, int da, int sa)
       
  2232 {
       
  2233     const int src_da = src * da;
       
  2234     const int dst_sa = dst * sa;
       
  2235     const int sa_da = sa * da;
       
  2236 
       
  2237     const int temp = src * (255 - da) + dst * (255 - sa);
       
  2238 
       
  2239     if (src == 0 || src_da + dst_sa <= sa_da)
       
  2240         return qt_div_255(temp);
       
  2241     return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp);
       
  2242 }
       
  2243 
       
  2244 template <typename T>
       
  2245 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage)
       
  2246 {
       
  2247     int sa = qAlpha(color);
       
  2248     int sr = qRed(color);
       
  2249     int sg = qGreen(color);
       
  2250     int sb = qBlue(color);
       
  2251 
       
  2252     PRELOAD_INIT(dest)
       
  2253     for (int i = 0; i < length; ++i) {
       
  2254         PRELOAD_COND(dest)
       
  2255         uint d = dest[i];
       
  2256         int da = qAlpha(d);
       
  2257 
       
  2258 #define OP(a, b) color_burn_op(a, b, da, sa)
       
  2259         int r =  OP(  qRed(d), sr);
       
  2260         int b =  OP( qBlue(d), sb);
       
  2261         int g =  OP(qGreen(d), sg);
       
  2262         int a = mix_alpha(da, sa);
       
  2263 #undef OP
       
  2264 
       
  2265         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2266     }
       
  2267 }
       
  2268 
       
  2269 static void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha)
       
  2270 {
       
  2271     if (const_alpha == 255)
       
  2272         comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
       
  2273     else
       
  2274         comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  2275 }
       
  2276 
       
  2277 template <typename T>
       
  2278 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  2279 {
       
  2280     PRELOAD_INIT2(dest, src)
       
  2281     for (int i = 0; i < length; ++i) {
       
  2282         PRELOAD_COND2(dest, src)
       
  2283         uint d = dest[i];
       
  2284         uint s = src[i];
       
  2285 
       
  2286         int da = qAlpha(d);
       
  2287         int sa = qAlpha(s);
       
  2288 
       
  2289 #define OP(a, b) color_burn_op(a, b, da, sa)
       
  2290         int r = OP(  qRed(d),   qRed(s));
       
  2291         int b = OP( qBlue(d),  qBlue(s));
       
  2292         int g = OP(qGreen(d), qGreen(s));
       
  2293         int a = mix_alpha(da, sa);
       
  2294 #undef OP
       
  2295 
       
  2296         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2297     }
       
  2298 }
       
  2299 
       
  2300 static void QT_FASTCALL comp_func_ColorBurn(uint *dest, const uint *src, int length, uint const_alpha)
       
  2301 {
       
  2302     if (const_alpha == 255)
       
  2303         comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
       
  2304     else
       
  2305         comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  2306 }
       
  2307 
       
  2308 /*
       
  2309     if 2.Sca < Sa
       
  2310         Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
       
  2311     otherwise
       
  2312         Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
       
  2313 */
       
  2314 static inline uint hardlight_op(int dst, int src, int da, int sa)
       
  2315 {
       
  2316     const uint temp = src * (255 - da) + dst * (255 - sa);
       
  2317 
       
  2318     if (2 * src < sa)
       
  2319         return qt_div_255(2 * src * dst + temp);
       
  2320     else
       
  2321         return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
       
  2322 }
       
  2323 
       
  2324 template <typename T>
       
  2325 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage)
       
  2326 {
       
  2327     int sa = qAlpha(color);
       
  2328     int sr = qRed(color);
       
  2329     int sg = qGreen(color);
       
  2330     int sb = qBlue(color);
       
  2331 
       
  2332     PRELOAD_INIT(dest)
       
  2333     for (int i = 0; i < length; ++i) {
       
  2334         PRELOAD_COND(dest)
       
  2335         uint d = dest[i];
       
  2336         int da = qAlpha(d);
       
  2337 
       
  2338 #define OP(a, b) hardlight_op(a, b, da, sa)
       
  2339         int r =  OP(  qRed(d), sr);
       
  2340         int b =  OP( qBlue(d), sb);
       
  2341         int g =  OP(qGreen(d), sg);
       
  2342         int a = mix_alpha(da, sa);
       
  2343 #undef OP
       
  2344 
       
  2345         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2346     }
       
  2347 }
       
  2348 
       
  2349 static void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha)
       
  2350 {
       
  2351     if (const_alpha == 255)
       
  2352         comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
       
  2353     else
       
  2354         comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  2355 }
       
  2356 
       
  2357 template <typename T>
       
  2358 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  2359 {
       
  2360     PRELOAD_INIT2(dest, src)
       
  2361     for (int i = 0; i < length; ++i) {
       
  2362         PRELOAD_COND2(dest, src)
       
  2363         uint d = dest[i];
       
  2364         uint s = src[i];
       
  2365 
       
  2366         int da = qAlpha(d);
       
  2367         int sa = qAlpha(s);
       
  2368 
       
  2369 #define OP(a, b) hardlight_op(a, b, da, sa)
       
  2370         int r = OP(  qRed(d),   qRed(s));
       
  2371         int b = OP( qBlue(d),  qBlue(s));
       
  2372         int g = OP(qGreen(d), qGreen(s));
       
  2373         int a = mix_alpha(da, sa);
       
  2374 #undef OP
       
  2375 
       
  2376         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2377     }
       
  2378 }
       
  2379 
       
  2380 static void QT_FASTCALL comp_func_HardLight(uint *dest, const uint *src, int length, uint const_alpha)
       
  2381 {
       
  2382     if (const_alpha == 255)
       
  2383         comp_func_HardLight_impl(dest, src, length, QFullCoverage());
       
  2384     else
       
  2385         comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  2386 }
       
  2387 
       
  2388 /*
       
  2389    if 2.Sca < Sa
       
  2390        Dca' = Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa)
       
  2391    otherwise if 8.Dca <= Da
       
  2392        Dca' = Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa).(3 - 8.Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
       
  2393    otherwise
       
  2394        Dca' = (Dca.Sa + ((Dca/Da)^(0.5).Da - Dca).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa)
       
  2395 */
       
  2396 static inline int soft_light_op(int dst, int src, int da, int sa)
       
  2397 {
       
  2398     const int src2 = src << 1;
       
  2399     const int dst_np = da != 0 ? (255 * dst) / da : 0;
       
  2400     const int temp = (src * (255 - da) + dst * (255 - sa)) * 255;
       
  2401 
       
  2402     if (src2 < sa)
       
  2403         return (dst * ((sa * 255) - (255 - dst_np) * (src2 - sa)) + temp) / 65025;
       
  2404     else if (8 * dst <= da)
       
  2405         return (dst * ((sa * 255) - ((255 - dst_np) * (src2 - sa) * ((3 * 255) - 8 * dst_np)) / 255) + temp) / 65025;
       
  2406     else {
       
  2407         // sqrt is too expensive to do three times per pixel, so skipping it for now
       
  2408         // a future possibility is to use a LUT
       
  2409         return ((dst * sa * 255) + (int(dst_np) * da - (dst * 255)) * (src2 - sa) + temp) / 65025;
       
  2410     }
       
  2411 }
       
  2412 
       
  2413 template <typename T>
       
  2414 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage)
       
  2415 {
       
  2416     int sa = qAlpha(color);
       
  2417     int sr = qRed(color);
       
  2418     int sg = qGreen(color);
       
  2419     int sb = qBlue(color);
       
  2420 
       
  2421     PRELOAD_INIT(dest)
       
  2422     for (int i = 0; i < length; ++i) {
       
  2423         PRELOAD_COND(dest)
       
  2424         uint d = dest[i];
       
  2425         int da = qAlpha(d);
       
  2426 
       
  2427 #define OP(a, b) soft_light_op(a, b, da, sa)
       
  2428         int r =  OP(  qRed(d), sr);
       
  2429         int b =  OP( qBlue(d), sb);
       
  2430         int g =  OP(qGreen(d), sg);
       
  2431         int a = mix_alpha(da, sa);
       
  2432 #undef OP
       
  2433 
       
  2434         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2435     }
       
  2436 }
       
  2437 
       
  2438 static void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
       
  2439 {
       
  2440     if (const_alpha == 255)
       
  2441         comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
       
  2442     else
       
  2443         comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  2444 }
       
  2445 
       
  2446 template <typename T>
       
  2447 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  2448 {
       
  2449     PRELOAD_INIT2(dest, src)
       
  2450     for (int i = 0; i < length; ++i) {
       
  2451         PRELOAD_COND2(dest, src)
       
  2452         uint d = dest[i];
       
  2453         uint s = src[i];
       
  2454 
       
  2455         int da = qAlpha(d);
       
  2456         int sa = qAlpha(s);
       
  2457 
       
  2458 #define OP(a, b) soft_light_op(a, b, da, sa)
       
  2459         int r = OP(  qRed(d),   qRed(s));
       
  2460         int b = OP( qBlue(d),  qBlue(s));
       
  2461         int g = OP(qGreen(d), qGreen(s));
       
  2462         int a = mix_alpha(da, sa);
       
  2463 #undef OP
       
  2464 
       
  2465         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2466     }
       
  2467 }
       
  2468 
       
  2469 static void QT_FASTCALL comp_func_SoftLight(uint *dest, const uint *src, int length, uint const_alpha)
       
  2470 {
       
  2471     if (const_alpha == 255)
       
  2472         comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
       
  2473     else
       
  2474         comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  2475 }
       
  2476 
       
  2477 /*
       
  2478    Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
       
  2479         = Sca + Dca - 2.min(Sca.Da, Dca.Sa)
       
  2480 */
       
  2481 static inline int difference_op(int dst, int src, int da, int sa)
       
  2482 {
       
  2483     return src + dst - qt_div_255(2 * qMin(src * da, dst * sa));
       
  2484 }
       
  2485 
       
  2486 template <typename T>
       
  2487 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage)
       
  2488 {
       
  2489     int sa = qAlpha(color);
       
  2490     int sr = qRed(color);
       
  2491     int sg = qGreen(color);
       
  2492     int sb = qBlue(color);
       
  2493 
       
  2494     PRELOAD_INIT(dest)
       
  2495     for (int i = 0; i < length; ++i) {
       
  2496         PRELOAD_COND(dest)
       
  2497         uint d = dest[i];
       
  2498         int da = qAlpha(d);
       
  2499 
       
  2500 #define OP(a, b) difference_op(a, b, da, sa)
       
  2501         int r =  OP(  qRed(d), sr);
       
  2502         int b =  OP( qBlue(d), sb);
       
  2503         int g =  OP(qGreen(d), sg);
       
  2504         int a = mix_alpha(da, sa);
       
  2505 #undef OP
       
  2506 
       
  2507         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2508     }
       
  2509 }
       
  2510 
       
  2511 static void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha)
       
  2512 {
       
  2513     if (const_alpha == 255)
       
  2514         comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
       
  2515     else
       
  2516         comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  2517 }
       
  2518 
       
  2519 template <typename T>
       
  2520 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  2521 {
       
  2522     PRELOAD_INIT2(dest, src)
       
  2523     for (int i = 0; i < length; ++i) {
       
  2524         PRELOAD_COND2(dest, src)
       
  2525         uint d = dest[i];
       
  2526         uint s = src[i];
       
  2527 
       
  2528         int da = qAlpha(d);
       
  2529         int sa = qAlpha(s);
       
  2530 
       
  2531 #define OP(a, b) difference_op(a, b, da, sa)
       
  2532         int r = OP(  qRed(d),   qRed(s));
       
  2533         int b = OP( qBlue(d),  qBlue(s));
       
  2534         int g = OP(qGreen(d), qGreen(s));
       
  2535         int a = mix_alpha(da, sa);
       
  2536 #undef OP
       
  2537 
       
  2538         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2539     }
       
  2540 }
       
  2541 
       
  2542 static void QT_FASTCALL comp_func_Difference(uint *dest, const uint *src, int length, uint const_alpha)
       
  2543 {
       
  2544     if (const_alpha == 255)
       
  2545         comp_func_Difference_impl(dest, src, length, QFullCoverage());
       
  2546     else
       
  2547         comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  2548 }
       
  2549 
       
  2550 /*
       
  2551     Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
       
  2552 */
       
  2553 template <typename T>
       
  2554 Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage)
       
  2555 {
       
  2556     int sa = qAlpha(color);
       
  2557     int sr = qRed(color);
       
  2558     int sg = qGreen(color);
       
  2559     int sb = qBlue(color);
       
  2560 
       
  2561     PRELOAD_INIT(dest)
       
  2562     for (int i = 0; i < length; ++i) {
       
  2563         PRELOAD_COND(dest)
       
  2564         uint d = dest[i];
       
  2565         int da = qAlpha(d);
       
  2566 
       
  2567 #define OP(a, b) (a + b - qt_div_255(2*(a*b)))
       
  2568         int r =  OP(  qRed(d), sr);
       
  2569         int b =  OP( qBlue(d), sb);
       
  2570         int g =  OP(qGreen(d), sg);
       
  2571         int a = mix_alpha(da, sa);
       
  2572 #undef OP
       
  2573 
       
  2574         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2575     }
       
  2576 }
       
  2577 
       
  2578 static void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha)
       
  2579 {
       
  2580     if (const_alpha == 255)
       
  2581         comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage());
       
  2582     else
       
  2583         comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
       
  2584 }
       
  2585 
       
  2586 template <typename T>
       
  2587 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *dest, const uint *src, int length, const T &coverage)
       
  2588 {
       
  2589     PRELOAD_INIT2(dest, src)
       
  2590     for (int i = 0; i < length; ++i) {
       
  2591         PRELOAD_COND2(dest, src)
       
  2592         uint d = dest[i];
       
  2593         uint s = src[i];
       
  2594 
       
  2595         int da = qAlpha(d);
       
  2596         int sa = qAlpha(s);
       
  2597 
       
  2598 #define OP(a, b) (a + b - ((a*b) >> 7))
       
  2599         int r = OP(  qRed(d),   qRed(s));
       
  2600         int b = OP( qBlue(d),  qBlue(s));
       
  2601         int g = OP(qGreen(d), qGreen(s));
       
  2602         int a = mix_alpha(da, sa);
       
  2603 #undef OP
       
  2604 
       
  2605         coverage.store(&dest[i], qRgba(r, g, b, a));
       
  2606     }
       
  2607 }
       
  2608 
       
  2609 static void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int length, uint const_alpha)
       
  2610 {
       
  2611     if (const_alpha == 255)
       
  2612         comp_func_Exclusion_impl(dest, src, length, QFullCoverage());
       
  2613     else
       
  2614         comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
       
  2615 }
       
  2616 
       
  2617 #if defined(Q_CC_RVCT)
       
  2618 // Restore pragma state from previous #pragma arm
       
  2619 #  pragma pop
       
  2620 #endif
       
  2621 
       
  2622 static void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest,
       
  2623                                                            int length,
       
  2624                                                            uint color,
       
  2625                                                            uint const_alpha)
       
  2626 {
       
  2627     Q_UNUSED(const_alpha);
       
  2628     while (length--)
       
  2629         *dest++ |= color;
       
  2630 }
       
  2631 
       
  2632 static void QT_FASTCALL rasterop_SourceOrDestination(uint *dest,
       
  2633                                                      const uint *src,
       
  2634                                                      int length,
       
  2635                                                      uint const_alpha)
       
  2636 {
       
  2637     Q_UNUSED(const_alpha);
       
  2638     while (length--)
       
  2639         *dest++ |= *src++;
       
  2640 }
       
  2641 
       
  2642 static void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest,
       
  2643                                                             int length,
       
  2644                                                             uint color,
       
  2645                                                             uint const_alpha)
       
  2646 {
       
  2647     Q_UNUSED(const_alpha);
       
  2648     color |= 0xff000000;
       
  2649     while (length--)
       
  2650         *dest++ &= color;
       
  2651 }
       
  2652 
       
  2653 static void QT_FASTCALL rasterop_SourceAndDestination(uint *dest,
       
  2654                                                       const uint *src,
       
  2655                                                       int length,
       
  2656                                                       uint const_alpha)
       
  2657 {
       
  2658     Q_UNUSED(const_alpha);
       
  2659     while (length--) {
       
  2660         *dest = (*src & *dest) | 0xff000000;
       
  2661         ++dest; ++src;
       
  2662     }
       
  2663 }
       
  2664 
       
  2665 static void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest,
       
  2666                                                             int length,
       
  2667                                                             uint color,
       
  2668                                                             uint const_alpha)
       
  2669 {
       
  2670     Q_UNUSED(const_alpha);
       
  2671     color &= 0x00ffffff;
       
  2672     while (length--)
       
  2673         *dest++ ^= color;
       
  2674 }
       
  2675 
       
  2676 static void QT_FASTCALL rasterop_SourceXorDestination(uint *dest,
       
  2677                                                       const uint *src,
       
  2678                                                       int length,
       
  2679                                                       uint const_alpha)
       
  2680 {
       
  2681     Q_UNUSED(const_alpha);
       
  2682     while (length--) {
       
  2683         *dest = (*src ^ *dest) | 0xff000000;
       
  2684         ++dest; ++src;
       
  2685     }
       
  2686 }
       
  2687 
       
  2688 static void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest,
       
  2689                                                                   int length,
       
  2690                                                                   uint color,
       
  2691                                                                   uint const_alpha)
       
  2692 {
       
  2693     Q_UNUSED(const_alpha);
       
  2694     color = ~color;
       
  2695     while (length--) {
       
  2696         *dest = (color & ~(*dest)) | 0xff000000;
       
  2697         ++dest;
       
  2698     }
       
  2699 }
       
  2700 
       
  2701 static void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *dest,
       
  2702                                                             const uint *src,
       
  2703                                                             int length,
       
  2704                                                             uint const_alpha)
       
  2705 {
       
  2706     Q_UNUSED(const_alpha);
       
  2707     while (length--) {
       
  2708         *dest = (~(*src) & ~(*dest)) | 0xff000000;
       
  2709         ++dest; ++src;
       
  2710     }
       
  2711 }
       
  2712 
       
  2713 static void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest,
       
  2714                                                                  int length,
       
  2715                                                                  uint color,
       
  2716                                                                  uint const_alpha)
       
  2717 {
       
  2718     Q_UNUSED(const_alpha);
       
  2719     color = ~color | 0xff000000;
       
  2720     while (length--) {
       
  2721         *dest = color | ~(*dest);
       
  2722         ++dest;
       
  2723     }
       
  2724 }
       
  2725 
       
  2726 static void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *dest,
       
  2727                                                            const uint *src,
       
  2728                                                            int length,
       
  2729                                                            uint const_alpha)
       
  2730 {
       
  2731     Q_UNUSED(const_alpha);
       
  2732     while (length--) {
       
  2733         *dest = ~(*src) | ~(*dest) | 0xff000000;
       
  2734         ++dest; ++src;
       
  2735     }
       
  2736 }
       
  2737 
       
  2738 static void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest,
       
  2739                                                                int length,
       
  2740                                                                uint color,
       
  2741                                                                uint const_alpha)
       
  2742 {
       
  2743     Q_UNUSED(const_alpha);
       
  2744     color = ~color & 0x00ffffff;
       
  2745     while (length--) {
       
  2746         *dest = color ^ (*dest);
       
  2747         ++dest;
       
  2748     }
       
  2749 }
       
  2750 
       
  2751 static void QT_FASTCALL rasterop_NotSourceXorDestination(uint *dest,
       
  2752                                                          const uint *src,
       
  2753                                                          int length,
       
  2754                                                          uint const_alpha)
       
  2755 {
       
  2756     Q_UNUSED(const_alpha);
       
  2757     while (length--) {
       
  2758         *dest = ((~(*src)) ^ (*dest)) | 0xff000000;
       
  2759         ++dest; ++src;
       
  2760     }
       
  2761 }
       
  2762 
       
  2763 static void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length,
       
  2764                                                  uint color, uint const_alpha)
       
  2765 {
       
  2766     Q_UNUSED(const_alpha);
       
  2767     qt_memfill(dest, ~color | 0xff000000, length);
       
  2768 }
       
  2769 
       
  2770 static void QT_FASTCALL rasterop_NotSource(uint *dest, const uint *src,
       
  2771                                            int length, uint const_alpha)
       
  2772 {
       
  2773     Q_UNUSED(const_alpha);
       
  2774     while (length--)
       
  2775         *dest++ = ~(*src++) | 0xff000000;
       
  2776 }
       
  2777 
       
  2778 static void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest,
       
  2779                                                                int length,
       
  2780                                                                uint color,
       
  2781                                                                uint const_alpha)
       
  2782 {
       
  2783     Q_UNUSED(const_alpha);
       
  2784     color = ~color | 0xff000000;
       
  2785     while (length--) {
       
  2786         *dest = color & *dest;
       
  2787         ++dest;
       
  2788     }
       
  2789 }
       
  2790 
       
  2791 static void QT_FASTCALL rasterop_NotSourceAndDestination(uint *dest,
       
  2792                                                          const uint *src,
       
  2793                                                          int length,
       
  2794                                                          uint const_alpha)
       
  2795 {
       
  2796     Q_UNUSED(const_alpha);
       
  2797     while (length--) {
       
  2798         *dest = (~(*src) & *dest) | 0xff000000;
       
  2799         ++dest; ++src;
       
  2800     }
       
  2801 }
       
  2802 
       
  2803 static void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest,
       
  2804                                                                int length,
       
  2805                                                                uint color,
       
  2806                                                                uint const_alpha)
       
  2807 {
       
  2808     Q_UNUSED(const_alpha);
       
  2809     while (length--) {
       
  2810         *dest = (color & ~(*dest)) | 0xff000000;
       
  2811         ++dest;
       
  2812     }
       
  2813 }
       
  2814 
       
  2815 static void QT_FASTCALL rasterop_SourceAndNotDestination(uint *dest,
       
  2816                                                          const uint *src,
       
  2817                                                          int length,
       
  2818                                                          uint const_alpha)
       
  2819 {
       
  2820     Q_UNUSED(const_alpha);
       
  2821     while (length--) {
       
  2822         *dest = (*src & ~(*dest)) | 0xff000000;
       
  2823         ++dest; ++src;
       
  2824     }
       
  2825 }
       
  2826 
       
  2827 static const CompositionFunctionSolid functionForModeSolid_C[] = {
       
  2828         comp_func_solid_SourceOver,
       
  2829         comp_func_solid_DestinationOver,
       
  2830         comp_func_solid_Clear,
       
  2831         comp_func_solid_Source,
       
  2832         comp_func_solid_Destination,
       
  2833         comp_func_solid_SourceIn,
       
  2834         comp_func_solid_DestinationIn,
       
  2835         comp_func_solid_SourceOut,
       
  2836         comp_func_solid_DestinationOut,
       
  2837         comp_func_solid_SourceAtop,
       
  2838         comp_func_solid_DestinationAtop,
       
  2839         comp_func_solid_XOR,
       
  2840         comp_func_solid_Plus,
       
  2841         comp_func_solid_Multiply,
       
  2842         comp_func_solid_Screen,
       
  2843         comp_func_solid_Overlay,
       
  2844         comp_func_solid_Darken,
       
  2845         comp_func_solid_Lighten,
       
  2846         comp_func_solid_ColorDodge,
       
  2847         comp_func_solid_ColorBurn,
       
  2848         comp_func_solid_HardLight,
       
  2849         comp_func_solid_SoftLight,
       
  2850         comp_func_solid_Difference,
       
  2851         comp_func_solid_Exclusion,
       
  2852         rasterop_solid_SourceOrDestination,
       
  2853         rasterop_solid_SourceAndDestination,
       
  2854         rasterop_solid_SourceXorDestination,
       
  2855         rasterop_solid_NotSourceAndNotDestination,
       
  2856         rasterop_solid_NotSourceOrNotDestination,
       
  2857         rasterop_solid_NotSourceXorDestination,
       
  2858         rasterop_solid_NotSource,
       
  2859         rasterop_solid_NotSourceAndDestination,
       
  2860         rasterop_solid_SourceAndNotDestination
       
  2861 };
       
  2862 
       
  2863 static const CompositionFunctionSolid *functionForModeSolid = functionForModeSolid_C;
       
  2864 
       
  2865 static const CompositionFunction functionForMode_C[] = {
       
  2866         comp_func_SourceOver,
       
  2867         comp_func_DestinationOver,
       
  2868         comp_func_Clear,
       
  2869         comp_func_Source,
       
  2870         comp_func_Destination,
       
  2871         comp_func_SourceIn,
       
  2872         comp_func_DestinationIn,
       
  2873         comp_func_SourceOut,
       
  2874         comp_func_DestinationOut,
       
  2875         comp_func_SourceAtop,
       
  2876         comp_func_DestinationAtop,
       
  2877         comp_func_XOR,
       
  2878         comp_func_Plus,
       
  2879         comp_func_Multiply,
       
  2880         comp_func_Screen,
       
  2881         comp_func_Overlay,
       
  2882         comp_func_Darken,
       
  2883         comp_func_Lighten,
       
  2884         comp_func_ColorDodge,
       
  2885         comp_func_ColorBurn,
       
  2886         comp_func_HardLight,
       
  2887         comp_func_SoftLight,
       
  2888         comp_func_Difference,
       
  2889         comp_func_Exclusion,
       
  2890         rasterop_SourceOrDestination,
       
  2891         rasterop_SourceAndDestination,
       
  2892         rasterop_SourceXorDestination,
       
  2893         rasterop_NotSourceAndNotDestination,
       
  2894         rasterop_NotSourceOrNotDestination,
       
  2895         rasterop_NotSourceXorDestination,
       
  2896         rasterop_NotSource,
       
  2897         rasterop_NotSourceAndDestination,
       
  2898         rasterop_SourceAndNotDestination
       
  2899 };
       
  2900 
       
  2901 static const CompositionFunction *functionForMode = functionForMode_C;
       
  2902 
       
  2903 static TextureBlendType getBlendType(const QSpanData *data)
       
  2904 {
       
  2905     TextureBlendType ft;
       
  2906     if (data->txop <= QTransform::TxTranslate)
       
  2907         if (data->texture.type == QTextureData::Tiled)
       
  2908             ft = BlendTiled;
       
  2909         else
       
  2910             ft = BlendUntransformed;
       
  2911     else if (data->bilinear)
       
  2912         if (data->texture.type == QTextureData::Tiled)
       
  2913             ft = BlendTransformedBilinearTiled;
       
  2914         else
       
  2915             ft = BlendTransformedBilinear;
       
  2916     else
       
  2917         if (data->texture.type == QTextureData::Tiled)
       
  2918             ft = BlendTransformedTiled;
       
  2919         else
       
  2920             ft = BlendTransformed;
       
  2921     return ft;
       
  2922 }
       
  2923 
       
  2924 static inline Operator getOperator(const QSpanData *data, const QSpan *spans, int spanCount)
       
  2925 {
       
  2926     Operator op;
       
  2927     bool solidSource = false;
       
  2928 
       
  2929     switch(data->type) {
       
  2930     case QSpanData::Solid:
       
  2931         solidSource = (qAlpha(data->solid.color) == 255);
       
  2932         break;
       
  2933     case QSpanData::LinearGradient:
       
  2934         solidSource = !data->gradient.alphaColor;
       
  2935         getLinearGradientValues(&op.linear, data);
       
  2936         op.src_fetch = fetchLinearGradient;
       
  2937         break;
       
  2938     case QSpanData::RadialGradient:
       
  2939         solidSource = !data->gradient.alphaColor;
       
  2940         getRadialGradientValues(&op.radial, data);
       
  2941         op.src_fetch = fetchRadialGradient;
       
  2942         break;
       
  2943     case QSpanData::ConicalGradient:
       
  2944         solidSource = !data->gradient.alphaColor;
       
  2945         op.src_fetch = fetchConicalGradient;
       
  2946         break;
       
  2947     case QSpanData::Texture:
       
  2948         op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format];
       
  2949         solidSource = !data->texture.hasAlpha;
       
  2950     default:
       
  2951         break;
       
  2952     }
       
  2953 
       
  2954     op.mode = data->rasterBuffer->compositionMode;
       
  2955     if (op.mode == QPainter::CompositionMode_SourceOver && solidSource)
       
  2956         op.mode = QPainter::CompositionMode_Source;
       
  2957 
       
  2958     op.dest_fetch = destFetchProc[data->rasterBuffer->format];
       
  2959     if (op.mode == QPainter::CompositionMode_Source) {
       
  2960         switch (data->rasterBuffer->format) {
       
  2961         case QImage::Format_RGB32:
       
  2962         case QImage::Format_ARGB32_Premultiplied:
       
  2963             // don't clear dest_fetch as it sets up the pointer correctly to save one copy
       
  2964             break;
       
  2965         default: {
       
  2966             const QSpan *lastSpan = spans + spanCount;
       
  2967             bool alphaSpans = false;
       
  2968             while (spans < lastSpan) {
       
  2969                 if (spans->coverage != 255) {
       
  2970                     alphaSpans = true;
       
  2971                     break;
       
  2972                 }
       
  2973                 ++spans;
       
  2974             }
       
  2975             if (!alphaSpans)
       
  2976                 op.dest_fetch = 0;
       
  2977         }
       
  2978         }
       
  2979     }
       
  2980 
       
  2981     op.dest_store = destStoreProc[data->rasterBuffer->format];
       
  2982 
       
  2983     op.funcSolid = functionForModeSolid[op.mode];
       
  2984     op.func = functionForMode[op.mode];
       
  2985 
       
  2986     return op;
       
  2987 }
       
  2988 
       
  2989 
       
  2990 
       
  2991 // -------------------- blend methods ---------------------
       
  2992 
       
  2993 enum SpanMethod {
       
  2994     RegularSpans,
       
  2995     CallbackSpans
       
  2996 };
       
  2997 
       
  2998 #if !defined(Q_CC_SUN)
       
  2999 static
       
  3000 #endif
       
  3001 void drawBufferSpan(QSpanData *data, const uint *buffer, int bufsize,
       
  3002                            int x, int y, int length, uint const_alpha)
       
  3003 {
       
  3004 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
       
  3005     data->rasterEngine->drawBufferSpan(buffer, bufsize, x, y, length, const_alpha);
       
  3006 #else
       
  3007     Q_UNUSED(data);
       
  3008     Q_UNUSED(buffer);
       
  3009     Q_UNUSED(bufsize);
       
  3010     Q_UNUSED(x);
       
  3011     Q_UNUSED(y);
       
  3012     Q_UNUSED(length);
       
  3013     Q_UNUSED(const_alpha);
       
  3014 #endif
       
  3015 }
       
  3016 
       
  3017 #if !defined(Q_CC_SUN)
       
  3018 static
       
  3019 #endif
       
  3020 void blend_color_generic(int count, const QSpan *spans, void *userData)
       
  3021 {
       
  3022     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  3023     uint buffer[buffer_size];
       
  3024     Operator op = getOperator(data, spans, count);
       
  3025 
       
  3026     while (count--) {
       
  3027         int x = spans->x;
       
  3028         int length = spans->len;
       
  3029         while (length) {
       
  3030             int l = qMin(buffer_size, length);
       
  3031             uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
       
  3032             op.funcSolid(dest, l, data->solid.color, spans->coverage);
       
  3033             if (op.dest_store)
       
  3034                 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
       
  3035             length -= l;
       
  3036             x += l;
       
  3037         }
       
  3038         ++spans;
       
  3039     }
       
  3040 }
       
  3041 
       
  3042 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
       
  3043 static void blend_color_generic_callback(int count, const QSpan *spans, void *userData)
       
  3044 {
       
  3045     // ### Falcon
       
  3046     Q_UNUSED(count);
       
  3047     Q_UNUSED(spans);
       
  3048     Q_UNUSED(userData);
       
  3049 //     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
       
  3050 //     data->rasterEngine->drawColorSpans(spans, count, data->solid.color);
       
  3051 }
       
  3052 #endif // QT_NO_RASTERCALLBACKS
       
  3053 
       
  3054 static void blend_color_argb(int count, const QSpan *spans, void *userData)
       
  3055 {
       
  3056     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  3057 
       
  3058     Operator op = getOperator(data, spans, count);
       
  3059 
       
  3060     if (op.mode == QPainter::CompositionMode_Source) {
       
  3061         // inline for performance
       
  3062         while (count--) {
       
  3063             uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
       
  3064             if (spans->coverage == 255) {
       
  3065                 QT_MEMFILL_UINT(target, spans->len, data->solid.color);
       
  3066             } else {
       
  3067                 uint c = BYTE_MUL(data->solid.color, spans->coverage);
       
  3068                 int ialpha = 255 - spans->coverage;
       
  3069                 for (int i = 0; i < spans->len; ++i)
       
  3070                     target[i] = c + BYTE_MUL(target[i], ialpha);
       
  3071             }
       
  3072             ++spans;
       
  3073         }
       
  3074         return;
       
  3075     }
       
  3076 
       
  3077     while (count--) {
       
  3078         uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
       
  3079         op.funcSolid(target, spans->len, data->solid.color, spans->coverage);
       
  3080         ++spans;
       
  3081     }
       
  3082 }
       
  3083 
       
  3084 template <class T>
       
  3085 Q_STATIC_TEMPLATE_FUNCTION void blendColor(int count, const QSpan *spans, void *userData)
       
  3086 {
       
  3087     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  3088     Operator op = getOperator(data, spans, count);
       
  3089 
       
  3090     if (op.mode == QPainter::CompositionMode_Source) {
       
  3091         const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(data->solid.color), 0);
       
  3092         while (count--) {
       
  3093             T *target = ((T*)data->rasterBuffer->scanLine(spans->y))
       
  3094                         + spans->x;
       
  3095             if (spans->coverage == 255) {
       
  3096                 qt_memfill(target, c, spans->len);
       
  3097             } else {
       
  3098                 const quint8 alpha = T::alpha(spans->coverage);
       
  3099                 const T color = c.byte_mul(alpha);
       
  3100                 const int ialpha = T::ialpha(spans->coverage);
       
  3101                 const T *end = target + spans->len;
       
  3102                 while (target < end) {
       
  3103                     *target = color + target->byte_mul(ialpha);
       
  3104                     ++target;
       
  3105                 }
       
  3106             }
       
  3107             ++spans;
       
  3108         }
       
  3109         return;
       
  3110     }
       
  3111 
       
  3112     if (op.mode == QPainter::CompositionMode_SourceOver) {
       
  3113         while (count--) {
       
  3114             const quint32 color = BYTE_MUL(data->solid.color, spans->coverage);
       
  3115             const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0);
       
  3116             const quint8 ialpha = T::alpha(qAlpha(~color));
       
  3117             T *target = ((T*)data->rasterBuffer->scanLine(spans->y)) + spans->x;
       
  3118             const T *end = target + spans->len;
       
  3119             while (target != end) {
       
  3120                 *target = c + target->byte_mul(ialpha);
       
  3121                 ++target;
       
  3122             }
       
  3123             ++spans;
       
  3124         }
       
  3125         return;
       
  3126     }
       
  3127 
       
  3128     blend_color_generic(count, spans, userData);
       
  3129 }
       
  3130 
       
  3131 #define SPANFUNC_POINTER_BLENDCOLOR(DST) blendColor<DST>
       
  3132 
       
  3133 static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
       
  3134 {
       
  3135     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  3136 
       
  3137     /*
       
  3138         We duplicate a little logic from getOperator() and calculate the
       
  3139         composition mode directly.  This allows blend_color_rgb16 to be used
       
  3140         from qt_gradient_quint16 with minimal overhead.
       
  3141      */
       
  3142     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
       
  3143     if (mode == QPainter::CompositionMode_SourceOver &&
       
  3144         qAlpha(data->solid.color) == 255)
       
  3145         mode = QPainter::CompositionMode_Source;
       
  3146 
       
  3147     if (mode == QPainter::CompositionMode_Source) {
       
  3148         // inline for performance
       
  3149         ushort c = qConvertRgb32To16(data->solid.color);
       
  3150         while (count--) {
       
  3151             ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
       
  3152             if (spans->coverage == 255) {
       
  3153                 QT_MEMFILL_USHORT(target, spans->len, c);
       
  3154             } else {
       
  3155                 ushort color = BYTE_MUL_RGB16(c, spans->coverage);
       
  3156                 int ialpha = 255 - spans->coverage;
       
  3157                 const ushort *end = target + spans->len;
       
  3158                 while (target < end) {
       
  3159                     *target = color + BYTE_MUL_RGB16(*target, ialpha);
       
  3160                     ++target;
       
  3161                 }
       
  3162             }
       
  3163             ++spans;
       
  3164         }
       
  3165         return;
       
  3166     }
       
  3167 
       
  3168     if (mode == QPainter::CompositionMode_SourceOver) {
       
  3169         while (count--) {
       
  3170             uint color = BYTE_MUL(data->solid.color, spans->coverage);
       
  3171             int ialpha = qAlpha(~color);
       
  3172             ushort c = qConvertRgb32To16(color);
       
  3173             ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
       
  3174             int len = spans->len;
       
  3175             bool pre = (((quintptr)target) & 0x3) != 0;
       
  3176             bool post = false;
       
  3177             if (pre) {
       
  3178                 // skip to word boundary
       
  3179                 *target = c + BYTE_MUL_RGB16(*target, ialpha);
       
  3180                 ++target;
       
  3181                 --len;
       
  3182             }
       
  3183             if (len & 0x1) {
       
  3184                 post = true;
       
  3185                 --len;
       
  3186             }
       
  3187             uint *target32 = (uint*)target;
       
  3188             uint c32 = c | (c<<16);
       
  3189             len >>= 1;
       
  3190             uint salpha = (ialpha+1) >> 3; // calculate here rather than in loop
       
  3191             while (len--) {
       
  3192                 // blend full words
       
  3193                 *target32 = c32 + BYTE_MUL_RGB16_32(*target32, salpha);
       
  3194                 ++target32;
       
  3195                 target += 2;
       
  3196             }
       
  3197             if (post) {
       
  3198                 // one last pixel beyond a full word
       
  3199                 *target = c + BYTE_MUL_RGB16(*target, ialpha);
       
  3200             }
       
  3201             ++spans;
       
  3202         }
       
  3203         return;
       
  3204     }
       
  3205 
       
  3206     blend_color_generic(count, spans, userData);
       
  3207 }
       
  3208 
       
  3209 template <typename T>
       
  3210 void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
       
  3211 {
       
  3212     uint const_alpha = 256;
       
  3213     if (data->type == QSpanData::Texture)
       
  3214         const_alpha = data->texture.const_alpha;
       
  3215 
       
  3216     int coverage = 0;
       
  3217     while (count) {
       
  3218         int x = spans->x;
       
  3219         const int y = spans->y;
       
  3220         int right = x + spans->len;
       
  3221 
       
  3222         // compute length of adjacent spans
       
  3223         for (int i = 1; i < count && spans[i].y == y && spans[i].x == right; ++i)
       
  3224             right += spans[i].len;
       
  3225         int length = right - x;
       
  3226 
       
  3227         while (length) {
       
  3228             int l = qMin(buffer_size, length);
       
  3229             length -= l;
       
  3230 
       
  3231             int process_length = l;
       
  3232             int process_x = x;
       
  3233 
       
  3234             const uint *src = handler.fetch(process_x, y, process_length);
       
  3235             int offset = 0;
       
  3236             while (l > 0) {
       
  3237                 if (x == spans->x) // new span?
       
  3238                     coverage = (spans->coverage * const_alpha) >> 8;
       
  3239 
       
  3240                 int right = spans->x + spans->len;
       
  3241                 int len = qMin(l, right - x);
       
  3242 
       
  3243                 handler.process(x, y, len, coverage, src, offset);
       
  3244 
       
  3245                 l -= len;
       
  3246                 x += len;
       
  3247                 offset += len;
       
  3248 
       
  3249                 if (x == right) { // done with current span?
       
  3250                     ++spans;
       
  3251                     --count;
       
  3252                 }
       
  3253             }
       
  3254             handler.store(process_x, y, process_length);
       
  3255         }
       
  3256     }
       
  3257 }
       
  3258 
       
  3259 struct QBlendBase
       
  3260 {
       
  3261     QBlendBase(QSpanData *d, Operator o)
       
  3262         : data(d)
       
  3263         , op(o)
       
  3264         , dest(0)
       
  3265     {
       
  3266     }
       
  3267 
       
  3268     QSpanData *data;
       
  3269     Operator op;
       
  3270 
       
  3271     uint *dest;
       
  3272 
       
  3273     uint buffer[buffer_size];
       
  3274     uint src_buffer[buffer_size];
       
  3275 };
       
  3276 
       
  3277 template <SpanMethod spanMethod>
       
  3278 class BlendSrcGeneric : public QBlendBase
       
  3279 {
       
  3280 public:
       
  3281     BlendSrcGeneric(QSpanData *d, Operator o)
       
  3282         : QBlendBase(d, o)
       
  3283     {
       
  3284     }
       
  3285 
       
  3286     const uint *fetch(int x, int y, int len)
       
  3287     {
       
  3288         if (spanMethod == RegularSpans)
       
  3289             dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, y, len) : buffer;
       
  3290 
       
  3291         return op.src_fetch(src_buffer, &op, data, y, x, len);
       
  3292     }
       
  3293 
       
  3294     void process(int x, int y, int len, int coverage, const uint *src, int offset)
       
  3295     {
       
  3296         if (spanMethod == RegularSpans)
       
  3297             op.func(dest + offset, src + offset, len, coverage);
       
  3298         else
       
  3299             drawBufferSpan(data, src + offset, len, x, y, len, coverage);
       
  3300     }
       
  3301 
       
  3302     void store(int x, int y, int len)
       
  3303     {
       
  3304         if (spanMethod == RegularSpans && op.dest_store) {
       
  3305             op.dest_store(data->rasterBuffer, x, y, dest, len);
       
  3306         }
       
  3307     }
       
  3308 };
       
  3309 
       
  3310 template <SpanMethod spanMethod>
       
  3311 Q_STATIC_TEMPLATE_FUNCTION void blend_src_generic(int count, const QSpan *spans, void *userData)
       
  3312 {
       
  3313     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  3314     BlendSrcGeneric<spanMethod> blend(data, getOperator(data, spans, count));
       
  3315     handleSpans(count, spans, data, blend);
       
  3316 }
       
  3317 
       
  3318 template <SpanMethod spanMethod>
       
  3319 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
       
  3320 {
       
  3321     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  3322 
       
  3323     uint buffer[buffer_size];
       
  3324     uint src_buffer[buffer_size];
       
  3325     Operator op = getOperator(data, spans, count);
       
  3326 
       
  3327     const int image_width = data->texture.width;
       
  3328     const int image_height = data->texture.height;
       
  3329     int xoff = -qRound(-data->dx);
       
  3330     int yoff = -qRound(-data->dy);
       
  3331 
       
  3332     while (count--) {
       
  3333         int x = spans->x;
       
  3334         int length = spans->len;
       
  3335         int sx = xoff + x;
       
  3336         int sy = yoff + spans->y;
       
  3337         if (sy >= 0 && sy < image_height && sx < image_width) {
       
  3338             if (sx < 0) {
       
  3339                 x -= sx;
       
  3340                 length += sx;
       
  3341                 sx = 0;
       
  3342             }
       
  3343             if (sx + length > image_width)
       
  3344                 length = image_width - sx;
       
  3345             if (length > 0) {
       
  3346                 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
       
  3347                 while (length) {
       
  3348                     int l = qMin(buffer_size, length);
       
  3349                     const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
       
  3350                     if (spanMethod == RegularSpans) {
       
  3351                         uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
       
  3352                         op.func(dest, src, l, coverage);
       
  3353                         if (op.dest_store)
       
  3354                             op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
       
  3355                     } else {
       
  3356                         drawBufferSpan(data, src, l, x, spans->y,
       
  3357                                        l, coverage);
       
  3358                     }
       
  3359                     x += l;
       
  3360                     sx += l;
       
  3361                     length -= l;
       
  3362                 }
       
  3363             }
       
  3364         }
       
  3365         ++spans;
       
  3366     }
       
  3367 }
       
  3368 
       
  3369 template <SpanMethod spanMethod>
       
  3370 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
       
  3371 {
       
  3372     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  3373     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
       
  3374         && data->texture.format != QImage::Format_RGB32) {
       
  3375         blend_untransformed_generic<spanMethod>(count, spans, userData);
       
  3376         return;
       
  3377     }
       
  3378 
       
  3379     Operator op = getOperator(data, spans, count);
       
  3380 
       
  3381     const int image_width = data->texture.width;
       
  3382     const int image_height = data->texture.height;
       
  3383     int xoff = -qRound(-data->dx);
       
  3384     int yoff = -qRound(-data->dy);
       
  3385 
       
  3386     while (count--) {
       
  3387         int x = spans->x;
       
  3388         int length = spans->len;
       
  3389         int sx = xoff + x;
       
  3390         int sy = yoff + spans->y;
       
  3391         if (sy >= 0 && sy < image_height && sx < image_width) {
       
  3392             if (sx < 0) {
       
  3393                 x -= sx;
       
  3394                 length += sx;
       
  3395                 sx = 0;
       
  3396             }
       
  3397             if (sx + length > image_width)
       
  3398                 length = image_width - sx;
       
  3399             if (length > 0) {
       
  3400                 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
       
  3401                 const uint *src = (uint *)data->texture.scanLine(sy) + sx;
       
  3402                 if (spanMethod == RegularSpans) {
       
  3403                     uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
       
  3404                     op.func(dest, src, length, coverage);
       
  3405                 } else {
       
  3406                     drawBufferSpan(data, src, length, x,
       
  3407                                    spans->y, length, coverage);
       
  3408                 }
       
  3409             }
       
  3410         }
       
  3411         ++spans;
       
  3412     }
       
  3413 }
       
  3414 
       
  3415 static inline quint16 interpolate_pixel_rgb16_255(quint16 x, quint8 a,
       
  3416                                                   quint16 y, quint8 b)
       
  3417 {
       
  3418     quint16 t = ((((x & 0x07e0) * a) + ((y & 0x07e0) * b)) >> 5) & 0x07e0;
       
  3419     t |= ((((x & 0xf81f) * a) + ((y & 0xf81f) * b)) >> 5) & 0xf81f;
       
  3420 
       
  3421     return t;
       
  3422 }
       
  3423 
       
  3424 static inline quint32 interpolate_pixel_rgb16x2_255(quint32 x, quint8 a,
       
  3425                                                     quint32 y, quint8 b)
       
  3426 {
       
  3427     uint t;
       
  3428     t = ((((x & 0xf81f07e0) >> 5) * a) + (((y & 0xf81f07e0) >> 5) * b)) & 0xf81f07e0;
       
  3429     t |= ((((x & 0x07e0f81f) * a) + ((y & 0x07e0f81f) * b)) >> 5) & 0x07e0f81f;
       
  3430     return t;
       
  3431 }
       
  3432 
       
  3433 static inline void blend_sourceOver_rgb16_rgb16(quint16 *dest,
       
  3434                                                 const quint16 *src,
       
  3435                                                 int length,
       
  3436                                                 const quint8 alpha,
       
  3437                                                 const quint8 ialpha)
       
  3438 {
       
  3439     const int dstAlign = ((quintptr)dest) & 0x3;
       
  3440     if (dstAlign) {
       
  3441         *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
       
  3442         ++dest;
       
  3443         ++src;
       
  3444         --length;
       
  3445     }
       
  3446     const int srcAlign = ((quintptr)src) & 0x3;
       
  3447     int length32 = length >> 1;
       
  3448     if (length32 && srcAlign == 0) {
       
  3449         while (length32--) {
       
  3450             const quint32 *src32 = reinterpret_cast<const quint32*>(src);
       
  3451             quint32 *dest32 = reinterpret_cast<quint32*>(dest);
       
  3452             *dest32 = interpolate_pixel_rgb16x2_255(*src32, alpha,
       
  3453                                                     *dest32, ialpha);
       
  3454             dest += 2;
       
  3455             src += 2;
       
  3456         }
       
  3457         length &= 0x1;
       
  3458     }
       
  3459     while (length--) {
       
  3460         *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
       
  3461         ++dest;
       
  3462         ++src;
       
  3463     }
       
  3464 }
       
  3465 
       
  3466 template <class DST, class SRC>
       
  3467 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3468 inline void madd_2(DST *dest, const quint16 alpha, const SRC *src)
       
  3469 {
       
  3470     Q_ASSERT((quintptr(dest) & 0x3) == 0);
       
  3471     Q_ASSERT((quintptr(src) & 0x3) == 0);
       
  3472     dest[0] = dest[0].byte_mul(alpha >> 8) + DST(src[0]);
       
  3473     dest[1] = dest[1].byte_mul(alpha & 0xff) + DST(src[1]);
       
  3474 }
       
  3475 
       
  3476 template <class DST, class SRC>
       
  3477 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3478 inline void madd_4(DST *dest, const quint32 alpha, const SRC *src)
       
  3479 {
       
  3480     Q_ASSERT((quintptr(dest) & 0x3) == 0);
       
  3481     Q_ASSERT((quintptr(src) & 0x3) == 0);
       
  3482     dest[0] = dest[0].byte_mul(alpha >> 24) + DST(src[0]);
       
  3483     dest[1] = dest[1].byte_mul((alpha >> 16) & 0xff) + DST(src[1]);
       
  3484     dest[2] = dest[2].byte_mul((alpha >> 8) & 0xff) + DST(src[2]);
       
  3485     dest[3] = dest[3].byte_mul(alpha & 0xff) + DST(src[3]);
       
  3486 }
       
  3487 
       
  3488 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
       
  3489 template <>
       
  3490 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3491 inline void madd_4(qargb8565 *dest, const quint32 a, const qargb8565 *src)
       
  3492 {
       
  3493     Q_ASSERT((quintptr(dest) & 0x3) == 0);
       
  3494     Q_ASSERT((quintptr(src) & 0x3) == 0);
       
  3495 
       
  3496     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
       
  3497     quint32 *dest32 = reinterpret_cast<quint32*>(dest);
       
  3498     quint32 x, y, t;
       
  3499     quint8 a8;
       
  3500 
       
  3501     {
       
  3502         x = dest32[0];
       
  3503         y = src32[0];
       
  3504 
       
  3505         a8 = a >> 24;
       
  3506 
       
  3507         // a0,g0
       
  3508         t = ((((x & 0x0007e0ff) * a8) >> 5) & 0x0007e0ff) + (y & 0x0007c0f8);
       
  3509 
       
  3510         // r0,b0
       
  3511         t |= ((((x & 0x00f81f00) * a8) >> 5) & 0x00f81f00) + (y & 0x00f81f00);
       
  3512 
       
  3513         a8 = (a >> 16) & 0xff;
       
  3514 
       
  3515         // a1
       
  3516         t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
       
  3517 
       
  3518         dest32[0] = t;
       
  3519     }
       
  3520     {
       
  3521         x = dest32[1];
       
  3522         y = src32[1];
       
  3523 
       
  3524         // r1,b1
       
  3525         t = ((((x & 0x0000f81f) * a8) >> 5) & 0x0000f81f) + (y & 0x0000f81f);
       
  3526 
       
  3527         // g1
       
  3528         t |= ((((x & 0x000007e0) * a8) >> 5) & 0x000007e0) + (y & 0x000007c0);
       
  3529 
       
  3530         a8 = (a >> 8) & 0xff;
       
  3531 
       
  3532         // a2
       
  3533         t |= ((((x & 0x00ff0000) * a8) >> 5)  & 0x00ff0000) + (y & 0x00f80000);
       
  3534 
       
  3535         {
       
  3536             // rgb2
       
  3537             quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
       
  3538             quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
       
  3539             quint16 t16;
       
  3540 
       
  3541             t16 = ((((x16 & 0xf81f) * a8) >> 5) & 0xf81f)  + (y16 & 0xf81f);
       
  3542             t16 |= ((((x16 & 0x07e0) * a8) >> 5) & 0x07e0)  + (y16 & 0x07c0);
       
  3543 
       
  3544             // rg2
       
  3545             t |= ((t16 & 0x00ff) << 24);
       
  3546 
       
  3547             dest32[1] = t;
       
  3548 
       
  3549             x = dest32[2];
       
  3550             y = src32[2];
       
  3551 
       
  3552             // gb2
       
  3553             t = (t16 >> 8);
       
  3554         }
       
  3555     }
       
  3556     {
       
  3557         a8 = a & 0xff;
       
  3558 
       
  3559         // g3,a3
       
  3560         t |= ((((x & 0x07e0ff00) * a8) >> 5) & 0x07e0ff00) + (y & 0x07c0f800);
       
  3561 
       
  3562         // r3,b3
       
  3563         t |= ((((x & 0xf81f0000) >> 5) * a8) & 0xf81f0000)+ (y & 0xf81f0000);
       
  3564 
       
  3565         dest32[2] = t;
       
  3566     }
       
  3567 }
       
  3568 #endif
       
  3569 
       
  3570 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
       
  3571 template <>
       
  3572 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3573 inline void madd_4(qargb8555 *dest, const quint32 a, const qargb8555 *src)
       
  3574 {
       
  3575     Q_ASSERT((quintptr(dest) & 0x3) == 0);
       
  3576     Q_ASSERT((quintptr(src) & 0x3) == 0);
       
  3577 
       
  3578     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
       
  3579     quint32 *dest32 = reinterpret_cast<quint32*>(dest);
       
  3580     quint32 x, y, t;
       
  3581     quint8 a8;
       
  3582 
       
  3583     {
       
  3584         x = dest32[0];
       
  3585         y = src32[0];
       
  3586 
       
  3587         a8 = a >> 24;
       
  3588 
       
  3589         // a0,g0
       
  3590         t = ((((x & 0x0003e0ff) * a8) >> 5) & 0x0003e0ff) + (y & 0x0003e0f8);
       
  3591 
       
  3592         // r0,b0
       
  3593         t |= ((((x & 0x007c1f00) * a8) >> 5) & 0x007c1f00) + (y & 0x007c1f00);
       
  3594 
       
  3595         a8 = (a >> 16) & 0xff;
       
  3596 
       
  3597         // a1
       
  3598         t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
       
  3599 
       
  3600         dest32[0] = t;
       
  3601     }
       
  3602     {
       
  3603         x = dest32[1];
       
  3604         y = src32[1];
       
  3605 
       
  3606         // r1,b1
       
  3607         t = ((((x & 0x00007c1f) * a8) >> 5) & 0x00007c1f) + (y & 0x00007c1f);
       
  3608 
       
  3609         // g1
       
  3610         t |= ((((x & 0x000003e0) * a8) >> 5) & 0x000003e0) + (y & 0x000003e0);
       
  3611 
       
  3612         a8 = (a >> 8) & 0xff;
       
  3613 
       
  3614         // a2
       
  3615         t |= ((((x & 0x00ff0000) * a8) >> 5)  & 0x00ff0000) + (y & 0x00f80000);
       
  3616 
       
  3617         {
       
  3618             // rgb2
       
  3619             quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
       
  3620             quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
       
  3621             quint16 t16;
       
  3622 
       
  3623             t16 = ((((x16 & 0x7c1f) * a8) >> 5) & 0x7c1f)  + (y16 & 0x7c1f);
       
  3624             t16 |= ((((x16 & 0x03e0) * a8) >> 5) & 0x03e0)  + (y16 & 0x03e0);
       
  3625 
       
  3626             // rg2
       
  3627             t |= ((t16 & 0x00ff) << 24);
       
  3628 
       
  3629             dest32[1] = t;
       
  3630 
       
  3631             x = dest32[2];
       
  3632             y = src32[2];
       
  3633 
       
  3634             // gb2
       
  3635             t = (t16 >> 8);
       
  3636         }
       
  3637     }
       
  3638     {
       
  3639         a8 = a & 0xff;
       
  3640 
       
  3641         // g3,a3
       
  3642         t |= ((((x & 0x03e0ff00) * a8) >> 5) & 0x03e0ff00) + (y & 0x03e0f800);
       
  3643 
       
  3644         // r3,b3
       
  3645         t |= ((((x & 0x7c1f0000) >> 5) * a8) & 0x7c1f0000)+ (y & 0x7c1f0000);
       
  3646 
       
  3647         dest32[2] = t;
       
  3648     }
       
  3649 }
       
  3650 #endif
       
  3651 
       
  3652 template <class T>
       
  3653 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3654 inline quint16 alpha_2(const T *src)
       
  3655 {
       
  3656     Q_ASSERT((quintptr(src) & 0x3) == 0);
       
  3657 
       
  3658     if (T::hasAlpha())
       
  3659         return (src[0].alpha() << 8) | src[1].alpha();
       
  3660     else
       
  3661         return 0xffff;
       
  3662 }
       
  3663 
       
  3664 template <class T>
       
  3665 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3666 inline quint32 alpha_4(const T *src)
       
  3667 {
       
  3668     Q_ASSERT((quintptr(src) & 0x3) == 0);
       
  3669 
       
  3670     if (T::hasAlpha()) {
       
  3671         return (src[0].alpha() << 24) | (src[1].alpha() << 16)
       
  3672             | (src[2].alpha() << 8) | src[3].alpha();
       
  3673     } else {
       
  3674         return 0xffffffff;
       
  3675     }
       
  3676 }
       
  3677 
       
  3678 template <>
       
  3679 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3680 inline quint32 alpha_4(const qargb8565 *src)
       
  3681 {
       
  3682     const quint8 *src8 = reinterpret_cast<const quint8*>(src);
       
  3683     return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
       
  3684 }
       
  3685 
       
  3686 template <>
       
  3687 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3688 inline quint32 alpha_4(const qargb6666 *src)
       
  3689 {
       
  3690     const quint8 *src8 = reinterpret_cast<const quint8*>(src);
       
  3691     return ((src8[2] & 0xfc) | (src8[2] >> 6)) << 24
       
  3692         | ((src8[5] & 0xfc) | (src8[5] >> 6))  << 16
       
  3693         | ((src8[8] & 0xfc) | (src8[8] >> 6)) << 8
       
  3694         | ((src8[11] & 0xfc) | (src8[11] >> 6));
       
  3695 }
       
  3696 
       
  3697 template <>
       
  3698 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3699 inline quint32 alpha_4(const qargb8555 *src)
       
  3700 {
       
  3701     Q_ASSERT((long(src) & 0x3) == 0);
       
  3702     const quint8 *src8 = reinterpret_cast<const quint8*>(src);
       
  3703     return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
       
  3704 }
       
  3705 
       
  3706 template <>
       
  3707 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3708 inline quint16 alpha_2(const qargb4444 *src)
       
  3709 {
       
  3710     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
       
  3711     const quint32 t = (*src32 & 0xf000f000) |
       
  3712                       ((*src32 & 0xf000f000) >> 4);
       
  3713     return (t >> 24) | (t & 0xff00);
       
  3714 }
       
  3715 
       
  3716 template <class T>
       
  3717 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3718 inline quint16 eff_alpha_2(quint16 alpha, const T*)
       
  3719 {
       
  3720     return (T::alpha((alpha >> 8) & 0xff) << 8)
       
  3721         | T::alpha(alpha & 0xff);
       
  3722 }
       
  3723 
       
  3724 template <>
       
  3725 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3726 inline quint16 eff_alpha_2(quint16 a, const qrgb565*)
       
  3727 {
       
  3728     return ((((a & 0xff00) + 0x0100) >> 3) & 0xff00)
       
  3729         | ((((a & 0x00ff) + 0x0001) >> 3) & 0x00ff);
       
  3730 }
       
  3731 
       
  3732 template <>
       
  3733 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3734 inline quint16 eff_alpha_2(quint16 a, const qrgb444*)
       
  3735 {
       
  3736     return (((a & 0x00ff) + 0x0001) >> 4)
       
  3737         | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
       
  3738 }
       
  3739 
       
  3740 template <>
       
  3741 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3742 inline quint16 eff_alpha_2(quint16 a, const qargb4444*)
       
  3743 {
       
  3744     return (((a & 0x00ff) + 0x0001) >> 4)
       
  3745         | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
       
  3746 }
       
  3747 
       
  3748 template <class T>
       
  3749 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3750 inline quint16 eff_ialpha_2(quint16 alpha, const T*)
       
  3751 {
       
  3752     return (T::ialpha((alpha >> 8) & 0xff) << 8)
       
  3753         | T::ialpha(alpha & 0xff);
       
  3754 }
       
  3755 
       
  3756 template <>
       
  3757 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3758 inline quint16 eff_ialpha_2(quint16 a, const qrgb565 *dummy)
       
  3759 {
       
  3760     return 0x2020 - eff_alpha_2(a, dummy);
       
  3761 }
       
  3762 
       
  3763 template <>
       
  3764 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3765 inline quint16 eff_ialpha_2(quint16 a, const qargb4444 *dummy)
       
  3766 {
       
  3767     return 0x1010 - eff_alpha_2(a, dummy);
       
  3768 }
       
  3769 
       
  3770 template <>
       
  3771 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3772 inline quint16 eff_ialpha_2(quint16 a, const qrgb444 *dummy)
       
  3773 {
       
  3774     return 0x1010 - eff_alpha_2(a, dummy);
       
  3775 }
       
  3776 
       
  3777 template <class T>
       
  3778 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3779 inline quint32 eff_alpha_4(quint32 alpha, const T*)
       
  3780 {
       
  3781     return (T::alpha(alpha >> 24) << 24)
       
  3782         | (T::alpha((alpha >> 16) & 0xff) << 16)
       
  3783         | (T::alpha((alpha >> 8) & 0xff) << 8)
       
  3784         | T::alpha(alpha & 0xff);
       
  3785 }
       
  3786 
       
  3787 template <>
       
  3788 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3789 inline quint32 eff_alpha_4(quint32 a, const qrgb888*)
       
  3790 {
       
  3791     return a;
       
  3792 }
       
  3793 
       
  3794 template <>
       
  3795 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3796 inline quint32 eff_alpha_4(quint32 a, const qargb8565*)
       
  3797 {
       
  3798     return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
       
  3799         | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
       
  3800 }
       
  3801 
       
  3802 template <>
       
  3803 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3804 inline quint32 eff_alpha_4(quint32 a, const qargb6666*)
       
  3805 {
       
  3806     return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
       
  3807         | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
       
  3808 }
       
  3809 
       
  3810 template <>
       
  3811 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3812 inline quint32 eff_alpha_4(quint32 a, const qrgb666*)
       
  3813 {
       
  3814     return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
       
  3815         | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
       
  3816 }
       
  3817 
       
  3818 template <>
       
  3819 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3820 inline quint32 eff_alpha_4(quint32 a, const qargb8555*)
       
  3821 {
       
  3822     return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
       
  3823         | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
       
  3824 }
       
  3825 
       
  3826 template <class T>
       
  3827 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3828 inline quint32 eff_ialpha_4(quint32 alpha, const T*)
       
  3829 {
       
  3830     return (T::ialpha(alpha >> 24) << 24)
       
  3831         | (T::ialpha((alpha >> 16) & 0xff) << 16)
       
  3832         | (T::ialpha((alpha >> 8) & 0xff) << 8)
       
  3833         | T::ialpha(alpha & 0xff);
       
  3834 }
       
  3835 
       
  3836 template <>
       
  3837 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3838 inline quint32 eff_ialpha_4(quint32 a, const qrgb888*)
       
  3839 {
       
  3840     return ~a;
       
  3841 }
       
  3842 
       
  3843 template <>
       
  3844 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3845 inline quint32 eff_ialpha_4(quint32 a, const qargb8565 *dummy)
       
  3846 {
       
  3847     return 0x20202020 - eff_alpha_4(a, dummy);
       
  3848 }
       
  3849 
       
  3850 template <>
       
  3851 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3852 inline quint32 eff_ialpha_4(quint32 a, const qargb6666 *dummy)
       
  3853 {
       
  3854     return 0x40404040 - eff_alpha_4(a, dummy);
       
  3855 }
       
  3856 
       
  3857 template <>
       
  3858 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3859 inline quint32 eff_ialpha_4(quint32 a, const qrgb666 *dummy)
       
  3860 {
       
  3861     return 0x40404040 - eff_alpha_4(a, dummy);
       
  3862 }
       
  3863 
       
  3864 template <>
       
  3865 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  3866 inline quint32 eff_ialpha_4(quint32 a, const qargb8555 *dummy)
       
  3867 {
       
  3868     return 0x20202020 - eff_alpha_4(a, dummy);
       
  3869 }
       
  3870 
       
  3871 template <class DST, class SRC>
       
  3872 inline void interpolate_pixel_unaligned_2(DST *dest, const SRC *src,
       
  3873                                           quint16 alpha)
       
  3874 {
       
  3875     const quint16 a = eff_alpha_2(alpha, dest);
       
  3876     const quint16 ia = eff_ialpha_2(alpha, dest);
       
  3877     dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
       
  3878     dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
       
  3879 }
       
  3880 
       
  3881 template <class DST, class SRC>
       
  3882 inline void interpolate_pixel_2(DST *dest, const SRC *src, quint16 alpha)
       
  3883 {
       
  3884     Q_ASSERT((long(dest) & 0x3) == 0);
       
  3885     Q_ASSERT((long(src) & 0x3) == 0);
       
  3886 
       
  3887     const quint16 a = eff_alpha_2(alpha, dest);
       
  3888     const quint16 ia = eff_ialpha_2(alpha, dest);
       
  3889 
       
  3890     dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
       
  3891     dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
       
  3892 }
       
  3893 
       
  3894 template <class DST, class SRC>
       
  3895 inline void interpolate_pixel(DST &dest, quint8 a, const SRC &src, quint8 b)
       
  3896 {
       
  3897     if (SRC::hasAlpha() && !DST::hasAlpha())
       
  3898         interpolate_pixel(dest, a, DST(src), b);
       
  3899     else
       
  3900         dest = dest.byte_mul(a) + DST(src).byte_mul(b);
       
  3901 }
       
  3902 
       
  3903 template <>
       
  3904 inline void interpolate_pixel(qargb8565 &dest, quint8 a,
       
  3905                               const qargb8565 &src, quint8 b)
       
  3906 {
       
  3907     quint8 *d = reinterpret_cast<quint8*>(&dest);
       
  3908     const quint8 *s = reinterpret_cast<const quint8*>(&src);
       
  3909     d[0] = (d[0] * a + s[0] * b) >> 5;
       
  3910 
       
  3911     const quint16 x = (d[2] << 8) | d[1];
       
  3912     const quint16 y = (s[2] << 8) | s[1];
       
  3913     quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
       
  3914     t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
       
  3915 
       
  3916     d[1] = t & 0xff;
       
  3917     d[2] = t >> 8;
       
  3918 }
       
  3919 
       
  3920 template <>
       
  3921 inline void interpolate_pixel(qrgb565 &dest, quint8 a,
       
  3922                               const qrgb565 &src, quint8 b)
       
  3923 {
       
  3924     const quint16 x = dest.rawValue();
       
  3925     const quint16 y = src.rawValue();
       
  3926     quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
       
  3927     t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
       
  3928     dest = t;
       
  3929 }
       
  3930 
       
  3931 template <>
       
  3932 inline void interpolate_pixel(qrgb555 &dest, quint8 a,
       
  3933                               const qrgb555 &src, quint8 b)
       
  3934 {
       
  3935     const quint16 x = dest.rawValue();
       
  3936     const quint16 y = src.rawValue();
       
  3937     quint16 t = (((x & 0x03e0) * a + (y & 0x03e0) * b) >> 5) & 0x03e0;
       
  3938     t |= ((((x & 0x7c1f) * a) + ((y & 0x7c1f) * b)) >> 5) & 0x7c1f;
       
  3939     dest = t;
       
  3940 }
       
  3941 
       
  3942 template <>
       
  3943 inline void interpolate_pixel(qrgb444 &dest, quint8 a,
       
  3944                               const qrgb444 &src, quint8 b)
       
  3945 {
       
  3946     const quint16 x = dest.rawValue();
       
  3947     const quint16 y = src.rawValue();
       
  3948     quint16 t = ((x & 0x00f0) * a + (y & 0x00f0) * b) & 0x0f00;
       
  3949     t |= ((x & 0x0f0f) * a + (y & 0x0f0f) * b) & 0xf0f0;
       
  3950     quint16 *d = reinterpret_cast<quint16*>(&dest);
       
  3951     *d = (t >> 4);
       
  3952 }
       
  3953 
       
  3954 template <class DST, class SRC>
       
  3955 inline void interpolate_pixel_2(DST *dest, quint8 a,
       
  3956                                 const SRC *src, quint8 b)
       
  3957 {
       
  3958     Q_ASSERT((long(dest) & 0x3) == 0);
       
  3959     Q_ASSERT((long(src) & 0x3) == 0);
       
  3960 
       
  3961     Q_ASSERT(!SRC::hasAlpha());
       
  3962 
       
  3963     dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
       
  3964     dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
       
  3965 }
       
  3966 
       
  3967 template <>
       
  3968 inline void interpolate_pixel_2(qrgb565 *dest, quint8 a,
       
  3969                                 const qrgb565 *src, quint8 b)
       
  3970 {
       
  3971     quint32 *x = reinterpret_cast<quint32*>(dest);
       
  3972     const quint32 *y = reinterpret_cast<const quint32*>(src);
       
  3973     quint32 t = (((*x & 0xf81f07e0) >> 5) * a +
       
  3974                  ((*y & 0xf81f07e0) >> 5) * b) & 0xf81f07e0;
       
  3975     t |= (((*x & 0x07e0f81f) * a
       
  3976            + (*y & 0x07e0f81f) * b) >> 5) & 0x07e0f81f;
       
  3977     *x = t;
       
  3978 }
       
  3979 
       
  3980 template <>
       
  3981 inline void interpolate_pixel_2(qrgb555 *dest, quint8 a,
       
  3982                                 const qrgb555 *src, quint8 b)
       
  3983 {
       
  3984     quint32 *x = reinterpret_cast<quint32*>(dest);
       
  3985     const quint32 *y = reinterpret_cast<const quint32*>(src);
       
  3986     quint32 t = (((*x & 0x7c1f03e0) >> 5) * a +
       
  3987                  ((*y & 0x7c1f03e0) >> 5) * b) & 0x7c1f03e0;
       
  3988     t |= (((*x & 0x03e07c1f) * a
       
  3989            + (*y & 0x03e07c1f) * b) >> 5) & 0x03e07c1f;
       
  3990     *x = t;
       
  3991 }
       
  3992 
       
  3993 template <>
       
  3994 inline void interpolate_pixel_2(qrgb444 *dest, quint8 a,
       
  3995                                 const qrgb444 *src, quint8 b)
       
  3996 {
       
  3997     quint32 *x = reinterpret_cast<quint32*>(dest);
       
  3998     const quint32 *y = reinterpret_cast<const quint32*>(src);
       
  3999     quint32 t = ((*x & 0x0f0f0f0f) * a + (*y & 0x0f0f0f0f) * b) & 0xf0f0f0f0;
       
  4000     t |= ((*x & 0x00f000f0) * a + (*y & 0x00f000f0) * b) & 0x0f000f00;
       
  4001     *x = t >> 4;
       
  4002 }
       
  4003 
       
  4004 template <class DST, class SRC>
       
  4005 inline void interpolate_pixel_4(DST *dest, const SRC *src, quint32 alpha)
       
  4006 {
       
  4007     Q_ASSERT((long(dest) & 0x3) == 0);
       
  4008     Q_ASSERT((long(src) & 0x3) == 0);
       
  4009 
       
  4010     const quint32 a = eff_alpha_4(alpha, dest);
       
  4011     const quint32 ia = eff_ialpha_4(alpha, dest);
       
  4012     dest[0] = DST(src[0]).byte_mul(a >> 24)
       
  4013               + dest[0].byte_mul(ia >> 24);
       
  4014     dest[1] = DST(src[1]).byte_mul((a >> 16) & 0xff)
       
  4015               + dest[1].byte_mul((ia >> 16) & 0xff);
       
  4016     dest[2] = DST(src[2]).byte_mul((a >> 8) & 0xff)
       
  4017               + dest[2].byte_mul((ia >> 8) & 0xff);
       
  4018     dest[3] = DST(src[3]).byte_mul(a & 0xff)
       
  4019               + dest[3].byte_mul(ia & 0xff);
       
  4020 }
       
  4021 
       
  4022 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
       
  4023 template <>
       
  4024 inline void interpolate_pixel_4(qargb8565 *dest, const qargb8565 *src,
       
  4025                                 quint32 alpha)
       
  4026 {
       
  4027     Q_ASSERT((long(dest) & 0x3) == 0);
       
  4028     Q_ASSERT((long(src) & 0x3) == 0);
       
  4029 
       
  4030     const quint32 a = eff_alpha_4(alpha, dest);
       
  4031     const quint32 ia = eff_ialpha_4(alpha, dest);
       
  4032     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
       
  4033     quint32 *dest32 = reinterpret_cast<quint32*>(dest);
       
  4034 
       
  4035     quint32 x, y, t;
       
  4036     quint8 a8, ia8;
       
  4037     {
       
  4038         x = src32[0];
       
  4039         y = dest32[0];
       
  4040 
       
  4041         a8 = a >> 24;
       
  4042         ia8 = ia >> 24;
       
  4043 
       
  4044         // a0,g0
       
  4045         t = (((x & 0x0007e0ff) * a8 + (y & 0x0007e0ff) * ia8) >> 5)
       
  4046             & 0x0007e0ff;
       
  4047 
       
  4048         // r0,b0
       
  4049         t |= (((x & 0x00f81f00) * a8 + (y & 0x00f81f00) * ia8) >> 5)
       
  4050              & 0x00f81f00;
       
  4051 
       
  4052         a8 = (a >> 16) & 0xff;
       
  4053         ia8 = (ia >> 16) & 0xff;
       
  4054 
       
  4055         // a1
       
  4056         t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
       
  4057              & 0xff000000;
       
  4058 
       
  4059         dest32[0] = t;
       
  4060     }
       
  4061     {
       
  4062         x = src32[1];
       
  4063         y = dest32[1];
       
  4064 
       
  4065         // r1,b1
       
  4066         t = (((x & 0x0000f81f) * a8 + (y & 0x0000f81f) * ia8) >> 5)
       
  4067             & 0x0000f81f;
       
  4068 
       
  4069         // g1
       
  4070         t |= (((x & 0x000007e0) * a8 + (y & 0x000007e0) * ia8) >> 5)
       
  4071              & 0x000007e0;
       
  4072 
       
  4073         a8 = (a >> 8) & 0xff;
       
  4074         ia8 = (ia >> 8) & 0xff;
       
  4075 
       
  4076         // a2
       
  4077         t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
       
  4078              & 0x00ff0000;
       
  4079 
       
  4080         {
       
  4081             // rgb2
       
  4082             quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
       
  4083             quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
       
  4084             quint16 t16;
       
  4085 
       
  4086             t16 = (((x16 & 0xf81f) * a8 + (y16 & 0xf81f) * ia8) >> 5) & 0xf81f;
       
  4087             t16 |= (((x16 & 0x07e0) * a8 + (y16 & 0x07e0) * ia8) >> 5) & 0x07e0;
       
  4088 
       
  4089             // rg2
       
  4090             t |= ((t16 & 0x00ff) << 24);
       
  4091 
       
  4092             dest32[1] = t;
       
  4093 
       
  4094             x = src32[2];
       
  4095             y = dest32[2];
       
  4096 
       
  4097             // gb2
       
  4098             t = (t16 >> 8);
       
  4099         }
       
  4100     }
       
  4101     {
       
  4102         a8 = a & 0xff;
       
  4103         ia8 = ia & 0xff;
       
  4104 
       
  4105         // g3,a3
       
  4106         t |= (((x & 0x07e0ff00) * a8 + (y & 0x07e0ff00) * ia8) >> 5)
       
  4107              & 0x07e0ff00;
       
  4108 
       
  4109         // r3,b3
       
  4110         t |= (((x & 0xf81f0000) >> 5) * a8 + ((y & 0xf81f0000) >> 5) * ia8)
       
  4111              & 0xf81f0000;
       
  4112 
       
  4113         dest32[2] = t;
       
  4114     }
       
  4115 }
       
  4116 #endif
       
  4117 
       
  4118 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
       
  4119 template <>
       
  4120 inline void interpolate_pixel_4(qargb8555 *dest, const qargb8555 *src,
       
  4121                                 quint32 alpha)
       
  4122 {
       
  4123     Q_ASSERT((long(dest) & 0x3) == 0);
       
  4124     Q_ASSERT((long(src) & 0x3) == 0);
       
  4125 
       
  4126 
       
  4127     const quint32 a = eff_alpha_4(alpha, dest);
       
  4128     const quint32 ia = eff_ialpha_4(alpha, dest);
       
  4129     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
       
  4130     quint32 *dest32 = reinterpret_cast<quint32*>(dest);
       
  4131 
       
  4132     quint32 x, y, t;
       
  4133     quint8 a8, ia8;
       
  4134     {
       
  4135         x = src32[0];
       
  4136         y = dest32[0];
       
  4137 
       
  4138         a8 = a >> 24;
       
  4139         ia8 = ia >> 24;
       
  4140 
       
  4141         // a0,g0
       
  4142         t = (((x & 0x0003e0ff) * a8 + (y & 0x0003e0ff) * ia8) >> 5)
       
  4143             & 0x0003e0ff;
       
  4144 
       
  4145         // r0,b0
       
  4146         t |= (((x & 0x007c1f00) * a8 + (y & 0x007c1f00) * ia8) >> 5)
       
  4147              & 0x007c1f00;
       
  4148 
       
  4149         a8 = (a >> 16) & 0xff;
       
  4150         ia8 = (ia >> 16) & 0xff;
       
  4151 
       
  4152         // a1
       
  4153         t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
       
  4154              & 0xff000000;
       
  4155 
       
  4156         dest32[0] = t;
       
  4157     }
       
  4158     {
       
  4159         x = src32[1];
       
  4160         y = dest32[1];
       
  4161 
       
  4162         // r1,b1
       
  4163         t = (((x & 0x00007c1f) * a8 + (y & 0x00007c1f) * ia8) >> 5)
       
  4164             & 0x00007c1f;
       
  4165 
       
  4166         // g1
       
  4167         t |= (((x & 0x000003e0) * a8 + (y & 0x000003e0) * ia8) >> 5)
       
  4168              & 0x000003e0;
       
  4169 
       
  4170         a8 = (a >> 8) & 0xff;
       
  4171         ia8 = (ia >> 8) & 0xff;
       
  4172 
       
  4173         // a2
       
  4174         t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
       
  4175              & 0x00ff0000;
       
  4176 
       
  4177         {
       
  4178             // rgb2
       
  4179             quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
       
  4180             quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
       
  4181             quint16 t16;
       
  4182 
       
  4183             t16 = (((x16 & 0x7c1f) * a8 + (y16 & 0x7c1f) * ia8) >> 5) & 0x7c1f;
       
  4184             t16 |= (((x16 & 0x03e0) * a8 + (y16 & 0x03e0) * ia8) >> 5) & 0x03e0;
       
  4185 
       
  4186             // rg2
       
  4187             t |= ((t16 & 0x00ff) << 24);
       
  4188 
       
  4189             dest32[1] = t;
       
  4190 
       
  4191             x = src32[2];
       
  4192             y = dest32[2];
       
  4193 
       
  4194             // gb2
       
  4195             t = (t16 >> 8);
       
  4196         }
       
  4197     }
       
  4198     {
       
  4199         a8 = a & 0xff;
       
  4200         ia8 = ia & 0xff;
       
  4201 
       
  4202         // g3,a3
       
  4203         t |= (((x & 0x03e0ff00) * a8 + (y & 0x03e0ff00) * ia8) >> 5)
       
  4204              & 0x03e0ff00;
       
  4205 
       
  4206         // r3,b3
       
  4207         t |= (((x & 0x7c1f0000) >> 5) * a8 + ((y & 0x7c1f0000) >> 5) * ia8)
       
  4208              & 0x7c1f0000;
       
  4209 
       
  4210         dest32[2] = t;
       
  4211     }
       
  4212 }
       
  4213 #endif
       
  4214 
       
  4215 template <>
       
  4216 inline void interpolate_pixel_4(qrgb888 *dest, const qrgb888 *src,
       
  4217                                 quint32 alpha)
       
  4218 {
       
  4219     Q_ASSERT((long(dest) & 0x3) == 0);
       
  4220     Q_ASSERT((long(src) & 0x3) == 0);
       
  4221 
       
  4222     const quint32 a = eff_alpha_4(alpha, dest);
       
  4223     const quint32 ia = eff_ialpha_4(alpha, dest);
       
  4224     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
       
  4225     quint32 *dest32 = reinterpret_cast<quint32*>(dest);
       
  4226 
       
  4227     {
       
  4228         quint32 x = src32[0];
       
  4229         quint32 y = dest32[0];
       
  4230 
       
  4231         quint32 t;
       
  4232         t = ((x >> 8) & 0xff00ff) * (a >> 24)
       
  4233             + ((y >> 8) & 0xff00ff) * (ia >> 24);
       
  4234         t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
       
  4235         t &= 0xff00ff00;
       
  4236 
       
  4237         x = (x & 0xff0000) * (a >> 24)
       
  4238             + (x & 0x0000ff) * ((a >> 16) & 0xff)
       
  4239             + (y & 0xff0000) * (ia >> 24)
       
  4240             + (y & 0x0000ff) * ((ia >> 16) & 0xff);
       
  4241         x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
       
  4242         x &= 0x00ff00ff;
       
  4243 
       
  4244         dest32[0] = x | t;
       
  4245     }
       
  4246     {
       
  4247         quint32 x = src32[1];
       
  4248         quint32 y = dest32[1];
       
  4249 
       
  4250         quint32 t;
       
  4251         t = ((x >> 8) & 0xff0000) * ((a >> 16) & 0xff)
       
  4252             + ((x >> 8) & 0x0000ff) * ((a >> 8) & 0xff)
       
  4253             + ((y >> 8) & 0xff0000) * ((ia >> 16) & 0xff)
       
  4254             + ((y >> 8) & 0x0000ff) * ((ia >> 8) & 0xff);
       
  4255         t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
       
  4256         t &= 0xff00ff00;
       
  4257 
       
  4258         x = (x & 0xff0000) * ((a >> 16) & 0xff)
       
  4259             + (x & 0x0000ff) * ((a >> 8) & 0xff)
       
  4260             + (y & 0xff0000) * ((ia >> 16) & 0xff)
       
  4261             + (y & 0x0000ff) * ((ia >> 8) & 0xff);
       
  4262         x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
       
  4263         x &= 0x00ff00ff;
       
  4264 
       
  4265         dest32[1] = x | t;
       
  4266     }
       
  4267     {
       
  4268         quint32 x = src32[2];
       
  4269         quint32 y = dest32[2];
       
  4270 
       
  4271         quint32 t;
       
  4272         t = ((x >> 8) & 0xff0000) * ((a >> 8) & 0xff)
       
  4273             + ((x >> 8) & 0x0000ff) * (a & 0xff)
       
  4274             + ((y >> 8) & 0xff0000) * ((ia >> 8) & 0xff)
       
  4275             + ((y >> 8) & 0x0000ff) * (ia & 0xff);
       
  4276         t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
       
  4277         t &= 0xff00ff00;
       
  4278 
       
  4279         x = (x & 0xff00ff) * (a & 0xff)
       
  4280             + (y & 0xff00ff) * (ia & 0xff);
       
  4281         x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
       
  4282         x &= 0x00ff00ff;
       
  4283 
       
  4284         dest32[2] = x | t;
       
  4285     }
       
  4286 }
       
  4287 
       
  4288 template <class DST, class SRC>
       
  4289 inline void interpolate_pixel_4(DST *dest, quint8 a,
       
  4290                                 const SRC *src, quint8 b)
       
  4291 {
       
  4292     Q_ASSERT((long(dest) & 0x3) == 0);
       
  4293     Q_ASSERT((long(src) & 0x3) == 0);
       
  4294 
       
  4295     dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
       
  4296     dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
       
  4297     dest[2] = dest[2].byte_mul(a) + DST(src[2]).byte_mul(b);
       
  4298     dest[3] = dest[3].byte_mul(a) + DST(src[3]).byte_mul(b);
       
  4299 }
       
  4300 
       
  4301 template <class DST, class SRC>
       
  4302 inline void blend_sourceOver_4(DST *dest, const SRC *src)
       
  4303 {
       
  4304     Q_ASSERT((long(dest) & 0x3) == 0);
       
  4305     Q_ASSERT((long(src) & 0x3) == 0);
       
  4306 
       
  4307     const quint32 a = alpha_4(src);
       
  4308     if (a == 0xffffffff) {
       
  4309         qt_memconvert(dest, src, 4);
       
  4310     } else if (a > 0) {
       
  4311         quint32 buf[3]; // array of quint32 to get correct alignment
       
  4312         qt_memconvert((DST*)(void*)buf, src, 4);
       
  4313         madd_4(dest, eff_ialpha_4(a, dest), (DST*)(void*)buf);
       
  4314     }
       
  4315 }
       
  4316 
       
  4317 template <>
       
  4318 inline void blend_sourceOver_4(qargb8565 *dest, const qargb8565 *src)
       
  4319 {
       
  4320     Q_ASSERT((long(dest) & 0x3) == 0);
       
  4321     Q_ASSERT((long(src) & 0x3) == 0);
       
  4322 
       
  4323     const quint32 a = alpha_4(src);
       
  4324     if (a == 0xffffffff) {
       
  4325         qt_memconvert(dest, src, 4);
       
  4326     } else if (a > 0) {
       
  4327         madd_4(dest, eff_ialpha_4(a, dest), src);
       
  4328     }
       
  4329 }
       
  4330 
       
  4331 template <>
       
  4332 inline void blend_sourceOver_4(qargb8555 *dest, const qargb8555 *src)
       
  4333 {
       
  4334     Q_ASSERT((long(dest) & 0x3) == 0);
       
  4335     Q_ASSERT((long(src) & 0x3) == 0);
       
  4336 
       
  4337     const quint32 a = alpha_4(src);
       
  4338     if (a == 0xffffffff) {
       
  4339         qt_memconvert(dest, src, 4);
       
  4340     } else if (a > 0) {
       
  4341         madd_4(dest, eff_ialpha_4(a, dest), src);
       
  4342     }
       
  4343 }
       
  4344 
       
  4345 template <>
       
  4346 inline void blend_sourceOver_4(qargb6666 *dest, const qargb6666 *src)
       
  4347 {
       
  4348     Q_ASSERT((long(dest) & 0x3) == 0);
       
  4349     Q_ASSERT((long(src) & 0x3) == 0);
       
  4350 
       
  4351     const quint32 a = alpha_4(src);
       
  4352     if (a == 0xffffffff) {
       
  4353         qt_memconvert(dest, src, 4);
       
  4354     } else if (a > 0) {
       
  4355         madd_4(dest, eff_ialpha_4(a, dest), src);
       
  4356     }
       
  4357 }
       
  4358 
       
  4359 template <class DST, class SRC>
       
  4360 void QT_FASTCALL blendUntransformed_unaligned(DST *dest, const SRC *src,
       
  4361                                               quint8 coverage, int length)
       
  4362 {
       
  4363     Q_ASSERT(coverage > 0);
       
  4364 
       
  4365     if (coverage < 255) {
       
  4366         if (SRC::hasAlpha()) {
       
  4367             for (int i = 0; i < length; ++i) {
       
  4368                 if (src[i].alpha()) {
       
  4369                     const quint8 alpha = qt_div_255(int(src[i].alpha()) * int(coverage));
       
  4370                     interpolate_pixel(dest[i], DST::ialpha(alpha),
       
  4371                             src[i], DST::alpha(alpha));
       
  4372                 }
       
  4373             }
       
  4374         } else {
       
  4375             const quint8 alpha = DST::alpha(coverage);
       
  4376             const quint8 ialpha = DST::ialpha(coverage);
       
  4377             if (alpha) {
       
  4378                 for (int i = 0; i < length; ++i)
       
  4379                     interpolate_pixel(dest[i], ialpha, src[i], alpha);
       
  4380             }
       
  4381         }
       
  4382         return;
       
  4383     }
       
  4384 
       
  4385     Q_ASSERT(coverage == 0xff);
       
  4386     Q_ASSERT(SRC::hasAlpha());
       
  4387 
       
  4388     if (SRC::hasAlpha()) {
       
  4389         for (int i = 0; i < length; ++i) {
       
  4390             const quint8 a = src->alpha();
       
  4391             if (a == 0xff)
       
  4392                 *dest = DST(*src);
       
  4393             else if (a > 0) {
       
  4394                 if (DST::hasAlpha())
       
  4395                     *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
       
  4396                 else
       
  4397                     *dest = DST(SRC(*src).truncedAlpha()) + dest->byte_mul(DST::ialpha(a));
       
  4398             }
       
  4399             ++src;
       
  4400             ++dest;
       
  4401         }
       
  4402     }
       
  4403 }
       
  4404 
       
  4405 template <class DST, class SRC>
       
  4406 void QT_FASTCALL blendUntransformed_dest16(DST *dest, const SRC *src,
       
  4407                                            quint8 coverage, int length)
       
  4408 {
       
  4409     Q_ASSERT(sizeof(DST) == 2);
       
  4410     Q_ASSERT(sizeof(SRC) == 2);
       
  4411     Q_ASSERT((long(dest) & 0x3) == (long(src) & 0x3));
       
  4412     Q_ASSERT(coverage > 0);
       
  4413 
       
  4414     const int align = quintptr(dest) & 0x3;
       
  4415 
       
  4416     if (coverage < 255) {
       
  4417         // align
       
  4418         if (align) {
       
  4419             const quint8 alpha = SRC::hasAlpha()
       
  4420                                  ? qt_div_255(int(src->alpha()) * int(coverage))
       
  4421                                  : coverage;
       
  4422             if (alpha) {
       
  4423                 interpolate_pixel(*dest, DST::ialpha(alpha),
       
  4424                                   *src, DST::alpha(alpha));
       
  4425             }
       
  4426             ++dest;
       
  4427             ++src;
       
  4428             --length;
       
  4429         }
       
  4430 
       
  4431         if (SRC::hasAlpha()) {
       
  4432             while (length >= 2) {
       
  4433                 const quint16 alpha16 = BYTE_MUL(uint(alpha_2(src)), uint(coverage));
       
  4434                 interpolate_pixel_2(dest, src, alpha16);
       
  4435                 length -= 2;
       
  4436                 src += 2;
       
  4437                 dest += 2;
       
  4438             }
       
  4439         } else {
       
  4440             const quint8 alpha = DST::alpha(coverage);
       
  4441             const quint8 ialpha = DST::ialpha(coverage);
       
  4442 
       
  4443             while (length >= 2) {
       
  4444                 interpolate_pixel_2(dest, ialpha, src, alpha);
       
  4445                 length -= 2;
       
  4446                 src += 2;
       
  4447                 dest += 2;
       
  4448             }
       
  4449         }
       
  4450 
       
  4451         // tail
       
  4452         if (length) {
       
  4453             const quint8 alpha = SRC::hasAlpha()
       
  4454                                  ? qt_div_255(int(src->alpha()) * int(coverage))
       
  4455                                  : coverage;
       
  4456             if (alpha) {
       
  4457                 interpolate_pixel(*dest, DST::ialpha(alpha),
       
  4458                                   *src, DST::alpha(alpha));
       
  4459             }
       
  4460         }
       
  4461 
       
  4462         return;
       
  4463     }
       
  4464 
       
  4465     Q_ASSERT(SRC::hasAlpha());
       
  4466     if (SRC::hasAlpha()) {
       
  4467         if (align) {
       
  4468             const quint8 alpha = src->alpha();
       
  4469             if (alpha == 0xff)
       
  4470                 *dest = DST(*src);
       
  4471             else if (alpha > 0)
       
  4472                 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
       
  4473             ++dest;
       
  4474             ++src;
       
  4475             --length;
       
  4476         }
       
  4477 
       
  4478         while (length >= 2) {
       
  4479             Q_ASSERT((long(dest) & 3) == 0);
       
  4480             Q_ASSERT((long(src) & 3) == 0);
       
  4481 
       
  4482             const quint16 a = alpha_2(src);
       
  4483             if (a == 0xffff) {
       
  4484                 qt_memconvert(dest, src, 2);
       
  4485             } else if (a > 0) {
       
  4486                 quint32 buf;
       
  4487                 if (sizeof(DST) == 2)
       
  4488                     qt_memconvert((DST*)(void*)&buf, src, 2);
       
  4489                 madd_2(dest, eff_ialpha_2(a, dest), (DST*)(void*)&buf);
       
  4490             }
       
  4491 
       
  4492             length -= 2;
       
  4493             src += 2;
       
  4494             dest += 2;
       
  4495         }
       
  4496 
       
  4497         if (length) {
       
  4498             const quint8 alpha = src->alpha();
       
  4499             if (alpha == 0xff)
       
  4500                 *dest = DST(*src);
       
  4501             else if (alpha > 0)
       
  4502                 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
       
  4503         }
       
  4504     }
       
  4505 }
       
  4506 
       
  4507 template <class DST, class SRC>
       
  4508 void QT_FASTCALL blendUntransformed_dest24(DST *dest, const SRC *src,
       
  4509                                            quint8 coverage, int length)
       
  4510 {
       
  4511     Q_ASSERT((long(dest) & 0x3) == (long(src) & 0x3));
       
  4512     Q_ASSERT(sizeof(DST) == 3);
       
  4513     Q_ASSERT(coverage > 0);
       
  4514 
       
  4515     const int align = quintptr(dest) & 0x3;
       
  4516 
       
  4517     if (coverage < 255) {
       
  4518         // align
       
  4519         for (int i = 0; i < align; ++i) {
       
  4520             if (SRC::hasAlpha()) {
       
  4521                 const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
       
  4522                 if (alpha)
       
  4523                     interpolate_pixel(*dest, DST::ialpha(alpha),
       
  4524                                       *src, DST::alpha(alpha));
       
  4525             } else {
       
  4526                 interpolate_pixel(*dest, DST::ialpha(coverage),
       
  4527                                   *src, DST::alpha(coverage));
       
  4528             }
       
  4529             ++dest;
       
  4530             ++src;
       
  4531             --length;
       
  4532         }
       
  4533 
       
  4534         if (SRC::hasAlpha()) {
       
  4535             while (length >= 4) {
       
  4536                 const quint32 alpha = BYTE_MUL(uint(alpha_4(src)), uint(coverage));
       
  4537                 if (alpha)
       
  4538                     interpolate_pixel_4(dest, src, alpha);
       
  4539                 length -= 4;
       
  4540                 src += 4;
       
  4541                 dest += 4;
       
  4542             }
       
  4543         } else {
       
  4544             const quint8 alpha = DST::alpha(coverage);
       
  4545             const quint8 ialpha = DST::ialpha(coverage);
       
  4546             while (length >= 4) {
       
  4547                 interpolate_pixel_4(dest, ialpha, src, alpha);
       
  4548                 length -= 4;
       
  4549                 src += 4;
       
  4550                 dest += 4;
       
  4551             }
       
  4552         }
       
  4553 
       
  4554         // tail
       
  4555         while (length--) {
       
  4556             if (SRC::hasAlpha()) {
       
  4557                 const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
       
  4558                 if (alpha)
       
  4559                     interpolate_pixel(*dest, DST::ialpha(alpha),
       
  4560                                       *src, DST::alpha(alpha));
       
  4561             } else {
       
  4562                 interpolate_pixel(*dest, DST::ialpha(coverage),
       
  4563                                   *src, DST::alpha(coverage));
       
  4564             }
       
  4565             ++dest;
       
  4566             ++src;
       
  4567         }
       
  4568 
       
  4569         return;
       
  4570     }
       
  4571 
       
  4572 
       
  4573     Q_ASSERT(coverage == 255);
       
  4574     Q_ASSERT(SRC::hasAlpha());
       
  4575 
       
  4576     if (SRC::hasAlpha()) {
       
  4577         // align
       
  4578         for (int i = 0; i < align; ++i) {
       
  4579             const quint8 a = src->alpha();
       
  4580             if (a == 0xff) {
       
  4581                 *dest = DST(*src);
       
  4582             } else if (a > 0) {
       
  4583                 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
       
  4584             }
       
  4585             ++dest;
       
  4586             ++src;
       
  4587             --length;
       
  4588         }
       
  4589 
       
  4590         while (length >= 4) {
       
  4591             blend_sourceOver_4(dest, src);
       
  4592             length -= 4;
       
  4593             src += 4;
       
  4594             dest += 4;
       
  4595         }
       
  4596 
       
  4597         // tail
       
  4598         while (length--) {
       
  4599             const quint8 a = src->alpha();
       
  4600             if (a == 0xff) {
       
  4601                 *dest = DST(*src);
       
  4602             } else if (a > 0) {
       
  4603                 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
       
  4604             }
       
  4605             ++dest;
       
  4606             ++src;
       
  4607         }
       
  4608     }
       
  4609 }
       
  4610 
       
  4611 template <class DST, class SRC>
       
  4612 Q_STATIC_TEMPLATE_SPECIALIZATION
       
  4613 void QT_FASTCALL blendUntransformed(int count, const QSpan *spans, void *userData)
       
  4614 {
       
  4615     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
       
  4616     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
       
  4617 
       
  4618     if (mode != QPainter::CompositionMode_SourceOver &&
       
  4619         mode != QPainter::CompositionMode_Source)
       
  4620     {
       
  4621         blend_src_generic<RegularSpans>(count, spans, userData);
       
  4622         return;
       
  4623     }
       
  4624 
       
  4625     const bool modeSource = !SRC::hasAlpha() ||
       
  4626                             mode == QPainter::CompositionMode_Source;
       
  4627     const int image_width = data->texture.width;
       
  4628     const int image_height = data->texture.height;
       
  4629     int xoff = -qRound(-data->dx);
       
  4630     int yoff = -qRound(-data->dy);
       
  4631 
       
  4632     while (count--) {
       
  4633         const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
       
  4634         if (coverage == 0) {
       
  4635             ++spans;
       
  4636             continue;
       
  4637         }
       
  4638 
       
  4639         int x = spans->x;
       
  4640         int length = spans->len;
       
  4641         int sx = xoff + x;
       
  4642         int sy = yoff + spans->y;
       
  4643         if (sy >= 0 && sy < image_height && sx < image_width) {
       
  4644             if (sx < 0) {
       
  4645                 x -= sx;
       
  4646                 length += sx;
       
  4647                 sx = 0;
       
  4648             }
       
  4649             if (sx + length > image_width)
       
  4650                 length = image_width - sx;
       
  4651             if (length > 0) {
       
  4652                 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
       
  4653                 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
       
  4654                 if (modeSource && coverage == 255) {
       
  4655                     qt_memconvert<DST, SRC>(dest, src, length);
       
  4656                 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && length >= 3 &&
       
  4657                            (quintptr(dest) & 3) == (quintptr(src) & 3))
       
  4658                 {
       
  4659                     blendUntransformed_dest24(dest, src, coverage, length);
       
  4660                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && length >= 3 &&
       
  4661                            (quintptr(dest) & 3) == (quintptr(src) & 3))
       
  4662                 {
       
  4663                     blendUntransformed_dest16(dest, src, coverage, length);
       
  4664                 } else {
       
  4665                     blendUntransformed_unaligned(dest, src, coverage, length);
       
  4666                 }
       
  4667             }
       
  4668         }
       
  4669         ++spans;
       
  4670     }
       
  4671 }
       
  4672 
       
  4673 static void blend_untransformed_rgb888(int count, const QSpan *spans,
       
  4674                                        void *userData)
       
  4675 {
       
  4676 #if defined(QT_QWS_DEPTH_24)
       
  4677     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  4678 
       
  4679     if (data->texture.format == QImage::Format_RGB888)
       
  4680         blendUntransformed<qrgb888, qrgb888>(count, spans, userData);
       
  4681     else
       
  4682 #endif
       
  4683         blend_untransformed_generic<RegularSpans>(count, spans, userData);
       
  4684 }
       
  4685 
       
  4686 static void blend_untransformed_argb6666(int count, const QSpan *spans,
       
  4687                                          void *userData)
       
  4688 {
       
  4689 #if defined(QT_QWS_DEPTH_18)
       
  4690     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  4691 
       
  4692     if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
       
  4693         blendUntransformed<qargb6666, qargb6666>(count, spans, userData);
       
  4694     else if (data->texture.format == QImage::Format_RGB666)
       
  4695         blendUntransformed<qargb6666, qrgb666>(count, spans, userData);
       
  4696     else
       
  4697 #endif
       
  4698         blend_untransformed_generic<RegularSpans>(count, spans, userData);
       
  4699 }
       
  4700 
       
  4701 static void blend_untransformed_rgb666(int count, const QSpan *spans,
       
  4702                                        void *userData)
       
  4703 {
       
  4704 #if defined(QT_QWS_DEPTH_18)
       
  4705     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  4706 
       
  4707     if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
       
  4708         blendUntransformed<qrgb666, qargb6666>(count, spans, userData);
       
  4709     else if (data->texture.format == QImage::Format_RGB666)
       
  4710         blendUntransformed<qrgb666, qrgb666>(count, spans, userData);
       
  4711     else
       
  4712 #endif
       
  4713         blend_untransformed_generic<RegularSpans>(count, spans, userData);
       
  4714 }
       
  4715 
       
  4716 static void blend_untransformed_argb8565(int count, const QSpan *spans,
       
  4717                                          void *userData)
       
  4718 {
       
  4719 #if defined(QT_QWS_DEPTH_16)
       
  4720     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  4721 
       
  4722     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
       
  4723         blendUntransformed<qargb8565, qargb8565>(count, spans, userData);
       
  4724     else if (data->texture.format == QImage::Format_RGB16)
       
  4725         blendUntransformed<qargb8565, qrgb565>(count, spans, userData);
       
  4726     else
       
  4727 #endif
       
  4728         blend_untransformed_generic<RegularSpans>(count, spans, userData);
       
  4729 }
       
  4730 
       
  4731 static void blend_untransformed_rgb565(int count, const QSpan *spans,
       
  4732                                        void *userData)
       
  4733 {
       
  4734 #if defined(QT_QWS_DEPTH_16)
       
  4735     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  4736 
       
  4737     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
       
  4738         blendUntransformed<qrgb565, qargb8565>(count, spans, userData);
       
  4739     else if (data->texture.format == QImage::Format_RGB16)
       
  4740         blendUntransformed<qrgb565, qrgb565>(count, spans, userData);
       
  4741     else
       
  4742 #endif
       
  4743         blend_untransformed_generic<RegularSpans>(count, spans, userData);
       
  4744 }
       
  4745 
       
  4746 static void blend_untransformed_argb8555(int count, const QSpan *spans,
       
  4747                                          void *userData)
       
  4748 {
       
  4749 #if defined(QT_QWS_DEPTH_15)
       
  4750     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  4751 
       
  4752     if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
       
  4753         blendUntransformed<qargb8555, qargb8555>(count, spans, userData);
       
  4754     else if (data->texture.format == QImage::Format_RGB555)
       
  4755         blendUntransformed<qargb8555, qrgb555>(count, spans, userData);
       
  4756     else
       
  4757 #endif
       
  4758         blend_untransformed_generic<RegularSpans>(count, spans, userData);
       
  4759 }
       
  4760 
       
  4761 static void blend_untransformed_rgb555(int count, const QSpan *spans,
       
  4762                                        void *userData)
       
  4763 {
       
  4764 #if defined(QT_QWS_DEPTH_15)
       
  4765     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  4766 
       
  4767     if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
       
  4768         blendUntransformed<qrgb555, qargb8555>(count, spans, userData);
       
  4769     else if (data->texture.format == QImage::Format_RGB555)
       
  4770         blendUntransformed<qrgb555, qrgb555>(count, spans, userData);
       
  4771     else
       
  4772 #endif
       
  4773         blend_untransformed_generic<RegularSpans>(count, spans, userData);
       
  4774 }
       
  4775 
       
  4776 static void blend_untransformed_argb4444(int count, const QSpan *spans,
       
  4777                                          void *userData)
       
  4778 {
       
  4779 #if defined(QT_QWS_DEPTH_12)
       
  4780     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  4781 
       
  4782     if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
       
  4783         blendUntransformed<qargb4444, qargb4444>(count, spans, userData);
       
  4784     else if (data->texture.format == QImage::Format_RGB444)
       
  4785         blendUntransformed<qargb4444, qrgb444>(count, spans, userData);
       
  4786     else
       
  4787 #endif
       
  4788         blend_untransformed_generic<RegularSpans>(count, spans, userData);
       
  4789 }
       
  4790 
       
  4791 static void blend_untransformed_rgb444(int count, const QSpan *spans,
       
  4792                                        void *userData)
       
  4793 {
       
  4794 #if defined(QT_QWS_DEPTH_12)
       
  4795     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  4796 
       
  4797     if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
       
  4798         blendUntransformed<qrgb444, qargb4444>(count, spans, userData);
       
  4799     else if (data->texture.format == QImage::Format_RGB444)
       
  4800         blendUntransformed<qrgb444, qrgb444>(count, spans, userData);
       
  4801     else
       
  4802 #endif
       
  4803         blend_untransformed_generic<RegularSpans>(count, spans, userData);
       
  4804 }
       
  4805 
       
  4806 template <SpanMethod spanMethod>
       
  4807 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_generic(int count, const QSpan *spans, void *userData)
       
  4808 {
       
  4809     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  4810 
       
  4811     uint buffer[buffer_size];
       
  4812     uint src_buffer[buffer_size];
       
  4813     Operator op = getOperator(data, spans, count);
       
  4814 
       
  4815     const int image_width = data->texture.width;
       
  4816     const int image_height = data->texture.height;
       
  4817     int xoff = -qRound(-data->dx) % image_width;
       
  4818     int yoff = -qRound(-data->dy) % image_height;
       
  4819 
       
  4820     if (xoff < 0)
       
  4821         xoff += image_width;
       
  4822     if (yoff < 0)
       
  4823         yoff += image_height;
       
  4824 
       
  4825     while (count--) {
       
  4826         int x = spans->x;
       
  4827         int length = spans->len;
       
  4828         int sx = (xoff + spans->x) % image_width;
       
  4829         int sy = (spans->y + yoff) % image_height;
       
  4830         if (sx < 0)
       
  4831             sx += image_width;
       
  4832         if (sy < 0)
       
  4833             sy += image_height;
       
  4834 
       
  4835         const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
       
  4836         while (length) {
       
  4837             int l = qMin(image_width - sx, length);
       
  4838             if (buffer_size < l)
       
  4839                 l = buffer_size;
       
  4840             const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
       
  4841             if (spanMethod == RegularSpans) {
       
  4842                 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
       
  4843                 op.func(dest, src, l, coverage);
       
  4844                 if (op.dest_store)
       
  4845                     op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
       
  4846             } else {
       
  4847                 drawBufferSpan(data, src, l, x, spans->y, l,
       
  4848                                coverage);
       
  4849             }
       
  4850             x += l;
       
  4851             sx += l;
       
  4852             length -= l;
       
  4853             if (sx >= image_width)
       
  4854                 sx = 0;
       
  4855         }
       
  4856         ++spans;
       
  4857     }
       
  4858 }
       
  4859 
       
  4860 template <SpanMethod spanMethod>
       
  4861 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_argb(int count, const QSpan *spans, void *userData)
       
  4862 {
       
  4863     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  4864     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
       
  4865         && data->texture.format != QImage::Format_RGB32) {
       
  4866         blend_tiled_generic<spanMethod>(count, spans, userData);
       
  4867         return;
       
  4868     }
       
  4869 
       
  4870     Operator op = getOperator(data, spans, count);
       
  4871 
       
  4872     int image_width = data->texture.width;
       
  4873     int image_height = data->texture.height;
       
  4874     int xoff = -qRound(-data->dx) % image_width;
       
  4875     int yoff = -qRound(-data->dy) % image_height;
       
  4876 
       
  4877     if (xoff < 0)
       
  4878         xoff += image_width;
       
  4879     if (yoff < 0)
       
  4880         yoff += image_height;
       
  4881 
       
  4882     while (count--) {
       
  4883         int x = spans->x;
       
  4884         int length = spans->len;
       
  4885         int sx = (xoff + spans->x) % image_width;
       
  4886         int sy = (spans->y + yoff) % image_height;
       
  4887         if (sx < 0)
       
  4888             sx += image_width;
       
  4889         if (sy < 0)
       
  4890             sy += image_height;
       
  4891 
       
  4892         const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
       
  4893         while (length) {
       
  4894             int l = qMin(image_width - sx, length);
       
  4895             if (buffer_size < l)
       
  4896                 l = buffer_size;
       
  4897             const uint *src = (uint *)data->texture.scanLine(sy) + sx;
       
  4898             if (spanMethod == RegularSpans) {
       
  4899                 uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
       
  4900                 op.func(dest, src, l, coverage);
       
  4901             } else {
       
  4902                 drawBufferSpan(data, src, buffer_size,
       
  4903                                x, spans->y, l, coverage);
       
  4904             }
       
  4905             x += l;
       
  4906             length -= l;
       
  4907             sx = 0;
       
  4908         }
       
  4909         ++spans;
       
  4910     }
       
  4911 }
       
  4912 
       
  4913 template <class DST, class SRC>
       
  4914 Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *userData)
       
  4915 {
       
  4916     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
       
  4917     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
       
  4918 
       
  4919     if (mode != QPainter::CompositionMode_SourceOver &&
       
  4920         mode != QPainter::CompositionMode_Source)
       
  4921     {
       
  4922         blend_src_generic<RegularSpans>(count, spans, userData);
       
  4923         return;
       
  4924     }
       
  4925 
       
  4926     const bool modeSource = !SRC::hasAlpha() ||
       
  4927                             mode == QPainter::CompositionMode_Source;
       
  4928     const int image_width = data->texture.width;
       
  4929     const int image_height = data->texture.height;
       
  4930     int xoff = -qRound(-data->dx) % image_width;
       
  4931     int yoff = -qRound(-data->dy) % image_height;
       
  4932 
       
  4933     if (xoff < 0)
       
  4934         xoff += image_width;
       
  4935     if (yoff < 0)
       
  4936         yoff += image_height;
       
  4937 
       
  4938     while (count--) {
       
  4939         const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
       
  4940         if (coverage == 0) {
       
  4941             ++spans;
       
  4942             continue;
       
  4943         }
       
  4944 
       
  4945         int x = spans->x;
       
  4946         int length = spans->len;
       
  4947         int sx = (xoff + spans->x) % image_width;
       
  4948         int sy = (spans->y + yoff) % image_height;
       
  4949         if (sx < 0)
       
  4950             sx += image_width;
       
  4951         if (sy < 0)
       
  4952             sy += image_height;
       
  4953 
       
  4954         if (modeSource && coverage == 255) {
       
  4955             // Copy the first texture block
       
  4956             length = qMin(image_width,length);
       
  4957             int tx = x;
       
  4958             while (length) {
       
  4959                 int l = qMin(image_width - sx, length);
       
  4960                 if (buffer_size < l)
       
  4961                     l = buffer_size;
       
  4962                 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + tx;
       
  4963                 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
       
  4964 
       
  4965                 qt_memconvert<DST, SRC>(dest, src, l);
       
  4966                 length -= l;
       
  4967                 tx += l;
       
  4968                 sx = 0;
       
  4969             }
       
  4970 
       
  4971             // Now use the rasterBuffer as the source of the texture,
       
  4972             // We can now progressively copy larger blocks
       
  4973             // - Less cpu time in code figuring out what to copy
       
  4974             // We are dealing with one block of data
       
  4975             // - More likely to fit in the cache
       
  4976             // - can use memcpy
       
  4977             int copy_image_width = qMin(image_width, int(spans->len));
       
  4978             length = spans->len - copy_image_width;
       
  4979             DST *src = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
       
  4980             DST *dest = src + copy_image_width;
       
  4981             while (copy_image_width < length) {
       
  4982                 qt_memconvert(dest, src, copy_image_width);
       
  4983                 dest += copy_image_width;
       
  4984                 length -= copy_image_width;
       
  4985                 copy_image_width *= 2;
       
  4986             }
       
  4987             qt_memconvert(dest, src, length);
       
  4988         } else {
       
  4989             while (length) {
       
  4990                 int l = qMin(image_width - sx, length);
       
  4991                 if (buffer_size < l)
       
  4992                     l = buffer_size;
       
  4993                 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
       
  4994                 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
       
  4995                 if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
       
  4996                            (quintptr(dest) & 3) == (quintptr(src) & 3))
       
  4997                 {
       
  4998                     blendUntransformed_dest24(dest, src, coverage, l);
       
  4999                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
       
  5000                            (quintptr(dest) & 3) == (quintptr(src) & 3))
       
  5001                 {
       
  5002                     blendUntransformed_dest16(dest, src, coverage, l);
       
  5003                 } else {
       
  5004                     blendUntransformed_unaligned(dest, src, coverage, l);
       
  5005                 }
       
  5006 
       
  5007                 x += l;
       
  5008                 length -= l;
       
  5009                 sx = 0;
       
  5010             }
       
  5011         }
       
  5012         ++spans;
       
  5013     }
       
  5014 }
       
  5015 
       
  5016 static void blend_tiled_rgb888(int count, const QSpan *spans, void *userData)
       
  5017 {
       
  5018 #if defined(QT_QWS_DEPTH_24)
       
  5019     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5020 
       
  5021     if (data->texture.format == QImage::Format_RGB888)
       
  5022         blendTiled<qrgb888, qrgb888>(count, spans, userData);
       
  5023     else
       
  5024 #endif
       
  5025         blend_tiled_generic<RegularSpans>(count, spans, userData);
       
  5026 }
       
  5027 
       
  5028 static void blend_tiled_argb6666(int count, const QSpan *spans, void *userData)
       
  5029 {
       
  5030 #if defined(QT_QWS_DEPTH_18)
       
  5031     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5032 
       
  5033     if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
       
  5034         blendTiled<qargb6666, qargb6666>(count, spans, userData);
       
  5035     else if (data->texture.format == QImage::Format_RGB666)
       
  5036         blendTiled<qargb6666, qrgb666>(count, spans, userData);
       
  5037     else
       
  5038 #endif
       
  5039         blend_tiled_generic<RegularSpans>(count, spans, userData);
       
  5040 }
       
  5041 
       
  5042 static void blend_tiled_rgb666(int count, const QSpan *spans, void *userData)
       
  5043 {
       
  5044 #if defined(QT_QWS_DEPTH_18)
       
  5045     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5046 
       
  5047     if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
       
  5048         blendTiled<qrgb666, qargb6666>(count, spans, userData);
       
  5049     else if (data->texture.format == QImage::Format_RGB666)
       
  5050         blendTiled<qrgb666, qrgb666>(count, spans, userData);
       
  5051     else
       
  5052 #endif
       
  5053         blend_tiled_generic<RegularSpans>(count, spans, userData);
       
  5054 }
       
  5055 
       
  5056 static void blend_tiled_argb8565(int count, const QSpan *spans, void *userData)
       
  5057 {
       
  5058 #if defined(QT_QWS_DEPTH_16)
       
  5059     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5060 
       
  5061     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
       
  5062         blendTiled<qargb8565, qargb8565>(count, spans, userData);
       
  5063     else if (data->texture.format == QImage::Format_RGB16)
       
  5064         blendTiled<qargb8565, qrgb565>(count, spans, userData);
       
  5065     else
       
  5066 #endif
       
  5067         blend_tiled_generic<RegularSpans>(count, spans, userData);
       
  5068 }
       
  5069 
       
  5070 static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
       
  5071 {
       
  5072 #if defined(QT_QWS_DEPTH_16)
       
  5073     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5074 
       
  5075     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
       
  5076         blendTiled<qrgb565, qargb8565>(count, spans, userData);
       
  5077     else if (data->texture.format == QImage::Format_RGB16)
       
  5078         blendTiled<qrgb565, qrgb565>(count, spans, userData);
       
  5079     else
       
  5080 #endif
       
  5081         blend_tiled_generic<RegularSpans>(count, spans, userData);
       
  5082 }
       
  5083 
       
  5084 static void blend_tiled_argb8555(int count, const QSpan *spans, void *userData)
       
  5085 {
       
  5086 #if defined(QT_QWS_DEPTH_15)
       
  5087     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5088 
       
  5089     if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
       
  5090         blendTiled<qargb8555, qargb8555>(count, spans, userData);
       
  5091     else if (data->texture.format == QImage::Format_RGB555)
       
  5092         blendTiled<qargb8555, qrgb555>(count, spans, userData);
       
  5093     else
       
  5094 #endif
       
  5095         blend_tiled_generic<RegularSpans>(count, spans, userData);
       
  5096 }
       
  5097 
       
  5098 static void blend_tiled_rgb555(int count, const QSpan *spans, void *userData)
       
  5099 {
       
  5100 #if defined(QT_QWS_DEPTH_15)
       
  5101     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5102 
       
  5103     if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
       
  5104         blendTiled<qrgb555, qargb8555>(count, spans, userData);
       
  5105     else if (data->texture.format == QImage::Format_RGB555)
       
  5106         blendTiled<qrgb555, qrgb555>(count, spans, userData);
       
  5107     else
       
  5108 #endif
       
  5109         blend_tiled_generic<RegularSpans>(count, spans, userData);
       
  5110 }
       
  5111 
       
  5112 static void blend_tiled_argb4444(int count, const QSpan *spans, void *userData)
       
  5113 {
       
  5114 #if defined(QT_QWS_DEPTH_12)
       
  5115     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5116 
       
  5117     if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
       
  5118         blendTiled<qargb4444, qargb4444>(count, spans, userData);
       
  5119     else if (data->texture.format == QImage::Format_RGB444)
       
  5120         blendTiled<qargb4444, qrgb444>(count, spans, userData);
       
  5121     else
       
  5122 #endif
       
  5123         blend_tiled_generic<RegularSpans>(count, spans, userData);
       
  5124 }
       
  5125 
       
  5126 static void blend_tiled_rgb444(int count, const QSpan *spans, void *userData)
       
  5127 {
       
  5128 #if defined(QT_QWS_DEPTH_12)
       
  5129     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5130 
       
  5131     if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
       
  5132         blendTiled<qrgb444, qargb4444>(count, spans, userData);
       
  5133     else if (data->texture.format == QImage::Format_RGB444)
       
  5134         blendTiled<qrgb444, qrgb444>(count, spans, userData);
       
  5135     else
       
  5136 #endif
       
  5137         blend_tiled_generic<RegularSpans>(count, spans, userData);
       
  5138 }
       
  5139 
       
  5140 
       
  5141 template <SpanMethod spanMethod>
       
  5142 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_bilinear_argb(int count, const QSpan *spans, void *userData)
       
  5143 {
       
  5144     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5145     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
       
  5146         && data->texture.format != QImage::Format_RGB32) {
       
  5147         blend_src_generic<spanMethod>(count, spans, userData);
       
  5148         return;
       
  5149     }
       
  5150 
       
  5151     CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
       
  5152     uint buffer[buffer_size];
       
  5153 
       
  5154     int image_x1 = data->texture.x1;
       
  5155     int image_y1 = data->texture.y1;
       
  5156     int image_x2 = data->texture.x2;
       
  5157     int image_y2 = data->texture.y2;
       
  5158     const int scanline_offset = data->texture.bytesPerLine / 4;
       
  5159 
       
  5160     if (data->fast_matrix) {
       
  5161         // The increment pr x in the scanline
       
  5162         int fdx = (int)(data->m11 * fixed_scale);
       
  5163         int fdy = (int)(data->m12 * fixed_scale);
       
  5164 
       
  5165         while (count--) {
       
  5166             void *t = data->rasterBuffer->scanLine(spans->y);
       
  5167 
       
  5168             uint *target = ((uint *)t) + spans->x;
       
  5169             uint *image_bits = (uint *)data->texture.imageData;
       
  5170 
       
  5171             const qreal cx = spans->x + 0.5;
       
  5172             const qreal cy = spans->y + 0.5;
       
  5173 
       
  5174             int x = int((data->m21 * cy
       
  5175                          + data->m11 * cx + data->dx) * fixed_scale) - half_point;
       
  5176             int y = int((data->m22 * cy
       
  5177                          + data->m12 * cx + data->dy) * fixed_scale) - half_point;
       
  5178 
       
  5179             int length = spans->len;
       
  5180             const int coverage = (data->texture.const_alpha * spans->coverage) >> 8;
       
  5181             while (length) {
       
  5182                 int l = qMin(length, buffer_size);
       
  5183                 const uint *end = buffer + l;
       
  5184                 uint *b = buffer;
       
  5185                 while (b < end) {
       
  5186                     int x1 = (x >> 16);
       
  5187                     int x2 = x1 + 1;
       
  5188                     int y1 = (y >> 16);
       
  5189                     int y2 = y1 + 1;
       
  5190 
       
  5191                     int distx = ((x - (x1 << 16)) >> 8);
       
  5192                     int disty = ((y - (y1 << 16)) >> 8);
       
  5193                     int idistx = 256 - distx;
       
  5194                     int idisty = 256 - disty;
       
  5195 
       
  5196                     x1 = qBound(image_x1, x1, image_x2 - 1);
       
  5197                     x2 = qBound(image_x1, x2, image_x2 - 1);
       
  5198                     y1 = qBound(image_y1, y1, image_y2 - 1);
       
  5199                     y2 = qBound(image_y1, y2, image_y2 - 1);
       
  5200 
       
  5201                     int y1_offset = y1 * scanline_offset;
       
  5202                     int y2_offset = y2 * scanline_offset;
       
  5203 
       
  5204 #if defined(Q_IRIX_GCC3_3_WORKAROUND)
       
  5205                     uint tl = gccBug(image_bits[y1_offset + x1]);
       
  5206                     uint tr = gccBug(image_bits[y1_offset + x2]);
       
  5207                     uint bl = gccBug(image_bits[y2_offset + x1]);
       
  5208                     uint br = gccBug(image_bits[y2_offset + x2]);
       
  5209 #else
       
  5210                     uint tl = image_bits[y1_offset + x1];
       
  5211                     uint tr = image_bits[y1_offset + x2];
       
  5212                     uint bl = image_bits[y2_offset + x1];
       
  5213                     uint br = image_bits[y2_offset + x2];
       
  5214 #endif
       
  5215 
       
  5216                     uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
       
  5217                     uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
       
  5218                     *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
       
  5219                     ++b;
       
  5220 
       
  5221                     x += fdx;
       
  5222                     y += fdy;
       
  5223                 }
       
  5224                 if (spanMethod == RegularSpans)
       
  5225                     func(target, buffer, l, coverage);
       
  5226                 else
       
  5227                     drawBufferSpan(data, buffer, buffer_size,
       
  5228                                    spans->x + spans->len - length,
       
  5229                                    spans->y, l, coverage);
       
  5230                 target += l;
       
  5231                 length -= l;
       
  5232             }
       
  5233             ++spans;
       
  5234         }
       
  5235     } else {
       
  5236         const qreal fdx = data->m11;
       
  5237         const qreal fdy = data->m12;
       
  5238         const qreal fdw = data->m13;
       
  5239 
       
  5240         while (count--) {
       
  5241             void *t = data->rasterBuffer->scanLine(spans->y);
       
  5242 
       
  5243             uint *target = ((uint *)t) + spans->x;
       
  5244             uint *image_bits = (uint *)data->texture.imageData;
       
  5245 
       
  5246             const qreal cx = spans->x + 0.5;
       
  5247             const qreal cy = spans->y + 0.5;
       
  5248 
       
  5249             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
       
  5250             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
       
  5251             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
       
  5252 
       
  5253             int length = spans->len;
       
  5254             const int coverage = (data->texture.const_alpha * spans->coverage) >> 8;
       
  5255             while (length) {
       
  5256                 int l = qMin(length, buffer_size);
       
  5257                 const uint *end = buffer + l;
       
  5258                 uint *b = buffer;
       
  5259                 while (b < end) {
       
  5260                     const qreal iw = w == 0 ? 1 : 1 / w;
       
  5261                     const qreal px = x * iw - 0.5;
       
  5262                     const qreal py = y * iw - 0.5;
       
  5263 
       
  5264                     int x1 = int(px) - (px < 0);
       
  5265                     int x2 = x1 + 1;
       
  5266                     int y1 = int(py) - (py < 0);
       
  5267                     int y2 = y1 + 1;
       
  5268 
       
  5269                     int distx = int((px - x1) * 256);
       
  5270                     int disty = int((py - y1) * 256);
       
  5271                     int idistx = 256 - distx;
       
  5272                     int idisty = 256 - disty;
       
  5273 
       
  5274                     x1 = qBound(image_x1, x1, image_x2 - 1);
       
  5275                     x2 = qBound(image_x1, x2, image_x2 - 1);
       
  5276                     y1 = qBound(image_y1, y1, image_y2 - 1);
       
  5277                     y2 = qBound(image_y1, y2, image_y2 - 1);
       
  5278 
       
  5279                     int y1_offset = y1 * scanline_offset;
       
  5280                     int y2_offset = y2 * scanline_offset;
       
  5281 
       
  5282 #if defined(Q_IRIX_GCC3_3_WORKAROUND)
       
  5283                     uint tl = gccBug(image_bits[y1_offset + x1]);
       
  5284                     uint tr = gccBug(image_bits[y1_offset + x2]);
       
  5285                     uint bl = gccBug(image_bits[y2_offset + x1]);
       
  5286                     uint br = gccBug(image_bits[y2_offset + x2]);
       
  5287 #else
       
  5288                     uint tl = image_bits[y1_offset + x1];
       
  5289                     uint tr = image_bits[y1_offset + x2];
       
  5290                     uint bl = image_bits[y2_offset + x1];
       
  5291                     uint br = image_bits[y2_offset + x2];
       
  5292 #endif
       
  5293 
       
  5294                     uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
       
  5295                     uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
       
  5296                     *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
       
  5297                     ++b;
       
  5298 
       
  5299                     x += fdx;
       
  5300                     y += fdy;
       
  5301                     w += fdw;
       
  5302                 }
       
  5303                 if (spanMethod == RegularSpans)
       
  5304                     func(target, buffer, l, coverage);
       
  5305                 else
       
  5306                     drawBufferSpan(data, buffer, buffer_size,
       
  5307                                    spans->x + spans->len - length,
       
  5308                                    spans->y, l, coverage);
       
  5309                 target += l;
       
  5310                 length -= l;
       
  5311             }
       
  5312             ++spans;
       
  5313         }
       
  5314     }
       
  5315 }
       
  5316 
       
  5317 template <class DST, class SRC>
       
  5318 Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan *spans,
       
  5319                                      void *userData)
       
  5320 {
       
  5321     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
       
  5322     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
       
  5323 
       
  5324 
       
  5325     if (mode != QPainter::CompositionMode_SourceOver) {
       
  5326         blend_src_generic<RegularSpans>(count, spans, userData);
       
  5327         return;
       
  5328     }
       
  5329 
       
  5330     SRC buffer[buffer_size];
       
  5331 
       
  5332     const int src_minx = data->texture.x1;
       
  5333     const int src_miny = data->texture.y1;
       
  5334     const int src_maxx = data->texture.x2 - 1;
       
  5335     const int src_maxy = data->texture.y2 - 1;
       
  5336 
       
  5337     if (data->fast_matrix) {
       
  5338         // The increment pr x in the scanline
       
  5339         const int fdx = (int)(data->m11 * fixed_scale);
       
  5340         const int fdy = (int)(data->m12 * fixed_scale);
       
  5341 
       
  5342         while (count--) {
       
  5343             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
       
  5344             if (coverage == 0) {
       
  5345                 ++spans;
       
  5346                 continue;
       
  5347             }
       
  5348 
       
  5349             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
       
  5350                         + spans->x;
       
  5351             const qreal cx = spans->x + qreal(0.5);
       
  5352             const qreal cy = spans->y + qreal(0.5);
       
  5353             int x = int((data->m21 * cy
       
  5354                          + data->m11 * cx + data->dx) * fixed_scale) - half_point;
       
  5355             int y = int((data->m22 * cy
       
  5356                          + data->m12 * cx + data->dy) * fixed_scale) - half_point;
       
  5357             int length = spans->len;
       
  5358 
       
  5359             while (length) {
       
  5360                 const int l = qMin(length, buffer_size);
       
  5361 
       
  5362                 const SRC *end = buffer + l;
       
  5363                 SRC *b = buffer;
       
  5364                 while (b < end) {
       
  5365                     int x1 = (x >> 16);
       
  5366                     int x2 = x1 + 1;
       
  5367                     int y1 = (y >> 16);
       
  5368                     int y2 = y1 + 1;
       
  5369 
       
  5370                     const int distx = ((x - (x1 << 16)) >> 8);
       
  5371                     const int disty = ((y - (y1 << 16)) >> 8);
       
  5372                     x1 = qBound(src_minx, x1, src_maxx);
       
  5373                     x2 = qBound(src_minx, x2, src_maxx);
       
  5374                     y1 = qBound(src_miny, y1, src_maxy);
       
  5375                     y2 = qBound(src_miny, y2, src_maxy);
       
  5376 
       
  5377 #if 0
       
  5378                     if (x1 == x2) {
       
  5379                         if (y1 == y2) {
       
  5380                             *b = ((SRC*)data->texture.scanLine(y1))[x1];
       
  5381                         } else {
       
  5382                             *b = ((SRC*)data->texture.scanLine(y1))[x1];
       
  5383                             const SRC t = data->texture.scanLine(y2)[x1];
       
  5384                             interpolate_pixel(*b, SRC::ialpha(disty),
       
  5385                                               t, SRC::alpha(disty));
       
  5386                         }
       
  5387                     } else if (y1 == y2) {
       
  5388                         *b = ((SRC*)data->texture.scanLine(y1))[x1];
       
  5389                         const SRC t = ((SRC*)data->texture.scanLine(y1))[x2];
       
  5390                         interpolate_pixel(*b, SRC::ialpha(distx),
       
  5391                                           t, SRC::alpha(distx));
       
  5392                     } else
       
  5393 #endif
       
  5394                     {
       
  5395                         const SRC *src1 = (SRC*)data->texture.scanLine(y1);
       
  5396                         const SRC *src2 = (SRC*)data->texture.scanLine(y2);
       
  5397                         SRC tl = src1[x1];
       
  5398                         const SRC tr = src1[x2];
       
  5399                         SRC bl = src2[x1];
       
  5400                         const SRC br = src2[x2];
       
  5401                         const quint8 ax = SRC::alpha(distx);
       
  5402                         const quint8 iax = SRC::ialpha(distx);
       
  5403 
       
  5404                         interpolate_pixel(tl, iax, tr, ax);
       
  5405                         interpolate_pixel(bl, iax, br, ax);
       
  5406                         interpolate_pixel(tl, SRC::ialpha(disty),
       
  5407                                           bl, SRC::alpha(disty));
       
  5408                         *b = tl;
       
  5409                     }
       
  5410                     ++b;
       
  5411 
       
  5412                     x += fdx;
       
  5413                     y += fdy;
       
  5414                 }
       
  5415 
       
  5416                 if (!SRC::hasAlpha() && coverage == 255) {
       
  5417                     qt_memconvert(dest, buffer, l);
       
  5418                 } else if (sizeof(DST) == 3 && l >= 4 &&
       
  5419                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
       
  5420                 {
       
  5421                     blendUntransformed_dest24(dest, buffer, coverage, l);
       
  5422                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
       
  5423                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
       
  5424                     blendUntransformed_dest16(dest, buffer, coverage, l);
       
  5425                 } else {
       
  5426                     blendUntransformed_unaligned(dest, buffer, coverage, l);
       
  5427                 }
       
  5428 
       
  5429                 dest += l;
       
  5430                 length -= l;
       
  5431             }
       
  5432             ++spans;
       
  5433         }
       
  5434     } else {
       
  5435         const qreal fdx = data->m11;
       
  5436         const qreal fdy = data->m12;
       
  5437         const qreal fdw = data->m13;
       
  5438 
       
  5439         while (count--) {
       
  5440             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
       
  5441             if (coverage == 0) {
       
  5442                 ++spans;
       
  5443                 continue;
       
  5444             }
       
  5445 
       
  5446             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
       
  5447                         + spans->x;
       
  5448 
       
  5449             const qreal cx = spans->x + qreal(0.5);
       
  5450             const qreal cy = spans->y + qreal(0.5);
       
  5451 
       
  5452             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
       
  5453             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
       
  5454             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
       
  5455 
       
  5456             int length = spans->len;
       
  5457             while (length) {
       
  5458                 const int l = qMin(length, buffer_size);
       
  5459                 const SRC *end = buffer + l;
       
  5460                 SRC *b = buffer;
       
  5461                 while (b < end) {
       
  5462                     const qreal iw = w == 0 ? 1 : 1 / w;
       
  5463                     const qreal px = x * iw - qreal(0.5);
       
  5464                     const qreal py = y * iw - qreal(0.5);
       
  5465 
       
  5466                     int x1 = int(px) - (px < 0);
       
  5467                     int x2 = x1 + 1;
       
  5468                     int y1 = int(py) - (py < 0);
       
  5469                     int y2 = y1 + 1;
       
  5470 
       
  5471                     const int distx = int((px - x1) * 256);
       
  5472                     const int disty = int((py - y1) * 256);
       
  5473 
       
  5474                     x1 = qBound(src_minx, x1, src_maxx);
       
  5475                     x2 = qBound(src_minx, x2, src_maxx);
       
  5476                     y1 = qBound(src_miny, y1, src_maxy);
       
  5477                     y2 = qBound(src_miny, y2, src_maxy);
       
  5478 
       
  5479                     const SRC *src1 = (SRC*)data->texture.scanLine(y1);
       
  5480                     const SRC *src2 = (SRC*)data->texture.scanLine(y2);
       
  5481                     SRC tl = src1[x1];
       
  5482                     const SRC tr = src1[x2];
       
  5483                     SRC bl = src2[x1];
       
  5484                     const SRC br = src2[x2];
       
  5485                     const quint8 ax = SRC::alpha(distx);
       
  5486                     const quint8 iax = SRC::ialpha(distx);
       
  5487 
       
  5488                     interpolate_pixel(tl, iax, tr, ax);
       
  5489                     interpolate_pixel(bl, iax, br, ax);
       
  5490                     interpolate_pixel(tl, SRC::ialpha(disty),
       
  5491                                       bl, SRC::alpha(disty));
       
  5492                     *b = tl;
       
  5493                     ++b;
       
  5494 
       
  5495                     x += fdx;
       
  5496                     y += fdy;
       
  5497                     w += fdw;
       
  5498                 }
       
  5499                 if (!SRC::hasAlpha() && coverage == 255) {
       
  5500                     qt_memconvert(dest, buffer, l);
       
  5501                 } else if (sizeof(DST) == 3 && l >= 4 &&
       
  5502                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
       
  5503                 {
       
  5504                     blendUntransformed_dest24(dest, buffer, coverage, l);
       
  5505                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
       
  5506                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
       
  5507                     blendUntransformed_dest16(dest, buffer, coverage, l);
       
  5508                 } else {
       
  5509                     blendUntransformed_unaligned(dest, buffer, coverage, l);
       
  5510                 }
       
  5511 
       
  5512                 dest += l;
       
  5513                 length -= l;
       
  5514             }
       
  5515             ++spans;
       
  5516         }
       
  5517     }
       
  5518 }
       
  5519 
       
  5520 static void blend_transformed_bilinear_rgb888(int count, const QSpan *spans, void *userData)
       
  5521 {
       
  5522 #if defined(QT_QWS_DEPTH_24)
       
  5523     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5524 
       
  5525     if (data->texture.format == QImage::Format_RGB888)
       
  5526         blendTransformedBilinear<qrgb888, qrgb888>(count, spans, userData);
       
  5527     else
       
  5528 #endif
       
  5529         blend_src_generic<RegularSpans>(count, spans, userData);
       
  5530 }
       
  5531 
       
  5532 static void blend_transformed_bilinear_argb6666(int count, const QSpan *spans, void *userData)
       
  5533 {
       
  5534 #if defined(QT_QWS_DEPTH_18)
       
  5535     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5536 
       
  5537     if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
       
  5538         blendTransformedBilinear<qargb6666, qargb6666>(count, spans, userData);
       
  5539     else if (data->texture.format == QImage::Format_RGB666)
       
  5540         blendTransformedBilinear<qargb6666, qrgb666>(count, spans, userData);
       
  5541     else
       
  5542 #endif
       
  5543         blend_src_generic<RegularSpans>(count, spans, userData);
       
  5544 }
       
  5545 
       
  5546 static void blend_transformed_bilinear_rgb666(int count, const QSpan *spans, void *userData)
       
  5547 {
       
  5548 #if defined(QT_QWS_DEPTH_18)
       
  5549     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5550 
       
  5551     if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
       
  5552         blendTransformedBilinear<qrgb666, qargb6666>(count, spans, userData);
       
  5553     else if (data->texture.format == QImage::Format_RGB666)
       
  5554         blendTransformedBilinear<qrgb666, qrgb666>(count, spans, userData);
       
  5555     else
       
  5556 #endif
       
  5557         blend_src_generic<RegularSpans>(count, spans, userData);
       
  5558 }
       
  5559 
       
  5560 static void blend_transformed_bilinear_argb8565(int count, const QSpan *spans, void *userData)
       
  5561 {
       
  5562 #if defined(QT_QWS_DEPTH_16)
       
  5563     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5564 
       
  5565     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
       
  5566         blendTransformedBilinear<qargb8565, qargb8565>(count, spans, userData);
       
  5567     else if (data->texture.format == QImage::Format_RGB16)
       
  5568         blendTransformedBilinear<qargb8565, qrgb565>(count, spans, userData);
       
  5569     else
       
  5570 #endif
       
  5571         blend_src_generic<RegularSpans>(count, spans, userData);
       
  5572 }
       
  5573 
       
  5574 static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans,
       
  5575                                               void *userData)
       
  5576 {
       
  5577 #if defined(QT_QWS_DEPTH_16)
       
  5578     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5579 
       
  5580     if (data->texture.format == QImage::Format_RGB16)
       
  5581         blendTransformedBilinear<qrgb565, qrgb565>(count, spans, userData);
       
  5582     else if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
       
  5583         blendTransformedBilinear<qrgb565, qargb8565>(count, spans, userData);
       
  5584     else
       
  5585 #endif
       
  5586         blend_src_generic<RegularSpans>(count, spans, userData);
       
  5587 }
       
  5588 
       
  5589 static void blend_transformed_bilinear_argb8555(int count, const QSpan *spans, void *userData)
       
  5590 {
       
  5591 #if defined(QT_QWS_DEPTH_15)
       
  5592     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5593 
       
  5594     if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
       
  5595         blendTransformedBilinear<qargb8555, qargb8555>(count, spans, userData);
       
  5596     else if (data->texture.format == QImage::Format_RGB555)
       
  5597         blendTransformedBilinear<qargb8555, qrgb555>(count, spans, userData);
       
  5598     else
       
  5599 #endif
       
  5600         blend_src_generic<RegularSpans>(count, spans, userData);
       
  5601 }
       
  5602 
       
  5603 static void blend_transformed_bilinear_rgb555(int count, const QSpan *spans, void *userData)
       
  5604 {
       
  5605 #if defined(QT_QWS_DEPTH_15)
       
  5606     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5607 
       
  5608     if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
       
  5609         blendTransformedBilinear<qrgb555, qargb8555>(count, spans, userData);
       
  5610     else if (data->texture.format == QImage::Format_RGB555)
       
  5611         blendTransformedBilinear<qrgb555, qrgb555>(count, spans, userData);
       
  5612     else
       
  5613 #endif
       
  5614         blend_src_generic<RegularSpans>(count, spans, userData);
       
  5615 }
       
  5616 
       
  5617 static void blend_transformed_bilinear_argb4444(int count, const QSpan *spans, void *userData)
       
  5618 {
       
  5619 #if defined(QT_QWS_DEPTH_12)
       
  5620     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5621 
       
  5622     if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
       
  5623         blendTransformedBilinear<qargb4444, qargb4444>(count, spans, userData);
       
  5624     else if (data->texture.format == QImage::Format_RGB444)
       
  5625         blendTransformedBilinear<qargb4444, qrgb444>(count, spans, userData);
       
  5626     else
       
  5627 #endif
       
  5628         blend_src_generic<RegularSpans>(count, spans, userData);
       
  5629 }
       
  5630 
       
  5631 static void blend_transformed_bilinear_rgb444(int count, const QSpan *spans, void *userData)
       
  5632 {
       
  5633 #if defined(QT_QWS_DEPTH_12)
       
  5634     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5635 
       
  5636     if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
       
  5637         blendTransformedBilinear<qrgb444, qargb4444>(count, spans, userData);
       
  5638     else if (data->texture.format == QImage::Format_RGB444)
       
  5639         blendTransformedBilinear<qrgb444, qrgb444>(count, spans, userData);
       
  5640     else
       
  5641 #endif
       
  5642         blend_src_generic<RegularSpans>(count, spans, userData);
       
  5643 }
       
  5644 
       
  5645 template <SpanMethod spanMethod>
       
  5646 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_bilinear_tiled_argb(int count, const QSpan *spans, void *userData)
       
  5647 {
       
  5648     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5649     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
       
  5650         && data->texture.format != QImage::Format_RGB32) {
       
  5651         blend_src_generic<spanMethod>(count, spans, userData);
       
  5652         return;
       
  5653     }
       
  5654 
       
  5655     CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
       
  5656     uint buffer[buffer_size];
       
  5657 
       
  5658     int image_width = data->texture.width;
       
  5659     int image_height = data->texture.height;
       
  5660     const int scanline_offset = data->texture.bytesPerLine / 4;
       
  5661 
       
  5662     if (data->fast_matrix) {
       
  5663         // The increment pr x in the scanline
       
  5664         int fdx = (int)(data->m11 * fixed_scale);
       
  5665         int fdy = (int)(data->m12 * fixed_scale);
       
  5666 
       
  5667         while (count--) {
       
  5668             void *t = data->rasterBuffer->scanLine(spans->y);
       
  5669 
       
  5670             uint *target = ((uint *)t) + spans->x;
       
  5671             uint *image_bits = (uint *)data->texture.imageData;
       
  5672 
       
  5673             const qreal cx = spans->x + 0.5;
       
  5674             const qreal cy = spans->y + 0.5;
       
  5675 
       
  5676             int x = int((data->m21 * cy
       
  5677                          + data->m11 * cx + data->dx) * fixed_scale) - half_point;
       
  5678             int y = int((data->m22 * cy
       
  5679                          + data->m12 * cx + data->dy) * fixed_scale) - half_point;
       
  5680 
       
  5681             int length = spans->len;
       
  5682             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
       
  5683             while (length) {
       
  5684                 int l = qMin(length, buffer_size);
       
  5685                 const uint *end = buffer + l;
       
  5686                 uint *b = buffer;
       
  5687                 while (b < end) {
       
  5688                     int x1 = (x >> 16);
       
  5689                     int x2 = (x1 + 1);
       
  5690                     int y1 = (y >> 16);
       
  5691                     int y2 = (y1 + 1);
       
  5692 
       
  5693                     int distx = ((x - (x1 << 16)) >> 8);
       
  5694                     int disty = ((y - (y1 << 16)) >> 8);
       
  5695                     int idistx = 256 - distx;
       
  5696                     int idisty = 256 - disty;
       
  5697 
       
  5698                     x1 %= image_width;
       
  5699                     x2 %= image_width;
       
  5700                     y1 %= image_height;
       
  5701                     y2 %= image_height;
       
  5702 
       
  5703                     if (x1 < 0) x1 += image_width;
       
  5704                     if (x2 < 0) x2 += image_width;
       
  5705                     if (y1 < 0) y1 += image_height;
       
  5706                     if (y2 < 0) y2 += image_height;
       
  5707 
       
  5708                     Q_ASSERT(x1 >= 0 && x1 < image_width);
       
  5709                     Q_ASSERT(x2 >= 0 && x2 < image_width);
       
  5710                     Q_ASSERT(y1 >= 0 && y1 < image_height);
       
  5711                     Q_ASSERT(y2 >= 0 && y2 < image_height);
       
  5712 
       
  5713                     int y1_offset = y1 * scanline_offset;
       
  5714                     int y2_offset = y2 * scanline_offset;
       
  5715 
       
  5716 #if defined(Q_IRIX_GCC3_3_WORKAROUND)
       
  5717                     uint tl = gccBug(image_bits[y1_offset + x1]);
       
  5718                     uint tr = gccBug(image_bits[y1_offset + x2]);
       
  5719                     uint bl = gccBug(image_bits[y2_offset + x1]);
       
  5720                     uint br = gccBug(image_bits[y2_offset + x2]);
       
  5721 #else
       
  5722                     uint tl = image_bits[y1_offset + x1];
       
  5723                     uint tr = image_bits[y1_offset + x2];
       
  5724                     uint bl = image_bits[y2_offset + x1];
       
  5725                     uint br = image_bits[y2_offset + x2];
       
  5726 #endif
       
  5727 
       
  5728                     uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
       
  5729                     uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
       
  5730                     *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
       
  5731                     ++b;
       
  5732                     x += fdx;
       
  5733                     y += fdy;
       
  5734                 }
       
  5735                 if (spanMethod == RegularSpans)
       
  5736                     func(target, buffer, l, coverage);
       
  5737                 else
       
  5738                     drawBufferSpan(data, buffer, buffer_size,
       
  5739                                    spans->x + spans->len - length,
       
  5740                                    spans->y, l, coverage);
       
  5741                 target += l;
       
  5742                 length -= l;
       
  5743             }
       
  5744             ++spans;
       
  5745         }
       
  5746     } else {
       
  5747         const qreal fdx = data->m11;
       
  5748         const qreal fdy = data->m12;
       
  5749         const qreal fdw = data->m13;
       
  5750         while (count--) {
       
  5751             void *t = data->rasterBuffer->scanLine(spans->y);
       
  5752 
       
  5753             uint *target = ((uint *)t) + spans->x;
       
  5754             uint *image_bits = (uint *)data->texture.imageData;
       
  5755 
       
  5756             const qreal cx = spans->x + 0.5;
       
  5757             const qreal cy = spans->y + 0.5;
       
  5758 
       
  5759             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
       
  5760             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
       
  5761             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
       
  5762 
       
  5763             int length = spans->len;
       
  5764             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
       
  5765             while (length) {
       
  5766                 int l = qMin(length, buffer_size);
       
  5767                 const uint *end = buffer + l;
       
  5768                 uint *b = buffer;
       
  5769                 while (b < end) {
       
  5770                     const qreal iw = w == 0 ? 1 : 1 / w;
       
  5771                     const qreal px = x * iw - 0.5;
       
  5772                     const qreal py = y * iw - 0.5;
       
  5773 
       
  5774                     int x1 = int(px) - (px < 0);
       
  5775                     int x2 = x1 + 1;
       
  5776                     int y1 = int(py) - (py < 0);
       
  5777                     int y2 = y1 + 1;
       
  5778 
       
  5779                     int distx = int((px - x1) * 256);
       
  5780                     int disty = int((py - y1) * 256);
       
  5781                     int idistx = 256 - distx;
       
  5782                     int idisty = 256 - disty;
       
  5783 
       
  5784                     x1 %= image_width;
       
  5785                     x2 %= image_width;
       
  5786                     y1 %= image_height;
       
  5787                     y2 %= image_height;
       
  5788 
       
  5789                     if (x1 < 0) x1 += image_width;
       
  5790                     if (x2 < 0) x2 += image_width;
       
  5791                     if (y1 < 0) y1 += image_height;
       
  5792                     if (y2 < 0) y2 += image_height;
       
  5793 
       
  5794                     Q_ASSERT(x1 >= 0 && x1 < image_width);
       
  5795                     Q_ASSERT(x2 >= 0 && x2 < image_width);
       
  5796                     Q_ASSERT(y1 >= 0 && y1 < image_height);
       
  5797                     Q_ASSERT(y2 >= 0 && y2 < image_height);
       
  5798 
       
  5799                     int y1_offset = y1 * scanline_offset;
       
  5800                     int y2_offset = y2 * scanline_offset;
       
  5801 
       
  5802 #if defined(Q_IRIX_GCC3_3_WORKAROUND)
       
  5803                     uint tl = gccBug(image_bits[y1_offset + x1]);
       
  5804                     uint tr = gccBug(image_bits[y1_offset + x2]);
       
  5805                     uint bl = gccBug(image_bits[y2_offset + x1]);
       
  5806                     uint br = gccBug(image_bits[y2_offset + x2]);
       
  5807 #else
       
  5808                     uint tl = image_bits[y1_offset + x1];
       
  5809                     uint tr = image_bits[y1_offset + x2];
       
  5810                     uint bl = image_bits[y2_offset + x1];
       
  5811                     uint br = image_bits[y2_offset + x2];
       
  5812 #endif
       
  5813 
       
  5814                     uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
       
  5815                     uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
       
  5816                     *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
       
  5817                     ++b;
       
  5818                     x += fdx;
       
  5819                     y += fdy;
       
  5820                     w += fdw;
       
  5821                 }
       
  5822                 if (spanMethod == RegularSpans)
       
  5823                     func(target, buffer, l, coverage);
       
  5824                 else
       
  5825                     drawBufferSpan(data, buffer, buffer_size,
       
  5826                                    spans->x + spans->len - length,
       
  5827                                    spans->y, l, coverage);
       
  5828                 target += l;
       
  5829                 length -= l;
       
  5830             }
       
  5831             ++spans;
       
  5832         }
       
  5833     }
       
  5834 }
       
  5835 
       
  5836 template <SpanMethod spanMethod>
       
  5837 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *spans, void *userData)
       
  5838 {
       
  5839     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  5840     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
       
  5841         && data->texture.format != QImage::Format_RGB32) {
       
  5842         blend_src_generic<spanMethod>(count, spans, userData);
       
  5843         return;
       
  5844     }
       
  5845 
       
  5846     CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
       
  5847     uint buffer[buffer_size];
       
  5848 
       
  5849     int image_width = data->texture.width;
       
  5850     int image_height = data->texture.height;
       
  5851     const int scanline_offset = data->texture.bytesPerLine / 4;
       
  5852 
       
  5853     if (data->fast_matrix) {
       
  5854         // The increment pr x in the scanline
       
  5855         int fdx = (int)(data->m11 * fixed_scale);
       
  5856         int fdy = (int)(data->m12 * fixed_scale);
       
  5857 
       
  5858         while (count--) {
       
  5859             void *t = data->rasterBuffer->scanLine(spans->y);
       
  5860 
       
  5861             uint *target = ((uint *)t) + spans->x;
       
  5862             uint *image_bits = (uint *)data->texture.imageData;
       
  5863 
       
  5864             const qreal cx = spans->x + 0.5;
       
  5865             const qreal cy = spans->y + 0.5;
       
  5866 
       
  5867             int x = int((data->m21 * cy
       
  5868                          + data->m11 * cx + data->dx) * fixed_scale);
       
  5869             int y = int((data->m22 * cy
       
  5870                          + data->m12 * cx + data->dy) * fixed_scale);
       
  5871 
       
  5872             int length = spans->len;
       
  5873             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
       
  5874             while (length) {
       
  5875                 int l = qMin(length, buffer_size);
       
  5876                 const uint *end = buffer + l;
       
  5877                 uint *b = buffer;
       
  5878                 while (b < end) {
       
  5879                     int px = x >> 16;
       
  5880                     int py = y >> 16;
       
  5881 
       
  5882                     bool out = (px < 0) || (px >= image_width)
       
  5883                                || (py < 0) || (py >= image_height);
       
  5884 
       
  5885                     int y_offset = py * scanline_offset;
       
  5886                     *b = out ? uint(0) : image_bits[y_offset + px];
       
  5887                     x += fdx;
       
  5888                     y += fdy;
       
  5889                     ++b;
       
  5890                 }
       
  5891                 if (spanMethod == RegularSpans)
       
  5892                     func(target, buffer, l, coverage);
       
  5893                 else
       
  5894                     drawBufferSpan(data, buffer, buffer_size,
       
  5895                                    spans->x + spans->len - length,
       
  5896                                    spans->y, l, coverage);
       
  5897                 target += l;
       
  5898                 length -= l;
       
  5899             }
       
  5900             ++spans;
       
  5901         }
       
  5902     } else {
       
  5903         const qreal fdx = data->m11;
       
  5904         const qreal fdy = data->m12;
       
  5905         const qreal fdw = data->m13;
       
  5906         while (count--) {
       
  5907             void *t = data->rasterBuffer->scanLine(spans->y);
       
  5908 
       
  5909             uint *target = ((uint *)t) + spans->x;
       
  5910             uint *image_bits = (uint *)data->texture.imageData;
       
  5911 
       
  5912             const qreal cx = spans->x + 0.5;
       
  5913             const qreal cy = spans->y + 0.5;
       
  5914 
       
  5915             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
       
  5916             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
       
  5917             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
       
  5918 
       
  5919             int length = spans->len;
       
  5920             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
       
  5921             while (length) {
       
  5922                 int l = qMin(length, buffer_size);
       
  5923                 const uint *end = buffer + l;
       
  5924                 uint *b = buffer;
       
  5925                 while (b < end) {
       
  5926                     const qreal iw = w == 0 ? 1 : 1 / w;
       
  5927                     const qreal tx = x * iw;
       
  5928                     const qreal ty = y * iw;
       
  5929                     const int px = int(tx) - (tx < 0);
       
  5930                     const int py = int(ty) - (ty < 0);
       
  5931 
       
  5932                     bool out = (px < 0) || (px >= image_width)
       
  5933                                || (py < 0) || (py >= image_height);
       
  5934 
       
  5935                     int y_offset = py * scanline_offset;
       
  5936                     *b = out ? uint(0) : image_bits[y_offset + px];
       
  5937                     x += fdx;
       
  5938                     y += fdy;
       
  5939                     w += fdw;
       
  5940 
       
  5941                     ++b;
       
  5942                 }
       
  5943                 if (spanMethod == RegularSpans)
       
  5944                     func(target, buffer, l, coverage);
       
  5945                 else
       
  5946                     drawBufferSpan(data, buffer, buffer_size,
       
  5947                                    spans->x + spans->len - length,
       
  5948                                    spans->y, l, coverage);
       
  5949                 target += l;
       
  5950                 length -= l;
       
  5951             }
       
  5952             ++spans;
       
  5953         }
       
  5954     }
       
  5955 }
       
  5956 
       
  5957 template <class DST, class SRC>
       
  5958 Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans, void *userData)
       
  5959 {
       
  5960     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
       
  5961     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
       
  5962 
       
  5963     if (mode != QPainter::CompositionMode_SourceOver) {
       
  5964         blend_src_generic<RegularSpans>(count, spans, userData);
       
  5965         return;
       
  5966     }
       
  5967 
       
  5968     SRC buffer[buffer_size];
       
  5969     const int image_width = data->texture.width;
       
  5970     const int image_height = data->texture.height;
       
  5971 
       
  5972     if (data->fast_matrix) {
       
  5973         // The increment pr x in the scanline
       
  5974         const int fdx = (int)(data->m11 * fixed_scale);
       
  5975         const int fdy = (int)(data->m12 * fixed_scale);
       
  5976 
       
  5977         while (count--) {
       
  5978             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
       
  5979             if (coverage == 0) {
       
  5980                 ++spans;
       
  5981                 continue;
       
  5982             }
       
  5983 
       
  5984             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
       
  5985                         + spans->x;
       
  5986             const qreal cx = spans->x + qreal(0.5);
       
  5987             const qreal cy = spans->y + qreal(0.5);
       
  5988             int x = int((data->m21 * cy
       
  5989                          + data->m11 * cx + data->dx) * fixed_scale);
       
  5990             int y = int((data->m22 * cy
       
  5991                          + data->m12 * cx + data->dy) * fixed_scale);
       
  5992             int length = spans->len;
       
  5993 
       
  5994             while (length) {
       
  5995                 const int l = qMin(length, buffer_size);
       
  5996 
       
  5997                 const SRC *end = buffer + l;
       
  5998                 SRC *b = buffer;
       
  5999                 while (b < end) {
       
  6000                     const int px = (x >> 16);
       
  6001                     const int py = (y >> 16);
       
  6002 
       
  6003                     if ((px < 0) || (px >= image_width) ||
       
  6004                         (py < 0) || (py >= image_height))
       
  6005                     {
       
  6006                         *b = 0;
       
  6007                     } else {
       
  6008                         *b = ((SRC*)data->texture.scanLine(py))[px];
       
  6009                     }
       
  6010                     ++b;
       
  6011 
       
  6012                     x += fdx;
       
  6013                     y += fdy;
       
  6014                 }
       
  6015 
       
  6016                 if (!SRC::hasAlpha() && coverage == 255) {
       
  6017                     qt_memconvert(dest, buffer, l);
       
  6018                 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
       
  6019                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
       
  6020                 {
       
  6021                     blendUntransformed_dest24(dest, buffer, coverage, l);
       
  6022                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
       
  6023                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
       
  6024                     blendUntransformed_dest16(dest, buffer, coverage, l);
       
  6025                 } else {
       
  6026                     blendUntransformed_unaligned(dest, buffer, coverage, l);
       
  6027                 }
       
  6028 
       
  6029                 dest += l;
       
  6030                 length -= l;
       
  6031             }
       
  6032             ++spans;
       
  6033         }
       
  6034     } else {
       
  6035         const qreal fdx = data->m11;
       
  6036         const qreal fdy = data->m12;
       
  6037         const qreal fdw = data->m13;
       
  6038 
       
  6039         while (count--) {
       
  6040             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
       
  6041             if (coverage == 0) {
       
  6042                 ++spans;
       
  6043                 continue;
       
  6044             }
       
  6045 
       
  6046             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
       
  6047                         + spans->x;
       
  6048 
       
  6049             const qreal cx = spans->x + qreal(0.5);
       
  6050             const qreal cy = spans->y + qreal(0.5);
       
  6051 
       
  6052             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
       
  6053             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
       
  6054             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
       
  6055 
       
  6056             int length = spans->len;
       
  6057             while (length) {
       
  6058                 const int l = qMin(length, buffer_size);
       
  6059                 const SRC *end = buffer + l;
       
  6060                 SRC *b = buffer;
       
  6061                 while (b < end) {
       
  6062                     const qreal iw = w == 0 ? 1 : 1 / w;
       
  6063                     const qreal tx = x * iw;
       
  6064                     const qreal ty = y * iw;
       
  6065 
       
  6066                     const int px = int(tx) - (tx < 0);
       
  6067                     const int py = int(ty) - (ty < 0);
       
  6068 
       
  6069                     if ((px < 0) || (px >= image_width) ||
       
  6070                         (py < 0) || (py >= image_height))
       
  6071                     {
       
  6072                         *b = 0;
       
  6073                     } else {
       
  6074                         *b = ((SRC*)data->texture.scanLine(py))[px];
       
  6075                     }
       
  6076                     ++b;
       
  6077 
       
  6078                     x += fdx;
       
  6079                     y += fdy;
       
  6080                     w += fdw;
       
  6081                 }
       
  6082                 if (!SRC::hasAlpha() && coverage == 255) {
       
  6083                     qt_memconvert(dest, buffer, l);
       
  6084                 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
       
  6085                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
       
  6086                 {
       
  6087                     blendUntransformed_dest24(dest, buffer, coverage, l);
       
  6088                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
       
  6089                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
       
  6090                     blendUntransformed_dest16(dest, buffer, coverage, l);
       
  6091                 } else {
       
  6092                     blendUntransformed_unaligned(dest, buffer, coverage, l);
       
  6093                 }
       
  6094 
       
  6095                 dest += l;
       
  6096                 length -= l;
       
  6097             }
       
  6098             ++spans;
       
  6099         }
       
  6100     }
       
  6101 }
       
  6102 
       
  6103 static void blend_transformed_rgb888(int count, const QSpan *spans,
       
  6104                                      void *userData)
       
  6105 {
       
  6106 #if defined(QT_QWS_DEPTH_24)
       
  6107     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6108 
       
  6109     if (data->texture.format == QImage::Format_RGB888)
       
  6110         blendTransformed<qrgb888, qrgb888>(count, spans, userData);
       
  6111     else
       
  6112 #endif
       
  6113         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6114 }
       
  6115 
       
  6116 static void blend_transformed_argb6666(int count, const QSpan *spans,
       
  6117                                        void *userData)
       
  6118 {
       
  6119 #if defined(QT_QWS_DEPTH_18)
       
  6120     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6121 
       
  6122     if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
       
  6123         blendTransformed<qargb6666, qargb6666>(count, spans, userData);
       
  6124     else if (data->texture.format == QImage::Format_RGB666)
       
  6125         blendTransformed<qargb6666, qrgb666>(count, spans, userData);
       
  6126     else
       
  6127 #endif
       
  6128         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6129 }
       
  6130 
       
  6131 static void blend_transformed_rgb666(int count, const QSpan *spans,
       
  6132                                        void *userData)
       
  6133 {
       
  6134 #if defined(QT_QWS_DEPTH_18)
       
  6135     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6136 
       
  6137     if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
       
  6138         blendTransformed<qrgb666, qargb6666>(count, spans, userData);
       
  6139     else if (data->texture.format == QImage::Format_RGB666)
       
  6140         blendTransformed<qrgb666, qrgb666>(count, spans, userData);
       
  6141     else
       
  6142 #endif
       
  6143         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6144 }
       
  6145 
       
  6146 static void blend_transformed_argb8565(int count, const QSpan *spans,
       
  6147                                          void *userData)
       
  6148 {
       
  6149 #if defined(QT_QWS_DEPTH_16)
       
  6150     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6151 
       
  6152     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
       
  6153         blendTransformed<qargb8565, qargb8565>(count, spans, userData);
       
  6154     else if (data->texture.format == QImage::Format_RGB16)
       
  6155         blendTransformed<qargb8565, qrgb565>(count, spans, userData);
       
  6156     else
       
  6157 #endif
       
  6158         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6159 }
       
  6160 
       
  6161 static void blend_transformed_rgb565(int count, const QSpan *spans,
       
  6162                                        void *userData)
       
  6163 {
       
  6164 #if defined(QT_QWS_DEPTH_16)
       
  6165     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6166 
       
  6167     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
       
  6168         blendTransformed<qrgb565, qargb8565>(count, spans, userData);
       
  6169     else if (data->texture.format == QImage::Format_RGB16)
       
  6170         blendTransformed<qrgb565, qrgb565>(count, spans, userData);
       
  6171     else
       
  6172 #endif
       
  6173         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6174 }
       
  6175 
       
  6176 static void blend_transformed_argb8555(int count, const QSpan *spans,
       
  6177                                          void *userData)
       
  6178 {
       
  6179 #if defined(QT_QWS_DEPTH_15)
       
  6180     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6181 
       
  6182     if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
       
  6183         blendTransformed<qargb8555, qargb8555>(count, spans, userData);
       
  6184     else if (data->texture.format == QImage::Format_RGB555)
       
  6185         blendTransformed<qargb8555, qrgb555>(count, spans, userData);
       
  6186     else
       
  6187 #endif
       
  6188         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6189 }
       
  6190 
       
  6191 static void blend_transformed_rgb555(int count, const QSpan *spans,
       
  6192                                        void *userData)
       
  6193 {
       
  6194 #if defined(QT_QWS_DEPTH_15)
       
  6195     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6196 
       
  6197     if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
       
  6198         blendTransformed<qrgb555, qargb8555>(count, spans, userData);
       
  6199     else if (data->texture.format == QImage::Format_RGB555)
       
  6200         blendTransformed<qrgb555, qrgb555>(count, spans, userData);
       
  6201     else
       
  6202 #endif
       
  6203         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6204 }
       
  6205 
       
  6206 static void blend_transformed_argb4444(int count, const QSpan *spans,
       
  6207                                          void *userData)
       
  6208 {
       
  6209 #if defined(QT_QWS_DEPTH_12)
       
  6210     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6211 
       
  6212     if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
       
  6213         blendTransformed<qargb4444, qargb4444>(count, spans, userData);
       
  6214     else if (data->texture.format == QImage::Format_RGB444)
       
  6215         blendTransformed<qargb4444, qrgb444>(count, spans, userData);
       
  6216     else
       
  6217 #endif
       
  6218         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6219 }
       
  6220 
       
  6221 static void blend_transformed_rgb444(int count, const QSpan *spans,
       
  6222                                        void *userData)
       
  6223 {
       
  6224 #if defined(QT_QWS_DEPTH_12)
       
  6225     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6226 
       
  6227     if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
       
  6228         blendTransformed<qrgb444, qargb4444>(count, spans, userData);
       
  6229     else if (data->texture.format == QImage::Format_RGB444)
       
  6230         blendTransformed<qrgb444, qrgb444>(count, spans, userData);
       
  6231     else
       
  6232 #endif
       
  6233         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6234 }
       
  6235 
       
  6236 template <SpanMethod spanMethod>
       
  6237 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QSpan *spans, void *userData)
       
  6238 {
       
  6239     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6240     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
       
  6241         && data->texture.format != QImage::Format_RGB32) {
       
  6242         blend_src_generic<spanMethod>(count, spans, userData);
       
  6243         return;
       
  6244     }
       
  6245 
       
  6246     CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
       
  6247     uint buffer[buffer_size];
       
  6248 
       
  6249     int image_width = data->texture.width;
       
  6250     int image_height = data->texture.height;
       
  6251     const int scanline_offset = data->texture.bytesPerLine / 4;
       
  6252 
       
  6253     if (data->fast_matrix) {
       
  6254         // The increment pr x in the scanline
       
  6255         int fdx = (int)(data->m11 * fixed_scale);
       
  6256         int fdy = (int)(data->m12 * fixed_scale);
       
  6257 
       
  6258         while (count--) {
       
  6259             void *t = data->rasterBuffer->scanLine(spans->y);
       
  6260 
       
  6261             uint *target = ((uint *)t) + spans->x;
       
  6262             uint *image_bits = (uint *)data->texture.imageData;
       
  6263 
       
  6264             const qreal cx = spans->x + 0.5;
       
  6265             const qreal cy = spans->y + 0.5;
       
  6266 
       
  6267             int x = int((data->m21 * cy
       
  6268                          + data->m11 * cx + data->dx) * fixed_scale);
       
  6269             int y = int((data->m22 * cy
       
  6270                          + data->m12 * cx + data->dy) * fixed_scale);
       
  6271 
       
  6272             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
       
  6273             int length = spans->len;
       
  6274             while (length) {
       
  6275                 int l = qMin(length, buffer_size);
       
  6276                 const uint *end = buffer + l;
       
  6277                 uint *b = buffer;
       
  6278                 while (b < end) {
       
  6279                     int px = x >> 16;
       
  6280                     int py = y >> 16;
       
  6281                     px %= image_width;
       
  6282                     py %= image_height;
       
  6283                     if (px < 0) px += image_width;
       
  6284                     if (py < 0) py += image_height;
       
  6285                     int y_offset = py * scanline_offset;
       
  6286 
       
  6287                     Q_ASSERT(px >= 0 && px < image_width);
       
  6288                     Q_ASSERT(py >= 0 && py < image_height);
       
  6289 
       
  6290                     *b = image_bits[y_offset + px];
       
  6291                     x += fdx;
       
  6292                     y += fdy;
       
  6293                     ++b;
       
  6294                 }
       
  6295                 if (spanMethod == RegularSpans)
       
  6296                     func(target, buffer, l, coverage);
       
  6297                 else
       
  6298                     drawBufferSpan(data, buffer, buffer_size,
       
  6299                                    spans->x + spans->len - length,
       
  6300                                    spans->y, l, coverage);
       
  6301                 target += l;
       
  6302                 length -= l;
       
  6303             }
       
  6304             ++spans;
       
  6305         }
       
  6306     } else {
       
  6307         const qreal fdx = data->m11;
       
  6308         const qreal fdy = data->m12;
       
  6309         const qreal fdw = data->m13;
       
  6310         while (count--) {
       
  6311             void *t = data->rasterBuffer->scanLine(spans->y);
       
  6312 
       
  6313             uint *target = ((uint *)t) + spans->x;
       
  6314             uint *image_bits = (uint *)data->texture.imageData;
       
  6315 
       
  6316             const qreal cx = spans->x + 0.5;
       
  6317             const qreal cy = spans->y + 0.5;
       
  6318 
       
  6319             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
       
  6320             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
       
  6321             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
       
  6322 
       
  6323             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
       
  6324             int length = spans->len;
       
  6325             while (length) {
       
  6326                 int l = qMin(length, buffer_size);
       
  6327                 const uint *end = buffer + l;
       
  6328                 uint *b = buffer;
       
  6329                 while (b < end) {
       
  6330                     const qreal iw = w == 0 ? 1 : 1 / w;
       
  6331                     const qreal tx = x * iw;
       
  6332                     const qreal ty = y * iw;
       
  6333                     int px = int(tx) - (tx < 0);
       
  6334                     int py = int(ty) - (ty < 0);
       
  6335 
       
  6336                     px %= image_width;
       
  6337                     py %= image_height;
       
  6338                     if (px < 0) px += image_width;
       
  6339                     if (py < 0) py += image_height;
       
  6340                     int y_offset = py * scanline_offset;
       
  6341 
       
  6342                     Q_ASSERT(px >= 0 && px < image_width);
       
  6343                     Q_ASSERT(py >= 0 && py < image_height);
       
  6344 
       
  6345                     *b = image_bits[y_offset + px];
       
  6346                     x += fdx;
       
  6347                     y += fdy;
       
  6348                     w += fdw;
       
  6349                     //force increment to avoid /0
       
  6350                     if (!w) {
       
  6351                         w += fdw;
       
  6352                     }
       
  6353                     ++b;
       
  6354                 }
       
  6355                 if (spanMethod == RegularSpans)
       
  6356                     func(target, buffer, l, coverage);
       
  6357                 else
       
  6358                     drawBufferSpan(data, buffer, buffer_size,
       
  6359                                    spans->x + spans->len - length,
       
  6360                                    spans->y, l, coverage);
       
  6361                 target += l;
       
  6362                 length -= l;
       
  6363             }
       
  6364             ++spans;
       
  6365         }
       
  6366     }
       
  6367 }
       
  6368 
       
  6369 template <class DST, class SRC>
       
  6370 Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *spans, void *userData)
       
  6371 {
       
  6372     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
       
  6373     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
       
  6374 
       
  6375     if (mode != QPainter::CompositionMode_SourceOver) {
       
  6376         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6377         return;
       
  6378     }
       
  6379 
       
  6380     SRC buffer[buffer_size];
       
  6381     const int image_width = data->texture.width;
       
  6382     const int image_height = data->texture.height;
       
  6383 
       
  6384     if (data->fast_matrix) {
       
  6385         // The increment pr x in the scanline
       
  6386         const int fdx = (int)(data->m11 * fixed_scale);
       
  6387         const int fdy = (int)(data->m12 * fixed_scale);
       
  6388 
       
  6389         while (count--) {
       
  6390             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
       
  6391             if (coverage == 0) {
       
  6392                 ++spans;
       
  6393                 continue;
       
  6394             }
       
  6395 
       
  6396             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
       
  6397                         + spans->x;
       
  6398             const qreal cx = spans->x + qreal(0.5);
       
  6399             const qreal cy = spans->y + qreal(0.5);
       
  6400             int x = int((data->m21 * cy
       
  6401                          + data->m11 * cx + data->dx) * fixed_scale);
       
  6402             int y = int((data->m22 * cy
       
  6403                          + data->m12 * cx + data->dy) * fixed_scale);
       
  6404             int length = spans->len;
       
  6405 
       
  6406             while (length) {
       
  6407                 const int l = qMin(length, buffer_size);
       
  6408 
       
  6409                 const SRC *end = buffer + l;
       
  6410                 SRC *b = buffer;
       
  6411                 while (b < end) {
       
  6412                     int px = (x >> 16) % image_width;
       
  6413                     int py = (y >> 16) % image_height;
       
  6414 
       
  6415                     if (px < 0)
       
  6416                         px += image_width;
       
  6417                     if (py < 0)
       
  6418                         py += image_height;
       
  6419 
       
  6420                     *b = ((SRC*)data->texture.scanLine(py))[px];
       
  6421                     ++b;
       
  6422 
       
  6423                     x += fdx;
       
  6424                     y += fdy;
       
  6425                 }
       
  6426 
       
  6427                 if (!SRC::hasAlpha() && coverage == 255) {
       
  6428                     qt_memconvert(dest, buffer, l);
       
  6429                 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
       
  6430                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
       
  6431                 {
       
  6432                     blendUntransformed_dest24(dest, buffer, coverage, l);
       
  6433                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
       
  6434                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
       
  6435                     blendUntransformed_dest16(dest, buffer, coverage, l);
       
  6436                 } else {
       
  6437                     blendUntransformed_unaligned(dest, buffer, coverage, l);
       
  6438                 }
       
  6439 
       
  6440                 dest += l;
       
  6441                 length -= l;
       
  6442             }
       
  6443             ++spans;
       
  6444         }
       
  6445     } else {
       
  6446         const qreal fdx = data->m11;
       
  6447         const qreal fdy = data->m12;
       
  6448         const qreal fdw = data->m13;
       
  6449 
       
  6450         while (count--) {
       
  6451             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
       
  6452             if (coverage == 0) {
       
  6453                 ++spans;
       
  6454                 continue;
       
  6455             }
       
  6456 
       
  6457             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
       
  6458                         + spans->x;
       
  6459 
       
  6460             const qreal cx = spans->x + qreal(0.5);
       
  6461             const qreal cy = spans->y + qreal(0.5);
       
  6462 
       
  6463             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
       
  6464             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
       
  6465             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
       
  6466 
       
  6467             int length = spans->len;
       
  6468             while (length) {
       
  6469                 const int l = qMin(length, buffer_size);
       
  6470                 const SRC *end = buffer + l;
       
  6471                 SRC *b = buffer;
       
  6472                 while (b < end) {
       
  6473                     const qreal iw = w == 0 ? 1 : 1 / w;
       
  6474                     const qreal tx = x * iw;
       
  6475                     const qreal ty = y * iw;
       
  6476 
       
  6477                     int px = int(tx) - (tx < 0);
       
  6478                     int py = int(ty) - (ty < 0);
       
  6479 
       
  6480                     if (px < 0)
       
  6481                         px += image_width;
       
  6482                     if (py < 0)
       
  6483                         py += image_height;
       
  6484 
       
  6485                     *b = ((SRC*)data->texture.scanLine(py))[px];
       
  6486                     ++b;
       
  6487 
       
  6488                     x += fdx;
       
  6489                     y += fdy;
       
  6490                     w += fdw;
       
  6491                     // force increment to avoid /0
       
  6492                     if (!w)
       
  6493                         w += fdw;
       
  6494                 }
       
  6495                 if (!SRC::hasAlpha() && coverage == 255) {
       
  6496                     qt_memconvert(dest, buffer, l);
       
  6497                 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
       
  6498                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
       
  6499                 {
       
  6500                     blendUntransformed_dest24(dest, buffer, coverage, l);
       
  6501                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
       
  6502                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
       
  6503                     blendUntransformed_dest16(dest, buffer, coverage, l);
       
  6504                 } else {
       
  6505                     blendUntransformed_unaligned(dest, buffer, coverage, l);
       
  6506                 }
       
  6507 
       
  6508                 dest += l;
       
  6509                 length -= l;
       
  6510             }
       
  6511             ++spans;
       
  6512         }
       
  6513     }
       
  6514 }
       
  6515 
       
  6516 static void blend_transformed_tiled_rgb888(int count, const QSpan *spans,
       
  6517                                            void *userData)
       
  6518 {
       
  6519 #if defined(QT_QWS_DEPTH_24)
       
  6520     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6521 
       
  6522     if (data->texture.format == QImage::Format_RGB888)
       
  6523         blendTransformedTiled<qrgb888, qrgb888>(count, spans, userData);
       
  6524     else
       
  6525 #endif
       
  6526         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6527 }
       
  6528 
       
  6529 static void blend_transformed_tiled_argb6666(int count, const QSpan *spans,
       
  6530                                              void *userData)
       
  6531 {
       
  6532 #if defined(QT_QWS_DEPTH_18)
       
  6533     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6534 
       
  6535     if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
       
  6536         blendTransformedTiled<qargb6666, qargb6666>(count, spans, userData);
       
  6537     else if (data->texture.format == QImage::Format_RGB666)
       
  6538         blendTransformedTiled<qargb6666, qrgb666>(count, spans, userData);
       
  6539     else
       
  6540 #endif
       
  6541         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6542 }
       
  6543 
       
  6544 static void blend_transformed_tiled_rgb666(int count, const QSpan *spans,
       
  6545                                            void *userData)
       
  6546 {
       
  6547 #if defined(QT_QWS_DEPTH_18)
       
  6548     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6549 
       
  6550     if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
       
  6551         blendTransformedTiled<qrgb666, qargb6666>(count, spans, userData);
       
  6552     else if (data->texture.format == QImage::Format_RGB666)
       
  6553         blendTransformedTiled<qrgb666, qrgb666>(count, spans, userData);
       
  6554     else
       
  6555 #endif
       
  6556         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6557 }
       
  6558 
       
  6559 static void blend_transformed_tiled_argb8565(int count, const QSpan *spans,
       
  6560                                              void *userData)
       
  6561 {
       
  6562 #if defined(QT_QWS_DEPTH_16)
       
  6563     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6564 
       
  6565     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
       
  6566         blendTransformedTiled<qargb8565, qargb8565>(count, spans, userData);
       
  6567     else if (data->texture.format == QImage::Format_RGB16)
       
  6568         blendTransformedTiled<qargb8565, qrgb565>(count, spans, userData);
       
  6569     else
       
  6570 #endif
       
  6571         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6572 }
       
  6573 
       
  6574 static void blend_transformed_tiled_rgb565(int count, const QSpan *spans,
       
  6575                                            void *userData)
       
  6576 {
       
  6577 #if defined(QT_QWS_DEPTH_16)
       
  6578     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6579 
       
  6580     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
       
  6581         blendTransformedTiled<qrgb565, qargb8565>(count, spans, userData);
       
  6582     else if (data->texture.format == QImage::Format_RGB16)
       
  6583         blendTransformedTiled<qrgb565, qrgb565>(count, spans, userData);
       
  6584     else
       
  6585 #endif
       
  6586         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6587 }
       
  6588 
       
  6589 static void blend_transformed_tiled_argb8555(int count, const QSpan *spans,
       
  6590                                              void *userData)
       
  6591 {
       
  6592 #if defined(QT_QWS_DEPTH_15)
       
  6593     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6594 
       
  6595     if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
       
  6596         blendTransformedTiled<qargb8555, qargb8555>(count, spans, userData);
       
  6597     else if (data->texture.format == QImage::Format_RGB555)
       
  6598         blendTransformedTiled<qargb8555, qrgb555>(count, spans, userData);
       
  6599     else
       
  6600 #endif
       
  6601         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6602 }
       
  6603 
       
  6604 static void blend_transformed_tiled_rgb555(int count, const QSpan *spans,
       
  6605                                            void *userData)
       
  6606 {
       
  6607 #if defined(QT_QWS_DEPTH_15)
       
  6608     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6609 
       
  6610     if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
       
  6611         blendTransformedTiled<qrgb555, qargb8555>(count, spans, userData);
       
  6612     else if (data->texture.format == QImage::Format_RGB555)
       
  6613         blendTransformedTiled<qrgb555, qrgb555>(count, spans, userData);
       
  6614     else
       
  6615 #endif
       
  6616         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6617 }
       
  6618 
       
  6619 static void blend_transformed_tiled_argb4444(int count, const QSpan *spans,
       
  6620                                              void *userData)
       
  6621 {
       
  6622 #if defined(QT_QWS_DEPTH_12)
       
  6623     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6624 
       
  6625     if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
       
  6626         blendTransformedTiled<qargb4444, qargb4444>(count, spans, userData);
       
  6627     else if (data->texture.format == QImage::Format_RGB444)
       
  6628         blendTransformedTiled<qargb4444, qrgb444>(count, spans, userData);
       
  6629     else
       
  6630 #endif
       
  6631         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6632 }
       
  6633 
       
  6634 static void blend_transformed_tiled_rgb444(int count, const QSpan *spans,
       
  6635                                            void *userData)
       
  6636 {
       
  6637 #if defined(QT_QWS_DEPTH_12)
       
  6638     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6639 
       
  6640     if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
       
  6641         blendTransformedTiled<qrgb444, qargb4444>(count, spans, userData);
       
  6642     else if (data->texture.format == QImage::Format_RGB444)
       
  6643         blendTransformedTiled<qrgb444, qrgb444>(count, spans, userData);
       
  6644     else
       
  6645 #endif
       
  6646         blend_src_generic<RegularSpans>(count, spans, userData);
       
  6647 }
       
  6648 
       
  6649 # define SPANFUNC_POINTER(Name, Arg) Name<Arg>
       
  6650 
       
  6651 
       
  6652 /* Image formats here are target formats */
       
  6653 static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats] = {
       
  6654     // Untransformed
       
  6655     {
       
  6656         0, // Invalid
       
  6657         SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Mono
       
  6658         SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // MonoLsb
       
  6659         SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Indexed8
       
  6660         SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // RGB32
       
  6661         SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // ARGB32
       
  6662         SPANFUNC_POINTER(blend_untransformed_argb, RegularSpans), // ARGB32_Premultiplied
       
  6663         blend_untransformed_rgb565,
       
  6664         blend_untransformed_argb8565,
       
  6665         blend_untransformed_rgb666,
       
  6666         blend_untransformed_argb6666,
       
  6667         blend_untransformed_rgb555,
       
  6668         blend_untransformed_argb8555,
       
  6669         blend_untransformed_rgb888,
       
  6670         blend_untransformed_rgb444,
       
  6671         blend_untransformed_argb4444,
       
  6672     },
       
  6673     // Tiled
       
  6674     {
       
  6675         0, // Invalid
       
  6676         SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Mono
       
  6677         SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // MonoLsb
       
  6678         SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Indexed8
       
  6679         SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // RGB32
       
  6680         SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // ARGB32
       
  6681         SPANFUNC_POINTER(blend_tiled_argb, RegularSpans), // ARGB32_Premultiplied
       
  6682         blend_tiled_rgb565,
       
  6683         blend_tiled_argb8565,
       
  6684         blend_tiled_rgb666,
       
  6685         blend_tiled_argb6666,
       
  6686         blend_tiled_rgb555,
       
  6687         blend_tiled_argb8555,
       
  6688         blend_tiled_rgb888,
       
  6689         blend_tiled_rgb444,
       
  6690         blend_tiled_argb4444,
       
  6691     },
       
  6692     // Transformed
       
  6693     {
       
  6694         0, // Invalid
       
  6695         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
       
  6696         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
       
  6697         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
       
  6698         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
       
  6699         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
       
  6700         SPANFUNC_POINTER(blend_transformed_argb, RegularSpans), // ARGB32_Premultiplied
       
  6701         blend_transformed_rgb565,
       
  6702         blend_transformed_argb8565,
       
  6703         blend_transformed_rgb666,
       
  6704         blend_transformed_argb6666,
       
  6705         blend_transformed_rgb555,
       
  6706         blend_transformed_argb8555,
       
  6707         blend_transformed_rgb888,
       
  6708         blend_transformed_rgb444,
       
  6709         blend_transformed_argb4444,
       
  6710     },
       
  6711      // TransformedTiled
       
  6712     {
       
  6713         0,
       
  6714         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
       
  6715         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
       
  6716         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
       
  6717         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
       
  6718         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
       
  6719         SPANFUNC_POINTER(blend_transformed_tiled_argb, RegularSpans), // ARGB32_Premultiplied
       
  6720         blend_transformed_tiled_rgb565,
       
  6721         blend_transformed_tiled_argb8565,
       
  6722         blend_transformed_tiled_rgb666,
       
  6723         blend_transformed_tiled_argb6666,
       
  6724         blend_transformed_tiled_rgb555,
       
  6725         blend_transformed_tiled_argb8555,
       
  6726         blend_transformed_tiled_rgb888,
       
  6727         blend_transformed_tiled_rgb444,
       
  6728         blend_transformed_tiled_argb4444
       
  6729     },
       
  6730     // Bilinear
       
  6731     {
       
  6732         0,
       
  6733         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
       
  6734         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
       
  6735         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
       
  6736         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
       
  6737         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
       
  6738         SPANFUNC_POINTER(blend_transformed_bilinear_argb, RegularSpans), // ARGB32_Premultiplied
       
  6739         blend_transformed_bilinear_rgb565,
       
  6740         blend_transformed_bilinear_argb8565,
       
  6741         blend_transformed_bilinear_rgb666,
       
  6742         blend_transformed_bilinear_argb6666,
       
  6743         blend_transformed_bilinear_rgb555,
       
  6744         blend_transformed_bilinear_argb8555,
       
  6745         blend_transformed_bilinear_rgb888,
       
  6746         blend_transformed_bilinear_rgb444,
       
  6747         blend_transformed_bilinear_argb4444,
       
  6748     },
       
  6749     // BilinearTiled
       
  6750     {
       
  6751         0,
       
  6752         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
       
  6753         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
       
  6754         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
       
  6755         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
       
  6756         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
       
  6757         SPANFUNC_POINTER(blend_transformed_bilinear_tiled_argb, RegularSpans), // ARGB32_Premultiplied
       
  6758         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB16
       
  6759         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8565_Premultiplied
       
  6760         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB666
       
  6761         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB6666_Premultiplied
       
  6762         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB555
       
  6763         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8555_Premultiplied
       
  6764         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB888
       
  6765         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB444
       
  6766         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB4444_Premultiplied
       
  6767     }
       
  6768 };
       
  6769 
       
  6770 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
       
  6771 static const ProcessSpans processTextureSpansCallback[NBlendTypes][QImage::NImageFormats] = {
       
  6772     // Untransformed
       
  6773     {
       
  6774         0, // Invalid
       
  6775         blend_untransformed_generic<CallbackSpans>,   // Mono
       
  6776         blend_untransformed_generic<CallbackSpans>,   // MonoLsb
       
  6777         blend_untransformed_generic<CallbackSpans>,   // Indexed8
       
  6778         blend_untransformed_generic<CallbackSpans>,   // RGB32
       
  6779         blend_untransformed_generic<CallbackSpans>,   // ARGB32
       
  6780         blend_untransformed_argb<CallbackSpans>,      // ARGB32_Premultiplied
       
  6781         blend_untransformed_generic<CallbackSpans>,   // RGB16
       
  6782         blend_untransformed_generic<CallbackSpans>,   // ARGB8565_Premultiplied
       
  6783         blend_untransformed_generic<CallbackSpans>,   // RGB666
       
  6784         blend_untransformed_generic<CallbackSpans>,   // ARGB6666_Premultiplied
       
  6785         blend_untransformed_generic<CallbackSpans>,   // RGB555
       
  6786         blend_untransformed_generic<CallbackSpans>,   // ARGB8555_Premultiplied
       
  6787         blend_untransformed_generic<CallbackSpans>,   // RGB888
       
  6788         blend_untransformed_generic<CallbackSpans>,   // RGB444
       
  6789         blend_untransformed_generic<CallbackSpans>    // ARGB4444_Premultiplied
       
  6790     },
       
  6791     // Tiled
       
  6792     {
       
  6793         0, // Invalid
       
  6794         blend_tiled_generic<CallbackSpans>,   // Mono
       
  6795         blend_tiled_generic<CallbackSpans>,   // MonoLsb
       
  6796         blend_tiled_generic<CallbackSpans>,   // Indexed8
       
  6797         blend_tiled_generic<CallbackSpans>,   // RGB32
       
  6798         blend_tiled_generic<CallbackSpans>,   // ARGB32
       
  6799         blend_tiled_argb<CallbackSpans>,      // ARGB32_Premultiplied
       
  6800         blend_tiled_generic<CallbackSpans>,   // RGB16
       
  6801         blend_tiled_generic<CallbackSpans>,   // ARGB8565_Premultiplied
       
  6802         blend_tiled_generic<CallbackSpans>,   // RGB666
       
  6803         blend_tiled_generic<CallbackSpans>,   // ARGB6666_Premultiplied
       
  6804         blend_tiled_generic<CallbackSpans>,   // RGB555
       
  6805         blend_tiled_generic<CallbackSpans>,   // ARGB8555_Premultiplied
       
  6806         blend_tiled_generic<CallbackSpans>,   // RGB888
       
  6807         blend_tiled_generic<CallbackSpans>,   // RGB444
       
  6808         blend_tiled_generic<CallbackSpans>    // ARGB4444_Premultiplied
       
  6809     },
       
  6810     // Transformed
       
  6811     {
       
  6812         0, // Invalid
       
  6813         blend_src_generic<CallbackSpans>,   // Mono
       
  6814         blend_src_generic<CallbackSpans>,   // MonoLsb
       
  6815         blend_src_generic<CallbackSpans>,   // Indexed8
       
  6816         blend_src_generic<CallbackSpans>,   // RGB32
       
  6817         blend_src_generic<CallbackSpans>,   // ARGB32
       
  6818         blend_transformed_argb<CallbackSpans>, // ARGB32_Premultiplied
       
  6819         blend_src_generic<CallbackSpans>,   // RGB16
       
  6820         blend_src_generic<CallbackSpans>,   // ARGB8565_Premultiplied
       
  6821         blend_src_generic<CallbackSpans>,   // RGB666
       
  6822         blend_src_generic<CallbackSpans>,   // ARGB6666_Premultiplied
       
  6823         blend_src_generic<CallbackSpans>,   // RGB555
       
  6824         blend_src_generic<CallbackSpans>,   // ARGB8555_Premultiplied
       
  6825         blend_src_generic<CallbackSpans>,   // RGB888
       
  6826         blend_src_generic<CallbackSpans>,   // RGB444
       
  6827         blend_src_generic<CallbackSpans>,   // ARGB4444_Premultiplied
       
  6828     },
       
  6829      // TransformedTiled
       
  6830     {
       
  6831         0,
       
  6832         blend_src_generic<CallbackSpans>,   // Mono
       
  6833         blend_src_generic<CallbackSpans>,   // MonoLsb
       
  6834         blend_src_generic<CallbackSpans>,   // Indexed8
       
  6835         blend_src_generic<CallbackSpans>,   // RGB32
       
  6836         blend_src_generic<CallbackSpans>,   // ARGB32
       
  6837         blend_transformed_tiled_argb<CallbackSpans>, // ARGB32_Premultiplied
       
  6838         blend_src_generic<CallbackSpans>,   // RGB16
       
  6839         blend_src_generic<CallbackSpans>,   // ARGB8565_Premultiplied
       
  6840         blend_src_generic<CallbackSpans>,   // RGB666
       
  6841         blend_src_generic<CallbackSpans>,   // ARGB6666_Premultiplied
       
  6842         blend_src_generic<CallbackSpans>,   // RGB555
       
  6843         blend_src_generic<CallbackSpans>,   // ARGB8555_Premultiplied
       
  6844         blend_src_generic<CallbackSpans>,   // RGB888
       
  6845         blend_src_generic<CallbackSpans>,   // RGB444
       
  6846         blend_src_generic<CallbackSpans>    // ARGB4444_Premultiplied
       
  6847     },
       
  6848     // Bilinear
       
  6849     {
       
  6850         0,
       
  6851         blend_src_generic<CallbackSpans>,   // Mono
       
  6852         blend_src_generic<CallbackSpans>,   // MonoLsb
       
  6853         blend_src_generic<CallbackSpans>,   // Indexed8
       
  6854         blend_src_generic<CallbackSpans>,   // RGB32
       
  6855         blend_src_generic<CallbackSpans>,   // ARGB32
       
  6856         blend_transformed_bilinear_argb<CallbackSpans>, // ARGB32_Premultiplied
       
  6857         blend_src_generic<CallbackSpans>,   // RGB16
       
  6858         blend_src_generic<CallbackSpans>,   // ARGB8565_Premultiplied
       
  6859         blend_src_generic<CallbackSpans>,   // RGB666
       
  6860         blend_src_generic<CallbackSpans>,   // ARGB6666_Premultiplied
       
  6861         blend_src_generic<CallbackSpans>,   // RGB555
       
  6862         blend_src_generic<CallbackSpans>,   // ARGB8555_Premultiplied
       
  6863         blend_src_generic<CallbackSpans>,   // RGB888
       
  6864         blend_src_generic<CallbackSpans>,   // RGB444
       
  6865         blend_src_generic<CallbackSpans>    // ARGB4444_Premultiplied
       
  6866     },
       
  6867     // BilinearTiled
       
  6868     {
       
  6869         0,
       
  6870         blend_src_generic<CallbackSpans>,   // Mono
       
  6871         blend_src_generic<CallbackSpans>,   // MonoLsb
       
  6872         blend_src_generic<CallbackSpans>,   // Indexed8
       
  6873         blend_src_generic<CallbackSpans>,   // RGB32
       
  6874         blend_src_generic<CallbackSpans>,   // ARGB32
       
  6875         blend_transformed_bilinear_tiled_argb<CallbackSpans>, // ARGB32_Premultiplied
       
  6876         blend_src_generic<CallbackSpans>,   // RGB16
       
  6877         blend_src_generic<CallbackSpans>,   // ARGB8565_Premultiplied
       
  6878         blend_src_generic<CallbackSpans>,   // RGB666
       
  6879         blend_src_generic<CallbackSpans>,   // ARGB6666_Premultiplied
       
  6880         blend_src_generic<CallbackSpans>,   // RGB555
       
  6881         blend_src_generic<CallbackSpans>,   // ARGB8555_Premultiplied
       
  6882         blend_src_generic<CallbackSpans>,   // RGB888
       
  6883         blend_src_generic<CallbackSpans>,   // RGB444
       
  6884         blend_src_generic<CallbackSpans>    // ARGB4444_Premultiplied
       
  6885     }
       
  6886 };
       
  6887 #endif // QT_NO_RASTERCALLBACKS
       
  6888 
       
  6889 void qBlendTexture(int count, const QSpan *spans, void *userData)
       
  6890 {
       
  6891     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6892     ProcessSpans proc = processTextureSpans[getBlendType(data)][data->rasterBuffer->format];
       
  6893     proc(count, spans, userData);
       
  6894 }
       
  6895 
       
  6896 #if defined (Q_WS_QWS) &&  !defined(QT_NO_RASTERCALLBACKS)
       
  6897 void qBlendTextureCallback(int count, const QSpan *spans, void *userData)
       
  6898 {
       
  6899     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6900     ProcessSpans proc = processTextureSpansCallback[getBlendType(data)][data->rasterBuffer->format];
       
  6901     proc(count, spans, userData);
       
  6902 }
       
  6903 #endif // QT_NO_RASTERCALLBACKS
       
  6904 
       
  6905 template <class DST>
       
  6906 inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
       
  6907                                    int x, int y, quint32 color,
       
  6908                                    const uchar *map,
       
  6909                                    int mapWidth, int mapHeight, int mapStride,
       
  6910                                    DST dummy = 0)
       
  6911 {
       
  6912     Q_UNUSED(dummy);
       
  6913     const DST c = qt_colorConvert<DST, quint32>(color, 0);
       
  6914     DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
       
  6915     const int destStride = rasterBuffer->bytesPerLine() / sizeof(DST);
       
  6916 
       
  6917     if (mapWidth > 8) {
       
  6918         while (mapHeight--) {
       
  6919             int x0 = 0;
       
  6920             int n = 0;
       
  6921             for (int x = 0; x < mapWidth; x += 8) {
       
  6922                 uchar s = map[x >> 3];
       
  6923                 for (int i = 0; i < 8; ++i) {
       
  6924                     if (s & 0x80) {
       
  6925                         ++n;
       
  6926                     } else {
       
  6927                         if (n) {
       
  6928                             qt_memfill(dest + x0, c, n);
       
  6929                             x0 += n + 1;
       
  6930                             n = 0;
       
  6931                         } else {
       
  6932                             ++x0;
       
  6933                         }
       
  6934                         if (!s) {
       
  6935                             x0 += 8 - 1 - i;
       
  6936                             break;
       
  6937                         }
       
  6938                     }
       
  6939                     s <<= 1;
       
  6940                 }
       
  6941             }
       
  6942             if (n)
       
  6943                 qt_memfill(dest + x0, c, n);
       
  6944             dest += destStride;
       
  6945             map += mapStride;
       
  6946         }
       
  6947     } else {
       
  6948         while (mapHeight--) {
       
  6949             int x0 = 0;
       
  6950             int n = 0;
       
  6951             for (uchar s = *map; s; s <<= 1) {
       
  6952                 if (s & 0x80) {
       
  6953                     ++n;
       
  6954                 } else if (n) {
       
  6955                     qt_memfill(dest + x0, c, n);
       
  6956                     x0 += n + 1;
       
  6957                     n = 0;
       
  6958                 } else {
       
  6959                     ++x0;
       
  6960                 }
       
  6961             }
       
  6962             if (n)
       
  6963                 qt_memfill(dest + x0, c, n);
       
  6964             dest += destStride;
       
  6965             map += mapStride;
       
  6966         }
       
  6967     }
       
  6968 }
       
  6969 
       
  6970 static void qt_gradient_quint32(int count, const QSpan *spans, void *userData)
       
  6971 {
       
  6972     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  6973 
       
  6974     bool isVerticalGradient =
       
  6975         data->txop <= QTransform::TxScale &&
       
  6976         data->type == QSpanData::LinearGradient &&
       
  6977         data->gradient.linear.end.x == data->gradient.linear.origin.x;
       
  6978 
       
  6979     if (isVerticalGradient) {
       
  6980         LinearGradientValues linear;
       
  6981         getLinearGradientValues(&linear, data);
       
  6982 
       
  6983         CompositionFunctionSolid funcSolid =
       
  6984             functionForModeSolid[data->rasterBuffer->compositionMode];
       
  6985 
       
  6986         /*
       
  6987             The logic for vertical gradient calculations is a mathematically
       
  6988             reduced copy of that in fetchLinearGradient() - which is basically:
       
  6989 
       
  6990                 qreal ry = data->m22 * (y + 0.5) + data->dy;
       
  6991                 qreal t = linear.dy*ry + linear.off;
       
  6992                 t *= (GRADIENT_STOPTABLE_SIZE - 1);
       
  6993                 quint32 color =
       
  6994                     qt_gradient_pixel_fixed(&data->gradient,
       
  6995                                             int(t * FIXPT_SIZE));
       
  6996 
       
  6997             This has then been converted to fixed point to improve performance.
       
  6998          */
       
  6999         const int gss = GRADIENT_STOPTABLE_SIZE - 1;
       
  7000         int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
       
  7001         int off = int((((linear.dy * (data->m22 * 0.5 + data->dy) + linear.off) * gss) * FIXPT_SIZE));
       
  7002 
       
  7003         while (count--) {
       
  7004             int y = spans->y;
       
  7005             int x = spans->x;
       
  7006 
       
  7007             quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x;
       
  7008             quint32 color =
       
  7009                 qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
       
  7010 
       
  7011             funcSolid(dst, spans->len, color, spans->coverage);
       
  7012             ++spans;
       
  7013         }
       
  7014 
       
  7015     } else {
       
  7016         blend_src_generic<RegularSpans>(count, spans, userData);
       
  7017     }
       
  7018 }
       
  7019 
       
  7020 static void qt_gradient_quint16(int count, const QSpan *spans, void *userData)
       
  7021 {
       
  7022     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  7023 
       
  7024     bool isVerticalGradient =
       
  7025         data->txop <= QTransform::TxScale &&
       
  7026         data->type == QSpanData::LinearGradient &&
       
  7027         data->gradient.linear.end.x == data->gradient.linear.origin.x;
       
  7028 
       
  7029     if (isVerticalGradient) {
       
  7030 
       
  7031         LinearGradientValues linear;
       
  7032         getLinearGradientValues(&linear, data);
       
  7033 
       
  7034         /*
       
  7035             The logic for vertical gradient calculations is a mathematically
       
  7036             reduced copy of that in fetchLinearGradient() - which is basically:
       
  7037 
       
  7038                 qreal ry = data->m22 * (y + 0.5) + data->dy;
       
  7039                 qreal t = linear.dy*ry + linear.off;
       
  7040                 t *= (GRADIENT_STOPTABLE_SIZE - 1);
       
  7041                 quint32 color =
       
  7042                     qt_gradient_pixel_fixed(&data->gradient,
       
  7043                                             int(t * FIXPT_SIZE));
       
  7044 
       
  7045             This has then been converted to fixed point to improve performance.
       
  7046          */
       
  7047         const int gss = GRADIENT_STOPTABLE_SIZE - 1;
       
  7048         int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
       
  7049         int off = int((((linear.dy * (data->m22 * 0.5 + data->dy) + linear.off) * gss) * FIXPT_SIZE));
       
  7050 
       
  7051         uint oldColor = data->solid.color;
       
  7052         while (count--) {
       
  7053             int y = spans->y;
       
  7054 
       
  7055             quint32 color = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
       
  7056 
       
  7057             data->solid.color = color;
       
  7058             blend_color_rgb16(1, spans, userData);
       
  7059             ++spans;
       
  7060         }
       
  7061         data->solid.color = oldColor;
       
  7062 
       
  7063     } else {
       
  7064         blend_src_generic<RegularSpans>(count, spans, userData);
       
  7065     }
       
  7066 }
       
  7067 
       
  7068 inline static void qt_bitmapblit_quint32(QRasterBuffer *rasterBuffer,
       
  7069                                    int x, int y, quint32 color,
       
  7070                                    const uchar *map,
       
  7071                                    int mapWidth, int mapHeight, int mapStride)
       
  7072 {
       
  7073     qt_bitmapblit_template<quint32>(rasterBuffer, x,  y,  color,
       
  7074                                     map, mapWidth, mapHeight, mapStride);
       
  7075 }
       
  7076 
       
  7077 inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
       
  7078                                    int x, int y, quint32 color,
       
  7079                                    const uchar *map,
       
  7080                                    int mapWidth, int mapHeight, int mapStride)
       
  7081 {
       
  7082     qt_bitmapblit_template<quint16>(rasterBuffer, x,  y,  color,
       
  7083                                     map, mapWidth, mapHeight, mapStride);
       
  7084 }
       
  7085 
       
  7086 
       
  7087 uchar qt_pow_rgb_gamma[256];
       
  7088 uchar qt_pow_rgb_invgamma[256];
       
  7089 
       
  7090 uint qt_pow_gamma[256];
       
  7091 uchar qt_pow_invgamma[2048];
       
  7092 
       
  7093 static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
       
  7094                                     int x, int y, quint32 color,
       
  7095                                     const uchar *map,
       
  7096                                     int mapWidth, int mapHeight, int mapStride,
       
  7097                                     const QClipData *)
       
  7098 {
       
  7099     const quint16 c = qt_colorConvert<quint16, quint32>(color, 0);
       
  7100     quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
       
  7101     const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
       
  7102 
       
  7103     while (mapHeight--) {
       
  7104         for (int i = 0; i < mapWidth; ++i) {
       
  7105             const int coverage = map[i];
       
  7106 
       
  7107             if (coverage == 0) {
       
  7108                 // nothing
       
  7109             } else if (coverage == 255) {
       
  7110                 dest[i] = c;
       
  7111             } else {
       
  7112                 int ialpha = 255 - coverage;
       
  7113                 dest[i] = BYTE_MUL_RGB16(c, coverage)
       
  7114                           + BYTE_MUL_RGB16(dest[i], ialpha);
       
  7115             }
       
  7116         }
       
  7117         dest += destStride;
       
  7118         map += mapStride;
       
  7119     }
       
  7120 }
       
  7121 
       
  7122 void qt_build_pow_tables() {
       
  7123     qreal smoothing = qreal(1.7);
       
  7124 
       
  7125 #ifdef Q_WS_MAC
       
  7126     // decided by testing a few things on an iMac, should probably get this from the
       
  7127     // system...
       
  7128     smoothing = 2.0;
       
  7129 #endif
       
  7130 
       
  7131 #ifdef Q_WS_WIN
       
  7132     int winSmooth;
       
  7133     if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0))
       
  7134         smoothing = winSmooth / 1000.0;
       
  7135 #endif
       
  7136 
       
  7137 #ifdef Q_WS_X11
       
  7138     Q_UNUSED(smoothing);
       
  7139     for (int i=0; i<256; ++i) {
       
  7140         qt_pow_rgb_gamma[i] = uchar(i);
       
  7141         qt_pow_rgb_invgamma[i] = uchar(i);
       
  7142     }
       
  7143 #else
       
  7144     for (int i=0; i<256; ++i) {
       
  7145         qt_pow_rgb_gamma[i] = uchar(qRound(pow(i / qreal(255.0), smoothing) * 255));
       
  7146         qt_pow_rgb_invgamma[i] = uchar(qRound(pow(i / qreal(255.), 1 / smoothing) * 255));
       
  7147     }
       
  7148 #endif
       
  7149 
       
  7150 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
       
  7151     const qreal gray_gamma = 2.31;
       
  7152     for (int i=0; i<256; ++i)
       
  7153         qt_pow_gamma[i] = uint(qRound(pow(i / qreal(255.), gray_gamma) * 2047));
       
  7154     for (int i=0; i<2048; ++i)
       
  7155         qt_pow_invgamma[i] = uchar(qRound(pow(i / 2047.0, 1 / gray_gamma) * 255));
       
  7156 #endif
       
  7157 }
       
  7158 
       
  7159 static inline void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
       
  7160 {
       
  7161     // Do a gray alphablend...
       
  7162     int da = qAlpha(*dst);
       
  7163     int dr = qRed(*dst);
       
  7164     int dg = qGreen(*dst);
       
  7165     int db = qBlue(*dst);
       
  7166 
       
  7167     if (da != 255
       
  7168 #if defined (Q_WS_WIN)
       
  7169         // Work around GDI messing up alpha channel
       
  7170         && qRed(*dst) <= da && qBlue(*dst) <= da && qGreen(*dst) <= da
       
  7171 #endif
       
  7172         ) {
       
  7173 
       
  7174         int a = qGray(coverage);
       
  7175         sr = qt_div_255(sr * a);
       
  7176         sg = qt_div_255(sg * a);
       
  7177         sb = qt_div_255(sb * a);
       
  7178 
       
  7179         int ia = 255 - a;
       
  7180         dr = qt_div_255(dr * ia);
       
  7181         dg = qt_div_255(dg * ia);
       
  7182         db = qt_div_255(db * ia);
       
  7183 
       
  7184         *dst = ((a + qt_div_255((255 - a) * da)) << 24)
       
  7185             |  ((sr + dr) << 16)
       
  7186             |  ((sg + dg) << 8)
       
  7187             |  ((sb + db));
       
  7188         return;
       
  7189     }
       
  7190 
       
  7191     int mr = qRed(coverage);
       
  7192     int mg = qGreen(coverage);
       
  7193     int mb = qBlue(coverage);
       
  7194 
       
  7195     dr = qt_pow_rgb_gamma[dr];
       
  7196     dg = qt_pow_rgb_gamma[dg];
       
  7197     db = qt_pow_rgb_gamma[db];
       
  7198 
       
  7199     int nr = qt_div_255((sr - dr) * mr) + dr;
       
  7200     int ng = qt_div_255((sg - dg) * mg) + dg;
       
  7201     int nb = qt_div_255((sb - db) * mb) + db;
       
  7202 
       
  7203     nr = qt_pow_rgb_invgamma[nr];
       
  7204     ng = qt_pow_rgb_invgamma[ng];
       
  7205     nb = qt_pow_rgb_invgamma[nb];
       
  7206 
       
  7207     *dst = qRgb(nr, ng, nb);
       
  7208 }
       
  7209 
       
  7210 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
       
  7211 static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
       
  7212 {
       
  7213     // Do a gammacorrected gray alphablend...
       
  7214     int dr = qRed(*dst);
       
  7215     int dg = qGreen(*dst);
       
  7216     int db = qBlue(*dst);
       
  7217 
       
  7218     dr = qt_pow_gamma[dr];
       
  7219     dg = qt_pow_gamma[dg];
       
  7220     db = qt_pow_gamma[db];
       
  7221 
       
  7222     int alpha = coverage;
       
  7223     int ialpha = 255 - alpha;
       
  7224     int nr = (sr * alpha + ialpha * dr) / 255;
       
  7225     int ng = (sg * alpha + ialpha * dg) / 255;
       
  7226     int nb = (sb * alpha + ialpha * db) / 255;
       
  7227 
       
  7228     nr = qt_pow_invgamma[nr];
       
  7229     ng = qt_pow_invgamma[ng];
       
  7230     nb = qt_pow_invgamma[nb];
       
  7231 
       
  7232     *dst = qRgb(nr, ng, nb);
       
  7233 }
       
  7234 #endif
       
  7235 
       
  7236 static void qt_alphamapblit_quint32(QRasterBuffer *rasterBuffer,
       
  7237                                     int x, int y, quint32 color,
       
  7238                                     const uchar *map,
       
  7239                                     int mapWidth, int mapHeight, int mapStride,
       
  7240                                     const QClipData *clip)
       
  7241 {
       
  7242     const quint32 c = color;
       
  7243     const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
       
  7244 
       
  7245 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
       
  7246     int sr = qRed(color);
       
  7247     int sg = qGreen(color);
       
  7248     int sb = qBlue(color);
       
  7249 
       
  7250     sr = qt_pow_gamma[sr];
       
  7251     sg = qt_pow_gamma[sg];
       
  7252     sb = qt_pow_gamma[sb];
       
  7253     bool opaque_src = (qAlpha(color) == 255);
       
  7254 #endif
       
  7255 
       
  7256     if (!clip) {
       
  7257         quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
       
  7258         while (mapHeight--) {
       
  7259             for (int i = 0; i < mapWidth; ++i) {
       
  7260                 const int coverage = map[i];
       
  7261 
       
  7262                 if (coverage == 0) {
       
  7263                     // nothing
       
  7264                 } else if (coverage == 255) {
       
  7265                     dest[i] = c;
       
  7266                 } else {
       
  7267 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
       
  7268                     if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
       
  7269                         && qAlpha(dest[i]) == 255) {
       
  7270                         grayBlendPixel(dest+i, coverage, sr, sg, sb);
       
  7271                     } else
       
  7272 #endif
       
  7273                     {
       
  7274                         int ialpha = 255 - coverage;
       
  7275                         dest[i] = INTERPOLATE_PIXEL_255(c, coverage, dest[i], ialpha);
       
  7276                     }
       
  7277                 }
       
  7278             }
       
  7279             dest += destStride;
       
  7280             map += mapStride;
       
  7281         }
       
  7282     } else {
       
  7283         int bottom = qMin(y + mapHeight, rasterBuffer->height());
       
  7284 
       
  7285         int top = qMax(y, 0);
       
  7286         map += (top - y) * mapStride;
       
  7287 
       
  7288         const_cast<QClipData *>(clip)->initialize();
       
  7289         for (int yp = top; yp<bottom; ++yp) {
       
  7290             const QClipData::ClipLine &line = clip->m_clipLines[yp];
       
  7291 
       
  7292             quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
       
  7293 
       
  7294             for (int i=0; i<line.count; ++i) {
       
  7295                 const QSpan &clip = line.spans[i];
       
  7296 
       
  7297                 int start = qMax<int>(x, clip.x);
       
  7298                 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
       
  7299 
       
  7300                 for (int xp=start; xp<end; ++xp) {
       
  7301                     const int coverage = map[xp - x];
       
  7302 
       
  7303                     if (coverage == 0) {
       
  7304                         // nothing
       
  7305                     } else if (coverage == 255) {
       
  7306                         dest[xp] = c;
       
  7307                     } else {
       
  7308 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
       
  7309                         if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
       
  7310                             && qAlpha(dest[xp]) == 255) {
       
  7311                             grayBlendPixel(dest+xp, coverage, sr, sg, sb);
       
  7312                         } else
       
  7313 #endif
       
  7314                         {
       
  7315                             int ialpha = 255 - coverage;
       
  7316                             dest[xp] = INTERPOLATE_PIXEL_255(c, coverage, dest[xp], ialpha);
       
  7317                         }
       
  7318                     }
       
  7319 
       
  7320                 } // for (i -> line.count)
       
  7321             } // for (yp -> bottom)
       
  7322             map += mapStride;
       
  7323         }
       
  7324     }
       
  7325 }
       
  7326 
       
  7327 static void qt_alphargbblit_quint32(QRasterBuffer *rasterBuffer,
       
  7328                                     int x, int y, quint32 color,
       
  7329                                     const uint *src, int mapWidth, int mapHeight, int srcStride,
       
  7330                                     const QClipData *clip)
       
  7331 {
       
  7332     const quint32 c = color;
       
  7333 
       
  7334     int sr = qRed(color);
       
  7335     int sg = qGreen(color);
       
  7336     int sb = qBlue(color);
       
  7337     int sa = qAlpha(color);
       
  7338 
       
  7339     sr = qt_pow_rgb_gamma[sr];
       
  7340     sg = qt_pow_rgb_gamma[sg];
       
  7341     sb = qt_pow_rgb_gamma[sb];
       
  7342 
       
  7343     if (sa == 0)
       
  7344         return;
       
  7345 
       
  7346     if (!clip) {
       
  7347         quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
       
  7348         const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
       
  7349         while (mapHeight--) {
       
  7350             for (int i = 0; i < mapWidth; ++i) {
       
  7351                 const uint coverage = src[i];
       
  7352                 if (coverage == 0xffffffff) {
       
  7353                     dst[i] = c;
       
  7354                 } else if (coverage != 0xff000000) {
       
  7355                     rgbBlendPixel(dst+i, coverage, sr, sg, sb);
       
  7356                 }
       
  7357             }
       
  7358 
       
  7359             dst += destStride;
       
  7360             src += srcStride;
       
  7361         }
       
  7362     } else {
       
  7363         int bottom = qMin(y + mapHeight, rasterBuffer->height());
       
  7364 
       
  7365         int top = qMax(y, 0);
       
  7366         src += (top - y) * srcStride;
       
  7367 
       
  7368         const_cast<QClipData *>(clip)->initialize();
       
  7369         for (int yp = top; yp<bottom; ++yp) {
       
  7370             const QClipData::ClipLine &line = clip->m_clipLines[yp];
       
  7371 
       
  7372             quint32 *dst = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
       
  7373 
       
  7374             for (int i=0; i<line.count; ++i) {
       
  7375                 const QSpan &clip = line.spans[i];
       
  7376 
       
  7377                 int start = qMax<int>(x, clip.x);
       
  7378                 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
       
  7379 
       
  7380                 for (int xp=start; xp<end; ++xp) {
       
  7381                     const uint coverage = src[xp - x];
       
  7382                     if (coverage == 0xffffffff) {
       
  7383                         dst[xp] = c;
       
  7384                     } else if (coverage != 0xff000000) {
       
  7385                         rgbBlendPixel(dst+xp, coverage, sr, sg, sb);
       
  7386                     }
       
  7387                 }
       
  7388             } // for (i -> line.count)
       
  7389             src += srcStride;
       
  7390         } // for (yp -> bottom)
       
  7391 
       
  7392     }
       
  7393 }
       
  7394 
       
  7395 template <class T>
       
  7396 inline void qt_rectfill_template(QRasterBuffer *rasterBuffer,
       
  7397                                  int x, int y, int width, int height,
       
  7398                                  quint32 color, T dummy = 0)
       
  7399 {
       
  7400     Q_UNUSED(dummy);
       
  7401 
       
  7402     qt_rectfill<T>(reinterpret_cast<T*>(rasterBuffer->buffer()),
       
  7403                    qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0),
       
  7404                    x, y, width, height, rasterBuffer->bytesPerLine());
       
  7405 }
       
  7406 
       
  7407 #define QT_RECTFILL(T)                                                  \
       
  7408     inline static void qt_rectfill_##T(QRasterBuffer *rasterBuffer,     \
       
  7409                                        int x, int y, int width, int height, \
       
  7410                                        quint32 color)                   \
       
  7411     {                                                                   \
       
  7412         qt_rectfill_template<T>(rasterBuffer, x, y, width, height, color); \
       
  7413     }
       
  7414 
       
  7415 QT_RECTFILL(quint32)
       
  7416 QT_RECTFILL(quint16)
       
  7417 QT_RECTFILL(qargb8565)
       
  7418 QT_RECTFILL(qrgb666)
       
  7419 QT_RECTFILL(qargb6666)
       
  7420 QT_RECTFILL(qrgb555)
       
  7421 QT_RECTFILL(qargb8555)
       
  7422 QT_RECTFILL(qrgb888)
       
  7423 QT_RECTFILL(qrgb444)
       
  7424 QT_RECTFILL(qargb4444)
       
  7425 #undef QT_RECTFILL
       
  7426 
       
  7427 
       
  7428 // Map table for destination image format. Contains function pointers
       
  7429 // for blends of various types unto the destination
       
  7430 
       
  7431 DrawHelper qDrawHelper[QImage::NImageFormats] =
       
  7432 {
       
  7433     // Format_Invalid,
       
  7434     { 0, 0, 0, 0, 0, 0 },
       
  7435     // Format_Mono,
       
  7436     {
       
  7437         blend_color_generic,
       
  7438         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
       
  7439         0, 0, 0, 0
       
  7440     },
       
  7441     // Format_MonoLSB,
       
  7442     {
       
  7443         blend_color_generic,
       
  7444         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
       
  7445         0, 0, 0, 0
       
  7446     },
       
  7447     // Format_Indexed8,
       
  7448     {
       
  7449         blend_color_generic,
       
  7450         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
       
  7451         0, 0, 0, 0
       
  7452     },
       
  7453     // Format_RGB32,
       
  7454     {
       
  7455         blend_color_argb,
       
  7456         qt_gradient_quint32,
       
  7457         qt_bitmapblit_quint32,
       
  7458         qt_alphamapblit_quint32,
       
  7459         qt_alphargbblit_quint32,
       
  7460         qt_rectfill_quint32
       
  7461     },
       
  7462     // Format_ARGB32,
       
  7463     {
       
  7464         blend_color_generic,
       
  7465         qt_gradient_quint32,
       
  7466         qt_bitmapblit_quint32,
       
  7467         qt_alphamapblit_quint32,
       
  7468         qt_alphargbblit_quint32,
       
  7469         qt_rectfill_quint32
       
  7470     },
       
  7471     // Format_ARGB32_Premultiplied
       
  7472     {
       
  7473         blend_color_argb,
       
  7474         qt_gradient_quint32,
       
  7475         qt_bitmapblit_quint32,
       
  7476         qt_alphamapblit_quint32,
       
  7477         qt_alphargbblit_quint32,
       
  7478         qt_rectfill_quint32
       
  7479     },
       
  7480     // Format_RGB16
       
  7481     {
       
  7482         blend_color_rgb16,
       
  7483         qt_gradient_quint16,
       
  7484         qt_bitmapblit_quint16,
       
  7485         qt_alphamapblit_quint16,
       
  7486         0,
       
  7487         qt_rectfill_quint16
       
  7488     },
       
  7489     // Format_ARGB8565_Premultiplied
       
  7490     {
       
  7491         SPANFUNC_POINTER_BLENDCOLOR(qargb8565),
       
  7492         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
       
  7493         0, 0, 0,
       
  7494         qt_rectfill_qargb8565
       
  7495     },
       
  7496     // Format_RGB666
       
  7497     {
       
  7498         SPANFUNC_POINTER_BLENDCOLOR(qrgb666),
       
  7499         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
       
  7500         0, 0, 0,
       
  7501         qt_rectfill_qrgb666
       
  7502     },
       
  7503     // Format_ARGB6666_Premultiplied
       
  7504     {
       
  7505         SPANFUNC_POINTER_BLENDCOLOR(qargb6666),
       
  7506         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
       
  7507         0, 0, 0,
       
  7508         qt_rectfill_qargb6666
       
  7509     },
       
  7510     // Format_RGB555
       
  7511     {
       
  7512         SPANFUNC_POINTER_BLENDCOLOR(qrgb555),
       
  7513         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
       
  7514         0, 0, 0,
       
  7515         qt_rectfill_qrgb555
       
  7516     },
       
  7517     // Format_ARGB8555_Premultiplied
       
  7518     {
       
  7519         SPANFUNC_POINTER_BLENDCOLOR(qargb8555),
       
  7520         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
       
  7521         0, 0, 0,
       
  7522         qt_rectfill_qargb8555
       
  7523     },
       
  7524     // Format_RGB888
       
  7525     {
       
  7526         SPANFUNC_POINTER_BLENDCOLOR(qrgb888),
       
  7527         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
       
  7528         0, 0, 0,
       
  7529         qt_rectfill_qrgb888
       
  7530     },
       
  7531     // Format_RGB444
       
  7532     {
       
  7533         SPANFUNC_POINTER_BLENDCOLOR(qrgb444),
       
  7534         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
       
  7535         0, 0, 0,
       
  7536         qt_rectfill_qrgb444
       
  7537     },
       
  7538     // Format_ARGB4444_Premultiplied
       
  7539     {
       
  7540         SPANFUNC_POINTER_BLENDCOLOR(qargb4444),
       
  7541         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
       
  7542         0, 0, 0,
       
  7543         qt_rectfill_qargb4444
       
  7544     }
       
  7545 };
       
  7546 
       
  7547 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
       
  7548 DrawHelper qDrawHelperCallback[QImage::NImageFormats] =
       
  7549 {
       
  7550     // Format_Invalid,
       
  7551     { 0, 0, 0, 0, 0, 0 },
       
  7552     // Format_Mono,
       
  7553     {
       
  7554         blend_color_generic_callback,
       
  7555         blend_src_generic<CallbackSpans>,
       
  7556         0, 0, 0, 0
       
  7557     },
       
  7558     // Format_MonoLSB,
       
  7559     {
       
  7560         blend_color_generic_callback,
       
  7561         blend_src_generic<CallbackSpans>,
       
  7562         0, 0, 0, 0
       
  7563     },
       
  7564     // Format_Indexed8,
       
  7565     {
       
  7566         blend_color_generic_callback,
       
  7567         blend_src_generic<CallbackSpans>,
       
  7568         0, 0, 0, 0
       
  7569     },
       
  7570     // Format_RGB32,
       
  7571     {
       
  7572         blend_color_generic_callback,
       
  7573         blend_src_generic<CallbackSpans>,
       
  7574         0, 0, 0, 0
       
  7575     },
       
  7576     // Format_ARGB32,
       
  7577     {
       
  7578         blend_color_generic_callback,
       
  7579         blend_src_generic<CallbackSpans>,
       
  7580         0, 0, 0, 0
       
  7581     },
       
  7582     // Format_ARGB32_Premultiplied
       
  7583     {
       
  7584         blend_color_generic_callback,
       
  7585         blend_src_generic<CallbackSpans>,
       
  7586         0, 0, 0, 0
       
  7587     },
       
  7588     // Format_RGB16
       
  7589     {
       
  7590         blend_color_generic_callback,
       
  7591         blend_src_generic<CallbackSpans>,
       
  7592         0, 0, 0, 0
       
  7593     },
       
  7594     // Format_ARGB8565_Premultiplied
       
  7595     {
       
  7596         blend_color_generic_callback,
       
  7597         blend_src_generic<CallbackSpans>,
       
  7598         0, 0, 0, 0
       
  7599     },
       
  7600     // Format_RGB666
       
  7601     {
       
  7602         blend_color_generic_callback,
       
  7603         blend_src_generic<CallbackSpans>,
       
  7604         0, 0, 0, 0
       
  7605     },
       
  7606     // Format_ARGB6666_Premultiplied
       
  7607     {
       
  7608         blend_color_generic_callback,
       
  7609         blend_src_generic<CallbackSpans>,
       
  7610         0, 0, 0, 0
       
  7611     },
       
  7612     // Format_RGB555
       
  7613     {
       
  7614         blend_color_generic_callback,
       
  7615         blend_src_generic<CallbackSpans>,
       
  7616         0, 0, 0, 0
       
  7617     },
       
  7618     // Format_ARGB8555_Premultiplied
       
  7619     {
       
  7620         blend_color_generic_callback,
       
  7621         blend_src_generic<CallbackSpans>,
       
  7622         0, 0, 0, 0
       
  7623     },
       
  7624     // Format_RGB888
       
  7625     {
       
  7626         blend_color_generic_callback,
       
  7627         blend_src_generic<CallbackSpans>,
       
  7628         0, 0, 0, 0
       
  7629     },
       
  7630     // Format_RGB444
       
  7631     {
       
  7632         blend_color_generic_callback,
       
  7633         blend_src_generic<CallbackSpans>,
       
  7634         0, 0, 0, 0
       
  7635     },
       
  7636     // Format_ARGB4444_Premultiplied
       
  7637     {
       
  7638         blend_color_generic_callback,
       
  7639         blend_src_generic<CallbackSpans>,
       
  7640         0, 0, 0, 0
       
  7641     }
       
  7642 };
       
  7643 #endif
       
  7644 
       
  7645 
       
  7646 
       
  7647 #if defined(Q_CC_MSVC) && !defined(_MIPS_)
       
  7648 template <class DST, class SRC>
       
  7649 inline void qt_memfill_template(DST *dest, SRC color, int count)
       
  7650 {
       
  7651     const DST c = qt_colorConvert<DST, SRC>(color, 0);
       
  7652     while (count--)
       
  7653         *dest++ = c;
       
  7654 }
       
  7655 
       
  7656 #else
       
  7657 
       
  7658 template <class DST, class SRC>
       
  7659 inline void qt_memfill_template(DST *dest, SRC color, int count)
       
  7660 {
       
  7661     const DST c = qt_colorConvert<DST, SRC>(color, 0);
       
  7662     int n = (count + 7) / 8;
       
  7663     switch (count & 0x07)
       
  7664     {
       
  7665     case 0: do { *dest++ = c;
       
  7666     case 7:      *dest++ = c;
       
  7667     case 6:      *dest++ = c;
       
  7668     case 5:      *dest++ = c;
       
  7669     case 4:      *dest++ = c;
       
  7670     case 3:      *dest++ = c;
       
  7671     case 2:      *dest++ = c;
       
  7672     case 1:      *dest++ = c;
       
  7673     } while (--n > 0);
       
  7674     }
       
  7675 }
       
  7676 
       
  7677 template <>
       
  7678 inline void qt_memfill_template(quint16 *dest, quint16 value, int count)
       
  7679 {
       
  7680     if (count < 3) {
       
  7681         switch (count) {
       
  7682         case 2: *dest++ = value;
       
  7683         case 1: *dest = value;
       
  7684         }
       
  7685         return;
       
  7686     }
       
  7687 
       
  7688     const int align = (quintptr)(dest) & 0x3;
       
  7689     switch (align) {
       
  7690     case 2: *dest++ = value; --count;
       
  7691     }
       
  7692 
       
  7693     const quint32 value32 = (value << 16) | value;
       
  7694     qt_memfill(reinterpret_cast<quint32*>(dest), value32, count / 2);
       
  7695     if (count & 0x1)
       
  7696         dest[count - 1] = value;
       
  7697 }
       
  7698 #endif
       
  7699 
       
  7700 static void qt_memfill_quint16(quint16 *dest, quint16 color, int count)
       
  7701 {
       
  7702     qt_memfill_template<quint16, quint16>(dest, color, count);
       
  7703 }
       
  7704 
       
  7705 typedef void (*qt_memfill32_func)(quint32 *dest, quint32 value, int count);
       
  7706 typedef void (*qt_memfill16_func)(quint16 *dest, quint16 value, int count);
       
  7707 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count);
       
  7708 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count);
       
  7709 
       
  7710 qt_memfill32_func qt_memfill32 = qt_memfill32_setup;
       
  7711 qt_memfill16_func qt_memfill16 = qt_memfill16_setup;
       
  7712 
       
  7713 enum CPUFeatures {
       
  7714     None        = 0,
       
  7715     MMX         = 0x1,
       
  7716     MMXEXT      = 0x2,
       
  7717     MMX3DNOW    = 0x4,
       
  7718     MMX3DNOWEXT = 0x8,
       
  7719     SSE         = 0x10,
       
  7720     SSE2        = 0x20,
       
  7721     CMOV        = 0x40,
       
  7722     IWMMXT      = 0x80
       
  7723 };
       
  7724 
       
  7725 static uint detectCPUFeatures()
       
  7726 {
       
  7727 #if defined (Q_OS_WINCE)
       
  7728 #if defined (ARM)
       
  7729     if (IsProcessorFeaturePresent(PF_ARM_INTEL_WMMX))
       
  7730         return IWMMXT;
       
  7731 #elif defined(_X86_)
       
  7732     uint features = 0;
       
  7733 #if defined QT_HAVE_MMX
       
  7734     if (IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE))
       
  7735         features |= MMX;
       
  7736 #endif
       
  7737 #if defined QT_HAVE_3DNOW
       
  7738     if (IsProcessorFeaturePresent(PF_3DNOW_INSTRUCTIONS_AVAILABLE))
       
  7739         features |= MMX3DNOW;
       
  7740 #endif
       
  7741     return features;
       
  7742 #endif
       
  7743     return 0;
       
  7744 #elif defined(QT_HAVE_IWMMXT)
       
  7745     // runtime detection only available when running as a previlegied process
       
  7746     static const bool doIWMMXT = !qgetenv("QT_NO_IWMMXT").toInt();
       
  7747     return doIWMMXT ? IWMMXT : 0;
       
  7748 #else
       
  7749     uint features = 0;
       
  7750 #if defined(__x86_64__) || defined(Q_OS_WIN64)
       
  7751     features = MMX|SSE|SSE2|CMOV;
       
  7752 #elif defined(__ia64__)
       
  7753     features = MMX|SSE|SSE2;
       
  7754 #elif defined(__i386__) || defined(_M_IX86)
       
  7755     unsigned int extended_result = 0;
       
  7756     uint result = 0;
       
  7757     /* see p. 118 of amd64 instruction set manual Vol3 */
       
  7758 #if defined(Q_CC_GNU)
       
  7759     asm ("push %%ebx\n"
       
  7760          "pushf\n"
       
  7761          "pop %%eax\n"
       
  7762          "mov %%eax, %%ebx\n"
       
  7763          "xor $0x00200000, %%eax\n"
       
  7764          "push %%eax\n"
       
  7765          "popf\n"
       
  7766          "pushf\n"
       
  7767          "pop %%eax\n"
       
  7768          "xor %%edx, %%edx\n"
       
  7769          "xor %%ebx, %%eax\n"
       
  7770          "jz 1f\n"
       
  7771 
       
  7772          "mov $0x00000001, %%eax\n"
       
  7773          "cpuid\n"
       
  7774          "1:\n"
       
  7775          "pop %%ebx\n"
       
  7776          "mov %%edx, %0\n"
       
  7777         : "=r" (result)
       
  7778         :
       
  7779         : "%eax", "%ecx", "%edx"
       
  7780         );
       
  7781 
       
  7782     asm ("push %%ebx\n"
       
  7783          "pushf\n"
       
  7784          "pop %%eax\n"
       
  7785          "mov %%eax, %%ebx\n"
       
  7786          "xor $0x00200000, %%eax\n"
       
  7787          "push %%eax\n"
       
  7788          "popf\n"
       
  7789          "pushf\n"
       
  7790          "pop %%eax\n"
       
  7791          "xor %%edx, %%edx\n"
       
  7792          "xor %%ebx, %%eax\n"
       
  7793          "jz 2f\n"
       
  7794 
       
  7795          "mov $0x80000000, %%eax\n"
       
  7796          "cpuid\n"
       
  7797          "cmp $0x80000000, %%eax\n"
       
  7798          "jbe 2f\n"
       
  7799          "mov $0x80000001, %%eax\n"
       
  7800          "cpuid\n"
       
  7801          "2:\n"
       
  7802          "pop %%ebx\n"
       
  7803          "mov %%edx, %0\n"
       
  7804         : "=r" (extended_result)
       
  7805         :
       
  7806         : "%eax", "%ecx", "%edx"
       
  7807         );
       
  7808 #elif defined (Q_OS_WIN)
       
  7809     _asm {
       
  7810         push eax
       
  7811         push ebx
       
  7812         push ecx
       
  7813         push edx
       
  7814         pushfd
       
  7815         pop eax
       
  7816         mov ebx, eax
       
  7817         xor eax, 00200000h
       
  7818         push eax
       
  7819         popfd
       
  7820         pushfd
       
  7821         pop eax
       
  7822         mov edx, 0
       
  7823         xor eax, ebx
       
  7824         jz skip
       
  7825 
       
  7826         mov eax, 1
       
  7827         cpuid
       
  7828         mov result, edx
       
  7829     skip:
       
  7830         pop edx
       
  7831         pop ecx
       
  7832         pop ebx
       
  7833         pop eax
       
  7834     }
       
  7835 
       
  7836     _asm {
       
  7837         push eax
       
  7838         push ebx
       
  7839         push ecx
       
  7840         push edx
       
  7841         pushfd
       
  7842         pop eax
       
  7843         mov ebx, eax
       
  7844         xor eax, 00200000h
       
  7845         push eax
       
  7846         popfd
       
  7847         pushfd
       
  7848         pop eax
       
  7849         mov edx, 0
       
  7850         xor eax, ebx
       
  7851         jz skip2
       
  7852 
       
  7853         mov eax, 80000000h
       
  7854         cpuid
       
  7855         cmp eax, 80000000h
       
  7856         jbe skip2
       
  7857         mov eax, 80000001h
       
  7858         cpuid
       
  7859         mov extended_result, edx
       
  7860     skip2:
       
  7861         pop edx
       
  7862         pop ecx
       
  7863         pop ebx
       
  7864         pop eax
       
  7865     }
       
  7866 #endif
       
  7867 
       
  7868     // result now contains the standard feature bits
       
  7869     if (result & (1u << 15))
       
  7870         features |= CMOV;
       
  7871     if (result & (1u << 23))
       
  7872         features |= MMX;
       
  7873     if (extended_result & (1u << 22))
       
  7874         features |= MMXEXT;
       
  7875     if (extended_result & (1u << 31))
       
  7876         features |= MMX3DNOW;
       
  7877     if (extended_result & (1u << 30))
       
  7878         features |= MMX3DNOWEXT;
       
  7879     if (result & (1u << 25))
       
  7880         features |= SSE;
       
  7881     if (result & (1u << 26))
       
  7882         features |= SSE2;
       
  7883 #endif // i386
       
  7884 
       
  7885     if (qgetenv("QT_NO_MMX").toInt())
       
  7886         features ^= MMX;
       
  7887     if (qgetenv("QT_NO_MMXEXT").toInt())
       
  7888         features ^= MMXEXT;
       
  7889     if (qgetenv("QT_NO_3DNOW").toInt())
       
  7890         features ^= MMX3DNOW;
       
  7891     if (qgetenv("QT_NO_3DNOWEXT").toInt())
       
  7892         features ^= MMX3DNOWEXT;
       
  7893     if (qgetenv("QT_NO_SSE").toInt())
       
  7894         features ^= SSE;
       
  7895     if (qgetenv("QT_NO_SSE2").toInt())
       
  7896         features ^= SSE2;
       
  7897 
       
  7898     return features;
       
  7899 #endif
       
  7900 }
       
  7901 
       
  7902 #if defined(Q_CC_RVCT) && defined(QT_HAVE_ARMV6)
       
  7903 // Move these to qdrawhelper_arm.c when all
       
  7904 // functions are implemented using arm assembly.
       
  7905 static CompositionFunctionSolid qt_functionForModeSolid_ARMv6[numCompositionFunctions] = {
       
  7906         comp_func_solid_SourceOver,
       
  7907         comp_func_solid_DestinationOver,
       
  7908         comp_func_solid_Clear,
       
  7909         comp_func_solid_Source,
       
  7910         comp_func_solid_Destination,
       
  7911         comp_func_solid_SourceIn,
       
  7912         comp_func_solid_DestinationIn,
       
  7913         comp_func_solid_SourceOut,
       
  7914         comp_func_solid_DestinationOut,
       
  7915         comp_func_solid_SourceAtop,
       
  7916         comp_func_solid_DestinationAtop,
       
  7917         comp_func_solid_XOR,
       
  7918         comp_func_solid_Plus,
       
  7919         comp_func_solid_Multiply,
       
  7920         comp_func_solid_Screen,
       
  7921         comp_func_solid_Overlay,
       
  7922         comp_func_solid_Darken,
       
  7923         comp_func_solid_Lighten,
       
  7924         comp_func_solid_ColorDodge,
       
  7925         comp_func_solid_ColorBurn,
       
  7926         comp_func_solid_HardLight,
       
  7927         comp_func_solid_SoftLight,
       
  7928         comp_func_solid_Difference,
       
  7929         comp_func_solid_Exclusion,
       
  7930         rasterop_solid_SourceOrDestination,
       
  7931         rasterop_solid_SourceAndDestination,
       
  7932         rasterop_solid_SourceXorDestination,
       
  7933         rasterop_solid_NotSourceAndNotDestination,
       
  7934         rasterop_solid_NotSourceOrNotDestination,
       
  7935         rasterop_solid_NotSourceXorDestination,
       
  7936         rasterop_solid_NotSource,
       
  7937         rasterop_solid_NotSourceAndDestination,
       
  7938         rasterop_solid_SourceAndNotDestination
       
  7939 };
       
  7940 
       
  7941 static CompositionFunction qt_functionForMode_ARMv6[numCompositionFunctions] = {
       
  7942         comp_func_SourceOver_armv6,
       
  7943         comp_func_DestinationOver,
       
  7944         comp_func_Clear,
       
  7945         comp_func_Source_armv6,
       
  7946         comp_func_Destination,
       
  7947         comp_func_SourceIn,
       
  7948         comp_func_DestinationIn,
       
  7949         comp_func_SourceOut,
       
  7950         comp_func_DestinationOut,
       
  7951         comp_func_SourceAtop,
       
  7952         comp_func_DestinationAtop,
       
  7953         comp_func_XOR,
       
  7954         comp_func_Plus,
       
  7955         comp_func_Multiply,
       
  7956         comp_func_Screen,
       
  7957         comp_func_Overlay,
       
  7958         comp_func_Darken,
       
  7959         comp_func_Lighten,
       
  7960         comp_func_ColorDodge,
       
  7961         comp_func_ColorBurn,
       
  7962         comp_func_HardLight,
       
  7963         comp_func_SoftLight,
       
  7964         comp_func_Difference,
       
  7965         comp_func_Exclusion,
       
  7966         rasterop_SourceOrDestination,
       
  7967         rasterop_SourceAndDestination,
       
  7968         rasterop_SourceXorDestination,
       
  7969         rasterop_NotSourceAndNotDestination,
       
  7970         rasterop_NotSourceOrNotDestination,
       
  7971         rasterop_NotSourceXorDestination,
       
  7972         rasterop_NotSource,
       
  7973         rasterop_NotSourceAndDestination,
       
  7974         rasterop_SourceAndNotDestination
       
  7975 };
       
  7976 
       
  7977 static void qt_blend_color_argb_armv6(int count, const QSpan *spans, void *userData)
       
  7978 {
       
  7979     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
       
  7980 
       
  7981     CompositionFunctionSolid func = qt_functionForModeSolid_ARMv6[data->rasterBuffer->compositionMode];
       
  7982     while (count--) {
       
  7983         uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
       
  7984         func(target, spans->len, data->solid.color, spans->coverage);
       
  7985         ++spans;
       
  7986     }
       
  7987 }
       
  7988 
       
  7989 #endif // Q_CC_RVCT && QT_HAVE_ARMV6
       
  7990 
       
  7991 
       
  7992 void qInitDrawhelperAsm()
       
  7993 {
       
  7994     static uint features = 0xffffffff;
       
  7995     if (features != 0xffffffff)
       
  7996         return;
       
  7997     features = detectCPUFeatures();
       
  7998 
       
  7999     qt_memfill32 = qt_memfill_template<quint32, quint32>;
       
  8000     qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16, quint16>;
       
  8001 
       
  8002     CompositionFunction *functionForModeAsm = 0;
       
  8003     CompositionFunctionSolid *functionForModeSolidAsm = 0;
       
  8004 
       
  8005 #ifdef QT_NO_DEBUG
       
  8006     if (false) {
       
  8007 #ifdef QT_HAVE_SSE2
       
  8008     } else if (features & SSE2) {
       
  8009         qt_memfill32 = qt_memfill32_sse2;
       
  8010         qt_memfill16 = qt_memfill16_sse2;
       
  8011         qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2;
       
  8012         qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2;
       
  8013         qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2;
       
  8014         qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2;
       
  8015 #endif
       
  8016 #ifdef QT_HAVE_SSE
       
  8017     } else if (features & SSE) {
       
  8018 //        qt_memfill32 = qt_memfill32_sse;
       
  8019         qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse;
       
  8020 #ifdef QT_HAVE_3DNOW
       
  8021         if (features & MMX3DNOW) {
       
  8022             qt_memfill32 = qt_memfill32_sse3dnow;
       
  8023             qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse3dnow;
       
  8024         }
       
  8025 #endif
       
  8026 #endif // SSE
       
  8027 #if defined(QT_HAVE_MMXEXT) && defined(QT_HAVE_SSE)
       
  8028     } else if (features & MMXEXT) {
       
  8029         qt_memfill32 = qt_memfill32_sse;
       
  8030         qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse;
       
  8031 # ifdef QT_HAVE_3DNOW
       
  8032         if (features & MMX3DNOW) {
       
  8033             qt_memfill32 = qt_memfill32_sse3dnow;
       
  8034             qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse3dnow;
       
  8035         }
       
  8036 # endif // 3DNOW
       
  8037 #endif // MMXEXT
       
  8038     }
       
  8039 #ifdef QT_HAVE_MMX
       
  8040     if (features & MMX) {
       
  8041         functionForModeAsm = qt_functionForMode_MMX;
       
  8042         functionForModeSolidAsm = qt_functionForModeSolid_MMX;
       
  8043         qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx;
       
  8044 #ifdef QT_HAVE_3DNOW
       
  8045         if (features & MMX3DNOW) {
       
  8046             functionForModeAsm = qt_functionForMode_MMX3DNOW;
       
  8047             functionForModeSolidAsm = qt_functionForModeSolid_MMX3DNOW;
       
  8048             qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx3dnow;
       
  8049         }
       
  8050 #endif // 3DNOW
       
  8051 
       
  8052         extern void qt_blend_rgb32_on_rgb32_mmx(uchar *destPixels, int dbpl,
       
  8053                                                 const uchar *srcPixels, int sbpl,
       
  8054                                                 int w, int h,
       
  8055                                                 int const_alpha);
       
  8056         extern void qt_blend_argb32_on_argb32_mmx(uchar *destPixels, int dbpl,
       
  8057                                                   const uchar *srcPixels, int sbpl,
       
  8058                                                   int w, int h,
       
  8059                                                   int const_alpha);
       
  8060 
       
  8061         qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mmx;
       
  8062         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mmx;
       
  8063         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mmx;
       
  8064         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mmx;
       
  8065 
       
  8066     }
       
  8067 #endif // MMX
       
  8068 
       
  8069 #ifdef QT_HAVE_SSE
       
  8070     if (features & SSE) {
       
  8071         functionForModeAsm = qt_functionForMode_SSE;
       
  8072         functionForModeSolidAsm = qt_functionForModeSolid_SSE;
       
  8073         qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse;
       
  8074 #ifdef QT_HAVE_3DNOW
       
  8075         if (features & MMX3DNOW) {
       
  8076             functionForModeAsm = qt_functionForMode_SSE3DNOW;
       
  8077             functionForModeSolidAsm = qt_functionForModeSolid_SSE3DNOW;
       
  8078             qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse3dnow;
       
  8079         }
       
  8080 #endif // 3DNOW
       
  8081         extern void qt_blend_rgb32_on_rgb32_sse(uchar *destPixels, int dbpl,
       
  8082                                                 const uchar *srcPixels, int sbpl,
       
  8083                                                 int w, int h,
       
  8084                                                 int const_alpha);
       
  8085         extern void qt_blend_argb32_on_argb32_sse(uchar *destPixels, int dbpl,
       
  8086                                                   const uchar *srcPixels, int sbpl,
       
  8087                                                   int w, int h,
       
  8088                                                   int const_alpha);
       
  8089 
       
  8090         qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
       
  8091         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
       
  8092         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
       
  8093         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
       
  8094     }
       
  8095 #endif // SSE
       
  8096 
       
  8097 #ifdef QT_HAVE_IWMMXT
       
  8098     if (features & IWMMXT) {
       
  8099         functionForModeAsm = qt_functionForMode_IWMMXT;
       
  8100         functionForModeSolidAsm = qt_functionForModeSolid_IWMMXT;
       
  8101         qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_iwmmxt;
       
  8102     }
       
  8103 #endif // IWMMXT
       
  8104 
       
  8105 #endif // QT_NO_DEBUG
       
  8106 
       
  8107 #if defined(Q_CC_RVCT) && defined(QT_HAVE_ARMV6)
       
  8108         functionForModeAsm = qt_functionForMode_ARMv6;
       
  8109         functionForModeSolidAsm = qt_functionForModeSolid_ARMv6;
       
  8110 
       
  8111         qt_memfill32 = qt_memfill32_armv6;
       
  8112 
       
  8113         qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_armv6;
       
  8114 
       
  8115         qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_armv6;
       
  8116         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_armv6;
       
  8117         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_armv6;
       
  8118         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_armv6;
       
  8119 #endif // Q_CC_RVCT && QT_HAVE_ARMV6
       
  8120 
       
  8121     if (functionForModeSolidAsm) {
       
  8122         const int destinationMode = QPainter::CompositionMode_Destination;
       
  8123         functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode];
       
  8124 
       
  8125         // use the default qdrawhelper implementation for the
       
  8126         // extended composition modes
       
  8127         for (int mode = 12; mode < 24; ++mode)
       
  8128             functionForModeSolidAsm[mode] = functionForModeSolid_C[mode];
       
  8129 
       
  8130         functionForModeSolid = functionForModeSolidAsm;
       
  8131     }
       
  8132     if (functionForModeAsm) {
       
  8133         const int destinationMode = QPainter::CompositionMode_Destination;
       
  8134         functionForModeAsm[destinationMode] = functionForMode_C[destinationMode];
       
  8135 
       
  8136         // use the default qdrawhelper implementation for the
       
  8137         // extended composition modes
       
  8138         for (int mode = 12; mode < numCompositionFunctions; ++mode)
       
  8139             functionForModeAsm[mode] = functionForMode_C[mode];
       
  8140 
       
  8141         functionForMode = functionForModeAsm;
       
  8142     }
       
  8143 
       
  8144     qt_build_pow_tables();
       
  8145 }
       
  8146 
       
  8147 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count)
       
  8148 {
       
  8149     qInitDrawhelperAsm();
       
  8150     qt_memfill32(dest, value, count);
       
  8151 }
       
  8152 
       
  8153 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count)
       
  8154 {
       
  8155     qInitDrawhelperAsm();
       
  8156     qt_memfill16(dest, value, count);
       
  8157 }
       
  8158 
       
  8159 #ifdef QT_QWS_DEPTH_GENERIC
       
  8160 
       
  8161 int qrgb::bpp = 0;
       
  8162 int qrgb::len_red = 0;
       
  8163 int qrgb::len_green = 0;
       
  8164 int qrgb::len_blue = 0;
       
  8165 int qrgb::len_alpha = 0;
       
  8166 int qrgb::off_red = 0;
       
  8167 int qrgb::off_green = 0;
       
  8168 int qrgb::off_blue = 0;
       
  8169 int qrgb::off_alpha = 0;
       
  8170 
       
  8171 template <typename SRC>
       
  8172 Q_STATIC_TEMPLATE_FUNCTION inline void qt_rectconvert_rgb(qrgb *dest, const SRC *src,
       
  8173                                       int x, int y, int width, int height,
       
  8174                                       int dstStride, int srcStride)
       
  8175 {
       
  8176     quint8 *dest8 = reinterpret_cast<quint8*>(dest)
       
  8177                     + y * dstStride + x * qrgb::bpp;
       
  8178 
       
  8179     srcStride = srcStride / sizeof(SRC) - width;
       
  8180     dstStride -= (width * qrgb::bpp);
       
  8181 
       
  8182     for (int j = 0;  j < height; ++j) {
       
  8183         for (int i = 0; i < width; ++i) {
       
  8184             const quint32 v = qt_convertToRgb<SRC>(*src++);
       
  8185 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
       
  8186             for (int j = qrgb::bpp - 1; j >= 0; --j)
       
  8187                 *dest8++ = (v >> (8 * j)) & 0xff;
       
  8188 #else
       
  8189             for (int j = 0; j < qrgb::bpp; ++j)
       
  8190                 *dest8++ = (v >> (8 * j)) & 0xff;
       
  8191 #endif
       
  8192         }
       
  8193 
       
  8194         dest8 += dstStride;
       
  8195         src += srcStride;
       
  8196     }
       
  8197 }
       
  8198 
       
  8199 template <>
       
  8200 void qt_rectconvert(qrgb *dest, const quint32 *src,
       
  8201                     int x, int y, int width, int height,
       
  8202                     int dstStride, int srcStride)
       
  8203 {
       
  8204     qt_rectconvert_rgb<quint32>(dest, src, x, y, width, height,
       
  8205                                 dstStride, srcStride);
       
  8206 }
       
  8207 
       
  8208 template <>
       
  8209 void qt_rectconvert(qrgb *dest, const quint16 *src,
       
  8210                     int x, int y, int width, int height,
       
  8211                     int dstStride, int srcStride)
       
  8212 {
       
  8213     qt_rectconvert_rgb<quint16>(dest, src, x, y, width, height,
       
  8214                                 dstStride, srcStride);
       
  8215 }
       
  8216 
       
  8217 #endif // QT_QWS_DEPTH_GENERIC
       
  8218 
       
  8219 QT_END_NAMESPACE