1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #if defined(__OPTIMIZE__) && !defined(__INTEL_COMPILER) && defined(__GNUC__) \
43 && (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
44 // GCC 4.4 supports #pragma GCC optimize and #pragma GCC target
45 # pragma GCC optimize "O3"
46 # if defined(__i386__) && defined(__SSE2__) && !defined(__SSE2_MATH__)
47 # pragma GCC target "fpmath=sse"
51 #include <qstylehints.h>
52 #include <qguiapplication.h>
54 #include <private/qdrawhelper_p.h>
55 #include <private/qpaintengine_raster_p.h>
56 #include <private/qpainter_p.h>
57 #include <private/qdrawhelper_x86_p.h>
58 #include <private/qdrawhelper_neon_p.h>
59 #if defined(QT_COMPILER_SUPPORTS_MIPS_DSP) || defined(QT_COMPILER_SUPPORTS_MIPS_DSPR2)
60 #include <private/qdrawhelper_mips_dsp_p.h>
62 #include <private/qmath_p.h>
63 #include <private/qguiapplication_p.h>
68 #define MASK(src, a) src = BYTE_MUL(src, a)
71 constants and structures
75 fixed_scale = 1 << 16,
79 // must be multiple of 4 for easier SIMD implementations
80 static const int buffer_size = 2048;
85 // To convert in place, let 'dest' and 'src' be the same.
86 static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint *src, int count,
87 const QPixelLayout *, const QRgb *clut)
89 for (int i = 0; i < count; ++i)
90 buffer[i] = PREMUL(clut[src[i]]);
94 static const uint *QT_FASTCALL convertPassThrough(uint *, const uint *src, int,
95 const QPixelLayout *, const QRgb *)
100 static const uint *QT_FASTCALL convertRGB16ToARGB32PM(uint *buffer, const uint *src, int count,
101 const QPixelLayout *, const QRgb *)
103 for (int i = 0; i < count; ++i)
104 buffer[i] = qConvertRgb16To32(src[i]);
108 static const uint *QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count,
109 const QPixelLayout *, const QRgb *)
111 for (int i = 0; i < count; ++i)
112 buffer[i] = PREMUL(src[i]);
116 static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int count,
117 const QPixelLayout *layout, const QRgb *)
119 Q_ASSERT(layout->redWidth >= 4);
120 Q_ASSERT(layout->greenWidth >= 4);
121 Q_ASSERT(layout->blueWidth >= 4);
122 Q_ASSERT(layout->alphaWidth == 0);
124 const uint redMask = ((1 << layout->redWidth) - 1);
125 const uint greenMask = ((1 << layout->greenWidth) - 1);
126 const uint blueMask = ((1 << layout->blueWidth) - 1);
128 const uchar redLeftShift = 8 - layout->redWidth;
129 const uchar greenLeftShift = 8 - layout->greenWidth;
130 const uchar blueLeftShift = 8 - layout->blueWidth;
132 const uchar redRightShift = 2 * layout->redWidth - 8;
133 const uchar greenRightShift = 2 * layout->greenWidth - 8;
134 const uchar blueRightShift = 2 * layout->blueWidth - 8;
136 for (int i = 0; i < count; ++i) {
137 uint red = (src[i] >> layout->redShift) & redMask;
138 uint green = (src[i] >> layout->greenShift) & greenMask;
139 uint blue = (src[i] >> layout->blueShift) & blueMask;
141 red = ((red << redLeftShift) | (red >> redRightShift)) << 16;
142 green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8;
143 blue = (blue << blueLeftShift) | (blue >> blueRightShift);
144 buffer[i] = 0xff000000 | red | green | blue;
150 static const uint *QT_FASTCALL convertToARGB32PM(uint *buffer, const uint *src, int count,
151 const QPixelLayout *layout, const QRgb *)
153 Q_ASSERT(layout->redWidth >= 4);
154 Q_ASSERT(layout->greenWidth >= 4);
155 Q_ASSERT(layout->blueWidth >= 4);
156 Q_ASSERT(layout->alphaWidth >= 4);
158 const uint redMask = ((1 << layout->redWidth) - 1);
159 const uint greenMask = ((1 << layout->greenWidth) - 1);
160 const uint blueMask = ((1 << layout->blueWidth) - 1);
162 const uchar redLeftShift = 8 - layout->redWidth;
163 const uchar greenLeftShift = 8 - layout->greenWidth;
164 const uchar blueLeftShift = 8 - layout->blueWidth;
166 const uchar redRightShift = 2 * layout->redWidth - 8;
167 const uchar greenRightShift = 2 * layout->greenWidth - 8;
168 const uchar blueRightShift = 2 * layout->blueWidth - 8;
170 const uint alphaMask = ((1 << layout->alphaWidth) - 1);
171 const uchar alphaLeftShift = 8 - layout->alphaWidth;
172 const uchar alphaRightShift = 2 * layout->alphaWidth - 8;
174 if (layout->premultiplied) {
175 for (int i = 0; i < count; ++i) {
176 uint alpha = (src[i] >> layout->alphaShift) & alphaMask;
177 uint red = (src[i] >> layout->redShift) & redMask;
178 uint green = (src[i] >> layout->greenShift) & greenMask;
179 uint blue = (src[i] >> layout->blueShift) & blueMask;
181 alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift);
182 red = qMin(alpha, (red << redLeftShift) | (red >> redRightShift));
183 green = qMin(alpha, (green << greenLeftShift) | (green >> greenRightShift));
184 blue = qMin(alpha, (blue << blueLeftShift) | (blue >> blueRightShift));
185 buffer[i] = (alpha << 24) | (red << 16) | (green << 8) | blue;
188 for (int i = 0; i < count; ++i) {
189 uint alpha = (src[i] >> layout->alphaShift) & alphaMask;
190 uint red = (src[i] >> layout->redShift) & redMask;
191 uint green = (src[i] >> layout->greenShift) & greenMask;
192 uint blue = (src[i] >> layout->blueShift) & blueMask;
194 alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift);
195 red = (red << redLeftShift) | (red >> redRightShift);
196 green = (green << greenLeftShift) | (green >> greenRightShift);
197 blue = (blue << blueLeftShift) | (blue >> blueRightShift);
198 buffer[i] = PREMUL((alpha << 24) | (red << 16) | (green << 8) | blue);
204 static const uint *QT_FASTCALL convertRGB16FromARGB32PM(uint *buffer, const uint *src, int count,
205 const QPixelLayout *, const QRgb *)
207 for (int i = 0; i < count; ++i)
208 buffer[i] = qConvertRgb32To16(INV_PREMUL(src[i]));
212 static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uint *src, int count,
213 const QPixelLayout *, const QRgb *)
215 for (int i = 0; i < count; ++i)
216 buffer[i] = INV_PREMUL(src[i]);
220 static const uint *QT_FASTCALL convertFromARGB32PM(uint *buffer, const uint *src, int count,
221 const QPixelLayout *layout, const QRgb *)
223 Q_ASSERT(layout->redWidth <= 8);
224 Q_ASSERT(layout->greenWidth <= 8);
225 Q_ASSERT(layout->blueWidth <= 8);
226 Q_ASSERT(layout->alphaWidth <= 8);
228 const uint redMask = (1 << layout->redWidth) - 1;
229 const uint greenMask = (1 << layout->greenWidth) - 1;
230 const uint blueMask = (1 << layout->blueWidth) - 1;
231 const uint alphaMask = (1 << layout->alphaWidth) - 1;
233 const uchar redRightShift = 24 - layout->redWidth;
234 const uchar greenRightShift = 16 - layout->greenWidth;
235 const uchar blueRightShift = 8 - layout->blueWidth;
236 const uchar alphaRightShift = 32 - layout->alphaWidth;
238 if (!layout->premultiplied) {
239 for (int i = 0; i < count; ++i)
240 buffer[i] = qAlpha(src[i]) == 255 ? src[i] : INV_PREMUL(src[i]);
243 for (int i = 0; i < count; ++i) {
244 uint red = ((src[i] >> redRightShift) & redMask) << layout->redShift;
245 uint green = ((src[i] >> greenRightShift) & greenMask) << layout->greenShift;
246 uint blue = ((src[i] >> blueRightShift) & blueMask) << layout->blueShift;
247 uint alpha = ((src[i] >> alphaRightShift) & alphaMask) << layout->alphaShift;
248 buffer[i] = red | green | blue | alpha;
254 // convertToArgb32() assumes that no color channel is less than 4 bits.
255 // convertFromArgb32() assumes that no color channel is more than 8 bits.
256 // QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits.
257 QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
258 { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0 }, // Format_Invalid
259 { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0 }, // Format_Mono
260 { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0 }, // Format_MonoLSB
261 { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0 }, // Format_Indexed8
262 { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough }, // Format_RGB32
263 { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM }, // Format_ARGB32
264 { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough }, // Format_ARGB32_Premultiplied
265 { 5, 11, 6, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertRGB16ToARGB32PM, convertRGB16FromARGB32PM }, // Format_RGB16
266 { 5, 19, 6, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB8565_Premultiplied
267 { 6, 12, 6, 6, 6, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM }, // Format_RGB666
268 { 6, 12, 6, 6, 6, 0, 6, 18, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB6666_Premultiplied
269 { 5, 10, 5, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM }, // Format_RGB555
270 { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB8555_Premultiplied
271 { 8, 0, 8, 8, 8, 16, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM }, // Format_RGB888
272 { 4, 8, 4, 4, 4, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM }, // Format_RGB444
273 { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, convertToARGB32PM, convertFromARGB32PM } // Format_ARGB4444_Premultiplied
276 FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = {
278 fetchPixels<QPixelLayout::BPP1MSB>, // BPP1MSB
279 fetchPixels<QPixelLayout::BPP1LSB>, // BPP1LSB
280 fetchPixels<QPixelLayout::BPP8>, // BPP8
281 fetchPixels<QPixelLayout::BPP16>, // BPP16
282 fetchPixels<QPixelLayout::BPP24>, // BPP24
283 fetchPixels<QPixelLayout::BPP32> // BPP32
286 StorePixelsFunc qStorePixels[QPixelLayout::BPPCount] = {
288 storePixels<QPixelLayout::BPP1MSB>, // BPP1MSB
289 storePixels<QPixelLayout::BPP1LSB>, // BPP1LSB
290 storePixels<QPixelLayout::BPP8>, // BPP8
291 storePixels<QPixelLayout::BPP16>, // BPP16
292 storePixels<QPixelLayout::BPP24>, // BPP24
293 storePixels<QPixelLayout::BPP32> // BPP32
296 typedef uint (QT_FASTCALL *FetchPixelFunc)(const uchar *src, int index);
298 FetchPixelFunc qFetchPixel[QPixelLayout::BPPCount] = {
300 fetchPixel<QPixelLayout::BPP1MSB>, // BPP1MSB
301 fetchPixel<QPixelLayout::BPP1LSB>, // BPP1LSB
302 fetchPixel<QPixelLayout::BPP8>, // BPP8
303 fetchPixel<QPixelLayout::BPP16>, // BPP16
304 fetchPixel<QPixelLayout::BPP24>, // BPP24
305 fetchPixel<QPixelLayout::BPP32> // BPP32
309 Destination fetch. This is simple as we don't have to do bounds checks or
313 static uint * QT_FASTCALL destFetchMono(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
315 uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
316 uint *start = buffer;
317 const uint *end = buffer + length;
318 while (buffer < end) {
319 *buffer = data[x>>3] & (0x80 >> (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
326 static uint * QT_FASTCALL destFetchMonoLsb(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
328 uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
329 uint *start = buffer;
330 const uint *end = buffer + length;
331 while (buffer < end) {
332 *buffer = data[x>>3] & (0x1 << (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
339 static uint * QT_FASTCALL destFetchARGB32P(uint *, QRasterBuffer *rasterBuffer, int x, int y, int)
341 return (uint *)rasterBuffer->scanLine(y) + x;
344 static uint * QT_FASTCALL destFetchRGB16(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
346 const ushort *Q_DECL_RESTRICT data = (const ushort *)rasterBuffer->scanLine(y) + x;
347 for (int i = 0; i < length; ++i)
348 buffer[i] = qConvertRgb16To32(data[i]);
352 static uint *QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
354 const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
355 const uint *ptr = qFetchPixels[layout->bpp](buffer, rasterBuffer->scanLine(y), x, length);
356 return const_cast<uint *>(layout->convertToARGB32PM(buffer, ptr, length, layout, 0));
360 static DestFetchProc destFetchProc[QImage::NImageFormats] =
363 destFetchMono, // Format_Mono,
364 destFetchMonoLsb, // Format_MonoLSB
365 0, // Format_Indexed8
366 destFetchARGB32P, // Format_RGB32
367 destFetch, // Format_ARGB32,
368 destFetchARGB32P, // Format_ARGB32_Premultiplied
369 destFetchRGB16, // Format_RGB16
370 destFetch, // Format_ARGB8565_Premultiplied
371 destFetch, // Format_RGB666
372 destFetch, // Format_ARGB6666_Premultiplied
373 destFetch, // Format_RGB555
374 destFetch, // Format_ARGB8555_Premultiplied
375 destFetch, // Format_RGB888
376 destFetch, // Format_RGB444
377 destFetch // Format_ARGB4444_Premultiplied
381 Returns the color in the mono destination color table
382 that is the "nearest" to /color/.
384 static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
386 QRgb color_0 = PREMUL(rbuf->destColor0);
387 QRgb color_1 = PREMUL(rbuf->destColor1);
388 color = PREMUL(color);
391 int g = qGreen(color);
392 int b = qBlue(color);
396 rx = r - qRed(color_0);
397 gx = g - qGreen(color_0);
398 bx = b - qBlue(color_0);
399 dist_0 = rx*rx + gx*gx + bx*bx;
401 rx = r - qRed(color_1);
402 gx = g - qGreen(color_1);
403 bx = b - qBlue(color_1);
404 dist_1 = rx*rx + gx*gx + bx*bx;
415 static void QT_FASTCALL destStoreMono(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
417 uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
418 if (rasterBuffer->monoDestinationWithClut) {
419 for (int i = 0; i < length; ++i) {
420 if (buffer[i] == rasterBuffer->destColor0) {
421 data[x >> 3] &= ~(0x80 >> (x & 7));
422 } else if (buffer[i] == rasterBuffer->destColor1) {
423 data[x >> 3] |= 0x80 >> (x & 7);
424 } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
425 data[x >> 3] &= ~(0x80 >> (x & 7));
427 data[x >> 3] |= 0x80 >> (x & 7);
432 for (int i = 0; i < length; ++i) {
433 if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
434 data[x >> 3] |= 0x80 >> (x & 7);
436 data[x >> 3] &= ~(0x80 >> (x & 7));
442 static void QT_FASTCALL destStoreMonoLsb(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
444 uchar *Q_DECL_RESTRICT data = (uchar *)rasterBuffer->scanLine(y);
445 if (rasterBuffer->monoDestinationWithClut) {
446 for (int i = 0; i < length; ++i) {
447 if (buffer[i] == rasterBuffer->destColor0) {
448 data[x >> 3] &= ~(1 << (x & 7));
449 } else if (buffer[i] == rasterBuffer->destColor1) {
450 data[x >> 3] |= 1 << (x & 7);
451 } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
452 data[x >> 3] &= ~(1 << (x & 7));
454 data[x >> 3] |= 1 << (x & 7);
459 for (int i = 0; i < length; ++i) {
460 if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
461 data[x >> 3] |= 1 << (x & 7);
463 data[x >> 3] &= ~(1 << (x & 7));
469 static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
471 quint16 *data = (quint16*)rasterBuffer->scanLine(y) + x;
472 for (int i = 0; i < length; ++i)
473 data[i] = qConvertRgb32To16(buffer[i]);
476 static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
478 uint buf[buffer_size];
479 const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
480 StorePixelsFunc store = qStorePixels[layout->bpp];
481 uchar *dest = rasterBuffer->scanLine(y);
483 int l = qMin(length, buffer_size);
484 const uint *ptr = layout->convertFromARGB32PM(buf, buffer, l, layout, 0);
485 store(dest, ptr, x, l);
492 static DestStoreProc destStoreProc[QImage::NImageFormats] =
495 destStoreMono, // Format_Mono,
496 destStoreMonoLsb, // Format_MonoLSB
497 0, // Format_Indexed8
499 destStore, // Format_ARGB32,
500 0, // Format_ARGB32_Premultiplied
501 destStoreRGB16, // Format_RGB16
502 destStore, // Format_ARGB8565_Premultiplied
503 destStore, // Format_RGB666
504 destStore, // Format_ARGB6666_Premultiplied
505 destStore, // Format_RGB555
506 destStore, // Format_ARGB8555_Premultiplied
507 destStore, // Format_RGB888
508 destStore, // Format_RGB444
509 destStore // Format_ARGB4444_Premultiplied
515 This is a bit more complicated, as we need several fetch routines for every surface type
517 We need 5 fetch methods per surface type:
519 transformed (tiled and not tiled)
520 transformed bilinear (tiled and not tiled)
522 We don't need bounds checks for untransformed, but we need them for the other ones.
524 The generic implementation does pixel by pixel fetches
527 enum TextureBlendType {
531 BlendTransformedTiled,
532 BlendTransformedBilinear,
533 BlendTransformedBilinearTiled,
537 static const uint *QT_FASTCALL fetchUntransformed(uint *buffer, const Operator *,
538 const QSpanData *data, int y, int x, int length)
540 const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
541 const uint *ptr = qFetchPixels[layout->bpp](buffer, data->texture.scanLine(y), x, length);
542 const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0;
543 return layout->convertToARGB32PM(buffer, ptr, length, layout, clut);
546 static const uint *QT_FASTCALL fetchUntransformedARGB32PM(uint *, const Operator *,
547 const QSpanData *data, int y, int x, int)
549 const uchar *scanLine = data->texture.scanLine(y);
550 return ((const uint *)scanLine) + x;
553 static const uint *QT_FASTCALL fetchUntransformedRGB16(uint *buffer, const Operator *,
554 const QSpanData *data, int y, int x,
557 const quint16 *scanLine = (const quint16 *)data->texture.scanLine(y) + x;
558 #ifdef QT_COMPILER_SUPPORTS_MIPS_DSPR2
559 qConvertRgb16To32_asm_mips_dspr2(buffer, scanLine, length);
561 for (int i = 0; i < length; ++i)
562 buffer[i] = qConvertRgb16To32(scanLine[i]);
567 // blendType is either BlendTransformed or BlendTransformedTiled
568 template<TextureBlendType blendType>
569 static const uint *QT_FASTCALL fetchTransformedARGB32PM(uint *buffer, const Operator *, const QSpanData *data,
570 int y, int x, int length)
572 int image_width = data->texture.width;
573 int image_height = data->texture.height;
575 const qreal cx = x + qreal(0.5);
576 const qreal cy = y + qreal(0.5);
578 const uint *end = buffer + length;
580 if (data->fast_matrix) {
581 // The increment pr x in the scanline
582 int fdx = (int)(data->m11 * fixed_scale);
583 int fdy = (int)(data->m12 * fixed_scale);
585 int fx = int((data->m21 * cy
586 + data->m11 * cx + data->dx) * fixed_scale);
587 int fy = int((data->m22 * cy
588 + data->m12 * cx + data->dy) * fixed_scale);
594 if (blendType == BlendTransformedTiled) {
597 if (px < 0) px += image_width;
598 if (py < 0) py += image_height;
600 px = qBound(0, px, image_width - 1);
601 py = qBound(0, py, image_height - 1);
603 *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
610 const qreal fdx = data->m11;
611 const qreal fdy = data->m12;
612 const qreal fdw = data->m13;
614 qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
615 qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
616 qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
619 const qreal iw = fw == 0 ? 1 : 1 / fw;
620 const qreal tx = fx * iw;
621 const qreal ty = fy * iw;
622 int px = int(tx) - (tx < 0);
623 int py = int(ty) - (ty < 0);
625 if (blendType == BlendTransformedTiled) {
628 if (px < 0) px += image_width;
629 if (py < 0) py += image_height;
631 px = qBound(0, px, image_width - 1);
632 py = qBound(0, py, image_height - 1);
634 *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
639 //force increment to avoid /0
649 template<TextureBlendType blendType> /* either BlendTransformed or BlendTransformedTiled */
650 static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data,
651 int y, int x, int length)
653 int image_width = data->texture.width;
654 int image_height = data->texture.height;
656 const qreal cx = x + qreal(0.5);
657 const qreal cy = y + qreal(0.5);
659 const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
660 FetchPixelFunc fetch = qFetchPixel[layout->bpp];
662 const uint *end = buffer + length;
664 if (data->fast_matrix) {
665 // The increment pr x in the scanline
666 int fdx = (int)(data->m11 * fixed_scale);
667 int fdy = (int)(data->m12 * fixed_scale);
669 int fx = int((data->m21 * cy
670 + data->m11 * cx + data->dx) * fixed_scale);
671 int fy = int((data->m22 * cy
672 + data->m12 * cx + data->dy) * fixed_scale);
678 if (blendType == BlendTransformedTiled) {
681 if (px < 0) px += image_width;
682 if (py < 0) py += image_height;
684 px = qBound(0, px, image_width - 1);
685 py = qBound(0, py, image_height - 1);
687 *b = fetch(data->texture.scanLine(py), px);
694 const qreal fdx = data->m11;
695 const qreal fdy = data->m12;
696 const qreal fdw = data->m13;
698 qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
699 qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
700 qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
703 const qreal iw = fw == 0 ? 1 : 1 / fw;
704 const qreal tx = fx * iw;
705 const qreal ty = fy * iw;
706 int px = int(tx) - (tx < 0);
707 int py = int(ty) - (ty < 0);
709 if (blendType == BlendTransformedTiled) {
712 if (px < 0) px += image_width;
713 if (py < 0) py += image_height;
715 px = qBound(0, px, image_width - 1);
716 py = qBound(0, py, image_height - 1);
718 *b = fetch(data->texture.scanLine(py), px);
723 //force increment to avoid /0
730 const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0;
731 return layout->convertToARGB32PM(buffer, buffer, length, layout, clut);
735 interpolate 4 argb pixels with the distx and disty factor.
736 distx and disty bust be between 0 and 16
738 static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, int distx, int disty)
740 uint distxy = distx * disty;
741 //idistx * disty = (16-distx) * disty = 16*disty - distxy
742 //idistx * idisty = (16-distx) * (16-disty) = 16*16 - 16*distx -16*dity + distxy
743 uint tlrb = (tl & 0x00ff00ff) * (16*16 - 16*distx - 16*disty + distxy);
744 uint tlag = ((tl & 0xff00ff00) >> 8) * (16*16 - 16*distx - 16*disty + distxy);
745 uint trrb = ((tr & 0x00ff00ff) * (distx*16 - distxy));
746 uint trag = (((tr & 0xff00ff00) >> 8) * (distx*16 - distxy));
747 uint blrb = ((bl & 0x00ff00ff) * (disty*16 - distxy));
748 uint blag = (((bl & 0xff00ff00) >> 8) * (disty*16 - distxy));
749 uint brrb = ((br & 0x00ff00ff) * (distxy));
750 uint brag = (((br & 0xff00ff00) >> 8) * (distxy));
751 return (((tlrb + trrb + blrb + brrb) >> 8) & 0x00ff00ff) | ((tlag + trag + blag + brag) & 0xff00ff00);
754 #if defined(__SSE2__)
755 #define interpolate_4_pixels_16_sse2(tl, tr, bl, br, distx, disty, colorMask, v_256, b) \
757 const __m128i dxdy = _mm_mullo_epi16 (distx, disty); \
758 const __m128i distx_ = _mm_slli_epi16(distx, 4); \
759 const __m128i disty_ = _mm_slli_epi16(disty, 4); \
760 const __m128i idxidy = _mm_add_epi16(dxdy, _mm_sub_epi16(v_256, _mm_add_epi16(distx_, disty_))); \
761 const __m128i dxidy = _mm_sub_epi16(distx_, dxdy); \
762 const __m128i idxdy = _mm_sub_epi16(disty_, dxdy); \
764 __m128i tlAG = _mm_srli_epi16(tl, 8); \
765 __m128i tlRB = _mm_and_si128(tl, colorMask); \
766 __m128i trAG = _mm_srli_epi16(tr, 8); \
767 __m128i trRB = _mm_and_si128(tr, colorMask); \
768 __m128i blAG = _mm_srli_epi16(bl, 8); \
769 __m128i blRB = _mm_and_si128(bl, colorMask); \
770 __m128i brAG = _mm_srli_epi16(br, 8); \
771 __m128i brRB = _mm_and_si128(br, colorMask); \
773 tlAG = _mm_mullo_epi16(tlAG, idxidy); \
774 tlRB = _mm_mullo_epi16(tlRB, idxidy); \
775 trAG = _mm_mullo_epi16(trAG, dxidy); \
776 trRB = _mm_mullo_epi16(trRB, dxidy); \
777 blAG = _mm_mullo_epi16(blAG, idxdy); \
778 blRB = _mm_mullo_epi16(blRB, idxdy); \
779 brAG = _mm_mullo_epi16(brAG, dxdy); \
780 brRB = _mm_mullo_epi16(brRB, dxdy); \
782 /* Add the values, and shift to only keep 8 significant bits per colors */ \
783 __m128i rAG =_mm_add_epi16(_mm_add_epi16(tlAG, trAG), _mm_add_epi16(blAG, brAG)); \
784 __m128i rRB =_mm_add_epi16(_mm_add_epi16(tlRB, trRB), _mm_add_epi16(blRB, brRB)); \
785 rAG = _mm_andnot_si128(colorMask, rAG); \
786 rRB = _mm_srli_epi16(rRB, 8); \
787 _mm_storeu_si128((__m128i*)(b), _mm_or_si128(rAG, rRB)); \
791 #if defined(__ARM_NEON__)
792 #define interpolate_4_pixels_16_neon(tl, tr, bl, br, distx, disty, disty_, colorMask, invColorMask, v_256, b) \
794 const int16x8_t dxdy = vmulq_s16(distx, disty); \
795 const int16x8_t distx_ = vshlq_n_s16(distx, 4); \
796 const int16x8_t idxidy = vaddq_s16(dxdy, vsubq_s16(v_256, vaddq_s16(distx_, disty_))); \
797 const int16x8_t dxidy = vsubq_s16(distx_, dxdy); \
798 const int16x8_t idxdy = vsubq_s16(disty_, dxdy); \
800 int16x8_t tlAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tl), 8)); \
801 int16x8_t tlRB = vandq_s16(tl, colorMask); \
802 int16x8_t trAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tr), 8)); \
803 int16x8_t trRB = vandq_s16(tr, colorMask); \
804 int16x8_t blAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bl), 8)); \
805 int16x8_t blRB = vandq_s16(bl, colorMask); \
806 int16x8_t brAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(br), 8)); \
807 int16x8_t brRB = vandq_s16(br, colorMask); \
809 int16x8_t rAG = vmulq_s16(tlAG, idxidy); \
810 int16x8_t rRB = vmulq_s16(tlRB, idxidy); \
811 rAG = vmlaq_s16(rAG, trAG, dxidy); \
812 rRB = vmlaq_s16(rRB, trRB, dxidy); \
813 rAG = vmlaq_s16(rAG, blAG, idxdy); \
814 rRB = vmlaq_s16(rRB, blRB, idxdy); \
815 rAG = vmlaq_s16(rAG, brAG, dxdy); \
816 rRB = vmlaq_s16(rRB, brRB, dxdy); \
818 rAG = vandq_s16(invColorMask, rAG); \
819 rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8)); \
820 vst1q_s16((int16_t*)(b), vorrq_s16(rAG, rRB)); \
824 template<TextureBlendType blendType>
825 void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2);
828 inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinearTiled>(int max, int, int, int &v1, int &v2)
836 Q_ASSERT(v1 >= 0 && v1 < max);
837 Q_ASSERT(v2 >= 0 && v2 < max);
841 inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(int, int l1, int l2, int &v1, int &v2)
849 Q_ASSERT(v1 >= l1 && v1 <= l2);
850 Q_ASSERT(v2 >= l1 && v2 <= l2);
853 template<TextureBlendType blendType> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
854 static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, const Operator *,
855 const QSpanData *data, int y, int x,
858 int image_width = data->texture.width;
859 int image_height = data->texture.height;
861 int image_x1 = data->texture.x1;
862 int image_y1 = data->texture.y1;
863 int image_x2 = data->texture.x2 - 1;
864 int image_y2 = data->texture.y2 - 1;
866 const qreal cx = x + qreal(0.5);
867 const qreal cy = y + qreal(0.5);
869 uint *end = buffer + length;
871 if (data->fast_matrix) {
872 // The increment pr x in the scanline
873 int fdx = (int)(data->m11 * fixed_scale);
874 int fdy = (int)(data->m12 * fixed_scale);
876 int fx = int((data->m21 * cy
877 + data->m11 * cx + data->dx) * fixed_scale);
878 int fy = int((data->m22 * cy
879 + data->m12 * cx + data->dy) * fixed_scale);
884 if (fdy == 0) { //simple scale, no rotation
887 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
888 const uint *s1 = (const uint *)data->texture.scanLine(y1);
889 const uint *s2 = (const uint *)data->texture.scanLine(y2);
891 if (fdx <= fixed_scale && fdx > 0) { // scale up on X
892 int disty = (fy & 0x0000ffff) >> 8;
893 int idisty = 256 - disty;
896 // The idea is first to do the interpolation between the row s1 and the row s2
897 // into an intermediate buffer, then we interpolate between two pixel of this buffer.
899 // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
900 // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG
901 quint32 intermediate_buffer[2][buffer_size + 2];
902 // count is the size used in the intermediate_buffer.
903 int count = qCeil(length * data->m11) + 2; //+1 for the last pixel to interpolate with, and +1 for rounding errors.
904 Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
907 if (blendType == BlendTransformedBilinearTiled) {
909 if (x < 0) x += image_width;
911 lim = qMin(count, image_x2-x+1);
913 Q_ASSERT(x <= image_x2);
914 uint t = s1[image_x1];
915 uint b = s2[image_x1];
916 quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
917 quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
919 intermediate_buffer[0][f] = rb;
920 intermediate_buffer[1][f] = ag;
923 } while (x < image_x1 && f < lim);
927 if (blendType != BlendTransformedBilinearTiled) {
928 #if defined(__SSE2__)
929 const __m128i disty_ = _mm_set1_epi16(disty);
930 const __m128i idisty_ = _mm_set1_epi16(idisty);
931 const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
934 for (; f < lim; x += 4, f += 4) {
935 // Load 4 pixels from s1, and split the alpha-green and red-blue component
936 __m128i top = _mm_loadu_si128((__m128i*)((const uint *)(s1)+x));
937 __m128i topAG = _mm_srli_epi16(top, 8);
938 __m128i topRB = _mm_and_si128(top, colorMask);
939 // Multiplies each colour component by idisty
940 topAG = _mm_mullo_epi16 (topAG, idisty_);
941 topRB = _mm_mullo_epi16 (topRB, idisty_);
943 // Same for the s2 vector
944 __m128i bottom = _mm_loadu_si128((__m128i*)((const uint *)(s2)+x));
945 __m128i bottomAG = _mm_srli_epi16(bottom, 8);
946 __m128i bottomRB = _mm_and_si128(bottom, colorMask);
947 bottomAG = _mm_mullo_epi16 (bottomAG, disty_);
948 bottomRB = _mm_mullo_epi16 (bottomRB, disty_);
950 // Add the values, and shift to only keep 8 significant bits per colors
951 __m128i rAG =_mm_add_epi16(topAG, bottomAG);
952 rAG = _mm_srli_epi16(rAG, 8);
953 _mm_storeu_si128((__m128i*)(&intermediate_buffer[1][f]), rAG);
954 __m128i rRB =_mm_add_epi16(topRB, bottomRB);
955 rRB = _mm_srli_epi16(rRB, 8);
956 _mm_storeu_si128((__m128i*)(&intermediate_buffer[0][f]), rRB);
958 #elif defined(__ARM_NEON__)
959 const int16x8_t disty_ = vdupq_n_s16(disty);
960 const int16x8_t idisty_ = vdupq_n_s16(idisty);
961 const int16x8_t colorMask = vdupq_n_s16(0x00ff);
964 for (; f < lim; x += 4, f += 4) {
965 // Load 4 pixels from s1, and split the alpha-green and red-blue component
966 int16x8_t top = vld1q_s16((int16_t*)((const uint *)(s1)+x));
967 int16x8_t topAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(top), 8));
968 int16x8_t topRB = vandq_s16(top, colorMask);
969 // Multiplies each colour component by idisty
970 topAG = vmulq_s16(topAG, idisty_);
971 topRB = vmulq_s16(topRB, idisty_);
973 // Same for the s2 vector
974 int16x8_t bottom = vld1q_s16((int16_t*)((const uint *)(s2)+x));
975 int16x8_t bottomAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bottom), 8));
976 int16x8_t bottomRB = vandq_s16(bottom, colorMask);
977 bottomAG = vmulq_s16(bottomAG, disty_);
978 bottomRB = vmulq_s16(bottomRB, disty_);
980 // Add the values, and shift to only keep 8 significant bits per colors
981 int16x8_t rAG = vaddq_s16(topAG, bottomAG);
982 rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8));
983 vst1q_s16((int16_t*)(&intermediate_buffer[1][f]), rAG);
984 int16x8_t rRB = vaddq_s16(topRB, bottomRB);
985 rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8));
986 vst1q_s16((int16_t*)(&intermediate_buffer[0][f]), rRB);
990 for (; f < count; f++) { // Same as above but without sse2
991 if (blendType == BlendTransformedBilinearTiled) {
992 if (x >= image_width) x -= image_width;
994 x = qMin(x, image_x2);
1000 intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
1001 intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
1004 // Now interpolate the values from the intermediate_buffer to get the final result.
1005 fx &= fixed_scale - 1;
1006 Q_ASSERT((fx >> 16) == 0);
1008 register int x1 = (fx >> 16);
1009 register int x2 = x1 + 1;
1011 Q_ASSERT(x2 < count);
1013 register int distx = (fx & 0x0000ffff) >> 8;
1014 register int idistx = 256 - distx;
1015 int rb = ((intermediate_buffer[0][x1] * idistx + intermediate_buffer[0][x2] * distx) >> 8) & 0xff00ff;
1016 int ag = (intermediate_buffer[1][x1] * idistx + intermediate_buffer[1][x2] * distx) & 0xff00ff00;
1021 } else if ((fdx < 0 && fdx > -(fixed_scale / 8)) || fabs(data->m22) < (1./8.)) { // scale up more than 8x
1022 int y1 = (fy >> 16);
1024 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1025 const uint *s1 = (const uint *)data->texture.scanLine(y1);
1026 const uint *s2 = (const uint *)data->texture.scanLine(y2);
1027 int disty = (fy & 0x0000ffff) >> 8;
1028 int idisty = 256 - disty;
1030 int x1 = (fx >> 16);
1032 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1038 int distx = (fx & 0x0000ffff) >> 8;
1039 int idistx = 256 - distx;
1041 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1042 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1043 *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1048 } else { //scale down
1049 int y1 = (fy >> 16);
1051 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1052 const uint *s1 = (const uint *)data->texture.scanLine(y1);
1053 const uint *s2 = (const uint *)data->texture.scanLine(y2);
1054 int disty = (fy & 0x0000ffff) >> 12;
1056 if (blendType != BlendTransformedBilinearTiled) {
1057 #define BILINEAR_DOWNSCALE_BOUNDS_PROLOG \
1059 int x1 = (fx >> 16); \
1061 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); \
1068 int distx = (fx & 0x0000ffff) >> 12; \
1069 *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty); \
1075 boundedEnd = qMin(end, buffer + uint((image_x2 - (fx >> 16)) / data->m11)); \
1077 boundedEnd = qMin(end, buffer + uint((image_x1 - (fx >> 16)) / data->m11)); \
1080 #if defined(__SSE2__)
1081 BILINEAR_DOWNSCALE_BOUNDS_PROLOG
1083 const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
1084 const __m128i v_256 = _mm_set1_epi16(256);
1085 const __m128i v_disty = _mm_set1_epi16(disty);
1086 __m128i v_fdx = _mm_set1_epi32(fdx*4);
1088 ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
1090 union Vect_buffer { __m128i vect; quint32 i[4]; };
1093 for (int i = 0; i < 4; i++) {
1098 while (b < boundedEnd) {
1100 Vect_buffer tl, tr, bl, br;
1102 for (int i = 0; i < 4; i++) {
1103 int x1 = v_fx.i[i] >> 16;
1104 const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1105 const uint *addr_tr = addr_tl + 1;
1108 bl.i[i] = *(addr_tl+secondLine);
1109 br.i[i] = *(addr_tr+secondLine);
1111 __m128i v_distx = _mm_srli_epi16(v_fx.vect, 12);
1112 v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1113 v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1115 interpolate_4_pixels_16_sse2(tl.vect, tr.vect, bl.vect, br.vect, v_distx, v_disty, colorMask, v_256, b);
1117 v_fx.vect = _mm_add_epi32(v_fx.vect, v_fdx);
1120 #elif defined(__ARM_NEON__)
1121 BILINEAR_DOWNSCALE_BOUNDS_PROLOG
1123 const int16x8_t colorMask = vdupq_n_s16(0x00ff);
1124 const int16x8_t invColorMask = vmvnq_s16(colorMask);
1125 const int16x8_t v_256 = vdupq_n_s16(256);
1126 const int16x8_t v_disty = vdupq_n_s16(disty);
1127 const int16x8_t v_disty_ = vshlq_n_s16(v_disty, 4);
1128 int32x4_t v_fdx = vdupq_n_s32(fdx*4);
1130 ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
1132 union Vect_buffer { int32x4_t vect; quint32 i[4]; };
1135 for (int i = 0; i < 4; i++) {
1140 const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
1142 while (b < boundedEnd) {
1144 Vect_buffer tl, tr, bl, br;
1146 Vect_buffer v_fx_shifted;
1147 v_fx_shifted.vect = vshrq_n_s32(v_fx.vect, 16);
1149 int32x4_t v_distx = vshrq_n_s32(vandq_s32(v_fx.vect, v_ffff_mask), 12);
1151 for (int i = 0; i < 4; i++) {
1152 int x1 = v_fx_shifted.i[i];
1153 const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1154 const uint *addr_tr = addr_tl + 1;
1157 bl.i[i] = *(addr_tl+secondLine);
1158 br.i[i] = *(addr_tr+secondLine);
1161 v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
1163 interpolate_4_pixels_16_neon(vreinterpretq_s16_s32(tl.vect), vreinterpretq_s16_s32(tr.vect), vreinterpretq_s16_s32(bl.vect), vreinterpretq_s16_s32(br.vect), vreinterpretq_s16_s32(v_distx), v_disty, v_disty_, colorMask, invColorMask, v_256, b);
1165 v_fx.vect = vaddq_s32(v_fx.vect, v_fdx);
1172 int x1 = (fx >> 16);
1174 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1179 int distx = (fx & 0x0000ffff) >> 12;
1180 *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1186 if (fabs(data->m11) > 8 || fabs(data->m22) > 8) {
1187 //if we are zooming more than 8 times, we use 8bit precision for the position.
1189 int x1 = (fx >> 16);
1191 int y1 = (fy >> 16);
1194 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1195 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1197 const uint *s1 = (const uint *)data->texture.scanLine(y1);
1198 const uint *s2 = (const uint *)data->texture.scanLine(y2);
1205 int distx = (fx & 0x0000ffff) >> 8;
1206 int disty = (fy & 0x0000ffff) >> 8;
1207 int idistx = 256 - distx;
1208 int idisty = 256 - disty;
1210 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1211 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1212 *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1219 //we are zooming less than 8x, use 4bit precision
1221 int x1 = (fx >> 16);
1223 int y1 = (fy >> 16);
1226 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1227 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1229 const uint *s1 = (const uint *)data->texture.scanLine(y1);
1230 const uint *s2 = (const uint *)data->texture.scanLine(y2);
1237 int distx = (fx & 0x0000ffff) >> 12;
1238 int disty = (fy & 0x0000ffff) >> 12;
1240 *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1249 const qreal fdx = data->m11;
1250 const qreal fdy = data->m12;
1251 const qreal fdw = data->m13;
1253 qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
1254 qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
1255 qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
1258 const qreal iw = fw == 0 ? 1 : 1 / fw;
1259 const qreal px = fx * iw - qreal(0.5);
1260 const qreal py = fy * iw - qreal(0.5);
1262 int x1 = int(px) - (px < 0);
1264 int y1 = int(py) - (py < 0);
1267 int distx = int((px - x1) * 256);
1268 int disty = int((py - y1) * 256);
1269 int idistx = 256 - distx;
1270 int idisty = 256 - disty;
1272 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1273 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1275 const uint *s1 = (const uint *)data->texture.scanLine(y1);
1276 const uint *s2 = (const uint *)data->texture.scanLine(y2);
1283 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1284 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1285 *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1290 //force increment to avoid /0
1301 // blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled
1302 template<TextureBlendType blendType>
1303 static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *,
1304 const QSpanData *data, int y, int x, int length)
1306 const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
1307 const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0;
1309 int image_width = data->texture.width;
1310 int image_height = data->texture.height;
1312 int image_x1 = data->texture.x1;
1313 int image_y1 = data->texture.y1;
1314 int image_x2 = data->texture.x2 - 1;
1315 int image_y2 = data->texture.y2 - 1;
1317 const qreal cx = x + qreal(0.5);
1318 const qreal cy = y + qreal(0.5);
1320 if (data->fast_matrix) {
1321 // The increment pr x in the scanline
1322 int fdx = (int)(data->m11 * fixed_scale);
1323 int fdy = (int)(data->m12 * fixed_scale);
1325 int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
1326 int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
1331 if (fdy == 0) { //simple scale, no rotation
1332 int y1 = (fy >> 16);
1334 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1335 const uchar *s1 = data->texture.scanLine(y1);
1336 const uchar *s2 = data->texture.scanLine(y2);
1338 if (fdx <= fixed_scale && fdx > 0) { // scale up on X
1339 int disty = (fy & 0x0000ffff) >> 8;
1340 int idisty = 256 - disty;
1343 // The idea is first to do the interpolation between the row s1 and the row s2
1344 // into an intermediate buffer, then we interpolate between two pixel of this buffer.
1345 FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
1346 uint buf1[buffer_size + 2];
1347 uint buf2[buffer_size + 2];
1351 int count = qCeil(length * data->m11) + 2; //+1 for the last pixel to interpolate with, and +1 for rounding errors.
1352 Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
1354 if (blendType == BlendTransformedBilinearTiled) {
1358 int len1 = qMin(count, image_width - x);
1359 int len2 = qMin(x, count - len1);
1361 ptr1 = fetch(buf1, s1, x, len1);
1362 ptr1 = layout->convertToARGB32PM(buf1, ptr1, len1, layout, clut);
1363 ptr2 = fetch(buf2, s2, x, len1);
1364 ptr2 = layout->convertToARGB32PM(buf2, ptr2, len1, layout, clut);
1365 for (int i = 0; i < len1; ++i) {
1368 buf1[i] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
1369 buf2[i] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
1373 ptr1 = fetch(buf1 + len1, s1, 0, len2);
1374 ptr1 = layout->convertToARGB32PM(buf1 + len1, ptr1, len2, layout, clut);
1375 ptr2 = fetch(buf2 + len1, s2, 0, len2);
1376 ptr2 = layout->convertToARGB32PM(buf2 + len1, ptr2, len2, layout, clut);
1377 for (int i = 0; i < len2; ++i) {
1380 buf1[i + len1] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
1381 buf2[i + len1] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
1384 for (int i = image_width; i < count; ++i) {
1385 buf1[i] = buf1[i - image_width];
1386 buf2[i] = buf2[i - image_width];
1389 int start = qMax(x, image_x1);
1390 int end = qMin(x + count, image_x2 + 1);
1391 int len = qMax(1, end - start);
1392 int leading = start - x;
1394 ptr1 = fetch(buf1 + leading, s1, start, len);
1395 ptr1 = layout->convertToARGB32PM(buf1 + leading, ptr1, len, layout, clut);
1396 ptr2 = fetch(buf2 + leading, s2, start, len);
1397 ptr2 = layout->convertToARGB32PM(buf2 + leading, ptr2, len, layout, clut);
1399 for (int i = 0; i < len; ++i) {
1402 buf1[i + leading] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
1403 buf2[i + leading] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
1406 for (int i = 0; i < leading; ++i) {
1407 buf1[i] = buf1[leading];
1408 buf2[i] = buf2[leading];
1410 for (int i = leading + len; i < count; ++i) {
1411 buf1[i] = buf1[i - 1];
1412 buf2[i] = buf2[i - 1];
1416 // Now interpolate the values from the intermediate_buffer to get the final result.
1417 fx &= fixed_scale - 1;
1418 Q_ASSERT((fx >> 16) == 0);
1419 for (int i = 0; i < length; ++i) {
1420 register int x1 = (fx >> 16);
1421 register int x2 = x1 + 1;
1423 Q_ASSERT(x2 < count);
1425 register int distx = (fx & 0x0000ffff) >> 8;
1426 register int idistx = 256 - distx;
1427 int rb = ((buf1[x1] * idistx + buf1[x2] * distx) >> 8) & 0xff00ff;
1428 int ag = (buf2[x1] * idistx + buf2[x2] * distx) & 0xff00ff00;
1429 buffer[i] = rb | ag;
1433 FetchPixelFunc fetch = qFetchPixel[layout->bpp];
1434 uint buf1[buffer_size];
1435 uint buf2[buffer_size];
1438 int len = qMin(length, buffer_size / 2);
1440 for (int i = 0; i < len; ++i) {
1441 int x1 = (fx >> 16);
1443 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1445 buf1[i * 2 + 0] = fetch(s1, x1);
1446 buf1[i * 2 + 1] = fetch(s1, x2);
1447 buf2[i * 2 + 0] = fetch(s2, x1);
1448 buf2[i * 2 + 1] = fetch(s2, x2);
1452 layout->convertToARGB32PM(buf1, buf1, len * 2, layout, clut);
1453 layout->convertToARGB32PM(buf2, buf2, len * 2, layout, clut);
1455 if ((fdx < 0 && fdx > -(fixed_scale / 8)) || fabs(data->m22) < (1./8.)) { // scale up more than 8x
1456 int disty = (fy & 0x0000ffff) >> 8;
1457 int idisty = 256 - disty;
1458 for (int i = 0; i < len; ++i) {
1459 uint tl = buf1[i * 2 + 0];
1460 uint tr = buf1[i * 2 + 1];
1461 uint bl = buf2[i * 2 + 0];
1462 uint br = buf2[i * 2 + 1];
1463 int distx = (fracX & 0x0000ffff) >> 8;
1464 int idistx = 256 - distx;
1465 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1466 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1467 b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1470 } else { //scale down
1471 int disty = (fy & 0x0000ffff) >> 12;
1472 for (int i = 0; i < len; ++i) {
1473 uint tl = buf1[i * 2 + 0];
1474 uint tr = buf1[i * 2 + 1];
1475 uint bl = buf2[i * 2 + 0];
1476 uint br = buf2[i * 2 + 1];
1477 int distx = (fracX & 0x0000ffff) >> 12;
1478 b[i] = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1487 FetchPixelFunc fetch = qFetchPixel[layout->bpp];
1488 uint buf1[buffer_size];
1489 uint buf2[buffer_size];
1493 int len = qMin(length, buffer_size / 2);
1496 for (int i = 0; i < len; ++i) {
1497 int x1 = (fx >> 16);
1499 int y1 = (fy >> 16);
1501 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1502 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1504 const uchar *s1 = data->texture.scanLine(y1);
1505 const uchar *s2 = data->texture.scanLine(y2);
1507 buf1[i * 2 + 0] = fetch(s1, x1);
1508 buf1[i * 2 + 1] = fetch(s1, x2);
1509 buf2[i * 2 + 0] = fetch(s2, x1);
1510 buf2[i * 2 + 1] = fetch(s2, x2);
1515 layout->convertToARGB32PM(buf1, buf1, len * 2, layout, clut);
1516 layout->convertToARGB32PM(buf2, buf2, len * 2, layout, clut);
1518 if (fabs(data->m11) > 8 || fabs(data->m22) > 8) {
1519 //if we are zooming more than 8 times, we use 8bit precision for the position.
1520 for (int i = 0; i < len; ++i) {
1521 uint tl = buf1[i * 2 + 0];
1522 uint tr = buf1[i * 2 + 1];
1523 uint bl = buf2[i * 2 + 0];
1524 uint br = buf2[i * 2 + 1];
1526 int distx = (fracX & 0x0000ffff) >> 8;
1527 int disty = (fracY & 0x0000ffff) >> 8;
1528 int idistx = 256 - distx;
1529 int idisty = 256 - disty;
1531 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1532 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1533 b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1538 //we are zooming less than 8x, use 4bit precision
1539 for (int i = 0; i < len; ++i) {
1540 uint tl = buf1[i * 2 + 0];
1541 uint tr = buf1[i * 2 + 1];
1542 uint bl = buf2[i * 2 + 0];
1543 uint br = buf2[i * 2 + 1];
1545 int distx = (fracX & 0x0000ffff) >> 12;
1546 int disty = (fracY & 0x0000ffff) >> 12;
1548 b[i] = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1559 const qreal fdx = data->m11;
1560 const qreal fdy = data->m12;
1561 const qreal fdw = data->m13;
1563 qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
1564 qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
1565 qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
1567 FetchPixelFunc fetch = qFetchPixel[layout->bpp];
1568 uint buf1[buffer_size];
1569 uint buf2[buffer_size];
1572 int distxs[buffer_size / 2];
1573 int distys[buffer_size / 2];
1576 int len = qMin(length, buffer_size / 2);
1577 for (int i = 0; i < len; ++i) {
1578 const qreal iw = fw == 0 ? 1 : 1 / fw;
1579 const qreal px = fx * iw - qreal(0.5);
1580 const qreal py = fy * iw - qreal(0.5);
1582 int x1 = int(px) - (px < 0);
1584 int y1 = int(py) - (py < 0);
1587 distxs[i] = int((px - x1) * 256);
1588 distys[i] = int((py - y1) * 256);
1590 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1591 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1593 const uchar *s1 = data->texture.scanLine(y1);
1594 const uchar *s2 = data->texture.scanLine(y2);
1596 buf1[i * 2 + 0] = fetch(s1, x1);
1597 buf1[i * 2 + 1] = fetch(s1, x2);
1598 buf2[i * 2 + 0] = fetch(s2, x1);
1599 buf2[i * 2 + 1] = fetch(s2, x2);
1604 //force increment to avoid /0
1609 layout->convertToARGB32PM(buf1, buf1, len * 2, layout, clut);
1610 layout->convertToARGB32PM(buf2, buf2, len * 2, layout, clut);
1612 for (int i = 0; i < len; ++i) {
1613 int distx = distxs[i];
1614 int disty = distys[i];
1615 int idistx = 256 - distx;
1616 int idisty = 256 - disty;
1618 uint tl = buf1[i * 2 + 0];
1619 uint tr = buf1[i * 2 + 1];
1620 uint bl = buf2[i * 2 + 0];
1621 uint br = buf2[i * 2 + 1];
1623 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1624 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1625 b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1635 static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = {
1639 fetchUntransformed, // Mono
1640 fetchUntransformed, // MonoLsb
1641 fetchUntransformed, // Indexed8
1642 fetchUntransformedARGB32PM, // RGB32
1643 fetchUntransformed, // ARGB32
1644 fetchUntransformedARGB32PM, // ARGB32_Premultiplied
1645 fetchUntransformedRGB16, // RGB16
1646 fetchUntransformed, // ARGB8565_Premultiplied
1647 fetchUntransformed, // RGB666
1648 fetchUntransformed, // ARGB6666_Premultiplied
1649 fetchUntransformed, // RGB555
1650 fetchUntransformed, // ARGB8555_Premultiplied
1651 fetchUntransformed, // RGB888
1652 fetchUntransformed, // RGB444
1653 fetchUntransformed // ARGB4444_Premultiplied
1658 fetchUntransformed, // Mono
1659 fetchUntransformed, // MonoLsb
1660 fetchUntransformed, // Indexed8
1661 fetchUntransformedARGB32PM, // RGB32
1662 fetchUntransformed, // ARGB32
1663 fetchUntransformedARGB32PM, // ARGB32_Premultiplied
1664 fetchUntransformedRGB16, // RGB16
1665 fetchUntransformed, // ARGB8565_Premultiplied
1666 fetchUntransformed, // RGB666
1667 fetchUntransformed, // ARGB6666_Premultiplied
1668 fetchUntransformed, // RGB555
1669 fetchUntransformed, // ARGB8555_Premultiplied
1670 fetchUntransformed, // RGB888
1671 fetchUntransformed, // RGB444
1672 fetchUntransformed // ARGB4444_Premultiplied
1677 fetchTransformed<BlendTransformed>, // Mono
1678 fetchTransformed<BlendTransformed>, // MonoLsb
1679 fetchTransformed<BlendTransformed>, // Indexed8
1680 fetchTransformedARGB32PM<BlendTransformed>, // RGB32
1681 fetchTransformed<BlendTransformed>, // ARGB32
1682 fetchTransformedARGB32PM<BlendTransformed>, // ARGB32_Premultiplied
1683 fetchTransformed<BlendTransformed>, // RGB16
1684 fetchTransformed<BlendTransformed>, // ARGB8565_Premultiplied
1685 fetchTransformed<BlendTransformed>, // RGB666
1686 fetchTransformed<BlendTransformed>, // ARGB6666_Premultiplied
1687 fetchTransformed<BlendTransformed>, // RGB555
1688 fetchTransformed<BlendTransformed>, // ARGB8555_Premultiplied
1689 fetchTransformed<BlendTransformed>, // RGB888
1690 fetchTransformed<BlendTransformed>, // RGB444
1691 fetchTransformed<BlendTransformed>, // ARGB4444_Premultiplied
1694 0, // TransformedTiled
1695 fetchTransformed<BlendTransformedTiled>, // Mono
1696 fetchTransformed<BlendTransformedTiled>, // MonoLsb
1697 fetchTransformed<BlendTransformedTiled>, // Indexed8
1698 fetchTransformedARGB32PM<BlendTransformedTiled>, // RGB32
1699 fetchTransformed<BlendTransformedTiled>, // ARGB32
1700 fetchTransformedARGB32PM<BlendTransformedTiled>, // ARGB32_Premultiplied
1701 fetchTransformed<BlendTransformedTiled>, // RGB16
1702 fetchTransformed<BlendTransformedTiled>, // ARGB8565_Premultiplied
1703 fetchTransformed<BlendTransformedTiled>, // RGB666
1704 fetchTransformed<BlendTransformedTiled>, // ARGB6666_Premultiplied
1705 fetchTransformed<BlendTransformedTiled>, // RGB555
1706 fetchTransformed<BlendTransformedTiled>, // ARGB8555_Premultiplied
1707 fetchTransformed<BlendTransformedTiled>, // RGB888
1708 fetchTransformed<BlendTransformedTiled>, // RGB444
1709 fetchTransformed<BlendTransformedTiled>, // ARGB4444_Premultiplied
1713 fetchTransformedBilinear<BlendTransformedBilinear>, // Mono
1714 fetchTransformedBilinear<BlendTransformedBilinear>, // MonoLsb
1715 fetchTransformedBilinear<BlendTransformedBilinear>, // Indexed8
1716 fetchTransformedBilinearARGB32PM<BlendTransformedBilinear>, // RGB32
1717 fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB32
1718 fetchTransformedBilinearARGB32PM<BlendTransformedBilinear>, // ARGB32_Premultiplied
1719 fetchTransformedBilinear<BlendTransformedBilinear>, // RGB16
1720 fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB8565_Premultiplied
1721 fetchTransformedBilinear<BlendTransformedBilinear>, // RGB666
1722 fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB6666_Premultiplied
1723 fetchTransformedBilinear<BlendTransformedBilinear>, // RGB555
1724 fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB8555_Premultiplied
1725 fetchTransformedBilinear<BlendTransformedBilinear>, // RGB888
1726 fetchTransformedBilinear<BlendTransformedBilinear>, // RGB444
1727 fetchTransformedBilinear<BlendTransformedBilinear> // ARGB4444_Premultiplied
1731 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // Mono
1732 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // MonoLsb
1733 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // Indexed8
1734 fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled>, // RGB32
1735 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB32
1736 fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled>, // ARGB32_Premultiplied
1737 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB16
1738 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB8565_Premultiplied
1739 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB666
1740 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB6666_Premultiplied
1741 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB555
1742 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB8555_Premultiplied
1743 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB888
1744 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB444
1745 fetchTransformedBilinear<BlendTransformedBilinearTiled> // ARGB4444_Premultiplied
1749 #define FIXPT_BITS 8
1750 #define FIXPT_SIZE (1<<FIXPT_BITS)
1752 static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
1754 int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
1755 return data->colorTable[qt_gradient_clamp(data, ipos)];
1758 static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
1760 v->dx = data->gradient.linear.end.x - data->gradient.linear.origin.x;
1761 v->dy = data->gradient.linear.end.y - data->gradient.linear.origin.y;
1762 v->l = v->dx * v->dx + v->dy * v->dy;
1767 v->off = -v->dx * data->gradient.linear.origin.x - v->dy * data->gradient.linear.origin.y;
1771 static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data,
1772 int y, int x, int length)
1774 const uint *b = buffer;
1779 if (op->linear.l == 0) {
1782 rx = data->m21 * (y + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx;
1783 ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(0.5)) + data->dy;
1784 t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off;
1785 inc = op->linear.dx * data->m11 + op->linear.dy * data->m12;
1786 affine = !data->m13 && !data->m23;
1789 t *= (GRADIENT_STOPTABLE_SIZE - 1);
1790 inc *= (GRADIENT_STOPTABLE_SIZE - 1);
1794 const uint *end = buffer + length;
1796 if (inc > qreal(-1e-5) && inc < qreal(1e-5)) {
1797 QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE)));
1799 if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) &&
1800 t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) {
1801 // we can use fixed point math
1802 int t_fixed = int(t * FIXPT_SIZE);
1803 int inc_fixed = int(inc * FIXPT_SIZE);
1804 while (buffer < end) {
1805 *buffer = qt_gradient_pixel_fixed(&data->gradient, t_fixed);
1806 t_fixed += inc_fixed;
1810 // we have to fall back to float math
1811 while (buffer < end) {
1812 *buffer = qt_gradient_pixel(&data->gradient, t/GRADIENT_STOPTABLE_SIZE);
1818 } else { // fall back to float math here as well
1819 qreal rw = data->m23 * (y + qreal(0.5)) + data->m13 * (x + qreal(0.5)) + data->m33;
1820 while (buffer < end) {
1823 t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off;
1825 *buffer = qt_gradient_pixel(&data->gradient, t);
1839 static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
1841 v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x;
1842 v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y;
1844 v->dr = data->gradient.radial.center.radius - data->gradient.radial.focal.radius;
1845 v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius;
1847 v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy;
1848 v->inv2a = 1 / (2 * v->a);
1850 v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0;
1853 class RadialFetchPlain
1856 static inline void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det,
1857 qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b)
1859 if (op->radial.extended) {
1860 while (buffer < end) {
1863 qreal w = qSqrt(det) - b;
1864 if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0)
1865 result = qt_gradient_pixel(&data->gradient, w);
1871 delta_det += delta_delta_det;
1877 while (buffer < end) {
1878 *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b);
1881 delta_det += delta_delta_det;
1888 const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data,
1889 int y, int x, int length)
1891 return qt_fetch_radial_gradient_template<RadialFetchPlain>(buffer, op, data, y, x, length);
1894 static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain;
1896 static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data,
1897 int y, int x, int length)
1899 const uint *b = buffer;
1900 qreal rx = data->m21 * (y + qreal(0.5))
1901 + data->dx + data->m11 * (x + qreal(0.5));
1902 qreal ry = data->m22 * (y + qreal(0.5))
1903 + data->dy + data->m12 * (x + qreal(0.5));
1904 bool affine = !data->m13 && !data->m23;
1906 const uint *end = buffer + length;
1908 rx -= data->gradient.conical.center.x;
1909 ry -= data->gradient.conical.center.y;
1910 while (buffer < end) {
1911 qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle;
1913 *buffer = qt_gradient_pixel(&data->gradient, 1 - angle / (2*Q_PI));
1920 qreal rw = data->m23 * (y + qreal(0.5))
1921 + data->m33 + data->m13 * (x + qreal(0.5));
1924 while (buffer < end) {
1925 qreal angle = qAtan2(ry/rw - data->gradient.conical.center.x,
1926 rx/rw - data->gradient.conical.center.y)
1927 + data->gradient.conical.angle;
1929 *buffer = qt_gradient_pixel(&data->gradient, 1. - angle / (2*Q_PI));
1943 #if defined(Q_CC_RVCT)
1944 // Force ARM code generation for comp_func_* -methods
1947 # if defined(Q_PROCESSOR_ARM_V6)
1948 static __forceinline void preload(const uint *start)
1950 asm( "pld [start]" );
1952 static const uint L2CacheLineLength = 32;
1953 static const uint L2CacheLineLengthInInts = L2CacheLineLength/sizeof(uint);
1954 # define PRELOAD_INIT(x) preload(x);
1955 # define PRELOAD_INIT2(x,y) PRELOAD_INIT(x) PRELOAD_INIT(y)
1956 # define PRELOAD_COND(x) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts);
1957 // Two consecutive preloads stall, so space them out a bit by using different modulus.
1958 # define PRELOAD_COND2(x,y) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); \
1959 if (((uint)&y[i])%L2CacheLineLength == 16) preload(&y[i] + L2CacheLineLengthInInts);
1960 # endif // Q_PROCESSOR_ARM_V6
1963 #if !defined(Q_CC_RVCT) || !defined(Q_PROCESSOR_ARM_V6)
1964 # define PRELOAD_INIT(x)
1965 # define PRELOAD_INIT2(x,y)
1966 # define PRELOAD_COND(x)
1967 # define PRELOAD_COND2(x,y)
1970 /* The constant alpha factor describes an alpha factor that gets applied
1971 to the result of the composition operation combining it with the destination.
1973 The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1.
1974 we get the unmodified operation
1976 result = src op dest
1977 dest = result * const_alpha + dest * (1. - const_alpha)
1979 This means that in the comments below, the first line is the const_alpha==255 case, the
1980 second line the general one.
1983 s == src, sa == alpha(src), sia = 1 - alpha(src)
1984 d == dest, da == alpha(dest), dia = 1 - alpha(dest)
1985 ca = const_alpha, cia = 1 - const_alpha
1987 The methods exist in two variants. One where we have a constant source, the other
1988 where the source is an array of pixels.
1995 #define comp_func_Clear_impl(dest, length, const_alpha)\
1997 if (const_alpha == 255) {\
1998 QT_MEMFILL_UINT(dest, length, 0);\
2000 int ialpha = 255 - const_alpha;\
2002 for (int i = 0; i < length; ++i) {\
2004 dest[i] = BYTE_MUL(dest[i], ialpha);\
2009 void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
2011 comp_func_Clear_impl(dest, length, const_alpha);
2014 void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
2016 comp_func_Clear_impl(dest, length, const_alpha);
2021 dest = s * ca + d * cia
2023 void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha)
2025 if (const_alpha == 255) {
2026 QT_MEMFILL_UINT(dest, length, color);
2028 int ialpha = 255 - const_alpha;
2029 color = BYTE_MUL(color, const_alpha);
2031 for (int i = 0; i < length; ++i) {
2033 dest[i] = color + BYTE_MUL(dest[i], ialpha);
2038 void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2040 if (const_alpha == 255) {
2041 ::memcpy(dest, src, length * sizeof(uint));
2043 int ialpha = 255 - const_alpha;
2044 PRELOAD_INIT2(dest, src)
2045 for (int i = 0; i < length; ++i) {
2046 PRELOAD_COND2(dest, src)
2047 dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha);
2052 void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
2056 void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint)
2061 result = s + d * sia
2062 dest = (s + d * sia) * ca + d * cia
2063 = s * ca + d * (sia * ca + cia)
2064 = s * ca + d * (1 - sa*ca)
2066 void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha)
2068 if ((const_alpha & qAlpha(color)) == 255) {
2069 QT_MEMFILL_UINT(dest, length, color);
2071 if (const_alpha != 255)
2072 color = BYTE_MUL(color, const_alpha);
2074 for (int i = 0; i < length; ++i) {
2076 dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color));
2081 void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2083 PRELOAD_INIT2(dest, src)
2084 if (const_alpha == 255) {
2085 for (int i = 0; i < length; ++i) {
2086 PRELOAD_COND2(dest, src)
2088 if (s >= 0xff000000)
2091 dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
2094 for (int i = 0; i < length; ++i) {
2095 PRELOAD_COND2(dest, src)
2096 uint s = BYTE_MUL(src[i], const_alpha);
2097 dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
2103 result = d + s * dia
2104 dest = (d + s * dia) * ca + d * cia
2107 void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha)
2109 if (const_alpha != 255)
2110 color = BYTE_MUL(color, const_alpha);
2112 for (int i = 0; i < length; ++i) {
2115 dest[i] = d + BYTE_MUL(color, qAlpha(~d));
2119 void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2121 PRELOAD_INIT2(dest, src)
2122 if (const_alpha == 255) {
2123 for (int i = 0; i < length; ++i) {
2124 PRELOAD_COND2(dest, src)
2126 dest[i] = d + BYTE_MUL(src[i], qAlpha(~d));
2129 for (int i = 0; i < length; ++i) {
2130 PRELOAD_COND2(dest, src)
2132 uint s = BYTE_MUL(src[i], const_alpha);
2133 dest[i] = d + BYTE_MUL(s, qAlpha(~d));
2140 dest = s * da * ca + d * cia
2142 void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha)
2145 if (const_alpha == 255) {
2146 for (int i = 0; i < length; ++i) {
2148 dest[i] = BYTE_MUL(color, qAlpha(dest[i]));
2151 color = BYTE_MUL(color, const_alpha);
2152 uint cia = 255 - const_alpha;
2153 for (int i = 0; i < length; ++i) {
2156 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia);
2161 void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2163 PRELOAD_INIT2(dest, src)
2164 if (const_alpha == 255) {
2165 for (int i = 0; i < length; ++i) {
2166 PRELOAD_COND2(dest, src)
2167 dest[i] = BYTE_MUL(src[i], qAlpha(dest[i]));
2170 uint cia = 255 - const_alpha;
2171 for (int i = 0; i < length; ++i) {
2172 PRELOAD_COND2(dest, src)
2174 uint s = BYTE_MUL(src[i], const_alpha);
2175 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia);
2182 dest = d * sa * ca + d * cia
2183 = d * (sa * ca + cia)
2185 void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha)
2187 uint a = qAlpha(color);
2188 if (const_alpha != 255) {
2189 a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
2192 for (int i = 0; i < length; ++i) {
2194 dest[i] = BYTE_MUL(dest[i], a);
2198 void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2200 PRELOAD_INIT2(dest, src)
2201 if (const_alpha == 255) {
2202 for (int i = 0; i < length; ++i) {
2203 PRELOAD_COND2(dest, src)
2204 dest[i] = BYTE_MUL(dest[i], qAlpha(src[i]));
2207 int cia = 255 - const_alpha;
2208 for (int i = 0; i < length; ++i) {
2209 PRELOAD_COND2(dest, src)
2210 uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia;
2211 dest[i] = BYTE_MUL(dest[i], a);
2218 dest = s * dia * ca + d * cia
2221 void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha)
2224 if (const_alpha == 255) {
2225 for (int i = 0; i < length; ++i) {
2227 dest[i] = BYTE_MUL(color, qAlpha(~dest[i]));
2230 color = BYTE_MUL(color, const_alpha);
2231 int cia = 255 - const_alpha;
2232 for (int i = 0; i < length; ++i) {
2235 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia);
2240 void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2242 PRELOAD_INIT2(dest, src)
2243 if (const_alpha == 255) {
2244 for (int i = 0; i < length; ++i) {
2245 PRELOAD_COND2(dest, src)
2246 dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i]));
2249 int cia = 255 - const_alpha;
2250 for (int i = 0; i < length; ++i) {
2251 PRELOAD_COND2(dest, src)
2252 uint s = BYTE_MUL(src[i], const_alpha);
2254 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia);
2261 dest = d * sia * ca + d * cia
2262 = d * (sia * ca + cia)
2264 void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha)
2266 uint a = qAlpha(~color);
2267 if (const_alpha != 255)
2268 a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
2270 for (int i = 0; i < length; ++i) {
2272 dest[i] = BYTE_MUL(dest[i], a);
2276 void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2278 PRELOAD_INIT2(dest, src)
2279 if (const_alpha == 255) {
2280 for (int i = 0; i < length; ++i) {
2281 PRELOAD_COND2(dest, src)
2282 dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i]));
2285 int cia = 255 - const_alpha;
2286 for (int i = 0; i < length; ++i) {
2287 PRELOAD_COND2(dest, src)
2288 uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia;
2289 dest[i] = BYTE_MUL(dest[i], sia);
2295 result = s*da + d*sia
2296 dest = s*da*ca + d*sia*ca + d *cia
2297 = s*ca * da + d * (sia*ca + cia)
2298 = s*ca * da + d * (1 - sa*ca)
2300 void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha)
2302 if (const_alpha != 255) {
2303 color = BYTE_MUL(color, const_alpha);
2305 uint sia = qAlpha(~color);
2307 for (int i = 0; i < length; ++i) {
2309 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia);
2313 void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2315 PRELOAD_INIT2(dest, src)
2316 if (const_alpha == 255) {
2317 for (int i = 0; i < length; ++i) {
2318 PRELOAD_COND2(dest, src)
2321 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
2324 for (int i = 0; i < length; ++i) {
2325 PRELOAD_COND2(dest, src)
2326 uint s = BYTE_MUL(src[i], const_alpha);
2328 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
2334 result = d*sa + s*dia
2335 dest = d*sa*ca + s*dia*ca + d *cia
2336 = s*ca * dia + d * (sa*ca + cia)
2338 void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha)
2340 uint a = qAlpha(color);
2341 if (const_alpha != 255) {
2342 color = BYTE_MUL(color, const_alpha);
2343 a = qAlpha(color) + 255 - const_alpha;
2346 for (int i = 0; i < length; ++i) {
2349 dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d));
2353 void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2355 PRELOAD_INIT2(dest, src)
2356 if (const_alpha == 255) {
2357 for (int i = 0; i < length; ++i) {
2358 PRELOAD_COND2(dest, src)
2361 dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d));
2364 int cia = 255 - const_alpha;
2365 for (int i = 0; i < length; ++i) {
2366 PRELOAD_COND2(dest, src)
2367 uint s = BYTE_MUL(src[i], const_alpha);
2369 uint a = qAlpha(s) + cia;
2370 dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d));
2376 result = d*sia + s*dia
2377 dest = d*sia*ca + s*dia*ca + d *cia
2378 = s*ca * dia + d * (sia*ca + cia)
2379 = s*ca * dia + d * (1 - sa*ca)
2381 void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha)
2383 if (const_alpha != 255)
2384 color = BYTE_MUL(color, const_alpha);
2385 uint sia = qAlpha(~color);
2388 for (int i = 0; i < length; ++i) {
2391 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia);
2395 void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2397 PRELOAD_INIT2(dest, src)
2398 if (const_alpha == 255) {
2399 for (int i = 0; i < length; ++i) {
2400 PRELOAD_COND2(dest, src)
2403 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
2406 for (int i = 0; i < length; ++i) {
2407 PRELOAD_COND2(dest, src)
2409 uint s = BYTE_MUL(src[i], const_alpha);
2410 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
2415 struct QFullCoverage {
2416 inline void store(uint *dest, const uint src) const
2422 struct QPartialCoverage {
2423 inline QPartialCoverage(uint const_alpha)
2425 , ica(255 - const_alpha)
2429 inline void store(uint *dest, const uint src) const
2431 *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
2439 static inline int mix_alpha(int da, int sa)
2441 return 255 - ((255 - sa) * (255 - da) >> 8);
2445 Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
2448 template <typename T>
2449 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage)
2454 for (int i = 0; i < length; ++i) {
2457 d = comp_func_Plus_one_pixel(d, s);
2458 coverage.store(&dest[i], d);
2462 void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha)
2464 if (const_alpha == 255)
2465 comp_func_solid_Plus_impl(dest, length, color, QFullCoverage());
2467 comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha));
2470 template <typename T>
2471 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2473 PRELOAD_INIT2(dest, src)
2474 for (int i = 0; i < length; ++i) {
2475 PRELOAD_COND2(dest, src)
2479 d = comp_func_Plus_one_pixel(d, s);
2481 coverage.store(&dest[i], d);
2485 void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2487 if (const_alpha == 255)
2488 comp_func_Plus_impl(dest, src, length, QFullCoverage());
2490 comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha));
2494 Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2496 static inline int multiply_op(int dst, int src, int da, int sa)
2498 return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa));
2501 template <typename T>
2502 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage)
2504 int sa = qAlpha(color);
2505 int sr = qRed(color);
2506 int sg = qGreen(color);
2507 int sb = qBlue(color);
2510 for (int i = 0; i < length; ++i) {
2515 #define OP(a, b) multiply_op(a, b, da, sa)
2516 int r = OP( qRed(d), sr);
2517 int b = OP( qBlue(d), sb);
2518 int g = OP(qGreen(d), sg);
2519 int a = mix_alpha(da, sa);
2522 coverage.store(&dest[i], qRgba(r, g, b, a));
2526 void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha)
2528 if (const_alpha == 255)
2529 comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
2531 comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
2534 template <typename T>
2535 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2537 PRELOAD_INIT2(dest, src)
2538 for (int i = 0; i < length; ++i) {
2539 PRELOAD_COND2(dest, src)
2546 #define OP(a, b) multiply_op(a, b, da, sa)
2547 int r = OP( qRed(d), qRed(s));
2548 int b = OP( qBlue(d), qBlue(s));
2549 int g = OP(qGreen(d), qGreen(s));
2550 int a = mix_alpha(da, sa);
2553 coverage.store(&dest[i], qRgba(r, g, b, a));
2557 void QT_FASTCALL comp_func_Multiply(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2559 if (const_alpha == 255)
2560 comp_func_Multiply_impl(dest, src, length, QFullCoverage());
2562 comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
2566 Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2567 = Sca + Dca - Sca.Dca
2569 template <typename T>
2570 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage)
2572 int sa = qAlpha(color);
2573 int sr = qRed(color);
2574 int sg = qGreen(color);
2575 int sb = qBlue(color);
2578 for (int i = 0; i < length; ++i) {
2583 #define OP(a, b) 255 - qt_div_255((255-a) * (255-b))
2584 int r = OP( qRed(d), sr);
2585 int b = OP( qBlue(d), sb);
2586 int g = OP(qGreen(d), sg);
2587 int a = mix_alpha(da, sa);
2590 coverage.store(&dest[i], qRgba(r, g, b, a));
2594 void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha)
2596 if (const_alpha == 255)
2597 comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
2599 comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
2602 template <typename T>
2603 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2605 PRELOAD_INIT2(dest, src)
2606 for (int i = 0; i < length; ++i) {
2607 PRELOAD_COND2(dest, src)
2614 #define OP(a, b) 255 - (((255-a) * (255-b)) >> 8)
2615 int r = OP( qRed(d), qRed(s));
2616 int b = OP( qBlue(d), qBlue(s));
2617 int g = OP(qGreen(d), qGreen(s));
2618 int a = mix_alpha(da, sa);
2621 coverage.store(&dest[i], qRgba(r, g, b, a));
2625 void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha)
2627 if (const_alpha == 255)
2628 comp_func_Screen_impl(dest, src, length, QFullCoverage());
2630 comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
2635 Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2637 Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2639 static inline int overlay_op(int dst, int src, int da, int sa)
2641 const int temp = src * (255 - da) + dst * (255 - sa);
2643 return qt_div_255(2 * src * dst + temp);
2645 return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2648 template <typename T>
2649 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage)
2651 int sa = qAlpha(color);
2652 int sr = qRed(color);
2653 int sg = qGreen(color);
2654 int sb = qBlue(color);
2657 for (int i = 0; i < length; ++i) {
2662 #define OP(a, b) overlay_op(a, b, da, sa)
2663 int r = OP( qRed(d), sr);
2664 int b = OP( qBlue(d), sb);
2665 int g = OP(qGreen(d), sg);
2666 int a = mix_alpha(da, sa);
2669 coverage.store(&dest[i], qRgba(r, g, b, a));
2673 void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha)
2675 if (const_alpha == 255)
2676 comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
2678 comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
2681 template <typename T>
2682 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2684 PRELOAD_INIT2(dest, src)
2685 for (int i = 0; i < length; ++i) {
2686 PRELOAD_COND2(dest, src)
2693 #define OP(a, b) overlay_op(a, b, da, sa)
2694 int r = OP( qRed(d), qRed(s));
2695 int b = OP( qBlue(d), qBlue(s));
2696 int g = OP(qGreen(d), qGreen(s));
2697 int a = mix_alpha(da, sa);
2700 coverage.store(&dest[i], qRgba(r, g, b, a));
2704 void QT_FASTCALL comp_func_Overlay(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2706 if (const_alpha == 255)
2707 comp_func_Overlay_impl(dest, src, length, QFullCoverage());
2709 comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
2713 Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2714 Da' = Sa + Da - Sa.Da
2716 static inline int darken_op(int dst, int src, int da, int sa)
2718 return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2721 template <typename T>
2722 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage)
2724 int sa = qAlpha(color);
2725 int sr = qRed(color);
2726 int sg = qGreen(color);
2727 int sb = qBlue(color);
2730 for (int i = 0; i < length; ++i) {
2735 #define OP(a, b) darken_op(a, b, da, sa)
2736 int r = OP( qRed(d), sr);
2737 int b = OP( qBlue(d), sb);
2738 int g = OP(qGreen(d), sg);
2739 int a = mix_alpha(da, sa);
2742 coverage.store(&dest[i], qRgba(r, g, b, a));
2746 void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha)
2748 if (const_alpha == 255)
2749 comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
2751 comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
2754 template <typename T>
2755 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2757 PRELOAD_INIT2(dest, src)
2758 for (int i = 0; i < length; ++i) {
2759 PRELOAD_COND2(dest, src)
2766 #define OP(a, b) darken_op(a, b, da, sa)
2767 int r = OP( qRed(d), qRed(s));
2768 int b = OP( qBlue(d), qBlue(s));
2769 int g = OP(qGreen(d), qGreen(s));
2770 int a = mix_alpha(da, sa);
2773 coverage.store(&dest[i], qRgba(r, g, b, a));
2777 void QT_FASTCALL comp_func_Darken(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2779 if (const_alpha == 255)
2780 comp_func_Darken_impl(dest, src, length, QFullCoverage());
2782 comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
2786 Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2787 Da' = Sa + Da - Sa.Da
2789 static inline int lighten_op(int dst, int src, int da, int sa)
2791 return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2794 template <typename T>
2795 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage)
2797 int sa = qAlpha(color);
2798 int sr = qRed(color);
2799 int sg = qGreen(color);
2800 int sb = qBlue(color);
2803 for (int i = 0; i < length; ++i) {
2808 #define OP(a, b) lighten_op(a, b, da, sa)
2809 int r = OP( qRed(d), sr);
2810 int b = OP( qBlue(d), sb);
2811 int g = OP(qGreen(d), sg);
2812 int a = mix_alpha(da, sa);
2815 coverage.store(&dest[i], qRgba(r, g, b, a));
2819 void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha)
2821 if (const_alpha == 255)
2822 comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
2824 comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
2827 template <typename T>
2828 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2830 PRELOAD_INIT2(dest, src)
2831 for (int i = 0; i < length; ++i) {
2832 PRELOAD_COND2(dest, src)
2839 #define OP(a, b) lighten_op(a, b, da, sa)
2840 int r = OP( qRed(d), qRed(s));
2841 int b = OP( qBlue(d), qBlue(s));
2842 int g = OP(qGreen(d), qGreen(s));
2843 int a = mix_alpha(da, sa);
2846 coverage.store(&dest[i], qRgba(r, g, b, a));
2850 void QT_FASTCALL comp_func_Lighten(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2852 if (const_alpha == 255)
2853 comp_func_Lighten_impl(dest, src, length, QFullCoverage());
2855 comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
2859 if Sca.Da + Dca.Sa >= Sa.Da
2860 Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
2862 Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2864 static inline int color_dodge_op(int dst, int src, int da, int sa)
2866 const int sa_da = sa * da;
2867 const int dst_sa = dst * sa;
2868 const int src_da = src * da;
2870 const int temp = src * (255 - da) + dst * (255 - sa);
2871 if (src_da + dst_sa >= sa_da)
2872 return qt_div_255(sa_da + temp);
2874 return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp);
2877 template <typename T>
2878 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage)
2880 int sa = qAlpha(color);
2881 int sr = qRed(color);
2882 int sg = qGreen(color);
2883 int sb = qBlue(color);
2886 for (int i = 0; i < length; ++i) {
2891 #define OP(a,b) color_dodge_op(a, b, da, sa)
2892 int r = OP( qRed(d), sr);
2893 int b = OP( qBlue(d), sb);
2894 int g = OP(qGreen(d), sg);
2895 int a = mix_alpha(da, sa);
2898 coverage.store(&dest[i], qRgba(r, g, b, a));
2902 void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha)
2904 if (const_alpha == 255)
2905 comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
2907 comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
2910 template <typename T>
2911 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2913 PRELOAD_INIT2(dest, src)
2914 for (int i = 0; i < length; ++i) {
2915 PRELOAD_COND2(dest, src)
2922 #define OP(a, b) color_dodge_op(a, b, da, sa)
2923 int r = OP( qRed(d), qRed(s));
2924 int b = OP( qBlue(d), qBlue(s));
2925 int g = OP(qGreen(d), qGreen(s));
2926 int a = mix_alpha(da, sa);
2929 coverage.store(&dest[i], qRgba(r, g, b, a));
2933 void QT_FASTCALL comp_func_ColorDodge(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2935 if (const_alpha == 255)
2936 comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
2938 comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
2942 if Sca.Da + Dca.Sa <= Sa.Da
2943 Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
2945 Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
2947 static inline int color_burn_op(int dst, int src, int da, int sa)
2949 const int src_da = src * da;
2950 const int dst_sa = dst * sa;
2951 const int sa_da = sa * da;
2953 const int temp = src * (255 - da) + dst * (255 - sa);
2955 if (src == 0 || src_da + dst_sa <= sa_da)
2956 return qt_div_255(temp);
2957 return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp);
2960 template <typename T>
2961 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage)
2963 int sa = qAlpha(color);
2964 int sr = qRed(color);
2965 int sg = qGreen(color);
2966 int sb = qBlue(color);
2969 for (int i = 0; i < length; ++i) {
2974 #define OP(a, b) color_burn_op(a, b, da, sa)
2975 int r = OP( qRed(d), sr);
2976 int b = OP( qBlue(d), sb);
2977 int g = OP(qGreen(d), sg);
2978 int a = mix_alpha(da, sa);
2981 coverage.store(&dest[i], qRgba(r, g, b, a));
2985 void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha)
2987 if (const_alpha == 255)
2988 comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
2990 comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
2993 template <typename T>
2994 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2996 PRELOAD_INIT2(dest, src)
2997 for (int i = 0; i < length; ++i) {
2998 PRELOAD_COND2(dest, src)
3005 #define OP(a, b) color_burn_op(a, b, da, sa)
3006 int r = OP( qRed(d), qRed(s));
3007 int b = OP( qBlue(d), qBlue(s));
3008 int g = OP(qGreen(d), qGreen(s));
3009 int a = mix_alpha(da, sa);
3012 coverage.store(&dest[i], qRgba(r, g, b, a));
3016 void QT_FASTCALL comp_func_ColorBurn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
3018 if (const_alpha == 255)
3019 comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
3021 comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
3026 Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
3028 Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
3030 static inline uint hardlight_op(int dst, int src, int da, int sa)
3032 const uint temp = src * (255 - da) + dst * (255 - sa);
3035 return qt_div_255(2 * src * dst + temp);
3037 return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
3040 template <typename T>
3041 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage)
3043 int sa = qAlpha(color);
3044 int sr = qRed(color);
3045 int sg = qGreen(color);
3046 int sb = qBlue(color);
3049 for (int i = 0; i < length; ++i) {
3054 #define OP(a, b) hardlight_op(a, b, da, sa)
3055 int r = OP( qRed(d), sr);
3056 int b = OP( qBlue(d), sb);
3057 int g = OP(qGreen(d), sg);
3058 int a = mix_alpha(da, sa);
3061 coverage.store(&dest[i], qRgba(r, g, b, a));
3065 void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha)
3067 if (const_alpha == 255)
3068 comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
3070 comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
3073 template <typename T>
3074 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
3076 PRELOAD_INIT2(dest, src)
3077 for (int i = 0; i < length; ++i) {
3078 PRELOAD_COND2(dest, src)
3085 #define OP(a, b) hardlight_op(a, b, da, sa)
3086 int r = OP( qRed(d), qRed(s));
3087 int b = OP( qBlue(d), qBlue(s));
3088 int g = OP(qGreen(d), qGreen(s));
3089 int a = mix_alpha(da, sa);
3092 coverage.store(&dest[i], qRgba(r, g, b, a));
3096 void QT_FASTCALL comp_func_HardLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
3098 if (const_alpha == 255)
3099 comp_func_HardLight_impl(dest, src, length, QFullCoverage());
3101 comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
3106 Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
3107 otherwise if 2.Sca > Sa and 4.Dca <= Da
3108 Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
3109 otherwise if 2.Sca > Sa and 4.Dca > Da
3110 Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
3112 static inline int soft_light_op(int dst, int src, int da, int sa)
3114 const int src2 = src << 1;
3115 const int dst_np = da != 0 ? (255 * dst) / da : 0;
3116 const int temp = (src * (255 - da) + dst * (255 - sa)) * 255;
3119 return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025;
3120 else if (4 * dst <= da)
3121 return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025;
3123 # ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
3124 return (dst * sa * 255 + da * (src2 - sa) * (qIntSqrtInt(dst_np * 255) - dst_np) + temp) / 65025;
3126 return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025;
3131 template <typename T>
3132 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage)
3134 int sa = qAlpha(color);
3135 int sr = qRed(color);
3136 int sg = qGreen(color);
3137 int sb = qBlue(color);
3140 for (int i = 0; i < length; ++i) {
3145 #define OP(a, b) soft_light_op(a, b, da, sa)
3146 int r = OP( qRed(d), sr);
3147 int b = OP( qBlue(d), sb);
3148 int g = OP(qGreen(d), sg);
3149 int a = mix_alpha(da, sa);
3152 coverage.store(&dest[i], qRgba(r, g, b, a));
3156 void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
3158 if (const_alpha == 255)
3159 comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
3161 comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
3164 template <typename T>
3165 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
3167 PRELOAD_INIT2(dest, src)
3168 for (int i = 0; i < length; ++i) {
3169 PRELOAD_COND2(dest, src)
3176 #define OP(a, b) soft_light_op(a, b, da, sa)
3177 int r = OP( qRed(d), qRed(s));
3178 int b = OP( qBlue(d), qBlue(s));
3179 int g = OP(qGreen(d), qGreen(s));
3180 int a = mix_alpha(da, sa);
3183 coverage.store(&dest[i], qRgba(r, g, b, a));
3187 void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
3189 if (const_alpha == 255)
3190 comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
3192 comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
3196 Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
3197 = Sca + Dca - 2.min(Sca.Da, Dca.Sa)
3199 static inline int difference_op(int dst, int src, int da, int sa)
3201 return src + dst - qt_div_255(2 * qMin(src * da, dst * sa));
3204 template <typename T>
3205 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage)
3207 int sa = qAlpha(color);
3208 int sr = qRed(color);
3209 int sg = qGreen(color);
3210 int sb = qBlue(color);
3213 for (int i = 0; i < length; ++i) {
3218 #define OP(a, b) difference_op(a, b, da, sa)
3219 int r = OP( qRed(d), sr);
3220 int b = OP( qBlue(d), sb);
3221 int g = OP(qGreen(d), sg);
3222 int a = mix_alpha(da, sa);
3225 coverage.store(&dest[i], qRgba(r, g, b, a));
3229 void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha)
3231 if (const_alpha == 255)
3232 comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
3234 comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
3237 template <typename T>
3238 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
3240 PRELOAD_INIT2(dest, src)
3241 for (int i = 0; i < length; ++i) {
3242 PRELOAD_COND2(dest, src)
3249 #define OP(a, b) difference_op(a, b, da, sa)
3250 int r = OP( qRed(d), qRed(s));
3251 int b = OP( qBlue(d), qBlue(s));
3252 int g = OP(qGreen(d), qGreen(s));
3253 int a = mix_alpha(da, sa);
3256 coverage.store(&dest[i], qRgba(r, g, b, a));
3260 void QT_FASTCALL comp_func_Difference(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
3262 if (const_alpha == 255)
3263 comp_func_Difference_impl(dest, src, length, QFullCoverage());
3265 comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
3269 Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
3271 template <typename T>
3272 Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage)
3274 int sa = qAlpha(color);
3275 int sr = qRed(color);
3276 int sg = qGreen(color);
3277 int sb = qBlue(color);
3280 for (int i = 0; i < length; ++i) {
3285 #define OP(a, b) (a + b - qt_div_255(2*(a*b)))
3286 int r = OP( qRed(d), sr);
3287 int b = OP( qBlue(d), sb);
3288 int g = OP(qGreen(d), sg);
3289 int a = mix_alpha(da, sa);
3292 coverage.store(&dest[i], qRgba(r, g, b, a));
3296 void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha)
3298 if (const_alpha == 255)
3299 comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage());
3301 comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
3304 template <typename T>
3305 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
3307 PRELOAD_INIT2(dest, src)
3308 for (int i = 0; i < length; ++i) {
3309 PRELOAD_COND2(dest, src)
3316 #define OP(a, b) (a + b - ((a*b) >> 7))
3317 int r = OP( qRed(d), qRed(s));
3318 int b = OP( qBlue(d), qBlue(s));
3319 int g = OP(qGreen(d), qGreen(s));
3320 int a = mix_alpha(da, sa);
3323 coverage.store(&dest[i], qRgba(r, g, b, a));
3327 void QT_FASTCALL comp_func_Exclusion(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
3329 if (const_alpha == 255)
3330 comp_func_Exclusion_impl(dest, src, length, QFullCoverage());
3332 comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
3335 #if defined(Q_CC_RVCT)
3336 // Restore pragma state from previous #pragma arm
3340 void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest,
3345 Q_UNUSED(const_alpha);
3350 void QT_FASTCALL rasterop_SourceOrDestination(uint *Q_DECL_RESTRICT dest,
3351 const uint *Q_DECL_RESTRICT src,
3355 Q_UNUSED(const_alpha);
3360 void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest,
3365 Q_UNUSED(const_alpha);
3366 color |= 0xff000000;
3371 void QT_FASTCALL rasterop_SourceAndDestination(uint *Q_DECL_RESTRICT dest,
3372 const uint *Q_DECL_RESTRICT src,
3376 Q_UNUSED(const_alpha);
3378 *dest = (*src & *dest) | 0xff000000;
3383 void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest,
3388 Q_UNUSED(const_alpha);
3389 color &= 0x00ffffff;
3394 void QT_FASTCALL rasterop_SourceXorDestination(uint *Q_DECL_RESTRICT dest,
3395 const uint *Q_DECL_RESTRICT src,
3399 Q_UNUSED(const_alpha);
3401 *dest = (*src ^ *dest) | 0xff000000;
3406 void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest,
3411 Q_UNUSED(const_alpha);
3414 *dest = (color & ~(*dest)) | 0xff000000;
3419 void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *Q_DECL_RESTRICT dest,
3420 const uint *Q_DECL_RESTRICT src,
3424 Q_UNUSED(const_alpha);
3426 *dest = (~(*src) & ~(*dest)) | 0xff000000;
3431 void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest,
3436 Q_UNUSED(const_alpha);
3437 color = ~color | 0xff000000;
3439 *dest = color | ~(*dest);
3444 void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *Q_DECL_RESTRICT dest,
3445 const uint *Q_DECL_RESTRICT src,
3449 Q_UNUSED(const_alpha);
3451 *dest = ~(*src) | ~(*dest) | 0xff000000;
3456 void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest,
3461 Q_UNUSED(const_alpha);
3462 color = ~color & 0x00ffffff;
3464 *dest = color ^ (*dest);
3469 void QT_FASTCALL rasterop_NotSourceXorDestination(uint *Q_DECL_RESTRICT dest,
3470 const uint *Q_DECL_RESTRICT src,
3474 Q_UNUSED(const_alpha);
3476 *dest = ((~(*src)) ^ (*dest)) | 0xff000000;
3481 void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length,
3482 uint color, uint const_alpha)
3484 Q_UNUSED(const_alpha);
3485 qt_memfill(dest, ~color | 0xff000000, length);
3488 void QT_FASTCALL rasterop_NotSource(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src,
3489 int length, uint const_alpha)
3491 Q_UNUSED(const_alpha);
3493 *dest++ = ~(*src++) | 0xff000000;
3496 void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest,
3501 Q_UNUSED(const_alpha);
3502 color = ~color | 0xff000000;
3504 *dest = color & *dest;
3509 void QT_FASTCALL rasterop_NotSourceAndDestination(uint *Q_DECL_RESTRICT dest,
3510 const uint *Q_DECL_RESTRICT src,
3514 Q_UNUSED(const_alpha);
3516 *dest = (~(*src) & *dest) | 0xff000000;
3521 void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest,
3526 Q_UNUSED(const_alpha);
3528 *dest = (color & ~(*dest)) | 0xff000000;
3533 void QT_FASTCALL rasterop_SourceAndNotDestination(uint *Q_DECL_RESTRICT dest,
3534 const uint *Q_DECL_RESTRICT src,
3538 Q_UNUSED(const_alpha);
3540 *dest = (*src & ~(*dest)) | 0xff000000;
3545 static CompositionFunctionSolid functionForModeSolid_C[] = {
3546 comp_func_solid_SourceOver,
3547 comp_func_solid_DestinationOver,
3548 comp_func_solid_Clear,
3549 comp_func_solid_Source,
3550 comp_func_solid_Destination,
3551 comp_func_solid_SourceIn,
3552 comp_func_solid_DestinationIn,
3553 comp_func_solid_SourceOut,
3554 comp_func_solid_DestinationOut,
3555 comp_func_solid_SourceAtop,
3556 comp_func_solid_DestinationAtop,
3557 comp_func_solid_XOR,
3558 comp_func_solid_Plus,
3559 comp_func_solid_Multiply,
3560 comp_func_solid_Screen,
3561 comp_func_solid_Overlay,
3562 comp_func_solid_Darken,
3563 comp_func_solid_Lighten,
3564 comp_func_solid_ColorDodge,
3565 comp_func_solid_ColorBurn,
3566 comp_func_solid_HardLight,
3567 comp_func_solid_SoftLight,
3568 comp_func_solid_Difference,
3569 comp_func_solid_Exclusion,
3570 rasterop_solid_SourceOrDestination,
3571 rasterop_solid_SourceAndDestination,
3572 rasterop_solid_SourceXorDestination,
3573 rasterop_solid_NotSourceAndNotDestination,
3574 rasterop_solid_NotSourceOrNotDestination,
3575 rasterop_solid_NotSourceXorDestination,
3576 rasterop_solid_NotSource,
3577 rasterop_solid_NotSourceAndDestination,
3578 rasterop_solid_SourceAndNotDestination
3581 static const CompositionFunctionSolid *functionForModeSolid = functionForModeSolid_C;
3583 static CompositionFunction functionForMode_C[] = {
3584 comp_func_SourceOver,
3585 comp_func_DestinationOver,
3588 comp_func_Destination,
3590 comp_func_DestinationIn,
3591 comp_func_SourceOut,
3592 comp_func_DestinationOut,
3593 comp_func_SourceAtop,
3594 comp_func_DestinationAtop,
3602 comp_func_ColorDodge,
3603 comp_func_ColorBurn,
3604 comp_func_HardLight,
3605 comp_func_SoftLight,
3606 comp_func_Difference,
3607 comp_func_Exclusion,
3608 rasterop_SourceOrDestination,
3609 rasterop_SourceAndDestination,
3610 rasterop_SourceXorDestination,
3611 rasterop_NotSourceAndNotDestination,
3612 rasterop_NotSourceOrNotDestination,
3613 rasterop_NotSourceXorDestination,
3615 rasterop_NotSourceAndDestination,
3616 rasterop_SourceAndNotDestination
3619 static const CompositionFunction *functionForMode = functionForMode_C;
3621 static TextureBlendType getBlendType(const QSpanData *data)
3623 TextureBlendType ft;
3624 if (data->txop <= QTransform::TxTranslate)
3625 if (data->texture.type == QTextureData::Tiled)
3628 ft = BlendUntransformed;
3629 else if (data->bilinear)
3630 if (data->texture.type == QTextureData::Tiled)
3631 ft = BlendTransformedBilinearTiled;
3633 ft = BlendTransformedBilinear;
3635 if (data->texture.type == QTextureData::Tiled)
3636 ft = BlendTransformedTiled;
3638 ft = BlendTransformed;
3642 static inline Operator getOperator(const QSpanData *data, const QSpan *spans, int spanCount)
3645 bool solidSource = false;
3647 switch(data->type) {
3648 case QSpanData::Solid:
3649 solidSource = (qAlpha(data->solid.color) == 255);
3651 case QSpanData::LinearGradient:
3652 solidSource = !data->gradient.alphaColor;
3653 getLinearGradientValues(&op.linear, data);
3654 op.src_fetch = qt_fetch_linear_gradient;
3656 case QSpanData::RadialGradient:
3657 solidSource = !data->gradient.alphaColor;
3658 getRadialGradientValues(&op.radial, data);
3659 op.src_fetch = qt_fetch_radial_gradient;
3661 case QSpanData::ConicalGradient:
3662 solidSource = !data->gradient.alphaColor;
3663 op.src_fetch = qt_fetch_conical_gradient;
3665 case QSpanData::Texture:
3666 op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format];
3667 solidSource = !data->texture.hasAlpha;
3672 op.mode = data->rasterBuffer->compositionMode;
3673 if (op.mode == QPainter::CompositionMode_SourceOver && solidSource)
3674 op.mode = QPainter::CompositionMode_Source;
3676 op.dest_fetch = destFetchProc[data->rasterBuffer->format];
3677 if (op.mode == QPainter::CompositionMode_Source) {
3678 switch (data->rasterBuffer->format) {
3679 case QImage::Format_RGB32:
3680 case QImage::Format_ARGB32_Premultiplied:
3681 // don't clear dest_fetch as it sets up the pointer correctly to save one copy
3684 if (data->type == QSpanData::Texture && data->texture.const_alpha != 256)
3686 const QSpan *lastSpan = spans + spanCount;
3687 bool alphaSpans = false;
3688 while (spans < lastSpan) {
3689 if (spans->coverage != 255) {
3701 op.dest_store = destStoreProc[data->rasterBuffer->format];
3703 op.funcSolid = functionForModeSolid[op.mode];
3704 op.func = functionForMode[op.mode];
3711 // -------------------- blend methods ---------------------
3713 #if !defined(Q_CC_SUN)
3716 void blend_color_generic(int count, const QSpan *spans, void *userData)
3718 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3719 uint buffer[buffer_size];
3720 Operator op = getOperator(data, spans, count);
3724 int length = spans->len;
3726 int l = qMin(buffer_size, length);
3727 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3728 op.funcSolid(dest, l, data->solid.color, spans->coverage);
3730 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3738 static void blend_color_argb(int count, const QSpan *spans, void *userData)
3740 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3742 Operator op = getOperator(data, spans, count);
3744 if (op.mode == QPainter::CompositionMode_Source) {
3745 // inline for performance
3747 uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3748 if (spans->coverage == 255) {
3749 QT_MEMFILL_UINT(target, spans->len, data->solid.color);
3751 uint c = BYTE_MUL(data->solid.color, spans->coverage);
3752 int ialpha = 255 - spans->coverage;
3753 for (int i = 0; i < spans->len; ++i)
3754 target[i] = c + BYTE_MUL(target[i], ialpha);
3762 uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3763 op.funcSolid(target, spans->len, data->solid.color, spans->coverage);
3768 static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
3770 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3773 We duplicate a little logic from getOperator() and calculate the
3774 composition mode directly. This allows blend_color_rgb16 to be used
3775 from qt_gradient_quint16 with minimal overhead.
3777 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
3778 if (mode == QPainter::CompositionMode_SourceOver &&
3779 qAlpha(data->solid.color) == 255)
3780 mode = QPainter::CompositionMode_Source;
3782 if (mode == QPainter::CompositionMode_Source) {
3783 // inline for performance
3784 ushort c = qConvertRgb32To16(data->solid.color);
3786 ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3787 if (spans->coverage == 255) {
3788 QT_MEMFILL_USHORT(target, spans->len, c);
3790 ushort color = BYTE_MUL_RGB16(c, spans->coverage);
3791 int ialpha = 255 - spans->coverage;
3792 const ushort *end = target + spans->len;
3793 while (target < end) {
3794 *target = color + BYTE_MUL_RGB16(*target, ialpha);
3803 if (mode == QPainter::CompositionMode_SourceOver) {
3805 uint color = BYTE_MUL(data->solid.color, spans->coverage);
3806 int ialpha = qAlpha(~color);
3807 ushort c = qConvertRgb32To16(color);
3808 ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3809 int len = spans->len;
3810 bool pre = (((quintptr)target) & 0x3) != 0;
3813 // skip to word boundary
3814 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3822 uint *target32 = (uint*)target;
3823 uint c32 = c | (c<<16);
3825 uint salpha = (ialpha+1) >> 3; // calculate here rather than in loop
3828 *target32 = c32 + BYTE_MUL_RGB16_32(*target32, salpha);
3833 // one last pixel beyond a full word
3834 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3841 blend_color_generic(count, spans, userData);
3844 template <typename T>
3845 void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
3847 uint const_alpha = 256;
3848 if (data->type == QSpanData::Texture)
3849 const_alpha = data->texture.const_alpha;
3854 const int y = spans->y;
3855 int right = x + spans->len;
3857 // compute length of adjacent spans
3858 for (int i = 1; i < count && spans[i].y == y && spans[i].x == right; ++i)
3859 right += spans[i].len;
3860 int length = right - x;
3863 int l = qMin(buffer_size, length);
3866 int process_length = l;
3869 const uint *src = handler.fetch(process_x, y, process_length);
3872 if (x == spans->x) // new span?
3873 coverage = (spans->coverage * const_alpha) >> 8;
3875 int right = spans->x + spans->len;
3876 int len = qMin(l, right - x);
3878 handler.process(x, y, len, coverage, src, offset);
3884 if (x == right) { // done with current span?
3889 handler.store(process_x, y, process_length);
3896 QBlendBase(QSpanData *d, Operator o)
3908 uint buffer[buffer_size];
3909 uint src_buffer[buffer_size];
3912 class BlendSrcGeneric : public QBlendBase
3915 BlendSrcGeneric(QSpanData *d, Operator o)
3920 const uint *fetch(int x, int y, int len)
3922 dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, y, len) : buffer;
3923 return op.src_fetch(src_buffer, &op, data, y, x, len);
3926 void process(int, int, int len, int coverage, const uint *src, int offset)
3928 op.func(dest + offset, src + offset, len, coverage);
3931 void store(int x, int y, int len)
3934 op.dest_store(data->rasterBuffer, x, y, dest, len);
3938 static void blend_src_generic(int count, const QSpan *spans, void *userData)
3940 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3941 BlendSrcGeneric blend(data, getOperator(data, spans, count));
3942 handleSpans(count, spans, data, blend);
3945 static void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
3947 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3949 uint buffer[buffer_size];
3950 uint src_buffer[buffer_size];
3951 Operator op = getOperator(data, spans, count);
3953 const int image_width = data->texture.width;
3954 const int image_height = data->texture.height;
3955 int xoff = -qRound(-data->dx);
3956 int yoff = -qRound(-data->dy);
3960 int length = spans->len;
3962 int sy = yoff + spans->y;
3963 if (sy >= 0 && sy < image_height && sx < image_width) {
3969 if (sx + length > image_width)
3970 length = image_width - sx;
3972 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3974 int l = qMin(buffer_size, length);
3975 const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
3976 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3977 op.func(dest, src, l, coverage);
3979 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3990 static void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
3992 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3993 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
3994 && data->texture.format != QImage::Format_RGB32) {
3995 blend_untransformed_generic(count, spans, userData);
3999 Operator op = getOperator(data, spans, count);
4001 const int image_width = data->texture.width;
4002 const int image_height = data->texture.height;
4003 int xoff = -qRound(-data->dx);
4004 int yoff = -qRound(-data->dy);
4008 int length = spans->len;
4010 int sy = yoff + spans->y;
4011 if (sy >= 0 && sy < image_height && sx < image_width) {
4017 if (sx + length > image_width)
4018 length = image_width - sx;
4020 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4021 const uint *src = (uint *)data->texture.scanLine(sy) + sx;
4022 uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
4023 op.func(dest, src, length, coverage);
4030 static inline quint16 interpolate_pixel_rgb16_255(quint16 x, quint8 a,
4031 quint16 y, quint8 b)
4033 quint16 t = ((((x & 0x07e0) * a) + ((y & 0x07e0) * b)) >> 5) & 0x07e0;
4034 t |= ((((x & 0xf81f) * a) + ((y & 0xf81f) * b)) >> 5) & 0xf81f;
4039 static inline quint32 interpolate_pixel_rgb16x2_255(quint32 x, quint8 a,
4040 quint32 y, quint8 b)
4043 t = ((((x & 0xf81f07e0) >> 5) * a) + (((y & 0xf81f07e0) >> 5) * b)) & 0xf81f07e0;
4044 t |= ((((x & 0x07e0f81f) * a) + ((y & 0x07e0f81f) * b)) >> 5) & 0x07e0f81f;
4048 static inline void blend_sourceOver_rgb16_rgb16(quint16 *Q_DECL_RESTRICT dest,
4049 const quint16 *Q_DECL_RESTRICT src,
4052 const quint8 ialpha)
4054 const int dstAlign = ((quintptr)dest) & 0x3;
4056 *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
4061 const int srcAlign = ((quintptr)src) & 0x3;
4062 int length32 = length >> 1;
4063 if (length32 && srcAlign == 0) {
4064 while (length32--) {
4065 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4066 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4067 *dest32 = interpolate_pixel_rgb16x2_255(*src32, alpha,
4075 *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
4081 static void blend_untransformed_rgb565(int count, const QSpan *spans, void *userData)
4083 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4084 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4086 if (data->texture.format != QImage::Format_RGB16
4087 || (mode != QPainter::CompositionMode_SourceOver
4088 && mode != QPainter::CompositionMode_Source))
4090 blend_untransformed_generic(count, spans, userData);
4094 const int image_width = data->texture.width;
4095 const int image_height = data->texture.height;
4096 int xoff = -qRound(-data->dx);
4097 int yoff = -qRound(-data->dy);
4100 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4101 if (coverage == 0) {
4107 int length = spans->len;
4109 int sy = yoff + spans->y;
4110 if (sy >= 0 && sy < image_height && sx < image_width) {
4116 if (sx + length > image_width)
4117 length = image_width - sx;
4119 quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + x;
4120 const quint16 *src = (quint16 *)data->texture.scanLine(sy) + sx;
4121 if (coverage == 255) {
4122 memcpy(dest, src, length * sizeof(quint16));
4124 const quint8 alpha = (coverage + 1) >> 3;
4125 const quint8 ialpha = 0x20 - alpha;
4127 blend_sourceOver_rgb16_rgb16(dest, src, length, alpha, ialpha);
4135 static void blend_tiled_generic(int count, const QSpan *spans, void *userData)
4137 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4139 uint buffer[buffer_size];
4140 uint src_buffer[buffer_size];
4141 Operator op = getOperator(data, spans, count);
4143 const int image_width = data->texture.width;
4144 const int image_height = data->texture.height;
4145 int xoff = -qRound(-data->dx) % image_width;
4146 int yoff = -qRound(-data->dy) % image_height;
4149 xoff += image_width;
4151 yoff += image_height;
4155 int length = spans->len;
4156 int sx = (xoff + spans->x) % image_width;
4157 int sy = (spans->y + yoff) % image_height;
4163 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4165 int l = qMin(image_width - sx, length);
4166 if (buffer_size < l)
4168 const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
4169 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
4170 op.func(dest, src, l, coverage);
4172 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
4176 if (sx >= image_width)
4183 static void blend_tiled_argb(int count, const QSpan *spans, void *userData)
4185 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4186 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
4187 && data->texture.format != QImage::Format_RGB32) {
4188 blend_tiled_generic(count, spans, userData);
4192 Operator op = getOperator(data, spans, count);
4194 int image_width = data->texture.width;
4195 int image_height = data->texture.height;
4196 int xoff = -qRound(-data->dx) % image_width;
4197 int yoff = -qRound(-data->dy) % image_height;
4200 xoff += image_width;
4202 yoff += image_height;
4206 int length = spans->len;
4207 int sx = (xoff + spans->x) % image_width;
4208 int sy = (spans->y + yoff) % image_height;
4214 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4216 int l = qMin(image_width - sx, length);
4217 if (buffer_size < l)
4219 const uint *src = (uint *)data->texture.scanLine(sy) + sx;
4220 uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
4221 op.func(dest, src, l, coverage);
4230 static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
4232 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4233 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4235 if (data->texture.format != QImage::Format_RGB16
4236 || (mode != QPainter::CompositionMode_SourceOver
4237 && mode != QPainter::CompositionMode_Source))
4239 blend_tiled_generic(count, spans, userData);
4243 const int image_width = data->texture.width;
4244 const int image_height = data->texture.height;
4245 int xoff = -qRound(-data->dx) % image_width;
4246 int yoff = -qRound(-data->dy) % image_height;
4249 xoff += image_width;
4251 yoff += image_height;
4254 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4255 if (coverage == 0) {
4261 int length = spans->len;
4262 int sx = (xoff + spans->x) % image_width;
4263 int sy = (spans->y + yoff) % image_height;
4269 if (coverage == 255) {
4270 // Copy the first texture block
4271 length = qMin(image_width,length);
4274 int l = qMin(image_width - sx, length);
4275 if (buffer_size < l)
4277 quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + tx;
4278 const quint16 *src = (quint16 *)data->texture.scanLine(sy) + sx;
4279 memcpy(dest, src, l * sizeof(quint16));
4285 // Now use the rasterBuffer as the source of the texture,
4286 // We can now progressively copy larger blocks
4287 // - Less cpu time in code figuring out what to copy
4288 // We are dealing with one block of data
4289 // - More likely to fit in the cache
4291 int copy_image_width = qMin(image_width, int(spans->len));
4292 length = spans->len - copy_image_width;
4293 quint16 *src = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x;
4294 quint16 *dest = src + copy_image_width;
4295 while (copy_image_width < length) {
4296 memcpy(dest, src, copy_image_width * sizeof(quint16));
4297 dest += copy_image_width;
4298 length -= copy_image_width;
4299 copy_image_width *= 2;
4302 memcpy(dest, src, length * sizeof(quint16));
4304 const quint8 alpha = (coverage + 1) >> 3;
4305 const quint8 ialpha = 0x20 - alpha;
4308 int l = qMin(image_width - sx, length);
4309 if (buffer_size < l)
4311 quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x;
4312 const quint16 *src = (quint16 *)data->texture.scanLine(sy) + sx;
4313 blend_sourceOver_rgb16_rgb16(dest, src, l, alpha, ialpha);
4324 static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans, void *userData)
4326 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4327 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4329 if (data->texture.format != QImage::Format_RGB16
4330 || (mode != QPainter::CompositionMode_SourceOver
4331 && mode != QPainter::CompositionMode_Source))
4333 blend_src_generic(count, spans, userData);
4337 quint16 buffer[buffer_size];
4339 const int src_minx = data->texture.x1;
4340 const int src_miny = data->texture.y1;
4341 const int src_maxx = data->texture.x2 - 1;
4342 const int src_maxy = data->texture.y2 - 1;
4344 if (data->fast_matrix) {
4345 // The increment pr x in the scanline
4346 const int fdx = (int)(data->m11 * fixed_scale);
4347 const int fdy = (int)(data->m12 * fixed_scale);
4350 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4351 const quint8 alpha = (coverage + 1) >> 3;
4352 const quint8 ialpha = 0x20 - alpha;
4358 quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4359 const qreal cx = spans->x + qreal(0.5);
4360 const qreal cy = spans->y + qreal(0.5);
4361 int x = int((data->m21 * cy
4362 + data->m11 * cx + data->dx) * fixed_scale) - half_point;
4363 int y = int((data->m22 * cy
4364 + data->m12 * cx + data->dy) * fixed_scale) - half_point;
4365 int length = spans->len;
4374 l = qMin(length, buffer_size);
4377 const quint16 *end = b + l;
4385 fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2);
4386 fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2);
4388 const quint16 *src1 = (quint16*)data->texture.scanLine(y1);
4389 const quint16 *src2 = (quint16*)data->texture.scanLine(y2);
4390 quint16 tl = src1[x1];
4391 const quint16 tr = src1[x2];
4392 quint16 bl = src2[x1];
4393 const quint16 br = src2[x2];
4395 const uint distxsl8 = x & 0xff00;
4396 const uint distysl8 = y & 0xff00;
4397 const uint distx = distxsl8 >> 8;
4398 const uint disty = distysl8 >> 8;
4399 const uint distxy = distx * disty;
4401 const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty)
4402 const uint trw = distxsl8 - distxy; // distx * (256 - disty)
4403 const uint blw = distysl8 - distxy; // (256 - distx) * disty
4404 const uint brw = distxy; // distx * disty
4405 uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw
4406 + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000;
4407 uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw
4408 + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000;
4409 uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw
4410 + (bl & 0x001f) * blw + (br & 0x001f) * brw);
4411 *b = quint16((red | green | blue) >> 16);
4419 blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
4427 const qreal fdx = data->m11;
4428 const qreal fdy = data->m12;
4429 const qreal fdw = data->m13;
4432 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4433 const quint8 alpha = (coverage + 1) >> 3;
4434 const quint8 ialpha = 0x20 - alpha;
4440 quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4442 const qreal cx = spans->x + qreal(0.5);
4443 const qreal cy = spans->y + qreal(0.5);
4445 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
4446 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
4447 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
4449 int length = spans->len;
4457 l = qMin(length, buffer_size);
4460 const quint16 *end = b + l;
4463 const qreal iw = w == 0 ? 1 : 1 / w;
4464 const qreal px = x * iw - qreal(0.5);
4465 const qreal py = y * iw - qreal(0.5);
4467 int x1 = int(px) - (px < 0);
4469 int y1 = int(py) - (py < 0);
4472 fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2);
4473 fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2);
4475 const quint16 *src1 = (quint16 *)data->texture.scanLine(y1);
4476 const quint16 *src2 = (quint16 *)data->texture.scanLine(y2);
4477 quint16 tl = src1[x1];
4478 const quint16 tr = src1[x2];
4479 quint16 bl = src2[x1];
4480 const quint16 br = src2[x2];
4482 const uint distx = uint((px - x1) * 256);
4483 const uint disty = uint((py - y1) * 256);
4484 const uint distxsl8 = distx << 8;
4485 const uint distysl8 = disty << 8;
4486 const uint distxy = distx * disty;
4488 const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty)
4489 const uint trw = distxsl8 - distxy; // distx * (256 - disty)
4490 const uint blw = distysl8 - distxy; // (256 - distx) * disty
4491 const uint brw = distxy; // distx * disty
4492 uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw
4493 + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000;
4494 uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw
4495 + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000;
4496 uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw
4497 + (bl & 0x001f) * blw + (br & 0x001f) * brw);
4498 *b = quint16((red | green | blue) >> 16);
4507 blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
4517 static void blend_transformed_argb(int count, const QSpan *spans, void *userData)
4519 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4520 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
4521 && data->texture.format != QImage::Format_RGB32) {
4522 blend_src_generic(count, spans, userData);
4526 CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
4527 uint buffer[buffer_size];
4529 int image_width = data->texture.width;
4530 int image_height = data->texture.height;
4532 if (data->fast_matrix) {
4533 // The increment pr x in the scanline
4534 int fdx = (int)(data->m11 * fixed_scale);
4535 int fdy = (int)(data->m12 * fixed_scale);
4538 void *t = data->rasterBuffer->scanLine(spans->y);
4540 uint *target = ((uint *)t) + spans->x;
4542 const qreal cx = spans->x + qreal(0.5);
4543 const qreal cy = spans->y + qreal(0.5);
4545 int x = int((data->m21 * cy
4546 + data->m11 * cx + data->dx) * fixed_scale);
4547 int y = int((data->m22 * cy
4548 + data->m12 * cx + data->dy) * fixed_scale);
4550 int length = spans->len;
4551 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4553 int l = qMin(length, buffer_size);
4554 const uint *end = buffer + l;
4557 int px = qBound(0, x >> 16, image_width - 1);
4558 int py = qBound(0, y >> 16, image_height - 1);
4559 *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
4565 func(target, buffer, l, coverage);
4572 const qreal fdx = data->m11;
4573 const qreal fdy = data->m12;
4574 const qreal fdw = data->m13;
4576 void *t = data->rasterBuffer->scanLine(spans->y);
4578 uint *target = ((uint *)t) + spans->x;
4580 const qreal cx = spans->x + qreal(0.5);
4581 const qreal cy = spans->y + qreal(0.5);
4583 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
4584 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
4585 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
4587 int length = spans->len;
4588 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4590 int l = qMin(length, buffer_size);
4591 const uint *end = buffer + l;
4594 const qreal iw = w == 0 ? 1 : 1 / w;
4595 const qreal tx = x * iw;
4596 const qreal ty = y * iw;
4597 const int px = qBound(0, int(tx) - (tx < 0), image_width - 1);
4598 const int py = qBound(0, int(ty) - (ty < 0), image_height - 1);
4600 *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
4607 func(target, buffer, l, coverage);
4616 static void blend_transformed_rgb565(int count, const QSpan *spans, void *userData)
4618 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4619 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4621 if (data->texture.format != QImage::Format_RGB16
4622 || (mode != QPainter::CompositionMode_SourceOver
4623 && mode != QPainter::CompositionMode_Source))
4625 blend_src_generic(count, spans, userData);
4629 quint16 buffer[buffer_size];
4630 const int image_width = data->texture.width;
4631 const int image_height = data->texture.height;
4633 if (data->fast_matrix) {
4634 // The increment pr x in the scanline
4635 const int fdx = (int)(data->m11 * fixed_scale);
4636 const int fdy = (int)(data->m12 * fixed_scale);
4639 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4640 const quint8 alpha = (coverage + 1) >> 3;
4641 const quint8 ialpha = 0x20 - alpha;
4647 quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4648 const qreal cx = spans->x + qreal(0.5);
4649 const qreal cy = spans->y + qreal(0.5);
4650 int x = int((data->m21 * cy
4651 + data->m11 * cx + data->dx) * fixed_scale);
4652 int y = int((data->m22 * cy
4653 + data->m12 * cx + data->dy) * fixed_scale);
4654 int length = spans->len;
4663 l = qMin(length, buffer_size);
4666 const quint16 *end = b + l;
4669 const int px = qBound(0, x >> 16, image_width - 1);
4670 const int py = qBound(0, y >> 16, image_height - 1);
4672 *b = ((quint16 *)data->texture.scanLine(py))[px];
4680 blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
4688 const qreal fdx = data->m11;
4689 const qreal fdy = data->m12;
4690 const qreal fdw = data->m13;
4693 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4694 const quint8 alpha = (coverage + 1) >> 3;
4695 const quint8 ialpha = 0x20 - alpha;
4701 quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4703 const qreal cx = spans->x + qreal(0.5);
4704 const qreal cy = spans->y + qreal(0.5);
4706 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
4707 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
4708 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
4710 int length = spans->len;
4718 l = qMin(length, buffer_size);
4721 const quint16 *end = b + l;
4724 const qreal iw = w == 0 ? 1 : 1 / w;
4725 const qreal tx = x * iw;
4726 const qreal ty = y * iw;
4728 const int px = qBound(0, int(tx) - (tx < 0), image_width - 1);
4729 const int py = qBound(0, int(ty) - (ty < 0), image_height - 1);
4731 *b = ((quint16 *)data->texture.scanLine(py))[px];
4740 blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
4750 static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *userData)
4752 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4753 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
4754 && data->texture.format != QImage::Format_RGB32) {
4755 blend_src_generic(count, spans, userData);
4759 CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
4760 uint buffer[buffer_size];
4762 int image_width = data->texture.width;
4763 int image_height = data->texture.height;
4764 const int scanline_offset = data->texture.bytesPerLine / 4;
4766 if (data->fast_matrix) {
4767 // The increment pr x in the scanline
4768 int fdx = (int)(data->m11 * fixed_scale);
4769 int fdy = (int)(data->m12 * fixed_scale);
4772 void *t = data->rasterBuffer->scanLine(spans->y);
4774 uint *target = ((uint *)t) + spans->x;
4775 uint *image_bits = (uint *)data->texture.imageData;
4777 const qreal cx = spans->x + qreal(0.5);
4778 const qreal cy = spans->y + qreal(0.5);
4780 int x = int((data->m21 * cy
4781 + data->m11 * cx + data->dx) * fixed_scale);
4782 int y = int((data->m22 * cy
4783 + data->m12 * cx + data->dy) * fixed_scale);
4785 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4786 int length = spans->len;
4788 int l = qMin(length, buffer_size);
4789 const uint *end = buffer + l;
4796 if (px < 0) px += image_width;
4797 if (py < 0) py += image_height;
4798 int y_offset = py * scanline_offset;
4800 Q_ASSERT(px >= 0 && px < image_width);
4801 Q_ASSERT(py >= 0 && py < image_height);
4803 *b = image_bits[y_offset + px];
4808 func(target, buffer, l, coverage);
4815 const qreal fdx = data->m11;
4816 const qreal fdy = data->m12;
4817 const qreal fdw = data->m13;
4819 void *t = data->rasterBuffer->scanLine(spans->y);
4821 uint *target = ((uint *)t) + spans->x;
4822 uint *image_bits = (uint *)data->texture.imageData;
4824 const qreal cx = spans->x + qreal(0.5);
4825 const qreal cy = spans->y + qreal(0.5);
4827 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
4828 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
4829 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
4831 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
4832 int length = spans->len;
4834 int l = qMin(length, buffer_size);
4835 const uint *end = buffer + l;
4838 const qreal iw = w == 0 ? 1 : 1 / w;
4839 const qreal tx = x * iw;
4840 const qreal ty = y * iw;
4841 int px = int(tx) - (tx < 0);
4842 int py = int(ty) - (ty < 0);
4846 if (px < 0) px += image_width;
4847 if (py < 0) py += image_height;
4848 int y_offset = py * scanline_offset;
4850 Q_ASSERT(px >= 0 && px < image_width);
4851 Q_ASSERT(py >= 0 && py < image_height);
4853 *b = image_bits[y_offset + px];
4857 //force increment to avoid /0
4863 func(target, buffer, l, coverage);
4872 static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void *userData)
4874 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4875 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4877 if (data->texture.format != QImage::Format_RGB16
4878 || (mode != QPainter::CompositionMode_SourceOver
4879 && mode != QPainter::CompositionMode_Source))
4881 blend_src_generic(count, spans, userData);
4885 quint16 buffer[buffer_size];
4886 const int image_width = data->texture.width;
4887 const int image_height = data->texture.height;
4889 if (data->fast_matrix) {
4890 // The increment pr x in the scanline
4891 const int fdx = (int)(data->m11 * fixed_scale);
4892 const int fdy = (int)(data->m12 * fixed_scale);
4895 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4896 const quint8 alpha = (coverage + 1) >> 3;
4897 const quint8 ialpha = 0x20 - alpha;
4903 quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4904 const qreal cx = spans->x + qreal(0.5);
4905 const qreal cy = spans->y + qreal(0.5);
4906 int x = int((data->m21 * cy
4907 + data->m11 * cx + data->dx) * fixed_scale);
4908 int y = int((data->m22 * cy
4909 + data->m12 * cx + data->dy) * fixed_scale);
4910 int length = spans->len;
4919 l = qMin(length, buffer_size);
4922 const quint16 *end = b + l;
4925 int px = (x >> 16) % image_width;
4926 int py = (y >> 16) % image_height;
4933 *b = ((quint16 *)data->texture.scanLine(py))[px];
4941 blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
4949 const qreal fdx = data->m11;
4950 const qreal fdy = data->m12;
4951 const qreal fdw = data->m13;
4954 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4955 const quint8 alpha = (coverage + 1) >> 3;
4956 const quint8 ialpha = 0x20 - alpha;
4962 quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
4964 const qreal cx = spans->x + qreal(0.5);
4965 const qreal cy = spans->y + qreal(0.5);
4967 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
4968 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
4969 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
4971 int length = spans->len;
4979 l = qMin(length, buffer_size);
4982 const quint16 *end = b + l;
4985 const qreal iw = w == 0 ? 1 : 1 / w;
4986 const qreal tx = x * iw;
4987 const qreal ty = y * iw;
4989 int px = int(tx) - (tx < 0);
4990 int py = int(ty) - (ty < 0);
4999 *b = ((quint16 *)data->texture.scanLine(py))[px];
5005 // force increment to avoid /0
5011 blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
5022 /* Image formats here are target formats */
5023 static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats] = {
5027 blend_untransformed_generic, // Mono
5028 blend_untransformed_generic, // MonoLsb
5029 blend_untransformed_generic, // Indexed8
5030 blend_untransformed_generic, // RGB32
5031 blend_untransformed_generic, // ARGB32
5032 blend_untransformed_argb, // ARGB32_Premultiplied
5033 blend_untransformed_rgb565,
5034 blend_untransformed_generic,
5035 blend_untransformed_generic,
5036 blend_untransformed_generic,
5037 blend_untransformed_generic,
5038 blend_untransformed_generic,
5039 blend_untransformed_generic,
5040 blend_untransformed_generic,
5041 blend_untransformed_generic,
5046 blend_tiled_generic, // Mono
5047 blend_tiled_generic, // MonoLsb
5048 blend_tiled_generic, // Indexed8
5049 blend_tiled_generic, // RGB32
5050 blend_tiled_generic, // ARGB32
5051 blend_tiled_argb, // ARGB32_Premultiplied
5053 blend_tiled_generic,
5054 blend_tiled_generic,
5055 blend_tiled_generic,
5056 blend_tiled_generic,
5057 blend_tiled_generic,
5058 blend_tiled_generic,
5059 blend_tiled_generic,
5060 blend_tiled_generic,
5065 blend_src_generic, // Mono
5066 blend_src_generic, // MonoLsb
5067 blend_src_generic, // Indexed8
5068 blend_src_generic, // RGB32
5069 blend_src_generic, // ARGB32
5070 blend_transformed_argb, // ARGB32_Premultiplied
5071 blend_transformed_rgb565,
5084 blend_src_generic, // Mono
5085 blend_src_generic, // MonoLsb
5086 blend_src_generic, // Indexed8
5087 blend_src_generic, // RGB32
5088 blend_src_generic, // ARGB32
5089 blend_transformed_tiled_argb, // ARGB32_Premultiplied
5090 blend_transformed_tiled_rgb565,
5103 blend_src_generic, // Mono
5104 blend_src_generic, // MonoLsb
5105 blend_src_generic, // Indexed8
5106 blend_src_generic, // RGB32
5107 blend_src_generic, // ARGB32
5108 blend_src_generic, // ARGB32_Premultiplied
5109 blend_transformed_bilinear_rgb565,
5122 blend_src_generic, // Mono
5123 blend_src_generic, // MonoLsb
5124 blend_src_generic, // Indexed8
5125 blend_src_generic, // RGB32
5126 blend_src_generic, // ARGB32
5127 blend_src_generic, // ARGB32_Premultiplied
5128 blend_src_generic, // RGB16
5129 blend_src_generic, // ARGB8565_Premultiplied
5130 blend_src_generic, // RGB666
5131 blend_src_generic, // ARGB6666_Premultiplied
5132 blend_src_generic, // RGB555
5133 blend_src_generic, // ARGB8555_Premultiplied
5134 blend_src_generic, // RGB888
5135 blend_src_generic, // RGB444
5136 blend_src_generic, // ARGB4444_Premultiplied
5140 void qBlendTexture(int count, const QSpan *spans, void *userData)
5142 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5143 ProcessSpans proc = processTextureSpans[getBlendType(data)][data->rasterBuffer->format];
5144 proc(count, spans, userData);
5147 template <class DST>
5148 inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
5149 int x, int y, DST color,
5151 int mapWidth, int mapHeight, int mapStride)
5153 DST *dest = reinterpret_cast<DST *>(rasterBuffer->scanLine(y)) + x;
5154 const int destStride = rasterBuffer->bytesPerLine() / sizeof(DST);
5157 while (mapHeight--) {
5160 for (int x = 0; x < mapWidth; x += 8) {
5161 uchar s = map[x >> 3];
5162 for (int i = 0; i < 8; ++i) {
5167 qt_memfill(dest + x0, color, n);
5182 qt_memfill(dest + x0, color, n);
5187 while (mapHeight--) {
5190 for (uchar s = *map; s; s <<= 1) {
5194 qt_memfill(dest + x0, color, n);
5202 qt_memfill(dest + x0, color, n);
5209 static void qt_gradient_quint32(int count, const QSpan *spans, void *userData)
5211 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5213 bool isVerticalGradient =
5214 data->txop <= QTransform::TxScale &&
5215 data->type == QSpanData::LinearGradient &&
5216 data->gradient.linear.end.x == data->gradient.linear.origin.x;
5218 if (isVerticalGradient) {
5219 LinearGradientValues linear;
5220 getLinearGradientValues(&linear, data);
5222 CompositionFunctionSolid funcSolid =
5223 functionForModeSolid[data->rasterBuffer->compositionMode];
5226 The logic for vertical gradient calculations is a mathematically
5227 reduced copy of that in fetchLinearGradient() - which is basically:
5229 qreal ry = data->m22 * (y + 0.5) + data->dy;
5230 qreal t = linear.dy*ry + linear.off;
5231 t *= (GRADIENT_STOPTABLE_SIZE - 1);
5233 qt_gradient_pixel_fixed(&data->gradient,
5234 int(t * FIXPT_SIZE));
5236 This has then been converted to fixed point to improve performance.
5238 const int gss = GRADIENT_STOPTABLE_SIZE - 1;
5239 int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
5240 int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
5246 quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x;
5248 qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
5250 funcSolid(dst, spans->len, color, spans->coverage);
5255 blend_src_generic(count, spans, userData);
5259 static void qt_gradient_quint16(int count, const QSpan *spans, void *userData)
5261 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5263 bool isVerticalGradient =
5264 data->txop <= QTransform::TxScale &&
5265 data->type == QSpanData::LinearGradient &&
5266 data->gradient.linear.end.x == data->gradient.linear.origin.x;
5268 if (isVerticalGradient) {
5270 LinearGradientValues linear;
5271 getLinearGradientValues(&linear, data);
5274 The logic for vertical gradient calculations is a mathematically
5275 reduced copy of that in fetchLinearGradient() - which is basically:
5277 qreal ry = data->m22 * (y + 0.5) + data->dy;
5278 qreal t = linear.dy*ry + linear.off;
5279 t *= (GRADIENT_STOPTABLE_SIZE - 1);
5281 qt_gradient_pixel_fixed(&data->gradient,
5282 int(t * FIXPT_SIZE));
5284 This has then been converted to fixed point to improve performance.
5286 const int gss = GRADIENT_STOPTABLE_SIZE - 1;
5287 int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
5288 int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
5290 uint oldColor = data->solid.color;
5294 quint32 color = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
5296 data->solid.color = color;
5297 blend_color_rgb16(1, spans, userData);
5300 data->solid.color = oldColor;
5303 blend_src_generic(count, spans, userData);
5307 inline static void qt_bitmapblit_quint32(QRasterBuffer *rasterBuffer,
5308 int x, int y, quint32 color,
5310 int mapWidth, int mapHeight, int mapStride)
5312 qt_bitmapblit_template<quint32>(rasterBuffer, x, y, color,
5313 map, mapWidth, mapHeight, mapStride);
5316 inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
5317 int x, int y, quint32 color,
5319 int mapWidth, int mapHeight, int mapStride)
5321 qt_bitmapblit_template<quint16>(rasterBuffer, x, y, qConvertRgb32To16(color),
5322 map, mapWidth, mapHeight, mapStride);
5325 static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
5326 int x, int y, quint32 color,
5328 int mapWidth, int mapHeight, int mapStride,
5331 const quint16 c = qConvertRgb32To16(color);
5332 quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
5333 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
5335 while (mapHeight--) {
5336 for (int i = 0; i < mapWidth; ++i) {
5337 const int coverage = map[i];
5339 if (coverage == 0) {
5341 } else if (coverage == 255) {
5344 int ialpha = 255 - coverage;
5345 dest[i] = BYTE_MUL_RGB16(c, coverage)
5346 + BYTE_MUL_RGB16(dest[i], ialpha);
5354 static inline void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb, const uchar *gamma, const uchar *invgamma)
5356 // Do a gray alphablend...
5357 int da = qAlpha(*dst);
5358 int dr = qRed(*dst);
5359 int dg = qGreen(*dst);
5360 int db = qBlue(*dst);
5365 int a = qGray(coverage);
5366 sr = qt_div_255(invgamma[sr] * a);
5367 sg = qt_div_255(invgamma[sg] * a);
5368 sb = qt_div_255(invgamma[sb] * a);
5371 dr = qt_div_255(dr * ia);
5372 dg = qt_div_255(dg * ia);
5373 db = qt_div_255(db * ia);
5375 *dst = ((a + qt_div_255((255 - a) * da)) << 24)
5382 int mr = qRed(coverage);
5383 int mg = qGreen(coverage);
5384 int mb = qBlue(coverage);
5390 int nr = qt_div_255((sr - dr) * mr) + dr;
5391 int ng = qt_div_255((sg - dg) * mg) + dg;
5392 int nb = qt_div_255((sb - db) * mb) + db;
5398 *dst = qRgb(nr, ng, nb);
5401 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
5402 static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb, const uint *gamma, const uchar *invgamma)
5404 // Do a gammacorrected gray alphablend...
5405 int dr = qRed(*dst);
5406 int dg = qGreen(*dst);
5407 int db = qBlue(*dst);
5413 int alpha = coverage;
5414 int ialpha = 255 - alpha;
5415 int nr = (sr * alpha + ialpha * dr) / 255;
5416 int ng = (sg * alpha + ialpha * dg) / 255;
5417 int nb = (sb * alpha + ialpha * db) / 255;
5423 *dst = qRgb(nr, ng, nb);
5427 static void qt_alphamapblit_quint32(QRasterBuffer *rasterBuffer,
5428 int x, int y, quint32 color,
5430 int mapWidth, int mapHeight, int mapStride,
5431 const QClipData *clip)
5433 const quint32 c = color;
5434 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
5436 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
5437 const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables();
5441 const uint *gamma = tables->qt_pow_gamma;
5442 const uchar *invgamma = tables->qt_pow_invgamma;
5444 int sr = gamma[qRed(color)];
5445 int sg = gamma[qGreen(color)];
5446 int sb = gamma[qBlue(color)];
5448 bool opaque_src = (qAlpha(color) == 255);
5452 quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
5453 while (mapHeight--) {
5454 for (int i = 0; i < mapWidth; ++i) {
5455 const int coverage = map[i];
5457 if (coverage == 0) {
5459 } else if (coverage == 255) {
5462 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
5463 if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
5464 && qAlpha(dest[i]) == 255) {
5465 grayBlendPixel(dest+i, coverage, sr, sg, sb, gamma, invgamma);
5469 int ialpha = 255 - coverage;
5470 dest[i] = INTERPOLATE_PIXEL_255(c, coverage, dest[i], ialpha);
5478 int bottom = qMin(y + mapHeight, rasterBuffer->height());
5480 int top = qMax(y, 0);
5481 map += (top - y) * mapStride;
5483 const_cast<QClipData *>(clip)->initialize();
5484 for (int yp = top; yp<bottom; ++yp) {
5485 const QClipData::ClipLine &line = clip->m_clipLines[yp];
5487 quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
5489 for (int i=0; i<line.count; ++i) {
5490 const QSpan &clip = line.spans[i];
5492 int start = qMax<int>(x, clip.x);
5493 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5495 for (int xp=start; xp<end; ++xp) {
5496 const int coverage = map[xp - x];
5498 if (coverage == 0) {
5500 } else if (coverage == 255) {
5503 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
5504 if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
5505 && qAlpha(dest[xp]) == 255) {
5506 grayBlendPixel(dest+xp, coverage, sr, sg, sb, gamma, invgamma);
5510 int ialpha = 255 - coverage;
5511 dest[xp] = INTERPOLATE_PIXEL_255(c, coverage, dest[xp], ialpha);
5515 } // for (i -> line.count)
5516 } // for (yp -> bottom)
5522 static void qt_alphargbblit_quint32(QRasterBuffer *rasterBuffer,
5523 int x, int y, quint32 color,
5524 const uint *src, int mapWidth, int mapHeight, int srcStride,
5525 const QClipData *clip)
5527 const quint32 c = color;
5529 int sr = qRed(color);
5530 int sg = qGreen(color);
5531 int sb = qBlue(color);
5532 int sa = qAlpha(color);
5534 const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables();
5538 const uchar *gamma = tables->qt_pow_rgb_gamma;
5539 const uchar *invgamma = tables->qt_pow_rgb_invgamma;
5549 quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
5550 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
5551 while (mapHeight--) {
5552 for (int i = 0; i < mapWidth; ++i) {
5553 const uint coverage = src[i];
5554 if (coverage == 0xffffffff) {
5556 } else if (coverage != 0xff000000) {
5557 rgbBlendPixel(dst+i, coverage, sr, sg, sb, gamma, invgamma);
5565 int bottom = qMin(y + mapHeight, rasterBuffer->height());
5567 int top = qMax(y, 0);
5568 src += (top - y) * srcStride;
5570 const_cast<QClipData *>(clip)->initialize();
5571 for (int yp = top; yp<bottom; ++yp) {
5572 const QClipData::ClipLine &line = clip->m_clipLines[yp];
5574 quint32 *dst = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
5576 for (int i=0; i<line.count; ++i) {
5577 const QSpan &clip = line.spans[i];
5579 int start = qMax<int>(x, clip.x);
5580 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
5582 for (int xp=start; xp<end; ++xp) {
5583 const uint coverage = src[xp - x];
5584 if (coverage == 0xffffffff) {
5586 } else if (coverage != 0xff000000) {
5587 rgbBlendPixel(dst+xp, coverage, sr, sg, sb, gamma, invgamma);
5590 } // for (i -> line.count)
5592 } // for (yp -> bottom)
5597 static void qt_rectfill_quint32(QRasterBuffer *rasterBuffer,
5598 int x, int y, int width, int height,
5601 qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
5602 color, x, y, width, height, rasterBuffer->bytesPerLine());
5605 static void qt_rectfill_quint16(QRasterBuffer *rasterBuffer,
5606 int x, int y, int width, int height,
5609 qt_rectfill<quint16>(reinterpret_cast<quint16 *>(rasterBuffer->buffer()),
5610 qConvertRgb32To16(color), x, y, width, height, rasterBuffer->bytesPerLine());
5613 static void qt_rectfill_nonpremul_quint32(QRasterBuffer *rasterBuffer,
5614 int x, int y, int width, int height,
5617 qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
5618 INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine());
5622 // Map table for destination image format. Contains function pointers
5623 // for blends of various types unto the destination
5625 DrawHelper qDrawHelper[QImage::NImageFormats] =
5628 { 0, 0, 0, 0, 0, 0 },
5631 blend_color_generic,
5637 blend_color_generic,
5643 blend_color_generic,
5650 qt_gradient_quint32,
5651 qt_bitmapblit_quint32,
5652 qt_alphamapblit_quint32,
5653 qt_alphargbblit_quint32,
5658 blend_color_generic,
5659 qt_gradient_quint32,
5660 qt_bitmapblit_quint32,
5661 qt_alphamapblit_quint32,
5662 qt_alphargbblit_quint32,
5663 qt_rectfill_nonpremul_quint32
5665 // Format_ARGB32_Premultiplied
5668 qt_gradient_quint32,
5669 qt_bitmapblit_quint32,
5670 qt_alphamapblit_quint32,
5671 qt_alphargbblit_quint32,
5677 qt_gradient_quint16,
5678 qt_bitmapblit_quint16,
5679 qt_alphamapblit_quint16,
5683 // Format_ARGB8565_Premultiplied
5685 blend_color_generic,
5691 blend_color_generic,
5695 // Format_ARGB6666_Premultiplied
5697 blend_color_generic,
5703 blend_color_generic,
5707 // Format_ARGB8555_Premultiplied
5709 blend_color_generic,
5715 blend_color_generic,
5721 blend_color_generic,
5725 // Format_ARGB4444_Premultiplied
5727 blend_color_generic,
5733 #if defined(Q_CC_MSVC) && !defined(_MIPS_)
5735 inline void qt_memfill_template(T *dest, T color, int count)
5744 inline void qt_memfill_template(T *dest, T color, int count)
5746 int n = (count + 7) / 8;
5747 switch (count & 0x07)
5749 case 0: do { *dest++ = color;
5750 case 7: *dest++ = color;
5751 case 6: *dest++ = color;
5752 case 5: *dest++ = color;
5753 case 4: *dest++ = color;
5754 case 3: *dest++ = color;
5755 case 2: *dest++ = color;
5756 case 1: *dest++ = color;
5762 inline void qt_memfill_template(quint16 *dest, quint16 value, int count)
5766 case 2: *dest++ = value;
5767 case 1: *dest = value;
5772 const int align = (quintptr)(dest) & 0x3;
5774 case 2: *dest++ = value; --count;
5777 const quint32 value32 = (value << 16) | value;
5778 qt_memfill(reinterpret_cast<quint32*>(dest), value32, count / 2);
5780 dest[count - 1] = value;
5784 static void qt_memfill_quint16(quint16 *dest, quint16 color, int count)
5786 qt_memfill_template<quint16>(dest, color, count);
5789 typedef void (*qt_memfill32_func)(quint32 *dest, quint32 value, int count);
5790 typedef void (*qt_memfill16_func)(quint16 *dest, quint16 value, int count);
5791 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count);
5792 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count);
5794 qt_memfill32_func qt_memfill32 = qt_memfill32_setup;
5795 qt_memfill16_func qt_memfill16 = qt_memfill16_setup;
5797 void qInitDrawhelperAsm()
5800 qt_memfill32 = qt_memfill_template<quint32>;
5801 qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16>;
5803 CompositionFunction *functionForModeAsm = 0;
5804 CompositionFunctionSolid *functionForModeSolidAsm = 0;
5806 const uint features = qDetectCPUFeatures();
5808 #ifdef QT_COMPILER_SUPPORTS_AVX
5809 } else if (features & AVX) {
5810 qt_memfill32 = qt_memfill32_avx;
5811 qt_memfill16 = qt_memfill16_avx;
5812 qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_avx;
5813 qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_avx;
5814 qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_avx;
5815 qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_avx;
5817 extern void qt_scale_image_argb32_on_argb32_avx(uchar *destPixels, int dbpl,
5818 const uchar *srcPixels, int sbpl,
5819 const QRectF &targetRect,
5820 const QRectF &sourceRect,
5823 qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_avx;
5824 qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_avx;
5826 #ifdef QT_COMPILER_SUPPORTS_SSE2
5827 } else if (features & SSE2) {
5828 qt_memfill32 = qt_memfill32_sse2;
5829 qt_memfill16 = qt_memfill16_sse2;
5830 qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2;
5831 qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2;
5832 qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2;
5833 qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2;
5835 extern void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
5836 const uchar *srcPixels, int sbpl,
5837 const QRectF &targetRect,
5838 const QRectF &sourceRect,
5841 qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
5842 qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2;
5846 #ifdef QT_COMPILER_SUPPORTS_SSE2
5847 if (features & SSE2) {
5848 extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
5849 const uchar *srcPixels, int sbpl,
5852 extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
5853 const uchar *srcPixels, int sbpl,
5857 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
5858 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
5859 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
5860 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
5862 extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
5863 int y, int x, int length);
5865 qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2;
5868 #ifdef QT_COMPILER_SUPPORTS_SSSE3
5869 if (features & SSSE3) {
5870 extern void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
5871 const uchar *srcPixels, int sbpl,
5875 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
5876 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
5880 #ifdef QT_COMPILER_SUPPORTS_AVX
5881 if (features & AVX) {
5882 extern void qt_blend_rgb32_on_rgb32_avx(uchar *destPixels, int dbpl,
5883 const uchar *srcPixels, int sbpl,
5886 extern void qt_blend_argb32_on_argb32_avx(uchar *destPixels, int dbpl,
5887 const uchar *srcPixels, int sbpl,
5891 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx;
5892 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx;
5893 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx;
5894 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx;
5896 extern const uint * QT_FASTCALL qt_fetch_radial_gradient_avx(uint *buffer, const Operator *op, const QSpanData *data,
5897 int y, int x, int length);
5899 qt_fetch_radial_gradient = qt_fetch_radial_gradient_avx;
5905 #ifdef QT_COMPILER_SUPPORTS_SSE2
5906 if (features & SSE2) {
5907 functionForModeAsm = qt_functionForMode_SSE2;
5908 functionForModeSolidAsm = qt_functionForModeSolid_SSE2;
5911 #ifdef QT_COMPILER_SUPPORTS_AVX
5912 if (features & AVX) {
5913 extern void QT_FASTCALL comp_func_SourceOver_avx(uint *destPixels,
5914 const uint *srcPixels,
5917 extern void QT_FASTCALL comp_func_solid_SourceOver_avx(uint *destPixels, int length, uint color, uint const_alpha);
5918 extern void QT_FASTCALL comp_func_Plus_avx(uint *dst, const uint *src, int length, uint const_alpha);
5919 extern void QT_FASTCALL comp_func_Source_avx(uint *dst, const uint *src, int length, uint const_alpha);
5921 functionForModeAsm[0] = comp_func_SourceOver_avx;
5922 functionForModeAsm[QPainter::CompositionMode_Source] = comp_func_Source_avx;
5923 functionForModeAsm[QPainter::CompositionMode_Plus] = comp_func_Plus_avx;
5924 functionForModeSolidAsm[0] = comp_func_solid_SourceOver_avx;
5928 #ifdef QT_COMPILER_SUPPORTS_IWMMXT
5929 if (features & IWMMXT) {
5930 functionForModeAsm = qt_functionForMode_IWMMXT;
5931 functionForModeSolidAsm = qt_functionForModeSolid_IWMMXT;
5932 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_iwmmxt;
5936 #if defined(QT_COMPILER_SUPPORTS_NEON)
5937 if (features & NEON) {
5938 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
5939 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
5940 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
5941 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
5942 qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon;
5943 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon;
5944 qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon;
5946 qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon;
5947 qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon;
5949 qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon;
5950 qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon;
5952 qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon;
5954 functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon;
5955 functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon;
5956 functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon;
5957 destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
5958 destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
5960 qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
5961 qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
5962 qt_memfill32 = qt_memfill32_neon;
5964 extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data,
5965 int y, int x, int length);
5967 qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon;
5971 #if defined(QT_COMPILER_SUPPORTS_MIPS_DSP)
5972 functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_asm_mips_dsp;
5973 functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_mips_dsp;
5975 qt_memfill32 = qt_memfill32_asm_mips_dsp;
5977 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp;
5978 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp;
5979 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mips_dsp;
5980 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mips_dsp;
5982 destFetchProc[QImage::Format_ARGB32] = qt_destFetchARGB32_mips_dsp;
5984 destStoreProc[QImage::Format_ARGB32] = qt_destStoreARGB32_mips_dsp;
5986 #endif // QT_COMPILER_SUPPORTS_MIPS_DSP
5987 if (functionForModeSolidAsm) {
5988 const int destinationMode = QPainter::CompositionMode_Destination;
5989 functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode];
5991 // use the default qdrawhelper implementation for the
5992 // extended composition modes
5993 for (int mode = 12; mode < 24; ++mode)
5994 functionForModeSolidAsm[mode] = functionForModeSolid_C[mode];
5996 functionForModeSolid = functionForModeSolidAsm;
5998 if (functionForModeAsm)
5999 functionForMode = functionForModeAsm;
6002 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count)
6004 qInitDrawhelperAsm();
6005 qt_memfill32(dest, value, count);
6008 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count)
6010 qInitDrawhelperAsm();
6011 qt_memfill16(dest, value, count);