1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include <private/qdrawhelper_p.h>
43 #include <private/qpaintengine_raster_p.h>
44 #include <private/qpainter_p.h>
45 #include <private/qdrawhelper_x86_p.h>
46 #ifdef QT_HAVE_ARM_SIMD
47 #include <private/qdrawhelper_arm_simd_p.h>
49 #include <private/qdrawhelper_neon_p.h>
50 #include <private/qmath_p.h>
56 #define MASK(src, a) src = BYTE_MUL(src, a)
58 #if defined(Q_OS_IRIX) && defined(Q_CC_GNU) && __GNUC__ == 3 && __GNUC__ < 4 && QT_POINTER_SIZE == 8
59 #define Q_IRIX_GCC3_3_WORKAROUND
61 // work around http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14484
63 static uint gccBug(uint value) __attribute__((noinline));
64 static uint gccBug(uint value)
71 constants and structures
75 fixed_scale = 1 << 16,
78 static const int buffer_size = 2048;
80 struct LinearGradientValues
88 struct RadialGradientValues
96 typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
97 typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length);
98 typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
103 QPainter::CompositionMode mode;
104 DestFetchProc dest_fetch;
105 DestStoreProc dest_store;
106 SourceFetchProc src_fetch;
107 CompositionFunctionSolid funcSolid;
108 CompositionFunction func;
110 LinearGradientValues linear;
111 RadialGradientValues radial;
112 // TextureValues texture;
117 Destination fetch. This is simple as we don't have to do bounds checks or
121 static uint * QT_FASTCALL destFetchMono(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
123 uchar *data = (uchar *)rasterBuffer->scanLine(y);
124 uint *start = buffer;
125 const uint *end = buffer + length;
126 while (buffer < end) {
127 *buffer = data[x>>3] & (0x80 >> (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
134 static uint * QT_FASTCALL destFetchMonoLsb(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
136 uchar *data = (uchar *)rasterBuffer->scanLine(y);
137 uint *start = buffer;
138 const uint *end = buffer + length;
139 while (buffer < end) {
140 *buffer = data[x>>3] & (0x1 << (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
147 static uint * QT_FASTCALL destFetchARGB32(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
149 const uint *data = (const uint *)rasterBuffer->scanLine(y) + x;
150 for (int i = 0; i < length; ++i)
151 buffer[i] = PREMUL(data[i]);
155 static uint * QT_FASTCALL destFetchARGB32P(uint *, QRasterBuffer *rasterBuffer, int x, int y, int)
157 return (uint *)rasterBuffer->scanLine(y) + x;
160 static uint * QT_FASTCALL destFetchRGB16(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
162 const ushort *data = (const ushort *)rasterBuffer->scanLine(y) + x;
163 for (int i = 0; i < length; ++i)
164 buffer[i] = qConvertRgb16To32(data[i]);
169 Q_STATIC_TEMPLATE_FUNCTION uint * QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer,
170 int x, int y, int length)
172 const DST *src = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
173 quint32 *dest = reinterpret_cast<quint32*>(buffer);
179 # define SPANFUNC_POINTER_DESTFETCH(Arg) destFetch<Arg>
181 static DestFetchProc destFetchProc[QImage::NImageFormats] =
184 destFetchMono, // Format_Mono,
185 destFetchMonoLsb, // Format_MonoLSB
186 0, // Format_Indexed8
187 destFetchARGB32P, // Format_RGB32
188 destFetchARGB32, // Format_ARGB32,
189 destFetchARGB32P, // Format_ARGB32_Premultiplied
190 destFetchRGB16, // Format_RGB16
191 SPANFUNC_POINTER_DESTFETCH(qargb8565), // Format_ARGB8565_Premultiplied
192 SPANFUNC_POINTER_DESTFETCH(qrgb666), // Format_RGB666
193 SPANFUNC_POINTER_DESTFETCH(qargb6666), // Format_ARGB6666_Premultiplied
194 SPANFUNC_POINTER_DESTFETCH(qrgb555), // Format_RGB555
195 SPANFUNC_POINTER_DESTFETCH(qargb8555), // Format_ARGB8555_Premultiplied
196 SPANFUNC_POINTER_DESTFETCH(qrgb888), // Format_RGB888
197 SPANFUNC_POINTER_DESTFETCH(qrgb444), // Format_RGB444
198 SPANFUNC_POINTER_DESTFETCH(qargb4444) // Format_ARGB4444_Premultiplied
202 Returns the color in the mono destination color table
203 that is the "nearest" to /color/.
205 static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
207 QRgb color_0 = PREMUL(rbuf->destColor0);
208 QRgb color_1 = PREMUL(rbuf->destColor1);
209 color = PREMUL(color);
212 int g = qGreen(color);
213 int b = qBlue(color);
217 rx = r - qRed(color_0);
218 gx = g - qGreen(color_0);
219 bx = b - qBlue(color_0);
220 dist_0 = rx*rx + gx*gx + bx*bx;
222 rx = r - qRed(color_1);
223 gx = g - qGreen(color_1);
224 bx = b - qBlue(color_1);
225 dist_1 = rx*rx + gx*gx + bx*bx;
236 static void QT_FASTCALL destStoreMono(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
238 uchar *data = (uchar *)rasterBuffer->scanLine(y);
239 if (rasterBuffer->monoDestinationWithClut) {
240 for (int i = 0; i < length; ++i) {
241 if (buffer[i] == rasterBuffer->destColor0) {
242 data[x >> 3] &= ~(0x80 >> (x & 7));
243 } else if (buffer[i] == rasterBuffer->destColor1) {
244 data[x >> 3] |= 0x80 >> (x & 7);
245 } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
246 data[x >> 3] &= ~(0x80 >> (x & 7));
248 data[x >> 3] |= 0x80 >> (x & 7);
253 for (int i = 0; i < length; ++i) {
254 if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
255 data[x >> 3] |= 0x80 >> (x & 7);
257 data[x >> 3] &= ~(0x80 >> (x & 7));
263 static void QT_FASTCALL destStoreMonoLsb(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
265 uchar *data = (uchar *)rasterBuffer->scanLine(y);
266 if (rasterBuffer->monoDestinationWithClut) {
267 for (int i = 0; i < length; ++i) {
268 if (buffer[i] == rasterBuffer->destColor0) {
269 data[x >> 3] &= ~(1 << (x & 7));
270 } else if (buffer[i] == rasterBuffer->destColor1) {
271 data[x >> 3] |= 1 << (x & 7);
272 } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
273 data[x >> 3] &= ~(1 << (x & 7));
275 data[x >> 3] |= 1 << (x & 7);
280 for (int i = 0; i < length; ++i) {
281 if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
282 data[x >> 3] |= 1 << (x & 7);
284 data[x >> 3] &= ~(1 << (x & 7));
290 static void QT_FASTCALL destStoreARGB32(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
292 uint *data = (uint *)rasterBuffer->scanLine(y) + x;
293 for (int i = 0; i < length; ++i) {
295 int alpha = qAlpha(p);
301 int inv_alpha = 0xff0000/qAlpha(buffer[i]);
302 data[i] = (p & 0xff000000)
303 | ((qRed(p)*inv_alpha) & 0xff0000)
304 | (((qGreen(p)*inv_alpha) >> 8) & 0xff00)
305 | ((qBlue(p)*inv_alpha) >> 16);
310 static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
312 quint16 *data = (quint16*)rasterBuffer->scanLine(y) + x;
313 qt_memconvert<quint16, quint32>(data, buffer, length);
317 Q_STATIC_TEMPLATE_FUNCTION void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer,
319 const uint *buffer, int length)
321 DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
322 const quint32p *src = reinterpret_cast<const quint32p*>(buffer);
324 *dest++ = DST(*src++);
327 # define SPANFUNC_POINTER_DESTSTORE(DEST) destStore<DEST>
329 static DestStoreProc destStoreProc[QImage::NImageFormats] =
332 destStoreMono, // Format_Mono,
333 destStoreMonoLsb, // Format_MonoLSB
334 0, // Format_Indexed8
336 destStoreARGB32, // Format_ARGB32,
337 0, // Format_ARGB32_Premultiplied
338 destStoreRGB16, // Format_RGB16
339 SPANFUNC_POINTER_DESTSTORE(qargb8565), // Format_ARGB8565_Premultiplied
340 SPANFUNC_POINTER_DESTSTORE(qrgb666), // Format_RGB666
341 SPANFUNC_POINTER_DESTSTORE(qargb6666), // Format_ARGB6666_Premultiplied
342 SPANFUNC_POINTER_DESTSTORE(qrgb555), // Format_RGB555
343 SPANFUNC_POINTER_DESTSTORE(qargb8555), // Format_ARGB8555_Premultiplied
344 SPANFUNC_POINTER_DESTSTORE(qrgb888), // Format_RGB888
345 SPANFUNC_POINTER_DESTSTORE(qrgb444), // Format_RGB444
346 SPANFUNC_POINTER_DESTSTORE(qargb4444) // Format_ARGB4444_Premultiplied
352 This is a bit more complicated, as we need several fetch routines for every surface type
354 We need 5 fetch methods per surface type:
356 transformed (tiled and not tiled)
357 transformed bilinear (tiled and not tiled)
359 We don't need bounds checks for untransformed, but we need them for the other ones.
361 The generic implementation does pixel by pixel fetches
364 template <QImage::Format format>
365 Q_STATIC_TEMPLATE_FUNCTION uint QT_FASTCALL qt_fetchPixel(const uchar *scanLine, int x, const QVector<QRgb> *rgb);
368 Q_STATIC_TEMPLATE_SPECIALIZATION
369 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Mono>(const uchar *scanLine,
370 int x, const QVector<QRgb> *rgb)
372 bool pixel = scanLine[x>>3] & (0x80 >> (x & 7));
373 if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
374 return pixel ? 0xff000000 : 0xffffffff;
378 Q_STATIC_TEMPLATE_SPECIALIZATION
379 uint QT_FASTCALL qt_fetchPixel<QImage::Format_MonoLSB>(const uchar *scanLine,
380 int x, const QVector<QRgb> *rgb)
382 bool pixel = scanLine[x>>3] & (0x1 << (x & 7));
383 if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
384 return pixel ? 0xff000000 : 0xffffffff;
388 Q_STATIC_TEMPLATE_SPECIALIZATION
389 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Indexed8>(const uchar *scanLine,
390 int x, const QVector<QRgb> *rgb)
392 return PREMUL(rgb->at(scanLine[x]));
396 Q_STATIC_TEMPLATE_SPECIALIZATION
397 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32>(const uchar *scanLine,
398 int x, const QVector<QRgb> *)
400 return PREMUL(((const uint *)scanLine)[x]);
404 Q_STATIC_TEMPLATE_SPECIALIZATION
405 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32_Premultiplied>(const uchar *scanLine,
406 int x, const QVector<QRgb> *)
408 return ((const uint *)scanLine)[x];
412 Q_STATIC_TEMPLATE_SPECIALIZATION
413 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB16>(const uchar *scanLine,
414 int x, const QVector<QRgb> *)
416 return qConvertRgb16To32(((const ushort *)scanLine)[x]);
420 Q_STATIC_TEMPLATE_SPECIALIZATION
421 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8565_Premultiplied>(const uchar *scanLine,
423 const QVector<QRgb> *)
425 const qargb8565 color = reinterpret_cast<const qargb8565*>(scanLine)[x];
426 return qt_colorConvert<quint32, qargb8565>(color, 0);
430 Q_STATIC_TEMPLATE_SPECIALIZATION
431 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB666>(const uchar *scanLine,
433 const QVector<QRgb> *)
435 const qrgb666 color = reinterpret_cast<const qrgb666*>(scanLine)[x];
436 return qt_colorConvert<quint32, qrgb666>(color, 0);
440 Q_STATIC_TEMPLATE_SPECIALIZATION
441 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB6666_Premultiplied>(const uchar *scanLine,
443 const QVector<QRgb> *)
445 const qargb6666 color = reinterpret_cast<const qargb6666*>(scanLine)[x];
446 return qt_colorConvert<quint32, qargb6666>(color, 0);
450 Q_STATIC_TEMPLATE_SPECIALIZATION
451 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB555>(const uchar *scanLine,
453 const QVector<QRgb> *)
455 const qrgb555 color = reinterpret_cast<const qrgb555*>(scanLine)[x];
456 return qt_colorConvert<quint32, qrgb555>(color, 0);
460 Q_STATIC_TEMPLATE_SPECIALIZATION
461 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8555_Premultiplied>(const uchar *scanLine,
463 const QVector<QRgb> *)
465 const qargb8555 color = reinterpret_cast<const qargb8555*>(scanLine)[x];
466 return qt_colorConvert<quint32, qargb8555>(color, 0);
470 Q_STATIC_TEMPLATE_SPECIALIZATION
471 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB888>(const uchar *scanLine,
473 const QVector<QRgb> *)
475 const qrgb888 color = reinterpret_cast<const qrgb888*>(scanLine)[x];
476 return qt_colorConvert<quint32, qrgb888>(color, 0);
480 Q_STATIC_TEMPLATE_SPECIALIZATION
481 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB444>(const uchar *scanLine,
483 const QVector<QRgb> *)
485 const qrgb444 color = reinterpret_cast<const qrgb444*>(scanLine)[x];
486 return qt_colorConvert<quint32, qrgb444>(color, 0);
490 Q_STATIC_TEMPLATE_SPECIALIZATION
491 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB4444_Premultiplied>(const uchar *scanLine,
493 const QVector<QRgb> *)
495 const qargb4444 color = reinterpret_cast<const qargb4444*>(scanLine)[x];
496 return qt_colorConvert<quint32, qargb4444>(color, 0);
500 Q_STATIC_TEMPLATE_SPECIALIZATION
501 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Invalid>(const uchar *,
503 const QVector<QRgb> *)
508 typedef uint (QT_FASTCALL *FetchPixelProc)(const uchar *scanLine, int x, const QVector<QRgb> *);
510 #define SPANFUNC_POINTER_FETCHPIXEL(Arg) qt_fetchPixel<QImage::Arg>
513 static const FetchPixelProc fetchPixelProc[QImage::NImageFormats] =
516 SPANFUNC_POINTER_FETCHPIXEL(Format_Mono),
517 SPANFUNC_POINTER_FETCHPIXEL(Format_MonoLSB),
518 SPANFUNC_POINTER_FETCHPIXEL(Format_Indexed8),
519 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
520 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32),
521 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
522 SPANFUNC_POINTER_FETCHPIXEL(Format_RGB16),
523 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8565_Premultiplied),
524 SPANFUNC_POINTER_FETCHPIXEL(Format_RGB666),
525 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB6666_Premultiplied),
526 SPANFUNC_POINTER_FETCHPIXEL(Format_RGB555),
527 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8555_Premultiplied),
528 SPANFUNC_POINTER_FETCHPIXEL(Format_RGB888),
529 SPANFUNC_POINTER_FETCHPIXEL(Format_RGB444),
530 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB4444_Premultiplied)
533 enum TextureBlendType {
537 BlendTransformedTiled,
538 BlendTransformedBilinear,
539 BlendTransformedBilinearTiled,
543 template <QImage::Format format>
544 Q_STATIC_TEMPLATE_FUNCTION const uint * QT_FASTCALL qt_fetchUntransformed(uint *buffer, const Operator *, const QSpanData *data,
545 int y, int x, int length)
547 const uchar *scanLine = data->texture.scanLine(y);
548 for (int i = 0; i < length; ++i)
549 buffer[i] = qt_fetchPixel<format>(scanLine, x + i, data->texture.colorTable);
554 Q_STATIC_TEMPLATE_SPECIALIZATION const uint * QT_FASTCALL
555 qt_fetchUntransformed<QImage::Format_ARGB32_Premultiplied>(uint *, const Operator *,
556 const QSpanData *data,
559 const uchar *scanLine = data->texture.scanLine(y);
560 return ((const uint *)scanLine) + x;
563 template<TextureBlendType blendType> /* either BlendTransformed or BlendTransformedTiled */
564 Q_STATIC_TEMPLATE_FUNCTION
565 const uint * QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data,
566 int y, int x, int length)
568 FetchPixelProc fetch = fetchPixelProc[data->texture.format];
570 int image_width = data->texture.width;
571 int image_height = data->texture.height;
573 const qreal cx = x + qreal(0.5);
574 const qreal cy = y + qreal(0.5);
576 const uint *end = buffer + length;
578 if (data->fast_matrix) {
579 // The increment pr x in the scanline
580 int fdx = (int)(data->m11 * fixed_scale);
581 int fdy = (int)(data->m12 * fixed_scale);
583 int fx = int((data->m21 * cy
584 + data->m11 * cx + data->dx) * fixed_scale);
585 int fy = int((data->m22 * cy
586 + data->m12 * cx + data->dy) * fixed_scale);
592 if (blendType == BlendTransformedTiled) {
595 if (px < 0) px += image_width;
596 if (py < 0) py += image_height;
598 const uchar *scanLine = data->texture.scanLine(py);
599 *b = fetch(scanLine, px, data->texture.colorTable);
601 if ((px < 0) || (px >= image_width)
602 || (py < 0) || (py >= image_height)) {
605 const uchar *scanLine = data->texture.scanLine(py);
606 *b = fetch(scanLine, px, data->texture.colorTable);
614 const qreal fdx = data->m11;
615 const qreal fdy = data->m12;
616 const qreal fdw = data->m13;
618 qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
619 qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
620 qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
623 const qreal iw = fw == 0 ? 1 : 1 / fw;
624 const qreal tx = fx * iw;
625 const qreal ty = fy * iw;
626 int px = int(tx) - (tx < 0);
627 int py = int(ty) - (ty < 0);
629 if (blendType == BlendTransformedTiled) {
632 if (px < 0) px += image_width;
633 if (py < 0) py += image_height;
635 const uchar *scanLine = data->texture.scanLine(py);
636 *b = fetch(scanLine, px, data->texture.colorTable);
638 if ((px < 0) || (px >= image_width)
639 || (py < 0) || (py >= image_height)) {
642 const uchar *scanLine = data->texture.scanLine(py);
643 *b = fetch(scanLine, px, data->texture.colorTable);
649 //force increment to avoid /0
661 interpolate 4 argb pixels with the distx and disty factor.
662 distx and disty bust be between 0 and 16
664 static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, int distx, int disty)
666 uint distxy = distx * disty;
667 //idistx * disty = (16-distx) * disty = 16*disty - distxy
668 //idistx * idisty = (16-distx) * (16-disty) = 16*16 - 16*distx -16*dity + distxy
669 uint tlrb = (tl & 0x00ff00ff) * (16*16 - 16*distx - 16*disty + distxy);
670 uint tlag = ((tl & 0xff00ff00) >> 8) * (16*16 - 16*distx - 16*disty + distxy);
671 uint trrb = ((tr & 0x00ff00ff) * (distx*16 - distxy));
672 uint trag = (((tr & 0xff00ff00) >> 8) * (distx*16 - distxy));
673 uint blrb = ((bl & 0x00ff00ff) * (disty*16 - distxy));
674 uint blag = (((bl & 0xff00ff00) >> 8) * (disty*16 - distxy));
675 uint brrb = ((br & 0x00ff00ff) * (distxy));
676 uint brag = (((br & 0xff00ff00) >> 8) * (distxy));
677 return (((tlrb + trrb + blrb + brrb) >> 8) & 0x00ff00ff) | ((tlag + trag + blag + brag) & 0xff00ff00);
680 #if defined(QT_ALWAYS_HAVE_SSE2)
681 #define interpolate_4_pixels_16_sse2(tl, tr, bl, br, distx, disty, colorMask, v_256, b) \
683 const __m128i dxdy = _mm_mullo_epi16 (distx, disty); \
684 const __m128i distx_ = _mm_slli_epi16(distx, 4); \
685 const __m128i disty_ = _mm_slli_epi16(disty, 4); \
686 const __m128i idxidy = _mm_add_epi16(dxdy, _mm_sub_epi16(v_256, _mm_add_epi16(distx_, disty_))); \
687 const __m128i dxidy = _mm_sub_epi16(distx_, dxdy); \
688 const __m128i idxdy = _mm_sub_epi16(disty_, dxdy); \
690 __m128i tlAG = _mm_srli_epi16(tl, 8); \
691 __m128i tlRB = _mm_and_si128(tl, colorMask); \
692 __m128i trAG = _mm_srli_epi16(tr, 8); \
693 __m128i trRB = _mm_and_si128(tr, colorMask); \
694 __m128i blAG = _mm_srli_epi16(bl, 8); \
695 __m128i blRB = _mm_and_si128(bl, colorMask); \
696 __m128i brAG = _mm_srli_epi16(br, 8); \
697 __m128i brRB = _mm_and_si128(br, colorMask); \
699 tlAG = _mm_mullo_epi16(tlAG, idxidy); \
700 tlRB = _mm_mullo_epi16(tlRB, idxidy); \
701 trAG = _mm_mullo_epi16(trAG, dxidy); \
702 trRB = _mm_mullo_epi16(trRB, dxidy); \
703 blAG = _mm_mullo_epi16(blAG, idxdy); \
704 blRB = _mm_mullo_epi16(blRB, idxdy); \
705 brAG = _mm_mullo_epi16(brAG, dxdy); \
706 brRB = _mm_mullo_epi16(brRB, dxdy); \
708 /* Add the values, and shift to only keep 8 significant bits per colors */ \
709 __m128i rAG =_mm_add_epi16(_mm_add_epi16(tlAG, trAG), _mm_add_epi16(blAG, brAG)); \
710 __m128i rRB =_mm_add_epi16(_mm_add_epi16(tlRB, trRB), _mm_add_epi16(blRB, brRB)); \
711 rAG = _mm_andnot_si128(colorMask, rAG); \
712 rRB = _mm_srli_epi16(rRB, 8); \
713 _mm_storeu_si128((__m128i*)(b), _mm_or_si128(rAG, rRB)); \
717 #if defined(QT_ALWAYS_HAVE_NEON)
718 #define interpolate_4_pixels_16_neon(tl, tr, bl, br, distx, disty, disty_, colorMask, invColorMask, v_256, b) \
720 const int16x8_t dxdy = vmulq_s16(distx, disty); \
721 const int16x8_t distx_ = vshlq_n_s16(distx, 4); \
722 const int16x8_t idxidy = vaddq_s16(dxdy, vsubq_s16(v_256, vaddq_s16(distx_, disty_))); \
723 const int16x8_t dxidy = vsubq_s16(distx_, dxdy); \
724 const int16x8_t idxdy = vsubq_s16(disty_, dxdy); \
726 int16x8_t tlAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tl), 8)); \
727 int16x8_t tlRB = vandq_s16(tl, colorMask); \
728 int16x8_t trAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tr), 8)); \
729 int16x8_t trRB = vandq_s16(tr, colorMask); \
730 int16x8_t blAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bl), 8)); \
731 int16x8_t blRB = vandq_s16(bl, colorMask); \
732 int16x8_t brAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(br), 8)); \
733 int16x8_t brRB = vandq_s16(br, colorMask); \
735 int16x8_t rAG = vmulq_s16(tlAG, idxidy); \
736 int16x8_t rRB = vmulq_s16(tlRB, idxidy); \
737 rAG = vmlaq_s16(rAG, trAG, dxidy); \
738 rRB = vmlaq_s16(rRB, trRB, dxidy); \
739 rAG = vmlaq_s16(rAG, blAG, idxdy); \
740 rRB = vmlaq_s16(rRB, blRB, idxdy); \
741 rAG = vmlaq_s16(rAG, brAG, dxdy); \
742 rRB = vmlaq_s16(rRB, brRB, dxdy); \
744 rAG = vandq_s16(invColorMask, rAG); \
745 rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8)); \
746 vst1q_s16((int16_t*)(b), vorrq_s16(rAG, rRB)); \
750 template<TextureBlendType blendType>
751 Q_STATIC_TEMPLATE_FUNCTION inline void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2)
753 if (blendType == BlendTransformedBilinearTiled) {
755 if (v1 < 0) v1 += max;
761 } else if (v1 >= l2) {
768 Q_ASSERT(v1 >= 0 && v1 < max);
769 Q_ASSERT(v2 >= 0 && v2 < max);
772 template<TextureBlendType blendType, QImage::Format format> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
773 Q_STATIC_TEMPLATE_FUNCTION
774 const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *, const QSpanData *data,
775 int y, int x, int length)
777 #ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
778 FetchPixelProc fetch;
779 if (format != QImage::Format_Invalid)
780 fetch = qt_fetchPixel<format>;
782 fetch = fetchPixelProc[data->texture.format];
784 FetchPixelProc fetch = (format != QImage::Format_Invalid) ? FetchPixelProc(qt_fetchPixel<format>) : fetchPixelProc[data->texture.format];
787 int image_width = data->texture.width;
788 int image_height = data->texture.height;
790 int image_x1 = data->texture.x1;
791 int image_y1 = data->texture.y1;
792 int image_x2 = data->texture.x2 - 1;
793 int image_y2 = data->texture.y2 - 1;
795 const qreal cx = x + qreal(0.5);
796 const qreal cy = y + qreal(0.5);
798 uint *end = buffer + length;
800 if (data->fast_matrix) {
801 // The increment pr x in the scanline
802 int fdx = (int)(data->m11 * fixed_scale);
803 int fdy = (int)(data->m12 * fixed_scale);
805 int fx = int((data->m21 * cy
806 + data->m11 * cx + data->dx) * fixed_scale);
807 int fy = int((data->m22 * cy
808 + data->m12 * cx + data->dy) * fixed_scale);
813 if (fdy == 0) { //simple scale, no rotation
816 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
817 const uchar *s1 = data->texture.scanLine(y1);
818 const uchar *s2 = data->texture.scanLine(y2);
820 if (fdx <= fixed_scale && fdx > 0) { // scale up on X
821 int disty = (fy & 0x0000ffff) >> 8;
822 int idisty = 256 - disty;
825 // The idea is first to do the interpolation between the row s1 and the row s2
826 // into an intermediate buffer, then we interpolate between two pixel of this buffer.
828 // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
829 // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG
830 quint32 intermediate_buffer[2][buffer_size + 2];
831 // count is the size used in the intermediate_buffer.
832 int count = qCeil(length * data->m11) + 2; //+1 for the last pixel to interpolate with, and +1 for rounding errors.
833 Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
836 if (blendType == BlendTransformedBilinearTiled) {
838 if (x < 0) x += image_width;
840 lim = qMin(count, image_x2-x+1);
842 Q_ASSERT(x <= image_x2);
843 uint t = fetch(s1, image_x1, data->texture.colorTable);
844 uint b = fetch(s2, image_x1, data->texture.colorTable);
845 quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
846 quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
848 intermediate_buffer[0][f] = rb;
849 intermediate_buffer[1][f] = ag;
852 } while (x < image_x1 && f < lim);
856 if (blendType != BlendTransformedBilinearTiled &&
857 (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)) {
858 #if defined(QT_ALWAYS_HAVE_SSE2)
859 const __m128i disty_ = _mm_set1_epi16(disty);
860 const __m128i idisty_ = _mm_set1_epi16(idisty);
861 const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
864 for (; f < lim; x += 4, f += 4) {
865 // Load 4 pixels from s1, and split the alpha-green and red-blue component
866 __m128i top = _mm_loadu_si128((__m128i*)((const uint *)(s1)+x));
867 __m128i topAG = _mm_srli_epi16(top, 8);
868 __m128i topRB = _mm_and_si128(top, colorMask);
869 // Multiplies each colour component by idisty
870 topAG = _mm_mullo_epi16 (topAG, idisty_);
871 topRB = _mm_mullo_epi16 (topRB, idisty_);
873 // Same for the s2 vector
874 __m128i bottom = _mm_loadu_si128((__m128i*)((const uint *)(s2)+x));
875 __m128i bottomAG = _mm_srli_epi16(bottom, 8);
876 __m128i bottomRB = _mm_and_si128(bottom, colorMask);
877 bottomAG = _mm_mullo_epi16 (bottomAG, disty_);
878 bottomRB = _mm_mullo_epi16 (bottomRB, disty_);
880 // Add the values, and shift to only keep 8 significant bits per colors
881 __m128i rAG =_mm_add_epi16(topAG, bottomAG);
882 rAG = _mm_srli_epi16(rAG, 8);
883 _mm_storeu_si128((__m128i*)(&intermediate_buffer[1][f]), rAG);
884 __m128i rRB =_mm_add_epi16(topRB, bottomRB);
885 rRB = _mm_srli_epi16(rRB, 8);
886 _mm_storeu_si128((__m128i*)(&intermediate_buffer[0][f]), rRB);
888 #elif defined(QT_ALWAYS_HAVE_NEON)
889 const int16x8_t disty_ = vdupq_n_s16(disty);
890 const int16x8_t idisty_ = vdupq_n_s16(idisty);
891 const int16x8_t colorMask = vdupq_n_s16(0x00ff);
894 for (; f < lim; x += 4, f += 4) {
895 // Load 4 pixels from s1, and split the alpha-green and red-blue component
896 int16x8_t top = vld1q_s16((int16_t*)((const uint *)(s1)+x));
897 int16x8_t topAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(top), 8));
898 int16x8_t topRB = vandq_s16(top, colorMask);
899 // Multiplies each colour component by idisty
900 topAG = vmulq_s16(topAG, idisty_);
901 topRB = vmulq_s16(topRB, idisty_);
903 // Same for the s2 vector
904 int16x8_t bottom = vld1q_s16((int16_t*)((const uint *)(s2)+x));
905 int16x8_t bottomAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bottom), 8));
906 int16x8_t bottomRB = vandq_s16(bottom, colorMask);
907 bottomAG = vmulq_s16(bottomAG, disty_);
908 bottomRB = vmulq_s16(bottomRB, disty_);
910 // Add the values, and shift to only keep 8 significant bits per colors
911 int16x8_t rAG = vaddq_s16(topAG, bottomAG);
912 rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8));
913 vst1q_s16((int16_t*)(&intermediate_buffer[1][f]), rAG);
914 int16x8_t rRB = vaddq_s16(topRB, bottomRB);
915 rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8));
916 vst1q_s16((int16_t*)(&intermediate_buffer[0][f]), rRB);
920 for (; f < count; f++) { // Same as above but without sse2
921 if (blendType == BlendTransformedBilinearTiled) {
922 if (x >= image_width) x -= image_width;
924 x = qMin(x, image_x2);
927 uint t = fetch(s1, x, data->texture.colorTable);
928 uint b = fetch(s2, x, data->texture.colorTable);
930 intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
931 intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
934 // Now interpolate the values from the intermediate_buffer to get the final result.
935 fx &= fixed_scale - 1;
936 Q_ASSERT((fx >> 16) == 0);
938 register int x1 = (fx >> 16);
939 register int x2 = x1 + 1;
941 Q_ASSERT(x2 < count);
943 register int distx = (fx & 0x0000ffff) >> 8;
944 register int idistx = 256 - distx;
945 int rb = ((intermediate_buffer[0][x1] * idistx + intermediate_buffer[0][x2] * distx) >> 8) & 0xff00ff;
946 int ag = (intermediate_buffer[1][x1] * idistx + intermediate_buffer[1][x2] * distx) & 0xff00ff00;
951 } else if ((fdx < 0 && fdx > -(fixed_scale / 8)) || fabs(data->m22) < (1./8.)) { // scale up more than 8x
954 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
955 const uchar *s1 = data->texture.scanLine(y1);
956 const uchar *s2 = data->texture.scanLine(y2);
957 int disty = (fy & 0x0000ffff) >> 8;
958 int idisty = 256 - disty;
962 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
963 uint tl = fetch(s1, x1, data->texture.colorTable);
964 uint tr = fetch(s1, x2, data->texture.colorTable);
965 uint bl = fetch(s2, x1, data->texture.colorTable);
966 uint br = fetch(s2, x2, data->texture.colorTable);
968 int distx = (fx & 0x0000ffff) >> 8;
969 int idistx = 256 - distx;
971 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
972 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
973 *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
978 } else { //scale down
981 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
982 const uchar *s1 = data->texture.scanLine(y1);
983 const uchar *s2 = data->texture.scanLine(y2);
984 int disty = (fy & 0x0000ffff) >> 12;
986 if (blendType != BlendTransformedBilinearTiled &&
987 (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)) {
989 #define BILINEAR_DOWNSCALE_BOUNDS_PROLOG \
991 int x1 = (fx >> 16); \
993 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); \
996 uint tl = fetch(s1, x1, data->texture.colorTable); \
997 uint tr = fetch(s1, x2, data->texture.colorTable); \
998 uint bl = fetch(s2, x1, data->texture.colorTable); \
999 uint br = fetch(s2, x2, data->texture.colorTable); \
1000 int distx = (fx & 0x0000ffff) >> 12; \
1001 *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty); \
1007 boundedEnd = qMin(end, buffer + uint((image_x2 - (fx >> 16)) / data->m11)); \
1009 boundedEnd = qMin(end, buffer + uint((image_x1 - (fx >> 16)) / data->m11)); \
1012 #if defined(QT_ALWAYS_HAVE_SSE2)
1013 BILINEAR_DOWNSCALE_BOUNDS_PROLOG
1015 const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
1016 const __m128i v_256 = _mm_set1_epi16(256);
1017 const __m128i v_disty = _mm_set1_epi16(disty);
1018 __m128i v_fdx = _mm_set1_epi32(fdx*4);
1020 ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
1022 union Vect_buffer { __m128i vect; quint32 i[4]; };
1025 for (int i = 0; i < 4; i++) {
1030 while (b < boundedEnd) {
1032 Vect_buffer tl, tr, bl, br;
1034 for (int i = 0; i < 4; i++) {
1035 int x1 = v_fx.i[i] >> 16;
1036 const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1037 const uint *addr_tr = addr_tl + 1;
1040 bl.i[i] = *(addr_tl+secondLine);
1041 br.i[i] = *(addr_tr+secondLine);
1043 __m128i v_distx = _mm_srli_epi16(v_fx.vect, 12);
1044 v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1045 v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1047 interpolate_4_pixels_16_sse2(tl.vect, tr.vect, bl.vect, br.vect, v_distx, v_disty, colorMask, v_256, b);
1049 v_fx.vect = _mm_add_epi32(v_fx.vect, v_fdx);
1052 #elif defined(QT_ALWAYS_HAVE_NEON)
1053 BILINEAR_DOWNSCALE_BOUNDS_PROLOG
1055 const int16x8_t colorMask = vdupq_n_s16(0x00ff);
1056 const int16x8_t invColorMask = vmvnq_s16(colorMask);
1057 const int16x8_t v_256 = vdupq_n_s16(256);
1058 const int16x8_t v_disty = vdupq_n_s16(disty);
1059 const int16x8_t v_disty_ = vshlq_n_s16(v_disty, 4);
1060 int32x4_t v_fdx = vdupq_n_s32(fdx*4);
1062 ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
1064 union Vect_buffer { int32x4_t vect; quint32 i[4]; };
1067 for (int i = 0; i < 4; i++) {
1072 const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
1074 while (b < boundedEnd) {
1076 Vect_buffer tl, tr, bl, br;
1078 Vect_buffer v_fx_shifted;
1079 v_fx_shifted.vect = vshrq_n_s32(v_fx.vect, 16);
1081 int32x4_t v_distx = vshrq_n_s32(vandq_s32(v_fx.vect, v_ffff_mask), 12);
1083 for (int i = 0; i < 4; i++) {
1084 int x1 = v_fx_shifted.i[i];
1085 const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1086 const uint *addr_tr = addr_tl + 1;
1089 bl.i[i] = *(addr_tl+secondLine);
1090 br.i[i] = *(addr_tr+secondLine);
1093 v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
1095 interpolate_4_pixels_16_neon(vreinterpretq_s16_s32(tl.vect), vreinterpretq_s16_s32(tr.vect), vreinterpretq_s16_s32(bl.vect), vreinterpretq_s16_s32(br.vect), vreinterpretq_s16_s32(v_distx), v_disty, v_disty_, colorMask, invColorMask, v_256, b);
1097 v_fx.vect = vaddq_s32(v_fx.vect, v_fdx);
1104 int x1 = (fx >> 16);
1106 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1107 uint tl = fetch(s1, x1, data->texture.colorTable);
1108 uint tr = fetch(s1, x2, data->texture.colorTable);
1109 uint bl = fetch(s2, x1, data->texture.colorTable);
1110 uint br = fetch(s2, x2, data->texture.colorTable);
1111 int distx = (fx & 0x0000ffff) >> 12;
1112 *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1118 if (fabs(data->m11) > 8 || fabs(data->m22) > 8) {
1119 //if we are zooming more than 8 times, we use 8bit precision for the position.
1121 int x1 = (fx >> 16);
1123 int y1 = (fy >> 16);
1126 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1127 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1129 const uchar *s1 = data->texture.scanLine(y1);
1130 const uchar *s2 = data->texture.scanLine(y2);
1132 uint tl = fetch(s1, x1, data->texture.colorTable);
1133 uint tr = fetch(s1, x2, data->texture.colorTable);
1134 uint bl = fetch(s2, x1, data->texture.colorTable);
1135 uint br = fetch(s2, x2, data->texture.colorTable);
1137 int distx = (fx & 0x0000ffff) >> 8;
1138 int disty = (fy & 0x0000ffff) >> 8;
1139 int idistx = 256 - distx;
1140 int idisty = 256 - disty;
1142 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1143 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1144 *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1151 //we are zooming less than 8x, use 4bit precision
1153 int x1 = (fx >> 16);
1155 int y1 = (fy >> 16);
1158 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1159 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1161 const uchar *s1 = data->texture.scanLine(y1);
1162 const uchar *s2 = data->texture.scanLine(y2);
1164 uint tl = fetch(s1, x1, data->texture.colorTable);
1165 uint tr = fetch(s1, x2, data->texture.colorTable);
1166 uint bl = fetch(s2, x1, data->texture.colorTable);
1167 uint br = fetch(s2, x2, data->texture.colorTable);
1169 int distx = (fx & 0x0000ffff) >> 12;
1170 int disty = (fy & 0x0000ffff) >> 12;
1172 *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1181 const qreal fdx = data->m11;
1182 const qreal fdy = data->m12;
1183 const qreal fdw = data->m13;
1185 qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
1186 qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
1187 qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
1190 const qreal iw = fw == 0 ? 1 : 1 / fw;
1191 const qreal px = fx * iw - qreal(0.5);
1192 const qreal py = fy * iw - qreal(0.5);
1194 int x1 = int(px) - (px < 0);
1196 int y1 = int(py) - (py < 0);
1199 int distx = int((px - x1) * 256);
1200 int disty = int((py - y1) * 256);
1201 int idistx = 256 - distx;
1202 int idisty = 256 - disty;
1204 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1205 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1207 const uchar *s1 = data->texture.scanLine(y1);
1208 const uchar *s2 = data->texture.scanLine(y2);
1210 uint tl = fetch(s1, x1, data->texture.colorTable);
1211 uint tr = fetch(s1, x2, data->texture.colorTable);
1212 uint bl = fetch(s2, x1, data->texture.colorTable);
1213 uint br = fetch(s2, x2, data->texture.colorTable);
1215 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1216 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1217 *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1222 //force increment to avoid /0
1233 #define SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Arg) qt_fetchUntransformed<QImage::Arg>
1235 static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = {
1239 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono), // Mono
1240 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB), // MonoLsb
1241 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8), // Indexed8
1242 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // RGB32
1243 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32), // ARGB32
1244 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // ARGB32_Premultiplied
1245 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16), // RGB16
1246 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
1247 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666), // RGB666
1248 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
1249 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555), // RGB555
1250 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
1251 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888), // RGB888
1252 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444), // RGB444
1253 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
1258 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono), // Mono
1259 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB), // MonoLsb
1260 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8), // Indexed8
1261 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // RGB32
1262 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32), // ARGB32
1263 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // ARGB32_Premultiplied
1264 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16), // RGB16
1265 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
1266 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666), // RGB666
1267 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
1268 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555), // RGB555
1269 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
1270 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888), // RGB888
1271 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444), // RGB444
1272 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
1277 fetchTransformed<BlendTransformed>, // Mono
1278 fetchTransformed<BlendTransformed>, // MonoLsb
1279 fetchTransformed<BlendTransformed>, // Indexed8
1280 fetchTransformed<BlendTransformed>, // RGB32
1281 fetchTransformed<BlendTransformed>, // ARGB32
1282 fetchTransformed<BlendTransformed>, // ARGB32_Premultiplied
1283 fetchTransformed<BlendTransformed>, // RGB16
1284 fetchTransformed<BlendTransformed>, // ARGB8565_Premultiplied
1285 fetchTransformed<BlendTransformed>, // RGB666
1286 fetchTransformed<BlendTransformed>, // ARGB6666_Premultiplied
1287 fetchTransformed<BlendTransformed>, // RGB555
1288 fetchTransformed<BlendTransformed>, // ARGB8555_Premultiplied
1289 fetchTransformed<BlendTransformed>, // RGB888
1290 fetchTransformed<BlendTransformed>, // RGB444
1291 fetchTransformed<BlendTransformed>, // ARGB4444_Premultiplied
1294 0, // TransformedTiled
1295 fetchTransformed<BlendTransformedTiled>, // Mono
1296 fetchTransformed<BlendTransformedTiled>, // MonoLsb
1297 fetchTransformed<BlendTransformedTiled>, // Indexed8
1298 fetchTransformed<BlendTransformedTiled>, // RGB32
1299 fetchTransformed<BlendTransformedTiled>, // ARGB32
1300 fetchTransformed<BlendTransformedTiled>, // ARGB32_Premultiplied
1301 fetchTransformed<BlendTransformedTiled>, // RGB16
1302 fetchTransformed<BlendTransformedTiled>, // ARGB8565_Premultiplied
1303 fetchTransformed<BlendTransformedTiled>, // RGB666
1304 fetchTransformed<BlendTransformedTiled>, // ARGB6666_Premultiplied
1305 fetchTransformed<BlendTransformedTiled>, // RGB555
1306 fetchTransformed<BlendTransformedTiled>, // ARGB8555_Premultiplied
1307 fetchTransformed<BlendTransformedTiled>, // RGB888
1308 fetchTransformed<BlendTransformedTiled>, // RGB444
1309 fetchTransformed<BlendTransformedTiled>, // ARGB4444_Premultiplied
1313 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // Mono
1314 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // MonoLsb
1315 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // Indexed8
1316 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>, // RGB32
1317 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32>, // ARGB32
1318 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>, // ARGB32_Premultiplied
1319 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB16
1320 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB8565_Premultiplied
1321 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB666
1322 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB6666_Premultiplied
1323 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB555
1324 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB8555_Premultiplied
1325 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB888
1326 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB444
1327 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid> // ARGB4444_Premultiplied
1331 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // Mono
1332 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // MonoLsb
1333 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // Indexed8
1334 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>, // RGB32
1335 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32>, // ARGB32
1336 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>, // ARGB32_Premultiplied
1337 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB16
1338 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB8565_Premultiplied
1339 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB666
1340 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB6666_Premultiplied
1341 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB555
1342 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB8555_Premultiplied
1343 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB888
1344 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB444
1345 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid> // ARGB4444_Premultiplied
1350 static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos)
1352 int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5));
1354 // calculate the actual offset.
1355 if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
1356 if (data->spread == QGradient::RepeatSpread) {
1357 ipos = ipos % GRADIENT_STOPTABLE_SIZE;
1358 ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
1360 } else if (data->spread == QGradient::ReflectSpread) {
1361 const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
1362 ipos = ipos % limit;
1363 ipos = ipos < 0 ? limit + ipos : ipos;
1364 ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
1367 if (ipos < 0) ipos = 0;
1368 else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
1372 Q_ASSERT(ipos >= 0);
1373 Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
1375 return data->colorTable[ipos];
1378 #define FIXPT_BITS 8
1379 #define FIXPT_SIZE (1<<FIXPT_BITS)
1381 static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
1383 int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
1385 // calculate the actual offset.
1386 if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
1387 if (data->spread == QGradient::RepeatSpread) {
1388 ipos = ipos % GRADIENT_STOPTABLE_SIZE;
1389 ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
1391 } else if (data->spread == QGradient::ReflectSpread) {
1392 const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
1393 ipos = ipos % limit;
1394 ipos = ipos < 0 ? limit + ipos : ipos;
1395 ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
1398 if (ipos < 0) ipos = 0;
1399 else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
1403 Q_ASSERT(ipos >= 0);
1404 Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
1406 return data->colorTable[ipos];
1409 static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
1411 v->dx = data->gradient.linear.end.x - data->gradient.linear.origin.x;
1412 v->dy = data->gradient.linear.end.y - data->gradient.linear.origin.y;
1413 v->l = v->dx * v->dx + v->dy * v->dy;
1418 v->off = -v->dx * data->gradient.linear.origin.x - v->dy * data->gradient.linear.origin.y;
1422 static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator *op, const QSpanData *data,
1423 int y, int x, int length)
1425 const uint *b = buffer;
1430 if (op->linear.l == 0) {
1433 rx = data->m21 * (y + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx;
1434 ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(0.5)) + data->dy;
1435 t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off;
1436 inc = op->linear.dx * data->m11 + op->linear.dy * data->m12;
1437 affine = !data->m13 && !data->m23;
1440 t *= (GRADIENT_STOPTABLE_SIZE - 1);
1441 inc *= (GRADIENT_STOPTABLE_SIZE - 1);
1445 const uint *end = buffer + length;
1447 if (inc > qreal(-1e-5) && inc < qreal(1e-5)) {
1448 QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE)));
1450 if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) &&
1451 t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) {
1452 // we can use fixed point math
1453 int t_fixed = int(t * FIXPT_SIZE);
1454 int inc_fixed = int(inc * FIXPT_SIZE);
1455 while (buffer < end) {
1456 *buffer = qt_gradient_pixel_fixed(&data->gradient, t_fixed);
1457 t_fixed += inc_fixed;
1461 // we have to fall back to float math
1462 while (buffer < end) {
1463 *buffer = qt_gradient_pixel(&data->gradient, t/GRADIENT_STOPTABLE_SIZE);
1469 } else { // fall back to float math here as well
1470 qreal rw = data->m23 * (y + qreal(0.5)) + data->m13 * (x + qreal(0.5)) + data->m33;
1471 while (buffer < end) {
1474 t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off;
1476 *buffer = qt_gradient_pixel(&data->gradient, t);
1490 static inline qreal determinant(qreal a, qreal b, qreal c)
1492 return (b * b) - (4 * a * c);
1495 // function to evaluate real roots
1496 static inline qreal realRoots(qreal a, qreal b, qreal detSqrt)
1498 return (-b + detSqrt)/(2 * a);
1501 static inline qreal qSafeSqrt(qreal x)
1503 return x > 0 ? qSqrt(x) : 0;
1506 static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
1508 v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x;
1509 v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y;
1510 v->a = data->gradient.radial.radius*data->gradient.radial.radius - v->dx*v->dx - v->dy*v->dy;
1513 static const uint * QT_FASTCALL fetchRadialGradient(uint *buffer, const Operator *op, const QSpanData *data,
1514 int y, int x, int length)
1516 const uint *b = buffer;
1517 qreal rx = data->m21 * (y + qreal(0.5))
1518 + data->dx + data->m11 * (x + qreal(0.5));
1519 qreal ry = data->m22 * (y + qreal(0.5))
1520 + data->dy + data->m12 * (x + qreal(0.5));
1521 bool affine = !data->m13 && !data->m23;
1522 //qreal r = data->gradient.radial.radius;
1524 const uint *end = buffer + length;
1526 rx -= data->gradient.radial.focal.x;
1527 ry -= data->gradient.radial.focal.y;
1529 qreal inv_a = 1 / qreal(2 * op->radial.a);
1531 const qreal delta_rx = data->m11;
1532 const qreal delta_ry = data->m12;
1534 qreal b = 2*(rx * op->radial.dx + ry * op->radial.dy);
1535 qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy);
1536 const qreal b_delta_b = 2 * b * delta_b;
1537 const qreal delta_b_delta_b = 2 * delta_b * delta_b;
1539 const qreal bb = b * b;
1540 const qreal delta_bb = delta_b * delta_b;
1545 const qreal rxrxryry = rx * rx + ry * ry;
1546 const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry;
1547 const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry);
1548 const qreal delta_rx_plus_ry = 2 * delta_rxrxryry;
1552 qreal det = (bb + 4 * op->radial.a * rxrxryry) * inv_a;
1553 qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a;
1554 const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a;
1556 while (buffer < end) {
1557 *buffer = qt_gradient_pixel(&data->gradient, qSafeSqrt(det) - b);
1560 delta_det += delta_delta_det;
1566 qreal rw = data->m23 * (y + qreal(0.5))
1567 + data->m33 + data->m13 * (x + qreal(0.5));
1570 while (buffer < end) {
1571 qreal gx = rx/rw - data->gradient.radial.focal.x;
1572 qreal gy = ry/rw - data->gradient.radial.focal.y;
1573 qreal b = 2*(gx*op->radial.dx + gy*op->radial.dy);
1574 qreal det = determinant(op->radial.a, b , -(gx*gx + gy*gy));
1575 qreal s = realRoots(op->radial.a, b, qSafeSqrt(det));
1577 *buffer = qt_gradient_pixel(&data->gradient, s);
1592 static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operator *, const QSpanData *data,
1593 int y, int x, int length)
1595 const uint *b = buffer;
1596 qreal rx = data->m21 * (y + qreal(0.5))
1597 + data->dx + data->m11 * (x + qreal(0.5));
1598 qreal ry = data->m22 * (y + qreal(0.5))
1599 + data->dy + data->m12 * (x + qreal(0.5));
1600 bool affine = !data->m13 && !data->m23;
1602 const uint *end = buffer + length;
1604 rx -= data->gradient.conical.center.x;
1605 ry -= data->gradient.conical.center.y;
1606 while (buffer < end) {
1607 qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle;
1609 *buffer = qt_gradient_pixel(&data->gradient, 1 - angle / (2*Q_PI));
1616 qreal rw = data->m23 * (y + qreal(0.5))
1617 + data->m33 + data->m13 * (x + qreal(0.5));
1620 while (buffer < end) {
1621 qreal angle = qAtan2(ry/rw - data->gradient.conical.center.x,
1622 rx/rw - data->gradient.conical.center.y)
1623 + data->gradient.conical.angle;
1625 *buffer = qt_gradient_pixel(&data->gradient, 1. - angle / (2*Q_PI));
1639 #if defined(Q_CC_RVCT)
1640 // Force ARM code generation for comp_func_* -methods
1643 # if defined(QT_HAVE_ARMV6)
1644 static __forceinline void preload(const uint *start)
1646 asm( "pld [start]" );
1648 static const uint L2CacheLineLength = 32;
1649 static const uint L2CacheLineLengthInInts = L2CacheLineLength/sizeof(uint);
1650 # define PRELOAD_INIT(x) preload(x);
1651 # define PRELOAD_INIT2(x,y) PRELOAD_INIT(x) PRELOAD_INIT(y)
1652 # define PRELOAD_COND(x) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts);
1653 // Two consecutive preloads stall, so space them out a bit by using different modulus.
1654 # define PRELOAD_COND2(x,y) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); \
1655 if (((uint)&y[i])%L2CacheLineLength == 16) preload(&y[i] + L2CacheLineLengthInInts);
1656 # endif // QT_HAVE_ARMV6
1659 #if !defined(Q_CC_RVCT) || !defined(QT_HAVE_ARMV6)
1660 # define PRELOAD_INIT(x)
1661 # define PRELOAD_INIT2(x,y)
1662 # define PRELOAD_COND(x)
1663 # define PRELOAD_COND2(x,y)
1666 /* The constant alpha factor describes an alpha factor that gets applied
1667 to the result of the composition operation combining it with the destination.
1669 The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1.
1670 we get the unmodified operation
1672 result = src op dest
1673 dest = result * const_alpha + dest * (1. - const_alpha)
1675 This means that in the comments below, the first line is the const_alpha==255 case, the
1676 second line the general one.
1679 s == src, sa == alpha(src), sia = 1 - alpha(src)
1680 d == dest, da == alpha(dest), dia = 1 - alpha(dest)
1681 ca = const_alpha, cia = 1 - const_alpha
1683 The methods exist in two variants. One where we have a constant source, the other
1684 where the source is an array of pixels.
1691 #define comp_func_Clear_impl(dest, length, const_alpha)\
1693 if (const_alpha == 255) {\
1694 QT_MEMFILL_UINT(dest, length, 0);\
1696 int ialpha = 255 - const_alpha;\
1698 for (int i = 0; i < length; ++i) {\
1700 dest[i] = BYTE_MUL(dest[i], ialpha);\
1705 void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
1707 comp_func_Clear_impl(dest, length, const_alpha);
1710 void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
1712 comp_func_Clear_impl(dest, length, const_alpha);
1717 dest = s * ca + d * cia
1719 void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha)
1721 if (const_alpha == 255) {
1722 QT_MEMFILL_UINT(dest, length, color);
1724 int ialpha = 255 - const_alpha;
1725 color = BYTE_MUL(color, const_alpha);
1727 for (int i = 0; i < length; ++i) {
1729 dest[i] = color + BYTE_MUL(dest[i], ialpha);
1734 void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length, uint const_alpha)
1736 if (const_alpha == 255) {
1737 ::memcpy(dest, src, length * sizeof(uint));
1739 int ialpha = 255 - const_alpha;
1740 PRELOAD_INIT2(dest, src)
1741 for (int i = 0; i < length; ++i) {
1742 PRELOAD_COND2(dest, src)
1743 dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha);
1748 void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
1752 void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint)
1757 result = s + d * sia
1758 dest = (s + d * sia) * ca + d * cia
1759 = s * ca + d * (sia * ca + cia)
1760 = s * ca + d * (1 - sa*ca)
1762 void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha)
1764 if ((const_alpha & qAlpha(color)) == 255) {
1765 QT_MEMFILL_UINT(dest, length, color);
1767 if (const_alpha != 255)
1768 color = BYTE_MUL(color, const_alpha);
1770 for (int i = 0; i < length; ++i) {
1772 dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color));
1777 void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha)
1779 PRELOAD_INIT2(dest, src)
1780 if (const_alpha == 255) {
1781 for (int i = 0; i < length; ++i) {
1782 PRELOAD_COND2(dest, src)
1784 if (s >= 0xff000000)
1787 dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
1790 for (int i = 0; i < length; ++i) {
1791 PRELOAD_COND2(dest, src)
1792 uint s = BYTE_MUL(src[i], const_alpha);
1793 dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
1799 result = d + s * dia
1800 dest = (d + s * dia) * ca + d * cia
1803 void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha)
1805 if (const_alpha != 255)
1806 color = BYTE_MUL(color, const_alpha);
1808 for (int i = 0; i < length; ++i) {
1811 dest[i] = d + BYTE_MUL(color, qAlpha(~d));
1815 void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha)
1817 PRELOAD_INIT2(dest, src)
1818 if (const_alpha == 255) {
1819 for (int i = 0; i < length; ++i) {
1820 PRELOAD_COND2(dest, src)
1822 dest[i] = d + BYTE_MUL(src[i], qAlpha(~d));
1825 for (int i = 0; i < length; ++i) {
1826 PRELOAD_COND2(dest, src)
1828 uint s = BYTE_MUL(src[i], const_alpha);
1829 dest[i] = d + BYTE_MUL(s, qAlpha(~d));
1836 dest = s * da * ca + d * cia
1838 void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha)
1841 if (const_alpha == 255) {
1842 for (int i = 0; i < length; ++i) {
1844 dest[i] = BYTE_MUL(color, qAlpha(dest[i]));
1847 color = BYTE_MUL(color, const_alpha);
1848 uint cia = 255 - const_alpha;
1849 for (int i = 0; i < length; ++i) {
1852 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia);
1857 void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha)
1859 PRELOAD_INIT2(dest, src)
1860 if (const_alpha == 255) {
1861 for (int i = 0; i < length; ++i) {
1862 PRELOAD_COND2(dest, src)
1863 dest[i] = BYTE_MUL(src[i], qAlpha(dest[i]));
1866 uint cia = 255 - const_alpha;
1867 for (int i = 0; i < length; ++i) {
1868 PRELOAD_COND2(dest, src)
1870 uint s = BYTE_MUL(src[i], const_alpha);
1871 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia);
1878 dest = d * sa * ca + d * cia
1879 = d * (sa * ca + cia)
1881 void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha)
1883 uint a = qAlpha(color);
1884 if (const_alpha != 255) {
1885 a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
1888 for (int i = 0; i < length; ++i) {
1890 dest[i] = BYTE_MUL(dest[i], a);
1894 void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha)
1896 PRELOAD_INIT2(dest, src)
1897 if (const_alpha == 255) {
1898 for (int i = 0; i < length; ++i) {
1899 PRELOAD_COND2(dest, src)
1900 dest[i] = BYTE_MUL(dest[i], qAlpha(src[i]));
1903 int cia = 255 - const_alpha;
1904 for (int i = 0; i < length; ++i) {
1905 PRELOAD_COND2(dest, src)
1906 uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia;
1907 dest[i] = BYTE_MUL(dest[i], a);
1914 dest = s * dia * ca + d * cia
1917 void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha)
1920 if (const_alpha == 255) {
1921 for (int i = 0; i < length; ++i) {
1923 dest[i] = BYTE_MUL(color, qAlpha(~dest[i]));
1926 color = BYTE_MUL(color, const_alpha);
1927 int cia = 255 - const_alpha;
1928 for (int i = 0; i < length; ++i) {
1931 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia);
1936 void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha)
1938 PRELOAD_INIT2(dest, src)
1939 if (const_alpha == 255) {
1940 for (int i = 0; i < length; ++i) {
1941 PRELOAD_COND2(dest, src)
1942 dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i]));
1945 int cia = 255 - const_alpha;
1946 for (int i = 0; i < length; ++i) {
1947 PRELOAD_COND2(dest, src)
1948 uint s = BYTE_MUL(src[i], const_alpha);
1950 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia);
1957 dest = d * sia * ca + d * cia
1958 = d * (sia * ca + cia)
1960 void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha)
1962 uint a = qAlpha(~color);
1963 if (const_alpha != 255)
1964 a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
1966 for (int i = 0; i < length; ++i) {
1968 dest[i] = BYTE_MUL(dest[i], a);
1972 void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha)
1974 PRELOAD_INIT2(dest, src)
1975 if (const_alpha == 255) {
1976 for (int i = 0; i < length; ++i) {
1977 PRELOAD_COND2(dest, src)
1978 dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i]));
1981 int cia = 255 - const_alpha;
1982 for (int i = 0; i < length; ++i) {
1983 PRELOAD_COND2(dest, src)
1984 uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia;
1985 dest[i] = BYTE_MUL(dest[i], sia);
1991 result = s*da + d*sia
1992 dest = s*da*ca + d*sia*ca + d *cia
1993 = s*ca * da + d * (sia*ca + cia)
1994 = s*ca * da + d * (1 - sa*ca)
1996 void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha)
1998 if (const_alpha != 255) {
1999 color = BYTE_MUL(color, const_alpha);
2001 uint sia = qAlpha(~color);
2003 for (int i = 0; i < length; ++i) {
2005 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia);
2009 void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha)
2011 PRELOAD_INIT2(dest, src)
2012 if (const_alpha == 255) {
2013 for (int i = 0; i < length; ++i) {
2014 PRELOAD_COND2(dest, src)
2017 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
2020 for (int i = 0; i < length; ++i) {
2021 PRELOAD_COND2(dest, src)
2022 uint s = BYTE_MUL(src[i], const_alpha);
2024 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
2030 result = d*sa + s*dia
2031 dest = d*sa*ca + s*dia*ca + d *cia
2032 = s*ca * dia + d * (sa*ca + cia)
2034 void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha)
2036 uint a = qAlpha(color);
2037 if (const_alpha != 255) {
2038 color = BYTE_MUL(color, const_alpha);
2039 a = qAlpha(color) + 255 - const_alpha;
2042 for (int i = 0; i < length; ++i) {
2045 dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d));
2049 void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha)
2051 PRELOAD_INIT2(dest, src)
2052 if (const_alpha == 255) {
2053 for (int i = 0; i < length; ++i) {
2054 PRELOAD_COND2(dest, src)
2057 dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d));
2060 int cia = 255 - const_alpha;
2061 for (int i = 0; i < length; ++i) {
2062 PRELOAD_COND2(dest, src)
2063 uint s = BYTE_MUL(src[i], const_alpha);
2065 uint a = qAlpha(s) + cia;
2066 dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d));
2072 result = d*sia + s*dia
2073 dest = d*sia*ca + s*dia*ca + d *cia
2074 = s*ca * dia + d * (sia*ca + cia)
2075 = s*ca * dia + d * (1 - sa*ca)
2077 void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha)
2079 if (const_alpha != 255)
2080 color = BYTE_MUL(color, const_alpha);
2081 uint sia = qAlpha(~color);
2084 for (int i = 0; i < length; ++i) {
2087 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia);
2091 void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha)
2093 PRELOAD_INIT2(dest, src)
2094 if (const_alpha == 255) {
2095 for (int i = 0; i < length; ++i) {
2096 PRELOAD_COND2(dest, src)
2099 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
2102 for (int i = 0; i < length; ++i) {
2103 PRELOAD_COND2(dest, src)
2105 uint s = BYTE_MUL(src[i], const_alpha);
2106 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
2111 struct QFullCoverage {
2112 inline void store(uint *dest, const uint src) const
2118 struct QPartialCoverage {
2119 inline QPartialCoverage(uint const_alpha)
2121 , ica(255 - const_alpha)
2125 inline void store(uint *dest, const uint src) const
2127 *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
2135 static inline int mix_alpha(int da, int sa)
2137 return 255 - ((255 - sa) * (255 - da) >> 8);
2141 Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
2144 template <typename T>
2145 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage)
2150 for (int i = 0; i < length; ++i) {
2153 d = comp_func_Plus_one_pixel(d, s);
2154 coverage.store(&dest[i], d);
2158 void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha)
2160 if (const_alpha == 255)
2161 comp_func_solid_Plus_impl(dest, length, color, QFullCoverage());
2163 comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha));
2166 template <typename T>
2167 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *dest, const uint *src, int length, const T &coverage)
2169 PRELOAD_INIT2(dest, src)
2170 for (int i = 0; i < length; ++i) {
2171 PRELOAD_COND2(dest, src)
2175 d = comp_func_Plus_one_pixel(d, s);
2177 coverage.store(&dest[i], d);
2181 void QT_FASTCALL comp_func_Plus(uint *dest, const uint *src, int length, uint const_alpha)
2183 if (const_alpha == 255)
2184 comp_func_Plus_impl(dest, src, length, QFullCoverage());
2186 comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha));
2190 Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2192 static inline int multiply_op(int dst, int src, int da, int sa)
2194 return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa));
2197 template <typename T>
2198 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage)
2200 int sa = qAlpha(color);
2201 int sr = qRed(color);
2202 int sg = qGreen(color);
2203 int sb = qBlue(color);
2206 for (int i = 0; i < length; ++i) {
2211 #define OP(a, b) multiply_op(a, b, da, sa)
2212 int r = OP( qRed(d), sr);
2213 int b = OP( qBlue(d), sb);
2214 int g = OP(qGreen(d), sg);
2215 int a = mix_alpha(da, sa);
2218 coverage.store(&dest[i], qRgba(r, g, b, a));
2222 void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha)
2224 if (const_alpha == 255)
2225 comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
2227 comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
2230 template <typename T>
2231 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *dest, const uint *src, int length, const T &coverage)
2233 PRELOAD_INIT2(dest, src)
2234 for (int i = 0; i < length; ++i) {
2235 PRELOAD_COND2(dest, src)
2242 #define OP(a, b) multiply_op(a, b, da, sa)
2243 int r = OP( qRed(d), qRed(s));
2244 int b = OP( qBlue(d), qBlue(s));
2245 int g = OP(qGreen(d), qGreen(s));
2246 int a = mix_alpha(da, sa);
2249 coverage.store(&dest[i], qRgba(r, g, b, a));
2253 void QT_FASTCALL comp_func_Multiply(uint *dest, const uint *src, int length, uint const_alpha)
2255 if (const_alpha == 255)
2256 comp_func_Multiply_impl(dest, src, length, QFullCoverage());
2258 comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
2262 Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2263 = Sca + Dca - Sca.Dca
2265 template <typename T>
2266 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage)
2268 int sa = qAlpha(color);
2269 int sr = qRed(color);
2270 int sg = qGreen(color);
2271 int sb = qBlue(color);
2274 for (int i = 0; i < length; ++i) {
2279 #define OP(a, b) 255 - qt_div_255((255-a) * (255-b))
2280 int r = OP( qRed(d), sr);
2281 int b = OP( qBlue(d), sb);
2282 int g = OP(qGreen(d), sg);
2283 int a = mix_alpha(da, sa);
2286 coverage.store(&dest[i], qRgba(r, g, b, a));
2290 void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha)
2292 if (const_alpha == 255)
2293 comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
2295 comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
2298 template <typename T>
2299 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *dest, const uint *src, int length, const T &coverage)
2301 PRELOAD_INIT2(dest, src)
2302 for (int i = 0; i < length; ++i) {
2303 PRELOAD_COND2(dest, src)
2310 #define OP(a, b) 255 - (((255-a) * (255-b)) >> 8)
2311 int r = OP( qRed(d), qRed(s));
2312 int b = OP( qBlue(d), qBlue(s));
2313 int g = OP(qGreen(d), qGreen(s));
2314 int a = mix_alpha(da, sa);
2317 coverage.store(&dest[i], qRgba(r, g, b, a));
2321 void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha)
2323 if (const_alpha == 255)
2324 comp_func_Screen_impl(dest, src, length, QFullCoverage());
2326 comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
2331 Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2333 Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2335 static inline int overlay_op(int dst, int src, int da, int sa)
2337 const int temp = src * (255 - da) + dst * (255 - sa);
2339 return qt_div_255(2 * src * dst + temp);
2341 return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2344 template <typename T>
2345 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage)
2347 int sa = qAlpha(color);
2348 int sr = qRed(color);
2349 int sg = qGreen(color);
2350 int sb = qBlue(color);
2353 for (int i = 0; i < length; ++i) {
2358 #define OP(a, b) overlay_op(a, b, da, sa)
2359 int r = OP( qRed(d), sr);
2360 int b = OP( qBlue(d), sb);
2361 int g = OP(qGreen(d), sg);
2362 int a = mix_alpha(da, sa);
2365 coverage.store(&dest[i], qRgba(r, g, b, a));
2369 void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha)
2371 if (const_alpha == 255)
2372 comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
2374 comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
2377 template <typename T>
2378 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *dest, const uint *src, int length, const T &coverage)
2380 PRELOAD_INIT2(dest, src)
2381 for (int i = 0; i < length; ++i) {
2382 PRELOAD_COND2(dest, src)
2389 #define OP(a, b) overlay_op(a, b, da, sa)
2390 int r = OP( qRed(d), qRed(s));
2391 int b = OP( qBlue(d), qBlue(s));
2392 int g = OP(qGreen(d), qGreen(s));
2393 int a = mix_alpha(da, sa);
2396 coverage.store(&dest[i], qRgba(r, g, b, a));
2400 void QT_FASTCALL comp_func_Overlay(uint *dest, const uint *src, int length, uint const_alpha)
2402 if (const_alpha == 255)
2403 comp_func_Overlay_impl(dest, src, length, QFullCoverage());
2405 comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
2409 Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2410 Da' = Sa + Da - Sa.Da
2412 static inline int darken_op(int dst, int src, int da, int sa)
2414 return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2417 template <typename T>
2418 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage)
2420 int sa = qAlpha(color);
2421 int sr = qRed(color);
2422 int sg = qGreen(color);
2423 int sb = qBlue(color);
2426 for (int i = 0; i < length; ++i) {
2431 #define OP(a, b) darken_op(a, b, da, sa)
2432 int r = OP( qRed(d), sr);
2433 int b = OP( qBlue(d), sb);
2434 int g = OP(qGreen(d), sg);
2435 int a = mix_alpha(da, sa);
2438 coverage.store(&dest[i], qRgba(r, g, b, a));
2442 void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha)
2444 if (const_alpha == 255)
2445 comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
2447 comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
2450 template <typename T>
2451 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *dest, const uint *src, int length, const T &coverage)
2453 PRELOAD_INIT2(dest, src)
2454 for (int i = 0; i < length; ++i) {
2455 PRELOAD_COND2(dest, src)
2462 #define OP(a, b) darken_op(a, b, da, sa)
2463 int r = OP( qRed(d), qRed(s));
2464 int b = OP( qBlue(d), qBlue(s));
2465 int g = OP(qGreen(d), qGreen(s));
2466 int a = mix_alpha(da, sa);
2469 coverage.store(&dest[i], qRgba(r, g, b, a));
2473 void QT_FASTCALL comp_func_Darken(uint *dest, const uint *src, int length, uint const_alpha)
2475 if (const_alpha == 255)
2476 comp_func_Darken_impl(dest, src, length, QFullCoverage());
2478 comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
2482 Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2483 Da' = Sa + Da - Sa.Da
2485 static inline int lighten_op(int dst, int src, int da, int sa)
2487 return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2490 template <typename T>
2491 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage)
2493 int sa = qAlpha(color);
2494 int sr = qRed(color);
2495 int sg = qGreen(color);
2496 int sb = qBlue(color);
2499 for (int i = 0; i < length; ++i) {
2504 #define OP(a, b) lighten_op(a, b, da, sa)
2505 int r = OP( qRed(d), sr);
2506 int b = OP( qBlue(d), sb);
2507 int g = OP(qGreen(d), sg);
2508 int a = mix_alpha(da, sa);
2511 coverage.store(&dest[i], qRgba(r, g, b, a));
2515 void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha)
2517 if (const_alpha == 255)
2518 comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
2520 comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
2523 template <typename T>
2524 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *dest, const uint *src, int length, const T &coverage)
2526 PRELOAD_INIT2(dest, src)
2527 for (int i = 0; i < length; ++i) {
2528 PRELOAD_COND2(dest, src)
2535 #define OP(a, b) lighten_op(a, b, da, sa)
2536 int r = OP( qRed(d), qRed(s));
2537 int b = OP( qBlue(d), qBlue(s));
2538 int g = OP(qGreen(d), qGreen(s));
2539 int a = mix_alpha(da, sa);
2542 coverage.store(&dest[i], qRgba(r, g, b, a));
2546 void QT_FASTCALL comp_func_Lighten(uint *dest, const uint *src, int length, uint const_alpha)
2548 if (const_alpha == 255)
2549 comp_func_Lighten_impl(dest, src, length, QFullCoverage());
2551 comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
2555 if Sca.Da + Dca.Sa >= Sa.Da
2556 Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
2558 Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2560 static inline int color_dodge_op(int dst, int src, int da, int sa)
2562 const int sa_da = sa * da;
2563 const int dst_sa = dst * sa;
2564 const int src_da = src * da;
2566 const int temp = src * (255 - da) + dst * (255 - sa);
2567 if (src_da + dst_sa >= sa_da)
2568 return qt_div_255(sa_da + temp);
2570 return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp);
2573 template <typename T>
2574 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage)
2576 int sa = qAlpha(color);
2577 int sr = qRed(color);
2578 int sg = qGreen(color);
2579 int sb = qBlue(color);
2582 for (int i = 0; i < length; ++i) {
2587 #define OP(a,b) color_dodge_op(a, b, da, sa)
2588 int r = OP( qRed(d), sr);
2589 int b = OP( qBlue(d), sb);
2590 int g = OP(qGreen(d), sg);
2591 int a = mix_alpha(da, sa);
2594 coverage.store(&dest[i], qRgba(r, g, b, a));
2598 void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha)
2600 if (const_alpha == 255)
2601 comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
2603 comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
2606 template <typename T>
2607 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *dest, const uint *src, int length, const T &coverage)
2609 PRELOAD_INIT2(dest, src)
2610 for (int i = 0; i < length; ++i) {
2611 PRELOAD_COND2(dest, src)
2618 #define OP(a, b) color_dodge_op(a, b, da, sa)
2619 int r = OP( qRed(d), qRed(s));
2620 int b = OP( qBlue(d), qBlue(s));
2621 int g = OP(qGreen(d), qGreen(s));
2622 int a = mix_alpha(da, sa);
2625 coverage.store(&dest[i], qRgba(r, g, b, a));
2629 void QT_FASTCALL comp_func_ColorDodge(uint *dest, const uint *src, int length, uint const_alpha)
2631 if (const_alpha == 255)
2632 comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
2634 comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
2638 if Sca.Da + Dca.Sa <= Sa.Da
2639 Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
2641 Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
2643 static inline int color_burn_op(int dst, int src, int da, int sa)
2645 const int src_da = src * da;
2646 const int dst_sa = dst * sa;
2647 const int sa_da = sa * da;
2649 const int temp = src * (255 - da) + dst * (255 - sa);
2651 if (src == 0 || src_da + dst_sa <= sa_da)
2652 return qt_div_255(temp);
2653 return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp);
2656 template <typename T>
2657 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage)
2659 int sa = qAlpha(color);
2660 int sr = qRed(color);
2661 int sg = qGreen(color);
2662 int sb = qBlue(color);
2665 for (int i = 0; i < length; ++i) {
2670 #define OP(a, b) color_burn_op(a, b, da, sa)
2671 int r = OP( qRed(d), sr);
2672 int b = OP( qBlue(d), sb);
2673 int g = OP(qGreen(d), sg);
2674 int a = mix_alpha(da, sa);
2677 coverage.store(&dest[i], qRgba(r, g, b, a));
2681 void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha)
2683 if (const_alpha == 255)
2684 comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
2686 comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
2689 template <typename T>
2690 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *dest, const uint *src, int length, const T &coverage)
2692 PRELOAD_INIT2(dest, src)
2693 for (int i = 0; i < length; ++i) {
2694 PRELOAD_COND2(dest, src)
2701 #define OP(a, b) color_burn_op(a, b, da, sa)
2702 int r = OP( qRed(d), qRed(s));
2703 int b = OP( qBlue(d), qBlue(s));
2704 int g = OP(qGreen(d), qGreen(s));
2705 int a = mix_alpha(da, sa);
2708 coverage.store(&dest[i], qRgba(r, g, b, a));
2712 void QT_FASTCALL comp_func_ColorBurn(uint *dest, const uint *src, int length, uint const_alpha)
2714 if (const_alpha == 255)
2715 comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
2717 comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
2722 Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2724 Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2726 static inline uint hardlight_op(int dst, int src, int da, int sa)
2728 const uint temp = src * (255 - da) + dst * (255 - sa);
2731 return qt_div_255(2 * src * dst + temp);
2733 return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2736 template <typename T>
2737 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage)
2739 int sa = qAlpha(color);
2740 int sr = qRed(color);
2741 int sg = qGreen(color);
2742 int sb = qBlue(color);
2745 for (int i = 0; i < length; ++i) {
2750 #define OP(a, b) hardlight_op(a, b, da, sa)
2751 int r = OP( qRed(d), sr);
2752 int b = OP( qBlue(d), sb);
2753 int g = OP(qGreen(d), sg);
2754 int a = mix_alpha(da, sa);
2757 coverage.store(&dest[i], qRgba(r, g, b, a));
2761 void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha)
2763 if (const_alpha == 255)
2764 comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
2766 comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2769 template <typename T>
2770 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *dest, const uint *src, int length, const T &coverage)
2772 PRELOAD_INIT2(dest, src)
2773 for (int i = 0; i < length; ++i) {
2774 PRELOAD_COND2(dest, src)
2781 #define OP(a, b) hardlight_op(a, b, da, sa)
2782 int r = OP( qRed(d), qRed(s));
2783 int b = OP( qBlue(d), qBlue(s));
2784 int g = OP(qGreen(d), qGreen(s));
2785 int a = mix_alpha(da, sa);
2788 coverage.store(&dest[i], qRgba(r, g, b, a));
2792 void QT_FASTCALL comp_func_HardLight(uint *dest, const uint *src, int length, uint const_alpha)
2794 if (const_alpha == 255)
2795 comp_func_HardLight_impl(dest, src, length, QFullCoverage());
2797 comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2802 Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
2803 otherwise if 2.Sca > Sa and 4.Dca <= Da
2804 Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2805 otherwise if 2.Sca > Sa and 4.Dca > Da
2806 Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2808 static inline int soft_light_op(int dst, int src, int da, int sa)
2810 const int src2 = src << 1;
2811 const int dst_np = da != 0 ? (255 * dst) / da : 0;
2812 const int temp = (src * (255 - da) + dst * (255 - sa)) * 255;
2815 return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025;
2816 else if (4 * dst <= da)
2817 return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025;
2819 # ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
2820 return (dst * sa * 255 + da * (src2 - sa) * (qIntSqrtInt(dst_np * 255) - dst_np) + temp) / 65025;
2822 return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025;
2827 template <typename T>
2828 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage)
2830 int sa = qAlpha(color);
2831 int sr = qRed(color);
2832 int sg = qGreen(color);
2833 int sb = qBlue(color);
2836 for (int i = 0; i < length; ++i) {
2841 #define OP(a, b) soft_light_op(a, b, da, sa)
2842 int r = OP( qRed(d), sr);
2843 int b = OP( qBlue(d), sb);
2844 int g = OP(qGreen(d), sg);
2845 int a = mix_alpha(da, sa);
2848 coverage.store(&dest[i], qRgba(r, g, b, a));
2852 void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
2854 if (const_alpha == 255)
2855 comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
2857 comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2860 template <typename T>
2861 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *dest, const uint *src, int length, const T &coverage)
2863 PRELOAD_INIT2(dest, src)
2864 for (int i = 0; i < length; ++i) {
2865 PRELOAD_COND2(dest, src)
2872 #define OP(a, b) soft_light_op(a, b, da, sa)
2873 int r = OP( qRed(d), qRed(s));
2874 int b = OP( qBlue(d), qBlue(s));
2875 int g = OP(qGreen(d), qGreen(s));
2876 int a = mix_alpha(da, sa);
2879 coverage.store(&dest[i], qRgba(r, g, b, a));
2883 void QT_FASTCALL comp_func_SoftLight(uint *dest, const uint *src, int length, uint const_alpha)
2885 if (const_alpha == 255)
2886 comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
2888 comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2892 Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2893 = Sca + Dca - 2.min(Sca.Da, Dca.Sa)
2895 static inline int difference_op(int dst, int src, int da, int sa)
2897 return src + dst - qt_div_255(2 * qMin(src * da, dst * sa));
2900 template <typename T>
2901 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage)
2903 int sa = qAlpha(color);
2904 int sr = qRed(color);
2905 int sg = qGreen(color);
2906 int sb = qBlue(color);
2909 for (int i = 0; i < length; ++i) {
2914 #define OP(a, b) difference_op(a, b, da, sa)
2915 int r = OP( qRed(d), sr);
2916 int b = OP( qBlue(d), sb);
2917 int g = OP(qGreen(d), sg);
2918 int a = mix_alpha(da, sa);
2921 coverage.store(&dest[i], qRgba(r, g, b, a));
2925 void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha)
2927 if (const_alpha == 255)
2928 comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
2930 comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
2933 template <typename T>
2934 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *dest, const uint *src, int length, const T &coverage)
2936 PRELOAD_INIT2(dest, src)
2937 for (int i = 0; i < length; ++i) {
2938 PRELOAD_COND2(dest, src)
2945 #define OP(a, b) difference_op(a, b, da, sa)
2946 int r = OP( qRed(d), qRed(s));
2947 int b = OP( qBlue(d), qBlue(s));
2948 int g = OP(qGreen(d), qGreen(s));
2949 int a = mix_alpha(da, sa);
2952 coverage.store(&dest[i], qRgba(r, g, b, a));
2956 void QT_FASTCALL comp_func_Difference(uint *dest, const uint *src, int length, uint const_alpha)
2958 if (const_alpha == 255)
2959 comp_func_Difference_impl(dest, src, length, QFullCoverage());
2961 comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
2965 Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2967 template <typename T>
2968 Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage)
2970 int sa = qAlpha(color);
2971 int sr = qRed(color);
2972 int sg = qGreen(color);
2973 int sb = qBlue(color);
2976 for (int i = 0; i < length; ++i) {
2981 #define OP(a, b) (a + b - qt_div_255(2*(a*b)))
2982 int r = OP( qRed(d), sr);
2983 int b = OP( qBlue(d), sb);
2984 int g = OP(qGreen(d), sg);
2985 int a = mix_alpha(da, sa);
2988 coverage.store(&dest[i], qRgba(r, g, b, a));
2992 void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha)
2994 if (const_alpha == 255)
2995 comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage());
2997 comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
3000 template <typename T>
3001 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *dest, const uint *src, int length, const T &coverage)
3003 PRELOAD_INIT2(dest, src)
3004 for (int i = 0; i < length; ++i) {
3005 PRELOAD_COND2(dest, src)
3012 #define OP(a, b) (a + b - ((a*b) >> 7))
3013 int r = OP( qRed(d), qRed(s));
3014 int b = OP( qBlue(d), qBlue(s));
3015 int g = OP(qGreen(d), qGreen(s));
3016 int a = mix_alpha(da, sa);
3019 coverage.store(&dest[i], qRgba(r, g, b, a));
3023 void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int length, uint const_alpha)
3025 if (const_alpha == 255)
3026 comp_func_Exclusion_impl(dest, src, length, QFullCoverage());
3028 comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
3031 #if defined(Q_CC_RVCT)
3032 // Restore pragma state from previous #pragma arm
3036 void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest,
3041 Q_UNUSED(const_alpha);
3046 void QT_FASTCALL rasterop_SourceOrDestination(uint *dest,
3051 Q_UNUSED(const_alpha);
3056 void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest,
3061 Q_UNUSED(const_alpha);
3062 color |= 0xff000000;
3067 void QT_FASTCALL rasterop_SourceAndDestination(uint *dest,
3072 Q_UNUSED(const_alpha);
3074 *dest = (*src & *dest) | 0xff000000;
3079 void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest,
3084 Q_UNUSED(const_alpha);
3085 color &= 0x00ffffff;
3090 void QT_FASTCALL rasterop_SourceXorDestination(uint *dest,
3095 Q_UNUSED(const_alpha);
3097 *dest = (*src ^ *dest) | 0xff000000;
3102 void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest,
3107 Q_UNUSED(const_alpha);
3110 *dest = (color & ~(*dest)) | 0xff000000;
3115 void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *dest,
3120 Q_UNUSED(const_alpha);
3122 *dest = (~(*src) & ~(*dest)) | 0xff000000;
3127 void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest,
3132 Q_UNUSED(const_alpha);
3133 color = ~color | 0xff000000;
3135 *dest = color | ~(*dest);
3140 void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *dest,
3145 Q_UNUSED(const_alpha);
3147 *dest = ~(*src) | ~(*dest) | 0xff000000;
3152 void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest,
3157 Q_UNUSED(const_alpha);
3158 color = ~color & 0x00ffffff;
3160 *dest = color ^ (*dest);
3165 void QT_FASTCALL rasterop_NotSourceXorDestination(uint *dest,
3170 Q_UNUSED(const_alpha);
3172 *dest = ((~(*src)) ^ (*dest)) | 0xff000000;
3177 void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length,
3178 uint color, uint const_alpha)
3180 Q_UNUSED(const_alpha);
3181 qt_memfill(dest, ~color | 0xff000000, length);
3184 void QT_FASTCALL rasterop_NotSource(uint *dest, const uint *src,
3185 int length, uint const_alpha)
3187 Q_UNUSED(const_alpha);
3189 *dest++ = ~(*src++) | 0xff000000;
3192 void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest,
3197 Q_UNUSED(const_alpha);
3198 color = ~color | 0xff000000;
3200 *dest = color & *dest;
3205 void QT_FASTCALL rasterop_NotSourceAndDestination(uint *dest,
3210 Q_UNUSED(const_alpha);
3212 *dest = (~(*src) & *dest) | 0xff000000;
3217 void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest,
3222 Q_UNUSED(const_alpha);
3224 *dest = (color & ~(*dest)) | 0xff000000;
3229 void QT_FASTCALL rasterop_SourceAndNotDestination(uint *dest,
3234 Q_UNUSED(const_alpha);
3236 *dest = (*src & ~(*dest)) | 0xff000000;
3241 static CompositionFunctionSolid functionForModeSolid_C[] = {
3242 comp_func_solid_SourceOver,
3243 comp_func_solid_DestinationOver,
3244 comp_func_solid_Clear,
3245 comp_func_solid_Source,
3246 comp_func_solid_Destination,
3247 comp_func_solid_SourceIn,
3248 comp_func_solid_DestinationIn,
3249 comp_func_solid_SourceOut,
3250 comp_func_solid_DestinationOut,
3251 comp_func_solid_SourceAtop,
3252 comp_func_solid_DestinationAtop,
3253 comp_func_solid_XOR,
3254 comp_func_solid_Plus,
3255 comp_func_solid_Multiply,
3256 comp_func_solid_Screen,
3257 comp_func_solid_Overlay,
3258 comp_func_solid_Darken,
3259 comp_func_solid_Lighten,
3260 comp_func_solid_ColorDodge,
3261 comp_func_solid_ColorBurn,
3262 comp_func_solid_HardLight,
3263 comp_func_solid_SoftLight,
3264 comp_func_solid_Difference,
3265 comp_func_solid_Exclusion,
3266 rasterop_solid_SourceOrDestination,
3267 rasterop_solid_SourceAndDestination,
3268 rasterop_solid_SourceXorDestination,
3269 rasterop_solid_NotSourceAndNotDestination,
3270 rasterop_solid_NotSourceOrNotDestination,
3271 rasterop_solid_NotSourceXorDestination,
3272 rasterop_solid_NotSource,
3273 rasterop_solid_NotSourceAndDestination,
3274 rasterop_solid_SourceAndNotDestination
3277 static const CompositionFunctionSolid *functionForModeSolid = functionForModeSolid_C;
3279 static CompositionFunction functionForMode_C[] = {
3280 comp_func_SourceOver,
3281 comp_func_DestinationOver,
3284 comp_func_Destination,
3286 comp_func_DestinationIn,
3287 comp_func_SourceOut,
3288 comp_func_DestinationOut,
3289 comp_func_SourceAtop,
3290 comp_func_DestinationAtop,
3298 comp_func_ColorDodge,
3299 comp_func_ColorBurn,
3300 comp_func_HardLight,
3301 comp_func_SoftLight,
3302 comp_func_Difference,
3303 comp_func_Exclusion,
3304 rasterop_SourceOrDestination,
3305 rasterop_SourceAndDestination,
3306 rasterop_SourceXorDestination,
3307 rasterop_NotSourceAndNotDestination,
3308 rasterop_NotSourceOrNotDestination,
3309 rasterop_NotSourceXorDestination,
3311 rasterop_NotSourceAndDestination,
3312 rasterop_SourceAndNotDestination
3315 static const CompositionFunction *functionForMode = functionForMode_C;
3317 static TextureBlendType getBlendType(const QSpanData *data)
3319 TextureBlendType ft;
3320 if (data->txop <= QTransform::TxTranslate)
3321 if (data->texture.type == QTextureData::Tiled)
3324 ft = BlendUntransformed;
3325 else if (data->bilinear)
3326 if (data->texture.type == QTextureData::Tiled)
3327 ft = BlendTransformedBilinearTiled;
3329 ft = BlendTransformedBilinear;
3331 if (data->texture.type == QTextureData::Tiled)
3332 ft = BlendTransformedTiled;
3334 ft = BlendTransformed;
3338 static inline Operator getOperator(const QSpanData *data, const QSpan *spans, int spanCount)
3341 bool solidSource = false;
3343 switch(data->type) {
3344 case QSpanData::Solid:
3345 solidSource = (qAlpha(data->solid.color) == 255);
3347 case QSpanData::LinearGradient:
3348 solidSource = !data->gradient.alphaColor;
3349 getLinearGradientValues(&op.linear, data);
3350 op.src_fetch = fetchLinearGradient;
3352 case QSpanData::RadialGradient:
3353 solidSource = !data->gradient.alphaColor;
3354 getRadialGradientValues(&op.radial, data);
3355 op.src_fetch = fetchRadialGradient;
3357 case QSpanData::ConicalGradient:
3358 solidSource = !data->gradient.alphaColor;
3359 op.src_fetch = fetchConicalGradient;
3361 case QSpanData::Texture:
3362 op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format];
3363 solidSource = !data->texture.hasAlpha;
3368 op.mode = data->rasterBuffer->compositionMode;
3369 if (op.mode == QPainter::CompositionMode_SourceOver && solidSource)
3370 op.mode = QPainter::CompositionMode_Source;
3372 op.dest_fetch = destFetchProc[data->rasterBuffer->format];
3373 if (op.mode == QPainter::CompositionMode_Source) {
3374 switch (data->rasterBuffer->format) {
3375 case QImage::Format_RGB32:
3376 case QImage::Format_ARGB32_Premultiplied:
3377 // don't clear dest_fetch as it sets up the pointer correctly to save one copy
3380 const QSpan *lastSpan = spans + spanCount;
3381 bool alphaSpans = false;
3382 while (spans < lastSpan) {
3383 if (spans->coverage != 255) {
3395 op.dest_store = destStoreProc[data->rasterBuffer->format];
3397 op.funcSolid = functionForModeSolid[op.mode];
3398 op.func = functionForMode[op.mode];
3405 // -------------------- blend methods ---------------------
3412 #if !defined(Q_CC_SUN)
3415 void drawBufferSpan(QSpanData *data, const uint *buffer, int bufsize,
3416 int x, int y, int length, uint const_alpha)
3424 Q_UNUSED(const_alpha);
3427 #if !defined(Q_CC_SUN)
3430 void blend_color_generic(int count, const QSpan *spans, void *userData)
3432 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3433 uint buffer[buffer_size];
3434 Operator op = getOperator(data, spans, count);
3438 int length = spans->len;
3440 int l = qMin(buffer_size, length);
3441 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3442 op.funcSolid(dest, l, data->solid.color, spans->coverage);
3444 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3452 static void blend_color_argb(int count, const QSpan *spans, void *userData)
3454 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3456 Operator op = getOperator(data, spans, count);
3458 if (op.mode == QPainter::CompositionMode_Source) {
3459 // inline for performance
3461 uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3462 if (spans->coverage == 255) {
3463 QT_MEMFILL_UINT(target, spans->len, data->solid.color);
3465 uint c = BYTE_MUL(data->solid.color, spans->coverage);
3466 int ialpha = 255 - spans->coverage;
3467 for (int i = 0; i < spans->len; ++i)
3468 target[i] = c + BYTE_MUL(target[i], ialpha);
3476 uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3477 op.funcSolid(target, spans->len, data->solid.color, spans->coverage);
3483 Q_STATIC_TEMPLATE_FUNCTION void blendColor(int count, const QSpan *spans, void *userData)
3485 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3486 Operator op = getOperator(data, spans, count);
3488 if (op.mode == QPainter::CompositionMode_Source) {
3489 const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(data->solid.color), 0);
3491 T *target = ((T*)data->rasterBuffer->scanLine(spans->y))
3493 if (spans->coverage == 255) {
3494 qt_memfill(target, c, spans->len);
3496 const quint8 alpha = T::alpha(spans->coverage);
3497 const T color = c.byte_mul(alpha);
3498 const int ialpha = T::ialpha(spans->coverage);
3499 const T *end = target + spans->len;
3500 while (target < end) {
3501 *target = color + target->byte_mul(ialpha);
3510 if (op.mode == QPainter::CompositionMode_SourceOver) {
3512 const quint32 color = BYTE_MUL(data->solid.color, spans->coverage);
3513 const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0);
3514 const quint8 ialpha = T::alpha(qAlpha(~color));
3515 T *target = ((T*)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3516 const T *end = target + spans->len;
3517 while (target != end) {
3518 *target = c + target->byte_mul(ialpha);
3526 blend_color_generic(count, spans, userData);
3529 #define SPANFUNC_POINTER_BLENDCOLOR(DST) blendColor<DST>
3531 static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
3533 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3536 We duplicate a little logic from getOperator() and calculate the
3537 composition mode directly. This allows blend_color_rgb16 to be used
3538 from qt_gradient_quint16 with minimal overhead.
3540 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
3541 if (mode == QPainter::CompositionMode_SourceOver &&
3542 qAlpha(data->solid.color) == 255)
3543 mode = QPainter::CompositionMode_Source;
3545 if (mode == QPainter::CompositionMode_Source) {
3546 // inline for performance
3547 ushort c = qConvertRgb32To16(data->solid.color);
3549 ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3550 if (spans->coverage == 255) {
3551 QT_MEMFILL_USHORT(target, spans->len, c);
3553 ushort color = BYTE_MUL_RGB16(c, spans->coverage);
3554 int ialpha = 255 - spans->coverage;
3555 const ushort *end = target + spans->len;
3556 while (target < end) {
3557 *target = color + BYTE_MUL_RGB16(*target, ialpha);
3566 if (mode == QPainter::CompositionMode_SourceOver) {
3568 uint color = BYTE_MUL(data->solid.color, spans->coverage);
3569 int ialpha = qAlpha(~color);
3570 ushort c = qConvertRgb32To16(color);
3571 ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3572 int len = spans->len;
3573 bool pre = (((quintptr)target) & 0x3) != 0;
3576 // skip to word boundary
3577 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3585 uint *target32 = (uint*)target;
3586 uint c32 = c | (c<<16);
3588 uint salpha = (ialpha+1) >> 3; // calculate here rather than in loop
3591 *target32 = c32 + BYTE_MUL_RGB16_32(*target32, salpha);
3596 // one last pixel beyond a full word
3597 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3604 blend_color_generic(count, spans, userData);
3607 template <typename T>
3608 void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
3610 uint const_alpha = 256;
3611 if (data->type == QSpanData::Texture)
3612 const_alpha = data->texture.const_alpha;
3617 const int y = spans->y;
3618 int right = x + spans->len;
3620 // compute length of adjacent spans
3621 for (int i = 1; i < count && spans[i].y == y && spans[i].x == right; ++i)
3622 right += spans[i].len;
3623 int length = right - x;
3626 int l = qMin(buffer_size, length);
3629 int process_length = l;
3632 const uint *src = handler.fetch(process_x, y, process_length);
3635 if (x == spans->x) // new span?
3636 coverage = (spans->coverage * const_alpha) >> 8;
3638 int right = spans->x + spans->len;
3639 int len = qMin(l, right - x);
3641 handler.process(x, y, len, coverage, src, offset);
3647 if (x == right) { // done with current span?
3652 handler.store(process_x, y, process_length);
3659 QBlendBase(QSpanData *d, Operator o)
3671 uint buffer[buffer_size];
3672 uint src_buffer[buffer_size];
3675 template <SpanMethod spanMethod>
3676 class BlendSrcGeneric : public QBlendBase
3679 BlendSrcGeneric(QSpanData *d, Operator o)
3684 const uint *fetch(int x, int y, int len)
3686 if (spanMethod == RegularSpans)
3687 dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, y, len) : buffer;
3689 return op.src_fetch(src_buffer, &op, data, y, x, len);
3692 void process(int x, int y, int len, int coverage, const uint *src, int offset)
3694 if (spanMethod == RegularSpans)
3695 op.func(dest + offset, src + offset, len, coverage);
3697 drawBufferSpan(data, src + offset, len, x, y, len, coverage);
3700 void store(int x, int y, int len)
3702 if (spanMethod == RegularSpans && op.dest_store) {
3703 op.dest_store(data->rasterBuffer, x, y, dest, len);
3708 template <SpanMethod spanMethod>
3709 Q_STATIC_TEMPLATE_FUNCTION void blend_src_generic(int count, const QSpan *spans, void *userData)
3711 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3712 BlendSrcGeneric<spanMethod> blend(data, getOperator(data, spans, count));
3713 handleSpans(count, spans, data, blend);
3716 template <SpanMethod spanMethod>
3717 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
3719 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3721 uint buffer[buffer_size];
3722 uint src_buffer[buffer_size];
3723 Operator op = getOperator(data, spans, count);
3725 const int image_width = data->texture.width;
3726 const int image_height = data->texture.height;
3727 int xoff = -qRound(-data->dx);
3728 int yoff = -qRound(-data->dy);
3732 int length = spans->len;
3734 int sy = yoff + spans->y;
3735 if (sy >= 0 && sy < image_height && sx < image_width) {
3741 if (sx + length > image_width)
3742 length = image_width - sx;
3744 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3746 int l = qMin(buffer_size, length);
3747 const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
3748 if (spanMethod == RegularSpans) {
3749 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3750 op.func(dest, src, l, coverage);
3752 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3754 drawBufferSpan(data, src, l, x, spans->y,
3767 template <SpanMethod spanMethod>
3768 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
3770 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3771 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
3772 && data->texture.format != QImage::Format_RGB32) {
3773 blend_untransformed_generic<spanMethod>(count, spans, userData);
3777 Operator op = getOperator(data, spans, count);
3779 const int image_width = data->texture.width;
3780 const int image_height = data->texture.height;
3781 int xoff = -qRound(-data->dx);
3782 int yoff = -qRound(-data->dy);
3786 int length = spans->len;
3788 int sy = yoff + spans->y;
3789 if (sy >= 0 && sy < image_height && sx < image_width) {
3795 if (sx + length > image_width)
3796 length = image_width - sx;
3798 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3799 const uint *src = (uint *)data->texture.scanLine(sy) + sx;
3800 if (spanMethod == RegularSpans) {
3801 uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
3802 op.func(dest, src, length, coverage);
3804 drawBufferSpan(data, src, length, x,
3805 spans->y, length, coverage);
3813 static inline quint16 interpolate_pixel_rgb16_255(quint16 x, quint8 a,
3814 quint16 y, quint8 b)
3816 quint16 t = ((((x & 0x07e0) * a) + ((y & 0x07e0) * b)) >> 5) & 0x07e0;
3817 t |= ((((x & 0xf81f) * a) + ((y & 0xf81f) * b)) >> 5) & 0xf81f;
3822 static inline quint32 interpolate_pixel_rgb16x2_255(quint32 x, quint8 a,
3823 quint32 y, quint8 b)
3826 t = ((((x & 0xf81f07e0) >> 5) * a) + (((y & 0xf81f07e0) >> 5) * b)) & 0xf81f07e0;
3827 t |= ((((x & 0x07e0f81f) * a) + ((y & 0x07e0f81f) * b)) >> 5) & 0x07e0f81f;
3831 static inline void blend_sourceOver_rgb16_rgb16(quint16 *dest,
3835 const quint8 ialpha)
3837 const int dstAlign = ((quintptr)dest) & 0x3;
3839 *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
3844 const int srcAlign = ((quintptr)src) & 0x3;
3845 int length32 = length >> 1;
3846 if (length32 && srcAlign == 0) {
3847 while (length32--) {
3848 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3849 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3850 *dest32 = interpolate_pixel_rgb16x2_255(*src32, alpha,
3858 *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
3864 template <class DST, class SRC>
3865 Q_STATIC_TEMPLATE_SPECIALIZATION
3866 inline void madd_2(DST *dest, const quint16 alpha, const SRC *src)
3868 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3869 Q_ASSERT((quintptr(src) & 0x3) == 0);
3870 dest[0] = dest[0].byte_mul(alpha >> 8) + DST(src[0]);
3871 dest[1] = dest[1].byte_mul(alpha & 0xff) + DST(src[1]);
3874 template <class DST, class SRC>
3875 Q_STATIC_TEMPLATE_SPECIALIZATION
3876 inline void madd_4(DST *dest, const quint32 alpha, const SRC *src)
3878 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3879 Q_ASSERT((quintptr(src) & 0x3) == 0);
3880 dest[0] = dest[0].byte_mul(alpha >> 24) + DST(src[0]);
3881 dest[1] = dest[1].byte_mul((alpha >> 16) & 0xff) + DST(src[1]);
3882 dest[2] = dest[2].byte_mul((alpha >> 8) & 0xff) + DST(src[2]);
3883 dest[3] = dest[3].byte_mul(alpha & 0xff) + DST(src[3]);
3886 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
3888 Q_STATIC_TEMPLATE_SPECIALIZATION
3889 inline void madd_4(qargb8565 *dest, const quint32 a, const qargb8565 *src)
3891 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3892 Q_ASSERT((quintptr(src) & 0x3) == 0);
3894 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3895 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3906 t = ((((x & 0x0007e0ff) * a8) >> 5) & 0x0007e0ff) + (y & 0x0007c0f8);
3909 t |= ((((x & 0x00f81f00) * a8) >> 5) & 0x00f81f00) + (y & 0x00f81f00);
3911 a8 = (a >> 16) & 0xff;
3914 t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
3923 t = ((((x & 0x0000f81f) * a8) >> 5) & 0x0000f81f) + (y & 0x0000f81f);
3926 t |= ((((x & 0x000007e0) * a8) >> 5) & 0x000007e0) + (y & 0x000007c0);
3928 a8 = (a >> 8) & 0xff;
3931 t |= ((((x & 0x00ff0000) * a8) >> 5) & 0x00ff0000) + (y & 0x00f80000);
3935 quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
3936 quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
3939 t16 = ((((x16 & 0xf81f) * a8) >> 5) & 0xf81f) + (y16 & 0xf81f);
3940 t16 |= ((((x16 & 0x07e0) * a8) >> 5) & 0x07e0) + (y16 & 0x07c0);
3943 t |= ((t16 & 0x00ff) << 24);
3958 t |= ((((x & 0x07e0ff00) * a8) >> 5) & 0x07e0ff00) + (y & 0x07c0f800);
3961 t |= ((((x & 0xf81f0000) >> 5) * a8) & 0xf81f0000)+ (y & 0xf81f0000);
3968 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
3970 Q_STATIC_TEMPLATE_SPECIALIZATION
3971 inline void madd_4(qargb8555 *dest, const quint32 a, const qargb8555 *src)
3973 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3974 Q_ASSERT((quintptr(src) & 0x3) == 0);
3976 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3977 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3988 t = ((((x & 0x0003e0ff) * a8) >> 5) & 0x0003e0ff) + (y & 0x0003e0f8);
3991 t |= ((((x & 0x007c1f00) * a8) >> 5) & 0x007c1f00) + (y & 0x007c1f00);
3993 a8 = (a >> 16) & 0xff;
3996 t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
4005 t = ((((x & 0x00007c1f) * a8) >> 5) & 0x00007c1f) + (y & 0x00007c1f);
4008 t |= ((((x & 0x000003e0) * a8) >> 5) & 0x000003e0) + (y & 0x000003e0);
4010 a8 = (a >> 8) & 0xff;
4013 t |= ((((x & 0x00ff0000) * a8) >> 5) & 0x00ff0000) + (y & 0x00f80000);
4017 quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
4018 quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
4021 t16 = ((((x16 & 0x7c1f) * a8) >> 5) & 0x7c1f) + (y16 & 0x7c1f);
4022 t16 |= ((((x16 & 0x03e0) * a8) >> 5) & 0x03e0) + (y16 & 0x03e0);
4025 t |= ((t16 & 0x00ff) << 24);
4040 t |= ((((x & 0x03e0ff00) * a8) >> 5) & 0x03e0ff00) + (y & 0x03e0f800);
4043 t |= ((((x & 0x7c1f0000) >> 5) * a8) & 0x7c1f0000)+ (y & 0x7c1f0000);
4051 Q_STATIC_TEMPLATE_SPECIALIZATION
4052 inline quint16 alpha_2(const T *src)
4054 Q_ASSERT((quintptr(src) & 0x3) == 0);
4057 return (src[0].alpha() << 8) | src[1].alpha();
4063 Q_STATIC_TEMPLATE_SPECIALIZATION
4064 inline quint32 alpha_4(const T *src)
4066 Q_ASSERT((quintptr(src) & 0x3) == 0);
4068 if (T::hasAlpha()) {
4069 return (src[0].alpha() << 24) | (src[1].alpha() << 16)
4070 | (src[2].alpha() << 8) | src[3].alpha();
4077 Q_STATIC_TEMPLATE_SPECIALIZATION
4078 inline quint32 alpha_4(const qargb8565 *src)
4080 const quint8 *src8 = reinterpret_cast<const quint8*>(src);
4081 return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
4085 Q_STATIC_TEMPLATE_SPECIALIZATION
4086 inline quint32 alpha_4(const qargb6666 *src)
4088 const quint8 *src8 = reinterpret_cast<const quint8*>(src);
4089 return ((src8[2] & 0xfc) | (src8[2] >> 6)) << 24
4090 | ((src8[5] & 0xfc) | (src8[5] >> 6)) << 16
4091 | ((src8[8] & 0xfc) | (src8[8] >> 6)) << 8
4092 | ((src8[11] & 0xfc) | (src8[11] >> 6));
4096 Q_STATIC_TEMPLATE_SPECIALIZATION
4097 inline quint32 alpha_4(const qargb8555 *src)
4099 Q_ASSERT((quintptr(src) & 0x3) == 0);
4100 const quint8 *src8 = reinterpret_cast<const quint8*>(src);
4101 return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
4105 Q_STATIC_TEMPLATE_SPECIALIZATION
4106 inline quint16 alpha_2(const qargb4444 *src)
4108 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4109 const quint32 t = (*src32 & 0xf000f000) |
4110 ((*src32 & 0xf000f000) >> 4);
4111 return (t >> 24) | (t & 0xff00);
4115 Q_STATIC_TEMPLATE_SPECIALIZATION
4116 inline quint16 eff_alpha_2(quint16 alpha, const T*)
4118 return (T::alpha((alpha >> 8) & 0xff) << 8)
4119 | T::alpha(alpha & 0xff);
4123 Q_STATIC_TEMPLATE_SPECIALIZATION
4124 inline quint16 eff_alpha_2(quint16 a, const qrgb565*)
4126 return ((((a & 0xff00) + 0x0100) >> 3) & 0xff00)
4127 | ((((a & 0x00ff) + 0x0001) >> 3) & 0x00ff);
4131 Q_STATIC_TEMPLATE_SPECIALIZATION
4132 inline quint16 eff_alpha_2(quint16 a, const qrgb444*)
4134 return (((a & 0x00ff) + 0x0001) >> 4)
4135 | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
4139 Q_STATIC_TEMPLATE_SPECIALIZATION
4140 inline quint16 eff_alpha_2(quint16 a, const qargb4444*)
4142 return (((a & 0x00ff) + 0x0001) >> 4)
4143 | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
4147 Q_STATIC_TEMPLATE_SPECIALIZATION
4148 inline quint16 eff_ialpha_2(quint16 alpha, const T*)
4150 return (T::ialpha((alpha >> 8) & 0xff) << 8)
4151 | T::ialpha(alpha & 0xff);
4155 Q_STATIC_TEMPLATE_SPECIALIZATION
4156 inline quint16 eff_ialpha_2(quint16 a, const qrgb565 *dummy)
4158 return 0x2020 - eff_alpha_2(a, dummy);
4162 Q_STATIC_TEMPLATE_SPECIALIZATION
4163 inline quint16 eff_ialpha_2(quint16 a, const qargb4444 *dummy)
4165 return 0x1010 - eff_alpha_2(a, dummy);
4169 Q_STATIC_TEMPLATE_SPECIALIZATION
4170 inline quint16 eff_ialpha_2(quint16 a, const qrgb444 *dummy)
4172 return 0x1010 - eff_alpha_2(a, dummy);
4176 Q_STATIC_TEMPLATE_SPECIALIZATION
4177 inline quint32 eff_alpha_4(quint32 alpha, const T*)
4179 return (T::alpha(alpha >> 24) << 24)
4180 | (T::alpha((alpha >> 16) & 0xff) << 16)
4181 | (T::alpha((alpha >> 8) & 0xff) << 8)
4182 | T::alpha(alpha & 0xff);
4186 Q_STATIC_TEMPLATE_SPECIALIZATION
4187 inline quint32 eff_alpha_4(quint32 a, const qrgb888*)
4193 Q_STATIC_TEMPLATE_SPECIALIZATION
4194 inline quint32 eff_alpha_4(quint32 a, const qargb8565*)
4196 return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
4197 | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
4201 Q_STATIC_TEMPLATE_SPECIALIZATION
4202 inline quint32 eff_alpha_4(quint32 a, const qargb6666*)
4204 return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
4205 | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
4209 Q_STATIC_TEMPLATE_SPECIALIZATION
4210 inline quint32 eff_alpha_4(quint32 a, const qrgb666*)
4212 return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
4213 | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
4217 Q_STATIC_TEMPLATE_SPECIALIZATION
4218 inline quint32 eff_alpha_4(quint32 a, const qargb8555*)
4220 return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
4221 | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
4225 Q_STATIC_TEMPLATE_SPECIALIZATION
4226 inline quint32 eff_ialpha_4(quint32 alpha, const T*)
4228 return (T::ialpha(alpha >> 24) << 24)
4229 | (T::ialpha((alpha >> 16) & 0xff) << 16)
4230 | (T::ialpha((alpha >> 8) & 0xff) << 8)
4231 | T::ialpha(alpha & 0xff);
4235 Q_STATIC_TEMPLATE_SPECIALIZATION
4236 inline quint32 eff_ialpha_4(quint32 a, const qrgb888*)
4242 Q_STATIC_TEMPLATE_SPECIALIZATION
4243 inline quint32 eff_ialpha_4(quint32 a, const qargb8565 *dummy)
4245 return 0x20202020 - eff_alpha_4(a, dummy);
4249 Q_STATIC_TEMPLATE_SPECIALIZATION
4250 inline quint32 eff_ialpha_4(quint32 a, const qargb6666 *dummy)
4252 return 0x40404040 - eff_alpha_4(a, dummy);
4256 Q_STATIC_TEMPLATE_SPECIALIZATION
4257 inline quint32 eff_ialpha_4(quint32 a, const qrgb666 *dummy)
4259 return 0x40404040 - eff_alpha_4(a, dummy);
4263 Q_STATIC_TEMPLATE_SPECIALIZATION
4264 inline quint32 eff_ialpha_4(quint32 a, const qargb8555 *dummy)
4266 return 0x20202020 - eff_alpha_4(a, dummy);
4269 template <class DST, class SRC>
4270 inline void interpolate_pixel_unaligned_2(DST *dest, const SRC *src,
4273 const quint16 a = eff_alpha_2(alpha, dest);
4274 const quint16 ia = eff_ialpha_2(alpha, dest);
4275 dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
4276 dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
4279 template <class DST, class SRC>
4280 inline void interpolate_pixel_2(DST *dest, const SRC *src, quint16 alpha)
4282 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4283 Q_ASSERT((quintptr(src) & 0x3) == 0);
4285 const quint16 a = eff_alpha_2(alpha, dest);
4286 const quint16 ia = eff_ialpha_2(alpha, dest);
4288 dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
4289 dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
4292 template <class DST, class SRC>
4293 inline void interpolate_pixel(DST &dest, quint8 a, const SRC &src, quint8 b)
4295 if (SRC::hasAlpha() && !DST::hasAlpha())
4296 interpolate_pixel(dest, a, DST(src), b);
4298 dest = dest.byte_mul(a) + DST(src).byte_mul(b);
4302 inline void interpolate_pixel(qargb8565 &dest, quint8 a,
4303 const qargb8565 &src, quint8 b)
4305 quint8 *d = reinterpret_cast<quint8*>(&dest);
4306 const quint8 *s = reinterpret_cast<const quint8*>(&src);
4307 d[0] = (d[0] * a + s[0] * b) >> 5;
4309 const quint16 x = (d[2] << 8) | d[1];
4310 const quint16 y = (s[2] << 8) | s[1];
4311 quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
4312 t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
4319 inline void interpolate_pixel(qrgb565 &dest, quint8 a,
4320 const qrgb565 &src, quint8 b)
4322 const quint16 x = dest.rawValue();
4323 const quint16 y = src.rawValue();
4324 quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
4325 t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
4330 inline void interpolate_pixel(qrgb555 &dest, quint8 a,
4331 const qrgb555 &src, quint8 b)
4333 const quint16 x = dest.rawValue();
4334 const quint16 y = src.rawValue();
4335 quint16 t = (((x & 0x03e0) * a + (y & 0x03e0) * b) >> 5) & 0x03e0;
4336 t |= ((((x & 0x7c1f) * a) + ((y & 0x7c1f) * b)) >> 5) & 0x7c1f;
4341 inline void interpolate_pixel(qrgb444 &dest, quint8 a,
4342 const qrgb444 &src, quint8 b)
4344 const quint16 x = dest.rawValue();
4345 const quint16 y = src.rawValue();
4346 quint16 t = ((x & 0x00f0) * a + (y & 0x00f0) * b) & 0x0f00;
4347 t |= ((x & 0x0f0f) * a + (y & 0x0f0f) * b) & 0xf0f0;
4348 quint16 *d = reinterpret_cast<quint16*>(&dest);
4352 template <class DST, class SRC>
4353 inline void interpolate_pixel_2(DST *dest, quint8 a,
4354 const SRC *src, quint8 b)
4356 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4357 Q_ASSERT((quintptr(src) & 0x3) == 0);
4359 Q_ASSERT(!SRC::hasAlpha());
4361 dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
4362 dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
4366 inline void interpolate_pixel_2(qrgb565 *dest, quint8 a,
4367 const qrgb565 *src, quint8 b)
4369 quint32 *x = reinterpret_cast<quint32*>(dest);
4370 const quint32 *y = reinterpret_cast<const quint32*>(src);
4371 quint32 t = (((*x & 0xf81f07e0) >> 5) * a +
4372 ((*y & 0xf81f07e0) >> 5) * b) & 0xf81f07e0;
4373 t |= (((*x & 0x07e0f81f) * a
4374 + (*y & 0x07e0f81f) * b) >> 5) & 0x07e0f81f;
4379 inline void interpolate_pixel_2(qrgb555 *dest, quint8 a,
4380 const qrgb555 *src, quint8 b)
4382 quint32 *x = reinterpret_cast<quint32*>(dest);
4383 const quint32 *y = reinterpret_cast<const quint32*>(src);
4384 quint32 t = (((*x & 0x7c1f03e0) >> 5) * a +
4385 ((*y & 0x7c1f03e0) >> 5) * b) & 0x7c1f03e0;
4386 t |= (((*x & 0x03e07c1f) * a
4387 + (*y & 0x03e07c1f) * b) >> 5) & 0x03e07c1f;
4392 inline void interpolate_pixel_2(qrgb444 *dest, quint8 a,
4393 const qrgb444 *src, quint8 b)
4395 quint32 *x = reinterpret_cast<quint32*>(dest);
4396 const quint32 *y = reinterpret_cast<const quint32*>(src);
4397 quint32 t = ((*x & 0x0f0f0f0f) * a + (*y & 0x0f0f0f0f) * b) & 0xf0f0f0f0;
4398 t |= ((*x & 0x00f000f0) * a + (*y & 0x00f000f0) * b) & 0x0f000f00;
4402 template <class DST, class SRC>
4403 inline void interpolate_pixel_4(DST *dest, const SRC *src, quint32 alpha)
4405 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4406 Q_ASSERT((quintptr(src) & 0x3) == 0);
4408 const quint32 a = eff_alpha_4(alpha, dest);
4409 const quint32 ia = eff_ialpha_4(alpha, dest);
4410 dest[0] = DST(src[0]).byte_mul(a >> 24)
4411 + dest[0].byte_mul(ia >> 24);
4412 dest[1] = DST(src[1]).byte_mul((a >> 16) & 0xff)
4413 + dest[1].byte_mul((ia >> 16) & 0xff);
4414 dest[2] = DST(src[2]).byte_mul((a >> 8) & 0xff)
4415 + dest[2].byte_mul((ia >> 8) & 0xff);
4416 dest[3] = DST(src[3]).byte_mul(a & 0xff)
4417 + dest[3].byte_mul(ia & 0xff);
4420 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4422 inline void interpolate_pixel_4(qargb8565 *dest, const qargb8565 *src,
4425 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4426 Q_ASSERT((quintptr(src) & 0x3) == 0);
4428 const quint32 a = eff_alpha_4(alpha, dest);
4429 const quint32 ia = eff_ialpha_4(alpha, dest);
4430 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4431 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4443 t = (((x & 0x0007e0ff) * a8 + (y & 0x0007e0ff) * ia8) >> 5)
4447 t |= (((x & 0x00f81f00) * a8 + (y & 0x00f81f00) * ia8) >> 5)
4450 a8 = (a >> 16) & 0xff;
4451 ia8 = (ia >> 16) & 0xff;
4454 t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
4464 t = (((x & 0x0000f81f) * a8 + (y & 0x0000f81f) * ia8) >> 5)
4468 t |= (((x & 0x000007e0) * a8 + (y & 0x000007e0) * ia8) >> 5)
4471 a8 = (a >> 8) & 0xff;
4472 ia8 = (ia >> 8) & 0xff;
4475 t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
4480 quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
4481 quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
4484 t16 = (((x16 & 0xf81f) * a8 + (y16 & 0xf81f) * ia8) >> 5) & 0xf81f;
4485 t16 |= (((x16 & 0x07e0) * a8 + (y16 & 0x07e0) * ia8) >> 5) & 0x07e0;
4488 t |= ((t16 & 0x00ff) << 24);
4504 t |= (((x & 0x07e0ff00) * a8 + (y & 0x07e0ff00) * ia8) >> 5)
4508 t |= (((x & 0xf81f0000) >> 5) * a8 + ((y & 0xf81f0000) >> 5) * ia8)
4516 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4518 inline void interpolate_pixel_4(qargb8555 *dest, const qargb8555 *src,
4521 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4522 Q_ASSERT((quintptr(src) & 0x3) == 0);
4525 const quint32 a = eff_alpha_4(alpha, dest);
4526 const quint32 ia = eff_ialpha_4(alpha, dest);
4527 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4528 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4540 t = (((x & 0x0003e0ff) * a8 + (y & 0x0003e0ff) * ia8) >> 5)
4544 t |= (((x & 0x007c1f00) * a8 + (y & 0x007c1f00) * ia8) >> 5)
4547 a8 = (a >> 16) & 0xff;
4548 ia8 = (ia >> 16) & 0xff;
4551 t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
4561 t = (((x & 0x00007c1f) * a8 + (y & 0x00007c1f) * ia8) >> 5)
4565 t |= (((x & 0x000003e0) * a8 + (y & 0x000003e0) * ia8) >> 5)
4568 a8 = (a >> 8) & 0xff;
4569 ia8 = (ia >> 8) & 0xff;
4572 t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
4577 quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
4578 quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
4581 t16 = (((x16 & 0x7c1f) * a8 + (y16 & 0x7c1f) * ia8) >> 5) & 0x7c1f;
4582 t16 |= (((x16 & 0x03e0) * a8 + (y16 & 0x03e0) * ia8) >> 5) & 0x03e0;
4585 t |= ((t16 & 0x00ff) << 24);
4601 t |= (((x & 0x03e0ff00) * a8 + (y & 0x03e0ff00) * ia8) >> 5)
4605 t |= (((x & 0x7c1f0000) >> 5) * a8 + ((y & 0x7c1f0000) >> 5) * ia8)
4614 inline void interpolate_pixel_4(qrgb888 *dest, const qrgb888 *src,
4617 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4618 Q_ASSERT((quintptr(src) & 0x3) == 0);
4620 const quint32 a = eff_alpha_4(alpha, dest);
4621 const quint32 ia = eff_ialpha_4(alpha, dest);
4622 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4623 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4626 quint32 x = src32[0];
4627 quint32 y = dest32[0];
4630 t = ((x >> 8) & 0xff00ff) * (a >> 24)
4631 + ((y >> 8) & 0xff00ff) * (ia >> 24);
4632 t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4635 x = (x & 0xff0000) * (a >> 24)
4636 + (x & 0x0000ff) * ((a >> 16) & 0xff)
4637 + (y & 0xff0000) * (ia >> 24)
4638 + (y & 0x0000ff) * ((ia >> 16) & 0xff);
4639 x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4645 quint32 x = src32[1];
4646 quint32 y = dest32[1];
4649 t = ((x >> 8) & 0xff0000) * ((a >> 16) & 0xff)
4650 + ((x >> 8) & 0x0000ff) * ((a >> 8) & 0xff)
4651 + ((y >> 8) & 0xff0000) * ((ia >> 16) & 0xff)
4652 + ((y >> 8) & 0x0000ff) * ((ia >> 8) & 0xff);
4653 t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4656 x = (x & 0xff0000) * ((a >> 16) & 0xff)
4657 + (x & 0x0000ff) * ((a >> 8) & 0xff)
4658 + (y & 0xff0000) * ((ia >> 16) & 0xff)
4659 + (y & 0x0000ff) * ((ia >> 8) & 0xff);
4660 x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4666 quint32 x = src32[2];
4667 quint32 y = dest32[2];
4670 t = ((x >> 8) & 0xff0000) * ((a >> 8) & 0xff)
4671 + ((x >> 8) & 0x0000ff) * (a & 0xff)
4672 + ((y >> 8) & 0xff0000) * ((ia >> 8) & 0xff)
4673 + ((y >> 8) & 0x0000ff) * (ia & 0xff);
4674 t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4677 x = (x & 0xff00ff) * (a & 0xff)
4678 + (y & 0xff00ff) * (ia & 0xff);
4679 x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4686 template <class DST, class SRC>
4687 inline void interpolate_pixel_4(DST *dest, quint8 a,
4688 const SRC *src, quint8 b)
4690 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4691 Q_ASSERT((quintptr(src) & 0x3) == 0);
4693 dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
4694 dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
4695 dest[2] = dest[2].byte_mul(a) + DST(src[2]).byte_mul(b);
4696 dest[3] = dest[3].byte_mul(a) + DST(src[3]).byte_mul(b);
4699 template <class DST, class SRC>
4700 inline void blend_sourceOver_4(DST *dest, const SRC *src)
4702 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4703 Q_ASSERT((quintptr(src) & 0x3) == 0);
4705 const quint32 a = alpha_4(src);
4706 if (a == 0xffffffff) {
4707 qt_memconvert(dest, src, 4);
4709 quint32 buf[3]; // array of quint32 to get correct alignment
4710 qt_memconvert((DST*)(void*)buf, src, 4);
4711 madd_4(dest, eff_ialpha_4(a, dest), (DST*)(void*)buf);
4716 inline void blend_sourceOver_4(qargb8565 *dest, const qargb8565 *src)
4718 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4719 Q_ASSERT((quintptr(src) & 0x3) == 0);
4721 const quint32 a = alpha_4(src);
4722 if (a == 0xffffffff) {
4723 qt_memconvert(dest, src, 4);
4725 madd_4(dest, eff_ialpha_4(a, dest), src);
4730 inline void blend_sourceOver_4(qargb8555 *dest, const qargb8555 *src)
4732 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4733 Q_ASSERT((quintptr(src) & 0x3) == 0);
4735 const quint32 a = alpha_4(src);
4736 if (a == 0xffffffff) {
4737 qt_memconvert(dest, src, 4);
4739 madd_4(dest, eff_ialpha_4(a, dest), src);
4744 inline void blend_sourceOver_4(qargb6666 *dest, const qargb6666 *src)
4746 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4747 Q_ASSERT((quintptr(src) & 0x3) == 0);
4749 const quint32 a = alpha_4(src);
4750 if (a == 0xffffffff) {
4751 qt_memconvert(dest, src, 4);
4753 madd_4(dest, eff_ialpha_4(a, dest), src);
4757 template <class DST, class SRC>
4758 void QT_FASTCALL blendUntransformed_unaligned(DST *dest, const SRC *src,
4759 quint8 coverage, int length)
4761 Q_ASSERT(coverage > 0);
4763 if (coverage < 255) {
4764 if (SRC::hasAlpha()) {
4765 for (int i = 0; i < length; ++i) {
4766 if (src[i].alpha()) {
4767 const quint8 alpha = qt_div_255(int(src[i].alpha()) * int(coverage));
4768 interpolate_pixel(dest[i], DST::ialpha(alpha),
4769 src[i], DST::alpha(alpha));
4773 const quint8 alpha = DST::alpha(coverage);
4774 const quint8 ialpha = DST::ialpha(coverage);
4776 for (int i = 0; i < length; ++i)
4777 interpolate_pixel(dest[i], ialpha, src[i], alpha);
4783 Q_ASSERT(coverage == 0xff);
4784 Q_ASSERT(SRC::hasAlpha());
4786 if (SRC::hasAlpha()) {
4787 for (int i = 0; i < length; ++i) {
4788 const quint8 a = src->alpha();
4792 if (DST::hasAlpha())
4793 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4795 *dest = DST(SRC(*src).truncedAlpha()) + dest->byte_mul(DST::ialpha(a));
4803 template <class DST, class SRC>
4804 void QT_FASTCALL blendUntransformed_dest16(DST *dest, const SRC *src,
4805 quint8 coverage, int length)
4807 Q_ASSERT(sizeof(DST) == 2);
4808 Q_ASSERT(sizeof(SRC) == 2);
4809 Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
4810 Q_ASSERT(coverage > 0);
4812 const int align = quintptr(dest) & 0x3;
4814 if (coverage < 255) {
4817 const quint8 alpha = SRC::hasAlpha()
4818 ? qt_div_255(int(src->alpha()) * int(coverage))
4821 interpolate_pixel(*dest, DST::ialpha(alpha),
4822 *src, DST::alpha(alpha));
4829 if (SRC::hasAlpha()) {
4830 while (length >= 2) {
4831 const quint16 alpha16 = BYTE_MUL(uint(alpha_2(src)), uint(coverage));
4832 interpolate_pixel_2(dest, src, alpha16);
4838 const quint8 alpha = DST::alpha(coverage);
4839 const quint8 ialpha = DST::ialpha(coverage);
4841 while (length >= 2) {
4842 interpolate_pixel_2(dest, ialpha, src, alpha);
4851 const quint8 alpha = SRC::hasAlpha()
4852 ? qt_div_255(int(src->alpha()) * int(coverage))
4855 interpolate_pixel(*dest, DST::ialpha(alpha),
4856 *src, DST::alpha(alpha));
4863 Q_ASSERT(SRC::hasAlpha());
4864 if (SRC::hasAlpha()) {
4866 const quint8 alpha = src->alpha();
4870 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
4876 while (length >= 2) {
4877 Q_ASSERT((quintptr(dest) & 3) == 0);
4878 Q_ASSERT((quintptr(src) & 3) == 0);
4880 const quint16 a = alpha_2(src);
4882 qt_memconvert(dest, src, 2);
4885 if (sizeof(DST) == 2)
4886 qt_memconvert((DST*)(void*)&buf, src, 2);
4887 madd_2(dest, eff_ialpha_2(a, dest), (DST*)(void*)&buf);
4896 const quint8 alpha = src->alpha();
4900 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
4905 template <class DST, class SRC>
4906 void QT_FASTCALL blendUntransformed_dest24(DST *dest, const SRC *src,
4907 quint8 coverage, int length)
4909 Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
4910 Q_ASSERT(sizeof(DST) == 3);
4911 Q_ASSERT(coverage > 0);
4913 const int align = quintptr(dest) & 0x3;
4915 if (coverage < 255) {
4917 for (int i = 0; i < align; ++i) {
4918 if (SRC::hasAlpha()) {
4919 const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
4921 interpolate_pixel(*dest, DST::ialpha(alpha),
4922 *src, DST::alpha(alpha));
4924 interpolate_pixel(*dest, DST::ialpha(coverage),
4925 *src, DST::alpha(coverage));
4932 if (SRC::hasAlpha()) {
4933 while (length >= 4) {
4934 const quint32 alpha = QT_PREPEND_NAMESPACE(BYTE_MUL)(uint(alpha_4(src)), uint(coverage));
4936 interpolate_pixel_4(dest, src, alpha);
4942 const quint8 alpha = DST::alpha(coverage);
4943 const quint8 ialpha = DST::ialpha(coverage);
4944 while (length >= 4) {
4945 interpolate_pixel_4(dest, ialpha, src, alpha);
4954 if (SRC::hasAlpha()) {
4955 const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
4957 interpolate_pixel(*dest, DST::ialpha(alpha),
4958 *src, DST::alpha(alpha));
4960 interpolate_pixel(*dest, DST::ialpha(coverage),
4961 *src, DST::alpha(coverage));
4971 Q_ASSERT(coverage == 255);
4972 Q_ASSERT(SRC::hasAlpha());
4974 if (SRC::hasAlpha()) {
4976 for (int i = 0; i < align; ++i) {
4977 const quint8 a = src->alpha();
4981 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4988 while (length >= 4) {
4989 blend_sourceOver_4(dest, src);
4997 const quint8 a = src->alpha();
5001 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
5009 template <class DST, class SRC>
5010 Q_STATIC_TEMPLATE_SPECIALIZATION
5011 void QT_FASTCALL blendUntransformed(int count, const QSpan *spans, void *userData)
5013 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5014 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5016 if (mode != QPainter::CompositionMode_SourceOver &&
5017 mode != QPainter::CompositionMode_Source)
5019 blend_src_generic<RegularSpans>(count, spans, userData);
5023 const bool modeSource = !SRC::hasAlpha() ||
5024 mode == QPainter::CompositionMode_Source;
5025 const int image_width = data->texture.width;
5026 const int image_height = data->texture.height;
5027 int xoff = -qRound(-data->dx);
5028 int yoff = -qRound(-data->dy);
5031 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5032 if (coverage == 0) {
5038 int length = spans->len;
5040 int sy = yoff + spans->y;
5041 if (sy >= 0 && sy < image_height && sx < image_width) {
5047 if (sx + length > image_width)
5048 length = image_width - sx;
5050 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5051 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5052 if (modeSource && coverage == 255) {
5053 qt_memconvert<DST, SRC>(dest, src, length);
5054 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && length >= 3 &&
5055 (quintptr(dest) & 3) == (quintptr(src) & 3))
5057 blendUntransformed_dest24(dest, src, coverage, length);
5058 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && length >= 3 &&
5059 (quintptr(dest) & 3) == (quintptr(src) & 3))
5061 blendUntransformed_dest16(dest, src, coverage, length);
5063 blendUntransformed_unaligned(dest, src, coverage, length);
5071 static void blend_untransformed_rgb888(int count, const QSpan *spans,
5074 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5077 static void blend_untransformed_argb6666(int count, const QSpan *spans,
5080 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5083 static void blend_untransformed_rgb666(int count, const QSpan *spans,
5086 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5089 static void blend_untransformed_argb8565(int count, const QSpan *spans,
5092 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5095 static void blend_untransformed_rgb565(int count, const QSpan *spans,
5098 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5100 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5101 blendUntransformed<qrgb565, qargb8565>(count, spans, userData);
5102 else if (data->texture.format == QImage::Format_RGB16)
5103 blendUntransformed<qrgb565, qrgb565>(count, spans, userData);
5105 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5108 static void blend_untransformed_argb8555(int count, const QSpan *spans,
5111 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5114 static void blend_untransformed_rgb555(int count, const QSpan *spans,
5117 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5120 static void blend_untransformed_argb4444(int count, const QSpan *spans,
5123 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5126 static void blend_untransformed_rgb444(int count, const QSpan *spans,
5129 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5132 template <SpanMethod spanMethod>
5133 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_generic(int count, const QSpan *spans, void *userData)
5135 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5137 uint buffer[buffer_size];
5138 uint src_buffer[buffer_size];
5139 Operator op = getOperator(data, spans, count);
5141 const int image_width = data->texture.width;
5142 const int image_height = data->texture.height;
5143 int xoff = -qRound(-data->dx) % image_width;
5144 int yoff = -qRound(-data->dy) % image_height;
5147 xoff += image_width;
5149 yoff += image_height;
5153 int length = spans->len;
5154 int sx = (xoff + spans->x) % image_width;
5155 int sy = (spans->y + yoff) % image_height;
5161 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5163 int l = qMin(image_width - sx, length);
5164 if (buffer_size < l)
5166 const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
5167 if (spanMethod == RegularSpans) {
5168 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
5169 op.func(dest, src, l, coverage);
5171 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
5173 drawBufferSpan(data, src, l, x, spans->y, l,
5179 if (sx >= image_width)
5186 template <SpanMethod spanMethod>
5187 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_argb(int count, const QSpan *spans, void *userData)
5189 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5190 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
5191 && data->texture.format != QImage::Format_RGB32) {
5192 blend_tiled_generic<spanMethod>(count, spans, userData);
5196 Operator op = getOperator(data, spans, count);
5198 int image_width = data->texture.width;
5199 int image_height = data->texture.height;
5200 int xoff = -qRound(-data->dx) % image_width;
5201 int yoff = -qRound(-data->dy) % image_height;
5204 xoff += image_width;
5206 yoff += image_height;
5210 int length = spans->len;
5211 int sx = (xoff + spans->x) % image_width;
5212 int sy = (spans->y + yoff) % image_height;
5218 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5220 int l = qMin(image_width - sx, length);
5221 if (buffer_size < l)
5223 const uint *src = (uint *)data->texture.scanLine(sy) + sx;
5224 if (spanMethod == RegularSpans) {
5225 uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
5226 op.func(dest, src, l, coverage);
5228 drawBufferSpan(data, src, buffer_size,
5229 x, spans->y, l, coverage);
5239 template <class DST, class SRC>
5240 Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *userData)
5242 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5243 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5245 if (mode != QPainter::CompositionMode_SourceOver &&
5246 mode != QPainter::CompositionMode_Source)
5248 blend_src_generic<RegularSpans>(count, spans, userData);
5252 const bool modeSource = !SRC::hasAlpha() ||
5253 mode == QPainter::CompositionMode_Source;
5254 const int image_width = data->texture.width;
5255 const int image_height = data->texture.height;
5256 int xoff = -qRound(-data->dx) % image_width;
5257 int yoff = -qRound(-data->dy) % image_height;
5260 xoff += image_width;
5262 yoff += image_height;
5265 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5266 if (coverage == 0) {
5272 int length = spans->len;
5273 int sx = (xoff + spans->x) % image_width;
5274 int sy = (spans->y + yoff) % image_height;
5280 if (modeSource && coverage == 255) {
5281 // Copy the first texture block
5282 length = qMin(image_width,length);
5285 int l = qMin(image_width - sx, length);
5286 if (buffer_size < l)
5288 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + tx;
5289 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5291 qt_memconvert<DST, SRC>(dest, src, l);
5297 // Now use the rasterBuffer as the source of the texture,
5298 // We can now progressively copy larger blocks
5299 // - Less cpu time in code figuring out what to copy
5300 // We are dealing with one block of data
5301 // - More likely to fit in the cache
5303 int copy_image_width = qMin(image_width, int(spans->len));
5304 length = spans->len - copy_image_width;
5305 DST *src = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5306 DST *dest = src + copy_image_width;
5307 while (copy_image_width < length) {
5308 qt_memconvert(dest, src, copy_image_width);
5309 dest += copy_image_width;
5310 length -= copy_image_width;
5311 copy_image_width *= 2;
5314 qt_memconvert(dest, src, length);
5317 int l = qMin(image_width - sx, length);
5318 if (buffer_size < l)
5320 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5321 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5322 if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5323 (quintptr(dest) & 3) == (quintptr(src) & 3))
5325 blendUntransformed_dest24(dest, src, coverage, l);
5326 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5327 (quintptr(dest) & 3) == (quintptr(src) & 3))
5329 blendUntransformed_dest16(dest, src, coverage, l);
5331 blendUntransformed_unaligned(dest, src, coverage, l);
5343 static void blend_tiled_rgb888(int count, const QSpan *spans, void *userData)
5345 blend_tiled_generic<RegularSpans>(count, spans, userData);
5348 static void blend_tiled_argb6666(int count, const QSpan *spans, void *userData)
5350 blend_tiled_generic<RegularSpans>(count, spans, userData);
5353 static void blend_tiled_rgb666(int count, const QSpan *spans, void *userData)
5355 blend_tiled_generic<RegularSpans>(count, spans, userData);
5358 static void blend_tiled_argb8565(int count, const QSpan *spans, void *userData)
5360 blend_tiled_generic<RegularSpans>(count, spans, userData);
5363 static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
5365 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5367 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5368 blendTiled<qrgb565, qargb8565>(count, spans, userData);
5369 else if (data->texture.format == QImage::Format_RGB16)
5370 blendTiled<qrgb565, qrgb565>(count, spans, userData);
5372 blend_tiled_generic<RegularSpans>(count, spans, userData);
5375 static void blend_tiled_argb8555(int count, const QSpan *spans, void *userData)
5377 blend_tiled_generic<RegularSpans>(count, spans, userData);
5380 static void blend_tiled_rgb555(int count, const QSpan *spans, void *userData)
5382 blend_tiled_generic<RegularSpans>(count, spans, userData);
5385 static void blend_tiled_argb4444(int count, const QSpan *spans, void *userData)
5387 blend_tiled_generic<RegularSpans>(count, spans, userData);
5390 static void blend_tiled_rgb444(int count, const QSpan *spans, void *userData)
5392 blend_tiled_generic<RegularSpans>(count, spans, userData);
5395 template <class DST, class SRC>
5396 Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan *spans,
5399 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5400 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5403 if (mode != QPainter::CompositionMode_SourceOver) {
5404 blend_src_generic<RegularSpans>(count, spans, userData);
5408 SRC buffer[buffer_size];
5410 const int src_minx = data->texture.x1;
5411 const int src_miny = data->texture.y1;
5412 const int src_maxx = data->texture.x2 - 1;
5413 const int src_maxy = data->texture.y2 - 1;
5415 if (data->fast_matrix) {
5416 // The increment pr x in the scanline
5417 const int fdx = (int)(data->m11 * fixed_scale);
5418 const int fdy = (int)(data->m12 * fixed_scale);
5421 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5422 if (coverage == 0) {
5427 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5429 const qreal cx = spans->x + qreal(0.5);
5430 const qreal cy = spans->y + qreal(0.5);
5431 int x = int((data->m21 * cy
5432 + data->m11 * cx + data->dx) * fixed_scale) - half_point;
5433 int y = int((data->m22 * cy
5434 + data->m12 * cx + data->dy) * fixed_scale) - half_point;
5435 int length = spans->len;
5438 const int l = qMin(length, buffer_size);
5440 const SRC *end = buffer + l;
5448 const int distx = (x & 0x0000ffff) >> 8;
5449 const int disty = (y & 0x0000ffff) >> 8;
5451 if (x1 < src_minx) {
5453 } else if (x1 >= src_maxx) {
5458 if (y1 < src_miny) {
5460 } else if (y1 >= src_maxy) {
5468 *b = ((SRC*)data->texture.scanLine(y1))[x1];
5470 *b = ((SRC*)data->texture.scanLine(y1))[x1];
5471 const SRC t = data->texture.scanLine(y2)[x1];
5472 interpolate_pixel(*b, SRC::ialpha(disty),
5473 t, SRC::alpha(disty));
5475 } else if (y1 == y2) {
5476 *b = ((SRC*)data->texture.scanLine(y1))[x1];
5477 const SRC t = ((SRC*)data->texture.scanLine(y1))[x2];
5478 interpolate_pixel(*b, SRC::ialpha(distx),
5479 t, SRC::alpha(distx));
5483 const SRC *src1 = (SRC*)data->texture.scanLine(y1);
5484 const SRC *src2 = (SRC*)data->texture.scanLine(y2);
5486 const SRC tr = src1[x2];
5488 const SRC br = src2[x2];
5489 const quint8 ax = SRC::alpha(distx);
5490 const quint8 iax = SRC::ialpha(distx);
5492 interpolate_pixel(tl, iax, tr, ax);
5493 interpolate_pixel(bl, iax, br, ax);
5494 interpolate_pixel(tl, SRC::ialpha(disty),
5495 bl, SRC::alpha(disty));
5504 if (!SRC::hasAlpha() && coverage == 255) {
5505 qt_memconvert(dest, buffer, l);
5506 } else if (sizeof(DST) == 3 && l >= 4 &&
5507 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5509 blendUntransformed_dest24(dest, buffer, coverage, l);
5510 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5511 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5512 blendUntransformed_dest16(dest, buffer, coverage, l);
5514 blendUntransformed_unaligned(dest, buffer, coverage, l);
5523 const qreal fdx = data->m11;
5524 const qreal fdy = data->m12;
5525 const qreal fdw = data->m13;
5528 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5529 if (coverage == 0) {
5534 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5537 const qreal cx = spans->x + qreal(0.5);
5538 const qreal cy = spans->y + qreal(0.5);
5540 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5541 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5542 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5544 int length = spans->len;
5546 const int l = qMin(length, buffer_size);
5547 const SRC *end = buffer + l;
5550 const qreal iw = w == 0 ? 1 : 1 / w;
5551 const qreal px = x * iw - qreal(0.5);
5552 const qreal py = y * iw - qreal(0.5);
5554 int x1 = int(px) - (px < 0);
5556 int y1 = int(py) - (py < 0);
5559 const int distx = int((px - x1) * 256);
5560 const int disty = int((py - y1) * 256);
5562 if (x1 < src_minx) {
5564 } else if (x1 >= src_maxx) {
5569 if (y1 < src_miny) {
5571 } else if (y1 >= src_maxy) {
5577 const SRC *src1 = (SRC*)data->texture.scanLine(y1);
5578 const SRC *src2 = (SRC*)data->texture.scanLine(y2);
5580 const SRC tr = src1[x2];
5582 const SRC br = src2[x2];
5583 const quint8 ax = SRC::alpha(distx);
5584 const quint8 iax = SRC::ialpha(distx);
5586 interpolate_pixel(tl, iax, tr, ax);
5587 interpolate_pixel(bl, iax, br, ax);
5588 interpolate_pixel(tl, SRC::ialpha(disty),
5589 bl, SRC::alpha(disty));
5597 if (!SRC::hasAlpha() && coverage == 255) {
5598 qt_memconvert(dest, buffer, l);
5599 } else if (sizeof(DST) == 3 && l >= 4 &&
5600 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5602 blendUntransformed_dest24(dest, buffer, coverage, l);
5603 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5604 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5605 blendUntransformed_dest16(dest, buffer, coverage, l);
5607 blendUntransformed_unaligned(dest, buffer, coverage, l);
5618 static void blend_transformed_bilinear_rgb888(int count, const QSpan *spans, void *userData)
5620 blend_src_generic<RegularSpans>(count, spans, userData);
5623 static void blend_transformed_bilinear_argb6666(int count, const QSpan *spans, void *userData)
5625 blend_src_generic<RegularSpans>(count, spans, userData);
5628 static void blend_transformed_bilinear_rgb666(int count, const QSpan *spans, void *userData)
5630 blend_src_generic<RegularSpans>(count, spans, userData);
5633 static void blend_transformed_bilinear_argb8565(int count, const QSpan *spans, void *userData)
5635 blend_src_generic<RegularSpans>(count, spans, userData);
5638 static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans,
5641 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5643 if (data->texture.format == QImage::Format_RGB16)
5644 blendTransformedBilinear<qrgb565, qrgb565>(count, spans, userData);
5645 else if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5646 blendTransformedBilinear<qrgb565, qargb8565>(count, spans, userData);
5648 blend_src_generic<RegularSpans>(count, spans, userData);
5651 static void blend_transformed_bilinear_argb8555(int count, const QSpan *spans, void *userData)
5653 blend_src_generic<RegularSpans>(count, spans, userData);
5656 static void blend_transformed_bilinear_rgb555(int count, const QSpan *spans, void *userData)
5658 blend_src_generic<RegularSpans>(count, spans, userData);
5661 static void blend_transformed_bilinear_argb4444(int count, const QSpan *spans, void *userData)
5663 blend_src_generic<RegularSpans>(count, spans, userData);
5666 static void blend_transformed_bilinear_rgb444(int count, const QSpan *spans, void *userData)
5668 blend_src_generic<RegularSpans>(count, spans, userData);
5671 template <SpanMethod spanMethod>
5672 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *spans, void *userData)
5674 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5675 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
5676 && data->texture.format != QImage::Format_RGB32) {
5677 blend_src_generic<spanMethod>(count, spans, userData);
5681 CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
5682 uint buffer[buffer_size];
5684 int image_width = data->texture.width;
5685 int image_height = data->texture.height;
5686 const int scanline_offset = data->texture.bytesPerLine / 4;
5688 if (data->fast_matrix) {
5689 // The increment pr x in the scanline
5690 int fdx = (int)(data->m11 * fixed_scale);
5691 int fdy = (int)(data->m12 * fixed_scale);
5694 void *t = data->rasterBuffer->scanLine(spans->y);
5696 uint *target = ((uint *)t) + spans->x;
5697 uint *image_bits = (uint *)data->texture.imageData;
5699 const qreal cx = spans->x + qreal(0.5);
5700 const qreal cy = spans->y + qreal(0.5);
5702 int x = int((data->m21 * cy
5703 + data->m11 * cx + data->dx) * fixed_scale);
5704 int y = int((data->m22 * cy
5705 + data->m12 * cx + data->dy) * fixed_scale);
5707 int length = spans->len;
5708 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5710 int l = qMin(length, buffer_size);
5711 const uint *end = buffer + l;
5717 bool out = (px < 0) || (px >= image_width)
5718 || (py < 0) || (py >= image_height);
5720 int y_offset = py * scanline_offset;
5721 *b = out ? uint(0) : image_bits[y_offset + px];
5726 if (spanMethod == RegularSpans)
5727 func(target, buffer, l, coverage);
5729 drawBufferSpan(data, buffer, buffer_size,
5730 spans->x + spans->len - length,
5731 spans->y, l, coverage);
5738 const qreal fdx = data->m11;
5739 const qreal fdy = data->m12;
5740 const qreal fdw = data->m13;
5742 void *t = data->rasterBuffer->scanLine(spans->y);
5744 uint *target = ((uint *)t) + spans->x;
5745 uint *image_bits = (uint *)data->texture.imageData;
5747 const qreal cx = spans->x + qreal(0.5);
5748 const qreal cy = spans->y + qreal(0.5);
5750 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5751 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5752 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5754 int length = spans->len;
5755 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5757 int l = qMin(length, buffer_size);
5758 const uint *end = buffer + l;
5761 const qreal iw = w == 0 ? 1 : 1 / w;
5762 const qreal tx = x * iw;
5763 const qreal ty = y * iw;
5764 const int px = int(tx) - (tx < 0);
5765 const int py = int(ty) - (ty < 0);
5767 bool out = (px < 0) || (px >= image_width)
5768 || (py < 0) || (py >= image_height);
5770 int y_offset = py * scanline_offset;
5771 *b = out ? uint(0) : image_bits[y_offset + px];
5778 if (spanMethod == RegularSpans)
5779 func(target, buffer, l, coverage);
5781 drawBufferSpan(data, buffer, buffer_size,
5782 spans->x + spans->len - length,
5783 spans->y, l, coverage);
5792 template <class DST, class SRC>
5793 Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans, void *userData)
5795 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5796 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5798 if (mode != QPainter::CompositionMode_SourceOver) {
5799 blend_src_generic<RegularSpans>(count, spans, userData);
5803 SRC buffer[buffer_size];
5804 const int image_width = data->texture.width;
5805 const int image_height = data->texture.height;
5807 if (data->fast_matrix) {
5808 // The increment pr x in the scanline
5809 const int fdx = (int)(data->m11 * fixed_scale);
5810 const int fdy = (int)(data->m12 * fixed_scale);
5813 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5814 if (coverage == 0) {
5819 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5821 const qreal cx = spans->x + qreal(0.5);
5822 const qreal cy = spans->y + qreal(0.5);
5823 int x = int((data->m21 * cy
5824 + data->m11 * cx + data->dx) * fixed_scale);
5825 int y = int((data->m22 * cy
5826 + data->m12 * cx + data->dy) * fixed_scale);
5827 int length = spans->len;
5830 const int l = qMin(length, buffer_size);
5832 const SRC *end = buffer + l;
5835 const int px = (x >> 16);
5836 const int py = (y >> 16);
5838 if ((px < 0) || (px >= image_width) ||
5839 (py < 0) || (py >= image_height))
5843 *b = ((SRC*)data->texture.scanLine(py))[px];
5851 if (!SRC::hasAlpha() && coverage == 255) {
5852 qt_memconvert(dest, buffer, l);
5853 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5854 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5856 blendUntransformed_dest24(dest, buffer, coverage, l);
5857 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5858 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5859 blendUntransformed_dest16(dest, buffer, coverage, l);
5861 blendUntransformed_unaligned(dest, buffer, coverage, l);
5870 const qreal fdx = data->m11;
5871 const qreal fdy = data->m12;
5872 const qreal fdw = data->m13;
5875 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5876 if (coverage == 0) {
5881 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5884 const qreal cx = spans->x + qreal(0.5);
5885 const qreal cy = spans->y + qreal(0.5);
5887 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5888 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5889 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5891 int length = spans->len;
5893 const int l = qMin(length, buffer_size);
5894 const SRC *end = buffer + l;
5897 const qreal iw = w == 0 ? 1 : 1 / w;
5898 const qreal tx = x * iw;
5899 const qreal ty = y * iw;
5901 const int px = int(tx) - (tx < 0);
5902 const int py = int(ty) - (ty < 0);
5904 if ((px < 0) || (px >= image_width) ||
5905 (py < 0) || (py >= image_height))
5909 *b = ((SRC*)data->texture.scanLine(py))[px];
5917 if (!SRC::hasAlpha() && coverage == 255) {
5918 qt_memconvert(dest, buffer, l);
5919 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5920 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5922 blendUntransformed_dest24(dest, buffer, coverage, l);
5923 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5924 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5925 blendUntransformed_dest16(dest, buffer, coverage, l);
5927 blendUntransformed_unaligned(dest, buffer, coverage, l);
5938 static void blend_transformed_rgb888(int count, const QSpan *spans,
5941 blend_src_generic<RegularSpans>(count, spans, userData);
5944 static void blend_transformed_argb6666(int count, const QSpan *spans,
5947 blend_src_generic<RegularSpans>(count, spans, userData);
5950 static void blend_transformed_rgb666(int count, const QSpan *spans,
5953 blend_src_generic<RegularSpans>(count, spans, userData);
5956 static void blend_transformed_argb8565(int count, const QSpan *spans,
5959 blend_src_generic<RegularSpans>(count, spans, userData);
5962 static void blend_transformed_rgb565(int count, const QSpan *spans,
5965 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5967 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5968 blendTransformed<qrgb565, qargb8565>(count, spans, userData);
5969 else if (data->texture.format == QImage::Format_RGB16)
5970 blendTransformed<qrgb565, qrgb565>(count, spans, userData);
5972 blend_src_generic<RegularSpans>(count, spans, userData);
5975 static void blend_transformed_argb8555(int count, const QSpan *spans,
5978 blend_src_generic<RegularSpans>(count, spans, userData);
5981 static void blend_transformed_rgb555(int count, const QSpan *spans,
5984 blend_src_generic<RegularSpans>(count, spans, userData);
5987 static void blend_transformed_argb4444(int count, const QSpan *spans,
5990 blend_src_generic<RegularSpans>(count, spans, userData);
5993 static void blend_transformed_rgb444(int count, const QSpan *spans,
5996 blend_src_generic<RegularSpans>(count, spans, userData);
5999 template <SpanMethod spanMethod>
6000 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QSpan *spans, void *userData)
6002 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6003 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
6004 && data->texture.format != QImage::Format_RGB32) {
6005 blend_src_generic<spanMethod>(count, spans, userData);
6009 CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
6010 uint buffer[buffer_size];
6012 int image_width = data->texture.width;
6013 int image_height = data->texture.height;
6014 const int scanline_offset = data->texture.bytesPerLine / 4;
6016 if (data->fast_matrix) {
6017 // The increment pr x in the scanline
6018 int fdx = (int)(data->m11 * fixed_scale);
6019 int fdy = (int)(data->m12 * fixed_scale);
6022 void *t = data->rasterBuffer->scanLine(spans->y);
6024 uint *target = ((uint *)t) + spans->x;
6025 uint *image_bits = (uint *)data->texture.imageData;
6027 const qreal cx = spans->x + qreal(0.5);
6028 const qreal cy = spans->y + qreal(0.5);
6030 int x = int((data->m21 * cy
6031 + data->m11 * cx + data->dx) * fixed_scale);
6032 int y = int((data->m22 * cy
6033 + data->m12 * cx + data->dy) * fixed_scale);
6035 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
6036 int length = spans->len;
6038 int l = qMin(length, buffer_size);
6039 const uint *end = buffer + l;
6046 if (px < 0) px += image_width;
6047 if (py < 0) py += image_height;
6048 int y_offset = py * scanline_offset;
6050 Q_ASSERT(px >= 0 && px < image_width);
6051 Q_ASSERT(py >= 0 && py < image_height);
6053 *b = image_bits[y_offset + px];
6058 if (spanMethod == RegularSpans)
6059 func(target, buffer, l, coverage);
6061 drawBufferSpan(data, buffer, buffer_size,
6062 spans->x + spans->len - length,
6063 spans->y, l, coverage);
6070 const qreal fdx = data->m11;
6071 const qreal fdy = data->m12;
6072 const qreal fdw = data->m13;
6074 void *t = data->rasterBuffer->scanLine(spans->y);
6076 uint *target = ((uint *)t) + spans->x;
6077 uint *image_bits = (uint *)data->texture.imageData;
6079 const qreal cx = spans->x + qreal(0.5);
6080 const qreal cy = spans->y + qreal(0.5);
6082 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
6083 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
6084 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
6086 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
6087 int length = spans->len;
6089 int l = qMin(length, buffer_size);
6090 const uint *end = buffer + l;
6093 const qreal iw = w == 0 ? 1 : 1 / w;
6094 const qreal tx = x * iw;
6095 const qreal ty = y * iw;
6096 int px = int(tx) - (tx < 0);
6097 int py = int(ty) - (ty < 0);
6101 if (px < 0) px += image_width;
6102 if (py < 0) py += image_height;
6103 int y_offset = py * scanline_offset;
6105 Q_ASSERT(px >= 0 && px < image_width);
6106 Q_ASSERT(py >= 0 && py < image_height);
6108 *b = image_bits[y_offset + px];
6112 //force increment to avoid /0
6118 if (spanMethod == RegularSpans)
6119 func(target, buffer, l, coverage);
6121 drawBufferSpan(data, buffer, buffer_size,
6122 spans->x + spans->len - length,
6123 spans->y, l, coverage);
6132 template <class DST, class SRC>
6133 Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *spans, void *userData)
6135 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
6136 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
6138 if (mode != QPainter::CompositionMode_SourceOver) {
6139 blend_src_generic<RegularSpans>(count, spans, userData);
6143 SRC buffer[buffer_size];
6144 const int image_width = data->texture.width;
6145 const int image_height = data->texture.height;
6147 if (data->fast_matrix) {
6148 // The increment pr x in the scanline
6149 const int fdx = (int)(data->m11 * fixed_scale);
6150 const int fdy = (int)(data->m12 * fixed_scale);
6153 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
6154 if (coverage == 0) {
6159 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
6161 const qreal cx = spans->x + qreal(0.5);
6162 const qreal cy = spans->y + qreal(0.5);
6163 int x = int((data->m21 * cy
6164 + data->m11 * cx + data->dx) * fixed_scale);
6165 int y = int((data->m22 * cy
6166 + data->m12 * cx + data->dy) * fixed_scale);
6167 int length = spans->len;
6170 const int l = qMin(length, buffer_size);
6172 const SRC *end = buffer + l;
6175 int px = (x >> 16) % image_width;
6176 int py = (y >> 16) % image_height;
6183 *b = ((SRC*)data->texture.scanLine(py))[px];
6190 if (!SRC::hasAlpha() && coverage == 255) {
6191 qt_memconvert(dest, buffer, l);
6192 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6193 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6195 blendUntransformed_dest24(dest, buffer, coverage, l);
6196 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6197 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6198 blendUntransformed_dest16(dest, buffer, coverage, l);
6200 blendUntransformed_unaligned(dest, buffer, coverage, l);
6209 const qreal fdx = data->m11;
6210 const qreal fdy = data->m12;
6211 const qreal fdw = data->m13;
6214 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
6215 if (coverage == 0) {
6220 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
6223 const qreal cx = spans->x + qreal(0.5);
6224 const qreal cy = spans->y + qreal(0.5);
6226 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
6227 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
6228 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
6230 int length = spans->len;
6232 const int l = qMin(length, buffer_size);
6233 const SRC *end = buffer + l;
6236 const qreal iw = w == 0 ? 1 : 1 / w;
6237 const qreal tx = x * iw;
6238 const qreal ty = y * iw;
6240 int px = int(tx) - (tx < 0);
6241 int py = int(ty) - (ty < 0);
6250 *b = ((SRC*)data->texture.scanLine(py))[px];
6256 // force increment to avoid /0
6260 if (!SRC::hasAlpha() && coverage == 255) {
6261 qt_memconvert(dest, buffer, l);
6262 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6263 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6265 blendUntransformed_dest24(dest, buffer, coverage, l);
6266 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6267 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6268 blendUntransformed_dest16(dest, buffer, coverage, l);
6270 blendUntransformed_unaligned(dest, buffer, coverage, l);
6281 static void blend_transformed_tiled_rgb888(int count, const QSpan *spans,
6284 blend_src_generic<RegularSpans>(count, spans, userData);
6287 static void blend_transformed_tiled_argb6666(int count, const QSpan *spans,
6290 blend_src_generic<RegularSpans>(count, spans, userData);
6293 static void blend_transformed_tiled_rgb666(int count, const QSpan *spans,
6296 blend_src_generic<RegularSpans>(count, spans, userData);
6299 static void blend_transformed_tiled_argb8565(int count, const QSpan *spans,
6302 blend_src_generic<RegularSpans>(count, spans, userData);
6305 static void blend_transformed_tiled_rgb565(int count, const QSpan *spans,
6308 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6310 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
6311 blendTransformedTiled<qrgb565, qargb8565>(count, spans, userData);
6312 else if (data->texture.format == QImage::Format_RGB16)
6313 blendTransformedTiled<qrgb565, qrgb565>(count, spans, userData);
6315 blend_src_generic<RegularSpans>(count, spans, userData);
6318 static void blend_transformed_tiled_argb8555(int count, const QSpan *spans,
6321 blend_src_generic<RegularSpans>(count, spans, userData);
6324 static void blend_transformed_tiled_rgb555(int count, const QSpan *spans,
6327 blend_src_generic<RegularSpans>(count, spans, userData);
6330 static void blend_transformed_tiled_argb4444(int count, const QSpan *spans,
6333 blend_src_generic<RegularSpans>(count, spans, userData);
6336 static void blend_transformed_tiled_rgb444(int count, const QSpan *spans,
6339 blend_src_generic<RegularSpans>(count, spans, userData);
6342 # define SPANFUNC_POINTER(Name, Arg) Name<Arg>
6345 /* Image formats here are target formats */
6346 static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats] = {
6350 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Mono
6351 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // MonoLsb
6352 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Indexed8
6353 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // RGB32
6354 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // ARGB32
6355 SPANFUNC_POINTER(blend_untransformed_argb, RegularSpans), // ARGB32_Premultiplied
6356 blend_untransformed_rgb565,
6357 blend_untransformed_argb8565,
6358 blend_untransformed_rgb666,
6359 blend_untransformed_argb6666,
6360 blend_untransformed_rgb555,
6361 blend_untransformed_argb8555,
6362 blend_untransformed_rgb888,
6363 blend_untransformed_rgb444,
6364 blend_untransformed_argb4444,
6369 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Mono
6370 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // MonoLsb
6371 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Indexed8
6372 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // RGB32
6373 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // ARGB32
6374 SPANFUNC_POINTER(blend_tiled_argb, RegularSpans), // ARGB32_Premultiplied
6376 blend_tiled_argb8565,
6378 blend_tiled_argb6666,
6380 blend_tiled_argb8555,
6383 blend_tiled_argb4444,
6388 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6389 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6390 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6391 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6392 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6393 SPANFUNC_POINTER(blend_transformed_argb, RegularSpans), // ARGB32_Premultiplied
6394 blend_transformed_rgb565,
6395 blend_transformed_argb8565,
6396 blend_transformed_rgb666,
6397 blend_transformed_argb6666,
6398 blend_transformed_rgb555,
6399 blend_transformed_argb8555,
6400 blend_transformed_rgb888,
6401 blend_transformed_rgb444,
6402 blend_transformed_argb4444,
6407 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6408 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6409 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6410 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6411 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6412 SPANFUNC_POINTER(blend_transformed_tiled_argb, RegularSpans), // ARGB32_Premultiplied
6413 blend_transformed_tiled_rgb565,
6414 blend_transformed_tiled_argb8565,
6415 blend_transformed_tiled_rgb666,
6416 blend_transformed_tiled_argb6666,
6417 blend_transformed_tiled_rgb555,
6418 blend_transformed_tiled_argb8555,
6419 blend_transformed_tiled_rgb888,
6420 blend_transformed_tiled_rgb444,
6421 blend_transformed_tiled_argb4444
6426 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6427 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6428 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6429 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6430 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6431 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
6432 blend_transformed_bilinear_rgb565,
6433 blend_transformed_bilinear_argb8565,
6434 blend_transformed_bilinear_rgb666,
6435 blend_transformed_bilinear_argb6666,
6436 blend_transformed_bilinear_rgb555,
6437 blend_transformed_bilinear_argb8555,
6438 blend_transformed_bilinear_rgb888,
6439 blend_transformed_bilinear_rgb444,
6440 blend_transformed_bilinear_argb4444,
6445 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6446 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6447 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6448 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6449 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6450 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
6451 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB16
6452 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8565_Premultiplied
6453 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB666
6454 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB6666_Premultiplied
6455 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB555
6456 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8555_Premultiplied
6457 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB888
6458 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB444
6459 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB4444_Premultiplied
6463 void qBlendTexture(int count, const QSpan *spans, void *userData)
6465 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6466 ProcessSpans proc = processTextureSpans[getBlendType(data)][data->rasterBuffer->format];
6467 proc(count, spans, userData);
6470 template <class DST>
6471 inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
6472 int x, int y, quint32 color,
6474 int mapWidth, int mapHeight, int mapStride,
6478 const DST c = qt_colorConvert<DST, quint32>(color, 0);
6479 DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
6480 const int destStride = rasterBuffer->bytesPerLine() / sizeof(DST);
6483 while (mapHeight--) {
6486 for (int x = 0; x < mapWidth; x += 8) {
6487 uchar s = map[x >> 3];
6488 for (int i = 0; i < 8; ++i) {
6493 qt_memfill(dest + x0, c, n);
6508 qt_memfill(dest + x0, c, n);
6513 while (mapHeight--) {
6516 for (uchar s = *map; s; s <<= 1) {
6520 qt_memfill(dest + x0, c, n);
6528 qt_memfill(dest + x0, c, n);
6535 static void qt_gradient_quint32(int count, const QSpan *spans, void *userData)
6537 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6539 bool isVerticalGradient =
6540 data->txop <= QTransform::TxScale &&
6541 data->type == QSpanData::LinearGradient &&
6542 data->gradient.linear.end.x == data->gradient.linear.origin.x;
6544 if (isVerticalGradient) {
6545 LinearGradientValues linear;
6546 getLinearGradientValues(&linear, data);
6548 CompositionFunctionSolid funcSolid =
6549 functionForModeSolid[data->rasterBuffer->compositionMode];
6552 The logic for vertical gradient calculations is a mathematically
6553 reduced copy of that in fetchLinearGradient() - which is basically:
6555 qreal ry = data->m22 * (y + 0.5) + data->dy;
6556 qreal t = linear.dy*ry + linear.off;
6557 t *= (GRADIENT_STOPTABLE_SIZE - 1);
6559 qt_gradient_pixel_fixed(&data->gradient,
6560 int(t * FIXPT_SIZE));
6562 This has then been converted to fixed point to improve performance.
6564 const int gss = GRADIENT_STOPTABLE_SIZE - 1;
6565 int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
6566 int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
6572 quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x;
6574 qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
6576 funcSolid(dst, spans->len, color, spans->coverage);
6581 blend_src_generic<RegularSpans>(count, spans, userData);
6585 static void qt_gradient_quint16(int count, const QSpan *spans, void *userData)
6587 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6589 bool isVerticalGradient =
6590 data->txop <= QTransform::TxScale &&
6591 data->type == QSpanData::LinearGradient &&
6592 data->gradient.linear.end.x == data->gradient.linear.origin.x;
6594 if (isVerticalGradient) {
6596 LinearGradientValues linear;
6597 getLinearGradientValues(&linear, data);
6600 The logic for vertical gradient calculations is a mathematically
6601 reduced copy of that in fetchLinearGradient() - which is basically:
6603 qreal ry = data->m22 * (y + 0.5) + data->dy;
6604 qreal t = linear.dy*ry + linear.off;
6605 t *= (GRADIENT_STOPTABLE_SIZE - 1);
6607 qt_gradient_pixel_fixed(&data->gradient,
6608 int(t * FIXPT_SIZE));
6610 This has then been converted to fixed point to improve performance.
6612 const int gss = GRADIENT_STOPTABLE_SIZE - 1;
6613 int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
6614 int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
6616 uint oldColor = data->solid.color;
6620 quint32 color = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
6622 data->solid.color = color;
6623 blend_color_rgb16(1, spans, userData);
6626 data->solid.color = oldColor;
6629 blend_src_generic<RegularSpans>(count, spans, userData);
6633 inline static void qt_bitmapblit_quint32(QRasterBuffer *rasterBuffer,
6634 int x, int y, quint32 color,
6636 int mapWidth, int mapHeight, int mapStride)
6638 qt_bitmapblit_template<quint32>(rasterBuffer, x, y, color,
6639 map, mapWidth, mapHeight, mapStride);
6642 inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
6643 int x, int y, quint32 color,
6645 int mapWidth, int mapHeight, int mapStride)
6647 qt_bitmapblit_template<quint16>(rasterBuffer, x, y, color,
6648 map, mapWidth, mapHeight, mapStride);
6652 uchar qt_pow_rgb_gamma[256];
6653 uchar qt_pow_rgb_invgamma[256];
6655 uint qt_pow_gamma[256];
6656 uchar qt_pow_invgamma[2048];
6658 static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
6659 int x, int y, quint32 color,
6661 int mapWidth, int mapHeight, int mapStride,
6664 const quint16 c = qt_colorConvert<quint16, quint32>(color, 0);
6665 quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
6666 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
6668 while (mapHeight--) {
6669 for (int i = 0; i < mapWidth; ++i) {
6670 const int coverage = map[i];
6672 if (coverage == 0) {
6674 } else if (coverage == 255) {
6677 int ialpha = 255 - coverage;
6678 dest[i] = BYTE_MUL_RGB16(c, coverage)
6679 + BYTE_MUL_RGB16(dest[i], ialpha);
6687 void qt_build_pow_tables() {
6688 qreal smoothing = qreal(1.7);
6691 // decided by testing a few things on an iMac, should probably get this from the
6693 smoothing = qreal(2.0);
6698 if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0))
6699 smoothing = winSmooth / qreal(1000.0);
6701 // Safeguard ourselves against corrupt registry values...
6702 if (smoothing > 5 || smoothing < 1)
6703 smoothing = qreal(1.4);
6708 Q_UNUSED(smoothing);
6709 for (int i=0; i<256; ++i) {
6710 qt_pow_rgb_gamma[i] = uchar(i);
6711 qt_pow_rgb_invgamma[i] = uchar(i);
6714 for (int i=0; i<256; ++i) {
6715 qt_pow_rgb_gamma[i] = uchar(qRound(qPow(i / qreal(255.0), smoothing) * 255));
6716 qt_pow_rgb_invgamma[i] = uchar(qRound(qPow(i / qreal(255.), 1 / smoothing) * 255));
6720 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
6721 const qreal gray_gamma = 2.31;
6722 for (int i=0; i<256; ++i)
6723 qt_pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047));
6724 for (int i=0; i<2048; ++i)
6725 qt_pow_invgamma[i] = uchar(qRound(qPow(i / qreal(2047.0), 1 / gray_gamma) * 255));
6729 static inline void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
6731 // Do a gray alphablend...
6732 int da = qAlpha(*dst);
6733 int dr = qRed(*dst);
6734 int dg = qGreen(*dst);
6735 int db = qBlue(*dst);
6738 #if defined (Q_WS_WIN)
6739 // Work around GDI messing up alpha channel
6740 && qRed(*dst) <= da && qBlue(*dst) <= da && qGreen(*dst) <= da
6744 int a = qGray(coverage);
6745 sr = qt_div_255(qt_pow_rgb_invgamma[sr] * a);
6746 sg = qt_div_255(qt_pow_rgb_invgamma[sg] * a);
6747 sb = qt_div_255(qt_pow_rgb_invgamma[sb] * a);
6750 dr = qt_div_255(dr * ia);
6751 dg = qt_div_255(dg * ia);
6752 db = qt_div_255(db * ia);
6754 *dst = ((a + qt_div_255((255 - a) * da)) << 24)
6761 int mr = qRed(coverage);
6762 int mg = qGreen(coverage);
6763 int mb = qBlue(coverage);
6765 dr = qt_pow_rgb_gamma[dr];
6766 dg = qt_pow_rgb_gamma[dg];
6767 db = qt_pow_rgb_gamma[db];
6769 int nr = qt_div_255((sr - dr) * mr) + dr;
6770 int ng = qt_div_255((sg - dg) * mg) + dg;
6771 int nb = qt_div_255((sb - db) * mb) + db;
6773 nr = qt_pow_rgb_invgamma[nr];
6774 ng = qt_pow_rgb_invgamma[ng];
6775 nb = qt_pow_rgb_invgamma[nb];
6777 *dst = qRgb(nr, ng, nb);
6780 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
6781 static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
6783 // Do a gammacorrected gray alphablend...
6784 int dr = qRed(*dst);
6785 int dg = qGreen(*dst);
6786 int db = qBlue(*dst);
6788 dr = qt_pow_gamma[dr];
6789 dg = qt_pow_gamma[dg];
6790 db = qt_pow_gamma[db];
6792 int alpha = coverage;
6793 int ialpha = 255 - alpha;
6794 int nr = (sr * alpha + ialpha * dr) / 255;
6795 int ng = (sg * alpha + ialpha * dg) / 255;
6796 int nb = (sb * alpha + ialpha * db) / 255;
6798 nr = qt_pow_invgamma[nr];
6799 ng = qt_pow_invgamma[ng];
6800 nb = qt_pow_invgamma[nb];
6802 *dst = qRgb(nr, ng, nb);
6806 static void qt_alphamapblit_quint32(QRasterBuffer *rasterBuffer,
6807 int x, int y, quint32 color,
6809 int mapWidth, int mapHeight, int mapStride,
6810 const QClipData *clip)
6812 const quint32 c = color;
6813 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
6815 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
6816 int sr = qRed(color);
6817 int sg = qGreen(color);
6818 int sb = qBlue(color);
6820 sr = qt_pow_gamma[sr];
6821 sg = qt_pow_gamma[sg];
6822 sb = qt_pow_gamma[sb];
6823 bool opaque_src = (qAlpha(color) == 255);
6827 quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
6828 while (mapHeight--) {
6829 for (int i = 0; i < mapWidth; ++i) {
6830 const int coverage = map[i];
6832 if (coverage == 0) {
6834 } else if (coverage == 255) {
6837 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
6838 if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
6839 && qAlpha(dest[i]) == 255) {
6840 grayBlendPixel(dest+i, coverage, sr, sg, sb);
6844 int ialpha = 255 - coverage;
6845 dest[i] = INTERPOLATE_PIXEL_255(c, coverage, dest[i], ialpha);
6853 int bottom = qMin(y + mapHeight, rasterBuffer->height());
6855 int top = qMax(y, 0);
6856 map += (top - y) * mapStride;
6858 const_cast<QClipData *>(clip)->initialize();
6859 for (int yp = top; yp<bottom; ++yp) {
6860 const QClipData::ClipLine &line = clip->m_clipLines[yp];
6862 quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
6864 for (int i=0; i<line.count; ++i) {
6865 const QSpan &clip = line.spans[i];
6867 int start = qMax<int>(x, clip.x);
6868 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
6870 for (int xp=start; xp<end; ++xp) {
6871 const int coverage = map[xp - x];
6873 if (coverage == 0) {
6875 } else if (coverage == 255) {
6878 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
6879 if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
6880 && qAlpha(dest[xp]) == 255) {
6881 grayBlendPixel(dest+xp, coverage, sr, sg, sb);
6885 int ialpha = 255 - coverage;
6886 dest[xp] = INTERPOLATE_PIXEL_255(c, coverage, dest[xp], ialpha);
6890 } // for (i -> line.count)
6891 } // for (yp -> bottom)
6897 static void qt_alphargbblit_quint32(QRasterBuffer *rasterBuffer,
6898 int x, int y, quint32 color,
6899 const uint *src, int mapWidth, int mapHeight, int srcStride,
6900 const QClipData *clip)
6902 const quint32 c = color;
6904 int sr = qRed(color);
6905 int sg = qGreen(color);
6906 int sb = qBlue(color);
6907 int sa = qAlpha(color);
6909 sr = qt_pow_rgb_gamma[sr];
6910 sg = qt_pow_rgb_gamma[sg];
6911 sb = qt_pow_rgb_gamma[sb];
6917 quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
6918 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
6919 while (mapHeight--) {
6920 for (int i = 0; i < mapWidth; ++i) {
6921 const uint coverage = src[i];
6922 if (coverage == 0xffffffff) {
6924 } else if (coverage != 0xff000000) {
6925 rgbBlendPixel(dst+i, coverage, sr, sg, sb);
6933 int bottom = qMin(y + mapHeight, rasterBuffer->height());
6935 int top = qMax(y, 0);
6936 src += (top - y) * srcStride;
6938 const_cast<QClipData *>(clip)->initialize();
6939 for (int yp = top; yp<bottom; ++yp) {
6940 const QClipData::ClipLine &line = clip->m_clipLines[yp];
6942 quint32 *dst = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
6944 for (int i=0; i<line.count; ++i) {
6945 const QSpan &clip = line.spans[i];
6947 int start = qMax<int>(x, clip.x);
6948 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
6950 for (int xp=start; xp<end; ++xp) {
6951 const uint coverage = src[xp - x];
6952 if (coverage == 0xffffffff) {
6954 } else if (coverage != 0xff000000) {
6955 rgbBlendPixel(dst+xp, coverage, sr, sg, sb);
6958 } // for (i -> line.count)
6960 } // for (yp -> bottom)
6966 inline void qt_rectfill_template(QRasterBuffer *rasterBuffer,
6967 int x, int y, int width, int height,
6968 quint32 color, T dummy = 0)
6972 qt_rectfill<T>(reinterpret_cast<T*>(rasterBuffer->buffer()),
6973 qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0),
6974 x, y, width, height, rasterBuffer->bytesPerLine());
6977 #define QT_RECTFILL(T) \
6978 inline static void qt_rectfill_##T(QRasterBuffer *rasterBuffer, \
6979 int x, int y, int width, int height, \
6982 qt_rectfill_template<T>(rasterBuffer, x, y, width, height, color); \
6985 QT_RECTFILL(quint32)
6986 QT_RECTFILL(quint16)
6987 QT_RECTFILL(qargb8565)
6988 QT_RECTFILL(qrgb666)
6989 QT_RECTFILL(qargb6666)
6990 QT_RECTFILL(qrgb555)
6991 QT_RECTFILL(qargb8555)
6992 QT_RECTFILL(qrgb888)
6993 QT_RECTFILL(qrgb444)
6994 QT_RECTFILL(qargb4444)
6997 inline static void qt_rectfill_nonpremul_quint32(QRasterBuffer *rasterBuffer,
6998 int x, int y, int width, int height,
7001 qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
7002 INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine());
7006 // Map table for destination image format. Contains function pointers
7007 // for blends of various types unto the destination
7009 DrawHelper qDrawHelper[QImage::NImageFormats] =
7012 { 0, 0, 0, 0, 0, 0 },
7015 blend_color_generic,
7016 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7021 blend_color_generic,
7022 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7027 blend_color_generic,
7028 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7034 qt_gradient_quint32,
7035 qt_bitmapblit_quint32,
7036 qt_alphamapblit_quint32,
7037 qt_alphargbblit_quint32,
7042 blend_color_generic,
7043 qt_gradient_quint32,
7044 qt_bitmapblit_quint32,
7045 qt_alphamapblit_quint32,
7046 qt_alphargbblit_quint32,
7047 qt_rectfill_nonpremul_quint32
7049 // Format_ARGB32_Premultiplied
7052 qt_gradient_quint32,
7053 qt_bitmapblit_quint32,
7054 qt_alphamapblit_quint32,
7055 qt_alphargbblit_quint32,
7061 qt_gradient_quint16,
7062 qt_bitmapblit_quint16,
7063 qt_alphamapblit_quint16,
7067 // Format_ARGB8565_Premultiplied
7069 SPANFUNC_POINTER_BLENDCOLOR(qargb8565),
7070 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7072 qt_rectfill_qargb8565
7076 SPANFUNC_POINTER_BLENDCOLOR(qrgb666),
7077 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7081 // Format_ARGB6666_Premultiplied
7083 SPANFUNC_POINTER_BLENDCOLOR(qargb6666),
7084 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7086 qt_rectfill_qargb6666
7090 SPANFUNC_POINTER_BLENDCOLOR(qrgb555),
7091 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7095 // Format_ARGB8555_Premultiplied
7097 SPANFUNC_POINTER_BLENDCOLOR(qargb8555),
7098 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7100 qt_rectfill_qargb8555
7104 SPANFUNC_POINTER_BLENDCOLOR(qrgb888),
7105 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7111 SPANFUNC_POINTER_BLENDCOLOR(qrgb444),
7112 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7116 // Format_ARGB4444_Premultiplied
7118 SPANFUNC_POINTER_BLENDCOLOR(qargb4444),
7119 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7121 qt_rectfill_qargb4444
7125 #if defined(Q_CC_MSVC) && !defined(_MIPS_)
7126 template <class DST, class SRC>
7127 inline void qt_memfill_template(DST *dest, SRC color, int count)
7129 const DST c = qt_colorConvert<DST, SRC>(color, 0);
7136 template <class DST, class SRC>
7137 inline void qt_memfill_template(DST *dest, SRC color, int count)
7139 const DST c = qt_colorConvert<DST, SRC>(color, 0);
7140 int n = (count + 7) / 8;
7141 switch (count & 0x07)
7143 case 0: do { *dest++ = c;
7144 case 7: *dest++ = c;
7145 case 6: *dest++ = c;
7146 case 5: *dest++ = c;
7147 case 4: *dest++ = c;
7148 case 3: *dest++ = c;
7149 case 2: *dest++ = c;
7150 case 1: *dest++ = c;
7156 inline void qt_memfill_template(quint16 *dest, quint16 value, int count)
7160 case 2: *dest++ = value;
7161 case 1: *dest = value;
7166 const int align = (quintptr)(dest) & 0x3;
7168 case 2: *dest++ = value; --count;
7171 const quint32 value32 = (value << 16) | value;
7172 qt_memfill(reinterpret_cast<quint32*>(dest), value32, count / 2);
7174 dest[count - 1] = value;
7178 static void qt_memfill_quint16(quint16 *dest, quint16 color, int count)
7180 qt_memfill_template<quint16, quint16>(dest, color, count);
7183 typedef void (*qt_memfill32_func)(quint32 *dest, quint32 value, int count);
7184 typedef void (*qt_memfill16_func)(quint16 *dest, quint16 value, int count);
7185 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count);
7186 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count);
7188 qt_memfill32_func qt_memfill32 = qt_memfill32_setup;
7189 qt_memfill16_func qt_memfill16 = qt_memfill16_setup;
7191 void qInitDrawhelperAsm()
7194 qt_memfill32 = qt_memfill_template<quint32, quint32>;
7195 qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16, quint16>;
7197 CompositionFunction *functionForModeAsm = 0;
7198 CompositionFunctionSolid *functionForModeSolidAsm = 0;
7200 const uint features = qDetectCPUFeatures();
7203 } else if (features & SSE2) {
7204 qt_memfill32 = qt_memfill32_sse2;
7205 qt_memfill16 = qt_memfill16_sse2;
7206 qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2;
7207 qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2;
7208 qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2;
7209 qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2;
7212 } else if (features & SSE) {
7213 // qt_memfill32 = qt_memfill32_sse;
7214 qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse;
7215 #ifdef QT_HAVE_3DNOW
7216 if (features & MMX3DNOW) {
7217 qt_memfill32 = qt_memfill32_sse3dnow;
7218 qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse3dnow;
7224 if (features & MMX) {
7225 functionForModeAsm = qt_functionForMode_MMX;
7227 functionForModeSolidAsm = qt_functionForModeSolid_MMX;
7228 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx;
7229 #ifdef QT_HAVE_3DNOW
7230 if (features & MMX3DNOW) {
7231 functionForModeAsm = qt_functionForMode_MMX3DNOW;
7232 functionForModeSolidAsm = qt_functionForModeSolid_MMX3DNOW;
7233 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx3dnow;
7237 extern void qt_blend_rgb32_on_rgb32_mmx(uchar *destPixels, int dbpl,
7238 const uchar *srcPixels, int sbpl,
7241 extern void qt_blend_argb32_on_argb32_mmx(uchar *destPixels, int dbpl,
7242 const uchar *srcPixels, int sbpl,
7246 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mmx;
7247 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mmx;
7248 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mmx;
7249 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mmx;
7255 if (features & SSE) {
7256 extern void qt_blend_rgb32_on_rgb32_sse(uchar *destPixels, int dbpl,
7257 const uchar *srcPixels, int sbpl,
7260 extern void qt_blend_argb32_on_argb32_sse(uchar *destPixels, int dbpl,
7261 const uchar *srcPixels, int sbpl,
7265 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
7266 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
7267 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
7268 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
7273 if (features & SSE2) {
7274 extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
7275 const uchar *srcPixels, int sbpl,
7278 extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
7279 const uchar *srcPixels, int sbpl,
7283 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
7284 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
7285 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
7286 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
7289 #ifdef QT_HAVE_SSSE3
7290 if (features & SSSE3) {
7291 extern void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
7292 const uchar *srcPixels, int sbpl,
7296 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
7297 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
7304 if (features & SSE) {
7305 functionForModeAsm = qt_functionForMode_SSE;
7306 functionForModeSolidAsm = qt_functionForModeSolid_SSE;
7307 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse;
7308 #ifdef QT_HAVE_3DNOW
7309 if (features & MMX3DNOW) {
7310 functionForModeAsm = qt_functionForMode_SSE3DNOW;
7311 functionForModeSolidAsm = qt_functionForModeSolid_SSE3DNOW;
7312 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse3dnow;
7318 if (features & SSE2) {
7319 extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels,
7320 const uint *srcPixels,
7323 extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha);
7324 extern void QT_FASTCALL comp_func_Plus_sse2(uint *dst, const uint *src, int length, uint const_alpha);
7325 extern void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, uint const_alpha);
7327 functionForModeAsm[0] = comp_func_SourceOver_sse2;
7328 functionForModeAsm[QPainter::CompositionMode_Source] = comp_func_Source_sse2;
7329 functionForModeAsm[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2;
7330 functionForModeSolidAsm[0] = comp_func_solid_SourceOver_sse2;
7334 #elif defined(QT_HAVE_SSE2)
7335 // this is the special case when SSE2 is usable but MMX/SSE is not usable (e.g.: Windows x64 + visual studio)
7336 if (features & SSE2) {
7337 functionForModeAsm = qt_functionForMode_onlySSE2;
7338 functionForModeSolidAsm = qt_functionForModeSolid_onlySSE2;
7342 #ifdef QT_HAVE_IWMMXT
7343 if (features & IWMMXT) {
7344 functionForModeAsm = qt_functionForMode_IWMMXT;
7345 functionForModeSolidAsm = qt_functionForModeSolid_IWMMXT;
7346 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_iwmmxt;
7350 #if defined(QT_HAVE_ARM_SIMD)
7351 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_arm_simd;
7352 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_arm_simd;
7353 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_arm_simd;
7354 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_arm_simd;
7355 #elif defined(QT_HAVE_NEON)
7356 if (features & NEON) {
7357 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
7358 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
7359 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7360 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7361 qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon;
7362 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon;
7363 qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon;
7365 qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon;
7366 qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon;
7368 qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon;
7369 qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon;
7371 qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon;
7373 functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon;
7374 functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon;
7375 functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon;
7376 destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
7377 destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
7379 qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
7380 qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
7381 qt_memfill32 = qt_memfill32_neon;
7385 if (functionForModeSolidAsm) {
7386 const int destinationMode = QPainter::CompositionMode_Destination;
7387 functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode];
7389 // use the default qdrawhelper implementation for the
7390 // extended composition modes
7391 for (int mode = 12; mode < 24; ++mode)
7392 functionForModeSolidAsm[mode] = functionForModeSolid_C[mode];
7394 functionForModeSolid = functionForModeSolidAsm;
7396 if (functionForModeAsm)
7397 functionForMode = functionForModeAsm;
7399 qt_build_pow_tables();
7402 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count)
7404 qInitDrawhelperAsm();
7405 qt_memfill32(dest, value, count);
7408 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count)
7410 qInitDrawhelperAsm();
7411 qt_memfill16(dest, value, count);