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