Get rid of QCustomRasterPaintDevice / QWS stuff in raster engine.
[profile/ivi/qtbase.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 + qreal(0.5);
574     const qreal cy = y + qreal(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 + qreal(0.5);
796     const qreal cy = y + qreal(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 - qreal(0.5);
1192             const qreal py = fy * iw - qreal(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) + qreal(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 + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx;
1434         ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(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 > qreal(-1e-5) && inc < qreal(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 + qreal(0.5)) + data->m13 * (x + qreal(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 + qreal(0.5))
1518                + data->dx + data->m11 * (x + qreal(0.5));
1519     qreal ry = data->m22 * (y + qreal(0.5))
1520                + data->dy + data->m12 * (x + qreal(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 + qreal(0.5))
1567                    + data->m33 + data->m13 * (x + qreal(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 + qreal(0.5))
1597                + data->dx + data->m11 * (x + qreal(0.5));
1598     qreal ry = data->m22 * (y + qreal(0.5))
1599                + data->dy + data->m12 * (x + qreal(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 + qreal(0.5))
1617                    + data->m33 + data->m13 * (x + qreal(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(qSqrt(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                 ++spans;
3388             }
3389             if (!alphaSpans)
3390                 op.dest_fetch = 0;
3391         }
3392         }
3393     }
3394
3395     op.dest_store = destStoreProc[data->rasterBuffer->format];
3396
3397     op.funcSolid = functionForModeSolid[op.mode];
3398     op.func = functionForMode[op.mode];
3399
3400     return op;
3401 }
3402
3403
3404
3405 // -------------------- blend methods ---------------------
3406
3407 enum SpanMethod {
3408     RegularSpans,
3409     CallbackSpans
3410 };
3411
3412 #if !defined(Q_CC_SUN)
3413 static
3414 #endif
3415 void drawBufferSpan(QSpanData *data, const uint *buffer, int bufsize,
3416                            int x, int y, int length, uint const_alpha)
3417 {
3418     Q_UNUSED(data);
3419     Q_UNUSED(buffer);
3420     Q_UNUSED(bufsize);
3421     Q_UNUSED(x);
3422     Q_UNUSED(y);
3423     Q_UNUSED(length);
3424     Q_UNUSED(const_alpha);
3425 }
3426
3427 #if !defined(Q_CC_SUN)
3428 static
3429 #endif
3430 void blend_color_generic(int count, const QSpan *spans, void *userData)
3431 {
3432     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3433     uint buffer[buffer_size];
3434     Operator op = getOperator(data, spans, count);
3435
3436     while (count--) {
3437         int x = spans->x;
3438         int length = spans->len;
3439         while (length) {
3440             int l = qMin(buffer_size, length);
3441             uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3442             op.funcSolid(dest, l, data->solid.color, spans->coverage);
3443             if (op.dest_store)
3444                 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3445             length -= l;
3446             x += l;
3447         }
3448         ++spans;
3449     }
3450 }
3451
3452 static void blend_color_argb(int count, const QSpan *spans, void *userData)
3453 {
3454     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3455
3456     Operator op = getOperator(data, spans, count);
3457
3458     if (op.mode == QPainter::CompositionMode_Source) {
3459         // inline for performance
3460         while (count--) {
3461             uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3462             if (spans->coverage == 255) {
3463                 QT_MEMFILL_UINT(target, spans->len, data->solid.color);
3464             } else {
3465                 uint c = BYTE_MUL(data->solid.color, spans->coverage);
3466                 int ialpha = 255 - spans->coverage;
3467                 for (int i = 0; i < spans->len; ++i)
3468                     target[i] = c + BYTE_MUL(target[i], ialpha);
3469             }
3470             ++spans;
3471         }
3472         return;
3473     }
3474
3475     while (count--) {
3476         uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3477         op.funcSolid(target, spans->len, data->solid.color, spans->coverage);
3478         ++spans;
3479     }
3480 }
3481
3482 template <class T>
3483 Q_STATIC_TEMPLATE_FUNCTION void blendColor(int count, const QSpan *spans, void *userData)
3484 {
3485     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3486     Operator op = getOperator(data, spans, count);
3487
3488     if (op.mode == QPainter::CompositionMode_Source) {
3489         const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(data->solid.color), 0);
3490         while (count--) {
3491             T *target = ((T*)data->rasterBuffer->scanLine(spans->y))
3492                         + spans->x;
3493             if (spans->coverage == 255) {
3494                 qt_memfill(target, c, spans->len);
3495             } else {
3496                 const quint8 alpha = T::alpha(spans->coverage);
3497                 const T color = c.byte_mul(alpha);
3498                 const int ialpha = T::ialpha(spans->coverage);
3499                 const T *end = target + spans->len;
3500                 while (target < end) {
3501                     *target = color + target->byte_mul(ialpha);
3502                     ++target;
3503                 }
3504             }
3505             ++spans;
3506         }
3507         return;
3508     }
3509
3510     if (op.mode == QPainter::CompositionMode_SourceOver) {
3511         while (count--) {
3512             const quint32 color = BYTE_MUL(data->solid.color, spans->coverage);
3513             const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0);
3514             const quint8 ialpha = T::alpha(qAlpha(~color));
3515             T *target = ((T*)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3516             const T *end = target + spans->len;
3517             while (target != end) {
3518                 *target = c + target->byte_mul(ialpha);
3519                 ++target;
3520             }
3521             ++spans;
3522         }
3523         return;
3524     }
3525
3526     blend_color_generic(count, spans, userData);
3527 }
3528
3529 #define SPANFUNC_POINTER_BLENDCOLOR(DST) blendColor<DST>
3530
3531 static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
3532 {
3533     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3534
3535     /*
3536         We duplicate a little logic from getOperator() and calculate the
3537         composition mode directly.  This allows blend_color_rgb16 to be used
3538         from qt_gradient_quint16 with minimal overhead.
3539      */
3540     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
3541     if (mode == QPainter::CompositionMode_SourceOver &&
3542         qAlpha(data->solid.color) == 255)
3543         mode = QPainter::CompositionMode_Source;
3544
3545     if (mode == QPainter::CompositionMode_Source) {
3546         // inline for performance
3547         ushort c = qConvertRgb32To16(data->solid.color);
3548         while (count--) {
3549             ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3550             if (spans->coverage == 255) {
3551                 QT_MEMFILL_USHORT(target, spans->len, c);
3552             } else {
3553                 ushort color = BYTE_MUL_RGB16(c, spans->coverage);
3554                 int ialpha = 255 - spans->coverage;
3555                 const ushort *end = target + spans->len;
3556                 while (target < end) {
3557                     *target = color + BYTE_MUL_RGB16(*target, ialpha);
3558                     ++target;
3559                 }
3560             }
3561             ++spans;
3562         }
3563         return;
3564     }
3565
3566     if (mode == QPainter::CompositionMode_SourceOver) {
3567         while (count--) {
3568             uint color = BYTE_MUL(data->solid.color, spans->coverage);
3569             int ialpha = qAlpha(~color);
3570             ushort c = qConvertRgb32To16(color);
3571             ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3572             int len = spans->len;
3573             bool pre = (((quintptr)target) & 0x3) != 0;
3574             bool post = false;
3575             if (pre) {
3576                 // skip to word boundary
3577                 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3578                 ++target;
3579                 --len;
3580             }
3581             if (len & 0x1) {
3582                 post = true;
3583                 --len;
3584             }
3585             uint *target32 = (uint*)target;
3586             uint c32 = c | (c<<16);
3587             len >>= 1;
3588             uint salpha = (ialpha+1) >> 3; // calculate here rather than in loop
3589             while (len--) {
3590                 // blend full words
3591                 *target32 = c32 + BYTE_MUL_RGB16_32(*target32, salpha);
3592                 ++target32;
3593                 target += 2;
3594             }
3595             if (post) {
3596                 // one last pixel beyond a full word
3597                 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3598             }
3599             ++spans;
3600         }
3601         return;
3602     }
3603
3604     blend_color_generic(count, spans, userData);
3605 }
3606
3607 template <typename T>
3608 void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
3609 {
3610     uint const_alpha = 256;
3611     if (data->type == QSpanData::Texture)
3612         const_alpha = data->texture.const_alpha;
3613
3614     int coverage = 0;
3615     while (count) {
3616         int x = spans->x;
3617         const int y = spans->y;
3618         int right = x + spans->len;
3619
3620         // compute length of adjacent spans
3621         for (int i = 1; i < count && spans[i].y == y && spans[i].x == right; ++i)
3622             right += spans[i].len;
3623         int length = right - x;
3624
3625         while (length) {
3626             int l = qMin(buffer_size, length);
3627             length -= l;
3628
3629             int process_length = l;
3630             int process_x = x;
3631
3632             const uint *src = handler.fetch(process_x, y, process_length);
3633             int offset = 0;
3634             while (l > 0) {
3635                 if (x == spans->x) // new span?
3636                     coverage = (spans->coverage * const_alpha) >> 8;
3637
3638                 int right = spans->x + spans->len;
3639                 int len = qMin(l, right - x);
3640
3641                 handler.process(x, y, len, coverage, src, offset);
3642
3643                 l -= len;
3644                 x += len;
3645                 offset += len;
3646
3647                 if (x == right) { // done with current span?
3648                     ++spans;
3649                     --count;
3650                 }
3651             }
3652             handler.store(process_x, y, process_length);
3653         }
3654     }
3655 }
3656
3657 struct QBlendBase
3658 {
3659     QBlendBase(QSpanData *d, Operator o)
3660         : data(d)
3661         , op(o)
3662         , dest(0)
3663     {
3664     }
3665
3666     QSpanData *data;
3667     Operator op;
3668
3669     uint *dest;
3670
3671     uint buffer[buffer_size];
3672     uint src_buffer[buffer_size];
3673 };
3674
3675 template <SpanMethod spanMethod>
3676 class BlendSrcGeneric : public QBlendBase
3677 {
3678 public:
3679     BlendSrcGeneric(QSpanData *d, Operator o)
3680         : QBlendBase(d, o)
3681     {
3682     }
3683
3684     const uint *fetch(int x, int y, int len)
3685     {
3686         if (spanMethod == RegularSpans)
3687             dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, y, len) : buffer;
3688
3689         return op.src_fetch(src_buffer, &op, data, y, x, len);
3690     }
3691
3692     void process(int x, int y, int len, int coverage, const uint *src, int offset)
3693     {
3694         if (spanMethod == RegularSpans)
3695             op.func(dest + offset, src + offset, len, coverage);
3696         else
3697             drawBufferSpan(data, src + offset, len, x, y, len, coverage);
3698     }
3699
3700     void store(int x, int y, int len)
3701     {
3702         if (spanMethod == RegularSpans && op.dest_store) {
3703             op.dest_store(data->rasterBuffer, x, y, dest, len);
3704         }
3705     }
3706 };
3707
3708 template <SpanMethod spanMethod>
3709 Q_STATIC_TEMPLATE_FUNCTION void blend_src_generic(int count, const QSpan *spans, void *userData)
3710 {
3711     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3712     BlendSrcGeneric<spanMethod> blend(data, getOperator(data, spans, count));
3713     handleSpans(count, spans, data, blend);
3714 }
3715
3716 template <SpanMethod spanMethod>
3717 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
3718 {
3719     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3720
3721     uint buffer[buffer_size];
3722     uint src_buffer[buffer_size];
3723     Operator op = getOperator(data, spans, count);
3724
3725     const int image_width = data->texture.width;
3726     const int image_height = data->texture.height;
3727     int xoff = -qRound(-data->dx);
3728     int yoff = -qRound(-data->dy);
3729
3730     while (count--) {
3731         int x = spans->x;
3732         int length = spans->len;
3733         int sx = xoff + x;
3734         int sy = yoff + spans->y;
3735         if (sy >= 0 && sy < image_height && sx < image_width) {
3736             if (sx < 0) {
3737                 x -= sx;
3738                 length += sx;
3739                 sx = 0;
3740             }
3741             if (sx + length > image_width)
3742                 length = image_width - sx;
3743             if (length > 0) {
3744                 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3745                 while (length) {
3746                     int l = qMin(buffer_size, length);
3747                     const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
3748                     if (spanMethod == RegularSpans) {
3749                         uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3750                         op.func(dest, src, l, coverage);
3751                         if (op.dest_store)
3752                             op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3753                     } else {
3754                         drawBufferSpan(data, src, l, x, spans->y,
3755                                        l, coverage);
3756                     }
3757                     x += l;
3758                     sx += l;
3759                     length -= l;
3760                 }
3761             }
3762         }
3763         ++spans;
3764     }
3765 }
3766
3767 template <SpanMethod spanMethod>
3768 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
3769 {
3770     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3771     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
3772         && data->texture.format != QImage::Format_RGB32) {
3773         blend_untransformed_generic<spanMethod>(count, spans, userData);
3774         return;
3775     }
3776
3777     Operator op = getOperator(data, spans, count);
3778
3779     const int image_width = data->texture.width;
3780     const int image_height = data->texture.height;
3781     int xoff = -qRound(-data->dx);
3782     int yoff = -qRound(-data->dy);
3783
3784     while (count--) {
3785         int x = spans->x;
3786         int length = spans->len;
3787         int sx = xoff + x;
3788         int sy = yoff + spans->y;
3789         if (sy >= 0 && sy < image_height && sx < image_width) {
3790             if (sx < 0) {
3791                 x -= sx;
3792                 length += sx;
3793                 sx = 0;
3794             }
3795             if (sx + length > image_width)
3796                 length = image_width - sx;
3797             if (length > 0) {
3798                 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3799                 const uint *src = (uint *)data->texture.scanLine(sy) + sx;
3800                 if (spanMethod == RegularSpans) {
3801                     uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
3802                     op.func(dest, src, length, coverage);
3803                 } else {
3804                     drawBufferSpan(data, src, length, x,
3805                                    spans->y, length, coverage);
3806                 }
3807             }
3808         }
3809         ++spans;
3810     }
3811 }
3812
3813 static inline quint16 interpolate_pixel_rgb16_255(quint16 x, quint8 a,
3814                                                   quint16 y, quint8 b)
3815 {
3816     quint16 t = ((((x & 0x07e0) * a) + ((y & 0x07e0) * b)) >> 5) & 0x07e0;
3817     t |= ((((x & 0xf81f) * a) + ((y & 0xf81f) * b)) >> 5) & 0xf81f;
3818
3819     return t;
3820 }
3821
3822 static inline quint32 interpolate_pixel_rgb16x2_255(quint32 x, quint8 a,
3823                                                     quint32 y, quint8 b)
3824 {
3825     uint t;
3826     t = ((((x & 0xf81f07e0) >> 5) * a) + (((y & 0xf81f07e0) >> 5) * b)) & 0xf81f07e0;
3827     t |= ((((x & 0x07e0f81f) * a) + ((y & 0x07e0f81f) * b)) >> 5) & 0x07e0f81f;
3828     return t;
3829 }
3830
3831 static inline void blend_sourceOver_rgb16_rgb16(quint16 *dest,
3832                                                 const quint16 *src,
3833                                                 int length,
3834                                                 const quint8 alpha,
3835                                                 const quint8 ialpha)
3836 {
3837     const int dstAlign = ((quintptr)dest) & 0x3;
3838     if (dstAlign) {
3839         *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
3840         ++dest;
3841         ++src;
3842         --length;
3843     }
3844     const int srcAlign = ((quintptr)src) & 0x3;
3845     int length32 = length >> 1;
3846     if (length32 && srcAlign == 0) {
3847         while (length32--) {
3848             const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3849             quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3850             *dest32 = interpolate_pixel_rgb16x2_255(*src32, alpha,
3851                                                     *dest32, ialpha);
3852             dest += 2;
3853             src += 2;
3854         }
3855         length &= 0x1;
3856     }
3857     while (length--) {
3858         *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
3859         ++dest;
3860         ++src;
3861     }
3862 }
3863
3864 template <class DST, class SRC>
3865 Q_STATIC_TEMPLATE_SPECIALIZATION
3866 inline void madd_2(DST *dest, const quint16 alpha, const SRC *src)
3867 {
3868     Q_ASSERT((quintptr(dest) & 0x3) == 0);
3869     Q_ASSERT((quintptr(src) & 0x3) == 0);
3870     dest[0] = dest[0].byte_mul(alpha >> 8) + DST(src[0]);
3871     dest[1] = dest[1].byte_mul(alpha & 0xff) + DST(src[1]);
3872 }
3873
3874 template <class DST, class SRC>
3875 Q_STATIC_TEMPLATE_SPECIALIZATION
3876 inline void madd_4(DST *dest, const quint32 alpha, const SRC *src)
3877 {
3878     Q_ASSERT((quintptr(dest) & 0x3) == 0);
3879     Q_ASSERT((quintptr(src) & 0x3) == 0);
3880     dest[0] = dest[0].byte_mul(alpha >> 24) + DST(src[0]);
3881     dest[1] = dest[1].byte_mul((alpha >> 16) & 0xff) + DST(src[1]);
3882     dest[2] = dest[2].byte_mul((alpha >> 8) & 0xff) + DST(src[2]);
3883     dest[3] = dest[3].byte_mul(alpha & 0xff) + DST(src[3]);
3884 }
3885
3886 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
3887 template <>
3888 Q_STATIC_TEMPLATE_SPECIALIZATION
3889 inline void madd_4(qargb8565 *dest, const quint32 a, const qargb8565 *src)
3890 {
3891     Q_ASSERT((quintptr(dest) & 0x3) == 0);
3892     Q_ASSERT((quintptr(src) & 0x3) == 0);
3893
3894     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3895     quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3896     quint32 x, y, t;
3897     quint8 a8;
3898
3899     {
3900         x = dest32[0];
3901         y = src32[0];
3902
3903         a8 = a >> 24;
3904
3905         // a0,g0
3906         t = ((((x & 0x0007e0ff) * a8) >> 5) & 0x0007e0ff) + (y & 0x0007c0f8);
3907
3908         // r0,b0
3909         t |= ((((x & 0x00f81f00) * a8) >> 5) & 0x00f81f00) + (y & 0x00f81f00);
3910
3911         a8 = (a >> 16) & 0xff;
3912
3913         // a1
3914         t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
3915
3916         dest32[0] = t;
3917     }
3918     {
3919         x = dest32[1];
3920         y = src32[1];
3921
3922         // r1,b1
3923         t = ((((x & 0x0000f81f) * a8) >> 5) & 0x0000f81f) + (y & 0x0000f81f);
3924
3925         // g1
3926         t |= ((((x & 0x000007e0) * a8) >> 5) & 0x000007e0) + (y & 0x000007c0);
3927
3928         a8 = (a >> 8) & 0xff;
3929
3930         // a2
3931         t |= ((((x & 0x00ff0000) * a8) >> 5)  & 0x00ff0000) + (y & 0x00f80000);
3932
3933         {
3934             // rgb2
3935             quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
3936             quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
3937             quint16 t16;
3938
3939             t16 = ((((x16 & 0xf81f) * a8) >> 5) & 0xf81f)  + (y16 & 0xf81f);
3940             t16 |= ((((x16 & 0x07e0) * a8) >> 5) & 0x07e0)  + (y16 & 0x07c0);
3941
3942             // rg2
3943             t |= ((t16 & 0x00ff) << 24);
3944
3945             dest32[1] = t;
3946
3947             x = dest32[2];
3948             y = src32[2];
3949
3950             // gb2
3951             t = (t16 >> 8);
3952         }
3953     }
3954     {
3955         a8 = a & 0xff;
3956
3957         // g3,a3
3958         t |= ((((x & 0x07e0ff00) * a8) >> 5) & 0x07e0ff00) + (y & 0x07c0f800);
3959
3960         // r3,b3
3961         t |= ((((x & 0xf81f0000) >> 5) * a8) & 0xf81f0000)+ (y & 0xf81f0000);
3962
3963         dest32[2] = t;
3964     }
3965 }
3966 #endif
3967
3968 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
3969 template <>
3970 Q_STATIC_TEMPLATE_SPECIALIZATION
3971 inline void madd_4(qargb8555 *dest, const quint32 a, const qargb8555 *src)
3972 {
3973     Q_ASSERT((quintptr(dest) & 0x3) == 0);
3974     Q_ASSERT((quintptr(src) & 0x3) == 0);
3975
3976     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3977     quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3978     quint32 x, y, t;
3979     quint8 a8;
3980
3981     {
3982         x = dest32[0];
3983         y = src32[0];
3984
3985         a8 = a >> 24;
3986
3987         // a0,g0
3988         t = ((((x & 0x0003e0ff) * a8) >> 5) & 0x0003e0ff) + (y & 0x0003e0f8);
3989
3990         // r0,b0
3991         t |= ((((x & 0x007c1f00) * a8) >> 5) & 0x007c1f00) + (y & 0x007c1f00);
3992
3993         a8 = (a >> 16) & 0xff;
3994
3995         // a1
3996         t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
3997
3998         dest32[0] = t;
3999     }
4000     {
4001         x = dest32[1];
4002         y = src32[1];
4003
4004         // r1,b1
4005         t = ((((x & 0x00007c1f) * a8) >> 5) & 0x00007c1f) + (y & 0x00007c1f);
4006
4007         // g1
4008         t |= ((((x & 0x000003e0) * a8) >> 5) & 0x000003e0) + (y & 0x000003e0);
4009
4010         a8 = (a >> 8) & 0xff;
4011
4012         // a2
4013         t |= ((((x & 0x00ff0000) * a8) >> 5)  & 0x00ff0000) + (y & 0x00f80000);
4014
4015         {
4016             // rgb2
4017             quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
4018             quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
4019             quint16 t16;
4020
4021             t16 = ((((x16 & 0x7c1f) * a8) >> 5) & 0x7c1f)  + (y16 & 0x7c1f);
4022             t16 |= ((((x16 & 0x03e0) * a8) >> 5) & 0x03e0)  + (y16 & 0x03e0);
4023
4024             // rg2
4025             t |= ((t16 & 0x00ff) << 24);
4026
4027             dest32[1] = t;
4028
4029             x = dest32[2];
4030             y = src32[2];
4031
4032             // gb2
4033             t = (t16 >> 8);
4034         }
4035     }
4036     {
4037         a8 = a & 0xff;
4038
4039         // g3,a3
4040         t |= ((((x & 0x03e0ff00) * a8) >> 5) & 0x03e0ff00) + (y & 0x03e0f800);
4041
4042         // r3,b3
4043         t |= ((((x & 0x7c1f0000) >> 5) * a8) & 0x7c1f0000)+ (y & 0x7c1f0000);
4044
4045         dest32[2] = t;
4046     }
4047 }
4048 #endif
4049
4050 template <class T>
4051 Q_STATIC_TEMPLATE_SPECIALIZATION
4052 inline quint16 alpha_2(const T *src)
4053 {
4054     Q_ASSERT((quintptr(src) & 0x3) == 0);
4055
4056     if (T::hasAlpha())
4057         return (src[0].alpha() << 8) | src[1].alpha();
4058     else
4059         return 0xffff;
4060 }
4061
4062 template <class T>
4063 Q_STATIC_TEMPLATE_SPECIALIZATION
4064 inline quint32 alpha_4(const T *src)
4065 {
4066     Q_ASSERT((quintptr(src) & 0x3) == 0);
4067
4068     if (T::hasAlpha()) {
4069         return (src[0].alpha() << 24) | (src[1].alpha() << 16)
4070             | (src[2].alpha() << 8) | src[3].alpha();
4071     } else {
4072         return 0xffffffff;
4073     }
4074 }
4075
4076 template <>
4077 Q_STATIC_TEMPLATE_SPECIALIZATION
4078 inline quint32 alpha_4(const qargb8565 *src)
4079 {
4080     const quint8 *src8 = reinterpret_cast<const quint8*>(src);
4081     return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
4082 }
4083
4084 template <>
4085 Q_STATIC_TEMPLATE_SPECIALIZATION
4086 inline quint32 alpha_4(const qargb6666 *src)
4087 {
4088     const quint8 *src8 = reinterpret_cast<const quint8*>(src);
4089     return ((src8[2] & 0xfc) | (src8[2] >> 6)) << 24
4090         | ((src8[5] & 0xfc) | (src8[5] >> 6))  << 16
4091         | ((src8[8] & 0xfc) | (src8[8] >> 6)) << 8
4092         | ((src8[11] & 0xfc) | (src8[11] >> 6));
4093 }
4094
4095 template <>
4096 Q_STATIC_TEMPLATE_SPECIALIZATION
4097 inline quint32 alpha_4(const qargb8555 *src)
4098 {
4099     Q_ASSERT((quintptr(src) & 0x3) == 0);
4100     const quint8 *src8 = reinterpret_cast<const quint8*>(src);
4101     return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
4102 }
4103
4104 template <>
4105 Q_STATIC_TEMPLATE_SPECIALIZATION
4106 inline quint16 alpha_2(const qargb4444 *src)
4107 {
4108     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4109     const quint32 t = (*src32 & 0xf000f000) |
4110                       ((*src32 & 0xf000f000) >> 4);
4111     return (t >> 24) | (t & 0xff00);
4112 }
4113
4114 template <class T>
4115 Q_STATIC_TEMPLATE_SPECIALIZATION
4116 inline quint16 eff_alpha_2(quint16 alpha, const T*)
4117 {
4118     return (T::alpha((alpha >> 8) & 0xff) << 8)
4119         | T::alpha(alpha & 0xff);
4120 }
4121
4122 template <>
4123 Q_STATIC_TEMPLATE_SPECIALIZATION
4124 inline quint16 eff_alpha_2(quint16 a, const qrgb565*)
4125 {
4126     return ((((a & 0xff00) + 0x0100) >> 3) & 0xff00)
4127         | ((((a & 0x00ff) + 0x0001) >> 3) & 0x00ff);
4128 }
4129
4130 template <>
4131 Q_STATIC_TEMPLATE_SPECIALIZATION
4132 inline quint16 eff_alpha_2(quint16 a, const qrgb444*)
4133 {
4134     return (((a & 0x00ff) + 0x0001) >> 4)
4135         | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
4136 }
4137
4138 template <>
4139 Q_STATIC_TEMPLATE_SPECIALIZATION
4140 inline quint16 eff_alpha_2(quint16 a, const qargb4444*)
4141 {
4142     return (((a & 0x00ff) + 0x0001) >> 4)
4143         | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
4144 }
4145
4146 template <class T>
4147 Q_STATIC_TEMPLATE_SPECIALIZATION
4148 inline quint16 eff_ialpha_2(quint16 alpha, const T*)
4149 {
4150     return (T::ialpha((alpha >> 8) & 0xff) << 8)
4151         | T::ialpha(alpha & 0xff);
4152 }
4153
4154 template <>
4155 Q_STATIC_TEMPLATE_SPECIALIZATION
4156 inline quint16 eff_ialpha_2(quint16 a, const qrgb565 *dummy)
4157 {
4158     return 0x2020 - eff_alpha_2(a, dummy);
4159 }
4160
4161 template <>
4162 Q_STATIC_TEMPLATE_SPECIALIZATION
4163 inline quint16 eff_ialpha_2(quint16 a, const qargb4444 *dummy)
4164 {
4165     return 0x1010 - eff_alpha_2(a, dummy);
4166 }
4167
4168 template <>
4169 Q_STATIC_TEMPLATE_SPECIALIZATION
4170 inline quint16 eff_ialpha_2(quint16 a, const qrgb444 *dummy)
4171 {
4172     return 0x1010 - eff_alpha_2(a, dummy);
4173 }
4174
4175 template <class T>
4176 Q_STATIC_TEMPLATE_SPECIALIZATION
4177 inline quint32 eff_alpha_4(quint32 alpha, const T*)
4178 {
4179     return (T::alpha(alpha >> 24) << 24)
4180         | (T::alpha((alpha >> 16) & 0xff) << 16)
4181         | (T::alpha((alpha >> 8) & 0xff) << 8)
4182         | T::alpha(alpha & 0xff);
4183 }
4184
4185 template <>
4186 Q_STATIC_TEMPLATE_SPECIALIZATION
4187 inline quint32 eff_alpha_4(quint32 a, const qrgb888*)
4188 {
4189     return a;
4190 }
4191
4192 template <>
4193 Q_STATIC_TEMPLATE_SPECIALIZATION
4194 inline quint32 eff_alpha_4(quint32 a, const qargb8565*)
4195 {
4196     return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
4197         | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
4198 }
4199
4200 template <>
4201 Q_STATIC_TEMPLATE_SPECIALIZATION
4202 inline quint32 eff_alpha_4(quint32 a, const qargb6666*)
4203 {
4204     return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
4205         | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
4206 }
4207
4208 template <>
4209 Q_STATIC_TEMPLATE_SPECIALIZATION
4210 inline quint32 eff_alpha_4(quint32 a, const qrgb666*)
4211 {
4212     return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
4213         | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
4214 }
4215
4216 template <>
4217 Q_STATIC_TEMPLATE_SPECIALIZATION
4218 inline quint32 eff_alpha_4(quint32 a, const qargb8555*)
4219 {
4220     return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
4221         | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
4222 }
4223
4224 template <class T>
4225 Q_STATIC_TEMPLATE_SPECIALIZATION
4226 inline quint32 eff_ialpha_4(quint32 alpha, const T*)
4227 {
4228     return (T::ialpha(alpha >> 24) << 24)
4229         | (T::ialpha((alpha >> 16) & 0xff) << 16)
4230         | (T::ialpha((alpha >> 8) & 0xff) << 8)
4231         | T::ialpha(alpha & 0xff);
4232 }
4233
4234 template <>
4235 Q_STATIC_TEMPLATE_SPECIALIZATION
4236 inline quint32 eff_ialpha_4(quint32 a, const qrgb888*)
4237 {
4238     return ~a;
4239 }
4240
4241 template <>
4242 Q_STATIC_TEMPLATE_SPECIALIZATION
4243 inline quint32 eff_ialpha_4(quint32 a, const qargb8565 *dummy)
4244 {
4245     return 0x20202020 - eff_alpha_4(a, dummy);
4246 }
4247
4248 template <>
4249 Q_STATIC_TEMPLATE_SPECIALIZATION
4250 inline quint32 eff_ialpha_4(quint32 a, const qargb6666 *dummy)
4251 {
4252     return 0x40404040 - eff_alpha_4(a, dummy);
4253 }
4254
4255 template <>
4256 Q_STATIC_TEMPLATE_SPECIALIZATION
4257 inline quint32 eff_ialpha_4(quint32 a, const qrgb666 *dummy)
4258 {
4259     return 0x40404040 - eff_alpha_4(a, dummy);
4260 }
4261
4262 template <>
4263 Q_STATIC_TEMPLATE_SPECIALIZATION
4264 inline quint32 eff_ialpha_4(quint32 a, const qargb8555 *dummy)
4265 {
4266     return 0x20202020 - eff_alpha_4(a, dummy);
4267 }
4268
4269 template <class DST, class SRC>
4270 inline void interpolate_pixel_unaligned_2(DST *dest, const SRC *src,
4271                                           quint16 alpha)
4272 {
4273     const quint16 a = eff_alpha_2(alpha, dest);
4274     const quint16 ia = eff_ialpha_2(alpha, dest);
4275     dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
4276     dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
4277 }
4278
4279 template <class DST, class SRC>
4280 inline void interpolate_pixel_2(DST *dest, const SRC *src, quint16 alpha)
4281 {
4282     Q_ASSERT((quintptr(dest) & 0x3) == 0);
4283     Q_ASSERT((quintptr(src) & 0x3) == 0);
4284
4285     const quint16 a = eff_alpha_2(alpha, dest);
4286     const quint16 ia = eff_ialpha_2(alpha, dest);
4287
4288     dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
4289     dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
4290 }
4291
4292 template <class DST, class SRC>
4293 inline void interpolate_pixel(DST &dest, quint8 a, const SRC &src, quint8 b)
4294 {
4295     if (SRC::hasAlpha() && !DST::hasAlpha())
4296         interpolate_pixel(dest, a, DST(src), b);
4297     else
4298         dest = dest.byte_mul(a) + DST(src).byte_mul(b);
4299 }
4300
4301 template <>
4302 inline void interpolate_pixel(qargb8565 &dest, quint8 a,
4303                               const qargb8565 &src, quint8 b)
4304 {
4305     quint8 *d = reinterpret_cast<quint8*>(&dest);
4306     const quint8 *s = reinterpret_cast<const quint8*>(&src);
4307     d[0] = (d[0] * a + s[0] * b) >> 5;
4308
4309     const quint16 x = (d[2] << 8) | d[1];
4310     const quint16 y = (s[2] << 8) | s[1];
4311     quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
4312     t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
4313
4314     d[1] = t & 0xff;
4315     d[2] = t >> 8;
4316 }
4317
4318 template <>
4319 inline void interpolate_pixel(qrgb565 &dest, quint8 a,
4320                               const qrgb565 &src, quint8 b)
4321 {
4322     const quint16 x = dest.rawValue();
4323     const quint16 y = src.rawValue();
4324     quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
4325     t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
4326     dest = t;
4327 }
4328
4329 template <>
4330 inline void interpolate_pixel(qrgb555 &dest, quint8 a,
4331                               const qrgb555 &src, quint8 b)
4332 {
4333     const quint16 x = dest.rawValue();
4334     const quint16 y = src.rawValue();
4335     quint16 t = (((x & 0x03e0) * a + (y & 0x03e0) * b) >> 5) & 0x03e0;
4336     t |= ((((x & 0x7c1f) * a) + ((y & 0x7c1f) * b)) >> 5) & 0x7c1f;
4337     dest = t;
4338 }
4339
4340 template <>
4341 inline void interpolate_pixel(qrgb444 &dest, quint8 a,
4342                               const qrgb444 &src, quint8 b)
4343 {
4344     const quint16 x = dest.rawValue();
4345     const quint16 y = src.rawValue();
4346     quint16 t = ((x & 0x00f0) * a + (y & 0x00f0) * b) & 0x0f00;
4347     t |= ((x & 0x0f0f) * a + (y & 0x0f0f) * b) & 0xf0f0;
4348     quint16 *d = reinterpret_cast<quint16*>(&dest);
4349     *d = (t >> 4);
4350 }
4351
4352 template <class DST, class SRC>
4353 inline void interpolate_pixel_2(DST *dest, quint8 a,
4354                                 const SRC *src, quint8 b)
4355 {
4356     Q_ASSERT((quintptr(dest) & 0x3) == 0);
4357     Q_ASSERT((quintptr(src) & 0x3) == 0);
4358
4359     Q_ASSERT(!SRC::hasAlpha());
4360
4361     dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
4362     dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
4363 }
4364
4365 template <>
4366 inline void interpolate_pixel_2(qrgb565 *dest, quint8 a,
4367                                 const qrgb565 *src, quint8 b)
4368 {
4369     quint32 *x = reinterpret_cast<quint32*>(dest);
4370     const quint32 *y = reinterpret_cast<const quint32*>(src);
4371     quint32 t = (((*x & 0xf81f07e0) >> 5) * a +
4372                  ((*y & 0xf81f07e0) >> 5) * b) & 0xf81f07e0;
4373     t |= (((*x & 0x07e0f81f) * a
4374            + (*y & 0x07e0f81f) * b) >> 5) & 0x07e0f81f;
4375     *x = t;
4376 }
4377
4378 template <>
4379 inline void interpolate_pixel_2(qrgb555 *dest, quint8 a,
4380                                 const qrgb555 *src, quint8 b)
4381 {
4382     quint32 *x = reinterpret_cast<quint32*>(dest);
4383     const quint32 *y = reinterpret_cast<const quint32*>(src);
4384     quint32 t = (((*x & 0x7c1f03e0) >> 5) * a +
4385                  ((*y & 0x7c1f03e0) >> 5) * b) & 0x7c1f03e0;
4386     t |= (((*x & 0x03e07c1f) * a
4387            + (*y & 0x03e07c1f) * b) >> 5) & 0x03e07c1f;
4388     *x = t;
4389 }
4390
4391 template <>
4392 inline void interpolate_pixel_2(qrgb444 *dest, quint8 a,
4393                                 const qrgb444 *src, quint8 b)
4394 {
4395     quint32 *x = reinterpret_cast<quint32*>(dest);
4396     const quint32 *y = reinterpret_cast<const quint32*>(src);
4397     quint32 t = ((*x & 0x0f0f0f0f) * a + (*y & 0x0f0f0f0f) * b) & 0xf0f0f0f0;
4398     t |= ((*x & 0x00f000f0) * a + (*y & 0x00f000f0) * b) & 0x0f000f00;
4399     *x = t >> 4;
4400 }
4401
4402 template <class DST, class SRC>
4403 inline void interpolate_pixel_4(DST *dest, const SRC *src, quint32 alpha)
4404 {
4405     Q_ASSERT((quintptr(dest) & 0x3) == 0);
4406     Q_ASSERT((quintptr(src) & 0x3) == 0);
4407
4408     const quint32 a = eff_alpha_4(alpha, dest);
4409     const quint32 ia = eff_ialpha_4(alpha, dest);
4410     dest[0] = DST(src[0]).byte_mul(a >> 24)
4411               + dest[0].byte_mul(ia >> 24);
4412     dest[1] = DST(src[1]).byte_mul((a >> 16) & 0xff)
4413               + dest[1].byte_mul((ia >> 16) & 0xff);
4414     dest[2] = DST(src[2]).byte_mul((a >> 8) & 0xff)
4415               + dest[2].byte_mul((ia >> 8) & 0xff);
4416     dest[3] = DST(src[3]).byte_mul(a & 0xff)
4417               + dest[3].byte_mul(ia & 0xff);
4418 }
4419
4420 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4421 template <>
4422 inline void interpolate_pixel_4(qargb8565 *dest, const qargb8565 *src,
4423                                 quint32 alpha)
4424 {
4425     Q_ASSERT((quintptr(dest) & 0x3) == 0);
4426     Q_ASSERT((quintptr(src) & 0x3) == 0);
4427
4428     const quint32 a = eff_alpha_4(alpha, dest);
4429     const quint32 ia = eff_ialpha_4(alpha, dest);
4430     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4431     quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4432
4433     quint32 x, y, t;
4434     quint8 a8, ia8;
4435     {
4436         x = src32[0];
4437         y = dest32[0];
4438
4439         a8 = a >> 24;
4440         ia8 = ia >> 24;
4441
4442         // a0,g0
4443         t = (((x & 0x0007e0ff) * a8 + (y & 0x0007e0ff) * ia8) >> 5)
4444             & 0x0007e0ff;
4445
4446         // r0,b0
4447         t |= (((x & 0x00f81f00) * a8 + (y & 0x00f81f00) * ia8) >> 5)
4448              & 0x00f81f00;
4449
4450         a8 = (a >> 16) & 0xff;
4451         ia8 = (ia >> 16) & 0xff;
4452
4453         // a1
4454         t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
4455              & 0xff000000;
4456
4457         dest32[0] = t;
4458     }
4459     {
4460         x = src32[1];
4461         y = dest32[1];
4462
4463         // r1,b1
4464         t = (((x & 0x0000f81f) * a8 + (y & 0x0000f81f) * ia8) >> 5)
4465             & 0x0000f81f;
4466
4467         // g1
4468         t |= (((x & 0x000007e0) * a8 + (y & 0x000007e0) * ia8) >> 5)
4469              & 0x000007e0;
4470
4471         a8 = (a >> 8) & 0xff;
4472         ia8 = (ia >> 8) & 0xff;
4473
4474         // a2
4475         t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
4476              & 0x00ff0000;
4477
4478         {
4479             // rgb2
4480             quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
4481             quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
4482             quint16 t16;
4483
4484             t16 = (((x16 & 0xf81f) * a8 + (y16 & 0xf81f) * ia8) >> 5) & 0xf81f;
4485             t16 |= (((x16 & 0x07e0) * a8 + (y16 & 0x07e0) * ia8) >> 5) & 0x07e0;
4486
4487             // rg2
4488             t |= ((t16 & 0x00ff) << 24);
4489
4490             dest32[1] = t;
4491
4492             x = src32[2];
4493             y = dest32[2];
4494
4495             // gb2
4496             t = (t16 >> 8);
4497         }
4498     }
4499     {
4500         a8 = a & 0xff;
4501         ia8 = ia & 0xff;
4502
4503         // g3,a3
4504         t |= (((x & 0x07e0ff00) * a8 + (y & 0x07e0ff00) * ia8) >> 5)
4505              & 0x07e0ff00;
4506
4507         // r3,b3
4508         t |= (((x & 0xf81f0000) >> 5) * a8 + ((y & 0xf81f0000) >> 5) * ia8)
4509              & 0xf81f0000;
4510
4511         dest32[2] = t;
4512     }
4513 }
4514 #endif
4515
4516 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4517 template <>
4518 inline void interpolate_pixel_4(qargb8555 *dest, const qargb8555 *src,
4519                                 quint32 alpha)
4520 {
4521     Q_ASSERT((quintptr(dest) & 0x3) == 0);
4522     Q_ASSERT((quintptr(src) & 0x3) == 0);
4523
4524
4525     const quint32 a = eff_alpha_4(alpha, dest);
4526     const quint32 ia = eff_ialpha_4(alpha, dest);
4527     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4528     quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4529
4530     quint32 x, y, t;
4531     quint8 a8, ia8;
4532     {
4533         x = src32[0];
4534         y = dest32[0];
4535
4536         a8 = a >> 24;
4537         ia8 = ia >> 24;
4538
4539         // a0,g0
4540         t = (((x & 0x0003e0ff) * a8 + (y & 0x0003e0ff) * ia8) >> 5)
4541             & 0x0003e0ff;
4542
4543         // r0,b0
4544         t |= (((x & 0x007c1f00) * a8 + (y & 0x007c1f00) * ia8) >> 5)
4545              & 0x007c1f00;
4546
4547         a8 = (a >> 16) & 0xff;
4548         ia8 = (ia >> 16) & 0xff;
4549
4550         // a1
4551         t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
4552              & 0xff000000;
4553
4554         dest32[0] = t;
4555     }
4556     {
4557         x = src32[1];
4558         y = dest32[1];
4559
4560         // r1,b1
4561         t = (((x & 0x00007c1f) * a8 + (y & 0x00007c1f) * ia8) >> 5)
4562             & 0x00007c1f;
4563
4564         // g1
4565         t |= (((x & 0x000003e0) * a8 + (y & 0x000003e0) * ia8) >> 5)
4566              & 0x000003e0;
4567
4568         a8 = (a >> 8) & 0xff;
4569         ia8 = (ia >> 8) & 0xff;
4570
4571         // a2
4572         t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
4573              & 0x00ff0000;
4574
4575         {
4576             // rgb2
4577             quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
4578             quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
4579             quint16 t16;
4580
4581             t16 = (((x16 & 0x7c1f) * a8 + (y16 & 0x7c1f) * ia8) >> 5) & 0x7c1f;
4582             t16 |= (((x16 & 0x03e0) * a8 + (y16 & 0x03e0) * ia8) >> 5) & 0x03e0;
4583
4584             // rg2
4585             t |= ((t16 & 0x00ff) << 24);
4586
4587             dest32[1] = t;
4588
4589             x = src32[2];
4590             y = dest32[2];
4591
4592             // gb2
4593             t = (t16 >> 8);
4594         }
4595     }
4596     {
4597         a8 = a & 0xff;
4598         ia8 = ia & 0xff;
4599
4600         // g3,a3
4601         t |= (((x & 0x03e0ff00) * a8 + (y & 0x03e0ff00) * ia8) >> 5)
4602              & 0x03e0ff00;
4603
4604         // r3,b3
4605         t |= (((x & 0x7c1f0000) >> 5) * a8 + ((y & 0x7c1f0000) >> 5) * ia8)
4606              & 0x7c1f0000;
4607
4608         dest32[2] = t;
4609     }
4610 }
4611 #endif
4612
4613 template <>
4614 inline void interpolate_pixel_4(qrgb888 *dest, const qrgb888 *src,
4615                                 quint32 alpha)
4616 {
4617     Q_ASSERT((quintptr(dest) & 0x3) == 0);
4618     Q_ASSERT((quintptr(src) & 0x3) == 0);
4619
4620     const quint32 a = eff_alpha_4(alpha, dest);
4621     const quint32 ia = eff_ialpha_4(alpha, dest);
4622     const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4623     quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4624
4625     {
4626         quint32 x = src32[0];
4627         quint32 y = dest32[0];
4628
4629         quint32 t;
4630         t = ((x >> 8) & 0xff00ff) * (a >> 24)
4631             + ((y >> 8) & 0xff00ff) * (ia >> 24);
4632         t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4633         t &= 0xff00ff00;
4634
4635         x = (x & 0xff0000) * (a >> 24)
4636             + (x & 0x0000ff) * ((a >> 16) & 0xff)
4637             + (y & 0xff0000) * (ia >> 24)
4638             + (y & 0x0000ff) * ((ia >> 16) & 0xff);
4639         x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4640         x &= 0x00ff00ff;
4641
4642         dest32[0] = x | t;
4643     }
4644     {
4645         quint32 x = src32[1];
4646         quint32 y = dest32[1];
4647
4648         quint32 t;
4649         t = ((x >> 8) & 0xff0000) * ((a >> 16) & 0xff)
4650             + ((x >> 8) & 0x0000ff) * ((a >> 8) & 0xff)
4651             + ((y >> 8) & 0xff0000) * ((ia >> 16) & 0xff)
4652             + ((y >> 8) & 0x0000ff) * ((ia >> 8) & 0xff);
4653         t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4654         t &= 0xff00ff00;
4655
4656         x = (x & 0xff0000) * ((a >> 16) & 0xff)
4657             + (x & 0x0000ff) * ((a >> 8) & 0xff)
4658             + (y & 0xff0000) * ((ia >> 16) & 0xff)
4659             + (y & 0x0000ff) * ((ia >> 8) & 0xff);
4660         x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4661         x &= 0x00ff00ff;
4662
4663         dest32[1] = x | t;
4664     }
4665     {
4666         quint32 x = src32[2];
4667         quint32 y = dest32[2];
4668
4669         quint32 t;
4670         t = ((x >> 8) & 0xff0000) * ((a >> 8) & 0xff)
4671             + ((x >> 8) & 0x0000ff) * (a & 0xff)
4672             + ((y >> 8) & 0xff0000) * ((ia >> 8) & 0xff)
4673             + ((y >> 8) & 0x0000ff) * (ia & 0xff);
4674         t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4675         t &= 0xff00ff00;
4676
4677         x = (x & 0xff00ff) * (a & 0xff)
4678             + (y & 0xff00ff) * (ia & 0xff);
4679         x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4680         x &= 0x00ff00ff;
4681
4682         dest32[2] = x | t;
4683     }
4684 }
4685
4686 template <class DST, class SRC>
4687 inline void interpolate_pixel_4(DST *dest, quint8 a,
4688                                 const SRC *src, quint8 b)
4689 {
4690     Q_ASSERT((quintptr(dest) & 0x3) == 0);
4691     Q_ASSERT((quintptr(src) & 0x3) == 0);
4692
4693     dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
4694     dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
4695     dest[2] = dest[2].byte_mul(a) + DST(src[2]).byte_mul(b);
4696     dest[3] = dest[3].byte_mul(a) + DST(src[3]).byte_mul(b);
4697 }
4698
4699 template <class DST, class SRC>
4700 inline void blend_sourceOver_4(DST *dest, const SRC *src)
4701 {
4702     Q_ASSERT((quintptr(dest) & 0x3) == 0);
4703     Q_ASSERT((quintptr(src) & 0x3) == 0);
4704
4705     const quint32 a = alpha_4(src);
4706     if (a == 0xffffffff) {
4707         qt_memconvert(dest, src, 4);
4708     } else if (a > 0) {
4709         quint32 buf[3]; // array of quint32 to get correct alignment
4710         qt_memconvert((DST*)(void*)buf, src, 4);
4711         madd_4(dest, eff_ialpha_4(a, dest), (DST*)(void*)buf);
4712     }
4713 }
4714
4715 template <>
4716 inline void blend_sourceOver_4(qargb8565 *dest, const qargb8565 *src)
4717 {
4718     Q_ASSERT((quintptr(dest) & 0x3) == 0);
4719     Q_ASSERT((quintptr(src) & 0x3) == 0);
4720
4721     const quint32 a = alpha_4(src);
4722     if (a == 0xffffffff) {
4723         qt_memconvert(dest, src, 4);
4724     } else if (a > 0) {
4725         madd_4(dest, eff_ialpha_4(a, dest), src);
4726     }
4727 }
4728
4729 template <>
4730 inline void blend_sourceOver_4(qargb8555 *dest, const qargb8555 *src)
4731 {
4732     Q_ASSERT((quintptr(dest) & 0x3) == 0);
4733     Q_ASSERT((quintptr(src) & 0x3) == 0);
4734
4735     const quint32 a = alpha_4(src);
4736     if (a == 0xffffffff) {
4737         qt_memconvert(dest, src, 4);
4738     } else if (a > 0) {
4739         madd_4(dest, eff_ialpha_4(a, dest), src);
4740     }
4741 }
4742
4743 template <>
4744 inline void blend_sourceOver_4(qargb6666 *dest, const qargb6666 *src)
4745 {
4746     Q_ASSERT((quintptr(dest) & 0x3) == 0);
4747     Q_ASSERT((quintptr(src) & 0x3) == 0);
4748
4749     const quint32 a = alpha_4(src);
4750     if (a == 0xffffffff) {
4751         qt_memconvert(dest, src, 4);
4752     } else if (a > 0) {
4753         madd_4(dest, eff_ialpha_4(a, dest), src);
4754     }
4755 }
4756
4757 template <class DST, class SRC>
4758 void QT_FASTCALL blendUntransformed_unaligned(DST *dest, const SRC *src,
4759                                               quint8 coverage, int length)
4760 {
4761     Q_ASSERT(coverage > 0);
4762
4763     if (coverage < 255) {
4764         if (SRC::hasAlpha()) {
4765             for (int i = 0; i < length; ++i) {
4766                 if (src[i].alpha()) {
4767                     const quint8 alpha = qt_div_255(int(src[i].alpha()) * int(coverage));
4768                     interpolate_pixel(dest[i], DST::ialpha(alpha),
4769                             src[i], DST::alpha(alpha));
4770                 }
4771             }
4772         } else {
4773             const quint8 alpha = DST::alpha(coverage);
4774             const quint8 ialpha = DST::ialpha(coverage);
4775             if (alpha) {
4776                 for (int i = 0; i < length; ++i)
4777                     interpolate_pixel(dest[i], ialpha, src[i], alpha);
4778             }
4779         }
4780         return;
4781     }
4782
4783     Q_ASSERT(coverage == 0xff);
4784     Q_ASSERT(SRC::hasAlpha());
4785
4786     if (SRC::hasAlpha()) {
4787         for (int i = 0; i < length; ++i) {
4788             const quint8 a = src->alpha();
4789             if (a == 0xff)
4790                 *dest = DST(*src);
4791             else if (a > 0) {
4792                 if (DST::hasAlpha())
4793                     *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4794                 else
4795                     *dest = DST(SRC(*src).truncedAlpha()) + dest->byte_mul(DST::ialpha(a));
4796             }
4797             ++src;
4798             ++dest;
4799         }
4800     }
4801 }
4802
4803 template <class DST, class SRC>
4804 void QT_FASTCALL blendUntransformed_dest16(DST *dest, const SRC *src,
4805                                            quint8 coverage, int length)
4806 {
4807     Q_ASSERT(sizeof(DST) == 2);
4808     Q_ASSERT(sizeof(SRC) == 2);
4809     Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
4810     Q_ASSERT(coverage > 0);
4811
4812     const int align = quintptr(dest) & 0x3;
4813
4814     if (coverage < 255) {
4815         // align
4816         if (align) {
4817             const quint8 alpha = SRC::hasAlpha()
4818                                  ? qt_div_255(int(src->alpha()) * int(coverage))
4819                                  : coverage;
4820             if (alpha) {
4821                 interpolate_pixel(*dest, DST::ialpha(alpha),
4822                                   *src, DST::alpha(alpha));
4823             }
4824             ++dest;
4825             ++src;
4826             --length;
4827         }
4828
4829         if (SRC::hasAlpha()) {
4830             while (length >= 2) {
4831                 const quint16 alpha16 = BYTE_MUL(uint(alpha_2(src)), uint(coverage));
4832                 interpolate_pixel_2(dest, src, alpha16);
4833                 length -= 2;
4834                 src += 2;
4835                 dest += 2;
4836             }
4837         } else {
4838             const quint8 alpha = DST::alpha(coverage);
4839             const quint8 ialpha = DST::ialpha(coverage);
4840
4841             while (length >= 2) {
4842                 interpolate_pixel_2(dest, ialpha, src, alpha);
4843                 length -= 2;
4844                 src += 2;
4845                 dest += 2;
4846             }
4847         }
4848
4849         // tail
4850         if (length) {
4851             const quint8 alpha = SRC::hasAlpha()
4852                                  ? qt_div_255(int(src->alpha()) * int(coverage))
4853                                  : coverage;
4854             if (alpha) {
4855                 interpolate_pixel(*dest, DST::ialpha(alpha),
4856                                   *src, DST::alpha(alpha));
4857             }
4858         }
4859
4860         return;
4861     }
4862
4863     Q_ASSERT(SRC::hasAlpha());
4864     if (SRC::hasAlpha()) {
4865         if (align) {
4866             const quint8 alpha = src->alpha();
4867             if (alpha == 0xff)
4868                 *dest = DST(*src);
4869             else if (alpha > 0)
4870                 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
4871             ++dest;
4872             ++src;
4873             --length;
4874         }
4875
4876         while (length >= 2) {
4877             Q_ASSERT((quintptr(dest) & 3) == 0);
4878             Q_ASSERT((quintptr(src) & 3) == 0);
4879
4880             const quint16 a = alpha_2(src);
4881             if (a == 0xffff) {
4882                 qt_memconvert(dest, src, 2);
4883             } else if (a > 0) {
4884                 quint32 buf;
4885                 if (sizeof(DST) == 2)
4886                     qt_memconvert((DST*)(void*)&buf, src, 2);
4887                 madd_2(dest, eff_ialpha_2(a, dest), (DST*)(void*)&buf);
4888             }
4889
4890             length -= 2;
4891             src += 2;
4892             dest += 2;
4893         }
4894
4895         if (length) {
4896             const quint8 alpha = src->alpha();
4897             if (alpha == 0xff)
4898                 *dest = DST(*src);
4899             else if (alpha > 0)
4900                 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
4901         }
4902     }
4903 }
4904
4905 template <class DST, class SRC>
4906 void QT_FASTCALL blendUntransformed_dest24(DST *dest, const SRC *src,
4907                                            quint8 coverage, int length)
4908 {
4909     Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
4910     Q_ASSERT(sizeof(DST) == 3);
4911     Q_ASSERT(coverage > 0);
4912
4913     const int align = quintptr(dest) & 0x3;
4914
4915     if (coverage < 255) {
4916         // align
4917         for (int i = 0; i < align; ++i) {
4918             if (SRC::hasAlpha()) {
4919                 const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
4920                 if (alpha)
4921                     interpolate_pixel(*dest, DST::ialpha(alpha),
4922                                       *src, DST::alpha(alpha));
4923             } else {
4924                 interpolate_pixel(*dest, DST::ialpha(coverage),
4925                                   *src, DST::alpha(coverage));
4926             }
4927             ++dest;
4928             ++src;
4929             --length;
4930         }
4931
4932         if (SRC::hasAlpha()) {
4933             while (length >= 4) {
4934                 const quint32 alpha = QT_PREPEND_NAMESPACE(BYTE_MUL)(uint(alpha_4(src)), uint(coverage));
4935                 if (alpha)
4936                     interpolate_pixel_4(dest, src, alpha);
4937                 length -= 4;
4938                 src += 4;
4939                 dest += 4;
4940             }
4941         } else {
4942             const quint8 alpha = DST::alpha(coverage);
4943             const quint8 ialpha = DST::ialpha(coverage);
4944             while (length >= 4) {
4945                 interpolate_pixel_4(dest, ialpha, src, alpha);
4946                 length -= 4;
4947                 src += 4;
4948                 dest += 4;
4949             }
4950         }
4951
4952         // tail
4953         while (length--) {
4954             if (SRC::hasAlpha()) {
4955                 const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
4956                 if (alpha)
4957                     interpolate_pixel(*dest, DST::ialpha(alpha),
4958                                       *src, DST::alpha(alpha));
4959             } else {
4960                 interpolate_pixel(*dest, DST::ialpha(coverage),
4961                                   *src, DST::alpha(coverage));
4962             }
4963             ++dest;
4964             ++src;
4965         }
4966
4967         return;
4968     }
4969
4970
4971     Q_ASSERT(coverage == 255);
4972     Q_ASSERT(SRC::hasAlpha());
4973
4974     if (SRC::hasAlpha()) {
4975         // align
4976         for (int i = 0; i < align; ++i) {
4977             const quint8 a = src->alpha();
4978             if (a == 0xff) {
4979                 *dest = DST(*src);
4980             } else if (a > 0) {
4981                 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4982             }
4983             ++dest;
4984             ++src;
4985             --length;
4986         }
4987
4988         while (length >= 4) {
4989             blend_sourceOver_4(dest, src);
4990             length -= 4;
4991             src += 4;
4992             dest += 4;
4993         }
4994
4995         // tail
4996         while (length--) {
4997             const quint8 a = src->alpha();
4998             if (a == 0xff) {
4999                 *dest = DST(*src);
5000             } else if (a > 0) {
5001                 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
5002             }
5003             ++dest;
5004             ++src;
5005         }
5006     }
5007 }
5008
5009 template <class DST, class SRC>
5010 Q_STATIC_TEMPLATE_SPECIALIZATION
5011 void QT_FASTCALL blendUntransformed(int count, const QSpan *spans, void *userData)
5012 {
5013     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5014     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5015
5016     if (mode != QPainter::CompositionMode_SourceOver &&
5017         mode != QPainter::CompositionMode_Source)
5018     {
5019         blend_src_generic<RegularSpans>(count, spans, userData);
5020         return;
5021     }
5022
5023     const bool modeSource = !SRC::hasAlpha() ||
5024                             mode == QPainter::CompositionMode_Source;
5025     const int image_width = data->texture.width;
5026     const int image_height = data->texture.height;
5027     int xoff = -qRound(-data->dx);
5028     int yoff = -qRound(-data->dy);
5029
5030     while (count--) {
5031         const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5032         if (coverage == 0) {
5033             ++spans;
5034             continue;
5035         }
5036
5037         int x = spans->x;
5038         int length = spans->len;
5039         int sx = xoff + x;
5040         int sy = yoff + spans->y;
5041         if (sy >= 0 && sy < image_height && sx < image_width) {
5042             if (sx < 0) {
5043                 x -= sx;
5044                 length += sx;
5045                 sx = 0;
5046             }
5047             if (sx + length > image_width)
5048                 length = image_width - sx;
5049             if (length > 0) {
5050                 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5051                 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5052                 if (modeSource && coverage == 255) {
5053                     qt_memconvert<DST, SRC>(dest, src, length);
5054                 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && length >= 3 &&
5055                            (quintptr(dest) & 3) == (quintptr(src) & 3))
5056                 {
5057                     blendUntransformed_dest24(dest, src, coverage, length);
5058                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && length >= 3 &&
5059                            (quintptr(dest) & 3) == (quintptr(src) & 3))
5060                 {
5061                     blendUntransformed_dest16(dest, src, coverage, length);
5062                 } else {
5063                     blendUntransformed_unaligned(dest, src, coverage, length);
5064                 }
5065             }
5066         }
5067         ++spans;
5068     }
5069 }
5070
5071 static void blend_untransformed_rgb888(int count, const QSpan *spans,
5072                                        void *userData)
5073 {
5074     blend_untransformed_generic<RegularSpans>(count, spans, userData);
5075 }
5076
5077 static void blend_untransformed_argb6666(int count, const QSpan *spans,
5078                                          void *userData)
5079 {
5080     blend_untransformed_generic<RegularSpans>(count, spans, userData);
5081 }
5082
5083 static void blend_untransformed_rgb666(int count, const QSpan *spans,
5084                                        void *userData)
5085 {
5086     blend_untransformed_generic<RegularSpans>(count, spans, userData);
5087 }
5088
5089 static void blend_untransformed_argb8565(int count, const QSpan *spans,
5090                                          void *userData)
5091 {
5092     blend_untransformed_generic<RegularSpans>(count, spans, userData);
5093 }
5094
5095 static void blend_untransformed_rgb565(int count, const QSpan *spans,
5096                                        void *userData)
5097 {
5098     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5099
5100     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5101         blendUntransformed<qrgb565, qargb8565>(count, spans, userData);
5102     else if (data->texture.format == QImage::Format_RGB16)
5103         blendUntransformed<qrgb565, qrgb565>(count, spans, userData);
5104     else
5105         blend_untransformed_generic<RegularSpans>(count, spans, userData);
5106 }
5107
5108 static void blend_untransformed_argb8555(int count, const QSpan *spans,
5109                                          void *userData)
5110 {
5111     blend_untransformed_generic<RegularSpans>(count, spans, userData);
5112 }
5113
5114 static void blend_untransformed_rgb555(int count, const QSpan *spans,
5115                                        void *userData)
5116 {
5117     blend_untransformed_generic<RegularSpans>(count, spans, userData);
5118 }
5119
5120 static void blend_untransformed_argb4444(int count, const QSpan *spans,
5121                                          void *userData)
5122 {
5123     blend_untransformed_generic<RegularSpans>(count, spans, userData);
5124 }
5125
5126 static void blend_untransformed_rgb444(int count, const QSpan *spans,
5127                                        void *userData)
5128 {
5129     blend_untransformed_generic<RegularSpans>(count, spans, userData);
5130 }
5131
5132 template <SpanMethod spanMethod>
5133 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_generic(int count, const QSpan *spans, void *userData)
5134 {
5135     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5136
5137     uint buffer[buffer_size];
5138     uint src_buffer[buffer_size];
5139     Operator op = getOperator(data, spans, count);
5140
5141     const int image_width = data->texture.width;
5142     const int image_height = data->texture.height;
5143     int xoff = -qRound(-data->dx) % image_width;
5144     int yoff = -qRound(-data->dy) % image_height;
5145
5146     if (xoff < 0)
5147         xoff += image_width;
5148     if (yoff < 0)
5149         yoff += image_height;
5150
5151     while (count--) {
5152         int x = spans->x;
5153         int length = spans->len;
5154         int sx = (xoff + spans->x) % image_width;
5155         int sy = (spans->y + yoff) % image_height;
5156         if (sx < 0)
5157             sx += image_width;
5158         if (sy < 0)
5159             sy += image_height;
5160
5161         const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5162         while (length) {
5163             int l = qMin(image_width - sx, length);
5164             if (buffer_size < l)
5165                 l = buffer_size;
5166             const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
5167             if (spanMethod == RegularSpans) {
5168                 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
5169                 op.func(dest, src, l, coverage);
5170                 if (op.dest_store)
5171                     op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
5172             } else {
5173                 drawBufferSpan(data, src, l, x, spans->y, l,
5174                                coverage);
5175             }
5176             x += l;
5177             sx += l;
5178             length -= l;
5179             if (sx >= image_width)
5180                 sx = 0;
5181         }
5182         ++spans;
5183     }
5184 }
5185
5186 template <SpanMethod spanMethod>
5187 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_argb(int count, const QSpan *spans, void *userData)
5188 {
5189     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5190     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
5191         && data->texture.format != QImage::Format_RGB32) {
5192         blend_tiled_generic<spanMethod>(count, spans, userData);
5193         return;
5194     }
5195
5196     Operator op = getOperator(data, spans, count);
5197
5198     int image_width = data->texture.width;
5199     int image_height = data->texture.height;
5200     int xoff = -qRound(-data->dx) % image_width;
5201     int yoff = -qRound(-data->dy) % image_height;
5202
5203     if (xoff < 0)
5204         xoff += image_width;
5205     if (yoff < 0)
5206         yoff += image_height;
5207
5208     while (count--) {
5209         int x = spans->x;
5210         int length = spans->len;
5211         int sx = (xoff + spans->x) % image_width;
5212         int sy = (spans->y + yoff) % image_height;
5213         if (sx < 0)
5214             sx += image_width;
5215         if (sy < 0)
5216             sy += image_height;
5217
5218         const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5219         while (length) {
5220             int l = qMin(image_width - sx, length);
5221             if (buffer_size < l)
5222                 l = buffer_size;
5223             const uint *src = (uint *)data->texture.scanLine(sy) + sx;
5224             if (spanMethod == RegularSpans) {
5225                 uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
5226                 op.func(dest, src, l, coverage);
5227             } else {
5228                 drawBufferSpan(data, src, buffer_size,
5229                                x, spans->y, l, coverage);
5230             }
5231             x += l;
5232             length -= l;
5233             sx = 0;
5234         }
5235         ++spans;
5236     }
5237 }
5238
5239 template <class DST, class SRC>
5240 Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *userData)
5241 {
5242     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5243     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5244
5245     if (mode != QPainter::CompositionMode_SourceOver &&
5246         mode != QPainter::CompositionMode_Source)
5247     {
5248         blend_src_generic<RegularSpans>(count, spans, userData);
5249         return;
5250     }
5251
5252     const bool modeSource = !SRC::hasAlpha() ||
5253                             mode == QPainter::CompositionMode_Source;
5254     const int image_width = data->texture.width;
5255     const int image_height = data->texture.height;
5256     int xoff = -qRound(-data->dx) % image_width;
5257     int yoff = -qRound(-data->dy) % image_height;
5258
5259     if (xoff < 0)
5260         xoff += image_width;
5261     if (yoff < 0)
5262         yoff += image_height;
5263
5264     while (count--) {
5265         const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5266         if (coverage == 0) {
5267             ++spans;
5268             continue;
5269         }
5270
5271         int x = spans->x;
5272         int length = spans->len;
5273         int sx = (xoff + spans->x) % image_width;
5274         int sy = (spans->y + yoff) % image_height;
5275         if (sx < 0)
5276             sx += image_width;
5277         if (sy < 0)
5278             sy += image_height;
5279
5280         if (modeSource && coverage == 255) {
5281             // Copy the first texture block
5282             length = qMin(image_width,length);
5283             int tx = x;
5284             while (length) {
5285                 int l = qMin(image_width - sx, length);
5286                 if (buffer_size < l)
5287                     l = buffer_size;
5288                 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + tx;
5289                 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5290
5291                 qt_memconvert<DST, SRC>(dest, src, l);
5292                 length -= l;
5293                 tx += l;
5294                 sx = 0;
5295             }
5296
5297             // Now use the rasterBuffer as the source of the texture,
5298             // We can now progressively copy larger blocks
5299             // - Less cpu time in code figuring out what to copy
5300             // We are dealing with one block of data
5301             // - More likely to fit in the cache
5302             // - can use memcpy
5303             int copy_image_width = qMin(image_width, int(spans->len));
5304             length = spans->len - copy_image_width;
5305             DST *src = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5306             DST *dest = src + copy_image_width;
5307             while (copy_image_width < length) {
5308                 qt_memconvert(dest, src, copy_image_width);
5309                 dest += copy_image_width;
5310                 length -= copy_image_width;
5311                 copy_image_width *= 2;
5312             }
5313             if (length > 0)
5314                 qt_memconvert(dest, src, length);
5315         } else {
5316             while (length) {
5317                 int l = qMin(image_width - sx, length);
5318                 if (buffer_size < l)
5319                     l = buffer_size;
5320                 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5321                 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5322                 if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5323                            (quintptr(dest) & 3) == (quintptr(src) & 3))
5324                 {
5325                     blendUntransformed_dest24(dest, src, coverage, l);
5326                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5327                            (quintptr(dest) & 3) == (quintptr(src) & 3))
5328                 {
5329                     blendUntransformed_dest16(dest, src, coverage, l);
5330                 } else {
5331                     blendUntransformed_unaligned(dest, src, coverage, l);
5332                 }
5333
5334                 x += l;
5335                 length -= l;
5336                 sx = 0;
5337             }
5338         }
5339         ++spans;
5340     }
5341 }
5342
5343 static void blend_tiled_rgb888(int count, const QSpan *spans, void *userData)
5344 {
5345     blend_tiled_generic<RegularSpans>(count, spans, userData);
5346 }
5347
5348 static void blend_tiled_argb6666(int count, const QSpan *spans, void *userData)
5349 {
5350     blend_tiled_generic<RegularSpans>(count, spans, userData);
5351 }
5352
5353 static void blend_tiled_rgb666(int count, const QSpan *spans, void *userData)
5354 {
5355     blend_tiled_generic<RegularSpans>(count, spans, userData);
5356 }
5357
5358 static void blend_tiled_argb8565(int count, const QSpan *spans, void *userData)
5359 {
5360     blend_tiled_generic<RegularSpans>(count, spans, userData);
5361 }
5362
5363 static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
5364 {
5365     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5366
5367     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5368         blendTiled<qrgb565, qargb8565>(count, spans, userData);
5369     else if (data->texture.format == QImage::Format_RGB16)
5370         blendTiled<qrgb565, qrgb565>(count, spans, userData);
5371     else
5372         blend_tiled_generic<RegularSpans>(count, spans, userData);
5373 }
5374
5375 static void blend_tiled_argb8555(int count, const QSpan *spans, void *userData)
5376 {
5377     blend_tiled_generic<RegularSpans>(count, spans, userData);
5378 }
5379
5380 static void blend_tiled_rgb555(int count, const QSpan *spans, void *userData)
5381 {
5382     blend_tiled_generic<RegularSpans>(count, spans, userData);
5383 }
5384
5385 static void blend_tiled_argb4444(int count, const QSpan *spans, void *userData)
5386 {
5387     blend_tiled_generic<RegularSpans>(count, spans, userData);
5388 }
5389
5390 static void blend_tiled_rgb444(int count, const QSpan *spans, void *userData)
5391 {
5392     blend_tiled_generic<RegularSpans>(count, spans, userData);
5393 }
5394
5395 template <class DST, class SRC>
5396 Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan *spans,
5397                                      void *userData)
5398 {
5399     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5400     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5401
5402
5403     if (mode != QPainter::CompositionMode_SourceOver) {
5404         blend_src_generic<RegularSpans>(count, spans, userData);
5405         return;
5406     }
5407
5408     SRC buffer[buffer_size];
5409
5410     const int src_minx = data->texture.x1;
5411     const int src_miny = data->texture.y1;
5412     const int src_maxx = data->texture.x2 - 1;
5413     const int src_maxy = data->texture.y2 - 1;
5414
5415     if (data->fast_matrix) {
5416         // The increment pr x in the scanline
5417         const int fdx = (int)(data->m11 * fixed_scale);
5418         const int fdy = (int)(data->m12 * fixed_scale);
5419
5420         while (count--) {
5421             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5422             if (coverage == 0) {
5423                 ++spans;
5424                 continue;
5425             }
5426
5427             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5428                         + spans->x;
5429             const qreal cx = spans->x + qreal(0.5);
5430             const qreal cy = spans->y + qreal(0.5);
5431             int x = int((data->m21 * cy
5432                          + data->m11 * cx + data->dx) * fixed_scale) - half_point;
5433             int y = int((data->m22 * cy
5434                          + data->m12 * cx + data->dy) * fixed_scale) - half_point;
5435             int length = spans->len;
5436
5437             while (length) {
5438                 const int l = qMin(length, buffer_size);
5439
5440                 const SRC *end = buffer + l;
5441                 SRC *b = buffer;
5442                 while (b < end) {
5443                     int x1 = (x >> 16);
5444                     int x2;
5445                     int y1 = (y >> 16);
5446                     int y2;
5447
5448                     const int distx = (x & 0x0000ffff) >> 8;
5449                     const int disty = (y & 0x0000ffff) >> 8;
5450
5451                     if (x1 < src_minx) {
5452                         x2 = x1 = src_minx;
5453                     } else if (x1 >= src_maxx) {
5454                         x2 = x1 = src_maxx;
5455                     } else {
5456                         x2 = x1 + 1;
5457                     }
5458                     if (y1 < src_miny) {
5459                         y2 = y1 = src_miny;
5460                     } else if (y1 >= src_maxy) {
5461                         y2 = y1 = src_maxy;
5462                     } else {
5463                         y2 = y1 + 1;
5464                     }
5465 #if 0
5466                     if (x1 == x2) {
5467                         if (y1 == y2) {
5468                             *b = ((SRC*)data->texture.scanLine(y1))[x1];
5469                         } else {
5470                             *b = ((SRC*)data->texture.scanLine(y1))[x1];
5471                             const SRC t = data->texture.scanLine(y2)[x1];
5472                             interpolate_pixel(*b, SRC::ialpha(disty),
5473                                               t, SRC::alpha(disty));
5474                         }
5475                     } else if (y1 == y2) {
5476                         *b = ((SRC*)data->texture.scanLine(y1))[x1];
5477                         const SRC t = ((SRC*)data->texture.scanLine(y1))[x2];
5478                         interpolate_pixel(*b, SRC::ialpha(distx),
5479                                           t, SRC::alpha(distx));
5480                     } else
5481 #endif
5482                     {
5483                         const SRC *src1 = (SRC*)data->texture.scanLine(y1);
5484                         const SRC *src2 = (SRC*)data->texture.scanLine(y2);
5485                         SRC tl = src1[x1];
5486                         const SRC tr = src1[x2];
5487                         SRC bl = src2[x1];
5488                         const SRC br = src2[x2];
5489                         const quint8 ax = SRC::alpha(distx);
5490                         const quint8 iax = SRC::ialpha(distx);
5491
5492                         interpolate_pixel(tl, iax, tr, ax);
5493                         interpolate_pixel(bl, iax, br, ax);
5494                         interpolate_pixel(tl, SRC::ialpha(disty),
5495                                           bl, SRC::alpha(disty));
5496                         *b = tl;
5497                     }
5498                     ++b;
5499
5500                     x += fdx;
5501                     y += fdy;
5502                 }
5503
5504                 if (!SRC::hasAlpha() && coverage == 255) {
5505                     qt_memconvert(dest, buffer, l);
5506                 } else if (sizeof(DST) == 3 && l >= 4 &&
5507                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5508                 {
5509                     blendUntransformed_dest24(dest, buffer, coverage, l);
5510                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5511                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5512                     blendUntransformed_dest16(dest, buffer, coverage, l);
5513                 } else {
5514                     blendUntransformed_unaligned(dest, buffer, coverage, l);
5515                 }
5516
5517                 dest += l;
5518                 length -= l;
5519             }
5520             ++spans;
5521         }
5522     } else {
5523         const qreal fdx = data->m11;
5524         const qreal fdy = data->m12;
5525         const qreal fdw = data->m13;
5526
5527         while (count--) {
5528             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5529             if (coverage == 0) {
5530                 ++spans;
5531                 continue;
5532             }
5533
5534             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5535                         + spans->x;
5536
5537             const qreal cx = spans->x + qreal(0.5);
5538             const qreal cy = spans->y + qreal(0.5);
5539
5540             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5541             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5542             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5543
5544             int length = spans->len;
5545             while (length) {
5546                 const int l = qMin(length, buffer_size);
5547                 const SRC *end = buffer + l;
5548                 SRC *b = buffer;
5549                 while (b < end) {
5550                     const qreal iw = w == 0 ? 1 : 1 / w;
5551                     const qreal px = x * iw - qreal(0.5);
5552                     const qreal py = y * iw - qreal(0.5);
5553
5554                     int x1 = int(px) - (px < 0);
5555                     int x2;
5556                     int y1 = int(py) - (py < 0);
5557                     int y2;
5558
5559                     const int distx = int((px - x1) * 256);
5560                     const int disty = int((py - y1) * 256);
5561
5562                     if (x1 < src_minx) {
5563                         x2 = x1 = src_minx;
5564                     } else if (x1 >= src_maxx) {
5565                         x2 = x1 = src_maxx;
5566                     } else {
5567                         x2 = x1 + 1;
5568                     }
5569                     if (y1 < src_miny) {
5570                         y2 = y1 = src_miny;
5571                     } else if (y1 >= src_maxy) {
5572                         y2 = y1 = src_maxy;
5573                     } else {
5574                         y2 = y1 + 1;
5575                     }
5576
5577                     const SRC *src1 = (SRC*)data->texture.scanLine(y1);
5578                     const SRC *src2 = (SRC*)data->texture.scanLine(y2);
5579                     SRC tl = src1[x1];
5580                     const SRC tr = src1[x2];
5581                     SRC bl = src2[x1];
5582                     const SRC br = src2[x2];
5583                     const quint8 ax = SRC::alpha(distx);
5584                     const quint8 iax = SRC::ialpha(distx);
5585
5586                     interpolate_pixel(tl, iax, tr, ax);
5587                     interpolate_pixel(bl, iax, br, ax);
5588                     interpolate_pixel(tl, SRC::ialpha(disty),
5589                                       bl, SRC::alpha(disty));
5590                     *b = tl;
5591                     ++b;
5592
5593                     x += fdx;
5594                     y += fdy;
5595                     w += fdw;
5596                 }
5597                 if (!SRC::hasAlpha() && coverage == 255) {
5598                     qt_memconvert(dest, buffer, l);
5599                 } else if (sizeof(DST) == 3 && l >= 4 &&
5600                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5601                 {
5602                     blendUntransformed_dest24(dest, buffer, coverage, l);
5603                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5604                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5605                     blendUntransformed_dest16(dest, buffer, coverage, l);
5606                 } else {
5607                     blendUntransformed_unaligned(dest, buffer, coverage, l);
5608                 }
5609
5610                 dest += l;
5611                 length -= l;
5612             }
5613             ++spans;
5614         }
5615     }
5616 }
5617
5618 static void blend_transformed_bilinear_rgb888(int count, const QSpan *spans, void *userData)
5619 {
5620     blend_src_generic<RegularSpans>(count, spans, userData);
5621 }
5622
5623 static void blend_transformed_bilinear_argb6666(int count, const QSpan *spans, void *userData)
5624 {
5625     blend_src_generic<RegularSpans>(count, spans, userData);
5626 }
5627
5628 static void blend_transformed_bilinear_rgb666(int count, const QSpan *spans, void *userData)
5629 {
5630     blend_src_generic<RegularSpans>(count, spans, userData);
5631 }
5632
5633 static void blend_transformed_bilinear_argb8565(int count, const QSpan *spans, void *userData)
5634 {
5635     blend_src_generic<RegularSpans>(count, spans, userData);
5636 }
5637
5638 static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans,
5639                                               void *userData)
5640 {
5641     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5642
5643     if (data->texture.format == QImage::Format_RGB16)
5644         blendTransformedBilinear<qrgb565, qrgb565>(count, spans, userData);
5645     else if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5646         blendTransformedBilinear<qrgb565, qargb8565>(count, spans, userData);
5647     else
5648         blend_src_generic<RegularSpans>(count, spans, userData);
5649 }
5650
5651 static void blend_transformed_bilinear_argb8555(int count, const QSpan *spans, void *userData)
5652 {
5653     blend_src_generic<RegularSpans>(count, spans, userData);
5654 }
5655
5656 static void blend_transformed_bilinear_rgb555(int count, const QSpan *spans, void *userData)
5657 {
5658     blend_src_generic<RegularSpans>(count, spans, userData);
5659 }
5660
5661 static void blend_transformed_bilinear_argb4444(int count, const QSpan *spans, void *userData)
5662 {
5663     blend_src_generic<RegularSpans>(count, spans, userData);
5664 }
5665
5666 static void blend_transformed_bilinear_rgb444(int count, const QSpan *spans, void *userData)
5667 {
5668     blend_src_generic<RegularSpans>(count, spans, userData);
5669 }
5670
5671 template <SpanMethod spanMethod>
5672 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *spans, void *userData)
5673 {
5674     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5675     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
5676         && data->texture.format != QImage::Format_RGB32) {
5677         blend_src_generic<spanMethod>(count, spans, userData);
5678         return;
5679     }
5680
5681     CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
5682     uint buffer[buffer_size];
5683
5684     int image_width = data->texture.width;
5685     int image_height = data->texture.height;
5686     const int scanline_offset = data->texture.bytesPerLine / 4;
5687
5688     if (data->fast_matrix) {
5689         // The increment pr x in the scanline
5690         int fdx = (int)(data->m11 * fixed_scale);
5691         int fdy = (int)(data->m12 * fixed_scale);
5692
5693         while (count--) {
5694             void *t = data->rasterBuffer->scanLine(spans->y);
5695
5696             uint *target = ((uint *)t) + spans->x;
5697             uint *image_bits = (uint *)data->texture.imageData;
5698
5699             const qreal cx = spans->x + qreal(0.5);
5700             const qreal cy = spans->y + qreal(0.5);
5701
5702             int x = int((data->m21 * cy
5703                          + data->m11 * cx + data->dx) * fixed_scale);
5704             int y = int((data->m22 * cy
5705                          + data->m12 * cx + data->dy) * fixed_scale);
5706
5707             int length = spans->len;
5708             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5709             while (length) {
5710                 int l = qMin(length, buffer_size);
5711                 const uint *end = buffer + l;
5712                 uint *b = buffer;
5713                 while (b < end) {
5714                     int px = x >> 16;
5715                     int py = y >> 16;
5716
5717                     bool out = (px < 0) || (px >= image_width)
5718                                || (py < 0) || (py >= image_height);
5719
5720                     int y_offset = py * scanline_offset;
5721                     *b = out ? uint(0) : image_bits[y_offset + px];
5722                     x += fdx;
5723                     y += fdy;
5724                     ++b;
5725                 }
5726                 if (spanMethod == RegularSpans)
5727                     func(target, buffer, l, coverage);
5728                 else
5729                     drawBufferSpan(data, buffer, buffer_size,
5730                                    spans->x + spans->len - length,
5731                                    spans->y, l, coverage);
5732                 target += l;
5733                 length -= l;
5734             }
5735             ++spans;
5736         }
5737     } else {
5738         const qreal fdx = data->m11;
5739         const qreal fdy = data->m12;
5740         const qreal fdw = data->m13;
5741         while (count--) {
5742             void *t = data->rasterBuffer->scanLine(spans->y);
5743
5744             uint *target = ((uint *)t) + spans->x;
5745             uint *image_bits = (uint *)data->texture.imageData;
5746
5747             const qreal cx = spans->x + qreal(0.5);
5748             const qreal cy = spans->y + qreal(0.5);
5749
5750             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5751             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5752             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5753
5754             int length = spans->len;
5755             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5756             while (length) {
5757                 int l = qMin(length, buffer_size);
5758                 const uint *end = buffer + l;
5759                 uint *b = buffer;
5760                 while (b < end) {
5761                     const qreal iw = w == 0 ? 1 : 1 / w;
5762                     const qreal tx = x * iw;
5763                     const qreal ty = y * iw;
5764                     const int px = int(tx) - (tx < 0);
5765                     const int py = int(ty) - (ty < 0);
5766
5767                     bool out = (px < 0) || (px >= image_width)
5768                                || (py < 0) || (py >= image_height);
5769
5770                     int y_offset = py * scanline_offset;
5771                     *b = out ? uint(0) : image_bits[y_offset + px];
5772                     x += fdx;
5773                     y += fdy;
5774                     w += fdw;
5775
5776                     ++b;
5777                 }
5778                 if (spanMethod == RegularSpans)
5779                     func(target, buffer, l, coverage);
5780                 else
5781                     drawBufferSpan(data, buffer, buffer_size,
5782                                    spans->x + spans->len - length,
5783                                    spans->y, l, coverage);
5784                 target += l;
5785                 length -= l;
5786             }
5787             ++spans;
5788         }
5789     }
5790 }
5791
5792 template <class DST, class SRC>
5793 Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans, void *userData)
5794 {
5795     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5796     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5797
5798     if (mode != QPainter::CompositionMode_SourceOver) {
5799         blend_src_generic<RegularSpans>(count, spans, userData);
5800         return;
5801     }
5802
5803     SRC buffer[buffer_size];
5804     const int image_width = data->texture.width;
5805     const int image_height = data->texture.height;
5806
5807     if (data->fast_matrix) {
5808         // The increment pr x in the scanline
5809         const int fdx = (int)(data->m11 * fixed_scale);
5810         const int fdy = (int)(data->m12 * fixed_scale);
5811
5812         while (count--) {
5813             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5814             if (coverage == 0) {
5815                 ++spans;
5816                 continue;
5817             }
5818
5819             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5820                         + spans->x;
5821             const qreal cx = spans->x + qreal(0.5);
5822             const qreal cy = spans->y + qreal(0.5);
5823             int x = int((data->m21 * cy
5824                          + data->m11 * cx + data->dx) * fixed_scale);
5825             int y = int((data->m22 * cy
5826                          + data->m12 * cx + data->dy) * fixed_scale);
5827             int length = spans->len;
5828
5829             while (length) {
5830                 const int l = qMin(length, buffer_size);
5831
5832                 const SRC *end = buffer + l;
5833                 SRC *b = buffer;
5834                 while (b < end) {
5835                     const int px = (x >> 16);
5836                     const int py = (y >> 16);
5837
5838                     if ((px < 0) || (px >= image_width) ||
5839                         (py < 0) || (py >= image_height))
5840                     {
5841                         *b = 0;
5842                     } else {
5843                         *b = ((SRC*)data->texture.scanLine(py))[px];
5844                     }
5845                     ++b;
5846
5847                     x += fdx;
5848                     y += fdy;
5849                 }
5850
5851                 if (!SRC::hasAlpha() && coverage == 255) {
5852                     qt_memconvert(dest, buffer, l);
5853                 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5854                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5855                 {
5856                     blendUntransformed_dest24(dest, buffer, coverage, l);
5857                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5858                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5859                     blendUntransformed_dest16(dest, buffer, coverage, l);
5860                 } else {
5861                     blendUntransformed_unaligned(dest, buffer, coverage, l);
5862                 }
5863
5864                 dest += l;
5865                 length -= l;
5866             }
5867             ++spans;
5868         }
5869     } else {
5870         const qreal fdx = data->m11;
5871         const qreal fdy = data->m12;
5872         const qreal fdw = data->m13;
5873
5874         while (count--) {
5875             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5876             if (coverage == 0) {
5877                 ++spans;
5878                 continue;
5879             }
5880
5881             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5882                         + spans->x;
5883
5884             const qreal cx = spans->x + qreal(0.5);
5885             const qreal cy = spans->y + qreal(0.5);
5886
5887             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5888             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5889             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5890
5891             int length = spans->len;
5892             while (length) {
5893                 const int l = qMin(length, buffer_size);
5894                 const SRC *end = buffer + l;
5895                 SRC *b = buffer;
5896                 while (b < end) {
5897                     const qreal iw = w == 0 ? 1 : 1 / w;
5898                     const qreal tx = x * iw;
5899                     const qreal ty = y * iw;
5900
5901                     const int px = int(tx) - (tx < 0);
5902                     const int py = int(ty) - (ty < 0);
5903
5904                     if ((px < 0) || (px >= image_width) ||
5905                         (py < 0) || (py >= image_height))
5906                     {
5907                         *b = 0;
5908                     } else {
5909                         *b = ((SRC*)data->texture.scanLine(py))[px];
5910                     }
5911                     ++b;
5912
5913                     x += fdx;
5914                     y += fdy;
5915                     w += fdw;
5916                 }
5917                 if (!SRC::hasAlpha() && coverage == 255) {
5918                     qt_memconvert(dest, buffer, l);
5919                 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5920                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5921                 {
5922                     blendUntransformed_dest24(dest, buffer, coverage, l);
5923                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5924                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5925                     blendUntransformed_dest16(dest, buffer, coverage, l);
5926                 } else {
5927                     blendUntransformed_unaligned(dest, buffer, coverage, l);
5928                 }
5929
5930                 dest += l;
5931                 length -= l;
5932             }
5933             ++spans;
5934         }
5935     }
5936 }
5937
5938 static void blend_transformed_rgb888(int count, const QSpan *spans,
5939                                      void *userData)
5940 {
5941     blend_src_generic<RegularSpans>(count, spans, userData);
5942 }
5943
5944 static void blend_transformed_argb6666(int count, const QSpan *spans,
5945                                        void *userData)
5946 {
5947     blend_src_generic<RegularSpans>(count, spans, userData);
5948 }
5949
5950 static void blend_transformed_rgb666(int count, const QSpan *spans,
5951                                        void *userData)
5952 {
5953     blend_src_generic<RegularSpans>(count, spans, userData);
5954 }
5955
5956 static void blend_transformed_argb8565(int count, const QSpan *spans,
5957                                          void *userData)
5958 {
5959     blend_src_generic<RegularSpans>(count, spans, userData);
5960 }
5961
5962 static void blend_transformed_rgb565(int count, const QSpan *spans,
5963                                        void *userData)
5964 {
5965     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5966
5967     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5968         blendTransformed<qrgb565, qargb8565>(count, spans, userData);
5969     else if (data->texture.format == QImage::Format_RGB16)
5970         blendTransformed<qrgb565, qrgb565>(count, spans, userData);
5971     else
5972         blend_src_generic<RegularSpans>(count, spans, userData);
5973 }
5974
5975 static void blend_transformed_argb8555(int count, const QSpan *spans,
5976                                          void *userData)
5977 {
5978     blend_src_generic<RegularSpans>(count, spans, userData);
5979 }
5980
5981 static void blend_transformed_rgb555(int count, const QSpan *spans,
5982                                        void *userData)
5983 {
5984     blend_src_generic<RegularSpans>(count, spans, userData);
5985 }
5986
5987 static void blend_transformed_argb4444(int count, const QSpan *spans,
5988                                          void *userData)
5989 {
5990     blend_src_generic<RegularSpans>(count, spans, userData);
5991 }
5992
5993 static void blend_transformed_rgb444(int count, const QSpan *spans,
5994                                        void *userData)
5995 {
5996     blend_src_generic<RegularSpans>(count, spans, userData);
5997 }
5998
5999 template <SpanMethod spanMethod>
6000 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QSpan *spans, void *userData)
6001 {
6002     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6003     if (data->texture.format != QImage::Format_ARGB32_Premultiplied
6004         && data->texture.format != QImage::Format_RGB32) {
6005         blend_src_generic<spanMethod>(count, spans, userData);
6006         return;
6007     }
6008
6009     CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
6010     uint buffer[buffer_size];
6011
6012     int image_width = data->texture.width;
6013     int image_height = data->texture.height;
6014     const int scanline_offset = data->texture.bytesPerLine / 4;
6015
6016     if (data->fast_matrix) {
6017         // The increment pr x in the scanline
6018         int fdx = (int)(data->m11 * fixed_scale);
6019         int fdy = (int)(data->m12 * fixed_scale);
6020
6021         while (count--) {
6022             void *t = data->rasterBuffer->scanLine(spans->y);
6023
6024             uint *target = ((uint *)t) + spans->x;
6025             uint *image_bits = (uint *)data->texture.imageData;
6026
6027             const qreal cx = spans->x + qreal(0.5);
6028             const qreal cy = spans->y + qreal(0.5);
6029
6030             int x = int((data->m21 * cy
6031                          + data->m11 * cx + data->dx) * fixed_scale);
6032             int y = int((data->m22 * cy
6033                          + data->m12 * cx + data->dy) * fixed_scale);
6034
6035             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
6036             int length = spans->len;
6037             while (length) {
6038                 int l = qMin(length, buffer_size);
6039                 const uint *end = buffer + l;
6040                 uint *b = buffer;
6041                 while (b < end) {
6042                     int px = x >> 16;
6043                     int py = y >> 16;
6044                     px %= image_width;
6045                     py %= image_height;
6046                     if (px < 0) px += image_width;
6047                     if (py < 0) py += image_height;
6048                     int y_offset = py * scanline_offset;
6049
6050                     Q_ASSERT(px >= 0 && px < image_width);
6051                     Q_ASSERT(py >= 0 && py < image_height);
6052
6053                     *b = image_bits[y_offset + px];
6054                     x += fdx;
6055                     y += fdy;
6056                     ++b;
6057                 }
6058                 if (spanMethod == RegularSpans)
6059                     func(target, buffer, l, coverage);
6060                 else
6061                     drawBufferSpan(data, buffer, buffer_size,
6062                                    spans->x + spans->len - length,
6063                                    spans->y, l, coverage);
6064                 target += l;
6065                 length -= l;
6066             }
6067             ++spans;
6068         }
6069     } else {
6070         const qreal fdx = data->m11;
6071         const qreal fdy = data->m12;
6072         const qreal fdw = data->m13;
6073         while (count--) {
6074             void *t = data->rasterBuffer->scanLine(spans->y);
6075
6076             uint *target = ((uint *)t) + spans->x;
6077             uint *image_bits = (uint *)data->texture.imageData;
6078
6079             const qreal cx = spans->x + qreal(0.5);
6080             const qreal cy = spans->y + qreal(0.5);
6081
6082             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
6083             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
6084             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
6085
6086             const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
6087             int length = spans->len;
6088             while (length) {
6089                 int l = qMin(length, buffer_size);
6090                 const uint *end = buffer + l;
6091                 uint *b = buffer;
6092                 while (b < end) {
6093                     const qreal iw = w == 0 ? 1 : 1 / w;
6094                     const qreal tx = x * iw;
6095                     const qreal ty = y * iw;
6096                     int px = int(tx) - (tx < 0);
6097                     int py = int(ty) - (ty < 0);
6098
6099                     px %= image_width;
6100                     py %= image_height;
6101                     if (px < 0) px += image_width;
6102                     if (py < 0) py += image_height;
6103                     int y_offset = py * scanline_offset;
6104
6105                     Q_ASSERT(px >= 0 && px < image_width);
6106                     Q_ASSERT(py >= 0 && py < image_height);
6107
6108                     *b = image_bits[y_offset + px];
6109                     x += fdx;
6110                     y += fdy;
6111                     w += fdw;
6112                     //force increment to avoid /0
6113                     if (!w) {
6114                         w += fdw;
6115                     }
6116                     ++b;
6117                 }
6118                 if (spanMethod == RegularSpans)
6119                     func(target, buffer, l, coverage);
6120                 else
6121                     drawBufferSpan(data, buffer, buffer_size,
6122                                    spans->x + spans->len - length,
6123                                    spans->y, l, coverage);
6124                 target += l;
6125                 length -= l;
6126             }
6127             ++spans;
6128         }
6129     }
6130 }
6131
6132 template <class DST, class SRC>
6133 Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *spans, void *userData)
6134 {
6135     QSpanData *data = reinterpret_cast<QSpanData*>(userData);
6136     QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
6137
6138     if (mode != QPainter::CompositionMode_SourceOver) {
6139         blend_src_generic<RegularSpans>(count, spans, userData);
6140         return;
6141     }
6142
6143     SRC buffer[buffer_size];
6144     const int image_width = data->texture.width;
6145     const int image_height = data->texture.height;
6146
6147     if (data->fast_matrix) {
6148         // The increment pr x in the scanline
6149         const int fdx = (int)(data->m11 * fixed_scale);
6150         const int fdy = (int)(data->m12 * fixed_scale);
6151
6152         while (count--) {
6153             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
6154             if (coverage == 0) {
6155                 ++spans;
6156                 continue;
6157             }
6158
6159             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
6160                         + spans->x;
6161             const qreal cx = spans->x + qreal(0.5);
6162             const qreal cy = spans->y + qreal(0.5);
6163             int x = int((data->m21 * cy
6164                          + data->m11 * cx + data->dx) * fixed_scale);
6165             int y = int((data->m22 * cy
6166                          + data->m12 * cx + data->dy) * fixed_scale);
6167             int length = spans->len;
6168
6169             while (length) {
6170                 const int l = qMin(length, buffer_size);
6171
6172                 const SRC *end = buffer + l;
6173                 SRC *b = buffer;
6174                 while (b < end) {
6175                     int px = (x >> 16) % image_width;
6176                     int py = (y >> 16) % image_height;
6177
6178                     if (px < 0)
6179                         px += image_width;
6180                     if (py < 0)
6181                         py += image_height;
6182
6183                     *b = ((SRC*)data->texture.scanLine(py))[px];
6184                     ++b;
6185
6186                     x += fdx;
6187                     y += fdy;
6188                 }
6189
6190                 if (!SRC::hasAlpha() && coverage == 255) {
6191                     qt_memconvert(dest, buffer, l);
6192                 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6193                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6194                 {
6195                     blendUntransformed_dest24(dest, buffer, coverage, l);
6196                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6197                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6198                     blendUntransformed_dest16(dest, buffer, coverage, l);
6199                 } else {
6200                     blendUntransformed_unaligned(dest, buffer, coverage, l);
6201                 }
6202
6203                 dest += l;
6204                 length -= l;
6205             }
6206             ++spans;
6207         }
6208     } else {
6209         const qreal fdx = data->m11;
6210         const qreal fdy = data->m12;
6211         const qreal fdw = data->m13;
6212
6213         while (count--) {
6214             const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
6215             if (coverage == 0) {
6216                 ++spans;
6217                 continue;
6218             }
6219
6220             DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
6221                         + spans->x;
6222
6223             const qreal cx = spans->x + qreal(0.5);
6224             const qreal cy = spans->y + qreal(0.5);
6225
6226             qreal x = data->m21 * cy + data->m11 * cx + data->dx;
6227             qreal y = data->m22 * cy + data->m12 * cx + data->dy;
6228             qreal w = data->m23 * cy + data->m13 * cx + data->m33;
6229
6230             int length = spans->len;
6231             while (length) {
6232                 const int l = qMin(length, buffer_size);
6233                 const SRC *end = buffer + l;
6234                 SRC *b = buffer;
6235                 while (b < end) {
6236                     const qreal iw = w == 0 ? 1 : 1 / w;
6237                     const qreal tx = x * iw;
6238                     const qreal ty = y * iw;
6239
6240                     int px = int(tx) - (tx < 0);
6241                     int py = int(ty) - (ty < 0);
6242
6243                     px %= image_width;
6244                     py %= image_height;
6245                     if (px < 0)
6246                         px += image_width;
6247                     if (py < 0)
6248                         py += image_height;
6249
6250                     *b = ((SRC*)data->texture.scanLine(py))[px];
6251                     ++b;
6252
6253                     x += fdx;
6254                     y += fdy;
6255                     w += fdw;
6256                     // force increment to avoid /0
6257                     if (!w)
6258                         w += fdw;
6259                 }
6260                 if (!SRC::hasAlpha() && coverage == 255) {
6261                     qt_memconvert(dest, buffer, l);
6262                 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6263                            (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6264                 {
6265                     blendUntransformed_dest24(dest, buffer, coverage, l);
6266                 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6267                            (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6268                     blendUntransformed_dest16(dest, buffer, coverage, l);
6269                 } else {
6270                     blendUntransformed_unaligned(dest, buffer, coverage, l);
6271                 }
6272
6273                 dest += l;
6274                 length -= l;
6275             }
6276             ++spans;
6277         }
6278     }
6279 }
6280
6281 static void blend_transformed_tiled_rgb888(int count, const QSpan *spans,
6282                                            void *userData)
6283 {
6284     blend_src_generic<RegularSpans>(count, spans, userData);
6285 }
6286
6287 static void blend_transformed_tiled_argb6666(int count, const QSpan *spans,
6288                                              void *userData)
6289 {
6290     blend_src_generic<RegularSpans>(count, spans, userData);
6291 }
6292
6293 static void blend_transformed_tiled_rgb666(int count, const QSpan *spans,
6294                                            void *userData)
6295 {
6296     blend_src_generic<RegularSpans>(count, spans, userData);
6297 }
6298
6299 static void blend_transformed_tiled_argb8565(int count, const QSpan *spans,
6300                                              void *userData)
6301 {
6302     blend_src_generic<RegularSpans>(count, spans, userData);
6303 }
6304
6305 static void blend_transformed_tiled_rgb565(int count, const QSpan *spans,
6306                                            void *userData)
6307 {
6308     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6309
6310     if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
6311         blendTransformedTiled<qrgb565, qargb8565>(count, spans, userData);
6312     else if (data->texture.format == QImage::Format_RGB16)
6313         blendTransformedTiled<qrgb565, qrgb565>(count, spans, userData);
6314     else
6315         blend_src_generic<RegularSpans>(count, spans, userData);
6316 }
6317
6318 static void blend_transformed_tiled_argb8555(int count, const QSpan *spans,
6319                                              void *userData)
6320 {
6321     blend_src_generic<RegularSpans>(count, spans, userData);
6322 }
6323
6324 static void blend_transformed_tiled_rgb555(int count, const QSpan *spans,
6325                                            void *userData)
6326 {
6327     blend_src_generic<RegularSpans>(count, spans, userData);
6328 }
6329
6330 static void blend_transformed_tiled_argb4444(int count, const QSpan *spans,
6331                                              void *userData)
6332 {
6333     blend_src_generic<RegularSpans>(count, spans, userData);
6334 }
6335
6336 static void blend_transformed_tiled_rgb444(int count, const QSpan *spans,
6337                                            void *userData)
6338 {
6339     blend_src_generic<RegularSpans>(count, spans, userData);
6340 }
6341
6342 # define SPANFUNC_POINTER(Name, Arg) Name<Arg>
6343
6344
6345 /* Image formats here are target formats */
6346 static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats] = {
6347     // Untransformed
6348     {
6349         0, // Invalid
6350         SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Mono
6351         SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // MonoLsb
6352         SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Indexed8
6353         SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // RGB32
6354         SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // ARGB32
6355         SPANFUNC_POINTER(blend_untransformed_argb, RegularSpans), // ARGB32_Premultiplied
6356         blend_untransformed_rgb565,
6357         blend_untransformed_argb8565,
6358         blend_untransformed_rgb666,
6359         blend_untransformed_argb6666,
6360         blend_untransformed_rgb555,
6361         blend_untransformed_argb8555,
6362         blend_untransformed_rgb888,
6363         blend_untransformed_rgb444,
6364         blend_untransformed_argb4444,
6365     },
6366     // Tiled
6367     {
6368         0, // Invalid
6369         SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Mono
6370         SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // MonoLsb
6371         SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Indexed8
6372         SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // RGB32
6373         SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // ARGB32
6374         SPANFUNC_POINTER(blend_tiled_argb, RegularSpans), // ARGB32_Premultiplied
6375         blend_tiled_rgb565,
6376         blend_tiled_argb8565,
6377         blend_tiled_rgb666,
6378         blend_tiled_argb6666,
6379         blend_tiled_rgb555,
6380         blend_tiled_argb8555,
6381         blend_tiled_rgb888,
6382         blend_tiled_rgb444,
6383         blend_tiled_argb4444,
6384     },
6385     // Transformed
6386     {
6387         0, // Invalid
6388         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6389         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6390         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6391         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6392         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6393         SPANFUNC_POINTER(blend_transformed_argb, RegularSpans), // ARGB32_Premultiplied
6394         blend_transformed_rgb565,
6395         blend_transformed_argb8565,
6396         blend_transformed_rgb666,
6397         blend_transformed_argb6666,
6398         blend_transformed_rgb555,
6399         blend_transformed_argb8555,
6400         blend_transformed_rgb888,
6401         blend_transformed_rgb444,
6402         blend_transformed_argb4444,
6403     },
6404      // TransformedTiled
6405     {
6406         0,
6407         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6408         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6409         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6410         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6411         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6412         SPANFUNC_POINTER(blend_transformed_tiled_argb, RegularSpans), // ARGB32_Premultiplied
6413         blend_transformed_tiled_rgb565,
6414         blend_transformed_tiled_argb8565,
6415         blend_transformed_tiled_rgb666,
6416         blend_transformed_tiled_argb6666,
6417         blend_transformed_tiled_rgb555,
6418         blend_transformed_tiled_argb8555,
6419         blend_transformed_tiled_rgb888,
6420         blend_transformed_tiled_rgb444,
6421         blend_transformed_tiled_argb4444
6422     },
6423     // Bilinear
6424     {
6425         0,
6426         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6427         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6428         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6429         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6430         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6431         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
6432         blend_transformed_bilinear_rgb565,
6433         blend_transformed_bilinear_argb8565,
6434         blend_transformed_bilinear_rgb666,
6435         blend_transformed_bilinear_argb6666,
6436         blend_transformed_bilinear_rgb555,
6437         blend_transformed_bilinear_argb8555,
6438         blend_transformed_bilinear_rgb888,
6439         blend_transformed_bilinear_rgb444,
6440         blend_transformed_bilinear_argb4444,
6441     },
6442     // BilinearTiled
6443     {
6444         0,
6445         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6446         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6447         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6448         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6449         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6450         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
6451         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB16
6452         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8565_Premultiplied
6453         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB666
6454         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB6666_Premultiplied
6455         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB555
6456         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8555_Premultiplied
6457         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB888
6458         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB444
6459         SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB4444_Premultiplied
6460     }
6461 };
6462
6463 void qBlendTexture(int count, const QSpan *spans, void *userData)
6464 {
6465     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6466     ProcessSpans proc = processTextureSpans[getBlendType(data)][data->rasterBuffer->format];
6467     proc(count, spans, userData);
6468 }
6469
6470 template <class DST>
6471 inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
6472                                    int x, int y, quint32 color,
6473                                    const uchar *map,
6474                                    int mapWidth, int mapHeight, int mapStride,
6475                                    DST dummy = 0)
6476 {
6477     Q_UNUSED(dummy);
6478     const DST c = qt_colorConvert<DST, quint32>(color, 0);
6479     DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
6480     const int destStride = rasterBuffer->bytesPerLine() / sizeof(DST);
6481
6482     if (mapWidth > 8) {
6483         while (mapHeight--) {
6484             int x0 = 0;
6485             int n = 0;
6486             for (int x = 0; x < mapWidth; x += 8) {
6487                 uchar s = map[x >> 3];
6488                 for (int i = 0; i < 8; ++i) {
6489                     if (s & 0x80) {
6490                         ++n;
6491                     } else {
6492                         if (n) {
6493                             qt_memfill(dest + x0, c, n);
6494                             x0 += n + 1;
6495                             n = 0;
6496                         } else {
6497                             ++x0;
6498                         }
6499                         if (!s) {
6500                             x0 += 8 - 1 - i;
6501                             break;
6502                         }
6503                     }
6504                     s <<= 1;
6505                 }
6506             }
6507             if (n)
6508                 qt_memfill(dest + x0, c, n);
6509             dest += destStride;
6510             map += mapStride;
6511         }
6512     } else {
6513         while (mapHeight--) {
6514             int x0 = 0;
6515             int n = 0;
6516             for (uchar s = *map; s; s <<= 1) {
6517                 if (s & 0x80) {
6518                     ++n;
6519                 } else if (n) {
6520                     qt_memfill(dest + x0, c, n);
6521                     x0 += n + 1;
6522                     n = 0;
6523                 } else {
6524                     ++x0;
6525                 }
6526             }
6527             if (n)
6528                 qt_memfill(dest + x0, c, n);
6529             dest += destStride;
6530             map += mapStride;
6531         }
6532     }
6533 }
6534
6535 static void qt_gradient_quint32(int count, const QSpan *spans, void *userData)
6536 {
6537     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6538
6539     bool isVerticalGradient =
6540         data->txop <= QTransform::TxScale &&
6541         data->type == QSpanData::LinearGradient &&
6542         data->gradient.linear.end.x == data->gradient.linear.origin.x;
6543
6544     if (isVerticalGradient) {
6545         LinearGradientValues linear;
6546         getLinearGradientValues(&linear, data);
6547
6548         CompositionFunctionSolid funcSolid =
6549             functionForModeSolid[data->rasterBuffer->compositionMode];
6550
6551         /*
6552             The logic for vertical gradient calculations is a mathematically
6553             reduced copy of that in fetchLinearGradient() - which is basically:
6554
6555                 qreal ry = data->m22 * (y + 0.5) + data->dy;
6556                 qreal t = linear.dy*ry + linear.off;
6557                 t *= (GRADIENT_STOPTABLE_SIZE - 1);
6558                 quint32 color =
6559                     qt_gradient_pixel_fixed(&data->gradient,
6560                                             int(t * FIXPT_SIZE));
6561
6562             This has then been converted to fixed point to improve performance.
6563          */
6564         const int gss = GRADIENT_STOPTABLE_SIZE - 1;
6565         int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
6566         int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
6567
6568         while (count--) {
6569             int y = spans->y;
6570             int x = spans->x;
6571
6572             quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x;
6573             quint32 color =
6574                 qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
6575
6576             funcSolid(dst, spans->len, color, spans->coverage);
6577             ++spans;
6578         }
6579
6580     } else {
6581         blend_src_generic<RegularSpans>(count, spans, userData);
6582     }
6583 }
6584
6585 static void qt_gradient_quint16(int count, const QSpan *spans, void *userData)
6586 {
6587     QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6588
6589     bool isVerticalGradient =
6590         data->txop <= QTransform::TxScale &&
6591         data->type == QSpanData::LinearGradient &&
6592         data->gradient.linear.end.x == data->gradient.linear.origin.x;
6593
6594     if (isVerticalGradient) {
6595
6596         LinearGradientValues linear;
6597         getLinearGradientValues(&linear, data);
6598
6599         /*
6600             The logic for vertical gradient calculations is a mathematically
6601             reduced copy of that in fetchLinearGradient() - which is basically:
6602
6603                 qreal ry = data->m22 * (y + 0.5) + data->dy;
6604                 qreal t = linear.dy*ry + linear.off;
6605                 t *= (GRADIENT_STOPTABLE_SIZE - 1);
6606                 quint32 color =
6607                     qt_gradient_pixel_fixed(&data->gradient,
6608                                             int(t * FIXPT_SIZE));
6609
6610             This has then been converted to fixed point to improve performance.
6611          */
6612         const int gss = GRADIENT_STOPTABLE_SIZE - 1;
6613         int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
6614         int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
6615
6616         uint oldColor = data->solid.color;
6617         while (count--) {
6618             int y = spans->y;
6619
6620             quint32 color = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
6621
6622             data->solid.color = color;
6623             blend_color_rgb16(1, spans, userData);
6624             ++spans;
6625         }
6626         data->solid.color = oldColor;
6627
6628     } else {
6629         blend_src_generic<RegularSpans>(count, spans, userData);
6630     }
6631 }
6632
6633 inline static void qt_bitmapblit_quint32(QRasterBuffer *rasterBuffer,
6634                                    int x, int y, quint32 color,
6635                                    const uchar *map,
6636                                    int mapWidth, int mapHeight, int mapStride)
6637 {
6638     qt_bitmapblit_template<quint32>(rasterBuffer, x,  y,  color,
6639                                     map, mapWidth, mapHeight, mapStride);
6640 }
6641
6642 inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
6643                                    int x, int y, quint32 color,
6644                                    const uchar *map,
6645                                    int mapWidth, int mapHeight, int mapStride)
6646 {
6647     qt_bitmapblit_template<quint16>(rasterBuffer, x,  y,  color,
6648                                     map, mapWidth, mapHeight, mapStride);
6649 }
6650
6651
6652 uchar qt_pow_rgb_gamma[256];
6653 uchar qt_pow_rgb_invgamma[256];
6654
6655 uint qt_pow_gamma[256];
6656 uchar qt_pow_invgamma[2048];
6657
6658 static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
6659                                     int x, int y, quint32 color,
6660                                     const uchar *map,
6661                                     int mapWidth, int mapHeight, int mapStride,
6662                                     const QClipData *)
6663 {
6664     const quint16 c = qt_colorConvert<quint16, quint32>(color, 0);
6665     quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
6666     const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
6667
6668     while (mapHeight--) {
6669         for (int i = 0; i < mapWidth; ++i) {
6670             const int coverage = map[i];
6671
6672             if (coverage == 0) {
6673                 // nothing
6674             } else if (coverage == 255) {
6675                 dest[i] = c;
6676             } else {
6677                 int ialpha = 255 - coverage;
6678                 dest[i] = BYTE_MUL_RGB16(c, coverage)
6679                           + BYTE_MUL_RGB16(dest[i], ialpha);
6680             }
6681         }
6682         dest += destStride;
6683         map += mapStride;
6684     }
6685 }
6686
6687 void qt_build_pow_tables() {
6688     qreal smoothing = qreal(1.7);
6689
6690 #ifdef Q_WS_MAC
6691     // decided by testing a few things on an iMac, should probably get this from the
6692     // system...
6693     smoothing = qreal(2.0);
6694 #endif
6695
6696 #ifdef Q_WS_WIN
6697     int winSmooth;
6698     if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0))
6699         smoothing = winSmooth / qreal(1000.0);
6700
6701     // Safeguard ourselves against corrupt registry values...
6702     if (smoothing > 5 || smoothing < 1)
6703         smoothing = qreal(1.4);
6704
6705 #endif
6706
6707 #ifdef Q_WS_X11
6708     Q_UNUSED(smoothing);
6709     for (int i=0; i<256; ++i) {
6710         qt_pow_rgb_gamma[i] = uchar(i);
6711         qt_pow_rgb_invgamma[i] = uchar(i);
6712     }
6713 #else
6714     for (int i=0; i<256; ++i) {
6715         qt_pow_rgb_gamma[i] = uchar(qRound(qPow(i / qreal(255.0), smoothing) * 255));
6716         qt_pow_rgb_invgamma[i] = uchar(qRound(qPow(i / qreal(255.), 1 / smoothing) * 255));
6717     }
6718 #endif
6719
6720 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
6721     const qreal gray_gamma = 2.31;
6722     for (int i=0; i<256; ++i)
6723         qt_pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047));
6724     for (int i=0; i<2048; ++i)
6725         qt_pow_invgamma[i] = uchar(qRound(qPow(i / qreal(2047.0), 1 / gray_gamma) * 255));
6726 #endif
6727 }
6728
6729 static inline void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
6730 {
6731     // Do a gray alphablend...
6732     int da = qAlpha(*dst);
6733     int dr = qRed(*dst);
6734     int dg = qGreen(*dst);
6735     int db = qBlue(*dst);
6736
6737     if (da != 255
6738 #if defined (Q_WS_WIN)
6739         // Work around GDI messing up alpha channel
6740         && qRed(*dst) <= da && qBlue(*dst) <= da && qGreen(*dst) <= da
6741 #endif
6742         ) {
6743
6744         int a = qGray(coverage);
6745         sr = qt_div_255(qt_pow_rgb_invgamma[sr] * a);
6746         sg = qt_div_255(qt_pow_rgb_invgamma[sg] * a);
6747         sb = qt_div_255(qt_pow_rgb_invgamma[sb] * a);
6748
6749         int ia = 255 - a;
6750         dr = qt_div_255(dr * ia);
6751         dg = qt_div_255(dg * ia);
6752         db = qt_div_255(db * ia);
6753
6754         *dst = ((a + qt_div_255((255 - a) * da)) << 24)
6755             |  ((sr + dr) << 16)
6756             |  ((sg + dg) << 8)
6757             |  ((sb + db));
6758         return;
6759     }
6760
6761     int mr = qRed(coverage);
6762     int mg = qGreen(coverage);
6763     int mb = qBlue(coverage);
6764
6765     dr = qt_pow_rgb_gamma[dr];
6766     dg = qt_pow_rgb_gamma[dg];
6767     db = qt_pow_rgb_gamma[db];
6768
6769     int nr = qt_div_255((sr - dr) * mr) + dr;
6770     int ng = qt_div_255((sg - dg) * mg) + dg;
6771     int nb = qt_div_255((sb - db) * mb) + db;
6772
6773     nr = qt_pow_rgb_invgamma[nr];
6774     ng = qt_pow_rgb_invgamma[ng];
6775     nb = qt_pow_rgb_invgamma[nb];
6776
6777     *dst = qRgb(nr, ng, nb);
6778 }
6779
6780 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
6781 static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
6782 {
6783     // Do a gammacorrected gray alphablend...
6784     int dr = qRed(*dst);
6785     int dg = qGreen(*dst);
6786     int db = qBlue(*dst);
6787
6788     dr = qt_pow_gamma[dr];
6789     dg = qt_pow_gamma[dg];
6790     db = qt_pow_gamma[db];
6791
6792     int alpha = coverage;
6793     int ialpha = 255 - alpha;
6794     int nr = (sr * alpha + ialpha * dr) / 255;
6795     int ng = (sg * alpha + ialpha * dg) / 255;
6796     int nb = (sb * alpha + ialpha * db) / 255;
6797
6798     nr = qt_pow_invgamma[nr];
6799     ng = qt_pow_invgamma[ng];
6800     nb = qt_pow_invgamma[nb];
6801
6802     *dst = qRgb(nr, ng, nb);
6803 }
6804 #endif
6805
6806 static void qt_alphamapblit_quint32(QRasterBuffer *rasterBuffer,
6807                                     int x, int y, quint32 color,
6808                                     const uchar *map,
6809                                     int mapWidth, int mapHeight, int mapStride,
6810                                     const QClipData *clip)
6811 {
6812     const quint32 c = color;
6813     const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
6814
6815 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
6816     int sr = qRed(color);
6817     int sg = qGreen(color);
6818     int sb = qBlue(color);
6819
6820     sr = qt_pow_gamma[sr];
6821     sg = qt_pow_gamma[sg];
6822     sb = qt_pow_gamma[sb];
6823     bool opaque_src = (qAlpha(color) == 255);
6824 #endif
6825
6826     if (!clip) {
6827         quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
6828         while (mapHeight--) {
6829             for (int i = 0; i < mapWidth; ++i) {
6830                 const int coverage = map[i];
6831
6832                 if (coverage == 0) {
6833                     // nothing
6834                 } else if (coverage == 255) {
6835                     dest[i] = c;
6836                 } else {
6837 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
6838                     if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
6839                         && qAlpha(dest[i]) == 255) {
6840                         grayBlendPixel(dest+i, coverage, sr, sg, sb);
6841                     } else
6842 #endif
6843                     {
6844                         int ialpha = 255 - coverage;
6845                         dest[i] = INTERPOLATE_PIXEL_255(c, coverage, dest[i], ialpha);
6846                     }
6847                 }
6848             }
6849             dest += destStride;
6850             map += mapStride;
6851         }
6852     } else {
6853         int bottom = qMin(y + mapHeight, rasterBuffer->height());
6854
6855         int top = qMax(y, 0);
6856         map += (top - y) * mapStride;
6857
6858         const_cast<QClipData *>(clip)->initialize();
6859         for (int yp = top; yp<bottom; ++yp) {
6860             const QClipData::ClipLine &line = clip->m_clipLines[yp];
6861
6862             quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
6863
6864             for (int i=0; i<line.count; ++i) {
6865                 const QSpan &clip = line.spans[i];
6866
6867                 int start = qMax<int>(x, clip.x);
6868                 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
6869
6870                 for (int xp=start; xp<end; ++xp) {
6871                     const int coverage = map[xp - x];
6872
6873                     if (coverage == 0) {
6874                         // nothing
6875                     } else if (coverage == 255) {
6876                         dest[xp] = c;
6877                     } else {
6878 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
6879                         if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
6880                             && qAlpha(dest[xp]) == 255) {
6881                             grayBlendPixel(dest+xp, coverage, sr, sg, sb);
6882                         } else
6883 #endif
6884                         {
6885                             int ialpha = 255 - coverage;
6886                             dest[xp] = INTERPOLATE_PIXEL_255(c, coverage, dest[xp], ialpha);
6887                         }
6888                     }
6889
6890                 } // for (i -> line.count)
6891             } // for (yp -> bottom)
6892             map += mapStride;
6893         }
6894     }
6895 }
6896
6897 static void qt_alphargbblit_quint32(QRasterBuffer *rasterBuffer,
6898                                     int x, int y, quint32 color,
6899                                     const uint *src, int mapWidth, int mapHeight, int srcStride,
6900                                     const QClipData *clip)
6901 {
6902     const quint32 c = color;
6903
6904     int sr = qRed(color);
6905     int sg = qGreen(color);
6906     int sb = qBlue(color);
6907     int sa = qAlpha(color);
6908
6909     sr = qt_pow_rgb_gamma[sr];
6910     sg = qt_pow_rgb_gamma[sg];
6911     sb = qt_pow_rgb_gamma[sb];
6912
6913     if (sa == 0)
6914         return;
6915
6916     if (!clip) {
6917         quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
6918         const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
6919         while (mapHeight--) {
6920             for (int i = 0; i < mapWidth; ++i) {
6921                 const uint coverage = src[i];
6922                 if (coverage == 0xffffffff) {
6923                     dst[i] = c;
6924                 } else if (coverage != 0xff000000) {
6925                     rgbBlendPixel(dst+i, coverage, sr, sg, sb);
6926                 }
6927             }
6928
6929             dst += destStride;
6930             src += srcStride;
6931         }
6932     } else {
6933         int bottom = qMin(y + mapHeight, rasterBuffer->height());
6934
6935         int top = qMax(y, 0);
6936         src += (top - y) * srcStride;
6937
6938         const_cast<QClipData *>(clip)->initialize();
6939         for (int yp = top; yp<bottom; ++yp) {
6940             const QClipData::ClipLine &line = clip->m_clipLines[yp];
6941
6942             quint32 *dst = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
6943
6944             for (int i=0; i<line.count; ++i) {
6945                 const QSpan &clip = line.spans[i];
6946
6947                 int start = qMax<int>(x, clip.x);
6948                 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
6949
6950                 for (int xp=start; xp<end; ++xp) {
6951                     const uint coverage = src[xp - x];
6952                     if (coverage == 0xffffffff) {
6953                         dst[xp] = c;
6954                     } else if (coverage != 0xff000000) {
6955                         rgbBlendPixel(dst+xp, coverage, sr, sg, sb);
6956                     }
6957                 }
6958             } // for (i -> line.count)
6959             src += srcStride;
6960         } // for (yp -> bottom)
6961
6962     }
6963 }
6964
6965 template <class T>
6966 inline void qt_rectfill_template(QRasterBuffer *rasterBuffer,
6967                                  int x, int y, int width, int height,
6968                                  quint32 color, T dummy = 0)
6969 {
6970     Q_UNUSED(dummy);
6971
6972     qt_rectfill<T>(reinterpret_cast<T*>(rasterBuffer->buffer()),
6973                    qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0),
6974                    x, y, width, height, rasterBuffer->bytesPerLine());
6975 }
6976
6977 #define QT_RECTFILL(T)                                                  \
6978     inline static void qt_rectfill_##T(QRasterBuffer *rasterBuffer,     \
6979                                        int x, int y, int width, int height, \
6980                                        quint32 color)                   \
6981     {                                                                   \
6982         qt_rectfill_template<T>(rasterBuffer, x, y, width, height, color); \
6983     }
6984
6985 QT_RECTFILL(quint32)
6986 QT_RECTFILL(quint16)
6987 QT_RECTFILL(qargb8565)
6988 QT_RECTFILL(qrgb666)
6989 QT_RECTFILL(qargb6666)
6990 QT_RECTFILL(qrgb555)
6991 QT_RECTFILL(qargb8555)
6992 QT_RECTFILL(qrgb888)
6993 QT_RECTFILL(qrgb444)
6994 QT_RECTFILL(qargb4444)
6995 #undef QT_RECTFILL
6996
6997 inline static void qt_rectfill_nonpremul_quint32(QRasterBuffer *rasterBuffer,
6998                                                  int x, int y, int width, int height,
6999                                                  quint32 color)
7000 {
7001     qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
7002                          INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine());
7003 }
7004
7005
7006 // Map table for destination image format. Contains function pointers
7007 // for blends of various types unto the destination
7008
7009 DrawHelper qDrawHelper[QImage::NImageFormats] =
7010 {
7011     // Format_Invalid,
7012     { 0, 0, 0, 0, 0, 0 },
7013     // Format_Mono,
7014     {
7015         blend_color_generic,
7016         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7017         0, 0, 0, 0
7018     },
7019     // Format_MonoLSB,
7020     {
7021         blend_color_generic,
7022         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7023         0, 0, 0, 0
7024     },
7025     // Format_Indexed8,
7026     {
7027         blend_color_generic,
7028         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7029         0, 0, 0, 0
7030     },
7031     // Format_RGB32,
7032     {
7033         blend_color_argb,
7034         qt_gradient_quint32,
7035         qt_bitmapblit_quint32,
7036         qt_alphamapblit_quint32,
7037         qt_alphargbblit_quint32,
7038         qt_rectfill_quint32
7039     },
7040     // Format_ARGB32,
7041     {
7042         blend_color_generic,
7043         qt_gradient_quint32,
7044         qt_bitmapblit_quint32,
7045         qt_alphamapblit_quint32,
7046         qt_alphargbblit_quint32,
7047         qt_rectfill_nonpremul_quint32
7048     },
7049     // Format_ARGB32_Premultiplied
7050     {
7051         blend_color_argb,
7052         qt_gradient_quint32,
7053         qt_bitmapblit_quint32,
7054         qt_alphamapblit_quint32,
7055         qt_alphargbblit_quint32,
7056         qt_rectfill_quint32
7057     },
7058     // Format_RGB16
7059     {
7060         blend_color_rgb16,
7061         qt_gradient_quint16,
7062         qt_bitmapblit_quint16,
7063         qt_alphamapblit_quint16,
7064         0,
7065         qt_rectfill_quint16
7066     },
7067     // Format_ARGB8565_Premultiplied
7068     {
7069         SPANFUNC_POINTER_BLENDCOLOR(qargb8565),
7070         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7071         0, 0, 0,
7072         qt_rectfill_qargb8565
7073     },
7074     // Format_RGB666
7075     {
7076         SPANFUNC_POINTER_BLENDCOLOR(qrgb666),
7077         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7078         0, 0, 0,
7079         qt_rectfill_qrgb666
7080     },
7081     // Format_ARGB6666_Premultiplied
7082     {
7083         SPANFUNC_POINTER_BLENDCOLOR(qargb6666),
7084         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7085         0, 0, 0,
7086         qt_rectfill_qargb6666
7087     },
7088     // Format_RGB555
7089     {
7090         SPANFUNC_POINTER_BLENDCOLOR(qrgb555),
7091         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7092         0, 0, 0,
7093         qt_rectfill_qrgb555
7094     },
7095     // Format_ARGB8555_Premultiplied
7096     {
7097         SPANFUNC_POINTER_BLENDCOLOR(qargb8555),
7098         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7099         0, 0, 0,
7100         qt_rectfill_qargb8555
7101     },
7102     // Format_RGB888
7103     {
7104         SPANFUNC_POINTER_BLENDCOLOR(qrgb888),
7105         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7106         0, 0, 0,
7107         qt_rectfill_qrgb888
7108     },
7109     // Format_RGB444
7110     {
7111         SPANFUNC_POINTER_BLENDCOLOR(qrgb444),
7112         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7113         0, 0, 0,
7114         qt_rectfill_qrgb444
7115     },
7116     // Format_ARGB4444_Premultiplied
7117     {
7118         SPANFUNC_POINTER_BLENDCOLOR(qargb4444),
7119         SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7120         0, 0, 0,
7121         qt_rectfill_qargb4444
7122     }
7123 };
7124
7125 #if defined(Q_CC_MSVC) && !defined(_MIPS_)
7126 template <class DST, class SRC>
7127 inline void qt_memfill_template(DST *dest, SRC color, int count)
7128 {
7129     const DST c = qt_colorConvert<DST, SRC>(color, 0);
7130     while (count--)
7131         *dest++ = c;
7132 }
7133
7134 #else
7135
7136 template <class DST, class SRC>
7137 inline void qt_memfill_template(DST *dest, SRC color, int count)
7138 {
7139     const DST c = qt_colorConvert<DST, SRC>(color, 0);
7140     int n = (count + 7) / 8;
7141     switch (count & 0x07)
7142     {
7143     case 0: do { *dest++ = c;
7144     case 7:      *dest++ = c;
7145     case 6:      *dest++ = c;
7146     case 5:      *dest++ = c;
7147     case 4:      *dest++ = c;
7148     case 3:      *dest++ = c;
7149     case 2:      *dest++ = c;
7150     case 1:      *dest++ = c;
7151     } while (--n > 0);
7152     }
7153 }
7154
7155 template <>
7156 inline void qt_memfill_template(quint16 *dest, quint16 value, int count)
7157 {
7158     if (count < 3) {
7159         switch (count) {
7160         case 2: *dest++ = value;
7161         case 1: *dest = value;
7162         }
7163         return;
7164     }
7165
7166     const int align = (quintptr)(dest) & 0x3;
7167     switch (align) {
7168     case 2: *dest++ = value; --count;
7169     }
7170
7171     const quint32 value32 = (value << 16) | value;
7172     qt_memfill(reinterpret_cast<quint32*>(dest), value32, count / 2);
7173     if (count & 0x1)
7174         dest[count - 1] = value;
7175 }
7176 #endif
7177
7178 static void qt_memfill_quint16(quint16 *dest, quint16 color, int count)
7179 {
7180     qt_memfill_template<quint16, quint16>(dest, color, count);
7181 }
7182
7183 typedef void (*qt_memfill32_func)(quint32 *dest, quint32 value, int count);
7184 typedef void (*qt_memfill16_func)(quint16 *dest, quint16 value, int count);
7185 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count);
7186 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count);
7187
7188 qt_memfill32_func qt_memfill32 = qt_memfill32_setup;
7189 qt_memfill16_func qt_memfill16 = qt_memfill16_setup;
7190
7191 void qInitDrawhelperAsm()
7192 {
7193
7194     qt_memfill32 = qt_memfill_template<quint32, quint32>;
7195     qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16, quint16>;
7196
7197     CompositionFunction *functionForModeAsm = 0;
7198     CompositionFunctionSolid *functionForModeSolidAsm = 0;
7199
7200     const uint features = qDetectCPUFeatures();
7201     if (false) {
7202 #ifdef QT_HAVE_SSE2
7203     } else if (features & SSE2) {
7204         qt_memfill32 = qt_memfill32_sse2;
7205         qt_memfill16 = qt_memfill16_sse2;
7206         qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2;
7207         qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2;
7208         qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2;
7209         qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2;
7210 #endif
7211 #ifdef QT_HAVE_SSE
7212     } else if (features & SSE) {
7213 //        qt_memfill32 = qt_memfill32_sse;
7214         qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse;
7215 #ifdef QT_HAVE_3DNOW
7216         if (features & MMX3DNOW) {
7217             qt_memfill32 = qt_memfill32_sse3dnow;
7218             qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse3dnow;
7219         }
7220 #endif
7221 #endif // SSE
7222     }
7223 #ifdef QT_HAVE_MMX
7224     if (features & MMX) {
7225         functionForModeAsm = qt_functionForMode_MMX;
7226
7227         functionForModeSolidAsm = qt_functionForModeSolid_MMX;
7228         qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx;
7229 #ifdef QT_HAVE_3DNOW
7230         if (features & MMX3DNOW) {
7231             functionForModeAsm = qt_functionForMode_MMX3DNOW;
7232             functionForModeSolidAsm = qt_functionForModeSolid_MMX3DNOW;
7233             qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx3dnow;
7234         }
7235 #endif // 3DNOW
7236
7237         extern void qt_blend_rgb32_on_rgb32_mmx(uchar *destPixels, int dbpl,
7238                                                 const uchar *srcPixels, int sbpl,
7239                                                 int w, int h,
7240                                                 int const_alpha);
7241         extern void qt_blend_argb32_on_argb32_mmx(uchar *destPixels, int dbpl,
7242                                                   const uchar *srcPixels, int sbpl,
7243                                                   int w, int h,
7244                                                   int const_alpha);
7245
7246         qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mmx;
7247         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mmx;
7248         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mmx;
7249         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mmx;
7250
7251     }
7252 #endif // MMX
7253
7254 #ifdef QT_HAVE_SSE
7255     if (features & SSE) {
7256         extern void qt_blend_rgb32_on_rgb32_sse(uchar *destPixels, int dbpl,
7257                                                 const uchar *srcPixels, int sbpl,
7258                                                 int w, int h,
7259                                                 int const_alpha);
7260         extern void qt_blend_argb32_on_argb32_sse(uchar *destPixels, int dbpl,
7261                                                   const uchar *srcPixels, int sbpl,
7262                                                   int w, int h,
7263                                                   int const_alpha);
7264
7265         qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
7266         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
7267         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
7268         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
7269     }
7270 #endif // SSE
7271
7272 #ifdef QT_HAVE_SSE2
7273     if (features & SSE2) {
7274         extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
7275                                                  const uchar *srcPixels, int sbpl,
7276                                                  int w, int h,
7277                                                  int const_alpha);
7278         extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
7279                                                    const uchar *srcPixels, int sbpl,
7280                                                    int w, int h,
7281                                                    int const_alpha);
7282
7283         qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
7284         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
7285         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
7286         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
7287     }
7288
7289 #ifdef QT_HAVE_SSSE3
7290     if (features & SSSE3) {
7291         extern void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
7292                                                     const uchar *srcPixels, int sbpl,
7293                                                     int w, int h,
7294                                                     int const_alpha);
7295
7296         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
7297         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
7298     }
7299 #endif // SSSE3
7300
7301 #endif // SSE2
7302
7303 #ifdef QT_HAVE_SSE
7304     if (features & SSE) {
7305         functionForModeAsm = qt_functionForMode_SSE;
7306         functionForModeSolidAsm = qt_functionForModeSolid_SSE;
7307         qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse;
7308 #ifdef QT_HAVE_3DNOW
7309         if (features & MMX3DNOW) {
7310             functionForModeAsm = qt_functionForMode_SSE3DNOW;
7311             functionForModeSolidAsm = qt_functionForModeSolid_SSE3DNOW;
7312             qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse3dnow;
7313         }
7314 #endif // 3DNOW
7315
7316
7317 #ifdef QT_HAVE_SSE2
7318         if (features & SSE2) {
7319             extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels,
7320                                                               const uint *srcPixels,
7321                                                               int length,
7322                                                               uint const_alpha);
7323             extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha);
7324             extern void QT_FASTCALL comp_func_Plus_sse2(uint *dst, const uint *src, int length, uint const_alpha);
7325             extern void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, uint const_alpha);
7326
7327             functionForModeAsm[0] = comp_func_SourceOver_sse2;
7328             functionForModeAsm[QPainter::CompositionMode_Source] = comp_func_Source_sse2;
7329             functionForModeAsm[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2;
7330             functionForModeSolidAsm[0] = comp_func_solid_SourceOver_sse2;
7331         }
7332 #endif
7333     }
7334 #elif defined(QT_HAVE_SSE2)
7335     // this is the special case when SSE2 is usable but MMX/SSE is not usable (e.g.: Windows x64 + visual studio)
7336     if (features & SSE2) {
7337         functionForModeAsm = qt_functionForMode_onlySSE2;
7338         functionForModeSolidAsm = qt_functionForModeSolid_onlySSE2;
7339     }
7340 #endif
7341
7342 #ifdef QT_HAVE_IWMMXT
7343     if (features & IWMMXT) {
7344         functionForModeAsm = qt_functionForMode_IWMMXT;
7345         functionForModeSolidAsm = qt_functionForModeSolid_IWMMXT;
7346         qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_iwmmxt;
7347     }
7348 #endif // IWMMXT
7349
7350 #if defined(QT_HAVE_ARM_SIMD)
7351     qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_arm_simd;
7352     qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_arm_simd;
7353     qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_arm_simd;
7354     qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_arm_simd;
7355 #elif defined(QT_HAVE_NEON)
7356     if (features & NEON) {
7357         qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
7358         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
7359         qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7360         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7361         qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon;
7362         qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon;
7363         qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon;
7364
7365         qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon;
7366         qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon;
7367
7368         qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon;
7369         qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon;
7370
7371         qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon;
7372
7373         functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon;
7374         functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon;
7375         functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon;
7376         destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
7377         destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
7378
7379         qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
7380         qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
7381         qt_memfill32 = qt_memfill32_neon;
7382     }
7383 #endif
7384
7385     if (functionForModeSolidAsm) {
7386         const int destinationMode = QPainter::CompositionMode_Destination;
7387         functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode];
7388
7389         // use the default qdrawhelper implementation for the
7390         // extended composition modes
7391         for (int mode = 12; mode < 24; ++mode)
7392             functionForModeSolidAsm[mode] = functionForModeSolid_C[mode];
7393
7394         functionForModeSolid = functionForModeSolidAsm;
7395     }
7396     if (functionForModeAsm)
7397         functionForMode = functionForModeAsm;
7398
7399     qt_build_pow_tables();
7400 }
7401
7402 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count)
7403 {
7404     qInitDrawhelperAsm();
7405     qt_memfill32(dest, value, count);
7406 }
7407
7408 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count)
7409 {
7410     qInitDrawhelperAsm();
7411     qt_memfill16(dest, value, count);
7412 }
7413
7414 QT_END_NAMESPACE