Make QRegion not need to be friends with QVector
[profile/ivi/qtbase.git] / src / gui / painting / qdrawhelper.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #if defined(__OPTIMIZE__) && !defined(__INTEL_COMPILER) && defined(__GNUC__) \
43     && (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
44 // GCC 4.4 supports #pragma GCC optimize and #pragma GCC target
45 #  pragma GCC optimize "O3"
46 #  if defined(__i386__) && defined(__SSE2__) && !defined(__SSE2_MATH__)
47 #   pragma GCC target "fpmath=sse"
48 #  endif
49 #endif
50
51 #include <qstylehints.h>
52 #include <qguiapplication.h>
53 #include <qatomic.h>
54 #include <private/qdrawhelper_p.h>
55 #include <private/qpaintengine_raster_p.h>
56 #include <private/qpainter_p.h>
57 #include <private/qdrawhelper_x86_p.h>
58 #include <private/qdrawhelper_neon_p.h>
59 #if defined(QT_COMPILER_SUPPORTS_MIPS_DSP) || defined(QT_COMPILER_SUPPORTS_MIPS_DSPR2)
60 #include <private/qdrawhelper_mips_dsp_p.h>
61 #endif
62 #include <private/qmath_p.h>
63 #include <private/qguiapplication_p.h>
64 #include <qmath.h>
65
66 QT_BEGIN_NAMESPACE
67
68 #define MASK(src, a) src = BYTE_MUL(src, a)
69
70 /*
71   constants and structures
72 */
73
74 enum {
75     fixed_scale = 1 << 16,
76     half_point = 1 << 15
77 };
78
79 // must be multiple of 4 for easier SIMD implementations
80 static const int buffer_size = 2048;
81
82
83
84
85 // To convert in place, let 'dest' and 'src' be the same.
86 static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint *src, int count,
87                                                         const QPixelLayout *, const QRgb *clut)
88 {
89     for (int i = 0; i < count; ++i)
90         buffer[i] = PREMUL(clut[src[i]]);
91     return buffer;
92 }
93
94 static const uint *QT_FASTCALL convertPassThrough(uint *, const uint *src, int,
95                                                   const QPixelLayout *, const QRgb *)
96 {
97     return src;
98 }
99
100 static const uint *QT_FASTCALL convertRGB16ToARGB32PM(uint *buffer, const uint *src, int count,
101                                                       const QPixelLayout *, const QRgb *)
102 {
103     for (int i = 0; i < count; ++i)
104         buffer[i] = qConvertRgb16To32(src[i]);
105     return buffer;
106 }
107
108 static const uint *QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count,
109                                                        const QPixelLayout *, const QRgb *)
110 {
111     for (int i = 0; i < count; ++i)
112         buffer[i] = PREMUL(src[i]);
113     return buffer;
114 }
115
116 static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int count,
117                                               const QPixelLayout *layout, const QRgb *)
118 {
119     Q_ASSERT(layout->redWidth >= 4);
120     Q_ASSERT(layout->greenWidth >= 4);
121     Q_ASSERT(layout->blueWidth >= 4);
122     Q_ASSERT(layout->alphaWidth == 0);
123
124     const uint redMask = ((1 << layout->redWidth) - 1);
125     const uint greenMask = ((1 << layout->greenWidth) - 1);
126     const uint blueMask = ((1 << layout->blueWidth) - 1);
127
128     const uchar redLeftShift = 8 - layout->redWidth;
129     const uchar greenLeftShift = 8 - layout->greenWidth;
130     const uchar blueLeftShift = 8 - layout->blueWidth;
131
132     const uchar redRightShift = 2 * layout->redWidth - 8;
133     const uchar greenRightShift = 2 * layout->greenWidth - 8;
134     const uchar blueRightShift = 2 * layout->blueWidth - 8;
135
136     for (int i = 0; i < count; ++i) {
137         uint red = (src[i] >> layout->redShift) & redMask;
138         uint green = (src[i] >> layout->greenShift) & greenMask;
139         uint blue = (src[i] >> layout->blueShift) & blueMask;
140
141         red = ((red << redLeftShift) | (red >> redRightShift)) << 16;
142         green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8;
143         blue = (blue << blueLeftShift) | (blue >> blueRightShift);
144         buffer[i] = 0xff000000 | red | green | blue;
145     }
146
147     return buffer;
148 }
149
150 static const uint *QT_FASTCALL convertToARGB32PM(uint *buffer, const uint *src, int count,
151                                                  const QPixelLayout *layout, const QRgb *)
152 {
153     Q_ASSERT(layout->redWidth >= 4);
154     Q_ASSERT(layout->greenWidth >= 4);
155     Q_ASSERT(layout->blueWidth >= 4);
156     Q_ASSERT(layout->alphaWidth >= 4);
157
158     const uint redMask = ((1 << layout->redWidth) - 1);
159     const uint greenMask = ((1 << layout->greenWidth) - 1);
160     const uint blueMask = ((1 << layout->blueWidth) - 1);
161
162     const uchar redLeftShift = 8 - layout->redWidth;
163     const uchar greenLeftShift = 8 - layout->greenWidth;
164     const uchar blueLeftShift = 8 - layout->blueWidth;
165
166     const uchar redRightShift = 2 * layout->redWidth - 8;
167     const uchar greenRightShift = 2 * layout->greenWidth - 8;
168     const uchar blueRightShift = 2 * layout->blueWidth - 8;
169
170     const uint alphaMask = ((1 << layout->alphaWidth) - 1);
171     const uchar alphaLeftShift = 8 - layout->alphaWidth;
172     const uchar alphaRightShift = 2 * layout->alphaWidth - 8;
173
174     if (layout->premultiplied) {
175         for (int i = 0; i < count; ++i) {
176             uint alpha = (src[i] >> layout->alphaShift) & alphaMask;
177             uint red = (src[i] >> layout->redShift) & redMask;
178             uint green = (src[i] >> layout->greenShift) & greenMask;
179             uint blue = (src[i] >> layout->blueShift) & blueMask;
180
181             alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift);
182             red = qMin(alpha, (red << redLeftShift) | (red >> redRightShift));
183             green = qMin(alpha, (green << greenLeftShift) | (green >> greenRightShift));
184             blue = qMin(alpha, (blue << blueLeftShift) | (blue >> blueRightShift));
185             buffer[i] = (alpha << 24) | (red << 16) | (green << 8) | blue;
186         }
187     } else {
188         for (int i = 0; i < count; ++i) {
189             uint alpha = (src[i] >> layout->alphaShift) & alphaMask;
190             uint red = (src[i] >> layout->redShift) & redMask;
191             uint green = (src[i] >> layout->greenShift) & greenMask;
192             uint blue = (src[i] >> layout->blueShift) & blueMask;
193
194             alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift);
195             red = (red << redLeftShift) | (red >> redRightShift);
196             green = (green << greenLeftShift) | (green >> greenRightShift);
197             blue = (blue << blueLeftShift) | (blue >> blueRightShift);
198             buffer[i] = PREMUL((alpha << 24) | (red << 16) | (green << 8) | blue);
199         }
200     }
201     return buffer;
202 }
203
204 static const uint *QT_FASTCALL convertRGB16FromARGB32PM(uint *buffer, const uint *src, int count,
205                                                         const QPixelLayout *, const QRgb *)
206 {
207     for (int i = 0; i < count; ++i)
208         buffer[i] = qConvertRgb32To16(INV_PREMUL(src[i]));
209     return buffer;
210 }
211
212 static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uint *src, int count,
213                                                          const QPixelLayout *, const QRgb *)
214 {
215     for (int i = 0; i < count; ++i)
216         buffer[i] = INV_PREMUL(src[i]);
217     return buffer;
218 }
219
220 static const uint *QT_FASTCALL convertFromARGB32PM(uint *buffer, const uint *src, int count,
221                                                    const QPixelLayout *layout, const QRgb *)
222 {
223     Q_ASSERT(layout->redWidth <= 8);
224     Q_ASSERT(layout->greenWidth <= 8);
225     Q_ASSERT(layout->blueWidth <= 8);
226     Q_ASSERT(layout->alphaWidth <= 8);
227
228     const uint redMask = (1 << layout->redWidth) - 1;
229     const uint greenMask = (1 << layout->greenWidth) - 1;
230     const uint blueMask = (1 << layout->blueWidth) - 1;
231     const uint alphaMask = (1 << layout->alphaWidth) - 1;
232
233     const uchar redRightShift = 24 - layout->redWidth;
234     const uchar greenRightShift = 16 - layout->greenWidth;
235     const uchar blueRightShift = 8 - layout->blueWidth;
236     const uchar alphaRightShift = 32 - layout->alphaWidth;
237
238     if (!layout->premultiplied) {
239         for (int i = 0; i < count; ++i)
240             buffer[i] = qAlpha(src[i]) == 255 ? src[i] : INV_PREMUL(src[i]);
241         src = buffer;
242     }
243     for (int i = 0; i < count; ++i) {
244         uint red = ((src[i] >> redRightShift) & redMask) << layout->redShift;
245         uint green = ((src[i] >> greenRightShift) & greenMask) << layout->greenShift;
246         uint blue = ((src[i] >> blueRightShift) & blueMask) << layout->blueShift;
247         uint alpha = ((src[i] >> alphaRightShift) & alphaMask) << layout->alphaShift;
248         buffer[i] = red | green | blue | alpha;
249     }
250     return buffer;
251 }
252
253 // Note:
254 // convertToArgb32() assumes that no color channel is less than 4 bits.
255 // convertFromArgb32() assumes that no color channel is more than 8 bits.
256 // QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits.
257 QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
258     { 0,  0, 0,  0, 0,  0, 0,  0, false, QPixelLayout::BPPNone, 0, 0 }, // Format_Invalid
259     { 0,  0, 0,  0, 0,  0, 0,  0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0 }, // Format_Mono
260     { 0,  0, 0,  0, 0,  0, 0,  0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0 }, // Format_MonoLSB
261     { 0,  0, 0,  0, 0,  0, 0,  0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0 }, // Format_Indexed8
262     { 8, 16, 8,  8, 8,  0, 0,  0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough }, // Format_RGB32
263     { 8, 16, 8,  8, 8,  0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM }, // Format_ARGB32
264     { 8, 16, 8,  8, 8,  0, 8, 24,  true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough }, // Format_ARGB32_Premultiplied
265     { 5, 11, 6,  5, 5,  0, 0,  0, false, QPixelLayout::BPP16, convertRGB16ToARGB32PM, convertRGB16FromARGB32PM }, // Format_RGB16
266     { 5, 19, 6, 13, 5,  8, 8,  0,  true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB8565_Premultiplied
267     { 6, 12, 6,  6, 6,  0, 0,  0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM }, // Format_RGB666
268     { 6, 12, 6,  6, 6,  0, 6, 18,  true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB6666_Premultiplied
269     { 5, 10, 5,  5, 5,  0, 0,  0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM }, // Format_RGB555
270     { 5, 18, 5, 13, 5,  8, 8,  0,  true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB8555_Premultiplied
271     { 8,  0, 8,  8, 8, 16, 0,  0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM }, // Format_RGB888
272     { 4,  8, 4,  4, 4,  0, 0,  0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM }, // Format_RGB444
273     { 4,  8, 4,  4, 4,  0, 4, 12,  true, QPixelLayout::BPP16, convertToARGB32PM, convertFromARGB32PM } // Format_ARGB4444_Premultiplied
274 };
275
276 FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = {
277     0, // BPPNone
278     fetchPixels<QPixelLayout::BPP1MSB>, // BPP1MSB
279     fetchPixels<QPixelLayout::BPP1LSB>, // BPP1LSB
280     fetchPixels<QPixelLayout::BPP8>, // BPP8
281     fetchPixels<QPixelLayout::BPP16>, // BPP16
282     fetchPixels<QPixelLayout::BPP24>, // BPP24
283     fetchPixels<QPixelLayout::BPP32> // BPP32
284 };
285
286 StorePixelsFunc qStorePixels[QPixelLayout::BPPCount] = {
287     0, // BPPNone
288     storePixels<QPixelLayout::BPP1MSB>, // BPP1MSB
289     storePixels<QPixelLayout::BPP1LSB>, // BPP1LSB
290     storePixels<QPixelLayout::BPP8>, // BPP8
291     storePixels<QPixelLayout::BPP16>, // BPP16
292     storePixels<QPixelLayout::BPP24>, // BPP24
293     storePixels<QPixelLayout::BPP32> // BPP32
294 };
295
296 typedef uint (QT_FASTCALL *FetchPixelFunc)(const uchar *src, int index);
297
298 FetchPixelFunc qFetchPixel[QPixelLayout::BPPCount] = {
299     0, // BPPNone
300     fetchPixel<QPixelLayout::BPP1MSB>, // BPP1MSB
301     fetchPixel<QPixelLayout::BPP1LSB>, // BPP1LSB
302     fetchPixel<QPixelLayout::BPP8>, // BPP8
303     fetchPixel<QPixelLayout::BPP16>, // BPP16
304     fetchPixel<QPixelLayout::BPP24>, // BPP24
305     fetchPixel<QPixelLayout::BPP32> // BPP32
306 };
307
308 /*
309   Destination fetch. This is simple as we don't have to do bounds checks or
310   transformations
311 */
312
313 static uint * QT_FASTCALL destFetchMono(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
314 {
315     uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
316     uint *start = buffer;
317     const uint *end = buffer + length;
318     while (buffer < end) {
319         *buffer = data[x>>3] & (0x80 >> (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
320         ++buffer;
321         ++x;
322     }
323     return start;
324 }
325
326 static uint * QT_FASTCALL destFetchMonoLsb(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
327 {
328     uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
329     uint *start = buffer;
330     const uint *end = buffer + length;
331     while (buffer < end) {
332         *buffer = data[x>>3] & (0x1 << (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
333         ++buffer;
334         ++x;
335     }
336     return start;
337 }
338
339 static uint * QT_FASTCALL destFetchARGB32P(uint *, QRasterBuffer *rasterBuffer, int x, int y, int)
340 {
341     return (uint *)rasterBuffer->scanLine(y) + x;
342 }
343
344 static uint * QT_FASTCALL destFetchRGB16(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
345 {
346     const ushort *Q_DECL_RESTRICT data = (const ushort *)rasterBuffer->scanLine(y) + x;
347     for (int i = 0; i < length; ++i)
348         buffer[i] = qConvertRgb16To32(data[i]);
349     return buffer;
350 }
351
352 static uint *QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
353 {
354     const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
355     const uint *ptr = qFetchPixels[layout->bpp](buffer, rasterBuffer->scanLine(y), x, length);
356     return const_cast<uint *>(layout->convertToARGB32PM(buffer, ptr, length, layout, 0));
357 }
358
359
360 static DestFetchProc destFetchProc[QImage::NImageFormats] =
361 {
362     0,                  // Format_Invalid
363     destFetchMono,      // Format_Mono,
364     destFetchMonoLsb,   // Format_MonoLSB
365     0,                  // Format_Indexed8
366     destFetchARGB32P,   // Format_RGB32
367     destFetch,          // Format_ARGB32,
368     destFetchARGB32P,   // Format_ARGB32_Premultiplied
369     destFetchRGB16,     // Format_RGB16
370     destFetch,          // Format_ARGB8565_Premultiplied
371     destFetch,          // Format_RGB666
372     destFetch,          // Format_ARGB6666_Premultiplied
373     destFetch,          // Format_RGB555
374     destFetch,          // Format_ARGB8555_Premultiplied
375     destFetch,          // Format_RGB888
376     destFetch,          // Format_RGB444
377     destFetch           // Format_ARGB4444_Premultiplied
378 };
379
380 /*
381    Returns the color in the mono destination color table
382    that is the "nearest" to /color/.
383 */
384 static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
385 {
386     QRgb color_0 = PREMUL(rbuf->destColor0);
387     QRgb color_1 = PREMUL(rbuf->destColor1);
388     color = PREMUL(color);
389
390     int r = qRed(color);
391     int g = qGreen(color);
392     int b = qBlue(color);
393     int rx, gx, bx;
394     int dist_0, dist_1;
395
396     rx = r - qRed(color_0);
397     gx = g - qGreen(color_0);
398     bx = b - qBlue(color_0);
399     dist_0 = rx*rx + gx*gx + bx*bx;
400
401     rx = r - qRed(color_1);
402     gx = g - qGreen(color_1);
403     bx = b - qBlue(color_1);
404     dist_1 = rx*rx + gx*gx + bx*bx;
405
406     if (dist_0 < dist_1)
407         return color_0;
408     return color_1;
409 }
410
411 /*
412   Destination store.
413 */
414
415 static void QT_FASTCALL destStoreMono(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
416 {
417     uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
418     if (rasterBuffer->monoDestinationWithClut) {
419         for (int i = 0; i < length; ++i) {
420             if (buffer[i] == rasterBuffer->destColor0) {
421                 data[x >> 3] &= ~(0x80 >> (x & 7));
422             } else if (buffer[i] == rasterBuffer->destColor1) {
423                 data[x >> 3] |= 0x80 >> (x & 7);
424             } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
425                 data[x >> 3] &= ~(0x80 >> (x & 7));
426             } else {
427                 data[x >> 3] |= 0x80 >> (x & 7);
428             }
429             ++x;
430         }
431     } else {
432         for (int i = 0; i < length; ++i) {
433             if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
434                 data[x >> 3] |= 0x80 >> (x & 7);
435             else
436                 data[x >> 3] &= ~(0x80 >> (x & 7));
437             ++x;
438         }
439     }
440 }
441
442 static void QT_FASTCALL destStoreMonoLsb(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
443 {
444     uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
445     if (rasterBuffer->monoDestinationWithClut) {
446         for (int i = 0; i < length; ++i) {
447             if (buffer[i] == rasterBuffer->destColor0) {
448                 data[x >> 3] &= ~(1 << (x & 7));
449             } else if (buffer[i] == rasterBuffer->destColor1) {
450                 data[x >> 3] |= 1 << (x & 7);
451             } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
452                 data[x >> 3] &= ~(1 << (x & 7));
453             } else {
454                 data[x >> 3] |= 1 << (x & 7);
455             }
456             ++x;
457         }
458     } else {
459         for (int i = 0; i < length; ++i) {
460             if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
461                 data[x >> 3] |= 1 << (x & 7);
462             else
463                 data[x >> 3] &= ~(1 << (x & 7));
464             ++x;
465         }
466     }
467 }
468
469 static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
470 {
471     quint16 *data = (quint16*)rasterBuffer->scanLine(y) + x;
472     for (int i = 0; i < length; ++i)
473         data[i] = qConvertRgb32To16(buffer[i]);
474 }
475
476 static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
477 {
478     uint buf[buffer_size];
479     const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
480     StorePixelsFunc store = qStorePixels[layout->bpp];
481     uchar *dest = rasterBuffer->scanLine(y);
482     while (length) {
483         int l = qMin(length, buffer_size);
484         const uint *ptr = layout->convertFromARGB32PM(buf, buffer, l, layout, 0);
485         store(dest, ptr, x, l);
486         length -= l;
487         buffer += l;
488         x += l;
489     }
490 }
491
492 static DestStoreProc destStoreProc[QImage::NImageFormats] =
493 {
494     0,                  // Format_Invalid
495     destStoreMono,      // Format_Mono,
496     destStoreMonoLsb,   // Format_MonoLSB
497     0,                  // Format_Indexed8
498     0,                  // Format_RGB32
499     destStore,          // Format_ARGB32,
500     0,                  // Format_ARGB32_Premultiplied
501     destStoreRGB16,     // Format_RGB16
502     destStore,          // Format_ARGB8565_Premultiplied
503     destStore,          // Format_RGB666
504     destStore,          // Format_ARGB6666_Premultiplied
505     destStore,          // Format_RGB555
506     destStore,          // Format_ARGB8555_Premultiplied
507     destStore,          // Format_RGB888
508     destStore,          // Format_RGB444
509     destStore           // Format_ARGB4444_Premultiplied
510 };
511
512 /*
513   Source fetches
514
515   This is a bit more complicated, as we need several fetch routines for every surface type
516
517   We need 5 fetch methods per surface type:
518   untransformed
519   transformed (tiled and not tiled)
520   transformed bilinear (tiled and not tiled)
521
522   We don't need bounds checks for untransformed, but we need them for the other ones.
523
524   The generic implementation does pixel by pixel fetches
525 */
526
527 enum TextureBlendType {
528     BlendUntransformed,
529     BlendTiled,
530     BlendTransformed,
531     BlendTransformedTiled,
532     BlendTransformedBilinear,
533     BlendTransformedBilinearTiled,
534     NBlendTypes
535 };
536
537 static const uint *QT_FASTCALL fetchUntransformed(uint *buffer, const Operator *,
538                                                   const QSpanData *data, int y, int x, int length)
539 {
540     const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
541     const uint *ptr = qFetchPixels[layout->bpp](buffer, data->texture.scanLine(y), x, length);
542     const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0;
543     return layout->convertToARGB32PM(buffer, ptr, length, layout, clut);
544 }
545
546 static const uint *QT_FASTCALL fetchUntransformedARGB32PM(uint *, const Operator *,
547                                                           const QSpanData *data, int y, int x, int)
548 {
549     const uchar *scanLine = data->texture.scanLine(y);
550     return ((const uint *)scanLine) + x;
551 }
552
553 static const uint *QT_FASTCALL fetchUntransformedRGB16(uint *buffer, const Operator *,
554                                                        const QSpanData *data, int y, int x,
555                                                        int length)
556 {
557     const quint16 *scanLine = (const quint16 *)data->texture.scanLine(y) + x;
558 #ifdef QT_COMPILER_SUPPORTS_MIPS_DSPR2
559     qConvertRgb16To32_asm_mips_dspr2(buffer, scanLine, length);
560 #else
561     for (int i = 0; i < length; ++i)
562         buffer[i] = qConvertRgb16To32(scanLine[i]);
563 #endif
564     return buffer;
565 }
566
567 // blendType is either BlendTransformed or BlendTransformedTiled
568 template<TextureBlendType blendType>
569 static const uint *QT_FASTCALL fetchTransformedARGB32PM(uint *buffer, const Operator *, const QSpanData *data,
570                                                         int y, int x, int length)
571 {
572     int image_width = data->texture.width;
573     int image_height = data->texture.height;
574
575     const qreal cx = x + qreal(0.5);
576     const qreal cy = y + qreal(0.5);
577
578     const uint *end = buffer + length;
579     uint *b = buffer;
580     if (data->fast_matrix) {
581         // The increment pr x in the scanline
582         int fdx = (int)(data->m11 * fixed_scale);
583         int fdy = (int)(data->m12 * fixed_scale);
584
585         int fx = int((data->m21 * cy
586                       + data->m11 * cx + data->dx) * fixed_scale);
587         int fy = int((data->m22 * cy
588                       + data->m12 * cx + data->dy) * fixed_scale);
589
590         while (b < end) {
591             int px = fx >> 16;
592             int py = fy >> 16;
593
594             if (blendType == BlendTransformedTiled) {
595                 px %= image_width;
596                 py %= image_height;
597                 if (px < 0) px += image_width;
598                 if (py < 0) py += image_height;
599             } else {
600                 px = qBound(0, px, image_width - 1);
601                 py = qBound(0, py, image_height - 1);
602             }
603             *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
604
605             fx += fdx;
606             fy += fdy;
607             ++b;
608         }
609     } else {
610         const qreal fdx = data->m11;
611         const qreal fdy = data->m12;
612         const qreal fdw = data->m13;
613
614         qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
615         qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
616         qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
617
618         while (b < end) {
619             const qreal iw = fw == 0 ? 1 : 1 / fw;
620             const qreal tx = fx * iw;
621             const qreal ty = fy * iw;
622             int px = int(tx) - (tx < 0);
623             int py = int(ty) - (ty < 0);
624
625             if (blendType == BlendTransformedTiled) {
626                 px %= image_width;
627                 py %= image_height;
628                 if (px < 0) px += image_width;
629                 if (py < 0) py += image_height;
630             } else {
631                 px = qBound(0, px, image_width - 1);
632                 py = qBound(0, py, image_height - 1);
633             }
634             *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
635
636             fx += fdx;
637             fy += fdy;
638             fw += fdw;
639             //force increment to avoid /0
640             if (!fw) {
641                 fw += fdw;
642             }
643             ++b;
644         }
645     }
646     return buffer;
647 }
648
649 template<TextureBlendType blendType>  /* either BlendTransformed or BlendTransformedTiled */
650 static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data,
651                                          int y, int x, int length)
652 {
653     int image_width = data->texture.width;
654     int image_height = data->texture.height;
655
656     const qreal cx = x + qreal(0.5);
657     const qreal cy = y + qreal(0.5);
658
659     const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
660     FetchPixelFunc fetch = qFetchPixel[layout->bpp];
661
662     const uint *end = buffer + length;
663     uint *b = buffer;
664     if (data->fast_matrix) {
665         // The increment pr x in the scanline
666         int fdx = (int)(data->m11 * fixed_scale);
667         int fdy = (int)(data->m12 * fixed_scale);
668
669         int fx = int((data->m21 * cy
670                       + data->m11 * cx + data->dx) * fixed_scale);
671         int fy = int((data->m22 * cy
672                       + data->m12 * cx + data->dy) * fixed_scale);
673
674         while (b < end) {
675             int px = fx >> 16;
676             int py = fy >> 16;
677
678             if (blendType == BlendTransformedTiled) {
679                 px %= image_width;
680                 py %= image_height;
681                 if (px < 0) px += image_width;
682                 if (py < 0) py += image_height;
683             } else {
684                 px = qBound(0, px, image_width - 1);
685                 py = qBound(0, py, image_height - 1);
686             }
687             *b = fetch(data->texture.scanLine(py), px);
688
689             fx += fdx;
690             fy += fdy;
691             ++b;
692         }
693     } else {
694         const qreal fdx = data->m11;
695         const qreal fdy = data->m12;
696         const qreal fdw = data->m13;
697
698         qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
699         qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
700         qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
701
702         while (b < end) {
703             const qreal iw = fw == 0 ? 1 : 1 / fw;
704             const qreal tx = fx * iw;
705             const qreal ty = fy * iw;
706             int px = int(tx) - (tx < 0);
707             int py = int(ty) - (ty < 0);
708
709             if (blendType == BlendTransformedTiled) {
710                 px %= image_width;
711                 py %= image_height;
712                 if (px < 0) px += image_width;
713                 if (py < 0) py += image_height;
714             } else {
715                 px = qBound(0, px, image_width - 1);
716                 py = qBound(0, py, image_height - 1);
717             }
718             *b = fetch(data->texture.scanLine(py), px);
719
720             fx += fdx;
721             fy += fdy;
722             fw += fdw;
723             //force increment to avoid /0
724             if (!fw) {
725                 fw += fdw;
726             }
727             ++b;
728         }
729     }
730     const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0;
731     return layout->convertToARGB32PM(buffer, buffer, length, layout, clut);
732 }
733
734 /** \internal
735   interpolate 4 argb pixels with the distx and disty factor.
736   distx and disty bust be between 0 and 16
737  */
738 static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, int distx, int disty)
739 {
740     uint distxy = distx * disty;
741     //idistx * disty = (16-distx) * disty = 16*disty - distxy
742     //idistx * idisty = (16-distx) * (16-disty) = 16*16 - 16*distx -16*dity + distxy
743     uint tlrb = (tl & 0x00ff00ff)         * (16*16 - 16*distx - 16*disty + distxy);
744     uint tlag = ((tl & 0xff00ff00) >> 8)  * (16*16 - 16*distx - 16*disty + distxy);
745     uint trrb = ((tr & 0x00ff00ff)        * (distx*16 - distxy));
746     uint trag = (((tr & 0xff00ff00) >> 8) * (distx*16 - distxy));
747     uint blrb = ((bl & 0x00ff00ff)        * (disty*16 - distxy));
748     uint blag = (((bl & 0xff00ff00) >> 8) * (disty*16 - distxy));
749     uint brrb = ((br & 0x00ff00ff)        * (distxy));
750     uint brag = (((br & 0xff00ff00) >> 8) * (distxy));
751     return (((tlrb + trrb + blrb + brrb) >> 8) & 0x00ff00ff) | ((tlag + trag + blag + brag) & 0xff00ff00);
752 }
753
754 #if defined(__SSE2__)
755 #define interpolate_4_pixels_16_sse2(tl, tr, bl, br, distx, disty, colorMask, v_256, b)  \
756 { \
757     const __m128i dxdy = _mm_mullo_epi16 (distx, disty); \
758     const __m128i distx_ = _mm_slli_epi16(distx, 4); \
759     const __m128i disty_ = _mm_slli_epi16(disty, 4); \
760     const __m128i idxidy =  _mm_add_epi16(dxdy, _mm_sub_epi16(v_256, _mm_add_epi16(distx_, disty_))); \
761     const __m128i dxidy =  _mm_sub_epi16(distx_, dxdy); \
762     const __m128i idxdy =  _mm_sub_epi16(disty_, dxdy); \
763  \
764     __m128i tlAG = _mm_srli_epi16(tl, 8); \
765     __m128i tlRB = _mm_and_si128(tl, colorMask); \
766     __m128i trAG = _mm_srli_epi16(tr, 8); \
767     __m128i trRB = _mm_and_si128(tr, colorMask); \
768     __m128i blAG = _mm_srli_epi16(bl, 8); \
769     __m128i blRB = _mm_and_si128(bl, colorMask); \
770     __m128i brAG = _mm_srli_epi16(br, 8); \
771     __m128i brRB = _mm_and_si128(br, colorMask); \
772  \
773     tlAG = _mm_mullo_epi16(tlAG, idxidy); \
774     tlRB = _mm_mullo_epi16(tlRB, idxidy); \
775     trAG = _mm_mullo_epi16(trAG, dxidy); \
776     trRB = _mm_mullo_epi16(trRB, dxidy); \
777     blAG = _mm_mullo_epi16(blAG, idxdy); \
778     blRB = _mm_mullo_epi16(blRB, idxdy); \
779     brAG = _mm_mullo_epi16(brAG, dxdy); \
780     brRB = _mm_mullo_epi16(brRB, dxdy); \
781  \
782     /* Add the values, and shift to only keep 8 significant bits per colors */ \
783     __m128i rAG =_mm_add_epi16(_mm_add_epi16(tlAG, trAG), _mm_add_epi16(blAG, brAG)); \
784     __m128i rRB =_mm_add_epi16(_mm_add_epi16(tlRB, trRB), _mm_add_epi16(blRB, brRB)); \
785     rAG = _mm_andnot_si128(colorMask, rAG); \
786     rRB = _mm_srli_epi16(rRB, 8); \
787     _mm_storeu_si128((__m128i*)(b), _mm_or_si128(rAG, rRB)); \
788 }
789 #endif
790
791 #if defined(__ARM_NEON__)
792 #define interpolate_4_pixels_16_neon(tl, tr, bl, br, distx, disty, disty_, colorMask, invColorMask, v_256, b)  \
793 { \
794     const int16x8_t dxdy = vmulq_s16(distx, disty); \
795     const int16x8_t distx_ = vshlq_n_s16(distx, 4); \
796     const int16x8_t idxidy =  vaddq_s16(dxdy, vsubq_s16(v_256, vaddq_s16(distx_, disty_))); \
797     const int16x8_t dxidy =  vsubq_s16(distx_, dxdy); \
798     const int16x8_t idxdy =  vsubq_s16(disty_, dxdy); \
799  \
800     int16x8_t tlAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tl), 8)); \
801     int16x8_t tlRB = vandq_s16(tl, colorMask); \
802     int16x8_t trAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tr), 8)); \
803     int16x8_t trRB = vandq_s16(tr, colorMask); \
804     int16x8_t blAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bl), 8)); \
805     int16x8_t blRB = vandq_s16(bl, colorMask); \
806     int16x8_t brAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(br), 8)); \
807     int16x8_t brRB = vandq_s16(br, colorMask); \
808  \
809     int16x8_t rAG = vmulq_s16(tlAG, idxidy); \
810     int16x8_t rRB = vmulq_s16(tlRB, idxidy); \
811     rAG = vmlaq_s16(rAG, trAG, dxidy); \
812     rRB = vmlaq_s16(rRB, trRB, dxidy); \
813     rAG = vmlaq_s16(rAG, blAG, idxdy); \
814     rRB = vmlaq_s16(rRB, blRB, idxdy); \
815     rAG = vmlaq_s16(rAG, brAG, dxdy); \
816     rRB = vmlaq_s16(rRB, brRB, dxdy); \
817  \
818     rAG = vandq_s16(invColorMask, rAG); \
819     rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8)); \
820     vst1q_s16((int16_t*)(b), vorrq_s16(rAG, rRB)); \
821 }
822 #endif
823
824 template<TextureBlendType blendType>
825 void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2);
826
827 template<>
828 inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinearTiled>(int max, int, int, int &v1, int &v2)
829 {
830     v1 %= max;
831     if (v1 < 0)
832         v1 += max;
833     v2 = v1 + 1;
834     if (v2 == max)
835         v2 = 0;
836     Q_ASSERT(v1 >= 0 && v1 < max);
837     Q_ASSERT(v2 >= 0 && v2 < max);
838 }
839
840 template<>
841 inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(int, int l1, int l2, int &v1, int &v2)
842 {
843     if (v1 < l1)
844         v2 = v1 = l1;
845     else if (v1 >= l2)
846         v2 = v1 = l2;
847     else
848         v2 = v1 + 1;
849     Q_ASSERT(v1 >= l1 && v1 <= l2);
850     Q_ASSERT(v2 >= l1 && v2 <= l2);
851 }
852
853 template<TextureBlendType blendType> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
854 static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, const Operator *,
855                                                                  const QSpanData *data, int y, int x,
856                                                                  int length)
857 {
858     int image_width = data->texture.width;
859     int image_height = data->texture.height;
860
861     int image_x1 = data->texture.x1;
862     int image_y1 = data->texture.y1;
863     int image_x2 = data->texture.x2 - 1;
864     int image_y2 = data->texture.y2 - 1;
865
866     const qreal cx = x + qreal(0.5);
867     const qreal cy = y + qreal(0.5);
868
869     uint *end = buffer + length;
870     uint *b = buffer;
871     if (data->fast_matrix) {
872         // The increment pr x in the scanline
873         int fdx = (int)(data->m11 * fixed_scale);
874         int fdy = (int)(data->m12 * fixed_scale);
875
876         int fx = int((data->m21 * cy
877                       + data->m11 * cx + data->dx) * fixed_scale);
878         int fy = int((data->m22 * cy
879                       + data->m12 * cx + data->dy) * fixed_scale);
880
881         fx -= half_point;
882         fy -= half_point;
883
884         if (fdy == 0) { //simple scale, no rotation
885             int y1 = (fy >> 16);
886             int y2;
887             fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
888             const uint *s1 = (const uint *)data->texture.scanLine(y1);
889             const uint *s2 = (const uint *)data->texture.scanLine(y2);
890
891             if (fdx <= fixed_scale && fdx > 0) { // scale up on X
892                 int disty = (fy & 0x0000ffff) >> 8;
893                 int idisty = 256 - disty;
894                 int x = fx >> 16;
895
896                 // The idea is first to do the interpolation between the row s1 and the row s2
897                 // into an intermediate buffer, then we interpolate between two pixel of this buffer.
898
899                 // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
900                 // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG
901                 quint32 intermediate_buffer[2][buffer_size + 2];
902                 // count is the size used in the intermediate_buffer.
903                 int count = qCeil(length * data->m11) + 2; //+1 for the last pixel to interpolate with, and +1 for rounding errors.
904                 Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
905                 int f = 0;
906                 int lim = count;
907                 if (blendType == BlendTransformedBilinearTiled) {
908                     x %= image_width;
909                     if (x < 0) x += image_width;
910                 } else {
911                     lim = qMin(count, image_x2-x+1);
912                     if (x < image_x1) {
913                         Q_ASSERT(x <= image_x2);
914                         uint t = s1[image_x1];
915                         uint b = s2[image_x1];
916                         quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
917                         quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
918                         do {
919                             intermediate_buffer[0][f] = rb;
920                             intermediate_buffer[1][f] = ag;
921                             f++;
922                             x++;
923                         } while (x < image_x1 && f < lim);
924                     }
925                 }
926
927                 if (blendType != BlendTransformedBilinearTiled) {
928 #if defined(__SSE2__)
929                     const __m128i disty_ = _mm_set1_epi16(disty);
930                     const __m128i idisty_ = _mm_set1_epi16(idisty);
931                     const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
932
933                     lim -= 3;
934                     for (; f < lim; x += 4, f += 4) {
935                         // Load 4 pixels from s1, and split the alpha-green and red-blue component
936                         __m128i top = _mm_loadu_si128((__m128i*)((const uint *)(s1)+x));
937                         __m128i topAG = _mm_srli_epi16(top, 8);
938                         __m128i topRB = _mm_and_si128(top, colorMask);
939                         // Multiplies each colour component by idisty
940                         topAG = _mm_mullo_epi16 (topAG, idisty_);
941                         topRB = _mm_mullo_epi16 (topRB, idisty_);
942
943                         // Same for the s2 vector
944                         __m128i bottom = _mm_loadu_si128((__m128i*)((const uint *)(s2)+x));
945                         __m128i bottomAG = _mm_srli_epi16(bottom, 8);
946                         __m128i bottomRB = _mm_and_si128(bottom, colorMask);
947                         bottomAG = _mm_mullo_epi16 (bottomAG, disty_);
948                         bottomRB = _mm_mullo_epi16 (bottomRB, disty_);
949
950                         // Add the values, and shift to only keep 8 significant bits per colors
951                         __m128i rAG =_mm_add_epi16(topAG, bottomAG);
952                         rAG = _mm_srli_epi16(rAG, 8);
953                         _mm_storeu_si128((__m128i*)(&intermediate_buffer[1][f]), rAG);
954                         __m128i rRB =_mm_add_epi16(topRB, bottomRB);
955                         rRB = _mm_srli_epi16(rRB, 8);
956                         _mm_storeu_si128((__m128i*)(&intermediate_buffer[0][f]), rRB);
957                     }
958 #elif defined(__ARM_NEON__)
959                     const int16x8_t disty_ = vdupq_n_s16(disty);
960                     const int16x8_t idisty_ = vdupq_n_s16(idisty);
961                     const int16x8_t colorMask = vdupq_n_s16(0x00ff);
962
963                     lim -= 3;
964                     for (; f < lim; x += 4, f += 4) {
965                         // Load 4 pixels from s1, and split the alpha-green and red-blue component
966                         int16x8_t top = vld1q_s16((int16_t*)((const uint *)(s1)+x));
967                         int16x8_t topAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(top), 8));
968                         int16x8_t topRB = vandq_s16(top, colorMask);
969                         // Multiplies each colour component by idisty
970                         topAG = vmulq_s16(topAG, idisty_);
971                         topRB = vmulq_s16(topRB, idisty_);
972
973                         // Same for the s2 vector
974                         int16x8_t bottom = vld1q_s16((int16_t*)((const uint *)(s2)+x));
975                         int16x8_t bottomAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bottom), 8));
976                         int16x8_t bottomRB = vandq_s16(bottom, colorMask);
977                         bottomAG = vmulq_s16(bottomAG, disty_);
978                         bottomRB = vmulq_s16(bottomRB, disty_);
979
980                         // Add the values, and shift to only keep 8 significant bits per colors
981                         int16x8_t rAG = vaddq_s16(topAG, bottomAG);
982                         rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8));
983                         vst1q_s16((int16_t*)(&intermediate_buffer[1][f]), rAG);
984                         int16x8_t rRB = vaddq_s16(topRB, bottomRB);
985                         rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8));
986                         vst1q_s16((int16_t*)(&intermediate_buffer[0][f]), rRB);
987                     }
988 #endif
989                 }
990                 for (; f < count; f++) { // Same as above but without sse2
991                     if (blendType == BlendTransformedBilinearTiled) {
992                         if (x >= image_width) x -= image_width;
993                     } else {
994                         x = qMin(x, image_x2);
995                     }
996
997                     uint t = s1[x];
998                     uint b = s2[x];
999
1000                     intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
1001                     intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
1002                     x++;
1003                 }
1004                 // Now interpolate the values from the intermediate_buffer to get the final result.
1005                 fx &= fixed_scale - 1;
1006                 Q_ASSERT((fx >> 16) == 0);
1007                 while (b < end) {
1008                     register int x1 = (fx >> 16);
1009                     register int x2 = x1 + 1;
1010                     Q_ASSERT(x1 >= 0);
1011                     Q_ASSERT(x2 < count);
1012
1013                     register int distx = (fx & 0x0000ffff) >> 8;
1014                     register int idistx = 256 - distx;
1015                     int rb = ((intermediate_buffer[0][x1] * idistx + intermediate_buffer[0][x2] * distx) >> 8) & 0xff00ff;
1016                     int ag = (intermediate_buffer[1][x1] * idistx + intermediate_buffer[1][x2] * distx) & 0xff00ff00;
1017                     *b = rb | ag;
1018                     b++;
1019                     fx += fdx;
1020                 }
1021             } else if ((fdx < 0 && fdx > -(fixed_scale / 8)) || fabs(data->m22) < (1./8.)) { // scale up more than 8x
1022                 int y1 = (fy >> 16);
1023                 int y2;
1024                 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1025                 const uint *s1 = (const uint *)data->texture.scanLine(y1);
1026                 const uint *s2 = (const uint *)data->texture.scanLine(y2);
1027                 int disty = (fy & 0x0000ffff) >> 8;
1028                 int idisty = 256 - disty;
1029                 while (b < end) {
1030                     int x1 = (fx >> 16);
1031                     int x2;
1032                     fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1033                     uint tl = s1[x1];
1034                     uint tr = s1[x2];
1035                     uint bl = s2[x1];
1036                     uint br = s2[x2];
1037
1038                     int distx = (fx & 0x0000ffff) >> 8;
1039                     int idistx = 256 - distx;
1040
1041                     uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1042                     uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1043                     *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1044
1045                     fx += fdx;
1046                     ++b;
1047                 }
1048             } else { //scale down
1049                 int y1 = (fy >> 16);
1050                 int y2;
1051                 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1052                 const uint *s1 = (const uint *)data->texture.scanLine(y1);
1053                 const uint *s2 = (const uint *)data->texture.scanLine(y2);
1054                 int disty = (fy & 0x0000ffff) >> 12;
1055
1056                 if (blendType != BlendTransformedBilinearTiled) {
1057 #define BILINEAR_DOWNSCALE_BOUNDS_PROLOG \
1058                     while (b < end) { \
1059                         int x1 = (fx >> 16); \
1060                         int x2; \
1061                         fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); \
1062                         if (x1 != x2) \
1063                             break; \
1064                         uint tl = s1[x1]; \
1065                         uint tr = s1[x2]; \
1066                         uint bl = s2[x1]; \
1067                         uint br = s2[x2]; \
1068                         int distx = (fx & 0x0000ffff) >> 12; \
1069                         *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty); \
1070                         fx += fdx; \
1071                         ++b; \
1072                     } \
1073                     uint *boundedEnd; \
1074                     if (fdx > 0) \
1075                         boundedEnd = qMin(end, buffer + uint((image_x2 - (fx >> 16)) / data->m11)); \
1076                     else \
1077                         boundedEnd = qMin(end, buffer + uint((image_x1 - (fx >> 16)) / data->m11)); \
1078                     boundedEnd -= 3;
1079
1080 #if defined(__SSE2__)
1081                     BILINEAR_DOWNSCALE_BOUNDS_PROLOG
1082
1083                     const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
1084                     const __m128i v_256 = _mm_set1_epi16(256);
1085                     const __m128i v_disty = _mm_set1_epi16(disty);
1086                     __m128i v_fdx = _mm_set1_epi32(fdx*4);
1087
1088                     ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
1089
1090                     union Vect_buffer { __m128i vect; quint32 i[4]; };
1091                     Vect_buffer v_fx;
1092
1093                     for (int i = 0; i < 4; i++) {
1094                         v_fx.i[i] = fx;
1095                         fx += fdx;
1096                     }
1097
1098                     while (b < boundedEnd) {
1099
1100                         Vect_buffer tl, tr, bl, br;
1101
1102                         for (int i = 0; i < 4; i++) {
1103                             int x1 = v_fx.i[i] >> 16;
1104                             const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1105                             const uint *addr_tr = addr_tl + 1;
1106                             tl.i[i] = *addr_tl;
1107                             tr.i[i] = *addr_tr;
1108                             bl.i[i] = *(addr_tl+secondLine);
1109                             br.i[i] = *(addr_tr+secondLine);
1110                         }
1111                         __m128i v_distx = _mm_srli_epi16(v_fx.vect, 12);
1112                         v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1113                         v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1114
1115                         interpolate_4_pixels_16_sse2(tl.vect, tr.vect, bl.vect, br.vect, v_distx, v_disty, colorMask, v_256, b);
1116                         b+=4;
1117                         v_fx.vect = _mm_add_epi32(v_fx.vect, v_fdx);
1118                     }
1119                     fx = v_fx.i[0];
1120 #elif defined(__ARM_NEON__)
1121                     BILINEAR_DOWNSCALE_BOUNDS_PROLOG
1122
1123                     const int16x8_t colorMask = vdupq_n_s16(0x00ff);
1124                     const int16x8_t invColorMask = vmvnq_s16(colorMask);
1125                     const int16x8_t v_256 = vdupq_n_s16(256);
1126                     const int16x8_t v_disty = vdupq_n_s16(disty);
1127                     const int16x8_t v_disty_ = vshlq_n_s16(v_disty, 4);
1128                     int32x4_t v_fdx = vdupq_n_s32(fdx*4);
1129
1130                     ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
1131
1132                     union Vect_buffer { int32x4_t vect; quint32 i[4]; };
1133                     Vect_buffer v_fx;
1134
1135                     for (int i = 0; i < 4; i++) {
1136                         v_fx.i[i] = fx;
1137                         fx += fdx;
1138                     }
1139
1140                     const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
1141
1142                     while (b < boundedEnd) {
1143
1144                         Vect_buffer tl, tr, bl, br;
1145
1146                         Vect_buffer v_fx_shifted;
1147                         v_fx_shifted.vect = vshrq_n_s32(v_fx.vect, 16);
1148
1149                         int32x4_t v_distx = vshrq_n_s32(vandq_s32(v_fx.vect, v_ffff_mask), 12);
1150
1151                         for (int i = 0; i < 4; i++) {
1152                             int x1 = v_fx_shifted.i[i];
1153                             const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1154                             const uint *addr_tr = addr_tl + 1;
1155                             tl.i[i] = *addr_tl;
1156                             tr.i[i] = *addr_tr;
1157                             bl.i[i] = *(addr_tl+secondLine);
1158                             br.i[i] = *(addr_tr+secondLine);
1159                         }
1160
1161                         v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
1162
1163                         interpolate_4_pixels_16_neon(vreinterpretq_s16_s32(tl.vect), vreinterpretq_s16_s32(tr.vect), vreinterpretq_s16_s32(bl.vect), vreinterpretq_s16_s32(br.vect), vreinterpretq_s16_s32(v_distx), v_disty, v_disty_, colorMask, invColorMask, v_256, b);
1164                         b+=4;
1165                         v_fx.vect = vaddq_s32(v_fx.vect, v_fdx);
1166                     }
1167                     fx = v_fx.i[0];
1168 #endif
1169                 }
1170
1171                 while (b < end) {
1172                     int x1 = (fx >> 16);
1173                     int x2;
1174                     fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1175                     uint tl = s1[x1];
1176                     uint tr = s1[x2];
1177                     uint bl = s2[x1];
1178                     uint br = s2[x2];
1179                     int distx = (fx & 0x0000ffff) >> 12;
1180                     *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1181                     fx += fdx;
1182                     ++b;
1183                 }
1184             }
1185         } else { //rotation
1186             if (fabs(data->m11) > 8 || fabs(data->m22) > 8) {
1187                 //if we are zooming more than 8 times, we use 8bit precision for the position.
1188                 while (b < end) {
1189                     int x1 = (fx >> 16);
1190                     int x2;
1191                     int y1 = (fy >> 16);
1192                     int y2;
1193
1194                     fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1195                     fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1196
1197                     const uint *s1 = (const uint *)data->texture.scanLine(y1);
1198                     const uint *s2 = (const uint *)data->texture.scanLine(y2);
1199
1200                     uint tl = s1[x1];
1201                     uint tr = s1[x2];
1202                     uint bl = s2[x1];
1203                     uint br = s2[x2];
1204
1205                     int distx = (fx & 0x0000ffff) >> 8;
1206                     int disty = (fy & 0x0000ffff) >> 8;
1207                     int idistx = 256 - distx;
1208                     int idisty = 256 - disty;
1209
1210                     uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1211                     uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1212                     *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1213
1214                     fx += fdx;
1215                     fy += fdy;
1216                     ++b;
1217                 }
1218             } else {
1219                 //we are zooming less than 8x, use 4bit precision
1220                 while (b < end) {
1221                     int x1 = (fx >> 16);
1222                     int x2;
1223                     int y1 = (fy >> 16);
1224                     int y2;
1225
1226                     fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1227                     fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1228
1229                     const uint *s1 = (const uint *)data->texture.scanLine(y1);
1230                     const uint *s2 = (const uint *)data->texture.scanLine(y2);
1231
1232                     uint tl = s1[x1];
1233                     uint tr = s1[x2];
1234                     uint bl = s2[x1];
1235                     uint br = s2[x2];
1236
1237                     int distx = (fx & 0x0000ffff) >> 12;
1238                     int disty = (fy & 0x0000ffff) >> 12;
1239
1240                     *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1241
1242                     fx += fdx;
1243                     fy += fdy;
1244                     ++b;
1245                 }
1246             }
1247         }
1248     } else {
1249         const qreal fdx = data->m11;
1250         const qreal fdy = data->m12;
1251         const qreal fdw = data->m13;
1252
1253         qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
1254         qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
1255         qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
1256
1257         while (b < end) {
1258             const qreal iw = fw == 0 ? 1 : 1 / fw;
1259             const qreal px = fx * iw - qreal(0.5);
1260             const qreal py = fy * iw - qreal(0.5);
1261
1262             int x1 = int(px) - (px < 0);
1263             int x2;
1264             int y1 = int(py) - (py < 0);
1265             int y2;
1266
1267             int distx = int((px - x1) * 256);
1268             int disty = int((py - y1) * 256);
1269             int idistx = 256 - distx;
1270             int idisty = 256 - disty;
1271
1272             fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1273             fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1274
1275             const uint *s1 = (const uint *)data->texture.scanLine(y1);
1276             const uint *s2 = (const uint *)data->texture.scanLine(y2);
1277
1278             uint tl = s1[x1];
1279             uint tr = s1[x2];
1280             uint bl = s2[x1];
1281             uint br = s2[x2];
1282
1283             uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1284             uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1285             *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1286
1287             fx += fdx;
1288             fy += fdy;
1289             fw += fdw;
1290             //force increment to avoid /0
1291             if (!fw) {
1292                 fw += fdw;
1293             }
1294             ++b;
1295         }
1296     }
1297
1298     return buffer;
1299 }
1300
1301 // blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled
1302 template<TextureBlendType blendType>
1303 static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *,
1304                                                         const QSpanData *data, int y, int x, int length)
1305 {
1306     const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
1307     const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0;
1308
1309     int image_width = data->texture.width;
1310     int image_height = data->texture.height;
1311
1312     int image_x1 = data->texture.x1;
1313     int image_y1 = data->texture.y1;
1314     int image_x2 = data->texture.x2 - 1;
1315     int image_y2 = data->texture.y2 - 1;
1316
1317     const qreal cx = x + qreal(0.5);
1318     const qreal cy = y + qreal(0.5);
1319
1320     if (data->fast_matrix) {
1321         // The increment pr x in the scanline
1322         int fdx = (int)(data->m11 * fixed_scale);
1323         int fdy = (int)(data->m12 * fixed_scale);
1324
1325         int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
1326         int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
1327
1328         fx -= half_point;
1329         fy -= half_point;
1330
1331         if (fdy == 0) { //simple scale, no rotation
1332             int y1 = (fy >> 16);
1333             int y2;
1334             fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1335             const uchar *s1 = data->texture.scanLine(y1);
1336             const uchar *s2 = data->texture.scanLine(y2);
1337
1338             if (fdx <= fixed_scale && fdx > 0) { // scale up on X
1339                 int disty = (fy & 0x0000ffff) >> 8;
1340                 int idisty = 256 - disty;
1341                 int x = fx >> 16;
1342
1343                 // The idea is first to do the interpolation between the row s1 and the row s2
1344                 // into an intermediate buffer, then we interpolate between two pixel of this buffer.
1345                 FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
1346                 uint buf1[buffer_size + 2];
1347                 uint buf2[buffer_size + 2];
1348                 const uint *ptr1;
1349                 const uint *ptr2;
1350
1351                 int count = qCeil(length * data->m11) + 2; //+1 for the last pixel to interpolate with, and +1 for rounding errors.
1352                 Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
1353
1354                 if (blendType == BlendTransformedBilinearTiled) {
1355                     x %= image_width;
1356                     if (x < 0)
1357                         x += image_width;
1358                     int len1 = qMin(count, image_width - x);
1359                     int len2 = qMin(x, count - len1);
1360
1361                     ptr1 = fetch(buf1, s1, x, len1);
1362                     ptr1 = layout->convertToARGB32PM(buf1, ptr1, len1, layout, clut);
1363                     ptr2 = fetch(buf2, s2, x, len1);
1364                     ptr2 = layout->convertToARGB32PM(buf2, ptr2, len1, layout, clut);
1365                     for (int i = 0; i < len1; ++i) {
1366                         uint t = ptr1[i];
1367                         uint b = ptr2[i];
1368                         buf1[i] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
1369                         buf2[i] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
1370                     }
1371
1372                     if (len2) {
1373                         ptr1 = fetch(buf1 + len1, s1, 0, len2);
1374                         ptr1 = layout->convertToARGB32PM(buf1 + len1, ptr1, len2, layout, clut);
1375                         ptr2 = fetch(buf2 + len1, s2, 0, len2);
1376                         ptr2 = layout->convertToARGB32PM(buf2 + len1, ptr2, len2, layout, clut);
1377                         for (int i = 0; i < len2; ++i) {
1378                             uint t = ptr1[i];
1379                             uint b = ptr2[i];
1380                             buf1[i + len1] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
1381                             buf2[i + len1] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
1382                         }
1383                     }
1384                     for (int i = image_width; i < count; ++i) {
1385                         buf1[i] = buf1[i - image_width];
1386                         buf2[i] = buf2[i - image_width];
1387                     }
1388                 } else {
1389                     int start = qMax(x, image_x1);
1390                     int end = qMin(x + count, image_x2 + 1);
1391                     int len = qMax(1, end - start);
1392                     int leading = start - x;
1393
1394                     ptr1 = fetch(buf1 + leading, s1, start, len);
1395                     ptr1 = layout->convertToARGB32PM(buf1 + leading, ptr1, len, layout, clut);
1396                     ptr2 = fetch(buf2 + leading, s2, start, len);
1397                     ptr2 = layout->convertToARGB32PM(buf2 + leading, ptr2, len, layout, clut);
1398
1399                     for (int i = 0; i < len; ++i) {
1400                         uint t = ptr1[i];
1401                         uint b = ptr2[i];
1402                         buf1[i + leading] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
1403                         buf2[i + leading] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
1404                     }
1405
1406                     for (int i = 0; i < leading; ++i) {
1407                         buf1[i] = buf1[leading];
1408                         buf2[i] = buf2[leading];
1409                     }
1410                     for (int i = leading + len; i < count; ++i) {
1411                         buf1[i] = buf1[i - 1];
1412                         buf2[i] = buf2[i - 1];
1413                     }
1414                 }
1415
1416                 // Now interpolate the values from the intermediate_buffer to get the final result.
1417                 fx &= fixed_scale - 1;
1418                 Q_ASSERT((fx >> 16) == 0);
1419                 for (int i = 0; i < length; ++i) {
1420                     register int x1 = (fx >> 16);
1421                     register int x2 = x1 + 1;
1422                     Q_ASSERT(x1 >= 0);
1423                     Q_ASSERT(x2 < count);
1424
1425                     register int distx = (fx & 0x0000ffff) >> 8;
1426                     register int idistx = 256 - distx;
1427                     int rb = ((buf1[x1] * idistx + buf1[x2] * distx) >> 8) & 0xff00ff;
1428                     int ag = (buf2[x1] * idistx + buf2[x2] * distx) & 0xff00ff00;
1429                     buffer[i] = rb | ag;
1430                     fx += fdx;
1431                 }
1432             } else {
1433                 FetchPixelFunc fetch = qFetchPixel[layout->bpp];
1434                 uint buf1[buffer_size];
1435                 uint buf2[buffer_size];
1436                 uint *b = buffer;
1437                 while (length) {
1438                     int len = qMin(length, buffer_size / 2);
1439                     int fracX = fx;
1440                     for (int i = 0; i < len; ++i) {
1441                         int x1 = (fx >> 16);
1442                         int x2;
1443                         fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1444
1445                         buf1[i * 2 + 0] = fetch(s1, x1);
1446                         buf1[i * 2 + 1] = fetch(s1, x2);
1447                         buf2[i * 2 + 0] = fetch(s2, x1);
1448                         buf2[i * 2 + 1] = fetch(s2, x2);
1449
1450                         fx += fdx;
1451                     }
1452                     layout->convertToARGB32PM(buf1, buf1, len * 2, layout, clut);
1453                     layout->convertToARGB32PM(buf2, buf2, len * 2, layout, clut);
1454
1455                     if ((fdx < 0 && fdx > -(fixed_scale / 8)) || fabs(data->m22) < (1./8.)) { // scale up more than 8x
1456                         int disty = (fy & 0x0000ffff) >> 8;
1457                         int idisty = 256 - disty;
1458                         for (int i = 0; i < len; ++i) {
1459                             uint tl = buf1[i * 2 + 0];
1460                             uint tr = buf1[i * 2 + 1];
1461                             uint bl = buf2[i * 2 + 0];
1462                             uint br = buf2[i * 2 + 1];
1463                             int distx = (fracX & 0x0000ffff) >> 8;
1464                             int idistx = 256 - distx;
1465                             uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1466                             uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1467                             b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1468                             fracX += fdx;
1469                         }
1470                     } else { //scale down
1471                         int disty = (fy & 0x0000ffff) >> 12;
1472                         for (int i = 0; i < len; ++i) {
1473                             uint tl = buf1[i * 2 + 0];
1474                             uint tr = buf1[i * 2 + 1];
1475                             uint bl = buf2[i * 2 + 0];
1476                             uint br = buf2[i * 2 + 1];
1477                             int distx = (fracX & 0x0000ffff) >> 12;
1478                             b[i] = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1479                             fracX += fdx;
1480                         }
1481                     }
1482                     length -= len;
1483                     b += len;
1484                 }
1485             }
1486         } else { //rotation
1487             FetchPixelFunc fetch = qFetchPixel[layout->bpp];
1488             uint buf1[buffer_size];
1489             uint buf2[buffer_size];
1490             uint *b = buffer;
1491
1492             while (length) {
1493                 int len = qMin(length, buffer_size / 2);
1494                 int fracX = fx;
1495                 int fracY = fy;
1496                 for (int i = 0; i < len; ++i) {
1497                     int x1 = (fx >> 16);
1498                     int x2;
1499                     int y1 = (fy >> 16);
1500                     int y2;
1501                     fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1502                     fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1503
1504                     const uchar *s1 = data->texture.scanLine(y1);
1505                     const uchar *s2 = data->texture.scanLine(y2);
1506
1507                     buf1[i * 2 + 0] = fetch(s1, x1);
1508                     buf1[i * 2 + 1] = fetch(s1, x2);
1509                     buf2[i * 2 + 0] = fetch(s2, x1);
1510                     buf2[i * 2 + 1] = fetch(s2, x2);
1511
1512                     fx += fdx;
1513                     fy += fdy;
1514                 }
1515                 layout->convertToARGB32PM(buf1, buf1, len * 2, layout, clut);
1516                 layout->convertToARGB32PM(buf2, buf2, len * 2, layout, clut);
1517
1518                 if (fabs(data->m11) > 8 || fabs(data->m22) > 8) {
1519                     //if we are zooming more than 8 times, we use 8bit precision for the position.
1520                     for (int i = 0; i < len; ++i) {
1521                         uint tl = buf1[i * 2 + 0];
1522                         uint tr = buf1[i * 2 + 1];
1523                         uint bl = buf2[i * 2 + 0];
1524                         uint br = buf2[i * 2 + 1];
1525
1526                         int distx = (fracX & 0x0000ffff) >> 8;
1527                         int disty = (fracY & 0x0000ffff) >> 8;
1528                         int idistx = 256 - distx;
1529                         int idisty = 256 - disty;
1530
1531                         uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1532                         uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1533                         b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1534                         fracX += fdx;
1535                         fracY += fdy;
1536                     }
1537                 } else {
1538                     //we are zooming less than 8x, use 4bit precision
1539                     for (int i = 0; i < len; ++i) {
1540                         uint tl = buf1[i * 2 + 0];
1541                         uint tr = buf1[i * 2 + 1];
1542                         uint bl = buf2[i * 2 + 0];
1543                         uint br = buf2[i * 2 + 1];
1544
1545                         int distx = (fracX & 0x0000ffff) >> 12;
1546                         int disty = (fracY & 0x0000ffff) >> 12;
1547
1548                         b[i] = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1549                         fracX += fdx;
1550                         fracY += fdy;
1551                     }
1552                 }
1553
1554                 length -= len;
1555                 b += len;
1556             }
1557         }
1558     } else {
1559         const qreal fdx = data->m11;
1560         const qreal fdy = data->m12;
1561         const qreal fdw = data->m13;
1562
1563         qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
1564         qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
1565         qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
1566
1567         FetchPixelFunc fetch = qFetchPixel[layout->bpp];
1568         uint buf1[buffer_size];
1569         uint buf2[buffer_size];
1570         uint *b = buffer;
1571
1572         int distxs[buffer_size / 2];
1573         int distys[buffer_size / 2];
1574
1575         while (length) {
1576             int len = qMin(length, buffer_size / 2);
1577             for (int i = 0; i < len; ++i) {
1578                 const qreal iw = fw == 0 ? 1 : 1 / fw;
1579                 const qreal px = fx * iw - qreal(0.5);
1580                 const qreal py = fy * iw - qreal(0.5);
1581
1582                 int x1 = int(px) - (px < 0);
1583                 int x2;
1584                 int y1 = int(py) - (py < 0);
1585                 int y2;
1586
1587                 distxs[i] = int((px - x1) * 256);
1588                 distys[i] = int((py - y1) * 256);
1589
1590                 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1591                 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1592
1593                 const uchar *s1 = data->texture.scanLine(y1);
1594                 const uchar *s2 = data->texture.scanLine(y2);
1595
1596                 buf1[i * 2 + 0] = fetch(s1, x1);
1597                 buf1[i * 2 + 1] = fetch(s1, x2);
1598                 buf2[i * 2 + 0] = fetch(s2, x1);
1599                 buf2[i * 2 + 1] = fetch(s2, x2);
1600
1601                 fx += fdx;
1602                 fy += fdy;
1603                 fw += fdw;
1604                 //force increment to avoid /0
1605                 if (!fw)
1606                     fw += fdw;
1607             }
1608
1609             layout->convertToARGB32PM(buf1, buf1, len * 2, layout, clut);
1610             layout->convertToARGB32PM(buf2, buf2, len * 2, layout, clut);
1611
1612             for (int i = 0; i < len; ++i) {
1613                 int distx = distxs[i];
1614                 int disty = distys[i];
1615                 int idistx = 256 - distx;
1616                 int idisty = 256 - disty;
1617
1618                 uint tl = buf1[i * 2 + 0];
1619                 uint tr = buf1[i * 2 + 1];
1620                 uint bl = buf2[i * 2 + 0];
1621                 uint br = buf2[i * 2 + 1];
1622
1623                 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1624                 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1625                 b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1626             }
1627             length -= len;
1628             b += len;
1629         }
1630     }
1631
1632     return buffer;
1633 }
1634
1635 static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = {
1636     // Untransformed
1637     {
1638         0, // Invalid
1639         fetchUntransformed,         // Mono
1640         fetchUntransformed,         // MonoLsb
1641         fetchUntransformed,         // Indexed8
1642         fetchUntransformedARGB32PM, // RGB32
1643         fetchUntransformed,         // ARGB32
1644         fetchUntransformedARGB32PM, // ARGB32_Premultiplied
1645         fetchUntransformedRGB16,    // RGB16
1646         fetchUntransformed,         // ARGB8565_Premultiplied
1647         fetchUntransformed,         // RGB666
1648         fetchUntransformed,         // ARGB6666_Premultiplied
1649         fetchUntransformed,         // RGB555
1650         fetchUntransformed,         // ARGB8555_Premultiplied
1651         fetchUntransformed,         // RGB888
1652         fetchUntransformed,         // RGB444
1653         fetchUntransformed          // ARGB4444_Premultiplied
1654     },
1655     // Tiled
1656     {
1657         0, // Invalid
1658         fetchUntransformed,         // Mono
1659         fetchUntransformed,         // MonoLsb
1660         fetchUntransformed,         // Indexed8
1661         fetchUntransformedARGB32PM, // RGB32
1662         fetchUntransformed,         // ARGB32
1663         fetchUntransformedARGB32PM, // ARGB32_Premultiplied
1664         fetchUntransformedRGB16,    // RGB16
1665         fetchUntransformed,         // ARGB8565_Premultiplied
1666         fetchUntransformed,         // RGB666
1667         fetchUntransformed,         // ARGB6666_Premultiplied
1668         fetchUntransformed,         // RGB555
1669         fetchUntransformed,         // ARGB8555_Premultiplied
1670         fetchUntransformed,         // RGB888
1671         fetchUntransformed,         // RGB444
1672         fetchUntransformed          // ARGB4444_Premultiplied
1673     },
1674     // Transformed
1675     {
1676         0, // Invalid
1677         fetchTransformed<BlendTransformed>,         // Mono
1678         fetchTransformed<BlendTransformed>,         // MonoLsb
1679         fetchTransformed<BlendTransformed>,         // Indexed8
1680         fetchTransformedARGB32PM<BlendTransformed>, // RGB32
1681         fetchTransformed<BlendTransformed>,         // ARGB32
1682         fetchTransformedARGB32PM<BlendTransformed>, // ARGB32_Premultiplied
1683         fetchTransformed<BlendTransformed>,         // RGB16
1684         fetchTransformed<BlendTransformed>,         // ARGB8565_Premultiplied
1685         fetchTransformed<BlendTransformed>,         // RGB666
1686         fetchTransformed<BlendTransformed>,         // ARGB6666_Premultiplied
1687         fetchTransformed<BlendTransformed>,         // RGB555
1688         fetchTransformed<BlendTransformed>,         // ARGB8555_Premultiplied
1689         fetchTransformed<BlendTransformed>,         // RGB888
1690         fetchTransformed<BlendTransformed>,         // RGB444
1691         fetchTransformed<BlendTransformed>,         // ARGB4444_Premultiplied
1692     },
1693     {
1694         0, // TransformedTiled
1695         fetchTransformed<BlendTransformedTiled>,            // Mono
1696         fetchTransformed<BlendTransformedTiled>,            // MonoLsb
1697         fetchTransformed<BlendTransformedTiled>,            // Indexed8
1698         fetchTransformedARGB32PM<BlendTransformedTiled>,    // RGB32
1699         fetchTransformed<BlendTransformedTiled>,            // ARGB32
1700         fetchTransformedARGB32PM<BlendTransformedTiled>,    // ARGB32_Premultiplied
1701         fetchTransformed<BlendTransformedTiled>,            // RGB16
1702         fetchTransformed<BlendTransformedTiled>,            // ARGB8565_Premultiplied
1703         fetchTransformed<BlendTransformedTiled>,            // RGB666
1704         fetchTransformed<BlendTransformedTiled>,            // ARGB6666_Premultiplied
1705         fetchTransformed<BlendTransformedTiled>,            // RGB555
1706         fetchTransformed<BlendTransformedTiled>,            // ARGB8555_Premultiplied
1707         fetchTransformed<BlendTransformedTiled>,            // RGB888
1708         fetchTransformed<BlendTransformedTiled>,            // RGB444
1709         fetchTransformed<BlendTransformedTiled>,            // ARGB4444_Premultiplied
1710     },
1711     {
1712         0, // Bilinear
1713         fetchTransformedBilinear<BlendTransformedBilinear>,         // Mono
1714         fetchTransformedBilinear<BlendTransformedBilinear>,         // MonoLsb
1715         fetchTransformedBilinear<BlendTransformedBilinear>,         // Indexed8
1716         fetchTransformedBilinearARGB32PM<BlendTransformedBilinear>, // RGB32
1717         fetchTransformedBilinear<BlendTransformedBilinear>,         // ARGB32
1718         fetchTransformedBilinearARGB32PM<BlendTransformedBilinear>, // ARGB32_Premultiplied
1719         fetchTransformedBilinear<BlendTransformedBilinear>,         // RGB16
1720         fetchTransformedBilinear<BlendTransformedBilinear>,         // ARGB8565_Premultiplied
1721         fetchTransformedBilinear<BlendTransformedBilinear>,         // RGB666
1722         fetchTransformedBilinear<BlendTransformedBilinear>,         // ARGB6666_Premultiplied
1723         fetchTransformedBilinear<BlendTransformedBilinear>,         // RGB555
1724         fetchTransformedBilinear<BlendTransformedBilinear>,         // ARGB8555_Premultiplied
1725         fetchTransformedBilinear<BlendTransformedBilinear>,         // RGB888
1726         fetchTransformedBilinear<BlendTransformedBilinear>,         // RGB444
1727         fetchTransformedBilinear<BlendTransformedBilinear>          // ARGB4444_Premultiplied
1728     },
1729     {
1730         0, // BilinearTiled
1731         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // Mono
1732         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // MonoLsb
1733         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // Indexed8
1734         fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled>,    // RGB32
1735         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // ARGB32
1736         fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled>,    // ARGB32_Premultiplied
1737         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // RGB16
1738         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // ARGB8565_Premultiplied
1739         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // RGB666
1740         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // ARGB6666_Premultiplied
1741         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // RGB555
1742         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // ARGB8555_Premultiplied
1743         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // RGB888
1744         fetchTransformedBilinear<BlendTransformedBilinearTiled>,            // RGB444
1745         fetchTransformedBilinear<BlendTransformedBilinearTiled>             // ARGB4444_Premultiplied
1746     },
1747 };
1748
1749 #define FIXPT_BITS 8
1750 #define FIXPT_SIZE (1<<FIXPT_BITS)
1751
1752 static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
1753 {
1754     int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
1755     return data->colorTable[qt_gradient_clamp(data, ipos)];
1756 }
1757
1758 static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
1759 {
1760     v->dx = data->gradient.linear.end.x - data->gradient.linear.origin.x;
1761     v->dy = data->gradient.linear.end.y - data->gradient.linear.origin.y;
1762     v->l = v->dx * v->dx + v->dy * v->dy;
1763     v->off = 0;
1764     if (v->l != 0) {
1765         v->dx /= v->l;
1766         v->dy /= v->l;
1767         v->off = -v->dx * data->gradient.linear.origin.x - v->dy * data->gradient.linear.origin.y;
1768     }
1769 }
1770
1771 static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data,
1772                                                          int y, int x, int length)
1773 {
1774     const uint *b = buffer;
1775     qreal t, inc;
1776
1777     bool affine = true;
1778     qreal rx=0, ry=0;
1779     if (op->linear.l == 0) {
1780         t = inc = 0;
1781     } else {
1782         rx = data->m21 * (y + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx;
1783         ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(0.5)) + data->dy;
1784         t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off;
1785         inc = op->linear.dx * data->m11 + op->linear.dy * data->m12;
1786         affine = !data->m13 && !data->m23;
1787
1788         if (affine) {
1789             t *= (GRADIENT_STOPTABLE_SIZE - 1);
1790             inc *= (GRADIENT_STOPTABLE_SIZE - 1);
1791         }
1792     }
1793
1794     const uint *end = buffer + length;
1795     if (affine) {
1796         if (inc > qreal(-1e-5) && inc < qreal(1e-5)) {
1797             QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE)));
1798         } else {
1799             if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) &&
1800                 t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) {
1801                 // we can use fixed point math
1802                 int t_fixed = int(t * FIXPT_SIZE);
1803                 int inc_fixed = int(inc * FIXPT_SIZE);
1804                 while (buffer < end) {
1805                     *buffer = qt_gradient_pixel_fixed(&data->gradient, t_fixed);
1806                     t_fixed += inc_fixed;
1807                     ++buffer;
1808                 }
1809             } else {
1810                 // we have to fall back to float math
1811                 while (buffer < end) {
1812                     *buffer = qt_gradient_pixel(&data->gradient, t/GRADIENT_STOPTABLE_SIZE);
1813                     t += inc;
1814                     ++buffer;
1815                 }
1816             }
1817         }
1818     } else { // fall back to float math here as well
1819         qreal rw = data->m23 * (y + qreal(0.5)) + data->m13 * (x + qreal(0.5)) + data->m33;
1820         while (buffer < end) {
1821             qreal x = rx/rw;
1822             qreal y = ry/rw;
1823             t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off;
1824
1825             *buffer = qt_gradient_pixel(&data->gradient, t);
1826             rx += data->m11;
1827             ry += data->m12;
1828             rw += data->m13;
1829             if (!rw) {
1830                 rw += data->m13;
1831             }
1832             ++buffer;
1833         }
1834     }
1835
1836     return b;
1837 }
1838
1839 static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
1840 {
1841     v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x;
1842     v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y;
1843
1844     v->dr = data->gradient.radial.center.radius - data->gradient.radial.focal.radius;
1845     v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius;
1846
1847     v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy;
1848     v->inv2a = 1 / (2 * v->a);
1849
1850     v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0;
1851 }
1852
1853 class RadialFetchPlain
1854 {
1855 public:
1856     static inline void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det,
1857                              qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b)
1858     {
1859         if (op->radial.extended) {
1860             while (buffer < end) {
1861                 quint32 result = 0;
1862                 if (det >= 0) {
1863                     qreal w = qSqrt(det) - b;
1864                     if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0)
1865                         result = qt_gradient_pixel(&data->gradient, w);
1866                 }
1867
1868                 *buffer = result;
1869
1870                 det += delta_det;
1871                 delta_det += delta_delta_det;
1872                 b += delta_b;
1873
1874                 ++buffer;
1875             }
1876         } else {
1877             while (buffer < end) {
1878                 *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b);
1879
1880                 det += delta_det;
1881                 delta_det += delta_delta_det;
1882                 b += delta_b;
1883             }
1884         }
1885     }
1886 };
1887
1888 const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data,
1889                                                         int y, int x, int length)
1890 {
1891     return qt_fetch_radial_gradient_template<RadialFetchPlain>(buffer, op, data, y, x, length);
1892 }
1893
1894 static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain;
1895
1896 static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data,
1897                                                           int y, int x, int length)
1898 {
1899     const uint *b = buffer;
1900     qreal rx = data->m21 * (y + qreal(0.5))
1901                + data->dx + data->m11 * (x + qreal(0.5));
1902     qreal ry = data->m22 * (y + qreal(0.5))
1903                + data->dy + data->m12 * (x + qreal(0.5));
1904     bool affine = !data->m13 && !data->m23;
1905
1906     const uint *end = buffer + length;
1907     if (affine) {
1908         rx -= data->gradient.conical.center.x;
1909         ry -= data->gradient.conical.center.y;
1910         while (buffer < end) {
1911             qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle;
1912
1913             *buffer = qt_gradient_pixel(&data->gradient, 1 - angle / (2*Q_PI));
1914
1915             rx += data->m11;
1916             ry += data->m12;
1917             ++buffer;
1918         }
1919     } else {
1920         qreal rw = data->m23 * (y + qreal(0.5))
1921                    + data->m33 + data->m13 * (x + qreal(0.5));
1922         if (!rw)
1923             rw = 1;
1924         while (buffer < end) {
1925             qreal angle = qAtan2(ry/rw - data->gradient.conical.center.x,
1926                                 rx/rw - data->gradient.conical.center.y)
1927                           + data->gradient.conical.angle;
1928
1929             *buffer = qt_gradient_pixel(&data->gradient, 1. - angle / (2*Q_PI));
1930
1931             rx += data->m11;
1932             ry += data->m12;
1933             rw += data->m13;
1934             if (!rw) {
1935                 rw += data->m13;
1936             }
1937             ++buffer;
1938         }
1939     }
1940     return b;
1941 }
1942
1943 #if defined(Q_CC_RVCT)
1944 // Force ARM code generation for comp_func_* -methods
1945 #  pragma push
1946 #  pragma arm
1947 #  if defined(Q_PROCESSOR_ARM_V6)
1948 static __forceinline void preload(const uint *start)
1949 {
1950     asm( "pld [start]" );
1951 }
1952 static const uint L2CacheLineLength = 32;
1953 static const uint L2CacheLineLengthInInts = L2CacheLineLength/sizeof(uint);
1954 #    define PRELOAD_INIT(x) preload(x);
1955 #    define PRELOAD_INIT2(x,y) PRELOAD_INIT(x) PRELOAD_INIT(y)
1956 #    define PRELOAD_COND(x) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts);
1957 // Two consecutive preloads stall, so space them out a bit by using different modulus.
1958 #    define PRELOAD_COND2(x,y) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); \
1959          if (((uint)&y[i])%L2CacheLineLength == 16) preload(&y[i] + L2CacheLineLengthInInts);
1960 #  endif // Q_PROCESSOR_ARM_V6
1961 #endif // Q_CC_RVCT
1962
1963 #if !defined(Q_CC_RVCT) || !defined(Q_PROCESSOR_ARM_V6)
1964 #    define PRELOAD_INIT(x)
1965 #    define PRELOAD_INIT2(x,y)
1966 #    define PRELOAD_COND(x)
1967 #    define PRELOAD_COND2(x,y)
1968 #endif
1969
1970 /* The constant alpha factor describes an alpha factor that gets applied
1971    to the result of the composition operation combining it with the destination.
1972
1973    The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1.
1974    we get the unmodified operation
1975
1976    result = src op dest
1977    dest = result * const_alpha + dest * (1. - const_alpha)
1978
1979    This means that in the comments below, the first line is the const_alpha==255 case, the
1980    second line the general one.
1981
1982    In the lines below:
1983    s == src, sa == alpha(src), sia = 1 - alpha(src)
1984    d == dest, da == alpha(dest), dia = 1 - alpha(dest)
1985    ca = const_alpha, cia = 1 - const_alpha
1986
1987    The methods exist in two variants. One where we have a constant source, the other
1988    where the source is an array of pixels.
1989 */
1990
1991 /*
1992   result = 0
1993   d = d * cia
1994 */
1995 #define comp_func_Clear_impl(dest, length, const_alpha)\
1996 {\
1997     if (const_alpha == 255) {\
1998         QT_MEMFILL_UINT(dest, length, 0);\
1999     } else {\
2000         int ialpha = 255 - const_alpha;\
2001         PRELOAD_INIT(dest)\
2002         for (int i = 0; i < length; ++i) {\
2003             PRELOAD_COND(dest)\
2004             dest[i] = BYTE_MUL(dest[i], ialpha);\
2005         }\
2006     }\
2007 }
2008
2009 void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
2010 {
2011     comp_func_Clear_impl(dest, length, const_alpha);
2012 }
2013
2014 void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
2015 {
2016     comp_func_Clear_impl(dest, length, const_alpha);
2017 }
2018
2019 /*
2020   result = s
2021   dest = s * ca + d * cia
2022 */
2023 void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha)
2024 {
2025     if (const_alpha == 255) {
2026         QT_MEMFILL_UINT(dest, length, color);
2027     } else {
2028         int ialpha = 255 - const_alpha;
2029         color = BYTE_MUL(color, const_alpha);
2030         PRELOAD_INIT(dest)
2031         for (int i = 0; i < length; ++i) {
2032             PRELOAD_COND(dest)
2033             dest[i] = color + BYTE_MUL(dest[i], ialpha);
2034         }
2035     }
2036 }
2037
2038 void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2039 {
2040     if (const_alpha == 255) {
2041         ::memcpy(dest, src, length * sizeof(uint));
2042     } else {
2043         int ialpha = 255 - const_alpha;
2044         PRELOAD_INIT2(dest, src)
2045         for (int i = 0; i < length; ++i) {
2046             PRELOAD_COND2(dest, src)
2047             dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha);
2048         }
2049     }
2050 }
2051
2052 void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
2053 {
2054 }
2055
2056 void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint)
2057 {
2058 }
2059
2060 /*
2061   result = s + d * sia
2062   dest = (s + d * sia) * ca + d * cia
2063        = s * ca + d * (sia * ca + cia)
2064        = s * ca + d * (1 - sa*ca)
2065 */
2066 void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha)
2067 {
2068     if ((const_alpha & qAlpha(color)) == 255) {
2069         QT_MEMFILL_UINT(dest, length, color);
2070     } else {
2071         if (const_alpha != 255)
2072             color = BYTE_MUL(color, const_alpha);
2073         PRELOAD_INIT(dest)
2074         for (int i = 0; i < length; ++i) {
2075             PRELOAD_COND(dest)
2076             dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color));
2077         }
2078     }
2079 }
2080
2081 void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2082 {
2083     PRELOAD_INIT2(dest, src)
2084     if (const_alpha == 255) {
2085         for (int i = 0; i < length; ++i) {
2086             PRELOAD_COND2(dest, src)
2087             uint s = src[i];
2088             if (s >= 0xff000000)
2089                 dest[i] = s;
2090             else if (s != 0)
2091                 dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
2092         }
2093     } else {
2094         for (int i = 0; i < length; ++i) {
2095             PRELOAD_COND2(dest, src)
2096             uint s = BYTE_MUL(src[i], const_alpha);
2097             dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
2098         }
2099     }
2100 }
2101
2102 /*
2103   result = d + s * dia
2104   dest = (d + s * dia) * ca + d * cia
2105        = d + s * dia * ca
2106 */
2107 void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha)
2108 {
2109     if (const_alpha != 255)
2110         color = BYTE_MUL(color, const_alpha);
2111     PRELOAD_INIT(dest)
2112     for (int i = 0; i < length; ++i) {
2113         PRELOAD_COND(dest)
2114         uint d = dest[i];
2115         dest[i] = d + BYTE_MUL(color, qAlpha(~d));
2116     }
2117 }
2118
2119 void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2120 {
2121     PRELOAD_INIT2(dest, src)
2122     if (const_alpha == 255) {
2123         for (int i = 0; i < length; ++i) {
2124             PRELOAD_COND2(dest, src)
2125             uint d = dest[i];
2126             dest[i] = d + BYTE_MUL(src[i], qAlpha(~d));
2127         }
2128     } else {
2129         for (int i = 0; i < length; ++i) {
2130             PRELOAD_COND2(dest, src)
2131             uint d = dest[i];
2132             uint s = BYTE_MUL(src[i], const_alpha);
2133             dest[i] = d + BYTE_MUL(s, qAlpha(~d));
2134         }
2135     }
2136 }
2137
2138 /*
2139   result = s * da
2140   dest = s * da * ca + d * cia
2141 */
2142 void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha)
2143 {
2144     PRELOAD_INIT(dest)
2145     if (const_alpha == 255) {
2146         for (int i = 0; i < length; ++i) {
2147             PRELOAD_COND(dest)
2148             dest[i] = BYTE_MUL(color, qAlpha(dest[i]));
2149         }
2150     } else {
2151         color = BYTE_MUL(color, const_alpha);
2152         uint cia = 255 - const_alpha;
2153         for (int i = 0; i < length; ++i) {
2154             PRELOAD_COND(dest)
2155             uint d = dest[i];
2156             dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia);
2157         }
2158     }
2159 }
2160
2161 void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2162 {
2163     PRELOAD_INIT2(dest, src)
2164     if (const_alpha == 255) {
2165         for (int i = 0; i < length; ++i) {
2166             PRELOAD_COND2(dest, src)
2167             dest[i] = BYTE_MUL(src[i], qAlpha(dest[i]));
2168         }
2169     } else {
2170         uint cia = 255 - const_alpha;
2171         for (int i = 0; i < length; ++i) {
2172             PRELOAD_COND2(dest, src)
2173             uint d = dest[i];
2174             uint s = BYTE_MUL(src[i], const_alpha);
2175             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia);
2176         }
2177     }
2178 }
2179
2180 /*
2181   result = d * sa
2182   dest = d * sa * ca + d * cia
2183        = d * (sa * ca + cia)
2184 */
2185 void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha)
2186 {
2187     uint a = qAlpha(color);
2188     if (const_alpha != 255) {
2189         a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
2190     }
2191     PRELOAD_INIT(dest)
2192     for (int i = 0; i < length; ++i) {
2193         PRELOAD_COND(dest)
2194         dest[i] = BYTE_MUL(dest[i], a);
2195     }
2196 }
2197
2198 void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2199 {
2200     PRELOAD_INIT2(dest, src)
2201     if (const_alpha == 255) {
2202         for (int i = 0; i < length; ++i) {
2203             PRELOAD_COND2(dest, src)
2204             dest[i] = BYTE_MUL(dest[i], qAlpha(src[i]));
2205         }
2206     } else {
2207         int cia = 255 - const_alpha;
2208         for (int i = 0; i < length; ++i) {
2209             PRELOAD_COND2(dest, src)
2210             uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia;
2211             dest[i] = BYTE_MUL(dest[i], a);
2212         }
2213     }
2214 }
2215
2216 /*
2217   result = s * dia
2218   dest = s * dia * ca + d * cia
2219 */
2220
2221 void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha)
2222 {
2223     PRELOAD_INIT(dest)
2224     if (const_alpha == 255) {
2225         for (int i = 0; i < length; ++i) {
2226             PRELOAD_COND(dest)
2227             dest[i] = BYTE_MUL(color, qAlpha(~dest[i]));
2228         }
2229     } else {
2230         color = BYTE_MUL(color, const_alpha);
2231         int cia = 255 - const_alpha;
2232         for (int i = 0; i < length; ++i) {
2233             PRELOAD_COND(dest)
2234             uint d = dest[i];
2235             dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia);
2236         }
2237     }
2238 }
2239
2240 void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2241 {
2242     PRELOAD_INIT2(dest, src)
2243     if (const_alpha == 255) {
2244         for (int i = 0; i < length; ++i) {
2245             PRELOAD_COND2(dest, src)
2246             dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i]));
2247         }
2248     } else {
2249         int cia = 255 - const_alpha;
2250         for (int i = 0; i < length; ++i) {
2251             PRELOAD_COND2(dest, src)
2252             uint s = BYTE_MUL(src[i], const_alpha);
2253             uint d = dest[i];
2254             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia);
2255         }
2256     }
2257 }
2258
2259 /*
2260   result = d * sia
2261   dest = d * sia * ca + d * cia
2262        = d * (sia * ca + cia)
2263 */
2264 void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha)
2265 {
2266     uint a = qAlpha(~color);
2267     if (const_alpha != 255)
2268         a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
2269     PRELOAD_INIT(dest)
2270     for (int i = 0; i < length; ++i) {
2271         PRELOAD_COND(dest)
2272         dest[i] = BYTE_MUL(dest[i], a);
2273     }
2274 }
2275
2276 void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2277 {
2278     PRELOAD_INIT2(dest, src)
2279     if (const_alpha == 255) {
2280         for (int i = 0; i < length; ++i) {
2281             PRELOAD_COND2(dest, src)
2282             dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i]));
2283         }
2284     } else {
2285         int cia = 255 - const_alpha;
2286         for (int i = 0; i < length; ++i) {
2287             PRELOAD_COND2(dest, src)
2288             uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia;
2289             dest[i] = BYTE_MUL(dest[i], sia);
2290         }
2291     }
2292 }
2293
2294 /*
2295   result = s*da + d*sia
2296   dest = s*da*ca + d*sia*ca + d *cia
2297        = s*ca * da + d * (sia*ca + cia)
2298        = s*ca * da + d * (1 - sa*ca)
2299 */
2300 void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha)
2301 {
2302     if (const_alpha != 255) {
2303         color = BYTE_MUL(color, const_alpha);
2304     }
2305     uint sia = qAlpha(~color);
2306     PRELOAD_INIT(dest)
2307     for (int i = 0; i < length; ++i) {
2308         PRELOAD_COND(dest)
2309         dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia);
2310     }
2311 }
2312
2313 void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2314 {
2315     PRELOAD_INIT2(dest, src)
2316     if (const_alpha == 255) {
2317         for (int i = 0; i < length; ++i) {
2318             PRELOAD_COND2(dest, src)
2319             uint s = src[i];
2320             uint d = dest[i];
2321             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
2322         }
2323     } else {
2324         for (int i = 0; i < length; ++i) {
2325             PRELOAD_COND2(dest, src)
2326             uint s = BYTE_MUL(src[i], const_alpha);
2327             uint d = dest[i];
2328             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
2329         }
2330     }
2331 }
2332
2333 /*
2334   result = d*sa + s*dia
2335   dest = d*sa*ca + s*dia*ca + d *cia
2336        = s*ca * dia + d * (sa*ca + cia)
2337 */
2338 void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha)
2339 {
2340     uint a = qAlpha(color);
2341     if (const_alpha != 255) {
2342         color = BYTE_MUL(color, const_alpha);
2343         a = qAlpha(color) + 255 - const_alpha;
2344     }
2345     PRELOAD_INIT(dest)
2346     for (int i = 0; i < length; ++i) {
2347         PRELOAD_COND(dest)
2348         uint d = dest[i];
2349         dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d));
2350     }
2351 }
2352
2353 void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2354 {
2355     PRELOAD_INIT2(dest, src)
2356     if (const_alpha == 255) {
2357         for (int i = 0; i < length; ++i) {
2358             PRELOAD_COND2(dest, src)
2359             uint s = src[i];
2360             uint d = dest[i];
2361             dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d));
2362         }
2363     } else {
2364         int cia = 255 - const_alpha;
2365         for (int i = 0; i < length; ++i) {
2366             PRELOAD_COND2(dest, src)
2367             uint s = BYTE_MUL(src[i], const_alpha);
2368             uint d = dest[i];
2369             uint a = qAlpha(s) + cia;
2370             dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d));
2371         }
2372     }
2373 }
2374
2375 /*
2376   result = d*sia + s*dia
2377   dest = d*sia*ca + s*dia*ca + d *cia
2378        = s*ca * dia + d * (sia*ca + cia)
2379        = s*ca * dia + d * (1 - sa*ca)
2380 */
2381 void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha)
2382 {
2383     if (const_alpha != 255)
2384         color = BYTE_MUL(color, const_alpha);
2385     uint sia = qAlpha(~color);
2386
2387     PRELOAD_INIT(dest)
2388     for (int i = 0; i < length; ++i) {
2389         PRELOAD_COND(dest)
2390         uint d = dest[i];
2391         dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia);
2392     }
2393 }
2394
2395 void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2396 {
2397     PRELOAD_INIT2(dest, src)
2398     if (const_alpha == 255) {
2399         for (int i = 0; i < length; ++i) {
2400             PRELOAD_COND2(dest, src)
2401             uint d = dest[i];
2402             uint s = src[i];
2403             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
2404         }
2405     } else {
2406         for (int i = 0; i < length; ++i) {
2407             PRELOAD_COND2(dest, src)
2408             uint d = dest[i];
2409             uint s = BYTE_MUL(src[i], const_alpha);
2410             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
2411         }
2412     }
2413 }
2414
2415 struct QFullCoverage {
2416     inline void store(uint *dest, const uint src) const
2417     {
2418         *dest = src;
2419     }
2420 };
2421
2422 struct QPartialCoverage {
2423     inline QPartialCoverage(uint const_alpha)
2424         : ca(const_alpha)
2425         , ica(255 - const_alpha)
2426     {
2427     }
2428
2429     inline void store(uint *dest, const uint src) const
2430     {
2431         *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
2432     }
2433
2434 private:
2435     const uint ca;
2436     const uint ica;
2437 };
2438
2439 static inline int mix_alpha(int da, int sa)
2440 {
2441     return 255 - ((255 - sa) * (255 - da) >> 8);
2442 }
2443
2444 /*
2445     Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
2446          = Sca + Dca
2447 */
2448 template <typename T>
2449 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage)
2450 {
2451     uint s = color;
2452
2453     PRELOAD_INIT(dest)
2454     for (int i = 0; i < length; ++i) {
2455         PRELOAD_COND(dest)
2456         uint d = dest[i];
2457         d = comp_func_Plus_one_pixel(d, s);
2458         coverage.store(&dest[i], d);
2459     }
2460 }
2461
2462 void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha)
2463 {
2464     if (const_alpha == 255)
2465         comp_func_solid_Plus_impl(dest, length, color, QFullCoverage());
2466     else
2467         comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha));
2468 }
2469
2470 template <typename T>
2471 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2472 {
2473     PRELOAD_INIT2(dest, src)
2474     for (int i = 0; i < length; ++i) {
2475         PRELOAD_COND2(dest, src)
2476         uint d = dest[i];
2477         uint s = src[i];
2478
2479         d = comp_func_Plus_one_pixel(d, s);
2480
2481         coverage.store(&dest[i], d);
2482     }
2483 }
2484
2485 void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2486 {
2487     if (const_alpha == 255)
2488         comp_func_Plus_impl(dest, src, length, QFullCoverage());
2489     else
2490         comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha));
2491 }
2492
2493 /*
2494     Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2495 */
2496 static inline int multiply_op(int dst, int src, int da, int sa)
2497 {
2498     return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa));
2499 }
2500
2501 template <typename T>
2502 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage)
2503 {
2504     int sa = qAlpha(color);
2505     int sr = qRed(color);
2506     int sg = qGreen(color);
2507     int sb = qBlue(color);
2508
2509     PRELOAD_INIT(dest)
2510     for (int i = 0; i < length; ++i) {
2511         PRELOAD_COND(dest)
2512         uint d = dest[i];
2513         int da = qAlpha(d);
2514
2515 #define OP(a, b) multiply_op(a, b, da, sa)
2516         int r = OP(  qRed(d), sr);
2517         int b = OP( qBlue(d), sb);
2518         int g = OP(qGreen(d), sg);
2519         int a = mix_alpha(da, sa);
2520 #undef OP
2521
2522         coverage.store(&dest[i], qRgba(r, g, b, a));
2523     }
2524 }
2525
2526 void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha)
2527 {
2528     if (const_alpha == 255)
2529         comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
2530     else
2531         comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
2532 }
2533
2534 template <typename T>
2535 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2536 {
2537     PRELOAD_INIT2(dest, src)
2538     for (int i = 0; i < length; ++i) {
2539         PRELOAD_COND2(dest, src)
2540         uint d = dest[i];
2541         uint s = src[i];
2542
2543         int da = qAlpha(d);
2544         int sa = qAlpha(s);
2545
2546 #define OP(a, b) multiply_op(a, b, da, sa)
2547         int r = OP(  qRed(d),   qRed(s));
2548         int b = OP( qBlue(d),  qBlue(s));
2549         int g = OP(qGreen(d), qGreen(s));
2550         int a = mix_alpha(da, sa);
2551 #undef OP
2552
2553         coverage.store(&dest[i], qRgba(r, g, b, a));
2554     }
2555 }
2556
2557 void QT_FASTCALL comp_func_Multiply(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2558 {
2559     if (const_alpha == 255)
2560         comp_func_Multiply_impl(dest, src, length, QFullCoverage());
2561     else
2562         comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
2563 }
2564
2565 /*
2566     Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2567          = Sca + Dca - Sca.Dca
2568 */
2569 template <typename T>
2570 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage)
2571 {
2572     int sa = qAlpha(color);
2573     int sr = qRed(color);
2574     int sg = qGreen(color);
2575     int sb = qBlue(color);
2576
2577     PRELOAD_INIT(dest)
2578     for (int i = 0; i < length; ++i) {
2579         PRELOAD_COND(dest)
2580         uint d = dest[i];
2581         int da = qAlpha(d);
2582
2583 #define OP(a, b) 255 - qt_div_255((255-a) * (255-b))
2584         int r = OP(  qRed(d), sr);
2585         int b = OP( qBlue(d), sb);
2586         int g = OP(qGreen(d), sg);
2587         int a = mix_alpha(da, sa);
2588 #undef OP
2589
2590         coverage.store(&dest[i], qRgba(r, g, b, a));
2591     }
2592 }
2593
2594 void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha)
2595 {
2596     if (const_alpha == 255)
2597         comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
2598     else
2599         comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
2600 }
2601
2602 template <typename T>
2603 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2604 {
2605     PRELOAD_INIT2(dest, src)
2606     for (int i = 0; i < length; ++i) {
2607         PRELOAD_COND2(dest, src)
2608         uint d = dest[i];
2609         uint s = src[i];
2610
2611         int da = qAlpha(d);
2612         int sa = qAlpha(s);
2613
2614 #define OP(a, b) 255 - (((255-a) * (255-b)) >> 8)
2615         int r = OP(  qRed(d),   qRed(s));
2616         int b = OP( qBlue(d),  qBlue(s));
2617         int g = OP(qGreen(d), qGreen(s));
2618         int a = mix_alpha(da, sa);
2619 #undef OP
2620
2621         coverage.store(&dest[i], qRgba(r, g, b, a));
2622     }
2623 }
2624
2625 void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha)
2626 {
2627     if (const_alpha == 255)
2628         comp_func_Screen_impl(dest, src, length, QFullCoverage());
2629     else
2630         comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
2631 }
2632
2633 /*
2634     if 2.Dca < Da
2635         Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2636     otherwise
2637         Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2638 */
2639 static inline int overlay_op(int dst, int src, int da, int sa)
2640 {
2641     const int temp = src * (255 - da) + dst * (255 - sa);
2642     if (2 * dst < da)
2643         return qt_div_255(2 * src * dst + temp);
2644     else
2645         return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2646 }
2647
2648 template <typename T>
2649 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage)
2650 {
2651     int sa = qAlpha(color);
2652     int sr = qRed(color);
2653     int sg = qGreen(color);
2654     int sb = qBlue(color);
2655
2656     PRELOAD_INIT(dest)
2657     for (int i = 0; i < length; ++i) {
2658         PRELOAD_COND(dest)
2659         uint d = dest[i];
2660         int da = qAlpha(d);
2661
2662 #define OP(a, b) overlay_op(a, b, da, sa)
2663         int r = OP(  qRed(d), sr);
2664         int b = OP( qBlue(d), sb);
2665         int g = OP(qGreen(d), sg);
2666         int a = mix_alpha(da, sa);
2667 #undef OP
2668
2669         coverage.store(&dest[i], qRgba(r, g, b, a));
2670     }
2671 }
2672
2673 void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha)
2674 {
2675     if (const_alpha == 255)
2676         comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
2677     else
2678         comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
2679 }
2680
2681 template <typename T>
2682 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2683 {
2684     PRELOAD_INIT2(dest, src)
2685     for (int i = 0; i < length; ++i) {
2686         PRELOAD_COND2(dest, src)
2687         uint d = dest[i];
2688         uint s = src[i];
2689
2690         int da = qAlpha(d);
2691         int sa = qAlpha(s);
2692
2693 #define OP(a, b) overlay_op(a, b, da, sa)
2694         int r = OP(  qRed(d),   qRed(s));
2695         int b = OP( qBlue(d),  qBlue(s));
2696         int g = OP(qGreen(d), qGreen(s));
2697         int a = mix_alpha(da, sa);
2698 #undef OP
2699
2700         coverage.store(&dest[i], qRgba(r, g, b, a));
2701     }
2702 }
2703
2704 void QT_FASTCALL comp_func_Overlay(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2705 {
2706     if (const_alpha == 255)
2707         comp_func_Overlay_impl(dest, src, length, QFullCoverage());
2708     else
2709         comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
2710 }
2711
2712 /*
2713     Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2714     Da'  = Sa + Da - Sa.Da
2715 */
2716 static inline int darken_op(int dst, int src, int da, int sa)
2717 {
2718     return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2719 }
2720
2721 template <typename T>
2722 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage)
2723 {
2724     int sa = qAlpha(color);
2725     int sr = qRed(color);
2726     int sg = qGreen(color);
2727     int sb = qBlue(color);
2728
2729     PRELOAD_INIT(dest)
2730     for (int i = 0; i < length; ++i) {
2731         PRELOAD_COND(dest)
2732         uint d = dest[i];
2733         int da = qAlpha(d);
2734
2735 #define OP(a, b) darken_op(a, b, da, sa)
2736         int r =  OP(  qRed(d), sr);
2737         int b =  OP( qBlue(d), sb);
2738         int g =  OP(qGreen(d), sg);
2739         int a = mix_alpha(da, sa);
2740 #undef OP
2741
2742         coverage.store(&dest[i], qRgba(r, g, b, a));
2743     }
2744 }
2745
2746 void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha)
2747 {
2748     if (const_alpha == 255)
2749         comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
2750     else
2751         comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
2752 }
2753
2754 template <typename T>
2755 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2756 {
2757     PRELOAD_INIT2(dest, src)
2758     for (int i = 0; i < length; ++i) {
2759         PRELOAD_COND2(dest, src)
2760         uint d = dest[i];
2761         uint s = src[i];
2762
2763         int da = qAlpha(d);
2764         int sa = qAlpha(s);
2765
2766 #define OP(a, b) darken_op(a, b, da, sa)
2767         int r = OP(  qRed(d),   qRed(s));
2768         int b = OP( qBlue(d),  qBlue(s));
2769         int g = OP(qGreen(d), qGreen(s));
2770         int a = mix_alpha(da, sa);
2771 #undef OP
2772
2773         coverage.store(&dest[i], qRgba(r, g, b, a));
2774     }
2775 }
2776
2777 void QT_FASTCALL comp_func_Darken(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2778 {
2779     if (const_alpha == 255)
2780         comp_func_Darken_impl(dest, src, length, QFullCoverage());
2781     else
2782         comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
2783 }
2784
2785 /*
2786    Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2787    Da'  = Sa + Da - Sa.Da
2788 */
2789 static inline int lighten_op(int dst, int src, int da, int sa)
2790 {
2791     return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2792 }
2793
2794 template <typename T>
2795 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage)
2796 {
2797     int sa = qAlpha(color);
2798     int sr = qRed(color);
2799     int sg = qGreen(color);
2800     int sb = qBlue(color);
2801
2802     PRELOAD_INIT(dest)
2803     for (int i = 0; i < length; ++i) {
2804         PRELOAD_COND(dest)
2805         uint d = dest[i];
2806         int da = qAlpha(d);
2807
2808 #define OP(a, b) lighten_op(a, b, da, sa)
2809         int r =  OP(  qRed(d), sr);
2810         int b =  OP( qBlue(d), sb);
2811         int g =  OP(qGreen(d), sg);
2812         int a = mix_alpha(da, sa);
2813 #undef OP
2814
2815         coverage.store(&dest[i], qRgba(r, g, b, a));
2816     }
2817 }
2818
2819 void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha)
2820 {
2821     if (const_alpha == 255)
2822         comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
2823     else
2824         comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
2825 }
2826
2827 template <typename T>
2828 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2829 {
2830     PRELOAD_INIT2(dest, src)
2831     for (int i = 0; i < length; ++i) {
2832         PRELOAD_COND2(dest, src)
2833         uint d = dest[i];
2834         uint s = src[i];
2835
2836         int da = qAlpha(d);
2837         int sa = qAlpha(s);
2838
2839 #define OP(a, b) lighten_op(a, b, da, sa)
2840         int r = OP(  qRed(d),   qRed(s));
2841         int b = OP( qBlue(d),  qBlue(s));
2842         int g = OP(qGreen(d), qGreen(s));
2843         int a = mix_alpha(da, sa);
2844 #undef OP
2845
2846         coverage.store(&dest[i], qRgba(r, g, b, a));
2847     }
2848 }
2849
2850 void QT_FASTCALL comp_func_Lighten(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2851 {
2852     if (const_alpha == 255)
2853         comp_func_Lighten_impl(dest, src, length, QFullCoverage());
2854     else
2855         comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
2856 }
2857
2858 /*
2859    if Sca.Da + Dca.Sa >= Sa.Da
2860        Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
2861    otherwise
2862        Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2863 */
2864 static inline int color_dodge_op(int dst, int src, int da, int sa)
2865 {
2866     const int sa_da = sa * da;
2867     const int dst_sa = dst * sa;
2868     const int src_da = src * da;
2869
2870     const int temp = src * (255 - da) + dst * (255 - sa);
2871     if (src_da + dst_sa >= sa_da)
2872         return qt_div_255(sa_da + temp);
2873     else
2874         return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp);
2875 }
2876
2877 template <typename T>
2878 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage)
2879 {
2880     int sa = qAlpha(color);
2881     int sr = qRed(color);
2882     int sg = qGreen(color);
2883     int sb = qBlue(color);
2884
2885     PRELOAD_INIT(dest)
2886     for (int i = 0; i < length; ++i) {
2887         PRELOAD_COND(dest)
2888         uint d = dest[i];
2889         int da = qAlpha(d);
2890
2891 #define OP(a,b) color_dodge_op(a, b, da, sa)
2892         int r = OP(  qRed(d), sr);
2893         int b = OP( qBlue(d), sb);
2894         int g = OP(qGreen(d), sg);
2895         int a = mix_alpha(da, sa);
2896 #undef OP
2897
2898         coverage.store(&dest[i], qRgba(r, g, b, a));
2899     }
2900 }
2901
2902 void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha)
2903 {
2904     if (const_alpha == 255)
2905         comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
2906     else
2907         comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
2908 }
2909
2910 template <typename T>
2911 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2912 {
2913     PRELOAD_INIT2(dest, src)
2914     for (int i = 0; i < length; ++i) {
2915         PRELOAD_COND2(dest, src)
2916         uint d = dest[i];
2917         uint s = src[i];
2918
2919         int da = qAlpha(d);
2920         int sa = qAlpha(s);
2921
2922 #define OP(a, b) color_dodge_op(a, b, da, sa)
2923         int r = OP(  qRed(d),   qRed(s));
2924         int b = OP( qBlue(d),  qBlue(s));
2925         int g = OP(qGreen(d), qGreen(s));
2926         int a = mix_alpha(da, sa);
2927 #undef OP
2928
2929         coverage.store(&dest[i], qRgba(r, g, b, a));
2930     }
2931 }
2932
2933 void QT_FASTCALL comp_func_ColorDodge(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2934 {
2935     if (const_alpha == 255)
2936         comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
2937     else
2938         comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
2939 }
2940
2941 /*
2942    if Sca.Da + Dca.Sa <= Sa.Da
2943        Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
2944    otherwise
2945        Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
2946 */
2947 static inline int color_burn_op(int dst, int src, int da, int sa)
2948 {
2949     const int src_da = src * da;
2950     const int dst_sa = dst * sa;
2951     const int sa_da = sa * da;
2952
2953     const int temp = src * (255 - da) + dst * (255 - sa);
2954
2955     if (src == 0 || src_da + dst_sa <= sa_da)
2956         return qt_div_255(temp);
2957     return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp);
2958 }
2959
2960 template <typename T>
2961 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage)
2962 {
2963     int sa = qAlpha(color);
2964     int sr = qRed(color);
2965     int sg = qGreen(color);
2966     int sb = qBlue(color);
2967
2968     PRELOAD_INIT(dest)
2969     for (int i = 0; i < length; ++i) {
2970         PRELOAD_COND(dest)
2971         uint d = dest[i];
2972         int da = qAlpha(d);
2973
2974 #define OP(a, b) color_burn_op(a, b, da, sa)
2975         int r =  OP(  qRed(d), sr);
2976         int b =  OP( qBlue(d), sb);
2977         int g =  OP(qGreen(d), sg);
2978         int a = mix_alpha(da, sa);
2979 #undef OP
2980
2981         coverage.store(&dest[i], qRgba(r, g, b, a));
2982     }
2983 }
2984
2985 void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha)
2986 {
2987     if (const_alpha == 255)
2988         comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
2989     else
2990         comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
2991 }
2992
2993 template <typename T>
2994 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2995 {
2996     PRELOAD_INIT2(dest, src)
2997     for (int i = 0; i < length; ++i) {
2998         PRELOAD_COND2(dest, src)
2999         uint d = dest[i];
3000         uint s = src[i];
3001
3002         int da = qAlpha(d);
3003         int sa = qAlpha(s);
3004
3005 #define OP(a, b) color_burn_op(a, b, da, sa)
3006         int r = OP(  qRed(d),   qRed(s));
3007         int b = OP( qBlue(d),  qBlue(s));
3008         int g = OP(qGreen(d), qGreen(s));
3009         int a = mix_alpha(da, sa);
3010 #undef OP
3011
3012         coverage.store(&dest[i], qRgba(r, g, b, a));
3013     }
3014 }
3015
3016 void QT_FASTCALL comp_func_ColorBurn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
3017 {
3018     if (const_alpha == 255)
3019         comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
3020     else
3021         comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
3022 }
3023
3024 /*
3025     if 2.Sca < Sa
3026         Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
3027     otherwise
3028         Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
3029 */
3030 static inline uint hardlight_op(int dst, int src, int da, int sa)
3031 {
3032     const uint temp = src * (255 - da) + dst * (255 - sa);
3033
3034     if (2 * src < sa)
3035         return qt_div_255(2 * src * dst + temp);
3036     else
3037         return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
3038 }
3039
3040 template <typename T>
3041 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage)
3042 {
3043     int sa = qAlpha(color);
3044     int sr = qRed(color);
3045     int sg = qGreen(color);
3046     int sb = qBlue(color);
3047
3048     PRELOAD_INIT(dest)
3049     for (int i = 0; i < length; ++i) {
3050         PRELOAD_COND(dest)
3051         uint d = dest[i];
3052         int da = qAlpha(d);
3053
3054 #define OP(a, b) hardlight_op(a, b, da, sa)
3055         int r =  OP(  qRed(d), sr);
3056         int b =  OP( qBlue(d), sb);
3057         int g =  OP(qGreen(d), sg);
3058         int a = mix_alpha(da, sa);
3059 #undef OP
3060
3061         coverage.store(&dest[i], qRgba(r, g, b, a));
3062     }
3063 }
3064
3065 void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha)
3066 {
3067     if (const_alpha == 255)
3068         comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
3069     else
3070         comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
3071 }
3072
3073 template <typename T>
3074 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
3075 {
3076     PRELOAD_INIT2(dest, src)
3077     for (int i = 0; i < length; ++i) {
3078         PRELOAD_COND2(dest, src)
3079         uint d = dest[i];
3080         uint s = src[i];
3081
3082         int da = qAlpha(d);
3083         int sa = qAlpha(s);
3084
3085 #define OP(a, b) hardlight_op(a, b, da, sa)
3086         int r = OP(  qRed(d),   qRed(s));
3087         int b = OP( qBlue(d),  qBlue(s));
3088         int g = OP(qGreen(d), qGreen(s));
3089         int a = mix_alpha(da, sa);
3090 #undef OP
3091
3092         coverage.store(&dest[i], qRgba(r, g, b, a));
3093     }
3094 }
3095
3096 void QT_FASTCALL comp_func_HardLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
3097 {
3098     if (const_alpha == 255)
3099         comp_func_HardLight_impl(dest, src, length, QFullCoverage());
3100     else
3101         comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
3102 }
3103
3104 /*
3105     if 2.Sca <= Sa
3106         Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
3107     otherwise if 2.Sca > Sa and 4.Dca <= Da
3108         Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
3109     otherwise if 2.Sca > Sa and 4.Dca > Da
3110         Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
3111 */
3112 static inline int soft_light_op(int dst, int src, int da, int sa)
3113 {
3114     const int src2 = src << 1;
3115     const int dst_np = da != 0 ? (255 * dst) / da : 0;
3116     const int temp = (src * (255 - da) + dst * (255 - sa)) * 255;
3117
3118     if (src2 < sa)
3119         return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025;
3120     else if (4 * dst <= da)
3121         return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025;
3122     else {
3123 #   ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
3124         return (dst * sa * 255 + da * (src2 - sa) * (qIntSqrtInt(dst_np * 255) - dst_np) + temp) / 65025;
3125 #   else
3126         return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025;
3127 #   endif
3128     }
3129 }
3130
3131 template <typename T>
3132 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage)
3133 {
3134     int sa = qAlpha(color);
3135     int sr = qRed(color);
3136     int sg = qGreen(color);
3137     int sb = qBlue(color);
3138
3139     PRELOAD_INIT(dest)
3140     for (int i = 0; i < length; ++i) {
3141         PRELOAD_COND(dest)
3142         uint d = dest[i];
3143         int da = qAlpha(d);
3144
3145 #define OP(a, b) soft_light_op(a, b, da, sa)
3146         int r =  OP(  qRed(d), sr);
3147         int b =  OP( qBlue(d), sb);
3148         int g =  OP(qGreen(d), sg);
3149         int a = mix_alpha(da, sa);
3150 #undef OP
3151
3152         coverage.store(&dest[i], qRgba(r, g, b, a));
3153     }
3154 }
3155
3156 void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
3157 {
3158     if (const_alpha == 255)
3159         comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
3160     else
3161         comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
3162 }
3163
3164 template <typename T>
3165 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
3166 {
3167     PRELOAD_INIT2(dest, src)
3168     for (int i = 0; i < length; ++i) {
3169         PRELOAD_COND2(dest, src)
3170         uint d = dest[i];
3171         uint s = src[i];
3172
3173         int da = qAlpha(d);
3174         int sa = qAlpha(s);
3175
3176 #define OP(a, b) soft_light_op(a, b, da, sa)
3177         int r = OP(  qRed(d),   qRed(s));
3178         int b = OP( qBlue(d),  qBlue(s));
3179         int g = OP(qGreen(d), qGreen(s));
3180         int a = mix_alpha(da, sa);
3181 #undef OP
3182
3183         coverage.store(&dest[i], qRgba(r, g, b, a));
3184     }
3185 }
3186
3187 void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
3188 {
3189     if (const_alpha == 255)
3190         comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
3191     else
3192         comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
3193 }
3194
3195 /*
3196    Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
3197         = Sca + Dca - 2.min(Sca.Da, Dca.Sa)
3198 */
3199 static inline int difference_op(int dst, int src, int da, int sa)
3200 {
3201     return src + dst - qt_div_255(2 * qMin(src * da, dst * sa));
3202 }
3203
3204 template <typename T>
3205 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage)
3206 {
3207     int sa = qAlpha(color);
3208     int sr = qRed(color);
3209     int sg = qGreen(color);
3210     int sb = qBlue(color);
3211
3212     PRELOAD_INIT(dest)
3213     for (int i = 0; i < length; ++i) {
3214         PRELOAD_COND(dest)
3215         uint d = dest[i];
3216         int da = qAlpha(d);
3217
3218 #define OP(a, b) difference_op(a, b, da, sa)
3219         int r =  OP(  qRed(d), sr);
3220         int b =  OP( qBlue(d), sb);
3221         int g =  OP(qGreen(d), sg);
3222         int a = mix_alpha(da, sa);
3223 #undef OP
3224
3225         coverage.store(&dest[i], qRgba(r, g, b, a));
3226     }
3227 }
3228
3229 void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha)
3230 {
3231     if (const_alpha == 255)
3232         comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
3233     else
3234         comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
3235 }
3236
3237 template <typename T>
3238 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
3239 {
3240     PRELOAD_INIT2(dest, src)
3241     for (int i = 0; i < length; ++i) {
3242         PRELOAD_COND2(dest, src)
3243         uint d = dest[i];
3244         uint s = src[i];
3245
3246         int da = qAlpha(d);
3247         int sa = qAlpha(s);
3248
3249 #define OP(a, b) difference_op(a, b, da, sa)
3250         int r = OP(  qRed(d),   qRed(s));
3251         int b = OP( qBlue(d),  qBlue(s));
3252         int g = OP(qGreen(d), qGreen(s));
3253         int a = mix_alpha(da, sa);
3254 #undef OP
3255
3256         coverage.store(&dest[i], qRgba(r, g, b, a));
3257     }
3258 }
3259
3260 void QT_FASTCALL comp_func_Difference(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
3261 {
3262     if (const_alpha == 255)
3263         comp_func_Difference_impl(dest, src, length, QFullCoverage());
3264     else
3265         comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
3266 }
3267
3268 /*
3269     Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
3270 */
3271 template <typename T>
3272 Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage)
3273 {
3274     int sa = qAlpha(color);
3275     int sr = qRed(color);
3276     int sg = qGreen(color);
3277     int sb = qBlue(color);
3278
3279     PRELOAD_INIT(dest)
3280     for (int i = 0; i < length; ++i) {
3281         PRELOAD_COND(dest)
3282         uint d = dest[i];
3283         int da = qAlpha(d);
3284
3285 #define OP(a, b) (a + b - qt_div_255(2*(a*b)))
3286         int r =  OP(  qRed(d), sr);
3287         int b =  OP( qBlue(d), sb);
3288         int g =  OP(qGreen(d), sg);
3289         int a = mix_alpha(da, sa);
3290 #undef OP
3291
3292         coverage.store(&dest[i], qRgba(r, g, b, a));
3293     }
3294 }
3295
3296 void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha)
3297 {
3298     if (const_alpha == 255)
3299         comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage());
3300     else
3301         comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
3302 }
3303
3304 template <typename T>
3305 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
3306 {
3307     PRELOAD_INIT2(dest, src)
3308     for (int i = 0; i < length; ++i) {
3309         PRELOAD_COND2(dest, src)
3310         uint d = dest[i];
3311         uint s = src[i];
3312
3313         int da = qAlpha(d);
3314         int sa = qAlpha(s);
3315
3316 #define OP(a, b) (a + b - ((a*b) >> 7))
3317         int r = OP(  qRed(d),   qRed(s));
3318         int b = OP( qBlue(d),  qBlue(s));
3319         int g = OP(qGreen(d), qGreen(s));
3320         int a = mix_alpha(da, sa);
3321 #undef OP
3322
3323         coverage.store(&dest[i], qRgba(r, g, b, a));
3324     }
3325 }
3326
3327 void QT_FASTCALL comp_func_Exclusion(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
3328 {
3329     if (const_alpha == 255)
3330         comp_func_Exclusion_impl(dest, src, length, QFullCoverage());
3331     else
3332         comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
3333 }
3334
3335 #if defined(Q_CC_RVCT)
3336 // Restore pragma state from previous #pragma arm
3337 #  pragma pop
3338 #endif
3339
3340 void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest,
3341                                                     int length,
3342                                                     uint color,
3343                                                     uint const_alpha)
3344 {
3345     Q_UNUSED(const_alpha);
3346     while (length--)
3347         *dest++ |= color;
3348 }
3349
3350 void QT_FASTCALL rasterop_SourceOrDestination(uint *Q_DECL_RESTRICT dest,
3351                                               const uint *Q_DECL_RESTRICT src,
3352                                               int length,
3353                                               uint const_alpha)
3354 {
3355     Q_UNUSED(const_alpha);
3356     while (length--)
3357         *dest++ |= *src++;
3358 }
3359
3360 void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest,
3361                                                      int length,
3362                                                      uint color,
3363                                                      uint const_alpha)
3364 {
3365     Q_UNUSED(const_alpha);
3366     color |= 0xff000000;
3367     while (length--)
3368         *dest++ &= color;
3369 }
3370
3371 void QT_FASTCALL rasterop_SourceAndDestination(uint *Q_DECL_RESTRICT dest,
3372                                                const uint *Q_DECL_RESTRICT src,
3373                                                int length,
3374                                                uint const_alpha)
3375 {
3376     Q_UNUSED(const_alpha);
3377     while (length--) {
3378         *dest = (*src & *dest) | 0xff000000;
3379         ++dest; ++src;
3380     }
3381 }
3382
3383 void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest,
3384                                                      int length,
3385                                                      uint color,
3386                                                      uint const_alpha)
3387 {
3388     Q_UNUSED(const_alpha);
3389     color &= 0x00ffffff;
3390     while (length--)
3391         *dest++ ^= color;
3392 }
3393
3394 void QT_FASTCALL rasterop_SourceXorDestination(uint *Q_DECL_RESTRICT dest,
3395                                                const uint *Q_DECL_RESTRICT src,
3396                                                int length,
3397                                                uint const_alpha)
3398 {
3399     Q_UNUSED(const_alpha);
3400     while (length--) {
3401         *dest = (*src ^ *dest) | 0xff000000;
3402         ++dest; ++src;
3403     }
3404 }
3405
3406 void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest,
3407                                                            int length,
3408                                                            uint color,
3409                                                            uint const_alpha)
3410 {
3411     Q_UNUSED(const_alpha);
3412     color = ~color;
3413     while (length--) {
3414         *dest = (color & ~(*dest)) | 0xff000000;
3415         ++dest;
3416     }
3417 }
3418
3419 void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *Q_DECL_RESTRICT dest,
3420                                                      const uint *Q_DECL_RESTRICT src,
3421                                                      int length,
3422                                                      uint const_alpha)
3423 {
3424     Q_UNUSED(const_alpha);
3425     while (length--) {
3426         *dest = (~(*src) & ~(*dest)) | 0xff000000;
3427         ++dest; ++src;
3428     }
3429 }
3430
3431 void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest,
3432                                                           int length,
3433                                                           uint color,
3434                                                           uint const_alpha)
3435 {
3436     Q_UNUSED(const_alpha);
3437     color = ~color | 0xff000000;
3438     while (length--) {
3439         *dest = color | ~(*dest);
3440         ++dest;
3441     }
3442 }
3443
3444 void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *Q_DECL_RESTRICT dest,
3445                                                     const uint *Q_DECL_RESTRICT src,
3446                                                     int length,
3447                                                     uint const_alpha)
3448 {
3449     Q_UNUSED(const_alpha);
3450     while (length--) {
3451         *dest = ~(*src) | ~(*dest) | 0xff000000;
3452         ++dest; ++src;
3453     }
3454 }
3455
3456 void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest,
3457                                                         int length,
3458                                                         uint color,
3459                                                         uint const_alpha)
3460 {
3461     Q_UNUSED(const_alpha);
3462     color = ~color & 0x00ffffff;
3463     while (length--) {
3464         *dest = color ^ (*dest);
3465         ++dest;
3466     }
3467 }
3468
3469 void QT_FASTCALL rasterop_NotSourceXorDestination(uint *Q_DECL_RESTRICT dest,
3470                                                   const uint *Q_DECL_RESTRICT src,
3471                                                   int length,
3472                                                   uint const_alpha)
3473 {
3474     Q_UNUSED(const_alpha);
3475     while (length--) {
3476         *dest = ((~(*src)) ^ (*dest)) | 0xff000000;
3477         ++dest; ++src;
3478     }
3479 }
3480
3481 void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length,
3482                                           uint color, uint const_alpha)
3483 {
3484     Q_UNUSED(const_alpha);
3485     qt_memfill(dest, ~color | 0xff000000, length);
3486 }
3487
3488 void QT_FASTCALL rasterop_NotSource(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src,
3489                                     int length, uint const_alpha)
3490 {
3491     Q_UNUSED(const_alpha);
3492     while (length--)
3493         *dest++ = ~(*src++) | 0xff000000;
3494 }
3495
3496 void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest,
3497                                                         int length,
3498                                                         uint color,
3499                                                         uint const_alpha)
3500 {
3501     Q_UNUSED(const_alpha);
3502     color = ~color | 0xff000000;
3503     while (length--) {
3504         *dest = color & *dest;
3505         ++dest;
3506     }
3507 }
3508
3509 void QT_FASTCALL rasterop_NotSourceAndDestination(uint *Q_DECL_RESTRICT dest,
3510                                                   const uint *Q_DECL_RESTRICT src,
3511                                                   int length,
3512                                                   uint const_alpha)
3513 {
3514     Q_UNUSED(const_alpha);
3515     while (length--) {
3516         *dest = (~(*src) & *dest) | 0xff000000;
3517         ++dest; ++src;
3518     }
3519 }
3520
3521 void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest,
3522                                                         int length,
3523                                                         uint color,
3524                                                         uint const_alpha)
3525 {
3526     Q_UNUSED(const_alpha);
3527     while (length--) {
3528         *dest = (color & ~(*dest)) | 0xff000000;
3529         ++dest;
3530     }
3531 }
3532
3533 void QT_FASTCALL rasterop_SourceAndNotDestination(uint *Q_DECL_RESTRICT dest,
3534                                                   const uint *Q_DECL_RESTRICT src,
3535                                                   int length,
3536                                                   uint const_alpha)
3537 {
3538     Q_UNUSED(const_alpha);
3539     while (length--) {
3540         *dest = (*src & ~(*dest)) | 0xff000000;
3541         ++dest; ++src;
3542     }
3543 }
3544
3545 static CompositionFunctionSolid functionForModeSolid_C[] = {
3546         comp_func_solid_SourceOver,
3547         comp_func_solid_DestinationOver,
3548         comp_func_solid_Clear,
3549         comp_func_solid_Source,
3550         comp_func_solid_Destination,
3551         comp_func_solid_SourceIn,
3552         comp_func_solid_DestinationIn,
3553         comp_func_solid_SourceOut,
3554         comp_func_solid_DestinationOut,
3555         comp_func_solid_SourceAtop,
3556         comp_func_solid_DestinationAtop,
3557         comp_func_solid_XOR,
3558         comp_func_solid_Plus,
3559         comp_func_solid_Multiply,
3560         comp_func_solid_Screen,
3561         comp_func_solid_Overlay,
3562         comp_func_solid_Darken,
3563         comp_func_solid_Lighten,
3564         comp_func_solid_ColorDodge,
3565         comp_func_solid_ColorBurn,
3566         comp_func_solid_HardLight,
3567         comp_func_solid_SoftLight,
3568         comp_func_solid_Difference,
3569         comp_func_solid_Exclusion,
3570         rasterop_solid_SourceOrDestination,
3571         rasterop_solid_SourceAndDestination,
3572         rasterop_solid_SourceXorDestination,
3573         rasterop_solid_NotSourceAndNotDestination,
3574         rasterop_solid_NotSourceOrNotDestination,
3575         rasterop_solid_NotSourceXorDestination,
3576         rasterop_solid_NotSource,
3577         rasterop_solid_NotSourceAndDestination,
3578         rasterop_solid_SourceAndNotDestination
3579 };
3580
3581 static const CompositionFunctionSolid *functionForModeSolid = functionForModeSolid_C;
3582
3583 static CompositionFunction functionForMode_C[] = {
3584         comp_func_SourceOver,
3585         comp_func_DestinationOver,
3586         comp_func_Clear,
3587         comp_func_Source,
3588         comp_func_Destination,
3589         comp_func_SourceIn,
3590         comp_func_DestinationIn,
3591         comp_func_SourceOut,
3592         comp_func_DestinationOut,
3593         comp_func_SourceAtop,
3594         comp_func_DestinationAtop,
3595         comp_func_XOR,
3596         comp_func_Plus,
3597         comp_func_Multiply,
3598         comp_func_Screen,
3599         comp_func_Overlay,
3600         comp_func_Darken,
3601         comp_func_Lighten,
3602         comp_func_ColorDodge,
3603         comp_func_ColorBurn,
3604         comp_func_HardLight,
3605         comp_func_SoftLight,
3606         comp_func_Difference,
3607         comp_func_Exclusion,
3608         rasterop_SourceOrDestination,
3609         rasterop_SourceAndDestination,
3610         rasterop_SourceXorDestination,
3611         rasterop_NotSourceAndNotDestination,
3612         rasterop_NotSourceOrNotDestination,
3613         rasterop_NotSourceXorDestination,
3614         rasterop_NotSource,
3615         rasterop_NotSourceAndDestination,
3616         rasterop_SourceAndNotDestination
3617 };
3618
3619 static const CompositionFunction *functionForMode = functionForMode_C;
3620
3621 static TextureBlendType getBlendType(const QSpanData *data)
3622 {
3623     TextureBlendType ft;
3624     if (data->txop <= QTransform::TxTranslate)
3625         if (data->texture.type == QTextureData::Tiled)
3626             ft = BlendTiled;
3627         else
3628             ft = BlendUntransformed;
3629     else if (data->bilinear)
3630         if (data->texture.type == QTextureData::Tiled)
3631             ft = BlendTransformedBilinearTiled;
3632         else
3633             ft = BlendTransformedBilinear;
3634     else
3635         if (data->texture.type == QTextureData::Tiled)
3636             ft = BlendTransformedTiled;
3637         else
3638             ft = BlendTransformed;
3639     return ft;
3640 }
3641
3642 static inline Operator getOperator(const QSpanData *data, const QSpan *spans, int spanCount)
3643 {
3644     Operator op;
3645     bool solidSource = false;
3646
3647     switch(data->type) {
3648     case QSpanData::Solid:
3649         solidSource = (qAlpha(data->solid.color) == 255);
3650         break;
3651     case QSpanData::LinearGradient:
3652         solidSource = !data->gradient.alphaColor;
3653         getLinearGradientValues(&op.linear, data);
3654         op.src_fetch = qt_fetch_linear_gradient;
3655         break;
3656     case QSpanData::RadialGradient:
3657         solidSource = !data->gradient.alphaColor;
3658         getRadialGradientValues(&op.radial, data);
3659         op.src_fetch = qt_fetch_radial_gradient;
3660         break;
3661     case QSpanData::ConicalGradient:
3662         solidSource = !data->gradient.alphaColor;
3663         op.src_fetch = qt_fetch_conical_gradient;
3664         break;
3665     case QSpanData::Texture:
3666         op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format];
3667         solidSource = !data->texture.hasAlpha;
3668     default:
3669         break;
3670     }
3671
3672     op.mode = data->rasterBuffer->compositionMode;
3673     if (op.mode == QPainter::CompositionMode_SourceOver && solidSource)
3674         op.mode = QPainter::CompositionMode_Source;
3675
3676     op.dest_fetch = destFetchProc[data->rasterBuffer->format];
3677     if (op.mode == QPainter::CompositionMode_Source) {
3678         switch (data->rasterBuffer->format) {
3679         case QImage::Format_RGB32:
3680         case QImage::Format_ARGB32_Premultiplied:
3681             // don't clear dest_fetch as it sets up the pointer correctly to save one copy
3682             break;
3683         default: {
3684             if (data->type == QSpanData::Texture && data->texture.const_alpha != 256)
3685                 break;
3686             const QSpan *lastSpan = spans + spanCount;
3687             bool alphaSpans = false;
3688             while (spans < lastSpan) {
3689                 if (spans->coverage != 255) {
3690                     alphaSpans = true;
3691                     break;
3692                 }
3693                 ++spans;
3694             }
3695             if (!alphaSpans)
3696                 op.dest_fetch = 0;
3697         }
3698         }
3699     }
3700
3701     op.dest_store = destStoreProc[data->rasterBuffer->format];
3702
3703     op.funcSolid = functionForModeSolid[op.mode];
3704     op.func = functionForMode[op.mode];
3705
3706     return op;
3707 }
3708
3709
3710
3711 // -------------------- blend methods ---------------------
3712
3713 #if !defined(Q_CC_SUN)
3714 static
3715 #endif
3716 void blend_color_generic(int count, const QSpan *spans, void *userData)
3717 {
3718     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3719     uint buffer[buffer_size];
3720     Operator op = getOperator(data, spans, count);
3721
3722     while (count--) {
3723         int x = spans->x;
3724         int length = spans->len;
3725         while (length) {
3726             int l = qMin(buffer_size, length);
3727             uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3728             op.funcSolid(dest, l, data->solid.color, spans->coverage);
3729             if (op.dest_store)
3730                 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3731             length -= l;
3732             x += l;
3733         }
3734         ++spans;
3735     }
3736 }
3737
3738 static void blend_color_argb(int count, const QSpan *spans, void *userData)
3739 {
3740     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3741
3742     Operator op = getOperator(data, spans, count);
3743
3744     if (op.mode == QPainter::CompositionMode_Source) {
3745         // inline for performance
3746         while (count--) {
3747             uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3748             if (spans->coverage == 255) {
3749                 QT_MEMFILL_UINT(target, spans->len, data->solid.color);
3750             } else {
3751                 uint c = BYTE_MUL(data->solid.color, spans->coverage);
3752                 int ialpha = 255 - spans->coverage;
3753                 for (int i = 0; i < spans->len; ++i)
3754                     target[i] = c + BYTE_MUL(target[i], ialpha);
3755             }
3756             ++spans;
3757         }
3758         return;
3759     }
3760
3761     while (count--) {
3762         uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3763         op.funcSolid(target, spans->len, data->solid.color, spans->coverage);
3764         ++spans;
3765     }
3766 }
3767
3768 static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
3769 {
3770     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3771
3772     /*
3773         We duplicate a little logic from getOperator() and calculate the
3774         composition mode directly.  This allows blend_color_rgb16 to be used
3775         from qt_gradient_quint16 with minimal overhead.
3776      */
3777     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
3778     if (mode == QPainter::CompositionMode_SourceOver &&
3779         qAlpha(data->solid.color) == 255)
3780         mode = QPainter::CompositionMode_Source;
3781
3782     if (mode == QPainter::CompositionMode_Source) {
3783         // inline for performance
3784         ushort c = qConvertRgb32To16(data->solid.color);
3785         while (count--) {
3786             ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3787             if (spans->coverage == 255) {
3788                 QT_MEMFILL_USHORT(target, spans->len, c);
3789             } else {
3790                 ushort color = BYTE_MUL_RGB16(c, spans->coverage);
3791                 int ialpha = 255 - spans->coverage;
3792                 const ushort *end = target + spans->len;
3793                 while (target < end) {
3794                     *target = color + BYTE_MUL_RGB16(*target, ialpha);
3795                     ++target;
3796                 }
3797             }
3798             ++spans;
3799         }
3800         return;
3801     }
3802
3803     if (mode == QPainter::CompositionMode_SourceOver) {
3804         while (count--) {
3805             uint color = BYTE_MUL(data->solid.color, spans->coverage);
3806             int ialpha = qAlpha(~color);
3807             ushort c = qConvertRgb32To16(color);
3808             ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3809             int len = spans->len;
3810             bool pre = (((quintptr)target) & 0x3) != 0;
3811             bool post = false;
3812             if (pre) {
3813                 // skip to word boundary
3814                 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3815                 ++target;
3816                 --len;
3817             }
3818             if (len & 0x1) {
3819                 post = true;
3820                 --len;
3821             }
3822             uint *target32 = (uint*)target;
3823             uint c32 = c | (c<<16);
3824             len >>= 1;
3825             uint salpha = (ialpha+1) >> 3; // calculate here rather than in loop
3826             while (len--) {
3827                 // blend full words
3828                 *target32 = c32 + BYTE_MUL_RGB16_32(*target32, salpha);
3829                 ++target32;
3830                 target += 2;
3831             }
3832             if (post) {
3833                 // one last pixel beyond a full word
3834                 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3835             }
3836             ++spans;
3837         }
3838         return;
3839     }
3840
3841     blend_color_generic(count, spans, userData);
3842 }
3843
3844 template <typename T>
3845 void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
3846 {
3847     uint const_alpha = 256;
3848     if (data->type == QSpanData::Texture)
3849         const_alpha = data->texture.const_alpha;
3850
3851     int coverage = 0;
3852     while (count) {
3853         int x = spans->x;
3854         const int y = spans->y;
3855         int right = x + spans->len;
3856
3857         // compute length of adjacent spans
3858         for (int i = 1; i < count && spans[i].y == y && spans[i].x == right; ++i)
3859             right += spans[i].len;
3860         int length = right - x;
3861
3862         while (length) {
3863             int l = qMin(buffer_size, length);
3864             length -= l;
3865
3866             int process_length = l;
3867             int process_x = x;
3868
3869             const uint *src = handler.fetch(process_x, y, process_length);
3870             int offset = 0;
3871             while (l > 0) {
3872                 if (x == spans->x) // new span?
3873                     coverage = (spans->coverage * const_alpha) >> 8;
3874
3875                 int right = spans->x + spans->len;
3876                 int len = qMin(l, right - x);
3877
3878                 handler.process(x, y, len, coverage, src, offset);
3879
3880                 l -= len;
3881                 x += len;
3882                 offset += len;
3883
3884                 if (x == right) { // done with current span?
3885                     ++spans;
3886                     --count;
3887                 }
3888             }
3889             handler.store(process_x, y, process_length);
3890         }
3891     }
3892 }
3893
3894 struct QBlendBase
3895 {
3896     QBlendBase(QSpanData *d, Operator o)
3897         : data(d)
3898         , op(o)
3899         , dest(0)
3900     {
3901     }
3902
3903     QSpanData *data;
3904     Operator op;
3905
3906     uint *dest;
3907
3908     uint buffer[buffer_size];
3909     uint src_buffer[buffer_size];
3910 };
3911
3912 class BlendSrcGeneric : public QBlendBase
3913 {
3914 public:
3915     BlendSrcGeneric(QSpanData *d, Operator o)
3916         : QBlendBase(d, o)
3917     {
3918     }
3919
3920     const uint *fetch(int x, int y, int len)
3921     {
3922         dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, y, len) : buffer;
3923         return op.src_fetch(src_buffer, &op, data, y, x, len);
3924     }
3925
3926     void process(int, int, int len, int coverage, const uint *src, int offset)
3927     {
3928         op.func(dest + offset, src + offset, len, coverage);
3929     }
3930
3931     void store(int x, int y, int len)
3932     {
3933         if (op.dest_store)
3934             op.dest_store(data->rasterBuffer, x, y, dest, len);
3935     }
3936 };
3937
3938 static void blend_src_generic(int count, const QSpan *spans, void *userData)
3939 {
3940     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3941     BlendSrcGeneric blend(data, getOperator(data, spans, count));
3942     handleSpans(count, spans, data, blend);
3943 }
3944
3945 static void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
3946 {
3947     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3948
3949     uint buffer[buffer_size];
3950     uint src_buffer[buffer_size];
3951     Operator op = getOperator(data, spans, count);
3952
3953     const int image_width = data->texture.width;
3954     const int image_height = data->texture.height;
3955     int xoff = -qRound(-data->dx);
3956     int yoff = -qRound(-data->dy);
3957
3958     while (count--) {
3959         int x = spans->x;
3960         int length = spans->len;
3961         int sx = xoff + x;
3962         int sy = yoff + spans->y;
3963         if (sy >= 0 && sy < image_height && sx < image_width) {
3964             if (sx < 0) {
3965                 x -= sx;
3966                 length += sx;
3967                 sx = 0;
3968             }
3969             if (sx + length > image_width)
3970                 length = image_width - sx;
3971             if (length > 0) {
3972                 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3973                 while (length) {
3974                     int l = qMin(buffer_size, length);
3975                     const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
3976                     uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3977                     op.func(dest, src, l, coverage);
3978                     if (op.dest_store)
3979                         op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3980                     x += l;
3981                     sx += l;
3982                     length -= l;
3983                 }
3984             }
3985         }
3986         ++spans;
3987     }
3988 }
3989
3990 static void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
3991 {
3992     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3993     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
3994         && data->texture.format != QImage::Format_RGB32) {
3995         blend_untransformed_generic(count, spans, userData);
3996         return;
3997     }
3998
3999     Operator op = getOperator(data, spans, count);
4000
4001     const int image_width = data->texture.width;
4002     const int image_height = data->texture.height;
4003     int xoff = -qRound(-data->dx);
4004     int yoff = -qRound(-data->dy);
4005
4006     while (count--) {
4007         int x = spans->x;
4008         int length = spans->len;
4009         int sx = xoff + x;
4010         int sy = yoff + spans->y;
4011         if (sy >= 0 && sy < image_height && sx < image_width) {
4012             if (sx < 0) {
4013                 x -= sx;
4014                 length += sx;
4015                 sx = 0;
4016             }
4017             if (sx + length > image_width)
4018                 length = image_width - sx;
4019             if (length > 0) {
4020                 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4021                 const uint *src = (uint *)data->texture.scanLine(sy) + sx;
4022                 uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
4023                 op.func(dest, src, length, coverage);
4024             }
4025         }
4026         ++spans;
4027     }
4028 }
4029
4030 static inline quint16 interpolate_pixel_rgb16_255(quint16 x, quint8 a,
4031                                                   quint16 y, quint8 b)
4032 {
4033     quint16 t = ((((x & 0x07e0) * a) + ((y & 0x07e0) * b)) >> 5) & 0x07e0;
4034     t |= ((((x & 0xf81f) * a) + ((y & 0xf81f) * b)) >> 5) & 0xf81f;
4035
4036     return t;
4037 }
4038
4039 static inline quint32 interpolate_pixel_rgb16x2_255(quint32 x, quint8 a,
4040                                                     quint32 y, quint8 b)
4041 {
4042     uint t;
4043     t = ((((x & 0xf81f07e0) >> 5) * a) + (((y & 0xf81f07e0) >> 5) * b)) & 0xf81f07e0;
4044     t |= ((((x & 0x07e0f81f) * a) + ((y & 0x07e0f81f) * b)) >> 5) & 0x07e0f81f;
4045     return t;
4046 }
4047
4048 static inline void blend_sourceOver_rgb16_rgb16(quint16 *Q_DECL_RESTRICT dest,
4049                                                 const quint16 *Q_DECL_RESTRICT src,
4050                                                 int length,
4051                                                 const quint8 alpha,
4052                                                 const quint8 ialpha)
4053 {
4054     const int dstAlign = ((quintptr)dest) & 0x3;
4055     if (dstAlign) {
4056         *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
4057         ++dest;
4058         ++src;
4059         --length;
4060     }
4061     const int srcAlign = ((quintptr)src) & 0x3;
4062     int length32 = length >> 1;
4063     if (length32 && srcAlign == 0) {
4064         while (length32--) {
4065             const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4066             quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4067             *dest32 = interpolate_pixel_rgb16x2_255(*src32, alpha,
4068                                                     *dest32, ialpha);
4069             dest += 2;
4070             src += 2;
4071         }
4072         length &= 0x1;
4073     }
4074     while (length--) {
4075         *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
4076         ++dest;
4077         ++src;
4078     }
4079 }
4080
4081 static void blend_untransformed_rgb565(int count, const QSpan *spans, void *userData)
4082 {
4083     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4084     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4085
4086     if (data->texture.format != QImage::Format_RGB16
4087             || (mode != QPainter::CompositionMode_SourceOver
4088                 && mode != QPainter::CompositionMode_Source))
4089     {
4090         blend_untransformed_generic(count, spans, userData);
4091         return;
4092     }
4093
4094     const int image_width = data->texture.width;
4095     const int image_height = data->texture.height;
4096     int xoff = -qRound(-data->dx);
4097     int yoff = -qRound(-data->dy);
4098
4099     while (count--) {
4100         const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4101         if (coverage == 0) {
4102             ++spans;
4103             continue;
4104         }
4105
4106         int x = spans->x;
4107         int length = spans->len;
4108         int sx = xoff + x;
4109         int sy = yoff + spans->y;
4110         if (sy >= 0 && sy < image_height && sx < image_width) {
4111             if (sx < 0) {
4112                 x -= sx;
4113                 length += sx;
4114                 sx = 0;
4115             }
4116             if (sx + length > image_width)
4117                 length = image_width - sx;
4118             if (length > 0) {
4119                 quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + x;
4120                 const quint16 *src = (quint16 *)data->texture.scanLine(sy) + sx;
4121                 if (coverage == 255) {
4122                     memcpy(dest, src, length * sizeof(quint16));
4123                 } else {
4124                     const quint8 alpha = (coverage + 1) >> 3;
4125                     const quint8 ialpha = 0x20 - alpha;
4126                     if (alpha > 0)
4127                         blend_sourceOver_rgb16_rgb16(dest, src, length, alpha, ialpha);
4128                 }
4129             }
4130         }
4131         ++spans;
4132     }
4133 }
4134
4135 static void blend_tiled_generic(int count, const QSpan *spans, void *userData)
4136 {
4137     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4138
4139     uint buffer[buffer_size];
4140     uint src_buffer[buffer_size];
4141     Operator op = getOperator(data, spans, count);
4142
4143     const int image_width = data->texture.width;
4144     const int image_height = data->texture.height;
4145     int xoff = -qRound(-data->dx) % image_width;
4146     int yoff = -qRound(-data->dy) % image_height;
4147
4148     if (xoff < 0)
4149         xoff += image_width;
4150     if (yoff < 0)
4151         yoff += image_height;
4152
4153     while (count--) {
4154         int x = spans->x;
4155         int length = spans->len;
4156         int sx = (xoff + spans->x) % image_width;
4157         int sy = (spans->y + yoff) % image_height;
4158         if (sx < 0)
4159             sx += image_width;
4160         if (sy < 0)
4161             sy += image_height;
4162
4163         const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4164         while (length) {
4165             int l = qMin(image_width - sx, length);
4166             if (buffer_size < l)
4167                 l = buffer_size;
4168             const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
4169             uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
4170             op.func(dest, src, l, coverage);
4171             if (op.dest_store)
4172                 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
4173             x += l;
4174             sx += l;
4175             length -= l;
4176             if (sx >= image_width)
4177                 sx = 0;
4178         }
4179         ++spans;
4180     }
4181 }
4182
4183 static void blend_tiled_argb(int count, const QSpan *spans, void *userData)
4184 {
4185     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4186     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
4187         && data->texture.format != QImage::Format_RGB32) {
4188         blend_tiled_generic(count, spans, userData);
4189         return;
4190     }
4191
4192     Operator op = getOperator(data, spans, count);
4193
4194     int image_width = data->texture.width;
4195     int image_height = data->texture.height;
4196     int xoff = -qRound(-data->dx) % image_width;
4197     int yoff = -qRound(-data->dy) % image_height;
4198
4199     if (xoff < 0)
4200         xoff += image_width;
4201     if (yoff < 0)
4202         yoff += image_height;
4203
4204     while (count--) {
4205         int x = spans->x;
4206         int length = spans->len;
4207         int sx = (xoff + spans->x) % image_width;
4208         int sy = (spans->y + yoff) % image_height;
4209         if (sx < 0)
4210             sx += image_width;
4211         if (sy < 0)
4212             sy += image_height;
4213
4214         const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4215         while (length) {
4216             int l = qMin(image_width - sx, length);
4217             if (buffer_size < l)
4218                 l = buffer_size;
4219             const uint *src = (uint *)data->texture.scanLine(sy) + sx;
4220             uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
4221             op.func(dest, src, l, coverage);
4222             x += l;
4223             length -= l;
4224             sx = 0;
4225         }
4226         ++spans;
4227     }
4228 }
4229
4230 static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
4231 {
4232     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4233     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4234
4235     if (data->texture.format != QImage::Format_RGB16
4236             || (mode != QPainter::CompositionMode_SourceOver
4237                 && mode != QPainter::CompositionMode_Source))
4238     {
4239         blend_tiled_generic(count, spans, userData);
4240         return;
4241     }
4242
4243     const int image_width = data->texture.width;
4244     const int image_height = data->texture.height;
4245     int xoff = -qRound(-data->dx) % image_width;
4246     int yoff = -qRound(-data->dy) % image_height;
4247
4248     if (xoff < 0)
4249         xoff += image_width;
4250     if (yoff < 0)
4251         yoff += image_height;
4252
4253     while (count--) {
4254         const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4255         if (coverage == 0) {
4256             ++spans;
4257             continue;
4258         }
4259
4260         int x = spans->x;
4261         int length = spans->len;
4262         int sx = (xoff + spans->x) % image_width;
4263         int sy = (spans->y + yoff) % image_height;
4264         if (sx < 0)
4265             sx += image_width;
4266         if (sy < 0)
4267             sy += image_height;
4268
4269         if (coverage == 255) {
4270             // Copy the first texture block
4271             length = qMin(image_width,length);
4272             int tx = x;
4273             while (length) {
4274                 int l = qMin(image_width - sx, length);
4275                 if (buffer_size < l)
4276                     l = buffer_size;
4277                 quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + tx;
4278                 const quint16 *src = (quint16 *)data->texture.scanLine(sy) + sx;
4279                 memcpy(dest, src, l * sizeof(quint16));
4280                 length -= l;
4281                 tx += l;
4282                 sx = 0;
4283             }
4284
4285             // Now use the rasterBuffer as the source of the texture,
4286             // We can now progressively copy larger blocks
4287             // - Less cpu time in code figuring out what to copy
4288             // We are dealing with one block of data
4289             // - More likely to fit in the cache
4290             // - can use memcpy
4291             int copy_image_width = qMin(image_width, int(spans->len));
4292             length = spans->len - copy_image_width;
4293             quint16 *src = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x;
4294             quint16 *dest = src + copy_image_width;
4295             while (copy_image_width < length) {
4296                 memcpy(dest, src, copy_image_width * sizeof(quint16));
4297                 dest += copy_image_width;
4298                 length -= copy_image_width;
4299                 copy_image_width *= 2;
4300             }
4301             if (length > 0)
4302                 memcpy(dest, src, length * sizeof(quint16));
4303         } else {
4304             const quint8 alpha = (coverage + 1) >> 3;
4305             const quint8 ialpha = 0x20 - alpha;
4306             if (alpha > 0) {
4307                 while (length) {
4308                     int l = qMin(image_width - sx, length);
4309                     if (buffer_size < l)
4310                         l = buffer_size;
4311                     quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x;
4312                     const quint16 *src = (quint16 *)data->texture.scanLine(sy) + sx;
4313                     blend_sourceOver_rgb16_rgb16(dest, src, l, alpha, ialpha);
4314                     x += l;
4315                     length -= l;
4316                     sx = 0;
4317                 }
4318             }
4319         }
4320         ++spans;
4321     }
4322 }
4323
4324 static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans, void *userData)
4325 {
4326     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4327     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4328
4329     if (data->texture.format != QImage::Format_RGB16
4330             || (mode != QPainter::CompositionMode_SourceOver
4331                 && mode != QPainter::CompositionMode_Source))
4332     {
4333         blend_src_generic(count, spans, userData);
4334         return;
4335     }
4336
4337     quint16 buffer[buffer_size];
4338
4339     const int src_minx = data->texture.x1;
4340     const int src_miny = data->texture.y1;
4341     const int src_maxx = data->texture.x2 - 1;
4342     const int src_maxy = data->texture.y2 - 1;
4343
4344     if (data->fast_matrix) {
4345         // The increment pr x in the scanline
4346         const int fdx = (int)(data->m11 * fixed_scale);
4347         const int fdy = (int)(data->m12 * fixed_scale);
4348
4349         while (count--) {
4350             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4351             const quint8 alpha = (coverage + 1) >> 3;
4352             const quint8 ialpha = 0x20 - alpha;
4353             if (alpha == 0) {
4354                 ++spans;
4355                 continue;
4356             }
4357
4358             quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4359             const qreal cx = spans->x + qreal(0.5);
4360             const qreal cy = spans->y + qreal(0.5);
4361             int x = int((data->m21 * cy
4362                          + data->m11 * cx + data->dx) * fixed_scale) - half_point;
4363             int y = int((data->m22 * cy
4364                          + data->m12 * cx + data->dy) * fixed_scale) - half_point;
4365             int length = spans->len;
4366
4367             while (length) {
4368                 int l;
4369                 quint16 *b;
4370                 if (ialpha == 0) {
4371                     l = length;
4372                     b = dest;
4373                 } else {
4374                     l = qMin(length, buffer_size);
4375                     b = buffer;
4376                 }
4377                 const quint16 *end = b + l;
4378
4379                 while (b < end) {
4380                     int x1 = (x >> 16);
4381                     int x2;
4382                     int y1 = (y >> 16);
4383                     int y2;
4384
4385                     fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2);
4386                     fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2);
4387
4388                     const quint16 *src1 = (quint16*)data->texture.scanLine(y1);
4389                     const quint16 *src2 = (quint16*)data->texture.scanLine(y2);
4390                     quint16 tl = src1[x1];
4391                     const quint16 tr = src1[x2];
4392                     quint16 bl = src2[x1];
4393                     const quint16 br = src2[x2];
4394
4395                     const uint distxsl8 = x & 0xff00;
4396                     const uint distysl8 = y & 0xff00;
4397                     const uint distx = distxsl8 >> 8;
4398                     const uint disty = distysl8 >> 8;
4399                     const uint distxy = distx * disty;
4400
4401                     const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty)
4402                     const uint trw = distxsl8 - distxy; // distx * (256 - disty)
4403                     const uint blw = distysl8 - distxy; // (256 - distx) * disty
4404                     const uint brw = distxy; // distx * disty
4405                     uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw
4406                             + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000;
4407                     uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw
4408                             + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000;
4409                     uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw
4410                             + (bl & 0x001f) * blw + (br & 0x001f) * brw);
4411                     *b = quint16((red | green | blue) >> 16);
4412
4413                     ++b;
4414                     x += fdx;
4415                     y += fdy;
4416                 }
4417
4418                 if (ialpha != 0)
4419                     blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
4420
4421                 dest += l;
4422                 length -= l;
4423             }
4424             ++spans;
4425         }
4426     } else {
4427         const qreal fdx = data->m11;
4428         const qreal fdy = data->m12;
4429         const qreal fdw = data->m13;
4430
4431         while (count--) {
4432             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4433             const quint8 alpha = (coverage + 1) >> 3;
4434             const quint8 ialpha = 0x20 - alpha;
4435             if (alpha == 0) {
4436                 ++spans;
4437                 continue;
4438             }
4439
4440             quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4441
4442             const qreal cx = spans->x + qreal(0.5);
4443             const qreal cy = spans->y + qreal(0.5);
4444
4445             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
4446             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
4447             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
4448
4449             int length = spans->len;
4450             while (length) {
4451                 int l;
4452                 quint16 *b;
4453                 if (ialpha == 0) {
4454                     l = length;
4455                     b = dest;
4456                 } else {
4457                     l = qMin(length, buffer_size);
4458                     b = buffer;
4459                 }
4460                 const quint16 *end = b + l;
4461
4462                 while (b < end) {
4463                     const qreal iw = w == 0 ? 1 : 1 / w;
4464                     const qreal px = x * iw - qreal(0.5);
4465                     const qreal py = y * iw - qreal(0.5);
4466
4467                     int x1 = int(px) - (px < 0);
4468                     int x2;
4469                     int y1 = int(py) - (py < 0);
4470                     int y2;
4471
4472                     fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2);
4473                     fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2);
4474
4475                     const quint16 *src1 = (quint16 *)data->texture.scanLine(y1);
4476                     const quint16 *src2 = (quint16 *)data->texture.scanLine(y2);
4477                     quint16 tl = src1[x1];
4478                     const quint16 tr = src1[x2];
4479                     quint16 bl = src2[x1];
4480                     const quint16 br = src2[x2];
4481
4482                     const uint distx = uint((px - x1) * 256);
4483                     const uint disty = uint((py - y1) * 256);
4484                     const uint distxsl8 = distx << 8;
4485                     const uint distysl8 = disty << 8;
4486                     const uint distxy = distx * disty;
4487
4488                     const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty)
4489                     const uint trw = distxsl8 - distxy; // distx * (256 - disty)
4490                     const uint blw = distysl8 - distxy; // (256 - distx) * disty
4491                     const uint brw = distxy; // distx * disty
4492                     uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw
4493                             + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000;
4494                     uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw
4495                             + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000;
4496                     uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw
4497                             + (bl & 0x001f) * blw + (br & 0x001f) * brw);
4498                     *b = quint16((red | green | blue) >> 16);
4499
4500                     ++b;
4501                     x += fdx;
4502                     y += fdy;
4503                     w += fdw;
4504                 }
4505
4506                 if (ialpha != 0)
4507                     blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
4508
4509                 dest += l;
4510                 length -= l;
4511             }
4512             ++spans;
4513         }
4514     }
4515 }
4516
4517 static void blend_transformed_argb(int count, const QSpan *spans, void *userData)
4518 {
4519     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4520     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
4521         && data->texture.format != QImage::Format_RGB32) {
4522         blend_src_generic(count, spans, userData);
4523         return;
4524     }
4525
4526     CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
4527     uint buffer[buffer_size];
4528
4529     int image_width = data->texture.width;
4530     int image_height = data->texture.height;
4531
4532     if (data->fast_matrix) {
4533         // The increment pr x in the scanline
4534         int fdx = (int)(data->m11 * fixed_scale);
4535         int fdy = (int)(data->m12 * fixed_scale);
4536
4537         while (count--) {
4538             void *t = data->rasterBuffer->scanLine(spans->y);
4539
4540             uint *target = ((uint *)t) + spans->x;
4541
4542             const qreal cx = spans->x + qreal(0.5);
4543             const qreal cy = spans->y + qreal(0.5);
4544
4545             int x = int((data->m21 * cy
4546                          + data->m11 * cx + data->dx) * fixed_scale);
4547             int y = int((data->m22 * cy
4548                          + data->m12 * cx + data->dy) * fixed_scale);
4549
4550             int length = spans->len;
4551             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4552             while (length) {
4553                 int l = qMin(length, buffer_size);
4554                 const uint *end = buffer + l;
4555                 uint *b = buffer;
4556                 while (b < end) {
4557                     int px = qBound(0, x >> 16, image_width - 1);
4558                     int py = qBound(0, y >> 16, image_height - 1);
4559                     *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
4560
4561                     x += fdx;
4562                     y += fdy;
4563                     ++b;
4564                 }
4565                 func(target, buffer, l, coverage);
4566                 target += l;
4567                 length -= l;
4568             }
4569             ++spans;
4570         }
4571     } else {
4572         const qreal fdx = data->m11;
4573         const qreal fdy = data->m12;
4574         const qreal fdw = data->m13;
4575         while (count--) {
4576             void *t = data->rasterBuffer->scanLine(spans->y);
4577
4578             uint *target = ((uint *)t) + spans->x;
4579
4580             const qreal cx = spans->x + qreal(0.5);
4581             const qreal cy = spans->y + qreal(0.5);
4582
4583             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
4584             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
4585             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
4586
4587             int length = spans->len;
4588             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4589             while (length) {
4590                 int l = qMin(length, buffer_size);
4591                 const uint *end = buffer + l;
4592                 uint *b = buffer;
4593                 while (b < end) {
4594                     const qreal iw = w == 0 ? 1 : 1 / w;
4595                     const qreal tx = x * iw;
4596                     const qreal ty = y * iw;
4597                     const int px = qBound(0, int(tx) - (tx < 0), image_width - 1);
4598                     const int py = qBound(0, int(ty) - (ty < 0), image_height - 1);
4599
4600                     *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
4601                     x += fdx;
4602                     y += fdy;
4603                     w += fdw;
4604
4605                     ++b;
4606                 }
4607                 func(target, buffer, l, coverage);
4608                 target += l;
4609                 length -= l;
4610             }
4611             ++spans;
4612         }
4613     }
4614 }
4615
4616 static void blend_transformed_rgb565(int count, const QSpan *spans, void *userData)
4617 {
4618     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4619     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4620
4621     if (data->texture.format != QImage::Format_RGB16
4622             || (mode != QPainter::CompositionMode_SourceOver
4623                 && mode != QPainter::CompositionMode_Source))
4624     {
4625         blend_src_generic(count, spans, userData);
4626         return;
4627     }
4628
4629     quint16 buffer[buffer_size];
4630     const int image_width = data->texture.width;
4631     const int image_height = data->texture.height;
4632
4633     if (data->fast_matrix) {
4634         // The increment pr x in the scanline
4635         const int fdx = (int)(data->m11 * fixed_scale);
4636         const int fdy = (int)(data->m12 * fixed_scale);
4637
4638         while (count--) {
4639             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4640             const quint8 alpha = (coverage + 1) >> 3;
4641             const quint8 ialpha = 0x20 - alpha;
4642             if (alpha == 0) {
4643                 ++spans;
4644                 continue;
4645             }
4646
4647             quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4648             const qreal cx = spans->x + qreal(0.5);
4649             const qreal cy = spans->y + qreal(0.5);
4650             int x = int((data->m21 * cy
4651                          + data->m11 * cx + data->dx) * fixed_scale);
4652             int y = int((data->m22 * cy
4653                          + data->m12 * cx + data->dy) * fixed_scale);
4654             int length = spans->len;
4655
4656             while (length) {
4657                 int l;
4658                 quint16 *b;
4659                 if (ialpha == 0) {
4660                     l = length;
4661                     b = dest;
4662                 } else {
4663                     l = qMin(length, buffer_size);
4664                     b = buffer;
4665                 }
4666                 const quint16 *end = b + l;
4667
4668                 while (b < end) {
4669                     const int px = qBound(0, x >> 16, image_width - 1);
4670                     const int py = qBound(0, y >> 16, image_height - 1);
4671
4672                     *b = ((quint16 *)data->texture.scanLine(py))[px];
4673                     ++b;
4674
4675                     x += fdx;
4676                     y += fdy;
4677                 }
4678
4679                 if (ialpha != 0)
4680                     blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
4681
4682                 dest += l;
4683                 length -= l;
4684             }
4685             ++spans;
4686         }
4687     } else {
4688         const qreal fdx = data->m11;
4689         const qreal fdy = data->m12;
4690         const qreal fdw = data->m13;
4691
4692         while (count--) {
4693             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4694             const quint8 alpha = (coverage + 1) >> 3;
4695             const quint8 ialpha = 0x20 - alpha;
4696             if (alpha == 0) {
4697                 ++spans;
4698                 continue;
4699             }
4700
4701             quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4702
4703             const qreal cx = spans->x + qreal(0.5);
4704             const qreal cy = spans->y + qreal(0.5);
4705
4706             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
4707             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
4708             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
4709
4710             int length = spans->len;
4711             while (length) {
4712                 int l;
4713                 quint16 *b;
4714                 if (ialpha == 0) {
4715                     l = length;
4716                     b = dest;
4717                 } else {
4718                     l = qMin(length, buffer_size);
4719                     b = buffer;
4720                 }
4721                 const quint16 *end = b + l;
4722
4723                 while (b < end) {
4724                     const qreal iw = w == 0 ? 1 : 1 / w;
4725                     const qreal tx = x * iw;
4726                     const qreal ty = y * iw;
4727
4728                     const int px = qBound(0, int(tx) - (tx < 0), image_width - 1);
4729                     const int py = qBound(0, int(ty) - (ty < 0), image_height - 1);
4730
4731                     *b = ((quint16 *)data->texture.scanLine(py))[px];
4732                     ++b;
4733
4734                     x += fdx;
4735                     y += fdy;
4736                     w += fdw;
4737                 }
4738
4739                 if (ialpha != 0)
4740                     blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
4741
4742                 dest += l;
4743                 length -= l;
4744             }
4745             ++spans;
4746         }
4747     }
4748 }
4749
4750 static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *userData)
4751 {
4752     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4753     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
4754         && data->texture.format != QImage::Format_RGB32) {
4755         blend_src_generic(count, spans, userData);
4756         return;
4757     }
4758
4759     CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
4760     uint buffer[buffer_size];
4761
4762     int image_width = data->texture.width;
4763     int image_height = data->texture.height;
4764     const int scanline_offset = data->texture.bytesPerLine / 4;
4765
4766     if (data->fast_matrix) {
4767         // The increment pr x in the scanline
4768         int fdx = (int)(data->m11 * fixed_scale);
4769         int fdy = (int)(data->m12 * fixed_scale);
4770
4771         while (count--) {
4772             void *t = data->rasterBuffer->scanLine(spans->y);
4773
4774             uint *target = ((uint *)t) + spans->x;
4775             uint *image_bits = (uint *)data->texture.imageData;
4776
4777             const qreal cx = spans->x + qreal(0.5);
4778             const qreal cy = spans->y + qreal(0.5);
4779
4780             int x = int((data->m21 * cy
4781                          + data->m11 * cx + data->dx) * fixed_scale);
4782             int y = int((data->m22 * cy
4783                          + data->m12 * cx + data->dy) * fixed_scale);
4784
4785             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4786             int length = spans->len;
4787             while (length) {
4788                 int l = qMin(length, buffer_size);
4789                 const uint *end = buffer + l;
4790                 uint *b = buffer;
4791                 while (b < end) {
4792                     int px = x >> 16;
4793                     int py = y >> 16;
4794                     px %= image_width;
4795                     py %= image_height;
4796                     if (px < 0) px += image_width;
4797                     if (py < 0) py += image_height;
4798                     int y_offset = py * scanline_offset;
4799
4800                     Q_ASSERT(px >= 0 && px < image_width);
4801                     Q_ASSERT(py >= 0 && py < image_height);
4802
4803                     *b = image_bits[y_offset + px];
4804                     x += fdx;
4805                     y += fdy;
4806                     ++b;
4807                 }
4808                 func(target, buffer, l, coverage);
4809                 target += l;
4810                 length -= l;
4811             }
4812             ++spans;
4813         }
4814     } else {
4815         const qreal fdx = data->m11;
4816         const qreal fdy = data->m12;
4817         const qreal fdw = data->m13;
4818         while (count--) {
4819             void *t = data->rasterBuffer->scanLine(spans->y);
4820
4821             uint *target = ((uint *)t) + spans->x;
4822             uint *image_bits = (uint *)data->texture.imageData;
4823
4824             const qreal cx = spans->x + qreal(0.5);
4825             const qreal cy = spans->y + qreal(0.5);
4826
4827             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
4828             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
4829             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
4830
4831             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4832             int length = spans->len;
4833             while (length) {
4834                 int l = qMin(length, buffer_size);
4835                 const uint *end = buffer + l;
4836                 uint *b = buffer;
4837                 while (b < end) {
4838                     const qreal iw = w == 0 ? 1 : 1 / w;
4839                     const qreal tx = x * iw;
4840                     const qreal ty = y * iw;
4841                     int px = int(tx) - (tx < 0);
4842                     int py = int(ty) - (ty < 0);
4843
4844                     px %= image_width;
4845                     py %= image_height;
4846                     if (px < 0) px += image_width;
4847                     if (py < 0) py += image_height;
4848                     int y_offset = py * scanline_offset;
4849
4850                     Q_ASSERT(px >= 0 && px < image_width);
4851                     Q_ASSERT(py >= 0 && py < image_height);
4852
4853                     *b = image_bits[y_offset + px];
4854                     x += fdx;
4855                     y += fdy;
4856                     w += fdw;
4857                     //force increment to avoid /0
4858                     if (!w) {
4859                         w += fdw;
4860                     }
4861                     ++b;
4862                 }
4863                 func(target, buffer, l, coverage);
4864                 target += l;
4865                 length -= l;
4866             }
4867             ++spans;
4868         }
4869     }
4870 }
4871
4872 static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void *userData)
4873 {
4874     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4875     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4876
4877     if (data->texture.format != QImage::Format_RGB16
4878             || (mode != QPainter::CompositionMode_SourceOver
4879                 && mode != QPainter::CompositionMode_Source))
4880     {
4881         blend_src_generic(count, spans, userData);
4882         return;
4883     }
4884
4885     quint16 buffer[buffer_size];
4886     const int image_width = data->texture.width;
4887     const int image_height = data->texture.height;
4888
4889     if (data->fast_matrix) {
4890         // The increment pr x in the scanline
4891         const int fdx = (int)(data->m11 * fixed_scale);
4892         const int fdy = (int)(data->m12 * fixed_scale);
4893
4894         while (count--) {
4895             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4896             const quint8 alpha = (coverage + 1) >> 3;
4897             const quint8 ialpha = 0x20 - alpha;
4898             if (alpha == 0) {
4899                 ++spans;
4900                 continue;
4901             }
4902
4903             quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4904             const qreal cx = spans->x + qreal(0.5);
4905             const qreal cy = spans->y + qreal(0.5);
4906             int x = int((data->m21 * cy
4907                          + data->m11 * cx + data->dx) * fixed_scale);
4908             int y = int((data->m22 * cy
4909                          + data->m12 * cx + data->dy) * fixed_scale);
4910             int length = spans->len;
4911
4912             while (length) {
4913                 int l;
4914                 quint16 *b;
4915                 if (ialpha == 0) {
4916                     l = length;
4917                     b = dest;
4918                 } else {
4919                     l = qMin(length, buffer_size);
4920                     b = buffer;
4921                 }
4922                 const quint16 *end = b + l;
4923
4924                 while (b < end) {
4925                     int px = (x >> 16) % image_width;
4926                     int py = (y >> 16) % image_height;
4927
4928                     if (px < 0)
4929                         px += image_width;
4930                     if (py < 0)
4931                         py += image_height;
4932
4933                     *b = ((quint16 *)data->texture.scanLine(py))[px];
4934                     ++b;
4935
4936                     x += fdx;
4937                     y += fdy;
4938                 }
4939
4940                 if (ialpha != 0)
4941                     blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
4942
4943                 dest += l;
4944                 length -= l;
4945             }
4946             ++spans;
4947         }
4948     } else {
4949         const qreal fdx = data->m11;
4950         const qreal fdy = data->m12;
4951         const qreal fdw = data->m13;
4952
4953         while (count--) {
4954             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4955             const quint8 alpha = (coverage + 1) >> 3;
4956             const quint8 ialpha = 0x20 - alpha;
4957             if (alpha == 0) {
4958                 ++spans;
4959                 continue;
4960             }
4961
4962             quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4963
4964             const qreal cx = spans->x + qreal(0.5);
4965             const qreal cy = spans->y + qreal(0.5);
4966
4967             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
4968             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
4969             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
4970
4971             int length = spans->len;
4972             while (length) {
4973                 int l;
4974                 quint16 *b;
4975                 if (ialpha == 0) {
4976                     l = length;
4977                     b = dest;
4978                 } else {
4979                     l = qMin(length, buffer_size);
4980                     b = buffer;
4981                 }
4982                 const quint16 *end = b + l;
4983
4984                 while (b < end) {
4985                     const qreal iw = w == 0 ? 1 : 1 / w;
4986                     const qreal tx = x * iw;
4987                     const qreal ty = y * iw;
4988
4989                     int px = int(tx) - (tx < 0);
4990                     int py = int(ty) - (ty < 0);
4991
4992                     px %= image_width;
4993                     py %= image_height;
4994                     if (px < 0)
4995                         px += image_width;
4996                     if (py < 0)
4997                         py += image_height;
4998
4999                     *b = ((quint16 *)data->texture.scanLine(py))[px];
5000                     ++b;
5001
5002                     x += fdx;
5003                     y += fdy;
5004                     w += fdw;
5005                     // force increment to avoid /0
5006                     if (!w)
5007                         w += fdw;
5008                 }
5009
5010                 if (ialpha != 0)
5011                     blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
5012
5013                 dest += l;
5014                 length -= l;
5015             }
5016             ++spans;
5017         }
5018     }
5019 }
5020
5021
5022 /* Image formats here are target formats */
5023 static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats] = {
5024     // Untransformed
5025     {
5026         0, // Invalid
5027         blend_untransformed_generic, // Mono
5028         blend_untransformed_generic, // MonoLsb
5029         blend_untransformed_generic, // Indexed8
5030         blend_untransformed_generic, // RGB32
5031         blend_untransformed_generic, // ARGB32
5032         blend_untransformed_argb, // ARGB32_Premultiplied
5033         blend_untransformed_rgb565,
5034         blend_untransformed_generic,
5035         blend_untransformed_generic,
5036         blend_untransformed_generic,
5037         blend_untransformed_generic,
5038         blend_untransformed_generic,
5039         blend_untransformed_generic,
5040         blend_untransformed_generic,
5041         blend_untransformed_generic,
5042     },
5043     // Tiled
5044     {
5045         0, // Invalid
5046         blend_tiled_generic, // Mono
5047         blend_tiled_generic, // MonoLsb
5048         blend_tiled_generic, // Indexed8
5049         blend_tiled_generic, // RGB32
5050         blend_tiled_generic, // ARGB32
5051         blend_tiled_argb, // ARGB32_Premultiplied
5052         blend_tiled_rgb565,
5053         blend_tiled_generic,
5054         blend_tiled_generic,
5055         blend_tiled_generic,
5056         blend_tiled_generic,
5057         blend_tiled_generic,
5058         blend_tiled_generic,
5059         blend_tiled_generic,
5060         blend_tiled_generic,
5061     },
5062     // Transformed
5063     {
5064         0, // Invalid
5065         blend_src_generic, // Mono
5066         blend_src_generic, // MonoLsb
5067         blend_src_generic, // Indexed8
5068         blend_src_generic, // RGB32
5069         blend_src_generic, // ARGB32
5070         blend_transformed_argb, // ARGB32_Premultiplied
5071         blend_transformed_rgb565,
5072         blend_src_generic,
5073         blend_src_generic,
5074         blend_src_generic,
5075         blend_src_generic,
5076         blend_src_generic,
5077         blend_src_generic,
5078         blend_src_generic,
5079         blend_src_generic,
5080     },
5081      // TransformedTiled
5082     {
5083         0,
5084         blend_src_generic, // Mono
5085         blend_src_generic, // MonoLsb
5086         blend_src_generic, // Indexed8
5087         blend_src_generic, // RGB32
5088         blend_src_generic, // ARGB32
5089         blend_transformed_tiled_argb, // ARGB32_Premultiplied
5090         blend_transformed_tiled_rgb565,
5091         blend_src_generic,
5092         blend_src_generic,
5093         blend_src_generic,
5094         blend_src_generic,
5095         blend_src_generic,
5096         blend_src_generic,
5097         blend_src_generic,
5098         blend_src_generic
5099     },
5100     // Bilinear
5101     {
5102         0,
5103         blend_src_generic, // Mono
5104         blend_src_generic, // MonoLsb
5105         blend_src_generic, // Indexed8
5106         blend_src_generic, // RGB32
5107         blend_src_generic, // ARGB32
5108         blend_src_generic, // ARGB32_Premultiplied
5109         blend_transformed_bilinear_rgb565,
5110         blend_src_generic,
5111         blend_src_generic,
5112         blend_src_generic,
5113         blend_src_generic,
5114         blend_src_generic,
5115         blend_src_generic,
5116         blend_src_generic,
5117         blend_src_generic,
5118     },
5119     // BilinearTiled
5120     {
5121         0,
5122         blend_src_generic, // Mono
5123         blend_src_generic, // MonoLsb
5124         blend_src_generic, // Indexed8
5125         blend_src_generic, // RGB32
5126         blend_src_generic, // ARGB32
5127         blend_src_generic, // ARGB32_Premultiplied
5128         blend_src_generic, // RGB16
5129         blend_src_generic, // ARGB8565_Premultiplied
5130         blend_src_generic, // RGB666
5131         blend_src_generic, // ARGB6666_Premultiplied
5132         blend_src_generic, // RGB555
5133         blend_src_generic, // ARGB8555_Premultiplied
5134         blend_src_generic, // RGB888
5135         blend_src_generic, // RGB444
5136         blend_src_generic, // ARGB4444_Premultiplied
5137     }
5138 };
5139
5140 void qBlendTexture(int count, const QSpan *spans, void *userData)
5141 {
5142     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5143     ProcessSpans proc = processTextureSpans[getBlendType(data)][data->rasterBuffer->format];
5144     proc(count, spans, userData);
5145 }
5146
5147 template <class DST>
5148 inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
5149                                    int x, int y, DST color,
5150                                    const uchar *map,
5151                                    int mapWidth, int mapHeight, int mapStride)
5152 {
5153     DST *dest = reinterpret_cast<DST *>(rasterBuffer->scanLine(y)) + x;
5154     const int destStride = rasterBuffer->bytesPerLine() / sizeof(DST);
5155
5156     if (mapWidth > 8) {
5157         while (mapHeight--) {
5158             int x0 = 0;
5159             int n = 0;
5160             for (int x = 0; x < mapWidth; x += 8) {
5161                 uchar s = map[x >> 3];
5162                 for (int i = 0; i < 8; ++i) {
5163                     if (s & 0x80) {
5164                         ++n;
5165                     } else {
5166                         if (n) {
5167                             qt_memfill(dest + x0, color, n);
5168                             x0 += n + 1;
5169                             n = 0;
5170                         } else {
5171                             ++x0;
5172                         }
5173                         if (!s) {
5174                             x0 += 8 - 1 - i;
5175                             break;
5176                         }
5177                     }
5178                     s <<= 1;
5179                 }
5180             }
5181             if (n)
5182                 qt_memfill(dest + x0, color, n);
5183             dest += destStride;
5184             map += mapStride;
5185         }
5186     } else {
5187         while (mapHeight--) {
5188             int x0 = 0;
5189             int n = 0;
5190             for (uchar s = *map; s; s <<= 1) {
5191                 if (s & 0x80) {
5192                     ++n;
5193                 } else if (n) {
5194                     qt_memfill(dest + x0, color, n);
5195                     x0 += n + 1;
5196                     n = 0;
5197                 } else {
5198                     ++x0;
5199                 }
5200             }
5201             if (n)
5202                 qt_memfill(dest + x0, color, n);
5203             dest += destStride;
5204             map += mapStride;
5205         }
5206     }
5207 }
5208
5209 static void qt_gradient_quint32(int count, const QSpan *spans, void *userData)
5210 {
5211     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5212
5213     bool isVerticalGradient =
5214         data->txop <= QTransform::TxScale &&
5215         data->type == QSpanData::LinearGradient &&
5216         data->gradient.linear.end.x == data->gradient.linear.origin.x;
5217
5218     if (isVerticalGradient) {
5219         LinearGradientValues linear;
5220         getLinearGradientValues(&linear, data);
5221
5222         CompositionFunctionSolid funcSolid =
5223             functionForModeSolid[data->rasterBuffer->compositionMode];
5224
5225         /*
5226             The logic for vertical gradient calculations is a mathematically
5227             reduced copy of that in fetchLinearGradient() - which is basically:
5228
5229                 qreal ry = data->m22 * (y + 0.5) + data->dy;
5230                 qreal t = linear.dy*ry + linear.off;
5231                 t *= (GRADIENT_STOPTABLE_SIZE - 1);
5232                 quint32 color =
5233                     qt_gradient_pixel_fixed(&data->gradient,
5234                                             int(t * FIXPT_SIZE));
5235
5236             This has then been converted to fixed point to improve performance.
5237          */
5238         const int gss = GRADIENT_STOPTABLE_SIZE - 1;
5239         int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
5240         int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
5241
5242         while (count--) {
5243             int y = spans->y;
5244             int x = spans->x;
5245
5246             quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x;
5247             quint32 color =
5248                 qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
5249
5250             funcSolid(dst, spans->len, color, spans->coverage);
5251             ++spans;
5252         }
5253
5254     } else {
5255         blend_src_generic(count, spans, userData);
5256     }
5257 }
5258
5259 static void qt_gradient_quint16(int count, const QSpan *spans, void *userData)
5260 {
5261     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5262
5263     bool isVerticalGradient =
5264         data->txop <= QTransform::TxScale &&
5265         data->type == QSpanData::LinearGradient &&
5266         data->gradient.linear.end.x == data->gradient.linear.origin.x;
5267
5268     if (isVerticalGradient) {
5269
5270         LinearGradientValues linear;
5271         getLinearGradientValues(&linear, data);
5272
5273         /*
5274             The logic for vertical gradient calculations is a mathematically
5275             reduced copy of that in fetchLinearGradient() - which is basically:
5276
5277                 qreal ry = data->m22 * (y + 0.5) + data->dy;
5278                 qreal t = linear.dy*ry + linear.off;
5279                 t *= (GRADIENT_STOPTABLE_SIZE - 1);
5280                 quint32 color =
5281                     qt_gradient_pixel_fixed(&data->gradient,
5282                                             int(t * FIXPT_SIZE));
5283
5284             This has then been converted to fixed point to improve performance.
5285          */
5286         const int gss = GRADIENT_STOPTABLE_SIZE - 1;
5287         int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
5288         int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
5289
5290         uint oldColor = data->solid.color;
5291         while (count--) {
5292             int y = spans->y;
5293
5294             quint32 color = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
5295
5296             data->solid.color = color;
5297             blend_color_rgb16(1, spans, userData);
5298             ++spans;
5299         }
5300         data->solid.color = oldColor;
5301
5302     } else {
5303         blend_src_generic(count, spans, userData);
5304     }
5305 }
5306
5307 inline static void qt_bitmapblit_quint32(QRasterBuffer *rasterBuffer,
5308                                    int x, int y, quint32 color,
5309                                    const uchar *map,
5310                                    int mapWidth, int mapHeight, int mapStride)
5311 {
5312     qt_bitmapblit_template<quint32>(rasterBuffer, x,  y,  color,
5313                                     map, mapWidth, mapHeight, mapStride);
5314 }
5315
5316 inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
5317                                    int x, int y, quint32 color,
5318                                    const uchar *map,
5319                                    int mapWidth, int mapHeight, int mapStride)
5320 {
5321     qt_bitmapblit_template<quint16>(rasterBuffer, x,  y,  qConvertRgb32To16(color),
5322                                     map, mapWidth, mapHeight, mapStride);
5323 }
5324
5325 static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
5326                                     int x, int y, quint32 color,
5327                                     const uchar *map,
5328                                     int mapWidth, int mapHeight, int mapStride,
5329                                     const QClipData *)
5330 {
5331     const quint16 c = qConvertRgb32To16(color);
5332     quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
5333     const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
5334
5335     while (mapHeight--) {
5336         for (int i = 0; i < mapWidth; ++i) {
5337             const int coverage = map[i];
5338
5339             if (coverage == 0) {
5340                 // nothing
5341             } else if (coverage == 255) {
5342                 dest[i] = c;
5343             } else {
5344                 int ialpha = 255 - coverage;
5345                 dest[i] = BYTE_MUL_RGB16(c, coverage)
5346                           + BYTE_MUL_RGB16(dest[i], ialpha);
5347             }
5348         }
5349         dest += destStride;
5350         map += mapStride;
5351     }
5352 }
5353
5354 static inline void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb, const uchar *gamma, const uchar *invgamma)
5355 {
5356     // Do a gray alphablend...
5357     int da = qAlpha(*dst);
5358     int dr = qRed(*dst);
5359     int dg = qGreen(*dst);
5360     int db = qBlue(*dst);
5361
5362     if (da != 255
5363         ) {
5364
5365         int a = qGray(coverage);
5366         sr = qt_div_255(invgamma[sr] * a);
5367         sg = qt_div_255(invgamma[sg] * a);
5368         sb = qt_div_255(invgamma[sb] * a);
5369
5370         int ia = 255 - a;
5371         dr = qt_div_255(dr * ia);
5372         dg = qt_div_255(dg * ia);
5373         db = qt_div_255(db * ia);
5374
5375         *dst = ((a + qt_div_255((255 - a) * da)) << 24)
5376             |  ((sr + dr) << 16)
5377             |  ((sg + dg) << 8)
5378             |  ((sb + db));
5379         return;
5380     }
5381
5382     int mr = qRed(coverage);
5383     int mg = qGreen(coverage);
5384     int mb = qBlue(coverage);
5385
5386     dr = gamma[dr];
5387     dg = gamma[dg];
5388     db = gamma[db];
5389
5390     int nr = qt_div_255((sr - dr) * mr) + dr;
5391     int ng = qt_div_255((sg - dg) * mg) + dg;
5392     int nb = qt_div_255((sb - db) * mb) + db;
5393
5394     nr = invgamma[nr];
5395     ng = invgamma[ng];
5396     nb = invgamma[nb];
5397
5398     *dst = qRgb(nr, ng, nb);
5399 }
5400
5401 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
5402 static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb, const uint *gamma, const uchar *invgamma)
5403 {
5404     // Do a gammacorrected gray alphablend...
5405     int dr = qRed(*dst);
5406     int dg = qGreen(*dst);
5407     int db = qBlue(*dst);
5408
5409     dr = gamma[dr];
5410     dg = gamma[dg];
5411     db = gamma[db];
5412
5413     int alpha = coverage;
5414     int ialpha = 255 - alpha;
5415     int nr = (sr * alpha + ialpha * dr) / 255;
5416     int ng = (sg * alpha + ialpha * dg) / 255;
5417     int nb = (sb * alpha + ialpha * db) / 255;
5418
5419     nr = invgamma[nr];
5420     ng = invgamma[ng];
5421     nb = invgamma[nb];
5422
5423     *dst = qRgb(nr, ng, nb);
5424 }
5425 #endif
5426
5427 static void qt_alphamapblit_quint32(QRasterBuffer *rasterBuffer,
5428                                     int x, int y, quint32 color,
5429                                     const uchar *map,
5430                                     int mapWidth, int mapHeight, int mapStride,
5431                                     const QClipData *clip)
5432 {
5433     const quint32 c = color;
5434     const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
5435
5436 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
5437     const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables();
5438     if (!tables)
5439         return;
5440
5441     const uint *gamma = tables->qt_pow_gamma;
5442     const uchar *invgamma = tables->qt_pow_invgamma;
5443
5444     int sr = gamma[qRed(color)];
5445     int sg = gamma[qGreen(color)];
5446     int sb = gamma[qBlue(color)];
5447
5448     bool opaque_src = (qAlpha(color) == 255);
5449 #endif
5450
5451     if (!clip) {
5452         quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
5453         while (mapHeight--) {
5454             for (int i = 0; i < mapWidth; ++i) {
5455                 const int coverage = map[i];
5456
5457                 if (coverage == 0) {
5458                     // nothing
5459                 } else if (coverage == 255) {
5460                     dest[i] = c;
5461                 } else {
5462 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
5463                     if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
5464                         && qAlpha(dest[i]) == 255) {
5465                         grayBlendPixel(dest+i, coverage, sr, sg, sb, gamma, invgamma);
5466                     } else
5467 #endif
5468                     {
5469                         int ialpha = 255 - coverage;
5470                         dest[i] = INTERPOLATE_PIXEL_255(c, coverage, dest[i], ialpha);
5471                     }
5472                 }
5473             }
5474             dest += destStride;
5475             map += mapStride;
5476         }
5477     } else {
5478         int bottom = qMin(y + mapHeight, rasterBuffer->height());
5479
5480         int top = qMax(y, 0);
5481         map += (top - y) * mapStride;
5482
5483         const_cast<QClipData *>(clip)->initialize();
5484         for (int yp = top; yp<bottom; ++yp) {
5485             const QClipData::ClipLine &line = clip->m_clipLines[yp];
5486
5487             quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
5488
5489             for (int i=0; i<line.count; ++i) {
5490                 const QSpan &clip = line.spans[i];
5491
5492                 int start = qMax<int>(x, clip.x);
5493                 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5494
5495                 for (int xp=start; xp<end; ++xp) {
5496                     const int coverage = map[xp - x];
5497
5498                     if (coverage == 0) {
5499                         // nothing
5500                     } else if (coverage == 255) {
5501                         dest[xp] = c;
5502                     } else {
5503 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
5504                         if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
5505                             && qAlpha(dest[xp]) == 255) {
5506                             grayBlendPixel(dest+xp, coverage, sr, sg, sb, gamma, invgamma);
5507                         } else
5508 #endif
5509                         {
5510                             int ialpha = 255 - coverage;
5511                             dest[xp] = INTERPOLATE_PIXEL_255(c, coverage, dest[xp], ialpha);
5512                         }
5513                     }
5514
5515                 } // for (i -> line.count)
5516             } // for (yp -> bottom)
5517             map += mapStride;
5518         }
5519     }
5520 }
5521
5522 static void qt_alphargbblit_quint32(QRasterBuffer *rasterBuffer,
5523                                     int x, int y, quint32 color,
5524                                     const uint *src, int mapWidth, int mapHeight, int srcStride,
5525                                     const QClipData *clip)
5526 {
5527     const quint32 c = color;
5528
5529     int sr = qRed(color);
5530     int sg = qGreen(color);
5531     int sb = qBlue(color);
5532     int sa = qAlpha(color);
5533
5534     const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables();
5535     if (!tables)
5536         return;
5537
5538     const uchar *gamma = tables->qt_pow_rgb_gamma;
5539     const uchar *invgamma = tables->qt_pow_rgb_invgamma;
5540
5541     sr = gamma[sr];
5542     sg = gamma[sg];
5543     sb = gamma[sb];
5544
5545     if (sa == 0)
5546         return;
5547
5548     if (!clip) {
5549         quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
5550         const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
5551         while (mapHeight--) {
5552             for (int i = 0; i < mapWidth; ++i) {
5553                 const uint coverage = src[i];
5554                 if (coverage == 0xffffffff) {
5555                     dst[i] = c;
5556                 } else if (coverage != 0xff000000) {
5557                     rgbBlendPixel(dst+i, coverage, sr, sg, sb, gamma, invgamma);
5558                 }
5559             }
5560
5561             dst += destStride;
5562             src += srcStride;
5563         }
5564     } else {
5565         int bottom = qMin(y + mapHeight, rasterBuffer->height());
5566
5567         int top = qMax(y, 0);
5568         src += (top - y) * srcStride;
5569
5570         const_cast<QClipData *>(clip)->initialize();
5571         for (int yp = top; yp<bottom; ++yp) {
5572             const QClipData::ClipLine &line = clip->m_clipLines[yp];
5573
5574             quint32 *dst = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
5575
5576             for (int i=0; i<line.count; ++i) {
5577                 const QSpan &clip = line.spans[i];
5578
5579                 int start = qMax<int>(x, clip.x);
5580                 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5581
5582                 for (int xp=start; xp<end; ++xp) {
5583                     const uint coverage = src[xp - x];
5584                     if (coverage == 0xffffffff) {
5585                         dst[xp] = c;
5586                     } else if (coverage != 0xff000000) {
5587                         rgbBlendPixel(dst+xp, coverage, sr, sg, sb, gamma, invgamma);
5588                     }
5589                 }
5590             } // for (i -> line.count)
5591             src += srcStride;
5592         } // for (yp -> bottom)
5593
5594     }
5595 }
5596
5597 static void qt_rectfill_quint32(QRasterBuffer *rasterBuffer,
5598                                 int x, int y, int width, int height,
5599                                 quint32 color)
5600 {
5601     qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
5602                          color, x, y, width, height, rasterBuffer->bytesPerLine());
5603 }
5604
5605 static void qt_rectfill_quint16(QRasterBuffer *rasterBuffer,
5606                                 int x, int y, int width, int height,
5607                                 quint32 color)
5608 {
5609     qt_rectfill<quint16>(reinterpret_cast<quint16 *>(rasterBuffer->buffer()),
5610                          qConvertRgb32To16(color), x, y, width, height, rasterBuffer->bytesPerLine());
5611 }
5612
5613 static void qt_rectfill_nonpremul_quint32(QRasterBuffer *rasterBuffer,
5614                                           int x, int y, int width, int height,
5615                                           quint32 color)
5616 {
5617     qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
5618                          INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine());
5619 }
5620
5621
5622 // Map table for destination image format. Contains function pointers
5623 // for blends of various types unto the destination
5624
5625 DrawHelper qDrawHelper[QImage::NImageFormats] =
5626 {
5627     // Format_Invalid,
5628     { 0, 0, 0, 0, 0, 0 },
5629     // Format_Mono,
5630     {
5631         blend_color_generic,
5632         blend_src_generic,
5633         0, 0, 0, 0
5634     },
5635     // Format_MonoLSB,
5636     {
5637         blend_color_generic,
5638         blend_src_generic,
5639         0, 0, 0, 0
5640     },
5641     // Format_Indexed8,
5642     {
5643         blend_color_generic,
5644         blend_src_generic,
5645         0, 0, 0, 0
5646     },
5647     // Format_RGB32,
5648     {
5649         blend_color_argb,
5650         qt_gradient_quint32,
5651         qt_bitmapblit_quint32,
5652         qt_alphamapblit_quint32,
5653         qt_alphargbblit_quint32,
5654         qt_rectfill_quint32
5655     },
5656     // Format_ARGB32,
5657     {
5658         blend_color_generic,
5659         qt_gradient_quint32,
5660         qt_bitmapblit_quint32,
5661         qt_alphamapblit_quint32,
5662         qt_alphargbblit_quint32,
5663         qt_rectfill_nonpremul_quint32
5664     },
5665     // Format_ARGB32_Premultiplied
5666     {
5667         blend_color_argb,
5668         qt_gradient_quint32,
5669         qt_bitmapblit_quint32,
5670         qt_alphamapblit_quint32,
5671         qt_alphargbblit_quint32,
5672         qt_rectfill_quint32
5673     },
5674     // Format_RGB16
5675     {
5676         blend_color_rgb16,
5677         qt_gradient_quint16,
5678         qt_bitmapblit_quint16,
5679         qt_alphamapblit_quint16,
5680         0,
5681         qt_rectfill_quint16
5682     },
5683     // Format_ARGB8565_Premultiplied
5684     {
5685         blend_color_generic,
5686         blend_src_generic,
5687         0, 0, 0, 0
5688     },
5689     // Format_RGB666
5690     {
5691         blend_color_generic,
5692         blend_src_generic,
5693         0, 0, 0, 0
5694     },
5695     // Format_ARGB6666_Premultiplied
5696     {
5697         blend_color_generic,
5698         blend_src_generic,
5699         0, 0, 0, 0
5700     },
5701     // Format_RGB555
5702     {
5703         blend_color_generic,
5704         blend_src_generic,
5705         0, 0, 0, 0
5706     },
5707     // Format_ARGB8555_Premultiplied
5708     {
5709         blend_color_generic,
5710         blend_src_generic,
5711         0, 0, 0, 0
5712     },
5713     // Format_RGB888
5714     {
5715         blend_color_generic,
5716         blend_src_generic,
5717         0, 0, 0, 0
5718     },
5719     // Format_RGB444
5720     {
5721         blend_color_generic,
5722         blend_src_generic,
5723         0, 0, 0, 0
5724     },
5725     // Format_ARGB4444_Premultiplied
5726     {
5727         blend_color_generic,
5728         blend_src_generic,
5729         0, 0, 0, 0
5730     }
5731 };
5732
5733 #if defined(Q_CC_MSVC) && !defined(_MIPS_)
5734 template <class T>
5735 inline void qt_memfill_template(T *dest, T color, int count)
5736 {
5737     while (count--)
5738         *dest++ = color;
5739 }
5740
5741 #else
5742
5743 template <class T>
5744 inline void qt_memfill_template(T *dest, T color, int count)
5745 {
5746     int n = (count + 7) / 8;
5747     switch (count & 0x07)
5748     {
5749     case 0: do { *dest++ = color;
5750     case 7:      *dest++ = color;
5751     case 6:      *dest++ = color;
5752     case 5:      *dest++ = color;
5753     case 4:      *dest++ = color;
5754     case 3:      *dest++ = color;
5755     case 2:      *dest++ = color;
5756     case 1:      *dest++ = color;
5757     } while (--n > 0);
5758     }
5759 }
5760
5761 template <>
5762 inline void qt_memfill_template(quint16 *dest, quint16 value, int count)
5763 {
5764     if (count < 3) {
5765         switch (count) {
5766         case 2: *dest++ = value;
5767         case 1: *dest = value;
5768         }
5769         return;
5770     }
5771
5772     const int align = (quintptr)(dest) & 0x3;
5773     switch (align) {
5774     case 2: *dest++ = value; --count;
5775     }
5776
5777     const quint32 value32 = (value << 16) | value;
5778     qt_memfill(reinterpret_cast<quint32*>(dest), value32, count / 2);
5779     if (count & 0x1)
5780         dest[count - 1] = value;
5781 }
5782 #endif
5783
5784 static void qt_memfill_quint16(quint16 *dest, quint16 color, int count)
5785 {
5786     qt_memfill_template<quint16>(dest, color, count);
5787 }
5788
5789 typedef void (*qt_memfill32_func)(quint32 *dest, quint32 value, int count);
5790 typedef void (*qt_memfill16_func)(quint16 *dest, quint16 value, int count);
5791 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count);
5792 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count);
5793
5794 qt_memfill32_func qt_memfill32 = qt_memfill32_setup;
5795 qt_memfill16_func qt_memfill16 = qt_memfill16_setup;
5796
5797 void qInitDrawhelperAsm()
5798 {
5799
5800     qt_memfill32 = qt_memfill_template<quint32>;
5801     qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16>;
5802
5803     CompositionFunction *functionForModeAsm = 0;
5804     CompositionFunctionSolid *functionForModeSolidAsm = 0;
5805
5806     const uint features = qDetectCPUFeatures();
5807     if (false) {
5808 #ifdef QT_COMPILER_SUPPORTS_AVX
5809     } else if (features & AVX) {
5810         qt_memfill32 = qt_memfill32_avx;
5811         qt_memfill16 = qt_memfill16_avx;
5812         qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_avx;
5813         qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_avx;
5814         qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_avx;
5815         qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_avx;
5816
5817         extern void qt_scale_image_argb32_on_argb32_avx(uchar *destPixels, int dbpl,
5818                                                          const uchar *srcPixels, int sbpl,
5819                                                          const QRectF &targetRect,
5820                                                          const QRectF &sourceRect,
5821                                                          const QRect &clip,
5822                                                          int const_alpha);
5823         qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_avx;
5824         qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_avx;
5825 #endif
5826 #ifdef QT_COMPILER_SUPPORTS_SSE2
5827     } else if (features & SSE2) {
5828         qt_memfill32 = qt_memfill32_sse2;
5829         qt_memfill16 = qt_memfill16_sse2;
5830         qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2;
5831         qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2;
5832         qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2;
5833         qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2;
5834
5835         extern void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
5836                                                          const uchar *srcPixels, int sbpl,
5837                                                          const QRectF &targetRect,
5838                                                          const QRectF &sourceRect,
5839                                                          const QRect &clip,
5840                                                          int const_alpha);
5841         qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
5842         qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
5843 #endif
5844     }
5845
5846 #ifdef QT_COMPILER_SUPPORTS_SSE2
5847     if (features & SSE2) {
5848         extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
5849                                                  const uchar *srcPixels, int sbpl,
5850                                                  int w, int h,
5851                                                  int const_alpha);
5852         extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
5853                                                    const uchar *srcPixels, int sbpl,
5854                                                    int w, int h,
5855                                                    int const_alpha);
5856
5857         qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
5858         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
5859         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
5860         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
5861
5862         extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
5863                                                                       int y, int x, int length);
5864
5865         qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2;
5866     }
5867
5868 #ifdef QT_COMPILER_SUPPORTS_SSSE3
5869     if (features & SSSE3) {
5870         extern void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
5871                                                     const uchar *srcPixels, int sbpl,
5872                                                     int w, int h,
5873                                                     int const_alpha);
5874
5875         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
5876         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
5877     }
5878 #endif // SSSE3
5879
5880 #ifdef QT_COMPILER_SUPPORTS_AVX
5881     if (features & AVX) {
5882         extern void qt_blend_rgb32_on_rgb32_avx(uchar *destPixels, int dbpl,
5883                                                 const uchar *srcPixels, int sbpl,
5884                                                 int w, int h,
5885                                                 int const_alpha);
5886         extern void qt_blend_argb32_on_argb32_avx(uchar *destPixels, int dbpl,
5887                                                   const uchar *srcPixels, int sbpl,
5888                                                   int w, int h,
5889                                                   int const_alpha);
5890
5891         qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx;
5892         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx;
5893         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx;
5894         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx;
5895
5896         extern const uint * QT_FASTCALL qt_fetch_radial_gradient_avx(uint *buffer, const Operator *op, const QSpanData *data,
5897                                                                      int y, int x, int length);
5898
5899         qt_fetch_radial_gradient = qt_fetch_radial_gradient_avx;
5900     }
5901 #endif // AVX
5902
5903 #endif // SSE2
5904
5905 #ifdef QT_COMPILER_SUPPORTS_SSE2
5906     if (features & SSE2) {
5907         functionForModeAsm = qt_functionForMode_SSE2;
5908         functionForModeSolidAsm = qt_functionForModeSolid_SSE2;
5909         }
5910 #endif
5911 #ifdef QT_COMPILER_SUPPORTS_AVX
5912         if (features & AVX) {
5913             extern void QT_FASTCALL comp_func_SourceOver_avx(uint *destPixels,
5914                                                              const uint *srcPixels,
5915                                                              int length,
5916                                                              uint const_alpha);
5917             extern void QT_FASTCALL comp_func_solid_SourceOver_avx(uint *destPixels, int length, uint color, uint const_alpha);
5918             extern void QT_FASTCALL comp_func_Plus_avx(uint *dst, const uint *src, int length, uint const_alpha);
5919             extern void QT_FASTCALL comp_func_Source_avx(uint *dst, const uint *src, int length, uint const_alpha);
5920
5921             functionForModeAsm[0] = comp_func_SourceOver_avx;
5922             functionForModeAsm[QPainter::CompositionMode_Source] = comp_func_Source_avx;
5923             functionForModeAsm[QPainter::CompositionMode_Plus] = comp_func_Plus_avx;
5924             functionForModeSolidAsm[0] = comp_func_solid_SourceOver_avx;
5925     }
5926 #endif // SSE2
5927
5928 #ifdef QT_COMPILER_SUPPORTS_IWMMXT
5929     if (features & IWMMXT) {
5930         functionForModeAsm = qt_functionForMode_IWMMXT;
5931         functionForModeSolidAsm = qt_functionForModeSolid_IWMMXT;
5932         qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_iwmmxt;
5933     }
5934 #endif // IWMMXT
5935
5936 #if defined(QT_COMPILER_SUPPORTS_NEON)
5937     if (features & NEON) {
5938         qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
5939         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
5940         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
5941         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
5942         qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon;
5943         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon;
5944         qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon;
5945
5946         qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon;
5947         qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon;
5948
5949         qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon;
5950         qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon;
5951
5952         qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon;
5953
5954         functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon;
5955         functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon;
5956         functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon;
5957         destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
5958         destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
5959
5960         qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
5961         qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
5962         qt_memfill32 = qt_memfill32_neon;
5963
5964         extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data,
5965                                                                       int y, int x, int length);
5966
5967         qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon;
5968     }
5969 #endif
5970
5971 #if defined(QT_COMPILER_SUPPORTS_MIPS_DSP)
5972         functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_asm_mips_dsp;
5973         functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_mips_dsp;
5974
5975         qt_memfill32 = qt_memfill32_asm_mips_dsp;
5976
5977         qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp;
5978         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp;
5979         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mips_dsp;
5980         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mips_dsp;
5981
5982         destFetchProc[QImage::Format_ARGB32] = qt_destFetchARGB32_mips_dsp;
5983
5984         destStoreProc[QImage::Format_ARGB32] = qt_destStoreARGB32_mips_dsp;
5985
5986 #endif // QT_COMPILER_SUPPORTS_MIPS_DSP
5987     if (functionForModeSolidAsm) {
5988         const int destinationMode = QPainter::CompositionMode_Destination;
5989         functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode];
5990
5991         // use the default qdrawhelper implementation for the
5992         // extended composition modes
5993         for (int mode = 12; mode < 24; ++mode)
5994             functionForModeSolidAsm[mode] = functionForModeSolid_C[mode];
5995
5996         functionForModeSolid = functionForModeSolidAsm;
5997     }
5998     if (functionForModeAsm)
5999         functionForMode = functionForModeAsm;
6000 }
6001
6002 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count)
6003 {
6004     qInitDrawhelperAsm();
6005     qt_memfill32(dest, value, count);
6006 }
6007
6008 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count)
6009 {
6010     qInitDrawhelperAsm();
6011     qt_memfill16(dest, value, count);
6012 }
6013
6014 QT_END_NAMESPACE