Fix compilation error.
[qt:qt.git] / src / gui / painting / qdrawhelper.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <private/qdrawhelper_p.h>
43 #include <private/qpaintengine_raster_p.h>
44 #include <private/qpainter_p.h>
45 #include <private/qdrawhelper_x86_p.h>
46 #ifdef QT_HAVE_ARM_SIMD
47 #include <private/qdrawhelper_arm_simd_p.h>
48 #endif
49 #include <private/qdrawhelper_neon_p.h>
50 #include <private/qmath_p.h>
51 #include <qmath.h>
52
53 QT_BEGIN_NAMESPACE
54
55
56 #define MASK(src, a) src = BYTE_MUL(src, a)
57
58 #if defined(Q_OS_IRIX) && defined(Q_CC_GNU) && __GNUC__ == 3 && __GNUC__ < 4 && QT_POINTER_SIZE == 8
59 #define Q_IRIX_GCC3_3_WORKAROUND
60 //
61 // work around http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14484
62 //
63 static uint gccBug(uint value) __attribute__((noinline));
64 static uint gccBug(uint value)
65 {
66     return value;
67 }
68 #endif
69
70 /*
71   constants and structures
72 */
73
74 enum {
75     fixed_scale = 1 << 16,
76     half_point = 1 << 15
77 };
78 static const int buffer_size = 2048;
79
80 struct LinearGradientValues
81 {
82     qreal dx;
83     qreal dy;
84     qreal l;
85     qreal off;
86 };
87
88 struct RadialGradientValues
89 {
90     qreal dx;
91     qreal dy;
92     qreal a;
93 };
94
95 struct Operator;
96 typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
97 typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length);
98 typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
99
100
101 struct Operator
102 {
103     QPainter::CompositionMode mode;
104     DestFetchProc dest_fetch;
105     DestStoreProc dest_store;
106     SourceFetchProc src_fetch;
107     CompositionFunctionSolid funcSolid;
108     CompositionFunction func;
109     union {
110         LinearGradientValues linear;
111         RadialGradientValues radial;
112 //        TextureValues texture;
113     };
114 };
115
116 /*
117   Destination fetch. This is simple as we don't have to do bounds checks or
118   transformations
119 */
120
121 static uint * QT_FASTCALL destFetchMono(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
122 {
123     uchar *data = (uchar *)rasterBuffer->scanLine(y);
124     uint *start = buffer;
125     const uint *end = buffer + length;
126     while (buffer < end) {
127         *buffer = data[x>>3] & (0x80 >> (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
128         ++buffer;
129         ++x;
130     }
131     return start;
132 }
133
134 static uint * QT_FASTCALL destFetchMonoLsb(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
135 {
136     uchar *data = (uchar *)rasterBuffer->scanLine(y);
137     uint *start = buffer;
138     const uint *end = buffer + length;
139     while (buffer < end) {
140         *buffer = data[x>>3] & (0x1 << (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
141         ++buffer;
142         ++x;
143     }
144     return start;
145 }
146
147 static uint * QT_FASTCALL destFetchARGB32(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
148 {
149     const uint *data = (const uint *)rasterBuffer->scanLine(y) + x;
150     for (int i = 0; i < length; ++i)
151         buffer[i] = PREMUL(data[i]);
152     return buffer;
153 }
154
155 static uint * QT_FASTCALL destFetchARGB32P(uint *, QRasterBuffer *rasterBuffer, int x, int y, int)
156 {
157     return (uint *)rasterBuffer->scanLine(y) + x;
158 }
159
160 static uint * QT_FASTCALL destFetchRGB16(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
161 {
162     const ushort *data = (const ushort *)rasterBuffer->scanLine(y) + x;
163     for (int i = 0; i < length; ++i)
164         buffer[i] = qConvertRgb16To32(data[i]);
165     return buffer;
166 }
167
168 template <class DST>
169 Q_STATIC_TEMPLATE_FUNCTION uint * QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer,
170                                     int x, int y, int length)
171 {
172     const DST *src = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
173     quint32 *dest = reinterpret_cast<quint32*>(buffer);
174     while (length--)
175         *dest++ = *src++;
176     return buffer;
177 }
178
179 # define SPANFUNC_POINTER_DESTFETCH(Arg) destFetch<Arg>
180
181 static DestFetchProc destFetchProc[QImage::NImageFormats] =
182 {
183     0, // Format_Invalid
184     destFetchMono, // Format_Mono,
185     destFetchMonoLsb, // Format_MonoLSB
186     0, // Format_Indexed8
187     destFetchARGB32P, // Format_RGB32
188     destFetchARGB32, // Format_ARGB32,
189     destFetchARGB32P, // Format_ARGB32_Premultiplied
190     destFetchRGB16,   // Format_RGB16
191     SPANFUNC_POINTER_DESTFETCH(qargb8565), // Format_ARGB8565_Premultiplied
192     SPANFUNC_POINTER_DESTFETCH(qrgb666),   // Format_RGB666
193     SPANFUNC_POINTER_DESTFETCH(qargb6666), // Format_ARGB6666_Premultiplied
194     SPANFUNC_POINTER_DESTFETCH(qrgb555),   // Format_RGB555
195     SPANFUNC_POINTER_DESTFETCH(qargb8555), // Format_ARGB8555_Premultiplied
196     SPANFUNC_POINTER_DESTFETCH(qrgb888),   // Format_RGB888
197     SPANFUNC_POINTER_DESTFETCH(qrgb444),   // Format_RGB444
198     SPANFUNC_POINTER_DESTFETCH(qargb4444)  // Format_ARGB4444_Premultiplied
199 };
200
201 /*
202    Returns the color in the mono destination color table
203    that is the "nearest" to /color/.
204 */
205 static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
206 {
207     QRgb color_0 = PREMUL(rbuf->destColor0);
208     QRgb color_1 = PREMUL(rbuf->destColor1);
209     color = PREMUL(color);
210
211     int r = qRed(color);
212     int g = qGreen(color);
213     int b = qBlue(color);
214     int rx, gx, bx;
215     int dist_0, dist_1;
216
217     rx = r - qRed(color_0);
218     gx = g - qGreen(color_0);
219     bx = b - qBlue(color_0);
220     dist_0 = rx*rx + gx*gx + bx*bx;
221
222     rx = r - qRed(color_1);
223     gx = g - qGreen(color_1);
224     bx = b - qBlue(color_1);
225     dist_1 = rx*rx + gx*gx + bx*bx;
226
227     if (dist_0 < dist_1)
228         return color_0;
229     return color_1;
230 }
231
232 /*
233   Destination store.
234 */
235
236 static void QT_FASTCALL destStoreMono(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
237 {
238     uchar *data = (uchar *)rasterBuffer->scanLine(y);
239     if (rasterBuffer->monoDestinationWithClut) {
240         for (int i = 0; i < length; ++i) {
241             if (buffer[i] == rasterBuffer->destColor0) {
242                 data[x >> 3] &= ~(0x80 >> (x & 7));
243             } else if (buffer[i] == rasterBuffer->destColor1) {
244                 data[x >> 3] |= 0x80 >> (x & 7);
245             } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
246                 data[x >> 3] &= ~(0x80 >> (x & 7));
247             } else {
248                 data[x >> 3] |= 0x80 >> (x & 7);
249             }
250             ++x;
251         }
252     } else {
253         for (int i = 0; i < length; ++i) {
254             if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
255                 data[x >> 3] |= 0x80 >> (x & 7);
256             else
257                 data[x >> 3] &= ~(0x80 >> (x & 7));
258             ++x;
259         }
260     }
261 }
262
263 static void QT_FASTCALL destStoreMonoLsb(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
264 {
265     uchar *data = (uchar *)rasterBuffer->scanLine(y);
266     if (rasterBuffer->monoDestinationWithClut) {
267         for (int i = 0; i < length; ++i) {
268             if (buffer[i] == rasterBuffer->destColor0) {
269                 data[x >> 3] &= ~(1 << (x & 7));
270             } else if (buffer[i] == rasterBuffer->destColor1) {
271                 data[x >> 3] |= 1 << (x & 7);
272             } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
273                 data[x >> 3] &= ~(1 << (x & 7));
274             } else {
275                 data[x >> 3] |= 1 << (x & 7);
276             }
277             ++x;
278         }
279     } else {
280         for (int i = 0; i < length; ++i) {
281             if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
282                 data[x >> 3] |= 1 << (x & 7);
283             else
284                 data[x >> 3] &= ~(1 << (x & 7));
285             ++x;
286         }
287     }
288 }
289
290 static void QT_FASTCALL destStoreARGB32(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
291 {
292     uint *data = (uint *)rasterBuffer->scanLine(y) + x;
293     for (int i = 0; i < length; ++i) {
294         int p = buffer[i];
295         int alpha = qAlpha(p);
296         if (alpha == 255)
297             data[i] = p;
298         else if (alpha == 0)
299             data[i] = 0;
300         else {
301             int inv_alpha = 0xff0000/qAlpha(buffer[i]);
302             data[i] = (p & 0xff000000)
303                       | ((qRed(p)*inv_alpha) & 0xff0000)
304                       | (((qGreen(p)*inv_alpha) >> 8) & 0xff00)
305                       | ((qBlue(p)*inv_alpha) >> 16);
306         }
307     }
308 }
309
310 static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
311 {
312     quint16 *data = (quint16*)rasterBuffer->scanLine(y) + x;
313     qt_memconvert<quint16, quint32>(data, buffer, length);
314 }
315
316 template <class DST>
317 Q_STATIC_TEMPLATE_FUNCTION void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer,
318                                   int x, int y,
319                                   const uint *buffer, int length)
320 {
321     DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
322     const quint32p *src = reinterpret_cast<const quint32p*>(buffer);
323     while (length--)
324         *dest++ = DST(*src++);
325 }
326
327 # define SPANFUNC_POINTER_DESTSTORE(DEST) destStore<DEST>
328
329 static DestStoreProc destStoreProc[QImage::NImageFormats] =
330 {
331     0, // Format_Invalid
332     destStoreMono, // Format_Mono,
333     destStoreMonoLsb, // Format_MonoLSB
334     0, // Format_Indexed8
335     0, // Format_RGB32
336     destStoreARGB32, // Format_ARGB32,
337     0, // Format_ARGB32_Premultiplied
338     destStoreRGB16, // Format_RGB16
339     SPANFUNC_POINTER_DESTSTORE(qargb8565), // Format_ARGB8565_Premultiplied
340     SPANFUNC_POINTER_DESTSTORE(qrgb666),   // Format_RGB666
341     SPANFUNC_POINTER_DESTSTORE(qargb6666), // Format_ARGB6666_Premultiplied
342     SPANFUNC_POINTER_DESTSTORE(qrgb555),   // Format_RGB555
343     SPANFUNC_POINTER_DESTSTORE(qargb8555), // Format_ARGB8555_Premultiplied
344     SPANFUNC_POINTER_DESTSTORE(qrgb888),   // Format_RGB888
345     SPANFUNC_POINTER_DESTSTORE(qrgb444),   // Format_RGB444
346     SPANFUNC_POINTER_DESTSTORE(qargb4444)  // Format_ARGB4444_Premultiplied
347 };
348
349 /*
350   Source fetches
351
352   This is a bit more complicated, as we need several fetch routines for every surface type
353
354   We need 5 fetch methods per surface type:
355   untransformed
356   transformed (tiled and not tiled)
357   transformed bilinear (tiled and not tiled)
358
359   We don't need bounds checks for untransformed, but we need them for the other ones.
360
361   The generic implementation does pixel by pixel fetches
362 */
363
364 template <QImage::Format format>
365 Q_STATIC_TEMPLATE_FUNCTION uint QT_FASTCALL qt_fetchPixel(const uchar *scanLine, int x, const QVector<QRgb> *rgb);
366
367 template<>
368 Q_STATIC_TEMPLATE_SPECIALIZATION
369 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Mono>(const uchar *scanLine,
370                                                  int x, const QVector<QRgb> *rgb)
371 {
372     bool pixel = scanLine[x>>3] & (0x80 >> (x & 7));
373     if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
374     return pixel ? 0xff000000 : 0xffffffff;
375 }
376
377 template<>
378 Q_STATIC_TEMPLATE_SPECIALIZATION
379 uint QT_FASTCALL qt_fetchPixel<QImage::Format_MonoLSB>(const uchar *scanLine,
380                                                     int x, const QVector<QRgb> *rgb)
381 {
382     bool pixel = scanLine[x>>3] & (0x1 << (x & 7));
383     if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
384     return pixel ? 0xff000000 : 0xffffffff;
385 }
386
387 template<>
388 Q_STATIC_TEMPLATE_SPECIALIZATION
389 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Indexed8>(const uchar *scanLine,
390                                                      int x, const QVector<QRgb> *rgb)
391 {
392     return PREMUL(rgb->at(scanLine[x]));
393 }
394
395 template<>
396 Q_STATIC_TEMPLATE_SPECIALIZATION
397 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32>(const uchar *scanLine,
398                                                    int x, const QVector<QRgb> *)
399 {
400     return PREMUL(((const uint *)scanLine)[x]);
401 }
402
403 template<>
404 Q_STATIC_TEMPLATE_SPECIALIZATION
405 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32_Premultiplied>(const uchar *scanLine,
406                                                                  int x, const QVector<QRgb> *)
407 {
408     return ((const uint *)scanLine)[x];
409 }
410
411 template<>
412 Q_STATIC_TEMPLATE_SPECIALIZATION
413 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB16>(const uchar *scanLine,
414                                                   int x, const QVector<QRgb> *)
415 {
416     return qConvertRgb16To32(((const ushort *)scanLine)[x]);
417 }
418
419 template<>
420 Q_STATIC_TEMPLATE_SPECIALIZATION
421 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8565_Premultiplied>(const uchar *scanLine,
422                                                      int x,
423                                                      const QVector<QRgb> *)
424 {
425     const qargb8565 color = reinterpret_cast<const qargb8565*>(scanLine)[x];
426     return qt_colorConvert<quint32, qargb8565>(color, 0);
427 }
428
429 template<>
430 Q_STATIC_TEMPLATE_SPECIALIZATION
431 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB666>(const uchar *scanLine,
432                                                    int x,
433                                                    const QVector<QRgb> *)
434 {
435     const qrgb666 color = reinterpret_cast<const qrgb666*>(scanLine)[x];
436     return qt_colorConvert<quint32, qrgb666>(color, 0);
437 }
438
439 template<>
440 Q_STATIC_TEMPLATE_SPECIALIZATION
441 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB6666_Premultiplied>(const uchar *scanLine,
442                                                    int x,
443                                                    const QVector<QRgb> *)
444 {
445     const qargb6666 color = reinterpret_cast<const qargb6666*>(scanLine)[x];
446     return qt_colorConvert<quint32, qargb6666>(color, 0);
447 }
448
449 template<>
450 Q_STATIC_TEMPLATE_SPECIALIZATION
451 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB555>(const uchar *scanLine,
452                                                    int x,
453                                                    const QVector<QRgb> *)
454 {
455     const qrgb555 color = reinterpret_cast<const qrgb555*>(scanLine)[x];
456     return qt_colorConvert<quint32, qrgb555>(color, 0);
457 }
458
459 template<>
460 Q_STATIC_TEMPLATE_SPECIALIZATION
461 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8555_Premultiplied>(const uchar *scanLine,
462                                                      int x,
463                                                      const QVector<QRgb> *)
464 {
465     const qargb8555 color = reinterpret_cast<const qargb8555*>(scanLine)[x];
466     return qt_colorConvert<quint32, qargb8555>(color, 0);
467 }
468
469 template<>
470 Q_STATIC_TEMPLATE_SPECIALIZATION
471 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB888>(const uchar *scanLine,
472                                                    int x,
473                                                    const QVector<QRgb> *)
474 {
475     const qrgb888 color = reinterpret_cast<const qrgb888*>(scanLine)[x];
476     return qt_colorConvert<quint32, qrgb888>(color, 0);
477 }
478
479 template<>
480 Q_STATIC_TEMPLATE_SPECIALIZATION
481 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB444>(const uchar *scanLine,
482                                                    int x,
483                                                    const QVector<QRgb> *)
484 {
485     const qrgb444 color = reinterpret_cast<const qrgb444*>(scanLine)[x];
486     return qt_colorConvert<quint32, qrgb444>(color, 0);
487 }
488
489 template<>
490 Q_STATIC_TEMPLATE_SPECIALIZATION
491 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB4444_Premultiplied>(const uchar *scanLine,
492                                                      int x,
493                                                      const QVector<QRgb> *)
494 {
495     const qargb4444 color = reinterpret_cast<const qargb4444*>(scanLine)[x];
496     return qt_colorConvert<quint32, qargb4444>(color, 0);
497 }
498
499 template<>
500 Q_STATIC_TEMPLATE_SPECIALIZATION
501 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Invalid>(const uchar *,
502                                                      int ,
503                                                      const QVector<QRgb> *)
504 {
505     return 0;
506 }
507
508 typedef uint (QT_FASTCALL *FetchPixelProc)(const uchar *scanLine, int x, const QVector<QRgb> *);
509
510 #define SPANFUNC_POINTER_FETCHPIXEL(Arg) qt_fetchPixel<QImage::Arg>
511
512
513 static const FetchPixelProc fetchPixelProc[QImage::NImageFormats] =
514 {
515     0,
516     SPANFUNC_POINTER_FETCHPIXEL(Format_Mono),
517     SPANFUNC_POINTER_FETCHPIXEL(Format_MonoLSB),
518     SPANFUNC_POINTER_FETCHPIXEL(Format_Indexed8),
519     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
520     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32),
521     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
522     SPANFUNC_POINTER_FETCHPIXEL(Format_RGB16),
523     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8565_Premultiplied),
524     SPANFUNC_POINTER_FETCHPIXEL(Format_RGB666),
525     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB6666_Premultiplied),
526     SPANFUNC_POINTER_FETCHPIXEL(Format_RGB555),
527     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8555_Premultiplied),
528     SPANFUNC_POINTER_FETCHPIXEL(Format_RGB888),
529     SPANFUNC_POINTER_FETCHPIXEL(Format_RGB444),
530     SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB4444_Premultiplied)
531 };
532
533 enum TextureBlendType {
534     BlendUntransformed,
535     BlendTiled,
536     BlendTransformed,
537     BlendTransformedTiled,
538     BlendTransformedBilinear,
539     BlendTransformedBilinearTiled,
540     NBlendTypes
541 };
542
543 template <QImage::Format format>
544 Q_STATIC_TEMPLATE_FUNCTION const uint * QT_FASTCALL qt_fetchUntransformed(uint *buffer, const Operator *, const QSpanData *data,
545                                              int y, int x, int length)
546 {
547     const uchar *scanLine = data->texture.scanLine(y);
548     for (int i = 0; i < length; ++i)
549         buffer[i] = qt_fetchPixel<format>(scanLine, x + i, data->texture.colorTable);
550     return buffer;
551 }
552
553 template <>
554 Q_STATIC_TEMPLATE_SPECIALIZATION const uint * QT_FASTCALL
555 qt_fetchUntransformed<QImage::Format_ARGB32_Premultiplied>(uint *, const Operator *,
556                                                          const QSpanData *data,
557                                                          int y, int x, int)
558 {
559     const uchar *scanLine = data->texture.scanLine(y);
560     return ((const uint *)scanLine) + x;
561 }
562
563 template<TextureBlendType blendType>  /* either BlendTransformed or BlendTransformedTiled */
564 Q_STATIC_TEMPLATE_FUNCTION
565 const uint * QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data,
566                                                          int y, int x, int length)
567 {
568     FetchPixelProc fetch = fetchPixelProc[data->texture.format];
569
570     int image_width = data->texture.width;
571     int image_height = data->texture.height;
572
573     const qreal cx = x + 0.5;
574     const qreal cy = y + 0.5;
575
576     const uint *end = buffer + length;
577     uint *b = buffer;
578     if (data->fast_matrix) {
579         // The increment pr x in the scanline
580         int fdx = (int)(data->m11 * fixed_scale);
581         int fdy = (int)(data->m12 * fixed_scale);
582
583         int fx = int((data->m21 * cy
584                       + data->m11 * cx + data->dx) * fixed_scale);
585         int fy = int((data->m22 * cy
586                       + data->m12 * cx + data->dy) * fixed_scale);
587
588         while (b < end) {
589             int px = fx >> 16;
590             int py = fy >> 16;
591
592             if (blendType == BlendTransformedTiled) {
593                 px %= image_width;
594                 py %= image_height;
595                 if (px < 0) px += image_width;
596                 if (py < 0) py += image_height;
597
598                 const uchar *scanLine = data->texture.scanLine(py);
599                 *b = fetch(scanLine, px, data->texture.colorTable);
600             } else {
601                 if ((px < 0) || (px >= image_width)
602                     || (py < 0) || (py >= image_height)) {
603                     *b = uint(0);
604                 } else {
605                     const uchar *scanLine = data->texture.scanLine(py);
606                     *b = fetch(scanLine, px, data->texture.colorTable);
607                 }
608             }
609             fx += fdx;
610             fy += fdy;
611             ++b;
612         }
613     } else {
614         const qreal fdx = data->m11;
615         const qreal fdy = data->m12;
616         const qreal fdw = data->m13;
617
618         qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
619         qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
620         qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
621
622         while (b < end) {
623             const qreal iw = fw == 0 ? 1 : 1 / fw;
624             const qreal tx = fx * iw;
625             const qreal ty = fy * iw;
626             int px = int(tx) - (tx < 0);
627             int py = int(ty) - (ty < 0);
628
629             if (blendType == BlendTransformedTiled) {
630                 px %= image_width;
631                 py %= image_height;
632                 if (px < 0) px += image_width;
633                 if (py < 0) py += image_height;
634
635                 const uchar *scanLine = data->texture.scanLine(py);
636                 *b = fetch(scanLine, px, data->texture.colorTable);
637             } else {
638                 if ((px < 0) || (px >= image_width)
639                     || (py < 0) || (py >= image_height)) {
640                     *b = uint(0);
641                 } else {
642                     const uchar *scanLine = data->texture.scanLine(py);
643                     *b = fetch(scanLine, px, data->texture.colorTable);
644                 }
645             }
646             fx += fdx;
647             fy += fdy;
648             fw += fdw;
649             //force increment to avoid /0
650             if (!fw) {
651                 fw += fdw;
652             }
653             ++b;
654         }
655     }
656
657     return buffer;
658 }
659
660 /** \internal
661   interpolate 4 argb pixels with the distx and disty factor.
662   distx and disty bust be between 0 and 16
663  */
664 static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, int distx, int disty)
665 {
666     uint distxy = distx * disty;
667     //idistx * disty = (16-distx) * disty = 16*disty - distxy
668     //idistx * idisty = (16-distx) * (16-disty) = 16*16 - 16*distx -16*dity + distxy
669     uint tlrb = (tl & 0x00ff00ff)         * (16*16 - 16*distx - 16*disty + distxy);
670     uint tlag = ((tl & 0xff00ff00) >> 8)  * (16*16 - 16*distx - 16*disty + distxy);
671     uint trrb = ((tr & 0x00ff00ff)        * (distx*16 - distxy));
672     uint trag = (((tr & 0xff00ff00) >> 8) * (distx*16 - distxy));
673     uint blrb = ((bl & 0x00ff00ff)        * (disty*16 - distxy));
674     uint blag = (((bl & 0xff00ff00) >> 8) * (disty*16 - distxy));
675     uint brrb = ((br & 0x00ff00ff)        * (distxy));
676     uint brag = (((br & 0xff00ff00) >> 8) * (distxy));
677     return (((tlrb + trrb + blrb + brrb) >> 8) & 0x00ff00ff) | ((tlag + trag + blag + brag) & 0xff00ff00);
678 }
679
680 #if defined(QT_ALWAYS_HAVE_SSE2)
681 #define interpolate_4_pixels_16_sse2(tl, tr, bl, br, distx, disty, colorMask, v_256, b)  \
682 { \
683     const __m128i dxdy = _mm_mullo_epi16 (distx, disty); \
684     const __m128i distx_ = _mm_slli_epi16(distx, 4); \
685     const __m128i disty_ = _mm_slli_epi16(disty, 4); \
686     const __m128i idxidy =  _mm_add_epi16(dxdy, _mm_sub_epi16(v_256, _mm_add_epi16(distx_, disty_))); \
687     const __m128i dxidy =  _mm_sub_epi16(distx_, dxdy); \
688     const __m128i idxdy =  _mm_sub_epi16(disty_, dxdy); \
689  \
690     __m128i tlAG = _mm_srli_epi16(tl, 8); \
691     __m128i tlRB = _mm_and_si128(tl, colorMask); \
692     __m128i trAG = _mm_srli_epi16(tr, 8); \
693     __m128i trRB = _mm_and_si128(tr, colorMask); \
694     __m128i blAG = _mm_srli_epi16(bl, 8); \
695     __m128i blRB = _mm_and_si128(bl, colorMask); \
696     __m128i brAG = _mm_srli_epi16(br, 8); \
697     __m128i brRB = _mm_and_si128(br, colorMask); \
698  \
699     tlAG = _mm_mullo_epi16(tlAG, idxidy); \
700     tlRB = _mm_mullo_epi16(tlRB, idxidy); \
701     trAG = _mm_mullo_epi16(trAG, dxidy); \
702     trRB = _mm_mullo_epi16(trRB, dxidy); \
703     blAG = _mm_mullo_epi16(blAG, idxdy); \
704     blRB = _mm_mullo_epi16(blRB, idxdy); \
705     brAG = _mm_mullo_epi16(brAG, dxdy); \
706     brRB = _mm_mullo_epi16(brRB, dxdy); \
707  \
708     /* Add the values, and shift to only keep 8 significant bits per colors */ \
709     __m128i rAG =_mm_add_epi16(_mm_add_epi16(tlAG, trAG), _mm_add_epi16(blAG, brAG)); \
710     __m128i rRB =_mm_add_epi16(_mm_add_epi16(tlRB, trRB), _mm_add_epi16(blRB, brRB)); \
711     rAG = _mm_andnot_si128(colorMask, rAG); \
712     rRB = _mm_srli_epi16(rRB, 8); \
713     _mm_storeu_si128((__m128i*)(b), _mm_or_si128(rAG, rRB)); \
714 }
715 #endif
716
717 #if defined(QT_ALWAYS_HAVE_NEON)
718 #define interpolate_4_pixels_16_neon(tl, tr, bl, br, distx, disty, disty_, colorMask, invColorMask, v_256, b)  \
719 { \
720     const int16x8_t dxdy = vmulq_s16(distx, disty); \
721     const int16x8_t distx_ = vshlq_n_s16(distx, 4); \
722     const int16x8_t idxidy =  vaddq_s16(dxdy, vsubq_s16(v_256, vaddq_s16(distx_, disty_))); \
723     const int16x8_t dxidy =  vsubq_s16(distx_, dxdy); \
724     const int16x8_t idxdy =  vsubq_s16(disty_, dxdy); \
725  \
726     int16x8_t tlAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tl), 8)); \
727     int16x8_t tlRB = vandq_s16(tl, colorMask); \
728     int16x8_t trAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tr), 8)); \
729     int16x8_t trRB = vandq_s16(tr, colorMask); \
730     int16x8_t blAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bl), 8)); \
731     int16x8_t blRB = vandq_s16(bl, colorMask); \
732     int16x8_t brAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(br), 8)); \
733     int16x8_t brRB = vandq_s16(br, colorMask); \
734  \
735     int16x8_t rAG = vmulq_s16(tlAG, idxidy); \
736     int16x8_t rRB = vmulq_s16(tlRB, idxidy); \
737     rAG = vmlaq_s16(rAG, trAG, dxidy); \
738     rRB = vmlaq_s16(rRB, trRB, dxidy); \
739     rAG = vmlaq_s16(rAG, blAG, idxdy); \
740     rRB = vmlaq_s16(rRB, blRB, idxdy); \
741     rAG = vmlaq_s16(rAG, brAG, dxdy); \
742     rRB = vmlaq_s16(rRB, brRB, dxdy); \
743  \
744     rAG = vandq_s16(invColorMask, rAG); \
745     rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8)); \
746     vst1q_s16((int16_t*)(b), vorrq_s16(rAG, rRB)); \
747 }
748 #endif
749
750 template<TextureBlendType blendType>
751 Q_STATIC_TEMPLATE_FUNCTION inline void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2)
752 {
753     if (blendType == BlendTransformedBilinearTiled) {
754         v1 %= max;
755         if (v1 < 0) v1 += max;
756         v2 = v1 + 1;
757         v2 %= max;
758     } else {
759         if (v1 < l1) {
760             v2 = v1 = l1;
761         } else if (v1 >= l2) {
762             v2 = v1 = l2;
763         } else {
764             v2 = v1 + 1;
765         }
766     }
767
768     Q_ASSERT(v1 >= 0 && v1 < max);
769     Q_ASSERT(v2 >= 0 && v2 < max);
770 }
771
772 template<TextureBlendType blendType, QImage::Format format> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
773 Q_STATIC_TEMPLATE_FUNCTION
774 const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *, const QSpanData *data,
775                                                   int y, int x, int length)
776 {
777 #ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
778     FetchPixelProc fetch;
779     if (format != QImage::Format_Invalid)
780         fetch = qt_fetchPixel<format>;
781     else
782         fetch = fetchPixelProc[data->texture.format];
783 #else
784     FetchPixelProc fetch = (format != QImage::Format_Invalid) ? FetchPixelProc(qt_fetchPixel<format>) : fetchPixelProc[data->texture.format];
785 #endif
786
787     int image_width = data->texture.width;
788     int image_height = data->texture.height;
789
790     int image_x1 = data->texture.x1;
791     int image_y1 = data->texture.y1;
792     int image_x2 = data->texture.x2 - 1;
793     int image_y2 = data->texture.y2 - 1;
794
795     const qreal cx = x + 0.5;
796     const qreal cy = y + 0.5;
797
798     uint *end = buffer + length;
799     uint *b = buffer;
800     if (data->fast_matrix) {
801         // The increment pr x in the scanline
802         int fdx = (int)(data->m11 * fixed_scale);
803         int fdy = (int)(data->m12 * fixed_scale);
804
805         int fx = int((data->m21 * cy
806                       + data->m11 * cx + data->dx) * fixed_scale);
807         int fy = int((data->m22 * cy
808                       + data->m12 * cx + data->dy) * fixed_scale);
809
810         fx -= half_point;
811         fy -= half_point;
812
813         if (fdy == 0) { //simple scale, no rotation
814             int y1 = (fy >> 16);
815             int y2;
816             fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
817             const uchar *s1 = data->texture.scanLine(y1);
818             const uchar *s2 = data->texture.scanLine(y2);
819
820             if (fdx <= fixed_scale && fdx > 0) { // scale up on X
821                 int disty = (fy & 0x0000ffff) >> 8;
822                 int idisty = 256 - disty;
823                 int x = fx >> 16;
824
825                 // The idea is first to do the interpolation between the row s1 and the row s2
826                 // into an intermediate buffer, then we interpolate between two pixel of this buffer.
827
828                 // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
829                 // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG
830                 quint32 intermediate_buffer[2][buffer_size + 2];
831                 // count is the size used in the intermediate_buffer.
832                 int count = qCeil(length * data->m11) + 2; //+1 for the last pixel to interpolate with, and +1 for rounding errors.
833                 Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
834                 int f = 0;
835                 int lim = count;
836                 if (blendType == BlendTransformedBilinearTiled) {
837                     x %= image_width;
838                     if (x < 0) x += image_width;
839                 } else {
840                     lim = qMin(count, image_x2-x+1);
841                     if (x < image_x1) {
842                         Q_ASSERT(x <= image_x2);
843                         uint t = fetch(s1, image_x1, data->texture.colorTable);
844                         uint b = fetch(s2, image_x1, data->texture.colorTable);
845                         quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
846                         quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
847                         do {
848                             intermediate_buffer[0][f] = rb;
849                             intermediate_buffer[1][f] = ag;
850                             f++;
851                             x++;
852                         } while (x < image_x1 && f < lim);
853                     }
854                 }
855
856                 if (blendType != BlendTransformedBilinearTiled &&
857                         (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)) {
858 #if defined(QT_ALWAYS_HAVE_SSE2)
859                     const __m128i disty_ = _mm_set1_epi16(disty);
860                     const __m128i idisty_ = _mm_set1_epi16(idisty);
861                     const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
862
863                     lim -= 3;
864                     for (; f < lim; x += 4, f += 4) {
865                         // Load 4 pixels from s1, and split the alpha-green and red-blue component
866                         __m128i top = _mm_loadu_si128((__m128i*)((const uint *)(s1)+x));
867                         __m128i topAG = _mm_srli_epi16(top, 8);
868                         __m128i topRB = _mm_and_si128(top, colorMask);
869                         // Multiplies each colour component by idisty
870                         topAG = _mm_mullo_epi16 (topAG, idisty_);
871                         topRB = _mm_mullo_epi16 (topRB, idisty_);
872
873                         // Same for the s2 vector
874                         __m128i bottom = _mm_loadu_si128((__m128i*)((const uint *)(s2)+x));
875                         __m128i bottomAG = _mm_srli_epi16(bottom, 8);
876                         __m128i bottomRB = _mm_and_si128(bottom, colorMask);
877                         bottomAG = _mm_mullo_epi16 (bottomAG, disty_);
878                         bottomRB = _mm_mullo_epi16 (bottomRB, disty_);
879
880                         // Add the values, and shift to only keep 8 significant bits per colors
881                         __m128i rAG =_mm_add_epi16(topAG, bottomAG);
882                         rAG = _mm_srli_epi16(rAG, 8);
883                         _mm_storeu_si128((__m128i*)(&intermediate_buffer[1][f]), rAG);
884                         __m128i rRB =_mm_add_epi16(topRB, bottomRB);
885                         rRB = _mm_srli_epi16(rRB, 8);
886                         _mm_storeu_si128((__m128i*)(&intermediate_buffer[0][f]), rRB);
887                     }
888 #elif defined(QT_ALWAYS_HAVE_NEON)
889                     const int16x8_t disty_ = vdupq_n_s16(disty);
890                     const int16x8_t idisty_ = vdupq_n_s16(idisty);
891                     const int16x8_t colorMask = vdupq_n_s16(0x00ff);
892
893                     lim -= 3;
894                     for (; f < lim; x += 4, f += 4) {
895                         // Load 4 pixels from s1, and split the alpha-green and red-blue component
896                         int16x8_t top = vld1q_s16((int16_t*)((const uint *)(s1)+x));
897                         int16x8_t topAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(top), 8));
898                         int16x8_t topRB = vandq_s16(top, colorMask);
899                         // Multiplies each colour component by idisty
900                         topAG = vmulq_s16(topAG, idisty_);
901                         topRB = vmulq_s16(topRB, idisty_);
902
903                         // Same for the s2 vector
904                         int16x8_t bottom = vld1q_s16((int16_t*)((const uint *)(s2)+x));
905                         int16x8_t bottomAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bottom), 8));
906                         int16x8_t bottomRB = vandq_s16(bottom, colorMask);
907                         bottomAG = vmulq_s16(bottomAG, disty_);
908                         bottomRB = vmulq_s16(bottomRB, disty_);
909
910                         // Add the values, and shift to only keep 8 significant bits per colors
911                         int16x8_t rAG = vaddq_s16(topAG, bottomAG);
912                         rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8));
913                         vst1q_s16((int16_t*)(&intermediate_buffer[1][f]), rAG);
914                         int16x8_t rRB = vaddq_s16(topRB, bottomRB);
915                         rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8));
916                         vst1q_s16((int16_t*)(&intermediate_buffer[0][f]), rRB);
917                     }
918 #endif
919                 }
920                 for (; f < count; f++) { // Same as above but without sse2
921                     if (blendType == BlendTransformedBilinearTiled) {
922                         if (x >= image_width) x -= image_width;
923                     } else {
924                         x = qMin(x, image_x2);
925                     }
926
927                     uint t = fetch(s1, x, data->texture.colorTable);
928                     uint b = fetch(s2, x, data->texture.colorTable);
929
930                     intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
931                     intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
932                     x++;
933                 }
934                 // Now interpolate the values from the intermediate_buffer to get the final result.
935                 fx &= fixed_scale - 1;
936                 Q_ASSERT((fx >> 16) == 0);
937                 while (b < end) {
938                     register int x1 = (fx >> 16);
939                     register int x2 = x1 + 1;
940                     Q_ASSERT(x1 >= 0);
941                     Q_ASSERT(x2 < count);
942
943                     register int distx = (fx & 0x0000ffff) >> 8;
944                     register int idistx = 256 - distx;
945                     int rb = ((intermediate_buffer[0][x1] * idistx + intermediate_buffer[0][x2] * distx) >> 8) & 0xff00ff;
946                     int ag = (intermediate_buffer[1][x1] * idistx + intermediate_buffer[1][x2] * distx) & 0xff00ff00;
947                     *b = rb | ag;
948                     b++;
949                     fx += fdx;
950                 }
951             } else if ((fdx < 0 && fdx > -(fixed_scale / 8)) || fabs(data->m22) < (1./8.)) { // scale up more than 8x
952                 int y1 = (fy >> 16);
953                 int y2;
954                 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
955                 const uchar *s1 = data->texture.scanLine(y1);
956                 const uchar *s2 = data->texture.scanLine(y2);
957                 int disty = (fy & 0x0000ffff) >> 8;
958                 int idisty = 256 - disty;
959                 while (b < end) {
960                     int x1 = (fx >> 16);
961                     int x2;
962                     fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
963                     uint tl = fetch(s1, x1, data->texture.colorTable);
964                     uint tr = fetch(s1, x2, data->texture.colorTable);
965                     uint bl = fetch(s2, x1, data->texture.colorTable);
966                     uint br = fetch(s2, x2, data->texture.colorTable);
967
968                     int distx = (fx & 0x0000ffff) >> 8;
969                     int idistx = 256 - distx;
970
971                     uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
972                     uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
973                     *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
974
975                     fx += fdx;
976                     ++b;
977                 }
978             } else { //scale down
979                 int y1 = (fy >> 16);
980                 int y2;
981                 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
982                 const uchar *s1 = data->texture.scanLine(y1);
983                 const uchar *s2 = data->texture.scanLine(y2);
984                 int disty = (fy & 0x0000ffff) >> 12;
985
986                 if (blendType != BlendTransformedBilinearTiled &&
987                     (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)) {
988
989 #define BILINEAR_DOWNSCALE_BOUNDS_PROLOG \
990                     while (b < end) { \
991                         int x1 = (fx >> 16); \
992                         int x2; \
993                         fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); \
994                         if (x1 != x2) \
995                             break; \
996                         uint tl = fetch(s1, x1, data->texture.colorTable); \
997                         uint tr = fetch(s1, x2, data->texture.colorTable); \
998                         uint bl = fetch(s2, x1, data->texture.colorTable); \
999                         uint br = fetch(s2, x2, data->texture.colorTable); \
1000                         int distx = (fx & 0x0000ffff) >> 12; \
1001                         *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty); \
1002                         fx += fdx; \
1003                         ++b; \
1004                     } \
1005                     uint *boundedEnd; \
1006                     if (fdx > 0) \
1007                         boundedEnd = qMin(end, buffer + uint((image_x2 - (fx >> 16)) / data->m11)); \
1008                     else \
1009                         boundedEnd = qMin(end, buffer + uint((image_x1 - (fx >> 16)) / data->m11)); \
1010                     boundedEnd -= 3;
1011
1012 #if defined(QT_ALWAYS_HAVE_SSE2)
1013                     BILINEAR_DOWNSCALE_BOUNDS_PROLOG
1014
1015                     const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
1016                     const __m128i v_256 = _mm_set1_epi16(256);
1017                     const __m128i v_disty = _mm_set1_epi16(disty);
1018                     __m128i v_fdx = _mm_set1_epi32(fdx*4);
1019
1020                     ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
1021
1022                     union Vect_buffer { __m128i vect; quint32 i[4]; };
1023                     Vect_buffer v_fx;
1024
1025                     for (int i = 0; i < 4; i++) {
1026                         v_fx.i[i] = fx;
1027                         fx += fdx;
1028                     }
1029
1030                     while (b < boundedEnd) {
1031
1032                         Vect_buffer tl, tr, bl, br;
1033
1034                         for (int i = 0; i < 4; i++) {
1035                             int x1 = v_fx.i[i] >> 16;
1036                             const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1037                             const uint *addr_tr = addr_tl + 1;
1038                             tl.i[i] = *addr_tl;
1039                             tr.i[i] = *addr_tr;
1040                             bl.i[i] = *(addr_tl+secondLine);
1041                             br.i[i] = *(addr_tr+secondLine);
1042                         }
1043                         __m128i v_distx = _mm_srli_epi16(v_fx.vect, 12);
1044                         v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1045                         v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1046
1047                         interpolate_4_pixels_16_sse2(tl.vect, tr.vect, bl.vect, br.vect, v_distx, v_disty, colorMask, v_256, b);
1048                         b+=4;
1049                         v_fx.vect = _mm_add_epi32(v_fx.vect, v_fdx);
1050                     }
1051                     fx = v_fx.i[0];
1052 #elif defined(QT_ALWAYS_HAVE_NEON)
1053                     BILINEAR_DOWNSCALE_BOUNDS_PROLOG
1054
1055                     const int16x8_t colorMask = vdupq_n_s16(0x00ff);
1056                     const int16x8_t invColorMask = vmvnq_s16(colorMask);
1057                     const int16x8_t v_256 = vdupq_n_s16(256);
1058                     const int16x8_t v_disty = vdupq_n_s16(disty);
1059                     const int16x8_t v_disty_ = vshlq_n_s16(v_disty, 4);
1060                     int32x4_t v_fdx = vdupq_n_s32(fdx*4);
1061
1062                     ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
1063
1064                     union Vect_buffer { int32x4_t vect; quint32 i[4]; };
1065                     Vect_buffer v_fx;
1066
1067                     for (int i = 0; i < 4; i++) {
1068                         v_fx.i[i] = fx;
1069                         fx += fdx;
1070                     }
1071
1072                     const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
1073
1074                     while (b < boundedEnd) {
1075
1076                         Vect_buffer tl, tr, bl, br;
1077
1078                         Vect_buffer v_fx_shifted;
1079                         v_fx_shifted.vect = vshrq_n_s32(v_fx.vect, 16);
1080
1081                         int32x4_t v_distx = vshrq_n_s32(vandq_s32(v_fx.vect, v_ffff_mask), 12);
1082
1083                         for (int i = 0; i < 4; i++) {
1084                             int x1 = v_fx_shifted.i[i];
1085                             const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1086                             const uint *addr_tr = addr_tl + 1;
1087                             tl.i[i] = *addr_tl;
1088                             tr.i[i] = *addr_tr;
1089                             bl.i[i] = *(addr_tl+secondLine);
1090                             br.i[i] = *(addr_tr+secondLine);
1091                         }
1092
1093                         v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
1094
1095                         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);
1096                         b+=4;
1097                         v_fx.vect = vaddq_s32(v_fx.vect, v_fdx);
1098                     }
1099                     fx = v_fx.i[0];
1100 #endif
1101                 }
1102
1103                 while (b < end) {
1104                     int x1 = (fx >> 16);
1105                     int x2;
1106                     fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1107                     uint tl = fetch(s1, x1, data->texture.colorTable);
1108                     uint tr = fetch(s1, x2, data->texture.colorTable);
1109                     uint bl = fetch(s2, x1, data->texture.colorTable);
1110                     uint br = fetch(s2, x2, data->texture.colorTable);
1111                     int distx = (fx & 0x0000ffff) >> 12;
1112                     *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1113                     fx += fdx;
1114                     ++b;
1115                 }
1116             }
1117         } else { //rotation
1118             if (fabs(data->m11) > 8 || fabs(data->m22) > 8) {
1119                 //if we are zooming more than 8 times, we use 8bit precision for the position.
1120                 while (b < end) {
1121                     int x1 = (fx >> 16);
1122                     int x2;
1123                     int y1 = (fy >> 16);
1124                     int y2;
1125
1126                     fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1127                     fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1128
1129                     const uchar *s1 = data->texture.scanLine(y1);
1130                     const uchar *s2 = data->texture.scanLine(y2);
1131
1132                     uint tl = fetch(s1, x1, data->texture.colorTable);
1133                     uint tr = fetch(s1, x2, data->texture.colorTable);
1134                     uint bl = fetch(s2, x1, data->texture.colorTable);
1135                     uint br = fetch(s2, x2, data->texture.colorTable);
1136
1137                     int distx = (fx & 0x0000ffff) >> 8;
1138                     int disty = (fy & 0x0000ffff) >> 8;
1139                     int idistx = 256 - distx;
1140                     int idisty = 256 - disty;
1141
1142                     uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1143                     uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1144                     *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1145
1146                     fx += fdx;
1147                     fy += fdy;
1148                     ++b;
1149                 }
1150             } else {
1151                 //we are zooming less than 8x, use 4bit precision
1152                 while (b < end) {
1153                     int x1 = (fx >> 16);
1154                     int x2;
1155                     int y1 = (fy >> 16);
1156                     int y2;
1157
1158                     fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1159                     fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1160
1161                     const uchar *s1 = data->texture.scanLine(y1);
1162                     const uchar *s2 = data->texture.scanLine(y2);
1163
1164                     uint tl = fetch(s1, x1, data->texture.colorTable);
1165                     uint tr = fetch(s1, x2, data->texture.colorTable);
1166                     uint bl = fetch(s2, x1, data->texture.colorTable);
1167                     uint br = fetch(s2, x2, data->texture.colorTable);
1168
1169                     int distx = (fx & 0x0000ffff) >> 12;
1170                     int disty = (fy & 0x0000ffff) >> 12;
1171
1172                     *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1173
1174                     fx += fdx;
1175                     fy += fdy;
1176                     ++b;
1177                 }
1178             }
1179         }
1180     } else {
1181         const qreal fdx = data->m11;
1182         const qreal fdy = data->m12;
1183         const qreal fdw = data->m13;
1184
1185         qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
1186         qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
1187         qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
1188
1189         while (b < end) {
1190             const qreal iw = fw == 0 ? 1 : 1 / fw;
1191             const qreal px = fx * iw - 0.5;
1192             const qreal py = fy * iw - 0.5;
1193
1194             int x1 = int(px) - (px < 0);
1195             int x2;
1196             int y1 = int(py) - (py < 0);
1197             int y2;
1198
1199             int distx = int((px - x1) * 256);
1200             int disty = int((py - y1) * 256);
1201             int idistx = 256 - distx;
1202             int idisty = 256 - disty;
1203
1204             fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1205             fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1206
1207             const uchar *s1 = data->texture.scanLine(y1);
1208             const uchar *s2 = data->texture.scanLine(y2);
1209
1210             uint tl = fetch(s1, x1, data->texture.colorTable);
1211             uint tr = fetch(s1, x2, data->texture.colorTable);
1212             uint bl = fetch(s2, x1, data->texture.colorTable);
1213             uint br = fetch(s2, x2, data->texture.colorTable);
1214
1215             uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1216             uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1217             *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1218
1219             fx += fdx;
1220             fy += fdy;
1221             fw += fdw;
1222             //force increment to avoid /0
1223             if (!fw) {
1224                 fw += fdw;
1225             }
1226             ++b;
1227         }
1228     }
1229
1230     return buffer;
1231 }
1232
1233 #define SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Arg) qt_fetchUntransformed<QImage::Arg>
1234
1235 static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = {
1236     // Untransformed
1237     {
1238         0, // Invalid
1239         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono),   // Mono
1240         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB),   // MonoLsb
1241         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8),   // Indexed8
1242         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied),   // RGB32
1243         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32),   // ARGB32
1244         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied),   // ARGB32_Premultiplied
1245         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16),   // RGB16
1246         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
1247         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666),  // RGB666
1248         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
1249         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555),  // RGB555
1250         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
1251         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888),  // RGB888
1252         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444),  // RGB444
1253         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
1254     },
1255     // Tiled
1256     {
1257         0, // Invalid
1258         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono),   // Mono
1259         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB),   // MonoLsb
1260         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8),   // Indexed8
1261         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied),   // RGB32
1262         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32),   // ARGB32
1263         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied),   // ARGB32_Premultiplied
1264         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16),   // RGB16
1265         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
1266         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666),  // RGB666
1267         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
1268         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555),  // RGB555
1269         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
1270         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888),  // RGB888
1271         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444),  // RGB444
1272         SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
1273     },
1274     // Transformed
1275     {
1276         0, // Invalid
1277         fetchTransformed<BlendTransformed>,   // Mono
1278         fetchTransformed<BlendTransformed>,   // MonoLsb
1279         fetchTransformed<BlendTransformed>,   // Indexed8
1280         fetchTransformed<BlendTransformed>,   // RGB32
1281         fetchTransformed<BlendTransformed>,   // ARGB32
1282         fetchTransformed<BlendTransformed>,   // ARGB32_Premultiplied
1283         fetchTransformed<BlendTransformed>,   // RGB16
1284         fetchTransformed<BlendTransformed>,   // ARGB8565_Premultiplied
1285         fetchTransformed<BlendTransformed>,   // RGB666
1286         fetchTransformed<BlendTransformed>,   // ARGB6666_Premultiplied
1287         fetchTransformed<BlendTransformed>,   // RGB555
1288         fetchTransformed<BlendTransformed>,   // ARGB8555_Premultiplied
1289         fetchTransformed<BlendTransformed>,   // RGB888
1290         fetchTransformed<BlendTransformed>,   // RGB444
1291         fetchTransformed<BlendTransformed>,   // ARGB4444_Premultiplied
1292     },
1293     {
1294         0, // TransformedTiled
1295         fetchTransformed<BlendTransformedTiled>,   // Mono
1296         fetchTransformed<BlendTransformedTiled>,   // MonoLsb
1297         fetchTransformed<BlendTransformedTiled>,   // Indexed8
1298         fetchTransformed<BlendTransformedTiled>,   // RGB32
1299         fetchTransformed<BlendTransformedTiled>,   // ARGB32
1300         fetchTransformed<BlendTransformedTiled>,   // ARGB32_Premultiplied
1301         fetchTransformed<BlendTransformedTiled>,   // RGB16
1302         fetchTransformed<BlendTransformedTiled>,   // ARGB8565_Premultiplied
1303         fetchTransformed<BlendTransformedTiled>,   // RGB666
1304         fetchTransformed<BlendTransformedTiled>,   // ARGB6666_Premultiplied
1305         fetchTransformed<BlendTransformedTiled>,   // RGB555
1306         fetchTransformed<BlendTransformedTiled>,   // ARGB8555_Premultiplied
1307         fetchTransformed<BlendTransformedTiled>,   // RGB888
1308         fetchTransformed<BlendTransformedTiled>,   // RGB444
1309         fetchTransformed<BlendTransformedTiled>,   // ARGB4444_Premultiplied
1310     },
1311     {
1312         0, // Bilinear
1313         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // Mono
1314         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // MonoLsb
1315         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // Indexed8
1316         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>,   // RGB32
1317         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32>,   // ARGB32
1318         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>,   // ARGB32_Premultiplied
1319         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // RGB16
1320         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // ARGB8565_Premultiplied
1321         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // RGB666
1322         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // ARGB6666_Premultiplied
1323         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // RGB555
1324         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // ARGB8555_Premultiplied
1325         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // RGB888
1326         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>,   // RGB444
1327         fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>    // ARGB4444_Premultiplied
1328     },
1329     {
1330         0, // BilinearTiled
1331         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // Mono
1332         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // MonoLsb
1333         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // Indexed8
1334         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>,   // RGB32
1335         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32>,   // ARGB32
1336         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>,   // ARGB32_Premultiplied
1337         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // RGB16
1338         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // ARGB8565_Premultiplied
1339         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // RGB666
1340         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // ARGB6666_Premultiplied
1341         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // RGB555
1342         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // ARGB8555_Premultiplied
1343         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // RGB888
1344         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>,   // RGB444
1345         fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>    // ARGB4444_Premultiplied
1346     },
1347 };
1348
1349
1350 static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos)
1351 {
1352     int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + 0.5);
1353
1354   // calculate the actual offset.
1355     if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
1356         if (data->spread == QGradient::RepeatSpread) {
1357             ipos = ipos % GRADIENT_STOPTABLE_SIZE;
1358             ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
1359
1360         } else if (data->spread == QGradient::ReflectSpread) {
1361             const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
1362             ipos = ipos % limit;
1363             ipos = ipos < 0 ? limit + ipos : ipos;
1364             ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
1365
1366         } else {
1367             if (ipos < 0) ipos = 0;
1368             else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
1369         }
1370     }
1371
1372     Q_ASSERT(ipos >= 0);
1373     Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
1374
1375     return data->colorTable[ipos];
1376 }
1377
1378 #define FIXPT_BITS 8
1379 #define FIXPT_SIZE (1<<FIXPT_BITS)
1380
1381 static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
1382 {
1383     int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
1384
1385     // calculate the actual offset.
1386     if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
1387         if (data->spread == QGradient::RepeatSpread) {
1388             ipos = ipos % GRADIENT_STOPTABLE_SIZE;
1389             ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
1390
1391         } else if (data->spread == QGradient::ReflectSpread) {
1392             const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
1393             ipos = ipos % limit;
1394             ipos = ipos < 0 ? limit + ipos : ipos;
1395             ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
1396
1397         } else {
1398             if (ipos < 0) ipos = 0;
1399             else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
1400         }
1401     }
1402
1403     Q_ASSERT(ipos >= 0);
1404     Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
1405
1406     return data->colorTable[ipos];
1407 }
1408
1409 static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
1410 {
1411     v->dx = data->gradient.linear.end.x - data->gradient.linear.origin.x;
1412     v->dy = data->gradient.linear.end.y - data->gradient.linear.origin.y;
1413     v->l = v->dx * v->dx + v->dy * v->dy;
1414     v->off = 0;
1415     if (v->l != 0) {
1416         v->dx /= v->l;
1417         v->dy /= v->l;
1418         v->off = -v->dx * data->gradient.linear.origin.x - v->dy * data->gradient.linear.origin.y;
1419     }
1420 }
1421
1422 static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator *op, const QSpanData *data,
1423                                                     int y, int x, int length)
1424 {
1425     const uint *b = buffer;
1426     qreal t, inc;
1427
1428     bool affine = true;
1429     qreal rx=0, ry=0;
1430     if (op->linear.l == 0) {
1431         t = inc = 0;
1432     } else {
1433         rx = data->m21 * (y + 0.5) + data->m11 * (x + 0.5) + data->dx;
1434         ry = data->m22 * (y + 0.5) + data->m12 * (x + 0.5) + data->dy;
1435         t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off;
1436         inc = op->linear.dx * data->m11 + op->linear.dy * data->m12;
1437         affine = !data->m13 && !data->m23;
1438
1439         if (affine) {
1440             t *= (GRADIENT_STOPTABLE_SIZE - 1);
1441             inc *= (GRADIENT_STOPTABLE_SIZE - 1);
1442         }
1443     }
1444
1445     const uint *end = buffer + length;
1446     if (affine) {
1447         if (inc > -1e-5 && inc < 1e-5) {
1448             QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE)));
1449         } else {
1450             if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) &&
1451                 t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) {
1452                 // we can use fixed point math
1453                 int t_fixed = int(t * FIXPT_SIZE);
1454                 int inc_fixed = int(inc * FIXPT_SIZE);
1455                 while (buffer < end) {
1456                     *buffer = qt_gradient_pixel_fixed(&data->gradient, t_fixed);
1457                     t_fixed += inc_fixed;
1458                     ++buffer;
1459                 }
1460             } else {
1461                 // we have to fall back to float math
1462                 while (buffer < end) {
1463                     *buffer = qt_gradient_pixel(&data->gradient, t/GRADIENT_STOPTABLE_SIZE);
1464                     t += inc;
1465                     ++buffer;
1466                 }
1467             }
1468         }
1469     } else { // fall back to float math here as well
1470         qreal rw = data->m23 * (y + 0.5) + data->m13 * (x + 0.5) + data->m33;
1471         while (buffer < end) {
1472             qreal x = rx/rw;
1473             qreal y = ry/rw;
1474             t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off;
1475
1476             *buffer = qt_gradient_pixel(&data->gradient, t);
1477             rx += data->m11;
1478             ry += data->m12;
1479             rw += data->m13;
1480             if (!rw) {
1481                 rw += data->m13;
1482             }
1483             ++buffer;
1484         }
1485     }
1486
1487     return b;
1488 }
1489
1490 static inline qreal determinant(qreal a, qreal b, qreal c)
1491 {
1492     return (b * b) - (4 * a * c);
1493 }
1494
1495 // function to evaluate real roots
1496 static inline qreal realRoots(qreal a, qreal b, qreal detSqrt)
1497 {
1498     return (-b + detSqrt)/(2 * a);
1499 }
1500
1501 static inline qreal qSafeSqrt(qreal x)
1502 {
1503     return x > 0 ? qSqrt(x) : 0;
1504 }
1505
1506 static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
1507 {
1508     v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x;
1509     v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y;
1510     v->a = data->gradient.radial.radius*data->gradient.radial.radius - v->dx*v->dx - v->dy*v->dy;
1511 }
1512
1513 static const uint * QT_FASTCALL fetchRadialGradient(uint *buffer, const Operator *op, const QSpanData *data,
1514                                                     int y, int x, int length)
1515 {
1516     const uint *b = buffer;
1517     qreal rx = data->m21 * (y + 0.5)
1518                + data->dx + data->m11 * (x + 0.5);
1519     qreal ry = data->m22 * (y + 0.5)
1520                + data->dy + data->m12 * (x + 0.5);
1521     bool affine = !data->m13 && !data->m23;
1522     //qreal r  = data->gradient.radial.radius;
1523
1524     const uint *end = buffer + length;
1525     if (affine) {
1526         rx -= data->gradient.radial.focal.x;
1527         ry -= data->gradient.radial.focal.y;
1528
1529         qreal inv_a = 1 / qreal(2 * op->radial.a);
1530
1531         const qreal delta_rx = data->m11;
1532         const qreal delta_ry = data->m12;
1533
1534         qreal b = 2*(rx * op->radial.dx + ry * op->radial.dy);
1535         qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy);
1536         const qreal b_delta_b = 2 * b * delta_b;
1537         const qreal delta_b_delta_b = 2 * delta_b * delta_b;
1538
1539         const qreal bb = b * b;
1540         const qreal delta_bb = delta_b * delta_b;
1541
1542         b *= inv_a;
1543         delta_b *= inv_a;
1544
1545         const qreal rxrxryry = rx * rx + ry * ry;
1546         const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry;
1547         const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry);
1548         const qreal delta_rx_plus_ry = 2 * delta_rxrxryry;
1549
1550         inv_a *= inv_a;
1551
1552         qreal det = (bb + 4 * op->radial.a * rxrxryry) * inv_a;
1553         qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a;
1554         const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a;
1555
1556         while (buffer < end) {
1557             *buffer = qt_gradient_pixel(&data->gradient, qSafeSqrt(det) - b);
1558
1559             det += delta_det;
1560             delta_det += delta_delta_det;
1561             b += delta_b;
1562
1563             ++buffer;
1564         }
1565     } else {
1566         qreal rw = data->m23 * (y + 0.5)
1567                    + data->m33 + data->m13 * (x + 0.5);
1568         if (!rw)
1569             rw = 1;
1570         while (buffer < end) {
1571             qreal gx = rx/rw - data->gradient.radial.focal.x;
1572             qreal gy = ry/rw - data->gradient.radial.focal.y;
1573             qreal b  = 2*(gx*op->radial.dx + gy*op->radial.dy);
1574             qreal det = determinant(op->radial.a, b , -(gx*gx + gy*gy));
1575             qreal s = realRoots(op->radial.a, b, qSafeSqrt(det));
1576
1577             *buffer = qt_gradient_pixel(&data->gradient, s);
1578
1579             rx += data->m11;
1580             ry += data->m12;
1581             rw += data->m13;
1582             if (!rw) {
1583                 rw += data->m13;
1584             }
1585             ++buffer;
1586         }
1587     }
1588
1589     return b;
1590 }
1591
1592 static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operator *, const QSpanData *data,
1593                                                      int y, int x, int length)
1594 {
1595     const uint *b = buffer;
1596     qreal rx = data->m21 * (y + 0.5)
1597                + data->dx + data->m11 * (x + 0.5);
1598     qreal ry = data->m22 * (y + 0.5)
1599                + data->dy + data->m12 * (x + 0.5);
1600     bool affine = !data->m13 && !data->m23;
1601
1602     const uint *end = buffer + length;
1603     if (affine) {
1604         rx -= data->gradient.conical.center.x;
1605         ry -= data->gradient.conical.center.y;
1606         while (buffer < end) {
1607             qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle;
1608
1609             *buffer = qt_gradient_pixel(&data->gradient, 1 - angle / (2*Q_PI));
1610
1611             rx += data->m11;
1612             ry += data->m12;
1613             ++buffer;
1614         }
1615     } else {
1616         qreal rw = data->m23 * (y + 0.5)
1617                    + data->m33 + data->m13 * (x + 0.5);
1618         if (!rw)
1619             rw = 1;
1620         while (buffer < end) {
1621             qreal angle = qAtan2(ry/rw - data->gradient.conical.center.x,
1622                                 rx/rw - data->gradient.conical.center.y)
1623                           + data->gradient.conical.angle;
1624
1625             *buffer = qt_gradient_pixel(&data->gradient, 1. - angle / (2*Q_PI));
1626
1627             rx += data->m11;
1628             ry += data->m12;
1629             rw += data->m13;
1630             if (!rw) {
1631                 rw += data->m13;
1632             }
1633             ++buffer;
1634         }
1635     }
1636     return b;
1637 }
1638
1639 #if defined(Q_CC_RVCT)
1640 // Force ARM code generation for comp_func_* -methods
1641 #  pragma push
1642 #  pragma arm
1643 #  if defined(QT_HAVE_ARMV6)
1644 static __forceinline void preload(const uint *start)
1645 {
1646     asm( "pld [start]" );
1647 }
1648 static const uint L2CacheLineLength = 32;
1649 static const uint L2CacheLineLengthInInts = L2CacheLineLength/sizeof(uint);
1650 #    define PRELOAD_INIT(x) preload(x);
1651 #    define PRELOAD_INIT2(x,y) PRELOAD_INIT(x) PRELOAD_INIT(y)
1652 #    define PRELOAD_COND(x) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts);
1653 // Two consecutive preloads stall, so space them out a bit by using different modulus.
1654 #    define PRELOAD_COND2(x,y) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); \
1655          if (((uint)&y[i])%L2CacheLineLength == 16) preload(&y[i] + L2CacheLineLengthInInts);
1656 #  endif // QT_HAVE_ARMV6
1657 #endif // Q_CC_RVCT
1658
1659 #if !defined(Q_CC_RVCT) || !defined(QT_HAVE_ARMV6)
1660 #    define PRELOAD_INIT(x)
1661 #    define PRELOAD_INIT2(x,y)
1662 #    define PRELOAD_COND(x)
1663 #    define PRELOAD_COND2(x,y)
1664 #endif
1665
1666 /* The constant alpha factor describes an alpha factor that gets applied
1667    to the result of the composition operation combining it with the destination.
1668
1669    The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1.
1670    we get the unmodified operation
1671
1672    result = src op dest
1673    dest = result * const_alpha + dest * (1. - const_alpha)
1674
1675    This means that in the comments below, the first line is the const_alpha==255 case, the
1676    second line the general one.
1677
1678    In the lines below:
1679    s == src, sa == alpha(src), sia = 1 - alpha(src)
1680    d == dest, da == alpha(dest), dia = 1 - alpha(dest)
1681    ca = const_alpha, cia = 1 - const_alpha
1682
1683    The methods exist in two variants. One where we have a constant source, the other
1684    where the source is an array of pixels.
1685 */
1686
1687 /*
1688   result = 0
1689   d = d * cia
1690 */
1691 #define comp_func_Clear_impl(dest, length, const_alpha)\
1692 {\
1693     if (const_alpha == 255) {\
1694         QT_MEMFILL_UINT(dest, length, 0);\
1695     } else {\
1696         int ialpha = 255 - const_alpha;\
1697         PRELOAD_INIT(dest)\
1698         for (int i = 0; i < length; ++i) {\
1699             PRELOAD_COND(dest)\
1700             dest[i] = BYTE_MUL(dest[i], ialpha);\
1701         }\
1702     }\
1703 }
1704
1705 void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
1706 {
1707     comp_func_Clear_impl(dest, length, const_alpha);
1708 }
1709
1710 void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
1711 {
1712     comp_func_Clear_impl(dest, length, const_alpha);
1713 }
1714
1715 /*
1716   result = s
1717   dest = s * ca + d * cia
1718 */
1719 void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha)
1720 {
1721     if (const_alpha == 255) {
1722         QT_MEMFILL_UINT(dest, length, color);
1723     } else {
1724         int ialpha = 255 - const_alpha;
1725         color = BYTE_MUL(color, const_alpha);
1726         PRELOAD_INIT(dest)
1727         for (int i = 0; i < length; ++i) {
1728             PRELOAD_COND(dest)
1729             dest[i] = color + BYTE_MUL(dest[i], ialpha);
1730         }
1731     }
1732 }
1733
1734 void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length, uint const_alpha)
1735 {
1736     if (const_alpha == 255) {
1737         ::memcpy(dest, src, length * sizeof(uint));
1738     } else {
1739         int ialpha = 255 - const_alpha;
1740         PRELOAD_INIT2(dest, src)
1741         for (int i = 0; i < length; ++i) {
1742             PRELOAD_COND2(dest, src)
1743             dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha);
1744         }
1745     }
1746 }
1747
1748 void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
1749 {
1750 }
1751
1752 void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint)
1753 {
1754 }
1755
1756 /*
1757   result = s + d * sia
1758   dest = (s + d * sia) * ca + d * cia
1759        = s * ca + d * (sia * ca + cia)
1760        = s * ca + d * (1 - sa*ca)
1761 */
1762 void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha)
1763 {
1764     if ((const_alpha & qAlpha(color)) == 255) {
1765         QT_MEMFILL_UINT(dest, length, color);
1766     } else {
1767         if (const_alpha != 255)
1768             color = BYTE_MUL(color, const_alpha);
1769         PRELOAD_INIT(dest)
1770         for (int i = 0; i < length; ++i) {
1771             PRELOAD_COND(dest)
1772             dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color));
1773         }
1774     }
1775 }
1776
1777 void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha)
1778 {
1779     PRELOAD_INIT2(dest, src)
1780     if (const_alpha == 255) {
1781         for (int i = 0; i < length; ++i) {
1782             PRELOAD_COND2(dest, src)
1783             uint s = src[i];
1784             if (s >= 0xff000000)
1785                 dest[i] = s;
1786             else if (s != 0)
1787                 dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
1788         }
1789     } else {
1790         for (int i = 0; i < length; ++i) {
1791             PRELOAD_COND2(dest, src)
1792             uint s = BYTE_MUL(src[i], const_alpha);
1793             dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
1794         }
1795     }
1796 }
1797
1798 /*
1799   result = d + s * dia
1800   dest = (d + s * dia) * ca + d * cia
1801        = d + s * dia * ca
1802 */
1803 void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha)
1804 {
1805     if (const_alpha != 255)
1806         color = BYTE_MUL(color, const_alpha);
1807     PRELOAD_INIT(dest)
1808     for (int i = 0; i < length; ++i) {
1809         PRELOAD_COND(dest)
1810         uint d = dest[i];
1811         dest[i] = d + BYTE_MUL(color, qAlpha(~d));
1812     }
1813 }
1814
1815 void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha)
1816 {
1817     PRELOAD_INIT2(dest, src)
1818     if (const_alpha == 255) {
1819         for (int i = 0; i < length; ++i) {
1820             PRELOAD_COND2(dest, src)
1821             uint d = dest[i];
1822             dest[i] = d + BYTE_MUL(src[i], qAlpha(~d));
1823         }
1824     } else {
1825         for (int i = 0; i < length; ++i) {
1826             PRELOAD_COND2(dest, src)
1827             uint d = dest[i];
1828             uint s = BYTE_MUL(src[i], const_alpha);
1829             dest[i] = d + BYTE_MUL(s, qAlpha(~d));
1830         }
1831     }
1832 }
1833
1834 /*
1835   result = s * da
1836   dest = s * da * ca + d * cia
1837 */
1838 void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha)
1839 {
1840     PRELOAD_INIT(dest)
1841     if (const_alpha == 255) {
1842         for (int i = 0; i < length; ++i) {
1843             PRELOAD_COND(dest)
1844             dest[i] = BYTE_MUL(color, qAlpha(dest[i]));
1845         }
1846     } else {
1847         color = BYTE_MUL(color, const_alpha);
1848         uint cia = 255 - const_alpha;
1849         for (int i = 0; i < length; ++i) {
1850             PRELOAD_COND(dest)
1851             uint d = dest[i];
1852             dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia);
1853         }
1854     }
1855 }
1856
1857 void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha)
1858 {
1859     PRELOAD_INIT2(dest, src)
1860     if (const_alpha == 255) {
1861         for (int i = 0; i < length; ++i) {
1862             PRELOAD_COND2(dest, src)
1863             dest[i] = BYTE_MUL(src[i], qAlpha(dest[i]));
1864         }
1865     } else {
1866         uint cia = 255 - const_alpha;
1867         for (int i = 0; i < length; ++i) {
1868             PRELOAD_COND2(dest, src)
1869             uint d = dest[i];
1870             uint s = BYTE_MUL(src[i], const_alpha);
1871             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia);
1872         }
1873     }
1874 }
1875
1876 /*
1877   result = d * sa
1878   dest = d * sa * ca + d * cia
1879        = d * (sa * ca + cia)
1880 */
1881 void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha)
1882 {
1883     uint a = qAlpha(color);
1884     if (const_alpha != 255) {
1885         a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
1886     }
1887     PRELOAD_INIT(dest)
1888     for (int i = 0; i < length; ++i) {
1889         PRELOAD_COND(dest)
1890         dest[i] = BYTE_MUL(dest[i], a);
1891     }
1892 }
1893
1894 void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha)
1895 {
1896     PRELOAD_INIT2(dest, src)
1897     if (const_alpha == 255) {
1898         for (int i = 0; i < length; ++i) {
1899             PRELOAD_COND2(dest, src)
1900             dest[i] = BYTE_MUL(dest[i], qAlpha(src[i]));
1901         }
1902     } else {
1903         int cia = 255 - const_alpha;
1904         for (int i = 0; i < length; ++i) {
1905             PRELOAD_COND2(dest, src)
1906             uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia;
1907             dest[i] = BYTE_MUL(dest[i], a);
1908         }
1909     }
1910 }
1911
1912 /*
1913   result = s * dia
1914   dest = s * dia * ca + d * cia
1915 */
1916
1917 void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha)
1918 {
1919     PRELOAD_INIT(dest)
1920     if (const_alpha == 255) {
1921         for (int i = 0; i < length; ++i) {
1922             PRELOAD_COND(dest)
1923             dest[i] = BYTE_MUL(color, qAlpha(~dest[i]));
1924         }
1925     } else {
1926         color = BYTE_MUL(color, const_alpha);
1927         int cia = 255 - const_alpha;
1928         for (int i = 0; i < length; ++i) {
1929             PRELOAD_COND(dest)
1930             uint d = dest[i];
1931             dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia);
1932         }
1933     }
1934 }
1935
1936 void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha)
1937 {
1938     PRELOAD_INIT2(dest, src)
1939     if (const_alpha == 255) {
1940         for (int i = 0; i < length; ++i) {
1941             PRELOAD_COND2(dest, src)
1942             dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i]));
1943         }
1944     } else {
1945         int cia = 255 - const_alpha;
1946         for (int i = 0; i < length; ++i) {
1947             PRELOAD_COND2(dest, src)
1948             uint s = BYTE_MUL(src[i], const_alpha);
1949             uint d = dest[i];
1950             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia);
1951         }
1952     }
1953 }
1954
1955 /*
1956   result = d * sia
1957   dest = d * sia * ca + d * cia
1958        = d * (sia * ca + cia)
1959 */
1960 void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha)
1961 {
1962     uint a = qAlpha(~color);
1963     if (const_alpha != 255)
1964         a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
1965     PRELOAD_INIT(dest)
1966     for (int i = 0; i < length; ++i) {
1967         PRELOAD_COND(dest)
1968         dest[i] = BYTE_MUL(dest[i], a);
1969     }
1970 }
1971
1972 void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha)
1973 {
1974     PRELOAD_INIT2(dest, src)
1975     if (const_alpha == 255) {
1976         for (int i = 0; i < length; ++i) {
1977             PRELOAD_COND2(dest, src)
1978             dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i]));
1979         }
1980     } else {
1981         int cia = 255 - const_alpha;
1982         for (int i = 0; i < length; ++i) {
1983             PRELOAD_COND2(dest, src)
1984             uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia;
1985             dest[i] = BYTE_MUL(dest[i], sia);
1986         }
1987     }
1988 }
1989
1990 /*
1991   result = s*da + d*sia
1992   dest = s*da*ca + d*sia*ca + d *cia
1993        = s*ca * da + d * (sia*ca + cia)
1994        = s*ca * da + d * (1 - sa*ca)
1995 */
1996 void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha)
1997 {
1998     if (const_alpha != 255) {
1999         color = BYTE_MUL(color, const_alpha);
2000     }
2001     uint sia = qAlpha(~color);
2002     PRELOAD_INIT(dest)
2003     for (int i = 0; i < length; ++i) {
2004         PRELOAD_COND(dest)
2005         dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia);
2006     }
2007 }
2008
2009 void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha)
2010 {
2011     PRELOAD_INIT2(dest, src)
2012     if (const_alpha == 255) {
2013         for (int i = 0; i < length; ++i) {
2014             PRELOAD_COND2(dest, src)
2015             uint s = src[i];
2016             uint d = dest[i];
2017             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
2018         }
2019     } else {
2020         for (int i = 0; i < length; ++i) {
2021             PRELOAD_COND2(dest, src)
2022             uint s = BYTE_MUL(src[i], const_alpha);
2023             uint d = dest[i];
2024             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
2025         }
2026     }
2027 }
2028
2029 /*
2030   result = d*sa + s*dia
2031   dest = d*sa*ca + s*dia*ca + d *cia
2032        = s*ca * dia + d * (sa*ca + cia)
2033 */
2034 void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha)
2035 {
2036     uint a = qAlpha(color);
2037     if (const_alpha != 255) {
2038         color = BYTE_MUL(color, const_alpha);
2039         a = qAlpha(color) + 255 - const_alpha;
2040     }
2041     PRELOAD_INIT(dest)
2042     for (int i = 0; i < length; ++i) {
2043         PRELOAD_COND(dest)
2044         uint d = dest[i];
2045         dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d));
2046     }
2047 }
2048
2049 void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha)
2050 {
2051     PRELOAD_INIT2(dest, src)
2052     if (const_alpha == 255) {
2053         for (int i = 0; i < length; ++i) {
2054             PRELOAD_COND2(dest, src)
2055             uint s = src[i];
2056             uint d = dest[i];
2057             dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d));
2058         }
2059     } else {
2060         int cia = 255 - const_alpha;
2061         for (int i = 0; i < length; ++i) {
2062             PRELOAD_COND2(dest, src)
2063             uint s = BYTE_MUL(src[i], const_alpha);
2064             uint d = dest[i];
2065             uint a = qAlpha(s) + cia;
2066             dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d));
2067         }
2068     }
2069 }
2070
2071 /*
2072   result = d*sia + s*dia
2073   dest = d*sia*ca + s*dia*ca + d *cia
2074        = s*ca * dia + d * (sia*ca + cia)
2075        = s*ca * dia + d * (1 - sa*ca)
2076 */
2077 void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha)
2078 {
2079     if (const_alpha != 255)
2080         color = BYTE_MUL(color, const_alpha);
2081     uint sia = qAlpha(~color);
2082
2083     PRELOAD_INIT(dest)
2084     for (int i = 0; i < length; ++i) {
2085         PRELOAD_COND(dest)
2086         uint d = dest[i];
2087         dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia);
2088     }
2089 }
2090
2091 void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha)
2092 {
2093     PRELOAD_INIT2(dest, src)
2094     if (const_alpha == 255) {
2095         for (int i = 0; i < length; ++i) {
2096             PRELOAD_COND2(dest, src)
2097             uint d = dest[i];
2098             uint s = src[i];
2099             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
2100         }
2101     } else {
2102         for (int i = 0; i < length; ++i) {
2103             PRELOAD_COND2(dest, src)
2104             uint d = dest[i];
2105             uint s = BYTE_MUL(src[i], const_alpha);
2106             dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
2107         }
2108     }
2109 }
2110
2111 struct QFullCoverage {
2112     inline void store(uint *dest, const uint src) const
2113     {
2114         *dest = src;
2115     }
2116 };
2117
2118 struct QPartialCoverage {
2119     inline QPartialCoverage(uint const_alpha)
2120         : ca(const_alpha)
2121         , ica(255 - const_alpha)
2122     {
2123     }
2124
2125     inline void store(uint *dest, const uint src) const
2126     {
2127         *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
2128     }
2129
2130 private:
2131     const uint ca;
2132     const uint ica;
2133 };
2134
2135 static inline int mix_alpha(int da, int sa)
2136 {
2137     return 255 - ((255 - sa) * (255 - da) >> 8);
2138 }
2139
2140 /*
2141     Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
2142          = Sca + Dca
2143 */
2144 template <typename T>
2145 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage)
2146 {
2147     uint s = color;
2148
2149     PRELOAD_INIT(dest)
2150     for (int i = 0; i < length; ++i) {
2151         PRELOAD_COND(dest)
2152         uint d = dest[i];
2153         d = comp_func_Plus_one_pixel(d, s);
2154         coverage.store(&dest[i], d);
2155     }
2156 }
2157
2158 void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha)
2159 {
2160     if (const_alpha == 255)
2161         comp_func_solid_Plus_impl(dest, length, color, QFullCoverage());
2162     else
2163         comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha));
2164 }
2165
2166 template <typename T>
2167 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *dest, const uint *src, int length, const T &coverage)
2168 {
2169     PRELOAD_INIT2(dest, src)
2170     for (int i = 0; i < length; ++i) {
2171         PRELOAD_COND2(dest, src)
2172         uint d = dest[i];
2173         uint s = src[i];
2174
2175         d = comp_func_Plus_one_pixel(d, s);
2176
2177         coverage.store(&dest[i], d);
2178     }
2179 }
2180
2181 void QT_FASTCALL comp_func_Plus(uint *dest, const uint *src, int length, uint const_alpha)
2182 {
2183     if (const_alpha == 255)
2184         comp_func_Plus_impl(dest, src, length, QFullCoverage());
2185     else
2186         comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha));
2187 }
2188
2189 /*
2190     Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2191 */
2192 static inline int multiply_op(int dst, int src, int da, int sa)
2193 {
2194     return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa));
2195 }
2196
2197 template <typename T>
2198 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage)
2199 {
2200     int sa = qAlpha(color);
2201     int sr = qRed(color);
2202     int sg = qGreen(color);
2203     int sb = qBlue(color);
2204
2205     PRELOAD_INIT(dest)
2206     for (int i = 0; i < length; ++i) {
2207         PRELOAD_COND(dest)
2208         uint d = dest[i];
2209         int da = qAlpha(d);
2210
2211 #define OP(a, b) multiply_op(a, b, da, sa)
2212         int r = OP(  qRed(d), sr);
2213         int b = OP( qBlue(d), sb);
2214         int g = OP(qGreen(d), sg);
2215         int a = mix_alpha(da, sa);
2216 #undef OP
2217
2218         coverage.store(&dest[i], qRgba(r, g, b, a));
2219     }
2220 }
2221
2222 void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha)
2223 {
2224     if (const_alpha == 255)
2225         comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
2226     else
2227         comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
2228 }
2229
2230 template <typename T>
2231 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *dest, const uint *src, int length, const T &coverage)
2232 {
2233     PRELOAD_INIT2(dest, src)
2234     for (int i = 0; i < length; ++i) {
2235         PRELOAD_COND2(dest, src)
2236         uint d = dest[i];
2237         uint s = src[i];
2238
2239         int da = qAlpha(d);
2240         int sa = qAlpha(s);
2241
2242 #define OP(a, b) multiply_op(a, b, da, sa)
2243         int r = OP(  qRed(d),   qRed(s));
2244         int b = OP( qBlue(d),  qBlue(s));
2245         int g = OP(qGreen(d), qGreen(s));
2246         int a = mix_alpha(da, sa);
2247 #undef OP
2248
2249         coverage.store(&dest[i], qRgba(r, g, b, a));
2250     }
2251 }
2252
2253 void QT_FASTCALL comp_func_Multiply(uint *dest, const uint *src, int length, uint const_alpha)
2254 {
2255     if (const_alpha == 255)
2256         comp_func_Multiply_impl(dest, src, length, QFullCoverage());
2257     else
2258         comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
2259 }
2260
2261 /*
2262     Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2263          = Sca + Dca - Sca.Dca
2264 */
2265 template <typename T>
2266 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage)
2267 {
2268     int sa = qAlpha(color);
2269     int sr = qRed(color);
2270     int sg = qGreen(color);
2271     int sb = qBlue(color);
2272
2273     PRELOAD_INIT(dest)
2274     for (int i = 0; i < length; ++i) {
2275         PRELOAD_COND(dest)
2276         uint d = dest[i];
2277         int da = qAlpha(d);
2278
2279 #define OP(a, b) 255 - qt_div_255((255-a) * (255-b))
2280         int r = OP(  qRed(d), sr);
2281         int b = OP( qBlue(d), sb);
2282         int g = OP(qGreen(d), sg);
2283         int a = mix_alpha(da, sa);
2284 #undef OP
2285
2286         coverage.store(&dest[i], qRgba(r, g, b, a));
2287     }
2288 }
2289
2290 void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha)
2291 {
2292     if (const_alpha == 255)
2293         comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
2294     else
2295         comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
2296 }
2297
2298 template <typename T>
2299 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *dest, const uint *src, int length, const T &coverage)
2300 {
2301     PRELOAD_INIT2(dest, src)
2302     for (int i = 0; i < length; ++i) {
2303         PRELOAD_COND2(dest, src)
2304         uint d = dest[i];
2305         uint s = src[i];
2306
2307         int da = qAlpha(d);
2308         int sa = qAlpha(s);
2309
2310 #define OP(a, b) 255 - (((255-a) * (255-b)) >> 8)
2311         int r = OP(  qRed(d),   qRed(s));
2312         int b = OP( qBlue(d),  qBlue(s));
2313         int g = OP(qGreen(d), qGreen(s));
2314         int a = mix_alpha(da, sa);
2315 #undef OP
2316
2317         coverage.store(&dest[i], qRgba(r, g, b, a));
2318     }
2319 }
2320
2321 void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha)
2322 {
2323     if (const_alpha == 255)
2324         comp_func_Screen_impl(dest, src, length, QFullCoverage());
2325     else
2326         comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
2327 }
2328
2329 /*
2330     if 2.Dca < Da
2331         Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2332     otherwise
2333         Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2334 */
2335 static inline int overlay_op(int dst, int src, int da, int sa)
2336 {
2337     const int temp = src * (255 - da) + dst * (255 - sa);
2338     if (2 * dst < da)
2339         return qt_div_255(2 * src * dst + temp);
2340     else
2341         return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2342 }
2343
2344 template <typename T>
2345 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage)
2346 {
2347     int sa = qAlpha(color);
2348     int sr = qRed(color);
2349     int sg = qGreen(color);
2350     int sb = qBlue(color);
2351
2352     PRELOAD_INIT(dest)
2353     for (int i = 0; i < length; ++i) {
2354         PRELOAD_COND(dest)
2355         uint d = dest[i];
2356         int da = qAlpha(d);
2357
2358 #define OP(a, b) overlay_op(a, b, da, sa)
2359         int r = OP(  qRed(d), sr);
2360         int b = OP( qBlue(d), sb);
2361         int g = OP(qGreen(d), sg);
2362         int a = mix_alpha(da, sa);
2363 #undef OP
2364
2365         coverage.store(&dest[i], qRgba(r, g, b, a));
2366     }
2367 }
2368
2369 void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha)
2370 {
2371     if (const_alpha == 255)
2372         comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
2373     else
2374         comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
2375 }
2376
2377 template <typename T>
2378 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *dest, const uint *src, int length, const T &coverage)
2379 {
2380     PRELOAD_INIT2(dest, src)
2381     for (int i = 0; i < length; ++i) {
2382         PRELOAD_COND2(dest, src)
2383         uint d = dest[i];
2384         uint s = src[i];
2385
2386         int da = qAlpha(d);
2387         int sa = qAlpha(s);
2388
2389 #define OP(a, b) overlay_op(a, b, da, sa)
2390         int r = OP(  qRed(d),   qRed(s));
2391         int b = OP( qBlue(d),  qBlue(s));
2392         int g = OP(qGreen(d), qGreen(s));
2393         int a = mix_alpha(da, sa);
2394 #undef OP
2395
2396         coverage.store(&dest[i], qRgba(r, g, b, a));
2397     }
2398 }
2399
2400 void QT_FASTCALL comp_func_Overlay(uint *dest, const uint *src, int length, uint const_alpha)
2401 {
2402     if (const_alpha == 255)
2403         comp_func_Overlay_impl(dest, src, length, QFullCoverage());
2404     else
2405         comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
2406 }
2407
2408 /*
2409     Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2410     Da'  = Sa + Da - Sa.Da
2411 */
2412 static inline int darken_op(int dst, int src, int da, int sa)
2413 {
2414     return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2415 }
2416
2417 template <typename T>
2418 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage)
2419 {
2420     int sa = qAlpha(color);
2421     int sr = qRed(color);
2422     int sg = qGreen(color);
2423     int sb = qBlue(color);
2424
2425     PRELOAD_INIT(dest)
2426     for (int i = 0; i < length; ++i) {
2427         PRELOAD_COND(dest)
2428         uint d = dest[i];
2429         int da = qAlpha(d);
2430
2431 #define OP(a, b) darken_op(a, b, da, sa)
2432         int r =  OP(  qRed(d), sr);
2433         int b =  OP( qBlue(d), sb);
2434         int g =  OP(qGreen(d), sg);
2435         int a = mix_alpha(da, sa);
2436 #undef OP
2437
2438         coverage.store(&dest[i], qRgba(r, g, b, a));
2439     }
2440 }
2441
2442 void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha)
2443 {
2444     if (const_alpha == 255)
2445         comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
2446     else
2447         comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
2448 }
2449
2450 template <typename T>
2451 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *dest, const uint *src, int length, const T &coverage)
2452 {
2453     PRELOAD_INIT2(dest, src)
2454     for (int i = 0; i < length; ++i) {
2455         PRELOAD_COND2(dest, src)
2456         uint d = dest[i];
2457         uint s = src[i];
2458
2459         int da = qAlpha(d);
2460         int sa = qAlpha(s);
2461
2462 #define OP(a, b) darken_op(a, b, da, sa)
2463         int r = OP(  qRed(d),   qRed(s));
2464         int b = OP( qBlue(d),  qBlue(s));
2465         int g = OP(qGreen(d), qGreen(s));
2466         int a = mix_alpha(da, sa);
2467 #undef OP
2468
2469         coverage.store(&dest[i], qRgba(r, g, b, a));
2470     }
2471 }
2472
2473 void QT_FASTCALL comp_func_Darken(uint *dest, const uint *src, int length, uint const_alpha)
2474 {
2475     if (const_alpha == 255)
2476         comp_func_Darken_impl(dest, src, length, QFullCoverage());
2477     else
2478         comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
2479 }
2480
2481 /*
2482    Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2483    Da'  = Sa + Da - Sa.Da
2484 */
2485 static inline int lighten_op(int dst, int src, int da, int sa)
2486 {
2487     return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2488 }
2489
2490 template <typename T>
2491 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage)
2492 {
2493     int sa = qAlpha(color);
2494     int sr = qRed(color);
2495     int sg = qGreen(color);
2496     int sb = qBlue(color);
2497
2498     PRELOAD_INIT(dest)
2499     for (int i = 0; i < length; ++i) {
2500         PRELOAD_COND(dest)
2501         uint d = dest[i];
2502         int da = qAlpha(d);
2503
2504 #define OP(a, b) lighten_op(a, b, da, sa)
2505         int r =  OP(  qRed(d), sr);
2506         int b =  OP( qBlue(d), sb);
2507         int g =  OP(qGreen(d), sg);
2508         int a = mix_alpha(da, sa);
2509 #undef OP
2510
2511         coverage.store(&dest[i], qRgba(r, g, b, a));
2512     }
2513 }
2514
2515 void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha)
2516 {
2517     if (const_alpha == 255)
2518         comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
2519     else
2520         comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
2521 }
2522
2523 template <typename T>
2524 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *dest, const uint *src, int length, const T &coverage)
2525 {
2526     PRELOAD_INIT2(dest, src)
2527     for (int i = 0; i < length; ++i) {
2528         PRELOAD_COND2(dest, src)
2529         uint d = dest[i];
2530         uint s = src[i];
2531
2532         int da = qAlpha(d);
2533         int sa = qAlpha(s);
2534
2535 #define OP(a, b) lighten_op(a, b, da, sa)
2536         int r = OP(  qRed(d),   qRed(s));
2537         int b = OP( qBlue(d),  qBlue(s));
2538         int g = OP(qGreen(d), qGreen(s));
2539         int a = mix_alpha(da, sa);
2540 #undef OP
2541
2542         coverage.store(&dest[i], qRgba(r, g, b, a));
2543     }
2544 }
2545
2546 void QT_FASTCALL comp_func_Lighten(uint *dest, const uint *src, int length, uint const_alpha)
2547 {
2548     if (const_alpha == 255)
2549         comp_func_Lighten_impl(dest, src, length, QFullCoverage());
2550     else
2551         comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
2552 }
2553
2554 /*
2555    if Sca.Da + Dca.Sa >= Sa.Da
2556        Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
2557    otherwise
2558        Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2559 */
2560 static inline int color_dodge_op(int dst, int src, int da, int sa)
2561 {
2562     const int sa_da = sa * da;
2563     const int dst_sa = dst * sa;
2564     const int src_da = src * da;
2565
2566     const int temp = src * (255 - da) + dst * (255 - sa);
2567     if (src_da + dst_sa >= sa_da)
2568         return qt_div_255(sa_da + temp);
2569     else
2570         return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp);
2571 }
2572
2573 template <typename T>
2574 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage)
2575 {
2576     int sa = qAlpha(color);
2577     int sr = qRed(color);
2578     int sg = qGreen(color);
2579     int sb = qBlue(color);
2580
2581     PRELOAD_INIT(dest)
2582     for (int i = 0; i < length; ++i) {
2583         PRELOAD_COND(dest)
2584         uint d = dest[i];
2585         int da = qAlpha(d);
2586
2587 #define OP(a,b) color_dodge_op(a, b, da, sa)
2588         int r = OP(  qRed(d), sr);
2589         int b = OP( qBlue(d), sb);
2590         int g = OP(qGreen(d), sg);
2591         int a = mix_alpha(da, sa);
2592 #undef OP
2593
2594         coverage.store(&dest[i], qRgba(r, g, b, a));
2595     }
2596 }
2597
2598 void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha)
2599 {
2600     if (const_alpha == 255)
2601         comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
2602     else
2603         comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
2604 }
2605
2606 template <typename T>
2607 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *dest, const uint *src, int length, const T &coverage)
2608 {
2609     PRELOAD_INIT2(dest, src)
2610     for (int i = 0; i < length; ++i) {
2611         PRELOAD_COND2(dest, src)
2612         uint d = dest[i];
2613         uint s = src[i];
2614
2615         int da = qAlpha(d);
2616         int sa = qAlpha(s);
2617
2618 #define OP(a, b) color_dodge_op(a, b, da, sa)
2619         int r = OP(  qRed(d),   qRed(s));
2620         int b = OP( qBlue(d),  qBlue(s));
2621         int g = OP(qGreen(d), qGreen(s));
2622         int a = mix_alpha(da, sa);
2623 #undef OP
2624
2625         coverage.store(&dest[i], qRgba(r, g, b, a));
2626     }
2627 }
2628
2629 void QT_FASTCALL comp_func_ColorDodge(uint *dest, const uint *src, int length, uint const_alpha)
2630 {
2631     if (const_alpha == 255)
2632         comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
2633     else
2634         comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
2635 }
2636
2637 /*
2638    if Sca.Da + Dca.Sa <= Sa.Da
2639        Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
2640    otherwise
2641        Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
2642 */
2643 static inline int color_burn_op(int dst, int src, int da, int sa)
2644 {
2645     const int src_da = src * da;
2646     const int dst_sa = dst * sa;
2647     const int sa_da = sa * da;
2648
2649     const int temp = src * (255 - da) + dst * (255 - sa);
2650
2651     if (src == 0 || src_da + dst_sa <= sa_da)
2652         return qt_div_255(temp);
2653     return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp);
2654 }
2655
2656 template <typename T>
2657 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage)
2658 {
2659     int sa = qAlpha(color);
2660     int sr = qRed(color);
2661     int sg = qGreen(color);
2662     int sb = qBlue(color);
2663
2664     PRELOAD_INIT(dest)
2665     for (int i = 0; i < length; ++i) {
2666         PRELOAD_COND(dest)
2667         uint d = dest[i];
2668         int da = qAlpha(d);
2669
2670 #define OP(a, b) color_burn_op(a, b, da, sa)
2671         int r =  OP(  qRed(d), sr);
2672         int b =  OP( qBlue(d), sb);
2673         int g =  OP(qGreen(d), sg);
2674         int a = mix_alpha(da, sa);
2675 #undef OP
2676
2677         coverage.store(&dest[i], qRgba(r, g, b, a));
2678     }
2679 }
2680
2681 void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha)
2682 {
2683     if (const_alpha == 255)
2684         comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
2685     else
2686         comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
2687 }
2688
2689 template <typename T>
2690 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *dest, const uint *src, int length, const T &coverage)
2691 {
2692     PRELOAD_INIT2(dest, src)
2693     for (int i = 0; i < length; ++i) {
2694         PRELOAD_COND2(dest, src)
2695         uint d = dest[i];
2696         uint s = src[i];
2697
2698         int da = qAlpha(d);
2699         int sa = qAlpha(s);
2700
2701 #define OP(a, b) color_burn_op(a, b, da, sa)
2702         int r = OP(  qRed(d),   qRed(s));
2703         int b = OP( qBlue(d),  qBlue(s));
2704         int g = OP(qGreen(d), qGreen(s));
2705         int a = mix_alpha(da, sa);
2706 #undef OP
2707
2708         coverage.store(&dest[i], qRgba(r, g, b, a));
2709     }
2710 }
2711
2712 void QT_FASTCALL comp_func_ColorBurn(uint *dest, const uint *src, int length, uint const_alpha)
2713 {
2714     if (const_alpha == 255)
2715         comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
2716     else
2717         comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
2718 }
2719
2720 /*
2721     if 2.Sca < Sa
2722         Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2723     otherwise
2724         Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2725 */
2726 static inline uint hardlight_op(int dst, int src, int da, int sa)
2727 {
2728     const uint temp = src * (255 - da) + dst * (255 - sa);
2729
2730     if (2 * src < sa)
2731         return qt_div_255(2 * src * dst + temp);
2732     else
2733         return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2734 }
2735
2736 template <typename T>
2737 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage)
2738 {
2739     int sa = qAlpha(color);
2740     int sr = qRed(color);
2741     int sg = qGreen(color);
2742     int sb = qBlue(color);
2743
2744     PRELOAD_INIT(dest)
2745     for (int i = 0; i < length; ++i) {
2746         PRELOAD_COND(dest)
2747         uint d = dest[i];
2748         int da = qAlpha(d);
2749
2750 #define OP(a, b) hardlight_op(a, b, da, sa)
2751         int r =  OP(  qRed(d), sr);
2752         int b =  OP( qBlue(d), sb);
2753         int g =  OP(qGreen(d), sg);
2754         int a = mix_alpha(da, sa);
2755 #undef OP
2756
2757         coverage.store(&dest[i], qRgba(r, g, b, a));
2758     }
2759 }
2760
2761 void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha)
2762 {
2763     if (const_alpha == 255)
2764         comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
2765     else
2766         comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2767 }
2768
2769 template <typename T>
2770 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *dest, const uint *src, int length, const T &coverage)
2771 {
2772     PRELOAD_INIT2(dest, src)
2773     for (int i = 0; i < length; ++i) {
2774         PRELOAD_COND2(dest, src)
2775         uint d = dest[i];
2776         uint s = src[i];
2777
2778         int da = qAlpha(d);
2779         int sa = qAlpha(s);
2780
2781 #define OP(a, b) hardlight_op(a, b, da, sa)
2782         int r = OP(  qRed(d),   qRed(s));
2783         int b = OP( qBlue(d),  qBlue(s));
2784         int g = OP(qGreen(d), qGreen(s));
2785         int a = mix_alpha(da, sa);
2786 #undef OP
2787
2788         coverage.store(&dest[i], qRgba(r, g, b, a));
2789     }
2790 }
2791
2792 void QT_FASTCALL comp_func_HardLight(uint *dest, const uint *src, int length, uint const_alpha)
2793 {
2794     if (const_alpha == 255)
2795         comp_func_HardLight_impl(dest, src, length, QFullCoverage());
2796     else
2797         comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2798 }
2799
2800 /*
2801     if 2.Sca <= Sa
2802         Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
2803     otherwise if 2.Sca > Sa and 4.Dca <= Da
2804         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)
2805     otherwise if 2.Sca > Sa and 4.Dca > Da
2806         Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2807 */
2808 static inline int soft_light_op(int dst, int src, int da, int sa)
2809 {
2810     const int src2 = src << 1;
2811     const int dst_np = da != 0 ? (255 * dst) / da : 0;
2812     const int temp = (src * (255 - da) + dst * (255 - sa)) * 255;
2813
2814     if (src2 < sa)
2815         return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025;
2816     else if (4 * dst <= da)
2817         return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025;
2818     else {
2819 #   ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
2820         return (dst * sa * 255 + da * (src2 - sa) * (qIntSqrtInt(dst_np * 255) - dst_np) + temp) / 65025;
2821 #   else
2822         return (dst * sa * 255 + da * (src2 - sa) * (int(sqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025;
2823 #   endif
2824     }
2825 }
2826
2827 template <typename T>
2828 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage)
2829 {
2830     int sa = qAlpha(color);
2831     int sr = qRed(color);
2832     int sg = qGreen(color);
2833     int sb = qBlue(color);
2834
2835     PRELOAD_INIT(dest)
2836     for (int i = 0; i < length; ++i) {
2837         PRELOAD_COND(dest)
2838         uint d = dest[i];
2839         int da = qAlpha(d);
2840
2841 #define OP(a, b) soft_light_op(a, b, da, sa)
2842         int r =  OP(  qRed(d), sr);
2843         int b =  OP( qBlue(d), sb);
2844         int g =  OP(qGreen(d), sg);
2845         int a = mix_alpha(da, sa);
2846 #undef OP
2847
2848         coverage.store(&dest[i], qRgba(r, g, b, a));
2849     }
2850 }
2851
2852 void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
2853 {
2854     if (const_alpha == 255)
2855         comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
2856     else
2857         comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2858 }
2859
2860 template <typename T>
2861 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *dest, const uint *src, int length, const T &coverage)
2862 {
2863     PRELOAD_INIT2(dest, src)
2864     for (int i = 0; i < length; ++i) {
2865         PRELOAD_COND2(dest, src)
2866         uint d = dest[i];
2867         uint s = src[i];
2868
2869         int da = qAlpha(d);
2870         int sa = qAlpha(s);
2871
2872 #define OP(a, b) soft_light_op(a, b, da, sa)
2873         int r = OP(  qRed(d),   qRed(s));
2874         int b = OP( qBlue(d),  qBlue(s));
2875         int g = OP(qGreen(d), qGreen(s));
2876         int a = mix_alpha(da, sa);
2877 #undef OP
2878
2879         coverage.store(&dest[i], qRgba(r, g, b, a));
2880     }
2881 }
2882
2883 void QT_FASTCALL comp_func_SoftLight(uint *dest, const uint *src, int length, uint const_alpha)
2884 {
2885     if (const_alpha == 255)
2886         comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
2887     else
2888         comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2889 }
2890
2891 /*
2892    Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2893         = Sca + Dca - 2.min(Sca.Da, Dca.Sa)
2894 */
2895 static inline int difference_op(int dst, int src, int da, int sa)
2896 {
2897     return src + dst - qt_div_255(2 * qMin(src * da, dst * sa));
2898 }
2899
2900 template <typename T>
2901 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage)
2902 {
2903     int sa = qAlpha(color);
2904     int sr = qRed(color);
2905     int sg = qGreen(color);
2906     int sb = qBlue(color);
2907
2908     PRELOAD_INIT(dest)
2909     for (int i = 0; i < length; ++i) {
2910         PRELOAD_COND(dest)
2911         uint d = dest[i];
2912         int da = qAlpha(d);
2913
2914 #define OP(a, b) difference_op(a, b, da, sa)
2915         int r =  OP(  qRed(d), sr);
2916         int b =  OP( qBlue(d), sb);
2917         int g =  OP(qGreen(d), sg);
2918         int a = mix_alpha(da, sa);
2919 #undef OP
2920
2921         coverage.store(&dest[i], qRgba(r, g, b, a));
2922     }
2923 }
2924
2925 void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha)
2926 {
2927     if (const_alpha == 255)
2928         comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
2929     else
2930         comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
2931 }
2932
2933 template <typename T>
2934 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *dest, const uint *src, int length, const T &coverage)
2935 {
2936     PRELOAD_INIT2(dest, src)
2937     for (int i = 0; i < length; ++i) {
2938         PRELOAD_COND2(dest, src)
2939         uint d = dest[i];
2940         uint s = src[i];
2941
2942         int da = qAlpha(d);
2943         int sa = qAlpha(s);
2944
2945 #define OP(a, b) difference_op(a, b, da, sa)
2946         int r = OP(  qRed(d),   qRed(s));
2947         int b = OP( qBlue(d),  qBlue(s));
2948         int g = OP(qGreen(d), qGreen(s));
2949         int a = mix_alpha(da, sa);
2950 #undef OP
2951
2952         coverage.store(&dest[i], qRgba(r, g, b, a));
2953     }
2954 }
2955
2956 void QT_FASTCALL comp_func_Difference(uint *dest, const uint *src, int length, uint const_alpha)
2957 {
2958     if (const_alpha == 255)
2959         comp_func_Difference_impl(dest, src, length, QFullCoverage());
2960     else
2961         comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
2962 }
2963
2964 /*
2965     Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2966 */
2967 template <typename T>
2968 Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage)
2969 {
2970     int sa = qAlpha(color);
2971     int sr = qRed(color);
2972     int sg = qGreen(color);
2973     int sb = qBlue(color);
2974
2975     PRELOAD_INIT(dest)
2976     for (int i = 0; i < length; ++i) {
2977         PRELOAD_COND(dest)
2978         uint d = dest[i];
2979         int da = qAlpha(d);
2980
2981 #define OP(a, b) (a + b - qt_div_255(2*(a*b)))
2982         int r =  OP(  qRed(d), sr);
2983         int b =  OP( qBlue(d), sb);
2984         int g =  OP(qGreen(d), sg);
2985         int a = mix_alpha(da, sa);
2986 #undef OP
2987
2988         coverage.store(&dest[i], qRgba(r, g, b, a));
2989     }
2990 }
2991
2992 void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha)
2993 {
2994     if (const_alpha == 255)
2995         comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage());
2996     else
2997         comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
2998 }
2999
3000 template <typename T>
3001 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *dest, const uint *src, int length, const T &coverage)
3002 {
3003     PRELOAD_INIT2(dest, src)
3004     for (int i = 0; i < length; ++i) {
3005         PRELOAD_COND2(dest, src)
3006         uint d = dest[i];
3007         uint s = src[i];
3008
3009         int da = qAlpha(d);
3010         int sa = qAlpha(s);
3011
3012 #define OP(a, b) (a + b - ((a*b) >> 7))
3013         int r = OP(  qRed(d),   qRed(s));
3014         int b = OP( qBlue(d),  qBlue(s));
3015         int g = OP(qGreen(d), qGreen(s));
3016         int a = mix_alpha(da, sa);
3017 #undef OP
3018
3019         coverage.store(&dest[i], qRgba(r, g, b, a));
3020     }
3021 }
3022
3023 void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int length, uint const_alpha)
3024 {
3025     if (const_alpha == 255)
3026         comp_func_Exclusion_impl(dest, src, length, QFullCoverage());
3027     else
3028         comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
3029 }
3030
3031 #if defined(Q_CC_RVCT)
3032 // Restore pragma state from previous #pragma arm
3033 #  pragma pop
3034 #endif
3035
3036 void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest,
3037                                                     int length,
3038                                                     uint color,
3039                                                     uint const_alpha)
3040 {
3041     Q_UNUSED(const_alpha);
3042     while (length--)
3043         *dest++ |= color;
3044 }
3045
3046 void QT_FASTCALL rasterop_SourceOrDestination(uint *dest,
3047                                               const uint *src,
3048                                               int length,
3049                                               uint const_alpha)
3050 {
3051     Q_UNUSED(const_alpha);
3052     while (length--)
3053         *dest++ |= *src++;
3054 }
3055
3056 void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest,
3057                                                      int length,
3058                                                      uint color,
3059                                                      uint const_alpha)
3060 {
3061     Q_UNUSED(const_alpha);
3062     color |= 0xff000000;
3063     while (length--)
3064         *dest++ &= color;
3065 }
3066
3067 void QT_FASTCALL rasterop_SourceAndDestination(uint *dest,
3068                                                const uint *src,
3069                                                int length,
3070                                                uint const_alpha)
3071 {
3072     Q_UNUSED(const_alpha);
3073     while (length--) {
3074         *dest = (*src & *dest) | 0xff000000;
3075         ++dest; ++src;
3076     }
3077 }
3078
3079 void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest,
3080                                                      int length,
3081                                                      uint color,
3082                                                      uint const_alpha)
3083 {
3084     Q_UNUSED(const_alpha);
3085     color &= 0x00ffffff;
3086     while (length--)
3087         *dest++ ^= color;
3088 }
3089
3090 void QT_FASTCALL rasterop_SourceXorDestination(uint *dest,
3091                                                const uint *src,
3092                                                int length,
3093                                                uint const_alpha)
3094 {
3095     Q_UNUSED(const_alpha);
3096     while (length--) {
3097         *dest = (*src ^ *dest) | 0xff000000;
3098         ++dest; ++src;
3099     }
3100 }
3101
3102 void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest,
3103                                                            int length,
3104                                                            uint color,
3105                                                            uint const_alpha)
3106 {
3107     Q_UNUSED(const_alpha);
3108     color = ~color;
3109     while (length--) {
3110         *dest = (color & ~(*dest)) | 0xff000000;
3111         ++dest;
3112     }
3113 }
3114
3115 void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *dest,
3116                                                      const uint *src,
3117                                                      int length,
3118                                                      uint const_alpha)
3119 {
3120     Q_UNUSED(const_alpha);
3121     while (length--) {
3122         *dest = (~(*src) & ~(*dest)) | 0xff000000;
3123         ++dest; ++src;
3124     }
3125 }
3126
3127 void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest,
3128                                                           int length,
3129                                                           uint color,
3130                                                           uint const_alpha)
3131 {
3132     Q_UNUSED(const_alpha);
3133     color = ~color | 0xff000000;
3134     while (length--) {
3135         *dest = color | ~(*dest);
3136         ++dest;
3137     }
3138 }
3139
3140 void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *dest,
3141                                                     const uint *src,
3142                                                     int length,
3143                                                     uint const_alpha)
3144 {
3145     Q_UNUSED(const_alpha);
3146     while (length--) {
3147         *dest = ~(*src) | ~(*dest) | 0xff000000;
3148         ++dest; ++src;
3149     }
3150 }
3151
3152 void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest,
3153                                                         int length,
3154                                                         uint color,
3155                                                         uint const_alpha)
3156 {
3157     Q_UNUSED(const_alpha);
3158     color = ~color & 0x00ffffff;
3159     while (length--) {
3160         *dest = color ^ (*dest);
3161         ++dest;
3162     }
3163 }
3164
3165 void QT_FASTCALL rasterop_NotSourceXorDestination(uint *dest,
3166                                                   const uint *src,
3167                                                   int length,
3168                                                   uint const_alpha)
3169 {
3170     Q_UNUSED(const_alpha);
3171     while (length--) {
3172         *dest = ((~(*src)) ^ (*dest)) | 0xff000000;
3173         ++dest; ++src;
3174     }
3175 }
3176
3177 void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length,
3178                                           uint color, uint const_alpha)
3179 {
3180     Q_UNUSED(const_alpha);
3181     qt_memfill(dest, ~color | 0xff000000, length);
3182 }
3183
3184 void QT_FASTCALL rasterop_NotSource(uint *dest, const uint *src,
3185                                     int length, uint const_alpha)
3186 {
3187     Q_UNUSED(const_alpha);
3188     while (length--)
3189         *dest++ = ~(*src++) | 0xff000000;
3190 }
3191
3192 void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest,
3193                                                         int length,
3194                                                         uint color,
3195                                                         uint const_alpha)
3196 {
3197     Q_UNUSED(const_alpha);
3198     color = ~color | 0xff000000;
3199     while (length--) {
3200         *dest = color & *dest;
3201         ++dest;
3202     }
3203 }
3204
3205 void QT_FASTCALL rasterop_NotSourceAndDestination(uint *dest,
3206                                                   const uint *src,
3207                                                   int length,
3208                                                   uint const_alpha)
3209 {
3210     Q_UNUSED(const_alpha);
3211     while (length--) {
3212         *dest = (~(*src) & *dest) | 0xff000000;
3213         ++dest; ++src;
3214     }
3215 }
3216
3217 void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest,
3218                                                         int length,
3219                                                         uint color,
3220                                                         uint const_alpha)
3221 {
3222     Q_UNUSED(const_alpha);
3223     while (length--) {
3224         *dest = (color & ~(*dest)) | 0xff000000;
3225         ++dest;
3226     }
3227 }
3228
3229 void QT_FASTCALL rasterop_SourceAndNotDestination(uint *dest,
3230                                                   const uint *src,
3231                                                   int length,
3232                                                   uint const_alpha)
3233 {
3234     Q_UNUSED(const_alpha);
3235     while (length--) {
3236         *dest = (*src & ~(*dest)) | 0xff000000;
3237         ++dest; ++src;
3238     }
3239 }
3240
3241 static CompositionFunctionSolid functionForModeSolid_C[] = {
3242         comp_func_solid_SourceOver,
3243         comp_func_solid_DestinationOver,
3244         comp_func_solid_Clear,
3245         comp_func_solid_Source,
3246         comp_func_solid_Destination,
3247         comp_func_solid_SourceIn,
3248         comp_func_solid_DestinationIn,
3249         comp_func_solid_SourceOut,
3250         comp_func_solid_DestinationOut,
3251         comp_func_solid_SourceAtop,
3252         comp_func_solid_DestinationAtop,
3253         comp_func_solid_XOR,
3254         comp_func_solid_Plus,
3255         comp_func_solid_Multiply,
3256         comp_func_solid_Screen,
3257         comp_func_solid_Overlay,
3258         comp_func_solid_Darken,
3259         comp_func_solid_Lighten,
3260         comp_func_solid_ColorDodge,
3261         comp_func_solid_ColorBurn,
3262         comp_func_solid_HardLight,
3263         comp_func_solid_SoftLight,
3264         comp_func_solid_Difference,
3265         comp_func_solid_Exclusion,
3266         rasterop_solid_SourceOrDestination,
3267         rasterop_solid_SourceAndDestination,
3268         rasterop_solid_SourceXorDestination,
3269         rasterop_solid_NotSourceAndNotDestination,
3270         rasterop_solid_NotSourceOrNotDestination,
3271         rasterop_solid_NotSourceXorDestination,
3272         rasterop_solid_NotSource,
3273         rasterop_solid_NotSourceAndDestination,
3274         rasterop_solid_SourceAndNotDestination
3275 };
3276
3277 static const CompositionFunctionSolid *functionForModeSolid = functionForModeSolid_C;
3278
3279 static CompositionFunction functionForMode_C[] = {
3280         comp_func_SourceOver,
3281         comp_func_DestinationOver,
3282         comp_func_Clear,
3283         comp_func_Source,
3284         comp_func_Destination,
3285         comp_func_SourceIn,
3286         comp_func_DestinationIn,
3287         comp_func_SourceOut,
3288         comp_func_DestinationOut,
3289         comp_func_SourceAtop,
3290         comp_func_DestinationAtop,
3291         comp_func_XOR,
3292         comp_func_Plus,
3293         comp_func_Multiply,
3294         comp_func_Screen,
3295         comp_func_Overlay,
3296         comp_func_Darken,
3297         comp_func_Lighten,
3298         comp_func_ColorDodge,
3299         comp_func_ColorBurn,
3300         comp_func_HardLight,
3301         comp_func_SoftLight,
3302         comp_func_Difference,
3303         comp_func_Exclusion,
3304         rasterop_SourceOrDestination,
3305         rasterop_SourceAndDestination,
3306         rasterop_SourceXorDestination,
3307         rasterop_NotSourceAndNotDestination,
3308         rasterop_NotSourceOrNotDestination,
3309         rasterop_NotSourceXorDestination,
3310         rasterop_NotSource,
3311         rasterop_NotSourceAndDestination,
3312         rasterop_SourceAndNotDestination
3313 };
3314
3315 static const CompositionFunction *functionForMode = functionForMode_C;
3316
3317 static TextureBlendType getBlendType(const QSpanData *data)
3318 {
3319     TextureBlendType ft;
3320     if (data->txop <= QTransform::TxTranslate)
3321         if (data->texture.type == QTextureData::Tiled)
3322             ft = BlendTiled;
3323         else
3324             ft = BlendUntransformed;
3325     else if (data->bilinear)
3326         if (data->texture.type == QTextureData::Tiled)
3327             ft = BlendTransformedBilinearTiled;
3328         else
3329             ft = BlendTransformedBilinear;
3330     else
3331         if (data->texture.type == QTextureData::Tiled)
3332             ft = BlendTransformedTiled;
3333         else
3334             ft = BlendTransformed;
3335     return ft;
3336 }
3337
3338 static inline Operator getOperator(const QSpanData *data, const QSpan *spans, int spanCount)
3339 {
3340     Operator op;
3341     bool solidSource = false;
3342
3343     switch(data->type) {
3344     case QSpanData::Solid:
3345         solidSource = (qAlpha(data->solid.color) == 255);
3346         break;
3347     case QSpanData::LinearGradient:
3348         solidSource = !data->gradient.alphaColor;
3349         getLinearGradientValues(&op.linear, data);
3350         op.src_fetch = fetchLinearGradient;
3351         break;
3352     case QSpanData::RadialGradient:
3353         solidSource = !data->gradient.alphaColor;
3354         getRadialGradientValues(&op.radial, data);
3355         op.src_fetch = fetchRadialGradient;
3356         break;
3357     case QSpanData::ConicalGradient:
3358         solidSource = !data->gradient.alphaColor;
3359         op.src_fetch = fetchConicalGradient;
3360         break;
3361     case QSpanData::Texture:
3362         op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format];
3363         solidSource = !data->texture.hasAlpha;
3364     default:
3365         break;
3366     }
3367
3368     op.mode = data->rasterBuffer->compositionMode;
3369     if (op.mode == QPainter::CompositionMode_SourceOver && solidSource)
3370         op.mode = QPainter::CompositionMode_Source;
3371
3372     op.dest_fetch = destFetchProc[data->rasterBuffer->format];
3373     if (op.mode == QPainter::CompositionMode_Source) {
3374         switch (data->rasterBuffer->format) {
3375         case QImage::Format_RGB32:
3376         case QImage::Format_ARGB32_Premultiplied:
3377             // don't clear dest_fetch as it sets up the pointer correctly to save one copy
3378             break;
3379         default: {
3380             const QSpan *lastSpan = spans + spanCount;
3381             bool alphaSpans = false;
3382             while (spans < lastSpan) {
3383                 if (spans->coverage != 255) {
3384                     alphaSpans = true;
3385                     break;
3386                 }
3387              &nbs