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