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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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,
79 // must be multiple of 4 for easier SIMD implementations
80 static const int buffer_size = 2048;
83 Destination fetch. This is simple as we don't have to do bounds checks or
87 static uint * QT_FASTCALL destFetchMono(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
89 uchar *data = (uchar *)rasterBuffer->scanLine(y);
91 const uint *end = buffer + length;
92 while (buffer < end) {
93 *buffer = data[x>>3] & (0x80 >> (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
100 static uint * QT_FASTCALL destFetchMonoLsb(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
102 uchar *data = (uchar *)rasterBuffer->scanLine(y);
103 uint *start = buffer;
104 const uint *end = buffer + length;
105 while (buffer < end) {
106 *buffer = data[x>>3] & (0x1 << (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
113 static uint * QT_FASTCALL destFetchARGB32(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
115 const uint *data = (const uint *)rasterBuffer->scanLine(y) + x;
116 for (int i = 0; i < length; ++i)
117 buffer[i] = PREMUL(data[i]);
121 static uint * QT_FASTCALL destFetchARGB32P(uint *, QRasterBuffer *rasterBuffer, int x, int y, int)
123 return (uint *)rasterBuffer->scanLine(y) + x;
126 static uint * QT_FASTCALL destFetchRGB16(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
128 const ushort *data = (const ushort *)rasterBuffer->scanLine(y) + x;
129 for (int i = 0; i < length; ++i)
130 buffer[i] = qConvertRgb16To32(data[i]);
135 Q_STATIC_TEMPLATE_FUNCTION uint * QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer,
136 int x, int y, int length)
138 const DST *src = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
139 quint32 *dest = reinterpret_cast<quint32*>(buffer);
145 # define SPANFUNC_POINTER_DESTFETCH(Arg) destFetch<Arg>
147 static DestFetchProc destFetchProc[QImage::NImageFormats] =
150 destFetchMono, // Format_Mono,
151 destFetchMonoLsb, // Format_MonoLSB
152 0, // Format_Indexed8
153 destFetchARGB32P, // Format_RGB32
154 destFetchARGB32, // Format_ARGB32,
155 destFetchARGB32P, // Format_ARGB32_Premultiplied
156 destFetchRGB16, // Format_RGB16
157 SPANFUNC_POINTER_DESTFETCH(qargb8565), // Format_ARGB8565_Premultiplied
158 SPANFUNC_POINTER_DESTFETCH(qrgb666), // Format_RGB666
159 SPANFUNC_POINTER_DESTFETCH(qargb6666), // Format_ARGB6666_Premultiplied
160 SPANFUNC_POINTER_DESTFETCH(qrgb555), // Format_RGB555
161 SPANFUNC_POINTER_DESTFETCH(qargb8555), // Format_ARGB8555_Premultiplied
162 SPANFUNC_POINTER_DESTFETCH(qrgb888), // Format_RGB888
163 SPANFUNC_POINTER_DESTFETCH(qrgb444), // Format_RGB444
164 SPANFUNC_POINTER_DESTFETCH(qargb4444) // Format_ARGB4444_Premultiplied
168 Returns the color in the mono destination color table
169 that is the "nearest" to /color/.
171 static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
173 QRgb color_0 = PREMUL(rbuf->destColor0);
174 QRgb color_1 = PREMUL(rbuf->destColor1);
175 color = PREMUL(color);
178 int g = qGreen(color);
179 int b = qBlue(color);
183 rx = r - qRed(color_0);
184 gx = g - qGreen(color_0);
185 bx = b - qBlue(color_0);
186 dist_0 = rx*rx + gx*gx + bx*bx;
188 rx = r - qRed(color_1);
189 gx = g - qGreen(color_1);
190 bx = b - qBlue(color_1);
191 dist_1 = rx*rx + gx*gx + bx*bx;
202 static void QT_FASTCALL destStoreMono(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
204 uchar *data = (uchar *)rasterBuffer->scanLine(y);
205 if (rasterBuffer->monoDestinationWithClut) {
206 for (int i = 0; i < length; ++i) {
207 if (buffer[i] == rasterBuffer->destColor0) {
208 data[x >> 3] &= ~(0x80 >> (x & 7));
209 } else if (buffer[i] == rasterBuffer->destColor1) {
210 data[x >> 3] |= 0x80 >> (x & 7);
211 } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
212 data[x >> 3] &= ~(0x80 >> (x & 7));
214 data[x >> 3] |= 0x80 >> (x & 7);
219 for (int i = 0; i < length; ++i) {
220 if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
221 data[x >> 3] |= 0x80 >> (x & 7);
223 data[x >> 3] &= ~(0x80 >> (x & 7));
229 static void QT_FASTCALL destStoreMonoLsb(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
231 uchar *data = (uchar *)rasterBuffer->scanLine(y);
232 if (rasterBuffer->monoDestinationWithClut) {
233 for (int i = 0; i < length; ++i) {
234 if (buffer[i] == rasterBuffer->destColor0) {
235 data[x >> 3] &= ~(1 << (x & 7));
236 } else if (buffer[i] == rasterBuffer->destColor1) {
237 data[x >> 3] |= 1 << (x & 7);
238 } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
239 data[x >> 3] &= ~(1 << (x & 7));
241 data[x >> 3] |= 1 << (x & 7);
246 for (int i = 0; i < length; ++i) {
247 if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
248 data[x >> 3] |= 1 << (x & 7);
250 data[x >> 3] &= ~(1 << (x & 7));
256 static void QT_FASTCALL destStoreARGB32(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
258 uint *data = (uint *)rasterBuffer->scanLine(y) + x;
259 for (int i = 0; i < length; ++i) {
261 int alpha = qAlpha(p);
267 int inv_alpha = 0xff0000/qAlpha(buffer[i]);
268 data[i] = (p & 0xff000000)
269 | ((qRed(p)*inv_alpha) & 0xff0000)
270 | (((qGreen(p)*inv_alpha) >> 8) & 0xff00)
271 | ((qBlue(p)*inv_alpha) >> 16);
276 static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
278 quint16 *data = (quint16*)rasterBuffer->scanLine(y) + x;
279 qt_memconvert<quint16, quint32>(data, buffer, length);
283 Q_STATIC_TEMPLATE_FUNCTION void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer,
285 const uint *buffer, int length)
287 DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
288 const quint32p *src = reinterpret_cast<const quint32p*>(buffer);
290 *dest++ = DST(*src++);
293 # define SPANFUNC_POINTER_DESTSTORE(DEST) destStore<DEST>
295 static DestStoreProc destStoreProc[QImage::NImageFormats] =
298 destStoreMono, // Format_Mono,
299 destStoreMonoLsb, // Format_MonoLSB
300 0, // Format_Indexed8
302 destStoreARGB32, // Format_ARGB32,
303 0, // Format_ARGB32_Premultiplied
304 destStoreRGB16, // Format_RGB16
305 SPANFUNC_POINTER_DESTSTORE(qargb8565), // Format_ARGB8565_Premultiplied
306 SPANFUNC_POINTER_DESTSTORE(qrgb666), // Format_RGB666
307 SPANFUNC_POINTER_DESTSTORE(qargb6666), // Format_ARGB6666_Premultiplied
308 SPANFUNC_POINTER_DESTSTORE(qrgb555), // Format_RGB555
309 SPANFUNC_POINTER_DESTSTORE(qargb8555), // Format_ARGB8555_Premultiplied
310 SPANFUNC_POINTER_DESTSTORE(qrgb888), // Format_RGB888
311 SPANFUNC_POINTER_DESTSTORE(qrgb444), // Format_RGB444
312 SPANFUNC_POINTER_DESTSTORE(qargb4444) // Format_ARGB4444_Premultiplied
318 This is a bit more complicated, as we need several fetch routines for every surface type
320 We need 5 fetch methods per surface type:
322 transformed (tiled and not tiled)
323 transformed bilinear (tiled and not tiled)
325 We don't need bounds checks for untransformed, but we need them for the other ones.
327 The generic implementation does pixel by pixel fetches
330 template <QImage::Format format>
331 Q_STATIC_TEMPLATE_FUNCTION uint QT_FASTCALL qt_fetchPixel(const uchar *scanLine, int x, const QVector<QRgb> *rgb);
334 Q_STATIC_TEMPLATE_SPECIALIZATION
335 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Mono>(const uchar *scanLine,
336 int x, const QVector<QRgb> *rgb)
338 bool pixel = scanLine[x>>3] & (0x80 >> (x & 7));
339 if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
340 return pixel ? 0xff000000 : 0xffffffff;
344 Q_STATIC_TEMPLATE_SPECIALIZATION
345 uint QT_FASTCALL qt_fetchPixel<QImage::Format_MonoLSB>(const uchar *scanLine,
346 int x, const QVector<QRgb> *rgb)
348 bool pixel = scanLine[x>>3] & (0x1 << (x & 7));
349 if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
350 return pixel ? 0xff000000 : 0xffffffff;
354 Q_STATIC_TEMPLATE_SPECIALIZATION
355 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Indexed8>(const uchar *scanLine,
356 int x, const QVector<QRgb> *rgb)
358 return PREMUL(rgb->at(scanLine[x]));
362 Q_STATIC_TEMPLATE_SPECIALIZATION
363 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32>(const uchar *scanLine,
364 int x, const QVector<QRgb> *)
366 return PREMUL(((const uint *)scanLine)[x]);
370 Q_STATIC_TEMPLATE_SPECIALIZATION
371 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32_Premultiplied>(const uchar *scanLine,
372 int x, const QVector<QRgb> *)
374 return ((const uint *)scanLine)[x];
378 Q_STATIC_TEMPLATE_SPECIALIZATION
379 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB16>(const uchar *scanLine,
380 int x, const QVector<QRgb> *)
382 return qConvertRgb16To32(((const ushort *)scanLine)[x]);
386 Q_STATIC_TEMPLATE_SPECIALIZATION
387 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8565_Premultiplied>(const uchar *scanLine,
389 const QVector<QRgb> *)
391 const qargb8565 color = reinterpret_cast<const qargb8565*>(scanLine)[x];
392 return qt_colorConvert<quint32, qargb8565>(color, 0);
396 Q_STATIC_TEMPLATE_SPECIALIZATION
397 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB666>(const uchar *scanLine,
399 const QVector<QRgb> *)
401 const qrgb666 color = reinterpret_cast<const qrgb666*>(scanLine)[x];
402 return qt_colorConvert<quint32, qrgb666>(color, 0);
406 Q_STATIC_TEMPLATE_SPECIALIZATION
407 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB6666_Premultiplied>(const uchar *scanLine,
409 const QVector<QRgb> *)
411 const qargb6666 color = reinterpret_cast<const qargb6666*>(scanLine)[x];
412 return qt_colorConvert<quint32, qargb6666>(color, 0);
416 Q_STATIC_TEMPLATE_SPECIALIZATION
417 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB555>(const uchar *scanLine,
419 const QVector<QRgb> *)
421 const qrgb555 color = reinterpret_cast<const qrgb555*>(scanLine)[x];
422 return qt_colorConvert<quint32, qrgb555>(color, 0);
426 Q_STATIC_TEMPLATE_SPECIALIZATION
427 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8555_Premultiplied>(const uchar *scanLine,
429 const QVector<QRgb> *)
431 const qargb8555 color = reinterpret_cast<const qargb8555*>(scanLine)[x];
432 return qt_colorConvert<quint32, qargb8555>(color, 0);
436 Q_STATIC_TEMPLATE_SPECIALIZATION
437 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB888>(const uchar *scanLine,
439 const QVector<QRgb> *)
441 const qrgb888 color = reinterpret_cast<const qrgb888*>(scanLine)[x];
442 return qt_colorConvert<quint32, qrgb888>(color, 0);
446 Q_STATIC_TEMPLATE_SPECIALIZATION
447 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB444>(const uchar *scanLine,
449 const QVector<QRgb> *)
451 const qrgb444 color = reinterpret_cast<const qrgb444*>(scanLine)[x];
452 return qt_colorConvert<quint32, qrgb444>(color, 0);
456 Q_STATIC_TEMPLATE_SPECIALIZATION
457 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB4444_Premultiplied>(const uchar *scanLine,
459 const QVector<QRgb> *)
461 const qargb4444 color = reinterpret_cast<const qargb4444*>(scanLine)[x];
462 return qt_colorConvert<quint32, qargb4444>(color, 0);
466 Q_STATIC_TEMPLATE_SPECIALIZATION
467 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Invalid>(const uchar *,
469 const QVector<QRgb> *)
474 typedef uint (QT_FASTCALL *FetchPixelProc)(const uchar *scanLine, int x, const QVector<QRgb> *);
476 #define SPANFUNC_POINTER_FETCHPIXEL(Arg) qt_fetchPixel<QImage::Arg>
479 static const FetchPixelProc fetchPixelProc[QImage::NImageFormats] =
482 SPANFUNC_POINTER_FETCHPIXEL(Format_Mono),
483 SPANFUNC_POINTER_FETCHPIXEL(Format_MonoLSB),
484 SPANFUNC_POINTER_FETCHPIXEL(Format_Indexed8),
485 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
486 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32),
487 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
488 SPANFUNC_POINTER_FETCHPIXEL(Format_RGB16),
489 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8565_Premultiplied),
490 SPANFUNC_POINTER_FETCHPIXEL(Format_RGB666),
491 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB6666_Premultiplied),
492 SPANFUNC_POINTER_FETCHPIXEL(Format_RGB555),
493 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8555_Premultiplied),
494 SPANFUNC_POINTER_FETCHPIXEL(Format_RGB888),
495 SPANFUNC_POINTER_FETCHPIXEL(Format_RGB444),
496 SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB4444_Premultiplied)
499 enum TextureBlendType {
503 BlendTransformedTiled,
504 BlendTransformedBilinear,
505 BlendTransformedBilinearTiled,
509 template <QImage::Format format>
510 Q_STATIC_TEMPLATE_FUNCTION const uint * QT_FASTCALL qt_fetchUntransformed(uint *buffer, const Operator *, const QSpanData *data,
511 int y, int x, int length)
513 const uchar *scanLine = data->texture.scanLine(y);
514 for (int i = 0; i < length; ++i)
515 buffer[i] = qt_fetchPixel<format>(scanLine, x + i, data->texture.colorTable);
520 Q_STATIC_TEMPLATE_SPECIALIZATION const uint * QT_FASTCALL
521 qt_fetchUntransformed<QImage::Format_ARGB32_Premultiplied>(uint *, const Operator *,
522 const QSpanData *data,
525 const uchar *scanLine = data->texture.scanLine(y);
526 return ((const uint *)scanLine) + x;
529 template<TextureBlendType blendType> /* either BlendTransformed or BlendTransformedTiled */
530 Q_STATIC_TEMPLATE_FUNCTION
531 const uint * QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data,
532 int y, int x, int length)
534 FetchPixelProc fetch = fetchPixelProc[data->texture.format];
536 int image_width = data->texture.width;
537 int image_height = data->texture.height;
539 const qreal cx = x + qreal(0.5);
540 const qreal cy = y + qreal(0.5);
542 const uint *end = buffer + length;
544 if (data->fast_matrix) {
545 // The increment pr x in the scanline
546 int fdx = (int)(data->m11 * fixed_scale);
547 int fdy = (int)(data->m12 * fixed_scale);
549 int fx = int((data->m21 * cy
550 + data->m11 * cx + data->dx) * fixed_scale);
551 int fy = int((data->m22 * cy
552 + data->m12 * cx + data->dy) * fixed_scale);
558 if (blendType == BlendTransformedTiled) {
561 if (px < 0) px += image_width;
562 if (py < 0) py += image_height;
564 const uchar *scanLine = data->texture.scanLine(py);
565 *b = fetch(scanLine, px, data->texture.colorTable);
567 if ((px < 0) || (px >= image_width)
568 || (py < 0) || (py >= image_height)) {
571 const uchar *scanLine = data->texture.scanLine(py);
572 *b = fetch(scanLine, px, data->texture.colorTable);
580 const qreal fdx = data->m11;
581 const qreal fdy = data->m12;
582 const qreal fdw = data->m13;
584 qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
585 qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
586 qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
589 const qreal iw = fw == 0 ? 1 : 1 / fw;
590 const qreal tx = fx * iw;
591 const qreal ty = fy * iw;
592 int px = int(tx) - (tx < 0);
593 int py = int(ty) - (ty < 0);
595 if (blendType == BlendTransformedTiled) {
598 if (px < 0) px += image_width;
599 if (py < 0) py += image_height;
601 const uchar *scanLine = data->texture.scanLine(py);
602 *b = fetch(scanLine, px, data->texture.colorTable);
604 if ((px < 0) || (px >= image_width)
605 || (py < 0) || (py >= image_height)) {
608 const uchar *scanLine = data->texture.scanLine(py);
609 *b = fetch(scanLine, px, data->texture.colorTable);
615 //force increment to avoid /0
627 interpolate 4 argb pixels with the distx and disty factor.
628 distx and disty bust be between 0 and 16
630 static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, int distx, int disty)
632 uint distxy = distx * disty;
633 //idistx * disty = (16-distx) * disty = 16*disty - distxy
634 //idistx * idisty = (16-distx) * (16-disty) = 16*16 - 16*distx -16*dity + distxy
635 uint tlrb = (tl & 0x00ff00ff) * (16*16 - 16*distx - 16*disty + distxy);
636 uint tlag = ((tl & 0xff00ff00) >> 8) * (16*16 - 16*distx - 16*disty + distxy);
637 uint trrb = ((tr & 0x00ff00ff) * (distx*16 - distxy));
638 uint trag = (((tr & 0xff00ff00) >> 8) * (distx*16 - distxy));
639 uint blrb = ((bl & 0x00ff00ff) * (disty*16 - distxy));
640 uint blag = (((bl & 0xff00ff00) >> 8) * (disty*16 - distxy));
641 uint brrb = ((br & 0x00ff00ff) * (distxy));
642 uint brag = (((br & 0xff00ff00) >> 8) * (distxy));
643 return (((tlrb + trrb + blrb + brrb) >> 8) & 0x00ff00ff) | ((tlag + trag + blag + brag) & 0xff00ff00);
646 #if defined(QT_ALWAYS_HAVE_SSE2)
647 #define interpolate_4_pixels_16_sse2(tl, tr, bl, br, distx, disty, colorMask, v_256, b) \
649 const __m128i dxdy = _mm_mullo_epi16 (distx, disty); \
650 const __m128i distx_ = _mm_slli_epi16(distx, 4); \
651 const __m128i disty_ = _mm_slli_epi16(disty, 4); \
652 const __m128i idxidy = _mm_add_epi16(dxdy, _mm_sub_epi16(v_256, _mm_add_epi16(distx_, disty_))); \
653 const __m128i dxidy = _mm_sub_epi16(distx_, dxdy); \
654 const __m128i idxdy = _mm_sub_epi16(disty_, dxdy); \
656 __m128i tlAG = _mm_srli_epi16(tl, 8); \
657 __m128i tlRB = _mm_and_si128(tl, colorMask); \
658 __m128i trAG = _mm_srli_epi16(tr, 8); \
659 __m128i trRB = _mm_and_si128(tr, colorMask); \
660 __m128i blAG = _mm_srli_epi16(bl, 8); \
661 __m128i blRB = _mm_and_si128(bl, colorMask); \
662 __m128i brAG = _mm_srli_epi16(br, 8); \
663 __m128i brRB = _mm_and_si128(br, colorMask); \
665 tlAG = _mm_mullo_epi16(tlAG, idxidy); \
666 tlRB = _mm_mullo_epi16(tlRB, idxidy); \
667 trAG = _mm_mullo_epi16(trAG, dxidy); \
668 trRB = _mm_mullo_epi16(trRB, dxidy); \
669 blAG = _mm_mullo_epi16(blAG, idxdy); \
670 blRB = _mm_mullo_epi16(blRB, idxdy); \
671 brAG = _mm_mullo_epi16(brAG, dxdy); \
672 brRB = _mm_mullo_epi16(brRB, dxdy); \
674 /* Add the values, and shift to only keep 8 significant bits per colors */ \
675 __m128i rAG =_mm_add_epi16(_mm_add_epi16(tlAG, trAG), _mm_add_epi16(blAG, brAG)); \
676 __m128i rRB =_mm_add_epi16(_mm_add_epi16(tlRB, trRB), _mm_add_epi16(blRB, brRB)); \
677 rAG = _mm_andnot_si128(colorMask, rAG); \
678 rRB = _mm_srli_epi16(rRB, 8); \
679 _mm_storeu_si128((__m128i*)(b), _mm_or_si128(rAG, rRB)); \
683 #if defined(QT_ALWAYS_HAVE_NEON)
684 #define interpolate_4_pixels_16_neon(tl, tr, bl, br, distx, disty, disty_, colorMask, invColorMask, v_256, b) \
686 const int16x8_t dxdy = vmulq_s16(distx, disty); \
687 const int16x8_t distx_ = vshlq_n_s16(distx, 4); \
688 const int16x8_t idxidy = vaddq_s16(dxdy, vsubq_s16(v_256, vaddq_s16(distx_, disty_))); \
689 const int16x8_t dxidy = vsubq_s16(distx_, dxdy); \
690 const int16x8_t idxdy = vsubq_s16(disty_, dxdy); \
692 int16x8_t tlAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tl), 8)); \
693 int16x8_t tlRB = vandq_s16(tl, colorMask); \
694 int16x8_t trAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tr), 8)); \
695 int16x8_t trRB = vandq_s16(tr, colorMask); \
696 int16x8_t blAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bl), 8)); \
697 int16x8_t blRB = vandq_s16(bl, colorMask); \
698 int16x8_t brAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(br), 8)); \
699 int16x8_t brRB = vandq_s16(br, colorMask); \
701 int16x8_t rAG = vmulq_s16(tlAG, idxidy); \
702 int16x8_t rRB = vmulq_s16(tlRB, idxidy); \
703 rAG = vmlaq_s16(rAG, trAG, dxidy); \
704 rRB = vmlaq_s16(rRB, trRB, dxidy); \
705 rAG = vmlaq_s16(rAG, blAG, idxdy); \
706 rRB = vmlaq_s16(rRB, blRB, idxdy); \
707 rAG = vmlaq_s16(rAG, brAG, dxdy); \
708 rRB = vmlaq_s16(rRB, brRB, dxdy); \
710 rAG = vandq_s16(invColorMask, rAG); \
711 rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8)); \
712 vst1q_s16((int16_t*)(b), vorrq_s16(rAG, rRB)); \
716 template<TextureBlendType blendType>
717 Q_STATIC_TEMPLATE_FUNCTION inline void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2)
719 if (blendType == BlendTransformedBilinearTiled) {
721 if (v1 < 0) v1 += max;
727 } else if (v1 >= l2) {
734 Q_ASSERT(v1 >= 0 && v1 < max);
735 Q_ASSERT(v2 >= 0 && v2 < max);
738 template<TextureBlendType blendType, QImage::Format format> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
739 Q_STATIC_TEMPLATE_FUNCTION
740 const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *, const QSpanData *data,
741 int y, int x, int length)
743 #ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
744 FetchPixelProc fetch;
745 if (format != QImage::Format_Invalid)
746 fetch = qt_fetchPixel<format>;
748 fetch = fetchPixelProc[data->texture.format];
750 FetchPixelProc fetch = (format != QImage::Format_Invalid) ? FetchPixelProc(qt_fetchPixel<format>) : fetchPixelProc[data->texture.format];
753 int image_width = data->texture.width;
754 int image_height = data->texture.height;
756 int image_x1 = data->texture.x1;
757 int image_y1 = data->texture.y1;
758 int image_x2 = data->texture.x2 - 1;
759 int image_y2 = data->texture.y2 - 1;
761 const qreal cx = x + qreal(0.5);
762 const qreal cy = y + qreal(0.5);
764 uint *end = buffer + length;
766 if (data->fast_matrix) {
767 // The increment pr x in the scanline
768 int fdx = (int)(data->m11 * fixed_scale);
769 int fdy = (int)(data->m12 * fixed_scale);
771 int fx = int((data->m21 * cy
772 + data->m11 * cx + data->dx) * fixed_scale);
773 int fy = int((data->m22 * cy
774 + data->m12 * cx + data->dy) * fixed_scale);
779 if (fdy == 0) { //simple scale, no rotation
782 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
783 const uchar *s1 = data->texture.scanLine(y1);
784 const uchar *s2 = data->texture.scanLine(y2);
786 if (fdx <= fixed_scale && fdx > 0) { // scale up on X
787 int disty = (fy & 0x0000ffff) >> 8;
788 int idisty = 256 - disty;
791 // The idea is first to do the interpolation between the row s1 and the row s2
792 // into an intermediate buffer, then we interpolate between two pixel of this buffer.
794 // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
795 // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG
796 quint32 intermediate_buffer[2][buffer_size + 2];
797 // count is the size used in the intermediate_buffer.
798 int count = qCeil(length * data->m11) + 2; //+1 for the last pixel to interpolate with, and +1 for rounding errors.
799 Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
802 if (blendType == BlendTransformedBilinearTiled) {
804 if (x < 0) x += image_width;
806 lim = qMin(count, image_x2-x+1);
808 Q_ASSERT(x <= image_x2);
809 uint t = fetch(s1, image_x1, data->texture.colorTable);
810 uint b = fetch(s2, image_x1, data->texture.colorTable);
811 quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
812 quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
814 intermediate_buffer[0][f] = rb;
815 intermediate_buffer[1][f] = ag;
818 } while (x < image_x1 && f < lim);
822 if (blendType != BlendTransformedBilinearTiled &&
823 (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)) {
824 #if defined(QT_ALWAYS_HAVE_SSE2)
825 const __m128i disty_ = _mm_set1_epi16(disty);
826 const __m128i idisty_ = _mm_set1_epi16(idisty);
827 const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
830 for (; f < lim; x += 4, f += 4) {
831 // Load 4 pixels from s1, and split the alpha-green and red-blue component
832 __m128i top = _mm_loadu_si128((__m128i*)((const uint *)(s1)+x));
833 __m128i topAG = _mm_srli_epi16(top, 8);
834 __m128i topRB = _mm_and_si128(top, colorMask);
835 // Multiplies each colour component by idisty
836 topAG = _mm_mullo_epi16 (topAG, idisty_);
837 topRB = _mm_mullo_epi16 (topRB, idisty_);
839 // Same for the s2 vector
840 __m128i bottom = _mm_loadu_si128((__m128i*)((const uint *)(s2)+x));
841 __m128i bottomAG = _mm_srli_epi16(bottom, 8);
842 __m128i bottomRB = _mm_and_si128(bottom, colorMask);
843 bottomAG = _mm_mullo_epi16 (bottomAG, disty_);
844 bottomRB = _mm_mullo_epi16 (bottomRB, disty_);
846 // Add the values, and shift to only keep 8 significant bits per colors
847 __m128i rAG =_mm_add_epi16(topAG, bottomAG);
848 rAG = _mm_srli_epi16(rAG, 8);
849 _mm_storeu_si128((__m128i*)(&intermediate_buffer[1][f]), rAG);
850 __m128i rRB =_mm_add_epi16(topRB, bottomRB);
851 rRB = _mm_srli_epi16(rRB, 8);
852 _mm_storeu_si128((__m128i*)(&intermediate_buffer[0][f]), rRB);
854 #elif defined(QT_ALWAYS_HAVE_NEON)
855 const int16x8_t disty_ = vdupq_n_s16(disty);
856 const int16x8_t idisty_ = vdupq_n_s16(idisty);
857 const int16x8_t colorMask = vdupq_n_s16(0x00ff);
860 for (; f < lim; x += 4, f += 4) {
861 // Load 4 pixels from s1, and split the alpha-green and red-blue component
862 int16x8_t top = vld1q_s16((int16_t*)((const uint *)(s1)+x));
863 int16x8_t topAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(top), 8));
864 int16x8_t topRB = vandq_s16(top, colorMask);
865 // Multiplies each colour component by idisty
866 topAG = vmulq_s16(topAG, idisty_);
867 topRB = vmulq_s16(topRB, idisty_);
869 // Same for the s2 vector
870 int16x8_t bottom = vld1q_s16((int16_t*)((const uint *)(s2)+x));
871 int16x8_t bottomAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bottom), 8));
872 int16x8_t bottomRB = vandq_s16(bottom, colorMask);
873 bottomAG = vmulq_s16(bottomAG, disty_);
874 bottomRB = vmulq_s16(bottomRB, disty_);
876 // Add the values, and shift to only keep 8 significant bits per colors
877 int16x8_t rAG = vaddq_s16(topAG, bottomAG);
878 rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8));
879 vst1q_s16((int16_t*)(&intermediate_buffer[1][f]), rAG);
880 int16x8_t rRB = vaddq_s16(topRB, bottomRB);
881 rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8));
882 vst1q_s16((int16_t*)(&intermediate_buffer[0][f]), rRB);
886 for (; f < count; f++) { // Same as above but without sse2
887 if (blendType == BlendTransformedBilinearTiled) {
888 if (x >= image_width) x -= image_width;
890 x = qMin(x, image_x2);
893 uint t = fetch(s1, x, data->texture.colorTable);
894 uint b = fetch(s2, x, data->texture.colorTable);
896 intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
897 intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
900 // Now interpolate the values from the intermediate_buffer to get the final result.
901 fx &= fixed_scale - 1;
902 Q_ASSERT((fx >> 16) == 0);
904 register int x1 = (fx >> 16);
905 register int x2 = x1 + 1;
907 Q_ASSERT(x2 < count);
909 register int distx = (fx & 0x0000ffff) >> 8;
910 register int idistx = 256 - distx;
911 int rb = ((intermediate_buffer[0][x1] * idistx + intermediate_buffer[0][x2] * distx) >> 8) & 0xff00ff;
912 int ag = (intermediate_buffer[1][x1] * idistx + intermediate_buffer[1][x2] * distx) & 0xff00ff00;
917 } else if ((fdx < 0 && fdx > -(fixed_scale / 8)) || fabs(data->m22) < (1./8.)) { // scale up more than 8x
920 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
921 const uchar *s1 = data->texture.scanLine(y1);
922 const uchar *s2 = data->texture.scanLine(y2);
923 int disty = (fy & 0x0000ffff) >> 8;
924 int idisty = 256 - disty;
928 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
929 uint tl = fetch(s1, x1, data->texture.colorTable);
930 uint tr = fetch(s1, x2, data->texture.colorTable);
931 uint bl = fetch(s2, x1, data->texture.colorTable);
932 uint br = fetch(s2, x2, data->texture.colorTable);
934 int distx = (fx & 0x0000ffff) >> 8;
935 int idistx = 256 - distx;
937 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
938 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
939 *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
944 } else { //scale down
947 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
948 const uchar *s1 = data->texture.scanLine(y1);
949 const uchar *s2 = data->texture.scanLine(y2);
950 int disty = (fy & 0x0000ffff) >> 12;
952 if (blendType != BlendTransformedBilinearTiled &&
953 (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)) {
955 #define BILINEAR_DOWNSCALE_BOUNDS_PROLOG \
957 int x1 = (fx >> 16); \
959 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); \
962 uint tl = fetch(s1, x1, data->texture.colorTable); \
963 uint tr = fetch(s1, x2, data->texture.colorTable); \
964 uint bl = fetch(s2, x1, data->texture.colorTable); \
965 uint br = fetch(s2, x2, data->texture.colorTable); \
966 int distx = (fx & 0x0000ffff) >> 12; \
967 *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty); \
973 boundedEnd = qMin(end, buffer + uint((image_x2 - (fx >> 16)) / data->m11)); \
975 boundedEnd = qMin(end, buffer + uint((image_x1 - (fx >> 16)) / data->m11)); \
978 #if defined(QT_ALWAYS_HAVE_SSE2)
979 BILINEAR_DOWNSCALE_BOUNDS_PROLOG
981 const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
982 const __m128i v_256 = _mm_set1_epi16(256);
983 const __m128i v_disty = _mm_set1_epi16(disty);
984 __m128i v_fdx = _mm_set1_epi32(fdx*4);
986 ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
988 union Vect_buffer { __m128i vect; quint32 i[4]; };
991 for (int i = 0; i < 4; i++) {
996 while (b < boundedEnd) {
998 Vect_buffer tl, tr, bl, br;
1000 for (int i = 0; i < 4; i++) {
1001 int x1 = v_fx.i[i] >> 16;
1002 const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1003 const uint *addr_tr = addr_tl + 1;
1006 bl.i[i] = *(addr_tl+secondLine);
1007 br.i[i] = *(addr_tr+secondLine);
1009 __m128i v_distx = _mm_srli_epi16(v_fx.vect, 12);
1010 v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1011 v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1013 interpolate_4_pixels_16_sse2(tl.vect, tr.vect, bl.vect, br.vect, v_distx, v_disty, colorMask, v_256, b);
1015 v_fx.vect = _mm_add_epi32(v_fx.vect, v_fdx);
1018 #elif defined(QT_ALWAYS_HAVE_NEON)
1019 BILINEAR_DOWNSCALE_BOUNDS_PROLOG
1021 const int16x8_t colorMask = vdupq_n_s16(0x00ff);
1022 const int16x8_t invColorMask = vmvnq_s16(colorMask);
1023 const int16x8_t v_256 = vdupq_n_s16(256);
1024 const int16x8_t v_disty = vdupq_n_s16(disty);
1025 const int16x8_t v_disty_ = vshlq_n_s16(v_disty, 4);
1026 int32x4_t v_fdx = vdupq_n_s32(fdx*4);
1028 ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
1030 union Vect_buffer { int32x4_t vect; quint32 i[4]; };
1033 for (int i = 0; i < 4; i++) {
1038 const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
1040 while (b < boundedEnd) {
1042 Vect_buffer tl, tr, bl, br;
1044 Vect_buffer v_fx_shifted;
1045 v_fx_shifted.vect = vshrq_n_s32(v_fx.vect, 16);
1047 int32x4_t v_distx = vshrq_n_s32(vandq_s32(v_fx.vect, v_ffff_mask), 12);
1049 for (int i = 0; i < 4; i++) {
1050 int x1 = v_fx_shifted.i[i];
1051 const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1052 const uint *addr_tr = addr_tl + 1;
1055 bl.i[i] = *(addr_tl+secondLine);
1056 br.i[i] = *(addr_tr+secondLine);
1059 v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
1061 interpolate_4_pixels_16_neon(vreinterpretq_s16_s32(tl.vect), vreinterpretq_s16_s32(tr.vect), vreinterpretq_s16_s32(bl.vect), vreinterpretq_s16_s32(br.vect), vreinterpretq_s16_s32(v_distx), v_disty, v_disty_, colorMask, invColorMask, v_256, b);
1063 v_fx.vect = vaddq_s32(v_fx.vect, v_fdx);
1070 int x1 = (fx >> 16);
1072 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1073 uint tl = fetch(s1, x1, data->texture.colorTable);
1074 uint tr = fetch(s1, x2, data->texture.colorTable);
1075 uint bl = fetch(s2, x1, data->texture.colorTable);
1076 uint br = fetch(s2, x2, data->texture.colorTable);
1077 int distx = (fx & 0x0000ffff) >> 12;
1078 *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1084 if (fabs(data->m11) > 8 || fabs(data->m22) > 8) {
1085 //if we are zooming more than 8 times, we use 8bit precision for the position.
1087 int x1 = (fx >> 16);
1089 int y1 = (fy >> 16);
1092 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1093 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1095 const uchar *s1 = data->texture.scanLine(y1);
1096 const uchar *s2 = data->texture.scanLine(y2);
1098 uint tl = fetch(s1, x1, data->texture.colorTable);
1099 uint tr = fetch(s1, x2, data->texture.colorTable);
1100 uint bl = fetch(s2, x1, data->texture.colorTable);
1101 uint br = fetch(s2, x2, data->texture.colorTable);
1103 int distx = (fx & 0x0000ffff) >> 8;
1104 int disty = (fy & 0x0000ffff) >> 8;
1105 int idistx = 256 - distx;
1106 int idisty = 256 - disty;
1108 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1109 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1110 *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1117 //we are zooming less than 8x, use 4bit precision
1119 int x1 = (fx >> 16);
1121 int y1 = (fy >> 16);
1124 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1125 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1127 const uchar *s1 = data->texture.scanLine(y1);
1128 const uchar *s2 = data->texture.scanLine(y2);
1130 uint tl = fetch(s1, x1, data->texture.colorTable);
1131 uint tr = fetch(s1, x2, data->texture.colorTable);
1132 uint bl = fetch(s2, x1, data->texture.colorTable);
1133 uint br = fetch(s2, x2, data->texture.colorTable);
1135 int distx = (fx & 0x0000ffff) >> 12;
1136 int disty = (fy & 0x0000ffff) >> 12;
1138 *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1147 const qreal fdx = data->m11;
1148 const qreal fdy = data->m12;
1149 const qreal fdw = data->m13;
1151 qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
1152 qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
1153 qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
1156 const qreal iw = fw == 0 ? 1 : 1 / fw;
1157 const qreal px = fx * iw - qreal(0.5);
1158 const qreal py = fy * iw - qreal(0.5);
1160 int x1 = int(px) - (px < 0);
1162 int y1 = int(py) - (py < 0);
1165 int distx = int((px - x1) * 256);
1166 int disty = int((py - y1) * 256);
1167 int idistx = 256 - distx;
1168 int idisty = 256 - disty;
1170 fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1171 fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1173 const uchar *s1 = data->texture.scanLine(y1);
1174 const uchar *s2 = data->texture.scanLine(y2);
1176 uint tl = fetch(s1, x1, data->texture.colorTable);
1177 uint tr = fetch(s1, x2, data->texture.colorTable);
1178 uint bl = fetch(s2, x1, data->texture.colorTable);
1179 uint br = fetch(s2, x2, data->texture.colorTable);
1181 uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1182 uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1183 *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1188 //force increment to avoid /0
1199 #define SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Arg) qt_fetchUntransformed<QImage::Arg>
1201 static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = {
1205 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono), // Mono
1206 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB), // MonoLsb
1207 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8), // Indexed8
1208 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // RGB32
1209 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32), // ARGB32
1210 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // ARGB32_Premultiplied
1211 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16), // RGB16
1212 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
1213 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666), // RGB666
1214 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
1215 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555), // RGB555
1216 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
1217 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888), // RGB888
1218 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444), // RGB444
1219 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
1224 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono), // Mono
1225 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB), // MonoLsb
1226 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8), // Indexed8
1227 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // RGB32
1228 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32), // ARGB32
1229 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // ARGB32_Premultiplied
1230 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16), // RGB16
1231 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
1232 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666), // RGB666
1233 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
1234 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555), // RGB555
1235 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
1236 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888), // RGB888
1237 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444), // RGB444
1238 SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
1243 fetchTransformed<BlendTransformed>, // Mono
1244 fetchTransformed<BlendTransformed>, // MonoLsb
1245 fetchTransformed<BlendTransformed>, // Indexed8
1246 fetchTransformed<BlendTransformed>, // RGB32
1247 fetchTransformed<BlendTransformed>, // ARGB32
1248 fetchTransformed<BlendTransformed>, // ARGB32_Premultiplied
1249 fetchTransformed<BlendTransformed>, // RGB16
1250 fetchTransformed<BlendTransformed>, // ARGB8565_Premultiplied
1251 fetchTransformed<BlendTransformed>, // RGB666
1252 fetchTransformed<BlendTransformed>, // ARGB6666_Premultiplied
1253 fetchTransformed<BlendTransformed>, // RGB555
1254 fetchTransformed<BlendTransformed>, // ARGB8555_Premultiplied
1255 fetchTransformed<BlendTransformed>, // RGB888
1256 fetchTransformed<BlendTransformed>, // RGB444
1257 fetchTransformed<BlendTransformed>, // ARGB4444_Premultiplied
1260 0, // TransformedTiled
1261 fetchTransformed<BlendTransformedTiled>, // Mono
1262 fetchTransformed<BlendTransformedTiled>, // MonoLsb
1263 fetchTransformed<BlendTransformedTiled>, // Indexed8
1264 fetchTransformed<BlendTransformedTiled>, // RGB32
1265 fetchTransformed<BlendTransformedTiled>, // ARGB32
1266 fetchTransformed<BlendTransformedTiled>, // ARGB32_Premultiplied
1267 fetchTransformed<BlendTransformedTiled>, // RGB16
1268 fetchTransformed<BlendTransformedTiled>, // ARGB8565_Premultiplied
1269 fetchTransformed<BlendTransformedTiled>, // RGB666
1270 fetchTransformed<BlendTransformedTiled>, // ARGB6666_Premultiplied
1271 fetchTransformed<BlendTransformedTiled>, // RGB555
1272 fetchTransformed<BlendTransformedTiled>, // ARGB8555_Premultiplied
1273 fetchTransformed<BlendTransformedTiled>, // RGB888
1274 fetchTransformed<BlendTransformedTiled>, // RGB444
1275 fetchTransformed<BlendTransformedTiled>, // ARGB4444_Premultiplied
1279 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // Mono
1280 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // MonoLsb
1281 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // Indexed8
1282 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>, // RGB32
1283 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32>, // ARGB32
1284 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>, // ARGB32_Premultiplied
1285 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB16
1286 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB8565_Premultiplied
1287 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB666
1288 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB6666_Premultiplied
1289 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB555
1290 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB8555_Premultiplied
1291 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB888
1292 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB444
1293 fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid> // ARGB4444_Premultiplied
1297 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // Mono
1298 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // MonoLsb
1299 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // Indexed8
1300 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>, // RGB32
1301 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32>, // ARGB32
1302 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>, // ARGB32_Premultiplied
1303 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB16
1304 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB8565_Premultiplied
1305 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB666
1306 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB6666_Premultiplied
1307 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB555
1308 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB8555_Premultiplied
1309 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB888
1310 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB444
1311 fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid> // ARGB4444_Premultiplied
1315 #define FIXPT_BITS 8
1316 #define FIXPT_SIZE (1<<FIXPT_BITS)
1318 static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
1320 int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
1321 return data->colorTable[qt_gradient_clamp(data, ipos)];
1324 static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
1326 v->dx = data->gradient.linear.end.x - data->gradient.linear.origin.x;
1327 v->dy = data->gradient.linear.end.y - data->gradient.linear.origin.y;
1328 v->l = v->dx * v->dx + v->dy * v->dy;
1333 v->off = -v->dx * data->gradient.linear.origin.x - v->dy * data->gradient.linear.origin.y;
1337 static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data,
1338 int y, int x, int length)
1340 const uint *b = buffer;
1345 if (op->linear.l == 0) {
1348 rx = data->m21 * (y + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx;
1349 ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(0.5)) + data->dy;
1350 t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off;
1351 inc = op->linear.dx * data->m11 + op->linear.dy * data->m12;
1352 affine = !data->m13 && !data->m23;
1355 t *= (GRADIENT_STOPTABLE_SIZE - 1);
1356 inc *= (GRADIENT_STOPTABLE_SIZE - 1);
1360 const uint *end = buffer + length;
1362 if (inc > qreal(-1e-5) && inc < qreal(1e-5)) {
1363 QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE)));
1365 if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) &&
1366 t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) {
1367 // we can use fixed point math
1368 int t_fixed = int(t * FIXPT_SIZE);
1369 int inc_fixed = int(inc * FIXPT_SIZE);
1370 while (buffer < end) {
1371 *buffer = qt_gradient_pixel_fixed(&data->gradient, t_fixed);
1372 t_fixed += inc_fixed;
1376 // we have to fall back to float math
1377 while (buffer < end) {
1378 *buffer = qt_gradient_pixel(&data->gradient, t/GRADIENT_STOPTABLE_SIZE);
1384 } else { // fall back to float math here as well
1385 qreal rw = data->m23 * (y + qreal(0.5)) + data->m13 * (x + qreal(0.5)) + data->m33;
1386 while (buffer < end) {
1389 t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off;
1391 *buffer = qt_gradient_pixel(&data->gradient, t);
1405 static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
1407 v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x;
1408 v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y;
1410 v->dr = data->gradient.radial.center.radius - data->gradient.radial.focal.radius;
1411 v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius;
1413 v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy;
1414 v->inv2a = 1 / (2 * v->a);
1416 v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0;
1419 class RadialFetchPlain
1422 static inline void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det,
1423 qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b)
1425 if (op->radial.extended) {
1426 while (buffer < end) {
1429 qreal w = qSqrt(det) - b;
1430 if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0)
1431 result = qt_gradient_pixel(&data->gradient, w);
1437 delta_det += delta_delta_det;
1443 while (buffer < end) {
1444 *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b);
1447 delta_det += delta_delta_det;
1454 const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data,
1455 int y, int x, int length)
1457 return qt_fetch_radial_gradient_template<RadialFetchPlain>(buffer, op, data, y, x, length);
1460 static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain;
1462 static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data,
1463 int y, int x, int length)
1465 const uint *b = buffer;
1466 qreal rx = data->m21 * (y + qreal(0.5))
1467 + data->dx + data->m11 * (x + qreal(0.5));
1468 qreal ry = data->m22 * (y + qreal(0.5))
1469 + data->dy + data->m12 * (x + qreal(0.5));
1470 bool affine = !data->m13 && !data->m23;
1472 const uint *end = buffer + length;
1474 rx -= data->gradient.conical.center.x;
1475 ry -= data->gradient.conical.center.y;
1476 while (buffer < end) {
1477 qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle;
1479 *buffer = qt_gradient_pixel(&data->gradient, 1 - angle / (2*Q_PI));
1486 qreal rw = data->m23 * (y + qreal(0.5))
1487 + data->m33 + data->m13 * (x + qreal(0.5));
1490 while (buffer < end) {
1491 qreal angle = qAtan2(ry/rw - data->gradient.conical.center.x,
1492 rx/rw - data->gradient.conical.center.y)
1493 + data->gradient.conical.angle;
1495 *buffer = qt_gradient_pixel(&data->gradient, 1. - angle / (2*Q_PI));
1509 #if defined(Q_CC_RVCT)
1510 // Force ARM code generation for comp_func_* -methods
1513 # if defined(QT_HAVE_ARMV6)
1514 static __forceinline void preload(const uint *start)
1516 asm( "pld [start]" );
1518 static const uint L2CacheLineLength = 32;
1519 static const uint L2CacheLineLengthInInts = L2CacheLineLength/sizeof(uint);
1520 # define PRELOAD_INIT(x) preload(x);
1521 # define PRELOAD_INIT2(x,y) PRELOAD_INIT(x) PRELOAD_INIT(y)
1522 # define PRELOAD_COND(x) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts);
1523 // Two consecutive preloads stall, so space them out a bit by using different modulus.
1524 # define PRELOAD_COND2(x,y) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); \
1525 if (((uint)&y[i])%L2CacheLineLength == 16) preload(&y[i] + L2CacheLineLengthInInts);
1526 # endif // QT_HAVE_ARMV6
1529 #if !defined(Q_CC_RVCT) || !defined(QT_HAVE_ARMV6)
1530 # define PRELOAD_INIT(x)
1531 # define PRELOAD_INIT2(x,y)
1532 # define PRELOAD_COND(x)
1533 # define PRELOAD_COND2(x,y)
1536 /* The constant alpha factor describes an alpha factor that gets applied
1537 to the result of the composition operation combining it with the destination.
1539 The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1.
1540 we get the unmodified operation
1542 result = src op dest
1543 dest = result * const_alpha + dest * (1. - const_alpha)
1545 This means that in the comments below, the first line is the const_alpha==255 case, the
1546 second line the general one.
1549 s == src, sa == alpha(src), sia = 1 - alpha(src)
1550 d == dest, da == alpha(dest), dia = 1 - alpha(dest)
1551 ca = const_alpha, cia = 1 - const_alpha
1553 The methods exist in two variants. One where we have a constant source, the other
1554 where the source is an array of pixels.
1561 #define comp_func_Clear_impl(dest, length, const_alpha)\
1563 if (const_alpha == 255) {\
1564 QT_MEMFILL_UINT(dest, length, 0);\
1566 int ialpha = 255 - const_alpha;\
1568 for (int i = 0; i < length; ++i) {\
1570 dest[i] = BYTE_MUL(dest[i], ialpha);\
1575 void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
1577 comp_func_Clear_impl(dest, length, const_alpha);
1580 void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
1582 comp_func_Clear_impl(dest, length, const_alpha);
1587 dest = s * ca + d * cia
1589 void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha)
1591 if (const_alpha == 255) {
1592 QT_MEMFILL_UINT(dest, length, color);
1594 int ialpha = 255 - const_alpha;
1595 color = BYTE_MUL(color, const_alpha);
1597 for (int i = 0; i < length; ++i) {
1599 dest[i] = color + BYTE_MUL(dest[i], ialpha);
1604 void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length, uint const_alpha)
1606 if (const_alpha == 255) {
1607 ::memcpy(dest, src, length * sizeof(uint));
1609 int ialpha = 255 - const_alpha;
1610 PRELOAD_INIT2(dest, src)
1611 for (int i = 0; i < length; ++i) {
1612 PRELOAD_COND2(dest, src)
1613 dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha);
1618 void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
1622 void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint)
1627 result = s + d * sia
1628 dest = (s + d * sia) * ca + d * cia
1629 = s * ca + d * (sia * ca + cia)
1630 = s * ca + d * (1 - sa*ca)
1632 void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha)
1634 if ((const_alpha & qAlpha(color)) == 255) {
1635 QT_MEMFILL_UINT(dest, length, color);
1637 if (const_alpha != 255)
1638 color = BYTE_MUL(color, const_alpha);
1640 for (int i = 0; i < length; ++i) {
1642 dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color));
1647 void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha)
1649 PRELOAD_INIT2(dest, src)
1650 if (const_alpha == 255) {
1651 for (int i = 0; i < length; ++i) {
1652 PRELOAD_COND2(dest, src)
1654 if (s >= 0xff000000)
1657 dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
1660 for (int i = 0; i < length; ++i) {
1661 PRELOAD_COND2(dest, src)
1662 uint s = BYTE_MUL(src[i], const_alpha);
1663 dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
1669 result = d + s * dia
1670 dest = (d + s * dia) * ca + d * cia
1673 void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha)
1675 if (const_alpha != 255)
1676 color = BYTE_MUL(color, const_alpha);
1678 for (int i = 0; i < length; ++i) {
1681 dest[i] = d + BYTE_MUL(color, qAlpha(~d));
1685 void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha)
1687 PRELOAD_INIT2(dest, src)
1688 if (const_alpha == 255) {
1689 for (int i = 0; i < length; ++i) {
1690 PRELOAD_COND2(dest, src)
1692 dest[i] = d + BYTE_MUL(src[i], qAlpha(~d));
1695 for (int i = 0; i < length; ++i) {
1696 PRELOAD_COND2(dest, src)
1698 uint s = BYTE_MUL(src[i], const_alpha);
1699 dest[i] = d + BYTE_MUL(s, qAlpha(~d));
1706 dest = s * da * ca + d * cia
1708 void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha)
1711 if (const_alpha == 255) {
1712 for (int i = 0; i < length; ++i) {
1714 dest[i] = BYTE_MUL(color, qAlpha(dest[i]));
1717 color = BYTE_MUL(color, const_alpha);
1718 uint cia = 255 - const_alpha;
1719 for (int i = 0; i < length; ++i) {
1722 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia);
1727 void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha)
1729 PRELOAD_INIT2(dest, src)
1730 if (const_alpha == 255) {
1731 for (int i = 0; i < length; ++i) {
1732 PRELOAD_COND2(dest, src)
1733 dest[i] = BYTE_MUL(src[i], qAlpha(dest[i]));
1736 uint cia = 255 - const_alpha;
1737 for (int i = 0; i < length; ++i) {
1738 PRELOAD_COND2(dest, src)
1740 uint s = BYTE_MUL(src[i], const_alpha);
1741 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia);
1748 dest = d * sa * ca + d * cia
1749 = d * (sa * ca + cia)
1751 void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha)
1753 uint a = qAlpha(color);
1754 if (const_alpha != 255) {
1755 a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
1758 for (int i = 0; i < length; ++i) {
1760 dest[i] = BYTE_MUL(dest[i], a);
1764 void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha)
1766 PRELOAD_INIT2(dest, src)
1767 if (const_alpha == 255) {
1768 for (int i = 0; i < length; ++i) {
1769 PRELOAD_COND2(dest, src)
1770 dest[i] = BYTE_MUL(dest[i], qAlpha(src[i]));
1773 int cia = 255 - const_alpha;
1774 for (int i = 0; i < length; ++i) {
1775 PRELOAD_COND2(dest, src)
1776 uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia;
1777 dest[i] = BYTE_MUL(dest[i], a);
1784 dest = s * dia * ca + d * cia
1787 void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha)
1790 if (const_alpha == 255) {
1791 for (int i = 0; i < length; ++i) {
1793 dest[i] = BYTE_MUL(color, qAlpha(~dest[i]));
1796 color = BYTE_MUL(color, const_alpha);
1797 int cia = 255 - const_alpha;
1798 for (int i = 0; i < length; ++i) {
1801 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia);
1806 void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha)
1808 PRELOAD_INIT2(dest, src)
1809 if (const_alpha == 255) {
1810 for (int i = 0; i < length; ++i) {
1811 PRELOAD_COND2(dest, src)
1812 dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i]));
1815 int cia = 255 - const_alpha;
1816 for (int i = 0; i < length; ++i) {
1817 PRELOAD_COND2(dest, src)
1818 uint s = BYTE_MUL(src[i], const_alpha);
1820 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia);
1827 dest = d * sia * ca + d * cia
1828 = d * (sia * ca + cia)
1830 void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha)
1832 uint a = qAlpha(~color);
1833 if (const_alpha != 255)
1834 a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
1836 for (int i = 0; i < length; ++i) {
1838 dest[i] = BYTE_MUL(dest[i], a);
1842 void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha)
1844 PRELOAD_INIT2(dest, src)
1845 if (const_alpha == 255) {
1846 for (int i = 0; i < length; ++i) {
1847 PRELOAD_COND2(dest, src)
1848 dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i]));
1851 int cia = 255 - const_alpha;
1852 for (int i = 0; i < length; ++i) {
1853 PRELOAD_COND2(dest, src)
1854 uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia;
1855 dest[i] = BYTE_MUL(dest[i], sia);
1861 result = s*da + d*sia
1862 dest = s*da*ca + d*sia*ca + d *cia
1863 = s*ca * da + d * (sia*ca + cia)
1864 = s*ca * da + d * (1 - sa*ca)
1866 void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha)
1868 if (const_alpha != 255) {
1869 color = BYTE_MUL(color, const_alpha);
1871 uint sia = qAlpha(~color);
1873 for (int i = 0; i < length; ++i) {
1875 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia);
1879 void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha)
1881 PRELOAD_INIT2(dest, src)
1882 if (const_alpha == 255) {
1883 for (int i = 0; i < length; ++i) {
1884 PRELOAD_COND2(dest, src)
1887 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
1890 for (int i = 0; i < length; ++i) {
1891 PRELOAD_COND2(dest, src)
1892 uint s = BYTE_MUL(src[i], const_alpha);
1894 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
1900 result = d*sa + s*dia
1901 dest = d*sa*ca + s*dia*ca + d *cia
1902 = s*ca * dia + d * (sa*ca + cia)
1904 void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha)
1906 uint a = qAlpha(color);
1907 if (const_alpha != 255) {
1908 color = BYTE_MUL(color, const_alpha);
1909 a = qAlpha(color) + 255 - const_alpha;
1912 for (int i = 0; i < length; ++i) {
1915 dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d));
1919 void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha)
1921 PRELOAD_INIT2(dest, src)
1922 if (const_alpha == 255) {
1923 for (int i = 0; i < length; ++i) {
1924 PRELOAD_COND2(dest, src)
1927 dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d));
1930 int cia = 255 - const_alpha;
1931 for (int i = 0; i < length; ++i) {
1932 PRELOAD_COND2(dest, src)
1933 uint s = BYTE_MUL(src[i], const_alpha);
1935 uint a = qAlpha(s) + cia;
1936 dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d));
1942 result = d*sia + s*dia
1943 dest = d*sia*ca + s*dia*ca + d *cia
1944 = s*ca * dia + d * (sia*ca + cia)
1945 = s*ca * dia + d * (1 - sa*ca)
1947 void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha)
1949 if (const_alpha != 255)
1950 color = BYTE_MUL(color, const_alpha);
1951 uint sia = qAlpha(~color);
1954 for (int i = 0; i < length; ++i) {
1957 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia);
1961 void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha)
1963 PRELOAD_INIT2(dest, src)
1964 if (const_alpha == 255) {
1965 for (int i = 0; i < length; ++i) {
1966 PRELOAD_COND2(dest, src)
1969 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
1972 for (int i = 0; i < length; ++i) {
1973 PRELOAD_COND2(dest, src)
1975 uint s = BYTE_MUL(src[i], const_alpha);
1976 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
1981 struct QFullCoverage {
1982 inline void store(uint *dest, const uint src) const
1988 struct QPartialCoverage {
1989 inline QPartialCoverage(uint const_alpha)
1991 , ica(255 - const_alpha)
1995 inline void store(uint *dest, const uint src) const
1997 *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
2005 static inline int mix_alpha(int da, int sa)
2007 return 255 - ((255 - sa) * (255 - da) >> 8);
2011 Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
2014 template <typename T>
2015 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage)
2020 for (int i = 0; i < length; ++i) {
2023 d = comp_func_Plus_one_pixel(d, s);
2024 coverage.store(&dest[i], d);
2028 void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha)
2030 if (const_alpha == 255)
2031 comp_func_solid_Plus_impl(dest, length, color, QFullCoverage());
2033 comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha));
2036 template <typename T>
2037 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *dest, const uint *src, int length, const T &coverage)
2039 PRELOAD_INIT2(dest, src)
2040 for (int i = 0; i < length; ++i) {
2041 PRELOAD_COND2(dest, src)
2045 d = comp_func_Plus_one_pixel(d, s);
2047 coverage.store(&dest[i], d);
2051 void QT_FASTCALL comp_func_Plus(uint *dest, const uint *src, int length, uint const_alpha)
2053 if (const_alpha == 255)
2054 comp_func_Plus_impl(dest, src, length, QFullCoverage());
2056 comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha));
2060 Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2062 static inline int multiply_op(int dst, int src, int da, int sa)
2064 return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa));
2067 template <typename T>
2068 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage)
2070 int sa = qAlpha(color);
2071 int sr = qRed(color);
2072 int sg = qGreen(color);
2073 int sb = qBlue(color);
2076 for (int i = 0; i < length; ++i) {
2081 #define OP(a, b) multiply_op(a, b, da, sa)
2082 int r = OP( qRed(d), sr);
2083 int b = OP( qBlue(d), sb);
2084 int g = OP(qGreen(d), sg);
2085 int a = mix_alpha(da, sa);
2088 coverage.store(&dest[i], qRgba(r, g, b, a));
2092 void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha)
2094 if (const_alpha == 255)
2095 comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
2097 comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
2100 template <typename T>
2101 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *dest, const uint *src, int length, const T &coverage)
2103 PRELOAD_INIT2(dest, src)
2104 for (int i = 0; i < length; ++i) {
2105 PRELOAD_COND2(dest, src)
2112 #define OP(a, b) multiply_op(a, b, da, sa)
2113 int r = OP( qRed(d), qRed(s));
2114 int b = OP( qBlue(d), qBlue(s));
2115 int g = OP(qGreen(d), qGreen(s));
2116 int a = mix_alpha(da, sa);
2119 coverage.store(&dest[i], qRgba(r, g, b, a));
2123 void QT_FASTCALL comp_func_Multiply(uint *dest, const uint *src, int length, uint const_alpha)
2125 if (const_alpha == 255)
2126 comp_func_Multiply_impl(dest, src, length, QFullCoverage());
2128 comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
2132 Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2133 = Sca + Dca - Sca.Dca
2135 template <typename T>
2136 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage)
2138 int sa = qAlpha(color);
2139 int sr = qRed(color);
2140 int sg = qGreen(color);
2141 int sb = qBlue(color);
2144 for (int i = 0; i < length; ++i) {
2149 #define OP(a, b) 255 - qt_div_255((255-a) * (255-b))
2150 int r = OP( qRed(d), sr);
2151 int b = OP( qBlue(d), sb);
2152 int g = OP(qGreen(d), sg);
2153 int a = mix_alpha(da, sa);
2156 coverage.store(&dest[i], qRgba(r, g, b, a));
2160 void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha)
2162 if (const_alpha == 255)
2163 comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
2165 comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
2168 template <typename T>
2169 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *dest, const uint *src, int length, const T &coverage)
2171 PRELOAD_INIT2(dest, src)
2172 for (int i = 0; i < length; ++i) {
2173 PRELOAD_COND2(dest, src)
2180 #define OP(a, b) 255 - (((255-a) * (255-b)) >> 8)
2181 int r = OP( qRed(d), qRed(s));
2182 int b = OP( qBlue(d), qBlue(s));
2183 int g = OP(qGreen(d), qGreen(s));
2184 int a = mix_alpha(da, sa);
2187 coverage.store(&dest[i], qRgba(r, g, b, a));
2191 void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha)
2193 if (const_alpha == 255)
2194 comp_func_Screen_impl(dest, src, length, QFullCoverage());
2196 comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
2201 Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2203 Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2205 static inline int overlay_op(int dst, int src, int da, int sa)
2207 const int temp = src * (255 - da) + dst * (255 - sa);
2209 return qt_div_255(2 * src * dst + temp);
2211 return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2214 template <typename T>
2215 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage)
2217 int sa = qAlpha(color);
2218 int sr = qRed(color);
2219 int sg = qGreen(color);
2220 int sb = qBlue(color);
2223 for (int i = 0; i < length; ++i) {
2228 #define OP(a, b) overlay_op(a, b, da, sa)
2229 int r = OP( qRed(d), sr);
2230 int b = OP( qBlue(d), sb);
2231 int g = OP(qGreen(d), sg);
2232 int a = mix_alpha(da, sa);
2235 coverage.store(&dest[i], qRgba(r, g, b, a));
2239 void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha)
2241 if (const_alpha == 255)
2242 comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
2244 comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
2247 template <typename T>
2248 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *dest, const uint *src, int length, const T &coverage)
2250 PRELOAD_INIT2(dest, src)
2251 for (int i = 0; i < length; ++i) {
2252 PRELOAD_COND2(dest, src)
2259 #define OP(a, b) overlay_op(a, b, da, sa)
2260 int r = OP( qRed(d), qRed(s));
2261 int b = OP( qBlue(d), qBlue(s));
2262 int g = OP(qGreen(d), qGreen(s));
2263 int a = mix_alpha(da, sa);
2266 coverage.store(&dest[i], qRgba(r, g, b, a));
2270 void QT_FASTCALL comp_func_Overlay(uint *dest, const uint *src, int length, uint const_alpha)
2272 if (const_alpha == 255)
2273 comp_func_Overlay_impl(dest, src, length, QFullCoverage());
2275 comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
2279 Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2280 Da' = Sa + Da - Sa.Da
2282 static inline int darken_op(int dst, int src, int da, int sa)
2284 return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2287 template <typename T>
2288 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage)
2290 int sa = qAlpha(color);
2291 int sr = qRed(color);
2292 int sg = qGreen(color);
2293 int sb = qBlue(color);
2296 for (int i = 0; i < length; ++i) {
2301 #define OP(a, b) darken_op(a, b, da, sa)
2302 int r = OP( qRed(d), sr);
2303 int b = OP( qBlue(d), sb);
2304 int g = OP(qGreen(d), sg);
2305 int a = mix_alpha(da, sa);
2308 coverage.store(&dest[i], qRgba(r, g, b, a));
2312 void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha)
2314 if (const_alpha == 255)
2315 comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
2317 comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
2320 template <typename T>
2321 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *dest, const uint *src, int length, const T &coverage)
2323 PRELOAD_INIT2(dest, src)
2324 for (int i = 0; i < length; ++i) {
2325 PRELOAD_COND2(dest, src)
2332 #define OP(a, b) darken_op(a, b, da, sa)
2333 int r = OP( qRed(d), qRed(s));
2334 int b = OP( qBlue(d), qBlue(s));
2335 int g = OP(qGreen(d), qGreen(s));
2336 int a = mix_alpha(da, sa);
2339 coverage.store(&dest[i], qRgba(r, g, b, a));
2343 void QT_FASTCALL comp_func_Darken(uint *dest, const uint *src, int length, uint const_alpha)
2345 if (const_alpha == 255)
2346 comp_func_Darken_impl(dest, src, length, QFullCoverage());
2348 comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
2352 Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2353 Da' = Sa + Da - Sa.Da
2355 static inline int lighten_op(int dst, int src, int da, int sa)
2357 return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2360 template <typename T>
2361 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage)
2363 int sa = qAlpha(color);
2364 int sr = qRed(color);
2365 int sg = qGreen(color);
2366 int sb = qBlue(color);
2369 for (int i = 0; i < length; ++i) {
2374 #define OP(a, b) lighten_op(a, b, da, sa)
2375 int r = OP( qRed(d), sr);
2376 int b = OP( qBlue(d), sb);
2377 int g = OP(qGreen(d), sg);
2378 int a = mix_alpha(da, sa);
2381 coverage.store(&dest[i], qRgba(r, g, b, a));
2385 void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha)
2387 if (const_alpha == 255)
2388 comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
2390 comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
2393 template <typename T>
2394 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *dest, const uint *src, int length, const T &coverage)
2396 PRELOAD_INIT2(dest, src)
2397 for (int i = 0; i < length; ++i) {
2398 PRELOAD_COND2(dest, src)
2405 #define OP(a, b) lighten_op(a, b, da, sa)
2406 int r = OP( qRed(d), qRed(s));
2407 int b = OP( qBlue(d), qBlue(s));
2408 int g = OP(qGreen(d), qGreen(s));
2409 int a = mix_alpha(da, sa);
2412 coverage.store(&dest[i], qRgba(r, g, b, a));
2416 void QT_FASTCALL comp_func_Lighten(uint *dest, const uint *src, int length, uint const_alpha)
2418 if (const_alpha == 255)
2419 comp_func_Lighten_impl(dest, src, length, QFullCoverage());
2421 comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
2425 if Sca.Da + Dca.Sa >= Sa.Da
2426 Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
2428 Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2430 static inline int color_dodge_op(int dst, int src, int da, int sa)
2432 const int sa_da = sa * da;
2433 const int dst_sa = dst * sa;
2434 const int src_da = src * da;
2436 const int temp = src * (255 - da) + dst * (255 - sa);
2437 if (src_da + dst_sa >= sa_da)
2438 return qt_div_255(sa_da + temp);
2440 return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp);
2443 template <typename T>
2444 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage)
2446 int sa = qAlpha(color);
2447 int sr = qRed(color);
2448 int sg = qGreen(color);
2449 int sb = qBlue(color);
2452 for (int i = 0; i < length; ++i) {
2457 #define OP(a,b) color_dodge_op(a, b, da, sa)
2458 int r = OP( qRed(d), sr);
2459 int b = OP( qBlue(d), sb);
2460 int g = OP(qGreen(d), sg);
2461 int a = mix_alpha(da, sa);
2464 coverage.store(&dest[i], qRgba(r, g, b, a));
2468 void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha)
2470 if (const_alpha == 255)
2471 comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
2473 comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
2476 template <typename T>
2477 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *dest, const uint *src, int length, const T &coverage)
2479 PRELOAD_INIT2(dest, src)
2480 for (int i = 0; i < length; ++i) {
2481 PRELOAD_COND2(dest, src)
2488 #define OP(a, b) color_dodge_op(a, b, da, sa)
2489 int r = OP( qRed(d), qRed(s));
2490 int b = OP( qBlue(d), qBlue(s));
2491 int g = OP(qGreen(d), qGreen(s));
2492 int a = mix_alpha(da, sa);
2495 coverage.store(&dest[i], qRgba(r, g, b, a));
2499 void QT_FASTCALL comp_func_ColorDodge(uint *dest, const uint *src, int length, uint const_alpha)
2501 if (const_alpha == 255)
2502 comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
2504 comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
2508 if Sca.Da + Dca.Sa <= Sa.Da
2509 Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
2511 Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
2513 static inline int color_burn_op(int dst, int src, int da, int sa)
2515 const int src_da = src * da;
2516 const int dst_sa = dst * sa;
2517 const int sa_da = sa * da;
2519 const int temp = src * (255 - da) + dst * (255 - sa);
2521 if (src == 0 || src_da + dst_sa <= sa_da)
2522 return qt_div_255(temp);
2523 return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp);
2526 template <typename T>
2527 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage)
2529 int sa = qAlpha(color);
2530 int sr = qRed(color);
2531 int sg = qGreen(color);
2532 int sb = qBlue(color);
2535 for (int i = 0; i < length; ++i) {
2540 #define OP(a, b) color_burn_op(a, b, da, sa)
2541 int r = OP( qRed(d), sr);
2542 int b = OP( qBlue(d), sb);
2543 int g = OP(qGreen(d), sg);
2544 int a = mix_alpha(da, sa);
2547 coverage.store(&dest[i], qRgba(r, g, b, a));
2551 void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha)
2553 if (const_alpha == 255)
2554 comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
2556 comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
2559 template <typename T>
2560 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *dest, const uint *src, int length, const T &coverage)
2562 PRELOAD_INIT2(dest, src)
2563 for (int i = 0; i < length; ++i) {
2564 PRELOAD_COND2(dest, src)
2571 #define OP(a, b) color_burn_op(a, b, da, sa)
2572 int r = OP( qRed(d), qRed(s));
2573 int b = OP( qBlue(d), qBlue(s));
2574 int g = OP(qGreen(d), qGreen(s));
2575 int a = mix_alpha(da, sa);
2578 coverage.store(&dest[i], qRgba(r, g, b, a));
2582 void QT_FASTCALL comp_func_ColorBurn(uint *dest, const uint *src, int length, uint const_alpha)
2584 if (const_alpha == 255)
2585 comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
2587 comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
2592 Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2594 Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2596 static inline uint hardlight_op(int dst, int src, int da, int sa)
2598 const uint temp = src * (255 - da) + dst * (255 - sa);
2601 return qt_div_255(2 * src * dst + temp);
2603 return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2606 template <typename T>
2607 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage)
2609 int sa = qAlpha(color);
2610 int sr = qRed(color);
2611 int sg = qGreen(color);
2612 int sb = qBlue(color);
2615 for (int i = 0; i < length; ++i) {
2620 #define OP(a, b) hardlight_op(a, b, da, sa)
2621 int r = OP( qRed(d), sr);
2622 int b = OP( qBlue(d), sb);
2623 int g = OP(qGreen(d), sg);
2624 int a = mix_alpha(da, sa);
2627 coverage.store(&dest[i], qRgba(r, g, b, a));
2631 void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha)
2633 if (const_alpha == 255)
2634 comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
2636 comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2639 template <typename T>
2640 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *dest, const uint *src, int length, const T &coverage)
2642 PRELOAD_INIT2(dest, src)
2643 for (int i = 0; i < length; ++i) {
2644 PRELOAD_COND2(dest, src)
2651 #define OP(a, b) hardlight_op(a, b, da, sa)
2652 int r = OP( qRed(d), qRed(s));
2653 int b = OP( qBlue(d), qBlue(s));
2654 int g = OP(qGreen(d), qGreen(s));
2655 int a = mix_alpha(da, sa);
2658 coverage.store(&dest[i], qRgba(r, g, b, a));
2662 void QT_FASTCALL comp_func_HardLight(uint *dest, const uint *src, int length, uint const_alpha)
2664 if (const_alpha == 255)
2665 comp_func_HardLight_impl(dest, src, length, QFullCoverage());
2667 comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2672 Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
2673 otherwise if 2.Sca > Sa and 4.Dca <= Da
2674 Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2675 otherwise if 2.Sca > Sa and 4.Dca > Da
2676 Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2678 static inline int soft_light_op(int dst, int src, int da, int sa)
2680 const int src2 = src << 1;
2681 const int dst_np = da != 0 ? (255 * dst) / da : 0;
2682 const int temp = (src * (255 - da) + dst * (255 - sa)) * 255;
2685 return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025;
2686 else if (4 * dst <= da)
2687 return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025;
2689 # ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
2690 return (dst * sa * 255 + da * (src2 - sa) * (qIntSqrtInt(dst_np * 255) - dst_np) + temp) / 65025;
2692 return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025;
2697 template <typename T>
2698 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage)
2700 int sa = qAlpha(color);
2701 int sr = qRed(color);
2702 int sg = qGreen(color);
2703 int sb = qBlue(color);
2706 for (int i = 0; i < length; ++i) {
2711 #define OP(a, b) soft_light_op(a, b, da, sa)
2712 int r = OP( qRed(d), sr);
2713 int b = OP( qBlue(d), sb);
2714 int g = OP(qGreen(d), sg);
2715 int a = mix_alpha(da, sa);
2718 coverage.store(&dest[i], qRgba(r, g, b, a));
2722 void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
2724 if (const_alpha == 255)
2725 comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
2727 comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2730 template <typename T>
2731 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *dest, const uint *src, int length, const T &coverage)
2733 PRELOAD_INIT2(dest, src)
2734 for (int i = 0; i < length; ++i) {
2735 PRELOAD_COND2(dest, src)
2742 #define OP(a, b) soft_light_op(a, b, da, sa)
2743 int r = OP( qRed(d), qRed(s));
2744 int b = OP( qBlue(d), qBlue(s));
2745 int g = OP(qGreen(d), qGreen(s));
2746 int a = mix_alpha(da, sa);
2749 coverage.store(&dest[i], qRgba(r, g, b, a));
2753 void QT_FASTCALL comp_func_SoftLight(uint *dest, const uint *src, int length, uint const_alpha)
2755 if (const_alpha == 255)
2756 comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
2758 comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2762 Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2763 = Sca + Dca - 2.min(Sca.Da, Dca.Sa)
2765 static inline int difference_op(int dst, int src, int da, int sa)
2767 return src + dst - qt_div_255(2 * qMin(src * da, dst * sa));
2770 template <typename T>
2771 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage)
2773 int sa = qAlpha(color);
2774 int sr = qRed(color);
2775 int sg = qGreen(color);
2776 int sb = qBlue(color);
2779 for (int i = 0; i < length; ++i) {
2784 #define OP(a, b) difference_op(a, b, da, sa)
2785 int r = OP( qRed(d), sr);
2786 int b = OP( qBlue(d), sb);
2787 int g = OP(qGreen(d), sg);
2788 int a = mix_alpha(da, sa);
2791 coverage.store(&dest[i], qRgba(r, g, b, a));
2795 void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha)
2797 if (const_alpha == 255)
2798 comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
2800 comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
2803 template <typename T>
2804 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *dest, const uint *src, int length, const T &coverage)
2806 PRELOAD_INIT2(dest, src)
2807 for (int i = 0; i < length; ++i) {
2808 PRELOAD_COND2(dest, src)
2815 #define OP(a, b) difference_op(a, b, da, sa)
2816 int r = OP( qRed(d), qRed(s));
2817 int b = OP( qBlue(d), qBlue(s));
2818 int g = OP(qGreen(d), qGreen(s));
2819 int a = mix_alpha(da, sa);
2822 coverage.store(&dest[i], qRgba(r, g, b, a));
2826 void QT_FASTCALL comp_func_Difference(uint *dest, const uint *src, int length, uint const_alpha)
2828 if (const_alpha == 255)
2829 comp_func_Difference_impl(dest, src, length, QFullCoverage());
2831 comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
2835 Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2837 template <typename T>
2838 Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage)
2840 int sa = qAlpha(color);
2841 int sr = qRed(color);
2842 int sg = qGreen(color);
2843 int sb = qBlue(color);
2846 for (int i = 0; i < length; ++i) {
2851 #define OP(a, b) (a + b - qt_div_255(2*(a*b)))
2852 int r = OP( qRed(d), sr);
2853 int b = OP( qBlue(d), sb);
2854 int g = OP(qGreen(d), sg);
2855 int a = mix_alpha(da, sa);
2858 coverage.store(&dest[i], qRgba(r, g, b, a));
2862 void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha)
2864 if (const_alpha == 255)
2865 comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage());
2867 comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
2870 template <typename T>
2871 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *dest, const uint *src, int length, const T &coverage)
2873 PRELOAD_INIT2(dest, src)
2874 for (int i = 0; i < length; ++i) {
2875 PRELOAD_COND2(dest, src)
2882 #define OP(a, b) (a + b - ((a*b) >> 7))
2883 int r = OP( qRed(d), qRed(s));
2884 int b = OP( qBlue(d), qBlue(s));
2885 int g = OP(qGreen(d), qGreen(s));
2886 int a = mix_alpha(da, sa);
2889 coverage.store(&dest[i], qRgba(r, g, b, a));
2893 void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int length, uint const_alpha)
2895 if (const_alpha == 255)
2896 comp_func_Exclusion_impl(dest, src, length, QFullCoverage());
2898 comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
2901 #if defined(Q_CC_RVCT)
2902 // Restore pragma state from previous #pragma arm
2906 void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest,
2911 Q_UNUSED(const_alpha);
2916 void QT_FASTCALL rasterop_SourceOrDestination(uint *dest,
2921 Q_UNUSED(const_alpha);
2926 void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest,
2931 Q_UNUSED(const_alpha);
2932 color |= 0xff000000;
2937 void QT_FASTCALL rasterop_SourceAndDestination(uint *dest,
2942 Q_UNUSED(const_alpha);
2944 *dest = (*src & *dest) | 0xff000000;
2949 void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest,
2954 Q_UNUSED(const_alpha);
2955 color &= 0x00ffffff;
2960 void QT_FASTCALL rasterop_SourceXorDestination(uint *dest,
2965 Q_UNUSED(const_alpha);
2967 *dest = (*src ^ *dest) | 0xff000000;
2972 void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest,
2977 Q_UNUSED(const_alpha);
2980 *dest = (color & ~(*dest)) | 0xff000000;
2985 void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *dest,
2990 Q_UNUSED(const_alpha);
2992 *dest = (~(*src) & ~(*dest)) | 0xff000000;
2997 void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest,
3002 Q_UNUSED(const_alpha);
3003 color = ~color | 0xff000000;
3005 *dest = color | ~(*dest);
3010 void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *dest,
3015 Q_UNUSED(const_alpha);
3017 *dest = ~(*src) | ~(*dest) | 0xff000000;
3022 void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest,
3027 Q_UNUSED(const_alpha);
3028 color = ~color & 0x00ffffff;
3030 *dest = color ^ (*dest);
3035 void QT_FASTCALL rasterop_NotSourceXorDestination(uint *dest,
3040 Q_UNUSED(const_alpha);
3042 *dest = ((~(*src)) ^ (*dest)) | 0xff000000;
3047 void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length,
3048 uint color, uint const_alpha)
3050 Q_UNUSED(const_alpha);
3051 qt_memfill(dest, ~color | 0xff000000, length);
3054 void QT_FASTCALL rasterop_NotSource(uint *dest, const uint *src,
3055 int length, uint const_alpha)
3057 Q_UNUSED(const_alpha);
3059 *dest++ = ~(*src++) | 0xff000000;
3062 void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest,
3067 Q_UNUSED(const_alpha);
3068 color = ~color | 0xff000000;
3070 *dest = color & *dest;
3075 void QT_FASTCALL rasterop_NotSourceAndDestination(uint *dest,
3080 Q_UNUSED(const_alpha);
3082 *dest = (~(*src) & *dest) | 0xff000000;
3087 void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest,
3092 Q_UNUSED(const_alpha);
3094 *dest = (color & ~(*dest)) | 0xff000000;
3099 void QT_FASTCALL rasterop_SourceAndNotDestination(uint *dest,
3104 Q_UNUSED(const_alpha);
3106 *dest = (*src & ~(*dest)) | 0xff000000;
3111 static CompositionFunctionSolid functionForModeSolid_C[] = {
3112 comp_func_solid_SourceOver,
3113 comp_func_solid_DestinationOver,
3114 comp_func_solid_Clear,
3115 comp_func_solid_Source,
3116 comp_func_solid_Destination,
3117 comp_func_solid_SourceIn,
3118 comp_func_solid_DestinationIn,
3119 comp_func_solid_SourceOut,
3120 comp_func_solid_DestinationOut,
3121 comp_func_solid_SourceAtop,
3122 comp_func_solid_DestinationAtop,
3123 comp_func_solid_XOR,
3124 comp_func_solid_Plus,
3125 comp_func_solid_Multiply,
3126 comp_func_solid_Screen,
3127 comp_func_solid_Overlay,
3128 comp_func_solid_Darken,
3129 comp_func_solid_Lighten,
3130 comp_func_solid_ColorDodge,
3131 comp_func_solid_ColorBurn,
3132 comp_func_solid_HardLight,
3133 comp_func_solid_SoftLight,
3134 comp_func_solid_Difference,
3135 comp_func_solid_Exclusion,
3136 rasterop_solid_SourceOrDestination,
3137 rasterop_solid_SourceAndDestination,
3138 rasterop_solid_SourceXorDestination,
3139 rasterop_solid_NotSourceAndNotDestination,
3140 rasterop_solid_NotSourceOrNotDestination,
3141 rasterop_solid_NotSourceXorDestination,
3142 rasterop_solid_NotSource,
3143 rasterop_solid_NotSourceAndDestination,
3144 rasterop_solid_SourceAndNotDestination
3147 static const CompositionFunctionSolid *functionForModeSolid = functionForModeSolid_C;
3149 static CompositionFunction functionForMode_C[] = {
3150 comp_func_SourceOver,
3151 comp_func_DestinationOver,
3154 comp_func_Destination,
3156 comp_func_DestinationIn,
3157 comp_func_SourceOut,
3158 comp_func_DestinationOut,
3159 comp_func_SourceAtop,
3160 comp_func_DestinationAtop,
3168 comp_func_ColorDodge,
3169 comp_func_ColorBurn,
3170 comp_func_HardLight,
3171 comp_func_SoftLight,
3172 comp_func_Difference,
3173 comp_func_Exclusion,
3174 rasterop_SourceOrDestination,
3175 rasterop_SourceAndDestination,
3176 rasterop_SourceXorDestination,
3177 rasterop_NotSourceAndNotDestination,
3178 rasterop_NotSourceOrNotDestination,
3179 rasterop_NotSourceXorDestination,
3181 rasterop_NotSourceAndDestination,
3182 rasterop_SourceAndNotDestination
3185 static const CompositionFunction *functionForMode = functionForMode_C;
3187 static TextureBlendType getBlendType(const QSpanData *data)
3189 TextureBlendType ft;
3190 if (data->txop <= QTransform::TxTranslate)
3191 if (data->texture.type == QTextureData::Tiled)
3194 ft = BlendUntransformed;
3195 else if (data->bilinear)
3196 if (data->texture.type == QTextureData::Tiled)
3197 ft = BlendTransformedBilinearTiled;
3199 ft = BlendTransformedBilinear;
3201 if (data->texture.type == QTextureData::Tiled)
3202 ft = BlendTransformedTiled;
3204 ft = BlendTransformed;
3208 static inline Operator getOperator(const QSpanData *data, const QSpan *spans, int spanCount)
3211 bool solidSource = false;
3213 switch(data->type) {
3214 case QSpanData::Solid:
3215 solidSource = (qAlpha(data->solid.color) == 255);
3217 case QSpanData::LinearGradient:
3218 solidSource = !data->gradient.alphaColor;
3219 getLinearGradientValues(&op.linear, data);
3220 op.src_fetch = qt_fetch_linear_gradient;
3222 case QSpanData::RadialGradient:
3223 solidSource = !data->gradient.alphaColor;
3224 getRadialGradientValues(&op.radial, data);
3225 op.src_fetch = qt_fetch_radial_gradient;
3227 case QSpanData::ConicalGradient:
3228 solidSource = !data->gradient.alphaColor;
3229 op.src_fetch = qt_fetch_conical_gradient;
3231 case QSpanData::Texture:
3232 op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format];
3233 solidSource = !data->texture.hasAlpha;
3238 op.mode = data->rasterBuffer->compositionMode;
3239 if (op.mode == QPainter::CompositionMode_SourceOver && solidSource)
3240 op.mode = QPainter::CompositionMode_Source;
3242 op.dest_fetch = destFetchProc[data->rasterBuffer->format];
3243 if (op.mode == QPainter::CompositionMode_Source) {
3244 switch (data->rasterBuffer->format) {
3245 case QImage::Format_RGB32:
3246 case QImage::Format_ARGB32_Premultiplied:
3247 // don't clear dest_fetch as it sets up the pointer correctly to save one copy
3250 const QSpan *lastSpan = spans + spanCount;
3251 bool alphaSpans = false;
3252 while (spans < lastSpan) {
3253 if (spans->coverage != 255) {
3265 op.dest_store = destStoreProc[data->rasterBuffer->format];
3267 op.funcSolid = functionForModeSolid[op.mode];
3268 op.func = functionForMode[op.mode];
3275 // -------------------- blend methods ---------------------
3282 #if !defined(Q_CC_SUN)
3285 void drawBufferSpan(QSpanData *data, const uint *buffer, int bufsize,
3286 int x, int y, int length, uint const_alpha)
3288 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3289 data->rasterEngine->drawBufferSpan(buffer, bufsize, x, y, length, const_alpha);
3297 Q_UNUSED(const_alpha);
3301 #if !defined(Q_CC_SUN)
3304 void blend_color_generic(int count, const QSpan *spans, void *userData)
3306 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3307 uint buffer[buffer_size];
3308 Operator op = getOperator(data, spans, count);
3312 int length = spans->len;
3314 int l = qMin(buffer_size, length);
3315 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3316 op.funcSolid(dest, l, data->solid.color, spans->coverage);
3318 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3326 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3327 static void blend_color_generic_callback(int count, const QSpan *spans, void *userData)
3333 // QSpanData *data = reinterpret_cast<QSpanData*>(userData);
3334 // data->rasterEngine->drawColorSpans(spans, count, data->solid.color);
3336 #endif // QT_NO_RASTERCALLBACKS
3338 static void blend_color_argb(int count, const QSpan *spans, void *userData)
3340 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3342 Operator op = getOperator(data, spans, count);
3344 if (op.mode == QPainter::CompositionMode_Source) {
3345 // inline for performance
3347 uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3348 if (spans->coverage == 255) {
3349 QT_MEMFILL_UINT(target, spans->len, data->solid.color);
3351 uint c = BYTE_MUL(data->solid.color, spans->coverage);
3352 int ialpha = 255 - spans->coverage;
3353 for (int i = 0; i < spans->len; ++i)
3354 target[i] = c + BYTE_MUL(target[i], ialpha);
3362 uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3363 op.funcSolid(target, spans->len, data->solid.color, spans->coverage);
3369 Q_STATIC_TEMPLATE_FUNCTION void blendColor(int count, const QSpan *spans, void *userData)
3371 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3372 Operator op = getOperator(data, spans, count);
3374 if (op.mode == QPainter::CompositionMode_Source) {
3375 const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(data->solid.color), 0);
3377 T *target = ((T*)data->rasterBuffer->scanLine(spans->y))
3379 if (spans->coverage == 255) {
3380 qt_memfill(target, c, spans->len);
3382 const quint8 alpha = T::alpha(spans->coverage);
3383 const T color = c.byte_mul(alpha);
3384 const int ialpha = T::ialpha(spans->coverage);
3385 const T *end = target + spans->len;
3386 while (target < end) {
3387 *target = color + target->byte_mul(ialpha);
3396 if (op.mode == QPainter::CompositionMode_SourceOver) {
3398 const quint32 color = BYTE_MUL(data->solid.color, spans->coverage);
3399 const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0);
3400 const quint8 ialpha = T::alpha(qAlpha(~color));
3401 T *target = ((T*)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3402 const T *end = target + spans->len;
3403 while (target != end) {
3404 *target = c + target->byte_mul(ialpha);
3412 blend_color_generic(count, spans, userData);
3415 #define SPANFUNC_POINTER_BLENDCOLOR(DST) blendColor<DST>
3417 static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
3419 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3422 We duplicate a little logic from getOperator() and calculate the
3423 composition mode directly. This allows blend_color_rgb16 to be used
3424 from qt_gradient_quint16 with minimal overhead.
3426 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
3427 if (mode == QPainter::CompositionMode_SourceOver &&
3428 qAlpha(data->solid.color) == 255)
3429 mode = QPainter::CompositionMode_Source;
3431 if (mode == QPainter::CompositionMode_Source) {
3432 // inline for performance
3433 ushort c = qConvertRgb32To16(data->solid.color);
3435 ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3436 if (spans->coverage == 255) {
3437 QT_MEMFILL_USHORT(target, spans->len, c);
3439 ushort color = BYTE_MUL_RGB16(c, spans->coverage);
3440 int ialpha = 255 - spans->coverage;
3441 const ushort *end = target + spans->len;
3442 while (target < end) {
3443 *target = color + BYTE_MUL_RGB16(*target, ialpha);
3452 if (mode == QPainter::CompositionMode_SourceOver) {
3454 uint color = BYTE_MUL(data->solid.color, spans->coverage);
3455 int ialpha = qAlpha(~color);
3456 ushort c = qConvertRgb32To16(color);
3457 ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3458 int len = spans->len;
3459 bool pre = (((quintptr)target) & 0x3) != 0;
3462 // skip to word boundary
3463 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3471 uint *target32 = (uint*)target;
3472 uint c32 = c | (c<<16);
3474 uint salpha = (ialpha+1) >> 3; // calculate here rather than in loop
3477 *target32 = c32 + BYTE_MUL_RGB16_32(*target32, salpha);
3482 // one last pixel beyond a full word
3483 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3490 blend_color_generic(count, spans, userData);
3493 template <typename T>
3494 void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
3496 uint const_alpha = 256;
3497 if (data->type == QSpanData::Texture)
3498 const_alpha = data->texture.const_alpha;
3503 const int y = spans->y;
3504 int right = x + spans->len;
3506 // compute length of adjacent spans
3507 for (int i = 1; i < count && spans[i].y == y && spans[i].x == right; ++i)
3508 right += spans[i].len;
3509 int length = right - x;
3512 int l = qMin(buffer_size, length);
3515 int process_length = l;
3518 const uint *src = handler.fetch(process_x, y, process_length);
3521 if (x == spans->x) // new span?
3522 coverage = (spans->coverage * const_alpha) >> 8;
3524 int right = spans->x + spans->len;
3525 int len = qMin(l, right - x);
3527 handler.process(x, y, len, coverage, src, offset);
3533 if (x == right) { // done with current span?
3538 handler.store(process_x, y, process_length);
3545 QBlendBase(QSpanData *d, Operator o)
3557 uint buffer[buffer_size];
3558 uint src_buffer[buffer_size];
3561 template <SpanMethod spanMethod>
3562 class BlendSrcGeneric : public QBlendBase
3565 BlendSrcGeneric(QSpanData *d, Operator o)
3570 const uint *fetch(int x, int y, int len)
3572 if (spanMethod == RegularSpans)
3573 dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, y, len) : buffer;
3575 return op.src_fetch(src_buffer, &op, data, y, x, len);
3578 void process(int x, int y, int len, int coverage, const uint *src, int offset)
3580 if (spanMethod == RegularSpans)
3581 op.func(dest + offset, src + offset, len, coverage);
3583 drawBufferSpan(data, src + offset, len, x, y, len, coverage);
3586 void store(int x, int y, int len)
3588 if (spanMethod == RegularSpans && op.dest_store) {
3589 op.dest_store(data->rasterBuffer, x, y, dest, len);
3594 template <SpanMethod spanMethod>
3595 Q_STATIC_TEMPLATE_FUNCTION void blend_src_generic(int count, const QSpan *spans, void *userData)
3597 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3598 BlendSrcGeneric<spanMethod> blend(data, getOperator(data, spans, count));
3599 handleSpans(count, spans, data, blend);
3602 template <SpanMethod spanMethod>
3603 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
3605 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3607 uint buffer[buffer_size];
3608 uint src_buffer[buffer_size];
3609 Operator op = getOperator(data, spans, count);
3611 const int image_width = data->texture.width;
3612 const int image_height = data->texture.height;
3613 int xoff = -qRound(-data->dx);
3614 int yoff = -qRound(-data->dy);
3618 int length = spans->len;
3620 int sy = yoff + spans->y;
3621 if (sy >= 0 && sy < image_height && sx < image_width) {
3627 if (sx + length > image_width)
3628 length = image_width - sx;
3630 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3632 int l = qMin(buffer_size, length);
3633 const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
3634 if (spanMethod == RegularSpans) {
3635 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3636 op.func(dest, src, l, coverage);
3638 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3640 drawBufferSpan(data, src, l, x, spans->y,
3653 template <SpanMethod spanMethod>
3654 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
3656 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3657 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
3658 && data->texture.format != QImage::Format_RGB32) {
3659 blend_untransformed_generic<spanMethod>(count, spans, userData);
3663 Operator op = getOperator(data, spans, count);
3665 const int image_width = data->texture.width;
3666 const int image_height = data->texture.height;
3667 int xoff = -qRound(-data->dx);
3668 int yoff = -qRound(-data->dy);
3672 int length = spans->len;
3674 int sy = yoff + spans->y;
3675 if (sy >= 0 && sy < image_height && sx < image_width) {
3681 if (sx + length > image_width)
3682 length = image_width - sx;
3684 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3685 const uint *src = (uint *)data->texture.scanLine(sy) + sx;
3686 if (spanMethod == RegularSpans) {
3687 uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
3688 op.func(dest, src, length, coverage);
3690 drawBufferSpan(data, src, length, x,
3691 spans->y, length, coverage);
3699 static inline quint16 interpolate_pixel_rgb16_255(quint16 x, quint8 a,
3700 quint16 y, quint8 b)
3702 quint16 t = ((((x & 0x07e0) * a) + ((y & 0x07e0) * b)) >> 5) & 0x07e0;
3703 t |= ((((x & 0xf81f) * a) + ((y & 0xf81f) * b)) >> 5) & 0xf81f;
3708 static inline quint32 interpolate_pixel_rgb16x2_255(quint32 x, quint8 a,
3709 quint32 y, quint8 b)
3712 t = ((((x & 0xf81f07e0) >> 5) * a) + (((y & 0xf81f07e0) >> 5) * b)) & 0xf81f07e0;
3713 t |= ((((x & 0x07e0f81f) * a) + ((y & 0x07e0f81f) * b)) >> 5) & 0x07e0f81f;
3717 static inline void blend_sourceOver_rgb16_rgb16(quint16 *dest,
3721 const quint8 ialpha)
3723 const int dstAlign = ((quintptr)dest) & 0x3;
3725 *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
3730 const int srcAlign = ((quintptr)src) & 0x3;
3731 int length32 = length >> 1;
3732 if (length32 && srcAlign == 0) {
3733 while (length32--) {
3734 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3735 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3736 *dest32 = interpolate_pixel_rgb16x2_255(*src32, alpha,
3744 *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
3750 template <class DST, class SRC>
3751 Q_STATIC_TEMPLATE_SPECIALIZATION
3752 inline void madd_2(DST *dest, const quint16 alpha, const SRC *src)
3754 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3755 Q_ASSERT((quintptr(src) & 0x3) == 0);
3756 dest[0] = dest[0].byte_mul(alpha >> 8) + DST(src[0]);
3757 dest[1] = dest[1].byte_mul(alpha & 0xff) + DST(src[1]);
3760 template <class DST, class SRC>
3761 Q_STATIC_TEMPLATE_SPECIALIZATION
3762 inline void madd_4(DST *dest, const quint32 alpha, const SRC *src)
3764 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3765 Q_ASSERT((quintptr(src) & 0x3) == 0);
3766 dest[0] = dest[0].byte_mul(alpha >> 24) + DST(src[0]);
3767 dest[1] = dest[1].byte_mul((alpha >> 16) & 0xff) + DST(src[1]);
3768 dest[2] = dest[2].byte_mul((alpha >> 8) & 0xff) + DST(src[2]);
3769 dest[3] = dest[3].byte_mul(alpha & 0xff) + DST(src[3]);
3772 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
3774 Q_STATIC_TEMPLATE_SPECIALIZATION
3775 inline void madd_4(qargb8565 *dest, const quint32 a, const qargb8565 *src)
3777 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3778 Q_ASSERT((quintptr(src) & 0x3) == 0);
3780 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3781 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3792 t = ((((x & 0x0007e0ff) * a8) >> 5) & 0x0007e0ff) + (y & 0x0007c0f8);
3795 t |= ((((x & 0x00f81f00) * a8) >> 5) & 0x00f81f00) + (y & 0x00f81f00);
3797 a8 = (a >> 16) & 0xff;
3800 t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
3809 t = ((((x & 0x0000f81f) * a8) >> 5) & 0x0000f81f) + (y & 0x0000f81f);
3812 t |= ((((x & 0x000007e0) * a8) >> 5) & 0x000007e0) + (y & 0x000007c0);
3814 a8 = (a >> 8) & 0xff;
3817 t |= ((((x & 0x00ff0000) * a8) >> 5) & 0x00ff0000) + (y & 0x00f80000);
3821 quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
3822 quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
3825 t16 = ((((x16 & 0xf81f) * a8) >> 5) & 0xf81f) + (y16 & 0xf81f);
3826 t16 |= ((((x16 & 0x07e0) * a8) >> 5) & 0x07e0) + (y16 & 0x07c0);
3829 t |= ((t16 & 0x00ff) << 24);
3844 t |= ((((x & 0x07e0ff00) * a8) >> 5) & 0x07e0ff00) + (y & 0x07c0f800);
3847 t |= ((((x & 0xf81f0000) >> 5) * a8) & 0xf81f0000)+ (y & 0xf81f0000);
3854 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
3856 Q_STATIC_TEMPLATE_SPECIALIZATION
3857 inline void madd_4(qargb8555 *dest, const quint32 a, const qargb8555 *src)
3859 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3860 Q_ASSERT((quintptr(src) & 0x3) == 0);
3862 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3863 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3874 t = ((((x & 0x0003e0ff) * a8) >> 5) & 0x0003e0ff) + (y & 0x0003e0f8);
3877 t |= ((((x & 0x007c1f00) * a8) >> 5) & 0x007c1f00) + (y & 0x007c1f00);
3879 a8 = (a >> 16) & 0xff;
3882 t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
3891 t = ((((x & 0x00007c1f) * a8) >> 5) & 0x00007c1f) + (y & 0x00007c1f);
3894 t |= ((((x & 0x000003e0) * a8) >> 5) & 0x000003e0) + (y & 0x000003e0);
3896 a8 = (a >> 8) & 0xff;
3899 t |= ((((x & 0x00ff0000) * a8) >> 5) & 0x00ff0000) + (y & 0x00f80000);
3903 quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
3904 quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
3907 t16 = ((((x16 & 0x7c1f) * a8) >> 5) & 0x7c1f) + (y16 & 0x7c1f);
3908 t16 |= ((((x16 & 0x03e0) * a8) >> 5) & 0x03e0) + (y16 & 0x03e0);
3911 t |= ((t16 & 0x00ff) << 24);
3926 t |= ((((x & 0x03e0ff00) * a8) >> 5) & 0x03e0ff00) + (y & 0x03e0f800);
3929 t |= ((((x & 0x7c1f0000) >> 5) * a8) & 0x7c1f0000)+ (y & 0x7c1f0000);
3937 Q_STATIC_TEMPLATE_SPECIALIZATION
3938 inline quint16 alpha_2(const T *src)
3940 Q_ASSERT((quintptr(src) & 0x3) == 0);
3943 return (src[0].alpha() << 8) | src[1].alpha();
3949 Q_STATIC_TEMPLATE_SPECIALIZATION
3950 inline quint32 alpha_4(const T *src)
3952 Q_ASSERT((quintptr(src) & 0x3) == 0);
3954 if (T::hasAlpha()) {
3955 return (src[0].alpha() << 24) | (src[1].alpha() << 16)
3956 | (src[2].alpha() << 8) | src[3].alpha();
3963 Q_STATIC_TEMPLATE_SPECIALIZATION
3964 inline quint32 alpha_4(const qargb8565 *src)
3966 const quint8 *src8 = reinterpret_cast<const quint8*>(src);
3967 return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
3971 Q_STATIC_TEMPLATE_SPECIALIZATION
3972 inline quint32 alpha_4(const qargb6666 *src)
3974 const quint8 *src8 = reinterpret_cast<const quint8*>(src);
3975 return ((src8[2] & 0xfc) | (src8[2] >> 6)) << 24
3976 | ((src8[5] & 0xfc) | (src8[5] >> 6)) << 16
3977 | ((src8[8] & 0xfc) | (src8[8] >> 6)) << 8
3978 | ((src8[11] & 0xfc) | (src8[11] >> 6));
3982 Q_STATIC_TEMPLATE_SPECIALIZATION
3983 inline quint32 alpha_4(const qargb8555 *src)
3985 Q_ASSERT((quintptr(src) & 0x3) == 0);
3986 const quint8 *src8 = reinterpret_cast<const quint8*>(src);
3987 return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
3991 Q_STATIC_TEMPLATE_SPECIALIZATION
3992 inline quint16 alpha_2(const qargb4444 *src)
3994 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3995 const quint32 t = (*src32 & 0xf000f000) |
3996 ((*src32 & 0xf000f000) >> 4);
3997 return (t >> 24) | (t & 0xff00);
4001 Q_STATIC_TEMPLATE_SPECIALIZATION
4002 inline quint16 eff_alpha_2(quint16 alpha, const T*)
4004 return (T::alpha((alpha >> 8) & 0xff) << 8)
4005 | T::alpha(alpha & 0xff);
4009 Q_STATIC_TEMPLATE_SPECIALIZATION
4010 inline quint16 eff_alpha_2(quint16 a, const qrgb565*)
4012 return ((((a & 0xff00) + 0x0100) >> 3) & 0xff00)
4013 | ((((a & 0x00ff) + 0x0001) >> 3) & 0x00ff);
4017 Q_STATIC_TEMPLATE_SPECIALIZATION
4018 inline quint16 eff_alpha_2(quint16 a, const qrgb444*)
4020 return (((a & 0x00ff) + 0x0001) >> 4)
4021 | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
4025 Q_STATIC_TEMPLATE_SPECIALIZATION
4026 inline quint16 eff_alpha_2(quint16 a, const qargb4444*)
4028 return (((a & 0x00ff) + 0x0001) >> 4)
4029 | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
4033 Q_STATIC_TEMPLATE_SPECIALIZATION
4034 inline quint16 eff_ialpha_2(quint16 alpha, const T*)
4036 return (T::ialpha((alpha >> 8) & 0xff) << 8)
4037 | T::ialpha(alpha & 0xff);
4041 Q_STATIC_TEMPLATE_SPECIALIZATION
4042 inline quint16 eff_ialpha_2(quint16 a, const qrgb565 *dummy)
4044 return 0x2020 - eff_alpha_2(a, dummy);
4048 Q_STATIC_TEMPLATE_SPECIALIZATION
4049 inline quint16 eff_ialpha_2(quint16 a, const qargb4444 *dummy)
4051 return 0x1010 - eff_alpha_2(a, dummy);
4055 Q_STATIC_TEMPLATE_SPECIALIZATION
4056 inline quint16 eff_ialpha_2(quint16 a, const qrgb444 *dummy)
4058 return 0x1010 - eff_alpha_2(a, dummy);
4062 Q_STATIC_TEMPLATE_SPECIALIZATION
4063 inline quint32 eff_alpha_4(quint32 alpha, const T*)
4065 return (T::alpha(alpha >> 24) << 24)
4066 | (T::alpha((alpha >> 16) & 0xff) << 16)
4067 | (T::alpha((alpha >> 8) & 0xff) << 8)
4068 | T::alpha(alpha & 0xff);
4072 Q_STATIC_TEMPLATE_SPECIALIZATION
4073 inline quint32 eff_alpha_4(quint32 a, const qrgb888*)
4079 Q_STATIC_TEMPLATE_SPECIALIZATION
4080 inline quint32 eff_alpha_4(quint32 a, const qargb8565*)
4082 return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
4083 | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
4087 Q_STATIC_TEMPLATE_SPECIALIZATION
4088 inline quint32 eff_alpha_4(quint32 a, const qargb6666*)
4090 return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
4091 | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
4095 Q_STATIC_TEMPLATE_SPECIALIZATION
4096 inline quint32 eff_alpha_4(quint32 a, const qrgb666*)
4098 return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
4099 | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
4103 Q_STATIC_TEMPLATE_SPECIALIZATION
4104 inline quint32 eff_alpha_4(quint32 a, const qargb8555*)
4106 return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
4107 | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
4111 Q_STATIC_TEMPLATE_SPECIALIZATION
4112 inline quint32 eff_ialpha_4(quint32 alpha, const T*)
4114 return (T::ialpha(alpha >> 24) << 24)
4115 | (T::ialpha((alpha >> 16) & 0xff) << 16)
4116 | (T::ialpha((alpha >> 8) & 0xff) << 8)
4117 | T::ialpha(alpha & 0xff);
4121 Q_STATIC_TEMPLATE_SPECIALIZATION
4122 inline quint32 eff_ialpha_4(quint32 a, const qrgb888*)
4128 Q_STATIC_TEMPLATE_SPECIALIZATION
4129 inline quint32 eff_ialpha_4(quint32 a, const qargb8565 *dummy)
4131 return 0x20202020 - eff_alpha_4(a, dummy);
4135 Q_STATIC_TEMPLATE_SPECIALIZATION
4136 inline quint32 eff_ialpha_4(quint32 a, const qargb6666 *dummy)
4138 return 0x40404040 - eff_alpha_4(a, dummy);
4142 Q_STATIC_TEMPLATE_SPECIALIZATION
4143 inline quint32 eff_ialpha_4(quint32 a, const qrgb666 *dummy)
4145 return 0x40404040 - eff_alpha_4(a, dummy);
4149 Q_STATIC_TEMPLATE_SPECIALIZATION
4150 inline quint32 eff_ialpha_4(quint32 a, const qargb8555 *dummy)
4152 return 0x20202020 - eff_alpha_4(a, dummy);
4155 template <class DST, class SRC>
4156 inline void interpolate_pixel_unaligned_2(DST *dest, const SRC *src,
4159 const quint16 a = eff_alpha_2(alpha, dest);
4160 const quint16 ia = eff_ialpha_2(alpha, dest);
4161 dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
4162 dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
4165 template <class DST, class SRC>
4166 inline void interpolate_pixel_2(DST *dest, const SRC *src, quint16 alpha)
4168 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4169 Q_ASSERT((quintptr(src) & 0x3) == 0);
4171 const quint16 a = eff_alpha_2(alpha, dest);
4172 const quint16 ia = eff_ialpha_2(alpha, dest);
4174 dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
4175 dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
4178 template <class DST, class SRC>
4179 inline void interpolate_pixel(DST &dest, quint8 a, const SRC &src, quint8 b)
4181 if (SRC::hasAlpha() && !DST::hasAlpha())
4182 interpolate_pixel(dest, a, DST(src), b);
4184 dest = dest.byte_mul(a) + DST(src).byte_mul(b);
4188 inline void interpolate_pixel(qargb8565 &dest, quint8 a,
4189 const qargb8565 &src, quint8 b)
4191 quint8 *d = reinterpret_cast<quint8*>(&dest);
4192 const quint8 *s = reinterpret_cast<const quint8*>(&src);
4193 d[0] = (d[0] * a + s[0] * b) >> 5;
4195 const quint16 x = (d[2] << 8) | d[1];
4196 const quint16 y = (s[2] << 8) | s[1];
4197 quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
4198 t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
4205 inline void interpolate_pixel(qrgb565 &dest, quint8 a,
4206 const qrgb565 &src, quint8 b)
4208 const quint16 x = dest.rawValue();
4209 const quint16 y = src.rawValue();
4210 quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
4211 t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
4216 inline void interpolate_pixel(qrgb555 &dest, quint8 a,
4217 const qrgb555 &src, quint8 b)
4219 const quint16 x = dest.rawValue();
4220 const quint16 y = src.rawValue();
4221 quint16 t = (((x & 0x03e0) * a + (y & 0x03e0) * b) >> 5) & 0x03e0;
4222 t |= ((((x & 0x7c1f) * a) + ((y & 0x7c1f) * b)) >> 5) & 0x7c1f;
4227 inline void interpolate_pixel(qrgb444 &dest, quint8 a,
4228 const qrgb444 &src, quint8 b)
4230 const quint16 x = dest.rawValue();
4231 const quint16 y = src.rawValue();
4232 quint16 t = ((x & 0x00f0) * a + (y & 0x00f0) * b) & 0x0f00;
4233 t |= ((x & 0x0f0f) * a + (y & 0x0f0f) * b) & 0xf0f0;
4234 quint16 *d = reinterpret_cast<quint16*>(&dest);
4238 template <class DST, class SRC>
4239 inline void interpolate_pixel_2(DST *dest, quint8 a,
4240 const SRC *src, quint8 b)
4242 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4243 Q_ASSERT((quintptr(src) & 0x3) == 0);
4245 Q_ASSERT(!SRC::hasAlpha());
4247 dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
4248 dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
4252 inline void interpolate_pixel_2(qrgb565 *dest, quint8 a,
4253 const qrgb565 *src, quint8 b)
4255 quint32 *x = reinterpret_cast<quint32*>(dest);
4256 const quint32 *y = reinterpret_cast<const quint32*>(src);
4257 quint32 t = (((*x & 0xf81f07e0) >> 5) * a +
4258 ((*y & 0xf81f07e0) >> 5) * b) & 0xf81f07e0;
4259 t |= (((*x & 0x07e0f81f) * a
4260 + (*y & 0x07e0f81f) * b) >> 5) & 0x07e0f81f;
4265 inline void interpolate_pixel_2(qrgb555 *dest, quint8 a,
4266 const qrgb555 *src, quint8 b)
4268 quint32 *x = reinterpret_cast<quint32*>(dest);
4269 const quint32 *y = reinterpret_cast<const quint32*>(src);
4270 quint32 t = (((*x & 0x7c1f03e0) >> 5) * a +
4271 ((*y & 0x7c1f03e0) >> 5) * b) & 0x7c1f03e0;
4272 t |= (((*x & 0x03e07c1f) * a
4273 + (*y & 0x03e07c1f) * b) >> 5) & 0x03e07c1f;
4278 inline void interpolate_pixel_2(qrgb444 *dest, quint8 a,
4279 const qrgb444 *src, quint8 b)
4281 quint32 *x = reinterpret_cast<quint32*>(dest);
4282 const quint32 *y = reinterpret_cast<const quint32*>(src);
4283 quint32 t = ((*x & 0x0f0f0f0f) * a + (*y & 0x0f0f0f0f) * b) & 0xf0f0f0f0;
4284 t |= ((*x & 0x00f000f0) * a + (*y & 0x00f000f0) * b) & 0x0f000f00;
4288 template <class DST, class SRC>
4289 inline void interpolate_pixel_4(DST *dest, const SRC *src, quint32 alpha)
4291 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4292 Q_ASSERT((quintptr(src) & 0x3) == 0);
4294 const quint32 a = eff_alpha_4(alpha, dest);
4295 const quint32 ia = eff_ialpha_4(alpha, dest);
4296 dest[0] = DST(src[0]).byte_mul(a >> 24)
4297 + dest[0].byte_mul(ia >> 24);
4298 dest[1] = DST(src[1]).byte_mul((a >> 16) & 0xff)
4299 + dest[1].byte_mul((ia >> 16) & 0xff);
4300 dest[2] = DST(src[2]).byte_mul((a >> 8) & 0xff)
4301 + dest[2].byte_mul((ia >> 8) & 0xff);
4302 dest[3] = DST(src[3]).byte_mul(a & 0xff)
4303 + dest[3].byte_mul(ia & 0xff);
4306 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4308 inline void interpolate_pixel_4(qargb8565 *dest, const qargb8565 *src,
4311 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4312 Q_ASSERT((quintptr(src) & 0x3) == 0);
4314 const quint32 a = eff_alpha_4(alpha, dest);
4315 const quint32 ia = eff_ialpha_4(alpha, dest);
4316 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4317 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4329 t = (((x & 0x0007e0ff) * a8 + (y & 0x0007e0ff) * ia8) >> 5)
4333 t |= (((x & 0x00f81f00) * a8 + (y & 0x00f81f00) * ia8) >> 5)
4336 a8 = (a >> 16) & 0xff;
4337 ia8 = (ia >> 16) & 0xff;
4340 t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
4350 t = (((x & 0x0000f81f) * a8 + (y & 0x0000f81f) * ia8) >> 5)
4354 t |= (((x & 0x000007e0) * a8 + (y & 0x000007e0) * ia8) >> 5)
4357 a8 = (a >> 8) & 0xff;
4358 ia8 = (ia >> 8) & 0xff;
4361 t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
4366 quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
4367 quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
4370 t16 = (((x16 & 0xf81f) * a8 + (y16 & 0xf81f) * ia8) >> 5) & 0xf81f;
4371 t16 |= (((x16 & 0x07e0) * a8 + (y16 & 0x07e0) * ia8) >> 5) & 0x07e0;
4374 t |= ((t16 & 0x00ff) << 24);
4390 t |= (((x & 0x07e0ff00) * a8 + (y & 0x07e0ff00) * ia8) >> 5)
4394 t |= (((x & 0xf81f0000) >> 5) * a8 + ((y & 0xf81f0000) >> 5) * ia8)
4402 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4404 inline void interpolate_pixel_4(qargb8555 *dest, const qargb8555 *src,
4407 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4408 Q_ASSERT((quintptr(src) & 0x3) == 0);
4411 const quint32 a = eff_alpha_4(alpha, dest);
4412 const quint32 ia = eff_ialpha_4(alpha, dest);
4413 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4414 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4426 t = (((x & 0x0003e0ff) * a8 + (y & 0x0003e0ff) * ia8) >> 5)
4430 t |= (((x & 0x007c1f00) * a8 + (y & 0x007c1f00) * ia8) >> 5)
4433 a8 = (a >> 16) & 0xff;
4434 ia8 = (ia >> 16) & 0xff;
4437 t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
4447 t = (((x & 0x00007c1f) * a8 + (y & 0x00007c1f) * ia8) >> 5)
4451 t |= (((x & 0x000003e0) * a8 + (y & 0x000003e0) * ia8) >> 5)
4454 a8 = (a >> 8) & 0xff;
4455 ia8 = (ia >> 8) & 0xff;
4458 t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
4463 quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
4464 quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
4467 t16 = (((x16 & 0x7c1f) * a8 + (y16 & 0x7c1f) * ia8) >> 5) & 0x7c1f;
4468 t16 |= (((x16 & 0x03e0) * a8 + (y16 & 0x03e0) * ia8) >> 5) & 0x03e0;
4471 t |= ((t16 & 0x00ff) << 24);
4487 t |= (((x & 0x03e0ff00) * a8 + (y & 0x03e0ff00) * ia8) >> 5)
4491 t |= (((x & 0x7c1f0000) >> 5) * a8 + ((y & 0x7c1f0000) >> 5) * ia8)
4500 inline void interpolate_pixel_4(qrgb888 *dest, const qrgb888 *src,
4503 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4504 Q_ASSERT((quintptr(src) & 0x3) == 0);
4506 const quint32 a = eff_alpha_4(alpha, dest);
4507 const quint32 ia = eff_ialpha_4(alpha, dest);
4508 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4509 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4512 quint32 x = src32[0];
4513 quint32 y = dest32[0];
4516 t = ((x >> 8) & 0xff00ff) * (a >> 24)
4517 + ((y >> 8) & 0xff00ff) * (ia >> 24);
4518 t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4521 x = (x & 0xff0000) * (a >> 24)
4522 + (x & 0x0000ff) * ((a >> 16) & 0xff)
4523 + (y & 0xff0000) * (ia >> 24)
4524 + (y & 0x0000ff) * ((ia >> 16) & 0xff);
4525 x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4531 quint32 x = src32[1];
4532 quint32 y = dest32[1];
4535 t = ((x >> 8) & 0xff0000) * ((a >> 16) & 0xff)
4536 + ((x >> 8) & 0x0000ff) * ((a >> 8) & 0xff)
4537 + ((y >> 8) & 0xff0000) * ((ia >> 16) & 0xff)
4538 + ((y >> 8) & 0x0000ff) * ((ia >> 8) & 0xff);
4539 t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4542 x = (x & 0xff0000) * ((a >> 16) & 0xff)
4543 + (x & 0x0000ff) * ((a >> 8) & 0xff)
4544 + (y & 0xff0000) * ((ia >> 16) & 0xff)
4545 + (y & 0x0000ff) * ((ia >> 8) & 0xff);
4546 x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4552 quint32 x = src32[2];
4553 quint32 y = dest32[2];
4556 t = ((x >> 8) & 0xff0000) * ((a >> 8) & 0xff)
4557 + ((x >> 8) & 0x0000ff) * (a & 0xff)
4558 + ((y >> 8) & 0xff0000) * ((ia >> 8) & 0xff)
4559 + ((y >> 8) & 0x0000ff) * (ia & 0xff);
4560 t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4563 x = (x & 0xff00ff) * (a & 0xff)
4564 + (y & 0xff00ff) * (ia & 0xff);
4565 x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4572 template <class DST, class SRC>
4573 inline void interpolate_pixel_4(DST *dest, quint8 a,
4574 const SRC *src, quint8 b)
4576 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4577 Q_ASSERT((quintptr(src) & 0x3) == 0);
4579 dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
4580 dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
4581 dest[2] = dest[2].byte_mul(a) + DST(src[2]).byte_mul(b);
4582 dest[3] = dest[3].byte_mul(a) + DST(src[3]).byte_mul(b);
4585 template <class DST, class SRC>
4586 inline void blend_sourceOver_4(DST *dest, const SRC *src)
4588 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4589 Q_ASSERT((quintptr(src) & 0x3) == 0);
4591 const quint32 a = alpha_4(src);
4592 if (a == 0xffffffff) {
4593 qt_memconvert(dest, src, 4);
4595 quint32 buf[3]; // array of quint32 to get correct alignment
4596 qt_memconvert((DST*)(void*)buf, src, 4);
4597 madd_4(dest, eff_ialpha_4(a, dest), (DST*)(void*)buf);
4602 inline void blend_sourceOver_4(qargb8565 *dest, const qargb8565 *src)
4604 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4605 Q_ASSERT((quintptr(src) & 0x3) == 0);
4607 const quint32 a = alpha_4(src);
4608 if (a == 0xffffffff) {
4609 qt_memconvert(dest, src, 4);
4611 madd_4(dest, eff_ialpha_4(a, dest), src);
4616 inline void blend_sourceOver_4(qargb8555 *dest, const qargb8555 *src)
4618 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4619 Q_ASSERT((quintptr(src) & 0x3) == 0);
4621 const quint32 a = alpha_4(src);
4622 if (a == 0xffffffff) {
4623 qt_memconvert(dest, src, 4);
4625 madd_4(dest, eff_ialpha_4(a, dest), src);
4630 inline void blend_sourceOver_4(qargb6666 *dest, const qargb6666 *src)
4632 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4633 Q_ASSERT((quintptr(src) & 0x3) == 0);
4635 const quint32 a = alpha_4(src);
4636 if (a == 0xffffffff) {
4637 qt_memconvert(dest, src, 4);
4639 madd_4(dest, eff_ialpha_4(a, dest), src);
4643 template <class DST, class SRC>
4644 void QT_FASTCALL blendUntransformed_unaligned(DST *dest, const SRC *src,
4645 quint8 coverage, int length)
4647 Q_ASSERT(coverage > 0);
4649 if (coverage < 255) {
4650 if (SRC::hasAlpha()) {
4651 for (int i = 0; i < length; ++i) {
4652 if (src[i].alpha()) {
4653 const quint8 alpha = qt_div_255(int(src[i].alpha()) * int(coverage));
4654 interpolate_pixel(dest[i], DST::ialpha(alpha),
4655 src[i], DST::alpha(alpha));
4659 const quint8 alpha = DST::alpha(coverage);
4660 const quint8 ialpha = DST::ialpha(coverage);
4662 for (int i = 0; i < length; ++i)
4663 interpolate_pixel(dest[i], ialpha, src[i], alpha);
4669 Q_ASSERT(coverage == 0xff);
4670 Q_ASSERT(SRC::hasAlpha());
4672 if (SRC::hasAlpha()) {
4673 for (int i = 0; i < length; ++i) {
4674 const quint8 a = src->alpha();
4678 if (DST::hasAlpha())
4679 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4681 *dest = DST(SRC(*src).truncedAlpha()) + dest->byte_mul(DST::ialpha(a));
4689 template <class DST, class SRC>
4690 void QT_FASTCALL blendUntransformed_dest16(DST *dest, const SRC *src,
4691 quint8 coverage, int length)
4693 Q_ASSERT(sizeof(DST) == 2);
4694 Q_ASSERT(sizeof(SRC) == 2);
4695 Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
4696 Q_ASSERT(coverage > 0);
4698 const int align = quintptr(dest) & 0x3;
4700 if (coverage < 255) {
4703 const quint8 alpha = SRC::hasAlpha()
4704 ? qt_div_255(int(src->alpha()) * int(coverage))
4707 interpolate_pixel(*dest, DST::ialpha(alpha),
4708 *src, DST::alpha(alpha));
4715 if (SRC::hasAlpha()) {
4716 while (length >= 2) {
4717 const quint16 alpha16 = BYTE_MUL(uint(alpha_2(src)), uint(coverage));
4718 interpolate_pixel_2(dest, src, alpha16);
4724 const quint8 alpha = DST::alpha(coverage);
4725 const quint8 ialpha = DST::ialpha(coverage);
4727 while (length >= 2) {
4728 interpolate_pixel_2(dest, ialpha, src, alpha);
4737 const quint8 alpha = SRC::hasAlpha()
4738 ? qt_div_255(int(src->alpha()) * int(coverage))
4741 interpolate_pixel(*dest, DST::ialpha(alpha),
4742 *src, DST::alpha(alpha));
4749 Q_ASSERT(SRC::hasAlpha());
4750 if (SRC::hasAlpha()) {
4752 const quint8 alpha = src->alpha();
4756 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
4762 while (length >= 2) {
4763 Q_ASSERT((quintptr(dest) & 3) == 0);
4764 Q_ASSERT((quintptr(src) & 3) == 0);
4766 const quint16 a = alpha_2(src);
4768 qt_memconvert(dest, src, 2);
4771 if (sizeof(DST) == 2)
4772 qt_memconvert((DST*)(void*)&buf, src, 2);
4773 madd_2(dest, eff_ialpha_2(a, dest), (DST*)(void*)&buf);
4782 const quint8 alpha = src->alpha();
4786 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
4791 template <class DST, class SRC>
4792 void QT_FASTCALL blendUntransformed_dest24(DST *dest, const SRC *src,
4793 quint8 coverage, int length)
4795 Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
4796 Q_ASSERT(sizeof(DST) == 3);
4797 Q_ASSERT(coverage > 0);
4799 const int align = quintptr(dest) & 0x3;
4801 if (coverage < 255) {
4803 for (int i = 0; i < align; ++i) {
4804 if (SRC::hasAlpha()) {
4805 const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
4807 interpolate_pixel(*dest, DST::ialpha(alpha),
4808 *src, DST::alpha(alpha));
4810 interpolate_pixel(*dest, DST::ialpha(coverage),
4811 *src, DST::alpha(coverage));
4818 if (SRC::hasAlpha()) {
4819 while (length >= 4) {
4820 const quint32 alpha = QT_PREPEND_NAMESPACE(BYTE_MUL)(uint(alpha_4(src)), uint(coverage));
4822 interpolate_pixel_4(dest, src, alpha);
4828 const quint8 alpha = DST::alpha(coverage);
4829 const quint8 ialpha = DST::ialpha(coverage);
4830 while (length >= 4) {
4831 interpolate_pixel_4(dest, ialpha, src, alpha);
4840 if (SRC::hasAlpha()) {
4841 const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
4843 interpolate_pixel(*dest, DST::ialpha(alpha),
4844 *src, DST::alpha(alpha));
4846 interpolate_pixel(*dest, DST::ialpha(coverage),
4847 *src, DST::alpha(coverage));
4857 Q_ASSERT(coverage == 255);
4858 Q_ASSERT(SRC::hasAlpha());
4860 if (SRC::hasAlpha()) {
4862 for (int i = 0; i < align; ++i) {
4863 const quint8 a = src->alpha();
4867 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4874 while (length >= 4) {
4875 blend_sourceOver_4(dest, src);
4883 const quint8 a = src->alpha();
4887 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4895 template <class DST, class SRC>
4896 Q_STATIC_TEMPLATE_SPECIALIZATION
4897 void QT_FASTCALL blendUntransformed(int count, const QSpan *spans, void *userData)
4899 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4900 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4902 if (mode != QPainter::CompositionMode_SourceOver &&
4903 mode != QPainter::CompositionMode_Source)
4905 blend_src_generic<RegularSpans>(count, spans, userData);
4909 const bool modeSource = !SRC::hasAlpha() ||
4910 mode == QPainter::CompositionMode_Source;
4911 const int image_width = data->texture.width;
4912 const int image_height = data->texture.height;
4913 int xoff = -qRound(-data->dx);
4914 int yoff = -qRound(-data->dy);
4917 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4918 if (coverage == 0) {
4924 int length = spans->len;
4926 int sy = yoff + spans->y;
4927 if (sy >= 0 && sy < image_height && sx < image_width) {
4933 if (sx + length > image_width)
4934 length = image_width - sx;
4936 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
4937 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
4938 if (modeSource && coverage == 255) {
4939 qt_memconvert<DST, SRC>(dest, src, length);
4940 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && length >= 3 &&
4941 (quintptr(dest) & 3) == (quintptr(src) & 3))
4943 blendUntransformed_dest24(dest, src, coverage, length);
4944 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && length >= 3 &&
4945 (quintptr(dest) & 3) == (quintptr(src) & 3))
4947 blendUntransformed_dest16(dest, src, coverage, length);
4949 blendUntransformed_unaligned(dest, src, coverage, length);
4957 static void blend_untransformed_rgb888(int count, const QSpan *spans,
4960 #if defined(QT_QWS_DEPTH_24)
4961 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4963 if (data->texture.format == QImage::Format_RGB888)
4964 blendUntransformed<qrgb888, qrgb888>(count, spans, userData);
4967 blend_untransformed_generic<RegularSpans>(count, spans, userData);
4970 static void blend_untransformed_argb6666(int count, const QSpan *spans,
4973 #if defined(QT_QWS_DEPTH_18)
4974 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4976 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
4977 blendUntransformed<qargb6666, qargb6666>(count, spans, userData);
4978 else if (data->texture.format == QImage::Format_RGB666)
4979 blendUntransformed<qargb6666, qrgb666>(count, spans, userData);
4982 blend_untransformed_generic<RegularSpans>(count, spans, userData);
4985 static void blend_untransformed_rgb666(int count, const QSpan *spans,
4988 #if defined(QT_QWS_DEPTH_18)
4989 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4991 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
4992 blendUntransformed<qrgb666, qargb6666>(count, spans, userData);
4993 else if (data->texture.format == QImage::Format_RGB666)
4994 blendUntransformed<qrgb666, qrgb666>(count, spans, userData);
4997 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5000 static void blend_untransformed_argb8565(int count, const QSpan *spans,
5003 #if defined(QT_QWS_DEPTH_16)
5004 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5006 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5007 blendUntransformed<qargb8565, qargb8565>(count, spans, userData);
5008 else if (data->texture.format == QImage::Format_RGB16)
5009 blendUntransformed<qargb8565, qrgb565>(count, spans, userData);
5012 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5015 static void blend_untransformed_rgb565(int count, const QSpan *spans,
5018 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
5019 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5021 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5022 blendUntransformed<qrgb565, qargb8565>(count, spans, userData);
5023 else if (data->texture.format == QImage::Format_RGB16)
5024 blendUntransformed<qrgb565, qrgb565>(count, spans, userData);
5027 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5030 static void blend_untransformed_argb8555(int count, const QSpan *spans,
5033 #if defined(QT_QWS_DEPTH_15)
5034 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5036 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5037 blendUntransformed<qargb8555, qargb8555>(count, spans, userData);
5038 else if (data->texture.format == QImage::Format_RGB555)
5039 blendUntransformed<qargb8555, qrgb555>(count, spans, userData);
5042 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5045 static void blend_untransformed_rgb555(int count, const QSpan *spans,
5048 #if defined(QT_QWS_DEPTH_15)
5049 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5051 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5052 blendUntransformed<qrgb555, qargb8555>(count, spans, userData);
5053 else if (data->texture.format == QImage::Format_RGB555)
5054 blendUntransformed<qrgb555, qrgb555>(count, spans, userData);
5057 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5060 static void blend_untransformed_argb4444(int count, const QSpan *spans,
5063 #if defined(QT_QWS_DEPTH_12)
5064 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5066 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5067 blendUntransformed<qargb4444, qargb4444>(count, spans, userData);
5068 else if (data->texture.format == QImage::Format_RGB444)
5069 blendUntransformed<qargb4444, qrgb444>(count, spans, userData);
5072 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5075 static void blend_untransformed_rgb444(int count, const QSpan *spans,
5078 #if defined(QT_QWS_DEPTH_12)
5079 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5081 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5082 blendUntransformed<qrgb444, qargb4444>(count, spans, userData);
5083 else if (data->texture.format == QImage::Format_RGB444)
5084 blendUntransformed<qrgb444, qrgb444>(count, spans, userData);
5087 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5090 template <SpanMethod spanMethod>
5091 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_generic(int count, const QSpan *spans, void *userData)
5093 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5095 uint buffer[buffer_size];
5096 uint src_buffer[buffer_size];
5097 Operator op = getOperator(data, spans, count);
5099 const int image_width = data->texture.width;
5100 const int image_height = data->texture.height;
5101 int xoff = -qRound(-data->dx) % image_width;
5102 int yoff = -qRound(-data->dy) % image_height;
5105 xoff += image_width;
5107 yoff += image_height;
5111 int length = spans->len;
5112 int sx = (xoff + spans->x) % image_width;
5113 int sy = (spans->y + yoff) % image_height;
5119 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5121 int l = qMin(image_width - sx, length);
5122 if (buffer_size < l)
5124 const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
5125 if (spanMethod == RegularSpans) {
5126 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
5127 op.func(dest, src, l, coverage);
5129 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
5131 drawBufferSpan(data, src, l, x, spans->y, l,
5137 if (sx >= image_width)
5144 template <SpanMethod spanMethod>
5145 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_argb(int count, const QSpan *spans, void *userData)
5147 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5148 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
5149 && data->texture.format != QImage::Format_RGB32) {
5150 blend_tiled_generic<spanMethod>(count, spans, userData);
5154 Operator op = getOperator(data, spans, count);
5156 int image_width = data->texture.width;
5157 int image_height = data->texture.height;
5158 int xoff = -qRound(-data->dx) % image_width;
5159 int yoff = -qRound(-data->dy) % image_height;
5162 xoff += image_width;
5164 yoff += image_height;
5168 int length = spans->len;
5169 int sx = (xoff + spans->x) % image_width;
5170 int sy = (spans->y + yoff) % image_height;
5176 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5178 int l = qMin(image_width - sx, length);
5179 if (buffer_size < l)
5181 const uint *src = (uint *)data->texture.scanLine(sy) + sx;
5182 if (spanMethod == RegularSpans) {
5183 uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
5184 op.func(dest, src, l, coverage);
5186 drawBufferSpan(data, src, buffer_size,
5187 x, spans->y, l, coverage);
5197 template <class DST, class SRC>
5198 Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *userData)
5200 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5201 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5203 if (mode != QPainter::CompositionMode_SourceOver &&
5204 mode != QPainter::CompositionMode_Source)
5206 blend_src_generic<RegularSpans>(count, spans, userData);
5210 const bool modeSource = !SRC::hasAlpha() ||
5211 mode == QPainter::CompositionMode_Source;
5212 const int image_width = data->texture.width;
5213 const int image_height = data->texture.height;
5214 int xoff = -qRound(-data->dx) % image_width;
5215 int yoff = -qRound(-data->dy) % image_height;
5218 xoff += image_width;
5220 yoff += image_height;
5223 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5224 if (coverage == 0) {
5230 int length = spans->len;
5231 int sx = (xoff + spans->x) % image_width;
5232 int sy = (spans->y + yoff) % image_height;
5238 if (modeSource && coverage == 255) {
5239 // Copy the first texture block
5240 length = qMin(image_width,length);
5243 int l = qMin(image_width - sx, length);
5244 if (buffer_size < l)
5246 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + tx;
5247 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5249 qt_memconvert<DST, SRC>(dest, src, l);
5255 // Now use the rasterBuffer as the source of the texture,
5256 // We can now progressively copy larger blocks
5257 // - Less cpu time in code figuring out what to copy
5258 // We are dealing with one block of data
5259 // - More likely to fit in the cache
5261 int copy_image_width = qMin(image_width, int(spans->len));
5262 length = spans->len - copy_image_width;
5263 DST *src = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5264 DST *dest = src + copy_image_width;
5265 while (copy_image_width < length) {
5266 qt_memconvert(dest, src, copy_image_width);
5267 dest += copy_image_width;
5268 length -= copy_image_width;
5269 copy_image_width *= 2;
5272 qt_memconvert(dest, src, length);
5275 int l = qMin(image_width - sx, length);
5276 if (buffer_size < l)
5278 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5279 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5280 if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5281 (quintptr(dest) & 3) == (quintptr(src) & 3))
5283 blendUntransformed_dest24(dest, src, coverage, l);
5284 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5285 (quintptr(dest) & 3) == (quintptr(src) & 3))
5287 blendUntransformed_dest16(dest, src, coverage, l);
5289 blendUntransformed_unaligned(dest, src, coverage, l);
5301 static void blend_tiled_rgb888(int count, const QSpan *spans, void *userData)
5303 #if defined(QT_QWS_DEPTH_24)
5304 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5306 if (data->texture.format == QImage::Format_RGB888)
5307 blendTiled<qrgb888, qrgb888>(count, spans, userData);
5310 blend_tiled_generic<RegularSpans>(count, spans, userData);
5313 static void blend_tiled_argb6666(int count, const QSpan *spans, void *userData)
5315 #if defined(QT_QWS_DEPTH_18)
5316 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5318 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
5319 blendTiled<qargb6666, qargb6666>(count, spans, userData);
5320 else if (data->texture.format == QImage::Format_RGB666)
5321 blendTiled<qargb6666, qrgb666>(count, spans, userData);
5324 blend_tiled_generic<RegularSpans>(count, spans, userData);
5327 static void blend_tiled_rgb666(int count, const QSpan *spans, void *userData)
5329 #if defined(QT_QWS_DEPTH_18)
5330 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5332 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
5333 blendTiled<qrgb666, qargb6666>(count, spans, userData);
5334 else if (data->texture.format == QImage::Format_RGB666)
5335 blendTiled<qrgb666, qrgb666>(count, spans, userData);
5338 blend_tiled_generic<RegularSpans>(count, spans, userData);
5341 static void blend_tiled_argb8565(int count, const QSpan *spans, void *userData)
5343 #if defined(QT_QWS_DEPTH_16)
5344 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5346 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5347 blendTiled<qargb8565, qargb8565>(count, spans, userData);
5348 else if (data->texture.format == QImage::Format_RGB16)
5349 blendTiled<qargb8565, qrgb565>(count, spans, userData);
5352 blend_tiled_generic<RegularSpans>(count, spans, userData);
5355 static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
5357 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
5358 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5360 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5361 blendTiled<qrgb565, qargb8565>(count, spans, userData);
5362 else if (data->texture.format == QImage::Format_RGB16)
5363 blendTiled<qrgb565, qrgb565>(count, spans, userData);
5366 blend_tiled_generic<RegularSpans>(count, spans, userData);
5369 static void blend_tiled_argb8555(int count, const QSpan *spans, void *userData)
5371 #if defined(QT_QWS_DEPTH_15)
5372 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5374 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5375 blendTiled<qargb8555, qargb8555>(count, spans, userData);
5376 else if (data->texture.format == QImage::Format_RGB555)
5377 blendTiled<qargb8555, qrgb555>(count, spans, userData);
5380 blend_tiled_generic<RegularSpans>(count, spans, userData);
5383 static void blend_tiled_rgb555(int count, const QSpan *spans, void *userData)
5385 #if defined(QT_QWS_DEPTH_15)
5386 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5388 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5389 blendTiled<qrgb555, qargb8555>(count, spans, userData);
5390 else if (data->texture.format == QImage::Format_RGB555)
5391 blendTiled<qrgb555, qrgb555>(count, spans, userData);
5394 blend_tiled_generic<RegularSpans>(count, spans, userData);
5397 static void blend_tiled_argb4444(int count, const QSpan *spans, void *userData)
5399 #if defined(QT_QWS_DEPTH_12)
5400 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5402 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5403 blendTiled<qargb4444, qargb4444>(count, spans, userData);
5404 else if (data->texture.format == QImage::Format_RGB444)
5405 blendTiled<qargb4444, qrgb444>(count, spans, userData);
5408 blend_tiled_generic<RegularSpans>(count, spans, userData);
5411 static void blend_tiled_rgb444(int count, const QSpan *spans, void *userData)
5413 #if defined(QT_QWS_DEPTH_12)
5414 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5416 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5417 blendTiled<qrgb444, qargb4444>(count, spans, userData);
5418 else if (data->texture.format == QImage::Format_RGB444)
5419 blendTiled<qrgb444, qrgb444>(count, spans, userData);
5422 blend_tiled_generic<RegularSpans>(count, spans, userData);
5425 template <class DST, class SRC>
5426 Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan *spans,
5429 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5430 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5433 if (mode != QPainter::CompositionMode_SourceOver) {
5434 blend_src_generic<RegularSpans>(count, spans, userData);
5438 SRC buffer[buffer_size];
5440 const int src_minx = data->texture.x1;
5441 const int src_miny = data->texture.y1;
5442 const int src_maxx = data->texture.x2 - 1;
5443 const int src_maxy = data->texture.y2 - 1;
5445 if (data->fast_matrix) {
5446 // The increment pr x in the scanline
5447 const int fdx = (int)(data->m11 * fixed_scale);
5448 const int fdy = (int)(data->m12 * fixed_scale);
5451 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5452 if (coverage == 0) {
5457 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5459 const qreal cx = spans->x + qreal(0.5);
5460 const qreal cy = spans->y + qreal(0.5);
5461 int x = int((data->m21 * cy
5462 + data->m11 * cx + data->dx) * fixed_scale) - half_point;
5463 int y = int((data->m22 * cy
5464 + data->m12 * cx + data->dy) * fixed_scale) - half_point;
5465 int length = spans->len;
5468 const int l = qMin(length, buffer_size);
5470 const SRC *end = buffer + l;
5478 const int distx = (x & 0x0000ffff) >> 8;
5479 const int disty = (y & 0x0000ffff) >> 8;
5481 if (x1 < src_minx) {
5483 } else if (x1 >= src_maxx) {
5488 if (y1 < src_miny) {
5490 } else if (y1 >= src_maxy) {
5498 *b = ((SRC*)data->texture.scanLine(y1))[x1];
5500 *b = ((SRC*)data->texture.scanLine(y1))[x1];
5501 const SRC t = data->texture.scanLine(y2)[x1];
5502 interpolate_pixel(*b, SRC::ialpha(disty),
5503 t, SRC::alpha(disty));
5505 } else if (y1 == y2) {
5506 *b = ((SRC*)data->texture.scanLine(y1))[x1];
5507 const SRC t = ((SRC*)data->texture.scanLine(y1))[x2];
5508 interpolate_pixel(*b, SRC::ialpha(distx),
5509 t, SRC::alpha(distx));
5513 const SRC *src1 = (SRC*)data->texture.scanLine(y1);
5514 const SRC *src2 = (SRC*)data->texture.scanLine(y2);
5516 const SRC tr = src1[x2];
5518 const SRC br = src2[x2];
5519 const quint8 ax = SRC::alpha(distx);
5520 const quint8 iax = SRC::ialpha(distx);
5522 interpolate_pixel(tl, iax, tr, ax);
5523 interpolate_pixel(bl, iax, br, ax);
5524 interpolate_pixel(tl, SRC::ialpha(disty),
5525 bl, SRC::alpha(disty));
5534 if (!SRC::hasAlpha() && coverage == 255) {
5535 qt_memconvert(dest, buffer, l);
5536 } else if (sizeof(DST) == 3 && l >= 4 &&
5537 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5539 blendUntransformed_dest24(dest, buffer, coverage, l);
5540 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5541 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5542 blendUntransformed_dest16(dest, buffer, coverage, l);
5544 blendUntransformed_unaligned(dest, buffer, coverage, l);
5553 const qreal fdx = data->m11;
5554 const qreal fdy = data->m12;
5555 const qreal fdw = data->m13;
5558 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5559 if (coverage == 0) {
5564 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5567 const qreal cx = spans->x + qreal(0.5);
5568 const qreal cy = spans->y + qreal(0.5);
5570 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5571 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5572 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5574 int length = spans->len;
5576 const int l = qMin(length, buffer_size);
5577 const SRC *end = buffer + l;
5580 const qreal iw = w == 0 ? 1 : 1 / w;
5581 const qreal px = x * iw - qreal(0.5);
5582 const qreal py = y * iw - qreal(0.5);
5584 int x1 = int(px) - (px < 0);
5586 int y1 = int(py) - (py < 0);
5589 const int distx = int((px - x1) * 256);
5590 const int disty = int((py - y1) * 256);
5592 if (x1 < src_minx) {
5594 } else if (x1 >= src_maxx) {
5599 if (y1 < src_miny) {
5601 } else if (y1 >= src_maxy) {
5607 const SRC *src1 = (SRC*)data->texture.scanLine(y1);
5608 const SRC *src2 = (SRC*)data->texture.scanLine(y2);
5610 const SRC tr = src1[x2];
5612 const SRC br = src2[x2];
5613 const quint8 ax = SRC::alpha(distx);
5614 const quint8 iax = SRC::ialpha(distx);
5616 interpolate_pixel(tl, iax, tr, ax);
5617 interpolate_pixel(bl, iax, br, ax);
5618 interpolate_pixel(tl, SRC::ialpha(disty),
5619 bl, SRC::alpha(disty));
5627 if (!SRC::hasAlpha() && coverage == 255) {
5628 qt_memconvert(dest, buffer, l);
5629 } else if (sizeof(DST) == 3 && l >= 4 &&
5630 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5632 blendUntransformed_dest24(dest, buffer, coverage, l);
5633 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5634 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5635 blendUntransformed_dest16(dest, buffer, coverage, l);
5637 blendUntransformed_unaligned(dest, buffer, coverage, l);
5648 static void blend_transformed_bilinear_rgb888(int count, const QSpan *spans, void *userData)
5650 #if defined(QT_QWS_DEPTH_24)
5651 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5653 if (data->texture.format == QImage::Format_RGB888)
5654 blendTransformedBilinear<qrgb888, qrgb888>(count, spans, userData);
5657 blend_src_generic<RegularSpans>(count, spans, userData);
5660 static void blend_transformed_bilinear_argb6666(int count, const QSpan *spans, void *userData)
5662 #if defined(QT_QWS_DEPTH_18)
5663 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5665 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
5666 blendTransformedBilinear<qargb6666, qargb6666>(count, spans, userData);
5667 else if (data->texture.format == QImage::Format_RGB666)
5668 blendTransformedBilinear<qargb6666, qrgb666>(count, spans, userData);
5671 blend_src_generic<RegularSpans>(count, spans, userData);
5674 static void blend_transformed_bilinear_rgb666(int count, const QSpan *spans, void *userData)
5676 #if defined(QT_QWS_DEPTH_18)
5677 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5679 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
5680 blendTransformedBilinear<qrgb666, qargb6666>(count, spans, userData);
5681 else if (data->texture.format == QImage::Format_RGB666)
5682 blendTransformedBilinear<qrgb666, qrgb666>(count, spans, userData);
5685 blend_src_generic<RegularSpans>(count, spans, userData);
5688 static void blend_transformed_bilinear_argb8565(int count, const QSpan *spans, void *userData)
5690 #if defined(QT_QWS_DEPTH_16)
5691 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5693 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5694 blendTransformedBilinear<qargb8565, qargb8565>(count, spans, userData);
5695 else if (data->texture.format == QImage::Format_RGB16)
5696 blendTransformedBilinear<qargb8565, qrgb565>(count, spans, userData);
5699 blend_src_generic<RegularSpans>(count, spans, userData);
5702 static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans,
5705 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
5706 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5708 if (data->texture.format == QImage::Format_RGB16)
5709 blendTransformedBilinear<qrgb565, qrgb565>(count, spans, userData);
5710 else if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5711 blendTransformedBilinear<qrgb565, qargb8565>(count, spans, userData);
5714 blend_src_generic<RegularSpans>(count, spans, userData);
5717 static void blend_transformed_bilinear_argb8555(int count, const QSpan *spans, void *userData)
5719 #if defined(QT_QWS_DEPTH_15)
5720 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5722 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5723 blendTransformedBilinear<qargb8555, qargb8555>(count, spans, userData);
5724 else if (data->texture.format == QImage::Format_RGB555)
5725 blendTransformedBilinear<qargb8555, qrgb555>(count, spans, userData);
5728 blend_src_generic<RegularSpans>(count, spans, userData);
5731 static void blend_transformed_bilinear_rgb555(int count, const QSpan *spans, void *userData)
5733 #if defined(QT_QWS_DEPTH_15)
5734 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5736 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5737 blendTransformedBilinear<qrgb555, qargb8555>(count, spans, userData);
5738 else if (data->texture.format == QImage::Format_RGB555)
5739 blendTransformedBilinear<qrgb555, qrgb555>(count, spans, userData);
5742 blend_src_generic<RegularSpans>(count, spans, userData);
5745 static void blend_transformed_bilinear_argb4444(int count, const QSpan *spans, void *userData)
5747 #if defined(QT_QWS_DEPTH_12)
5748 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5750 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5751 blendTransformedBilinear<qargb4444, qargb4444>(count, spans, userData);
5752 else if (data->texture.format == QImage::Format_RGB444)
5753 blendTransformedBilinear<qargb4444, qrgb444>(count, spans, userData);
5756 blend_src_generic<RegularSpans>(count, spans, userData);
5759 static void blend_transformed_bilinear_rgb444(int count, const QSpan *spans, void *userData)
5761 #if defined(QT_QWS_DEPTH_12)
5762 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5764 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5765 blendTransformedBilinear<qrgb444, qargb4444>(count, spans, userData);
5766 else if (data->texture.format == QImage::Format_RGB444)
5767 blendTransformedBilinear<qrgb444, qrgb444>(count, spans, userData);
5770 blend_src_generic<RegularSpans>(count, spans, userData);
5773 template <SpanMethod spanMethod>
5774 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *spans, void *userData)
5776 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5777 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
5778 && data->texture.format != QImage::Format_RGB32) {
5779 blend_src_generic<spanMethod>(count, spans, userData);
5783 CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
5784 uint buffer[buffer_size];
5786 int image_width = data->texture.width;
5787 int image_height = data->texture.height;
5788 const int scanline_offset = data->texture.bytesPerLine / 4;
5790 if (data->fast_matrix) {
5791 // The increment pr x in the scanline
5792 int fdx = (int)(data->m11 * fixed_scale);
5793 int fdy = (int)(data->m12 * fixed_scale);
5796 void *t = data->rasterBuffer->scanLine(spans->y);
5798 uint *target = ((uint *)t) + spans->x;
5799 uint *image_bits = (uint *)data->texture.imageData;
5801 const qreal cx = spans->x + qreal(0.5);
5802 const qreal cy = spans->y + qreal(0.5);
5804 int x = int((data->m21 * cy
5805 + data->m11 * cx + data->dx) * fixed_scale);
5806 int y = int((data->m22 * cy
5807 + data->m12 * cx + data->dy) * fixed_scale);
5809 int length = spans->len;
5810 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5812 int l = qMin(length, buffer_size);
5813 const uint *end = buffer + l;
5819 bool out = (px < 0) || (px >= image_width)
5820 || (py < 0) || (py >= image_height);
5822 int y_offset = py * scanline_offset;
5823 *b = out ? uint(0) : image_bits[y_offset + px];
5828 if (spanMethod == RegularSpans)
5829 func(target, buffer, l, coverage);
5831 drawBufferSpan(data, buffer, buffer_size,
5832 spans->x + spans->len - length,
5833 spans->y, l, coverage);
5840 const qreal fdx = data->m11;
5841 const qreal fdy = data->m12;
5842 const qreal fdw = data->m13;
5844 void *t = data->rasterBuffer->scanLine(spans->y);
5846 uint *target = ((uint *)t) + spans->x;
5847 uint *image_bits = (uint *)data->texture.imageData;
5849 const qreal cx = spans->x + qreal(0.5);
5850 const qreal cy = spans->y + qreal(0.5);
5852 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5853 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5854 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5856 int length = spans->len;
5857 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5859 int l = qMin(length, buffer_size);
5860 const uint *end = buffer + l;
5863 const qreal iw = w == 0 ? 1 : 1 / w;
5864 const qreal tx = x * iw;
5865 const qreal ty = y * iw;
5866 const int px = int(tx) - (tx < 0);
5867 const int py = int(ty) - (ty < 0);
5869 bool out = (px < 0) || (px >= image_width)
5870 || (py < 0) || (py >= image_height);
5872 int y_offset = py * scanline_offset;
5873 *b = out ? uint(0) : image_bits[y_offset + px];
5880 if (spanMethod == RegularSpans)
5881 func(target, buffer, l, coverage);
5883 drawBufferSpan(data, buffer, buffer_size,
5884 spans->x + spans->len - length,
5885 spans->y, l, coverage);
5894 template <class DST, class SRC>
5895 Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans, void *userData)
5897 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5898 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5900 if (mode != QPainter::CompositionMode_SourceOver) {
5901 blend_src_generic<RegularSpans>(count, spans, userData);
5905 SRC buffer[buffer_size];
5906 const int image_width = data->texture.width;
5907 const int image_height = data->texture.height;
5909 if (data->fast_matrix) {
5910 // The increment pr x in the scanline
5911 const int fdx = (int)(data->m11 * fixed_scale);
5912 const int fdy = (int)(data->m12 * fixed_scale);
5915 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5916 if (coverage == 0) {
5921 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5923 const qreal cx = spans->x + qreal(0.5);
5924 const qreal cy = spans->y + qreal(0.5);
5925 int x = int((data->m21 * cy
5926 + data->m11 * cx + data->dx) * fixed_scale);
5927 int y = int((data->m22 * cy
5928 + data->m12 * cx + data->dy) * fixed_scale);
5929 int length = spans->len;
5932 const int l = qMin(length, buffer_size);
5934 const SRC *end = buffer + l;
5937 const int px = (x >> 16);
5938 const int py = (y >> 16);
5940 if ((px < 0) || (px >= image_width) ||
5941 (py < 0) || (py >= image_height))
5945 *b = ((SRC*)data->texture.scanLine(py))[px];
5953 if (!SRC::hasAlpha() && coverage == 255) {
5954 qt_memconvert(dest, buffer, l);
5955 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5956 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5958 blendUntransformed_dest24(dest, buffer, coverage, l);
5959 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5960 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5961 blendUntransformed_dest16(dest, buffer, coverage, l);
5963 blendUntransformed_unaligned(dest, buffer, coverage, l);
5972 const qreal fdx = data->m11;
5973 const qreal fdy = data->m12;
5974 const qreal fdw = data->m13;
5977 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5978 if (coverage == 0) {
5983 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5986 const qreal cx = spans->x + qreal(0.5);
5987 const qreal cy = spans->y + qreal(0.5);
5989 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5990 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5991 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5993 int length = spans->len;
5995 const int l = qMin(length, buffer_size);
5996 const SRC *end = buffer + l;
5999 const qreal iw = w == 0 ? 1 : 1 / w;
6000 const qreal tx = x * iw;
6001 const qreal ty = y * iw;
6003 const int px = int(tx) - (tx < 0);
6004 const int py = int(ty) - (ty < 0);
6006 if ((px < 0) || (px >= image_width) ||
6007 (py < 0) || (py >= image_height))
6011 *b = ((SRC*)data->texture.scanLine(py))[px];
6019 if (!SRC::hasAlpha() && coverage == 255) {
6020 qt_memconvert(dest, buffer, l);
6021 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6022 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6024 blendUntransformed_dest24(dest, buffer, coverage, l);
6025 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6026 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6027 blendUntransformed_dest16(dest, buffer, coverage, l);
6029 blendUntransformed_unaligned(dest, buffer, coverage, l);
6040 static void blend_transformed_rgb888(int count, const QSpan *spans,
6043 #if defined(QT_QWS_DEPTH_24)
6044 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6046 if (data->texture.format == QImage::Format_RGB888)
6047 blendTransformed<qrgb888, qrgb888>(count, spans, userData);
6050 blend_src_generic<RegularSpans>(count, spans, userData);
6053 static void blend_transformed_argb6666(int count, const QSpan *spans,
6056 #if defined(QT_QWS_DEPTH_18)
6057 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6059 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
6060 blendTransformed<qargb6666, qargb6666>(count, spans, userData);
6061 else if (data->texture.format == QImage::Format_RGB666)
6062 blendTransformed<qargb6666, qrgb666>(count, spans, userData);
6065 blend_src_generic<RegularSpans>(count, spans, userData);
6068 static void blend_transformed_rgb666(int count, const QSpan *spans,
6071 #if defined(QT_QWS_DEPTH_18)
6072 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6074 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
6075 blendTransformed<qrgb666, qargb6666>(count, spans, userData);
6076 else if (data->texture.format == QImage::Format_RGB666)
6077 blendTransformed<qrgb666, qrgb666>(count, spans, userData);
6080 blend_src_generic<RegularSpans>(count, spans, userData);
6083 static void blend_transformed_argb8565(int count, const QSpan *spans,
6086 #if defined(QT_QWS_DEPTH_16)
6087 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6089 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
6090 blendTransformed<qargb8565, qargb8565>(count, spans, userData);
6091 else if (data->texture.format == QImage::Format_RGB16)
6092 blendTransformed<qargb8565, qrgb565>(count, spans, userData);
6095 blend_src_generic<RegularSpans>(count, spans, userData);
6098 static void blend_transformed_rgb565(int count, const QSpan *spans,
6101 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
6102 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6104 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
6105 blendTransformed<qrgb565, qargb8565>(count, spans, userData);
6106 else if (data->texture.format == QImage::Format_RGB16)
6107 blendTransformed<qrgb565, qrgb565>(count, spans, userData);
6110 blend_src_generic<RegularSpans>(count, spans, userData);
6113 static void blend_transformed_argb8555(int count, const QSpan *spans,
6116 #if defined(QT_QWS_DEPTH_15)
6117 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6119 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
6120 blendTransformed<qargb8555, qargb8555>(count, spans, userData);
6121 else if (data->texture.format == QImage::Format_RGB555)
6122 blendTransformed<qargb8555, qrgb555>(count, spans, userData);
6125 blend_src_generic<RegularSpans>(count, spans, userData);
6128 static void blend_transformed_rgb555(int count, const QSpan *spans,
6131 #if defined(QT_QWS_DEPTH_15)
6132 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6134 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
6135 blendTransformed<qrgb555, qargb8555>(count, spans, userData);
6136 else if (data->texture.format == QImage::Format_RGB555)
6137 blendTransformed<qrgb555, qrgb555>(count, spans, userData);
6140 blend_src_generic<RegularSpans>(count, spans, userData);
6143 static void blend_transformed_argb4444(int count, const QSpan *spans,
6146 #if defined(QT_QWS_DEPTH_12)
6147 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6149 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
6150 blendTransformed<qargb4444, qargb4444>(count, spans, userData);
6151 else if (data->texture.format == QImage::Format_RGB444)
6152 blendTransformed<qargb4444, qrgb444>(count, spans, userData);
6155 blend_src_generic<RegularSpans>(count, spans, userData);
6158 static void blend_transformed_rgb444(int count, const QSpan *spans,
6161 #if defined(QT_QWS_DEPTH_12)
6162 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6164 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
6165 blendTransformed<qrgb444, qargb4444>(count, spans, userData);
6166 else if (data->texture.format == QImage::Format_RGB444)
6167 blendTransformed<qrgb444, qrgb444>(count, spans, userData);
6170 blend_src_generic<RegularSpans>(count, spans, userData);
6173 template <SpanMethod spanMethod>
6174 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QSpan *spans, void *userData)
6176 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6177 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
6178 && data->texture.format != QImage::Format_RGB32) {
6179 blend_src_generic<spanMethod>(count, spans, userData);
6183 CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
6184 uint buffer[buffer_size];
6186 int image_width = data->texture.width;
6187 int image_height = data->texture.height;
6188 const int scanline_offset = data->texture.bytesPerLine / 4;
6190 if (data->fast_matrix) {
6191 // The increment pr x in the scanline
6192 int fdx = (int)(data->m11 * fixed_scale);
6193 int fdy = (int)(data->m12 * fixed_scale);
6196 void *t = data->rasterBuffer->scanLine(spans->y);
6198 uint *target = ((uint *)t) + spans->x;
6199 uint *image_bits = (uint *)data->texture.imageData;
6201 const qreal cx = spans->x + qreal(0.5);
6202 const qreal cy = spans->y + qreal(0.5);
6204 int x = int((data->m21 * cy
6205 + data->m11 * cx + data->dx) * fixed_scale);
6206 int y = int((data->m22 * cy
6207 + data->m12 * cx + data->dy) * fixed_scale);
6209 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
6210 int length = spans->len;
6212 int l = qMin(length, buffer_size);
6213 const uint *end = buffer + l;
6220 if (px < 0) px += image_width;
6221 if (py < 0) py += image_height;
6222 int y_offset = py * scanline_offset;
6224 Q_ASSERT(px >= 0 && px < image_width);
6225 Q_ASSERT(py >= 0 && py < image_height);
6227 *b = image_bits[y_offset + px];
6232 if (spanMethod == RegularSpans)
6233 func(target, buffer, l, coverage);
6235 drawBufferSpan(data, buffer, buffer_size,
6236 spans->x + spans->len - length,
6237 spans->y, l, coverage);
6244 const qreal fdx = data->m11;
6245 const qreal fdy = data->m12;
6246 const qreal fdw = data->m13;
6248 void *t = data->rasterBuffer->scanLine(spans->y);
6250 uint *target = ((uint *)t) + spans->x;
6251 uint *image_bits = (uint *)data->texture.imageData;
6253 const qreal cx = spans->x + qreal(0.5);
6254 const qreal cy = spans->y + qreal(0.5);
6256 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
6257 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
6258 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
6260 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
6261 int length = spans->len;
6263 int l = qMin(length, buffer_size);
6264 const uint *end = buffer + l;
6267 const qreal iw = w == 0 ? 1 : 1 / w;
6268 const qreal tx = x * iw;
6269 const qreal ty = y * iw;
6270 int px = int(tx) - (tx < 0);
6271 int py = int(ty) - (ty < 0);
6275 if (px < 0) px += image_width;
6276 if (py < 0) py += image_height;
6277 int y_offset = py * scanline_offset;
6279 Q_ASSERT(px >= 0 && px < image_width);
6280 Q_ASSERT(py >= 0 && py < image_height);
6282 *b = image_bits[y_offset + px];
6286 //force increment to avoid /0
6292 if (spanMethod == RegularSpans)
6293 func(target, buffer, l, coverage);
6295 drawBufferSpan(data, buffer, buffer_size,
6296 spans->x + spans->len - length,
6297 spans->y, l, coverage);
6306 template <class DST, class SRC>
6307 Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *spans, void *userData)
6309 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
6310 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
6312 if (mode != QPainter::CompositionMode_SourceOver) {
6313 blend_src_generic<RegularSpans>(count, spans, userData);
6317 SRC buffer[buffer_size];
6318 const int image_width = data->texture.width;
6319 const int image_height = data->texture.height;
6321 if (data->fast_matrix) {
6322 // The increment pr x in the scanline
6323 const int fdx = (int)(data->m11 * fixed_scale);
6324 const int fdy = (int)(data->m12 * fixed_scale);
6327 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
6328 if (coverage == 0) {
6333 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
6335 const qreal cx = spans->x + qreal(0.5);
6336 const qreal cy = spans->y + qreal(0.5);
6337 int x = int((data->m21 * cy
6338 + data->m11 * cx + data->dx) * fixed_scale);
6339 int y = int((data->m22 * cy
6340 + data->m12 * cx + data->dy) * fixed_scale);
6341 int length = spans->len;
6344 const int l = qMin(length, buffer_size);
6346 const SRC *end = buffer + l;
6349 int px = (x >> 16) % image_width;
6350 int py = (y >> 16) % image_height;
6357 *b = ((SRC*)data->texture.scanLine(py))[px];
6364 if (!SRC::hasAlpha() && coverage == 255) {
6365 qt_memconvert(dest, buffer, l);
6366 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6367 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6369 blendUntransformed_dest24(dest, buffer, coverage, l);
6370 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6371 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6372 blendUntransformed_dest16(dest, buffer, coverage, l);
6374 blendUntransformed_unaligned(dest, buffer, coverage, l);
6383 const qreal fdx = data->m11;
6384 const qreal fdy = data->m12;
6385 const qreal fdw = data->m13;
6388 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
6389 if (coverage == 0) {
6394 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
6397 const qreal cx = spans->x + qreal(0.5);
6398 const qreal cy = spans->y + qreal(0.5);
6400 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
6401 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
6402 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
6404 int length = spans->len;
6406 const int l = qMin(length, buffer_size);
6407 const SRC *end = buffer + l;
6410 const qreal iw = w == 0 ? 1 : 1 / w;
6411 const qreal tx = x * iw;
6412 const qreal ty = y * iw;
6414 int px = int(tx) - (tx < 0);
6415 int py = int(ty) - (ty < 0);
6424 *b = ((SRC*)data->texture.scanLine(py))[px];
6430 // force increment to avoid /0
6434 if (!SRC::hasAlpha() && coverage == 255) {
6435 qt_memconvert(dest, buffer, l);
6436 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6437 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6439 blendUntransformed_dest24(dest, buffer, coverage, l);
6440 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6441 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6442 blendUntransformed_dest16(dest, buffer, coverage, l);
6444 blendUntransformed_unaligned(dest, buffer, coverage, l);
6455 static void blend_transformed_tiled_rgb888(int count, const QSpan *spans,
6458 #if defined(QT_QWS_DEPTH_24)
6459 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6461 if (data->texture.format == QImage::Format_RGB888)
6462 blendTransformedTiled<qrgb888, qrgb888>(count, spans, userData);
6465 blend_src_generic<RegularSpans>(count, spans, userData);
6468 static void blend_transformed_tiled_argb6666(int count, const QSpan *spans,
6471 #if defined(QT_QWS_DEPTH_18)
6472 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6474 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
6475 blendTransformedTiled<qargb6666, qargb6666>(count, spans, userData);
6476 else if (data->texture.format == QImage::Format_RGB666)
6477 blendTransformedTiled<qargb6666, qrgb666>(count, spans, userData);
6480 blend_src_generic<RegularSpans>(count, spans, userData);
6483 static void blend_transformed_tiled_rgb666(int count, const QSpan *spans,
6486 #if defined(QT_QWS_DEPTH_18)
6487 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6489 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
6490 blendTransformedTiled<qrgb666, qargb6666>(count, spans, userData);
6491 else if (data->texture.format == QImage::Format_RGB666)
6492 blendTransformedTiled<qrgb666, qrgb666>(count, spans, userData);
6495 blend_src_generic<RegularSpans>(count, spans, userData);
6498 static void blend_transformed_tiled_argb8565(int count, const QSpan *spans,
6501 #if defined(QT_QWS_DEPTH_16)
6502 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6504 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
6505 blendTransformedTiled<qargb8565, qargb8565>(count, spans, userData);
6506 else if (data->texture.format == QImage::Format_RGB16)
6507 blendTransformedTiled<qargb8565, qrgb565>(count, spans, userData);
6510 blend_src_generic<RegularSpans>(count, spans, userData);
6513 static void blend_transformed_tiled_rgb565(int count, const QSpan *spans,
6516 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
6517 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6519 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
6520 blendTransformedTiled<qrgb565, qargb8565>(count, spans, userData);
6521 else if (data->texture.format == QImage::Format_RGB16)
6522 blendTransformedTiled<qrgb565, qrgb565>(count, spans, userData);
6525 blend_src_generic<RegularSpans>(count, spans, userData);
6528 static void blend_transformed_tiled_argb8555(int count, const QSpan *spans,
6531 #if defined(QT_QWS_DEPTH_15)
6532 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6534 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
6535 blendTransformedTiled<qargb8555, qargb8555>(count, spans, userData);
6536 else if (data->texture.format == QImage::Format_RGB555)
6537 blendTransformedTiled<qargb8555, qrgb555>(count, spans, userData);
6540 blend_src_generic<RegularSpans>(count, spans, userData);
6543 static void blend_transformed_tiled_rgb555(int count, const QSpan *spans,
6546 #if defined(QT_QWS_DEPTH_15)
6547 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6549 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
6550 blendTransformedTiled<qrgb555, qargb8555>(count, spans, userData);
6551 else if (data->texture.format == QImage::Format_RGB555)
6552 blendTransformedTiled<qrgb555, qrgb555>(count, spans, userData);
6555 blend_src_generic<RegularSpans>(count, spans, userData);
6558 static void blend_transformed_tiled_argb4444(int count, const QSpan *spans,
6561 #if defined(QT_QWS_DEPTH_12)
6562 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6564 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
6565 blendTransformedTiled<qargb4444, qargb4444>(count, spans, userData);
6566 else if (data->texture.format == QImage::Format_RGB444)
6567 blendTransformedTiled<qargb4444, qrgb444>(count, spans, userData);
6570 blend_src_generic<RegularSpans>(count, spans, userData);
6573 static void blend_transformed_tiled_rgb444(int count, const QSpan *spans,
6576 #if defined(QT_QWS_DEPTH_12)
6577 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6579 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
6580 blendTransformedTiled<qrgb444, qargb4444>(count, spans, userData);
6581 else if (data->texture.format == QImage::Format_RGB444)
6582 blendTransformedTiled<qrgb444, qrgb444>(count, spans, userData);
6585 blend_src_generic<RegularSpans>(count, spans, userData);
6588 # define SPANFUNC_POINTER(Name, Arg) Name<Arg>
6591 /* Image formats here are target formats */
6592 static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats] = {
6596 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Mono
6597 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // MonoLsb
6598 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Indexed8
6599 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // RGB32
6600 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // ARGB32
6601 SPANFUNC_POINTER(blend_untransformed_argb, RegularSpans), // ARGB32_Premultiplied
6602 blend_untransformed_rgb565,
6603 blend_untransformed_argb8565,
6604 blend_untransformed_rgb666,
6605 blend_untransformed_argb6666,
6606 blend_untransformed_rgb555,
6607 blend_untransformed_argb8555,
6608 blend_untransformed_rgb888,
6609 blend_untransformed_rgb444,
6610 blend_untransformed_argb4444,
6615 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Mono
6616 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // MonoLsb
6617 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Indexed8
6618 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // RGB32
6619 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // ARGB32
6620 SPANFUNC_POINTER(blend_tiled_argb, RegularSpans), // ARGB32_Premultiplied
6622 blend_tiled_argb8565,
6624 blend_tiled_argb6666,
6626 blend_tiled_argb8555,
6629 blend_tiled_argb4444,
6634 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6635 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6636 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6637 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6638 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6639 SPANFUNC_POINTER(blend_transformed_argb, RegularSpans), // ARGB32_Premultiplied
6640 blend_transformed_rgb565,
6641 blend_transformed_argb8565,
6642 blend_transformed_rgb666,
6643 blend_transformed_argb6666,
6644 blend_transformed_rgb555,
6645 blend_transformed_argb8555,
6646 blend_transformed_rgb888,
6647 blend_transformed_rgb444,
6648 blend_transformed_argb4444,
6653 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6654 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6655 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6656 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6657 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6658 SPANFUNC_POINTER(blend_transformed_tiled_argb, RegularSpans), // ARGB32_Premultiplied
6659 blend_transformed_tiled_rgb565,
6660 blend_transformed_tiled_argb8565,
6661 blend_transformed_tiled_rgb666,
6662 blend_transformed_tiled_argb6666,
6663 blend_transformed_tiled_rgb555,
6664 blend_transformed_tiled_argb8555,
6665 blend_transformed_tiled_rgb888,
6666 blend_transformed_tiled_rgb444,
6667 blend_transformed_tiled_argb4444
6672 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6673 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6674 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6675 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6676 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6677 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
6678 blend_transformed_bilinear_rgb565,
6679 blend_transformed_bilinear_argb8565,
6680 blend_transformed_bilinear_rgb666,
6681 blend_transformed_bilinear_argb6666,
6682 blend_transformed_bilinear_rgb555,
6683 blend_transformed_bilinear_argb8555,
6684 blend_transformed_bilinear_rgb888,
6685 blend_transformed_bilinear_rgb444,
6686 blend_transformed_bilinear_argb4444,
6691 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6692 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6693 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6694 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6695 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6696 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
6697 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB16
6698 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8565_Premultiplied
6699 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB666
6700 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB6666_Premultiplied
6701 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB555
6702 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8555_Premultiplied
6703 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB888
6704 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB444
6705 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB4444_Premultiplied
6709 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
6710 static const ProcessSpans processTextureSpansCallback[NBlendTypes][QImage::NImageFormats] = {
6714 blend_untransformed_generic<CallbackSpans>, // Mono
6715 blend_untransformed_generic<CallbackSpans>, // MonoLsb
6716 blend_untransformed_generic<CallbackSpans>, // Indexed8
6717 blend_untransformed_generic<CallbackSpans>, // RGB32
6718 blend_untransformed_generic<CallbackSpans>, // ARGB32
6719 blend_untransformed_argb<CallbackSpans>, // ARGB32_Premultiplied
6720 blend_untransformed_generic<CallbackSpans>, // RGB16
6721 blend_untransformed_generic<CallbackSpans>, // ARGB8565_Premultiplied
6722 blend_untransformed_generic<CallbackSpans>, // RGB666
6723 blend_untransformed_generic<CallbackSpans>, // ARGB6666_Premultiplied
6724 blend_untransformed_generic<CallbackSpans>, // RGB555
6725 blend_untransformed_generic<CallbackSpans>, // ARGB8555_Premultiplied
6726 blend_untransformed_generic<CallbackSpans>, // RGB888
6727 blend_untransformed_generic<CallbackSpans>, // RGB444
6728 blend_untransformed_generic<CallbackSpans> // ARGB4444_Premultiplied
6733 blend_tiled_generic<CallbackSpans>, // Mono
6734 blend_tiled_generic<CallbackSpans>, // MonoLsb
6735 blend_tiled_generic<CallbackSpans>, // Indexed8
6736 blend_tiled_generic<CallbackSpans>, // RGB32
6737 blend_tiled_generic<CallbackSpans>, // ARGB32
6738 blend_tiled_argb<CallbackSpans>, // ARGB32_Premultiplied
6739 blend_tiled_generic<CallbackSpans>, // RGB16
6740 blend_tiled_generic<CallbackSpans>, // ARGB8565_Premultiplied
6741 blend_tiled_generic<CallbackSpans>, // RGB666
6742 blend_tiled_generic<CallbackSpans>, // ARGB6666_Premultiplied
6743 blend_tiled_generic<CallbackSpans>, // RGB555
6744 blend_tiled_generic<CallbackSpans>, // ARGB8555_Premultiplied
6745 blend_tiled_generic<CallbackSpans>, // RGB888
6746 blend_tiled_generic<CallbackSpans>, // RGB444
6747 blend_tiled_generic<CallbackSpans> // ARGB4444_Premultiplied
6752 blend_src_generic<CallbackSpans>, // Mono
6753 blend_src_generic<CallbackSpans>, // MonoLsb
6754 blend_src_generic<CallbackSpans>, // Indexed8
6755 blend_src_generic<CallbackSpans>, // RGB32
6756 blend_src_generic<CallbackSpans>, // ARGB32
6757 blend_transformed_argb<CallbackSpans>, // ARGB32_Premultiplied
6758 blend_src_generic<CallbackSpans>, // RGB16
6759 blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6760 blend_src_generic<CallbackSpans>, // RGB666
6761 blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6762 blend_src_generic<CallbackSpans>, // RGB555
6763 blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6764 blend_src_generic<CallbackSpans>, // RGB888
6765 blend_src_generic<CallbackSpans>, // RGB444
6766 blend_src_generic<CallbackSpans>, // ARGB4444_Premultiplied
6771 blend_src_generic<CallbackSpans>, // Mono
6772 blend_src_generic<CallbackSpans>, // MonoLsb
6773 blend_src_generic<CallbackSpans>, // Indexed8
6774 blend_src_generic<CallbackSpans>, // RGB32
6775 blend_src_generic<CallbackSpans>, // ARGB32
6776 blend_transformed_tiled_argb<CallbackSpans>, // ARGB32_Premultiplied
6777 blend_src_generic<CallbackSpans>, // RGB16
6778 blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6779 blend_src_generic<CallbackSpans>, // RGB666
6780 blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6781 blend_src_generic<CallbackSpans>, // RGB555
6782 blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6783 blend_src_generic<CallbackSpans>, // RGB888
6784 blend_src_generic<CallbackSpans>, // RGB444
6785 blend_src_generic<CallbackSpans> // ARGB4444_Premultiplied
6790 blend_src_generic<CallbackSpans>, // Mono
6791 blend_src_generic<CallbackSpans>, // MonoLsb
6792 blend_src_generic<CallbackSpans>, // Indexed8
6793 blend_src_generic<CallbackSpans>, // RGB32
6794 blend_src_generic<CallbackSpans>, // ARGB32
6795 blend_src_generic<CallbackSpans>, // ARGB32_Premultiplied
6796 blend_src_generic<CallbackSpans>, // RGB16
6797 blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6798 blend_src_generic<CallbackSpans>, // RGB666
6799 blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6800 blend_src_generic<CallbackSpans>, // RGB555
6801 blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6802 blend_src_generic<CallbackSpans>, // RGB888
6803 blend_src_generic<CallbackSpans>, // RGB444
6804 blend_src_generic<CallbackSpans> // ARGB4444_Premultiplied
6809 blend_src_generic<CallbackSpans>, // Mono
6810 blend_src_generic<CallbackSpans>, // MonoLsb
6811 blend_src_generic<CallbackSpans>, // Indexed8
6812 blend_src_generic<CallbackSpans>, // RGB32
6813 blend_src_generic<CallbackSpans>, // ARGB32
6814 blend_src_generic<CallbackSpans>, // ARGB32_Premultiplied
6815 blend_src_generic<CallbackSpans>, // RGB16
6816 blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6817 blend_src_generic<CallbackSpans>, // RGB666
6818 blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6819 blend_src_generic<CallbackSpans>, // RGB555
6820 blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6821 blend_src_generic<CallbackSpans>, // RGB888
6822 blend_src_generic<CallbackSpans>, // RGB444
6823 blend_src_generic<CallbackSpans> // ARGB4444_Premultiplied
6826 #endif // QT_NO_RASTERCALLBACKS
6828 void qBlendTexture(int count, const QSpan *spans, void *userData)
6830 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6831 ProcessSpans proc = processTextureSpans[getBlendType(data)][data->rasterBuffer->format];
6832 proc(count, spans, userData);
6835 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
6836 void qBlendTextureCallback(int count, const QSpan *spans, void *userData)
6838 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6839 ProcessSpans proc = processTextureSpansCallback[getBlendType(data)][data->rasterBuffer->format];
6840 proc(count, spans, userData);
6842 #endif // QT_NO_RASTERCALLBACKS
6844 template <class DST>
6845 inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
6846 int x, int y, quint32 color,
6848 int mapWidth, int mapHeight, int mapStride,
6852 const DST c = qt_colorConvert<DST, quint32>(color, 0);
6853 DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
6854 const int destStride = rasterBuffer->bytesPerLine() / sizeof(DST);
6857 while (mapHeight--) {
6860 for (int x = 0; x < mapWidth; x += 8) {
6861 uchar s = map[x >> 3];
6862 for (int i = 0; i < 8; ++i) {
6867 qt_memfill(dest + x0, c, n);
6882 qt_memfill(dest + x0, c, n);
6887 while (mapHeight--) {
6890 for (uchar s = *map; s; s <<= 1) {
6894 qt_memfill(dest + x0, c, n);
6902 qt_memfill(dest + x0, c, n);
6909 static void qt_gradient_quint32(int count, const QSpan *spans, void *userData)
6911 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6913 bool isVerticalGradient =
6914 data->txop <= QTransform::TxScale &&
6915 data->type == QSpanData::LinearGradient &&
6916 data->gradient.linear.end.x == data->gradient.linear.origin.x;
6918 if (isVerticalGradient) {
6919 LinearGradientValues linear;
6920 getLinearGradientValues(&linear, data);
6922 CompositionFunctionSolid funcSolid =
6923 functionForModeSolid[data->rasterBuffer->compositionMode];
6926 The logic for vertical gradient calculations is a mathematically
6927 reduced copy of that in fetchLinearGradient() - which is basically:
6929 qreal ry = data->m22 * (y + 0.5) + data->dy;
6930 qreal t = linear.dy*ry + linear.off;
6931 t *= (GRADIENT_STOPTABLE_SIZE - 1);
6933 qt_gradient_pixel_fixed(&data->gradient,
6934 int(t * FIXPT_SIZE));
6936 This has then been converted to fixed point to improve performance.
6938 const int gss = GRADIENT_STOPTABLE_SIZE - 1;
6939 int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
6940 int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
6946 quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x;
6948 qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
6950 funcSolid(dst, spans->len, color, spans->coverage);
6955 blend_src_generic<RegularSpans>(count, spans, userData);
6959 static void qt_gradient_quint16(int count, const QSpan *spans, void *userData)
6961 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6963 bool isVerticalGradient =
6964 data->txop <= QTransform::TxScale &&
6965 data->type == QSpanData::LinearGradient &&
6966 data->gradient.linear.end.x == data->gradient.linear.origin.x;
6968 if (isVerticalGradient) {
6970 LinearGradientValues linear;
6971 getLinearGradientValues(&linear, data);
6974 The logic for vertical gradient calculations is a mathematically
6975 reduced copy of that in fetchLinearGradient() - which is basically:
6977 qreal ry = data->m22 * (y + 0.5) + data->dy;
6978 qreal t = linear.dy*ry + linear.off;
6979 t *= (GRADIENT_STOPTABLE_SIZE - 1);
6981 qt_gradient_pixel_fixed(&data->gradient,
6982 int(t * FIXPT_SIZE));
6984 This has then been converted to fixed point to improve performance.
6986 const int gss = GRADIENT_STOPTABLE_SIZE - 1;
6987 int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
6988 int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
6990 uint oldColor = data->solid.color;
6994 quint32 color = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
6996 data->solid.color = color;
6997 blend_color_rgb16(1, spans, userData);
7000 data->solid.color = oldColor;
7003 blend_src_generic<RegularSpans>(count, spans, userData);
7007 inline static void qt_bitmapblit_quint32(QRasterBuffer *rasterBuffer,
7008 int x, int y, quint32 color,
7010 int mapWidth, int mapHeight, int mapStride)
7012 qt_bitmapblit_template<quint32>(rasterBuffer, x, y, color,
7013 map, mapWidth, mapHeight, mapStride);
7016 inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
7017 int x, int y, quint32 color,
7019 int mapWidth, int mapHeight, int mapStride)
7021 qt_bitmapblit_template<quint16>(rasterBuffer, x, y, color,
7022 map, mapWidth, mapHeight, mapStride);
7026 uchar qt_pow_rgb_gamma[256];
7027 uchar qt_pow_rgb_invgamma[256];
7029 uint qt_pow_gamma[256];
7030 uchar qt_pow_invgamma[2048];
7032 static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
7033 int x, int y, quint32 color,
7035 int mapWidth, int mapHeight, int mapStride,
7038 const quint16 c = qt_colorConvert<quint16, quint32>(color, 0);
7039 quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
7040 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
7042 while (mapHeight--) {
7043 for (int i = 0; i < mapWidth; ++i) {
7044 const int coverage = map[i];
7046 if (coverage == 0) {
7048 } else if (coverage == 255) {
7051 int ialpha = 255 - coverage;
7052 dest[i] = BYTE_MUL_RGB16(c, coverage)
7053 + BYTE_MUL_RGB16(dest[i], ialpha);
7061 void qt_build_pow_tables() {
7062 qreal smoothing = qreal(1.7);
7065 // decided by testing a few things on an iMac, should probably get this from the
7067 smoothing = qreal(2.0);
7071 extern qreal qt_fontsmoothing_gamma; // qapplication_win.cpp
7072 smoothing = qt_fontsmoothing_gamma;
7076 Q_UNUSED(smoothing);
7077 for (int i=0; i<256; ++i) {
7078 qt_pow_rgb_gamma[i] = uchar(i);
7079 qt_pow_rgb_invgamma[i] = uchar(i);
7082 for (int i=0; i<256; ++i) {
7083 qt_pow_rgb_gamma[i] = uchar(qRound(qPow(i / qreal(255.0), smoothing) * 255));
7084 qt_pow_rgb_invgamma[i] = uchar(qRound(qPow(i / qreal(255.), 1 / smoothing) * 255));
7088 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7089 const qreal gray_gamma = 2.31;
7090 for (int i=0; i<256; ++i)
7091 qt_pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047));
7092 for (int i=0; i<2048; ++i)
7093 qt_pow_invgamma[i] = uchar(qRound(qPow(i / qreal(2047.0), 1 / gray_gamma) * 255));
7097 static inline void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
7099 // Do a gray alphablend...
7100 int da = qAlpha(*dst);
7101 int dr = qRed(*dst);
7102 int dg = qGreen(*dst);
7103 int db = qBlue(*dst);
7106 #if defined (Q_WS_WIN)
7107 // Work around GDI messing up alpha channel
7108 && qRed(*dst) <= da && qBlue(*dst) <= da && qGreen(*dst) <= da
7112 int a = qGray(coverage);
7113 sr = qt_div_255(qt_pow_rgb_invgamma[sr] * a);
7114 sg = qt_div_255(qt_pow_rgb_invgamma[sg] * a);
7115 sb = qt_div_255(qt_pow_rgb_invgamma[sb] * a);
7118 dr = qt_div_255(dr * ia);
7119 dg = qt_div_255(dg * ia);
7120 db = qt_div_255(db * ia);
7122 *dst = ((a + qt_div_255((255 - a) * da)) << 24)
7129 int mr = qRed(coverage);
7130 int mg = qGreen(coverage);
7131 int mb = qBlue(coverage);
7133 dr = qt_pow_rgb_gamma[dr];
7134 dg = qt_pow_rgb_gamma[dg];
7135 db = qt_pow_rgb_gamma[db];
7137 int nr = qt_div_255((sr - dr) * mr) + dr;
7138 int ng = qt_div_255((sg - dg) * mg) + dg;
7139 int nb = qt_div_255((sb - db) * mb) + db;
7141 nr = qt_pow_rgb_invgamma[nr];
7142 ng = qt_pow_rgb_invgamma[ng];
7143 nb = qt_pow_rgb_invgamma[nb];
7145 *dst = qRgb(nr, ng, nb);
7148 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7149 static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
7151 // Do a gammacorrected gray alphablend...
7152 int dr = qRed(*dst);
7153 int dg = qGreen(*dst);
7154 int db = qBlue(*dst);
7156 dr = qt_pow_gamma[dr];
7157 dg = qt_pow_gamma[dg];
7158 db = qt_pow_gamma[db];
7160 int alpha = coverage;
7161 int ialpha = 255 - alpha;
7162 int nr = (sr * alpha + ialpha * dr) / 255;
7163 int ng = (sg * alpha + ialpha * dg) / 255;
7164 int nb = (sb * alpha + ialpha * db) / 255;
7166 nr = qt_pow_invgamma[nr];
7167 ng = qt_pow_invgamma[ng];
7168 nb = qt_pow_invgamma[nb];
7170 *dst = qRgb(nr, ng, nb);
7174 static void qt_alphamapblit_quint32(QRasterBuffer *rasterBuffer,
7175 int x, int y, quint32 color,
7177 int mapWidth, int mapHeight, int mapStride,
7178 const QClipData *clip)
7180 const quint32 c = color;
7181 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
7183 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7184 int sr = qRed(color);
7185 int sg = qGreen(color);
7186 int sb = qBlue(color);
7188 sr = qt_pow_gamma[sr];
7189 sg = qt_pow_gamma[sg];
7190 sb = qt_pow_gamma[sb];
7191 bool opaque_src = (qAlpha(color) == 255);
7195 quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
7196 while (mapHeight--) {
7197 for (int i = 0; i < mapWidth; ++i) {
7198 const int coverage = map[i];
7200 if (coverage == 0) {
7202 } else if (coverage == 255) {
7205 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7206 if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
7207 && qAlpha(dest[i]) == 255) {
7208 grayBlendPixel(dest+i, coverage, sr, sg, sb);
7212 int ialpha = 255 - coverage;
7213 dest[i] = INTERPOLATE_PIXEL_255(c, coverage, dest[i], ialpha);
7221 int bottom = qMin(y + mapHeight, rasterBuffer->height());
7223 int top = qMax(y, 0);
7224 map += (top - y) * mapStride;
7226 const_cast<QClipData *>(clip)->initialize();
7227 for (int yp = top; yp<bottom; ++yp) {
7228 const QClipData::ClipLine &line = clip->m_clipLines[yp];
7230 quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
7232 for (int i=0; i<line.count; ++i) {
7233 const QSpan &clip = line.spans[i];
7235 int start = qMax<int>(x, clip.x);
7236 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
7238 for (int xp=start; xp<end; ++xp) {
7239 const int coverage = map[xp - x];
7241 if (coverage == 0) {
7243 } else if (coverage == 255) {
7246 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7247 if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
7248 && qAlpha(dest[xp]) == 255) {
7249 grayBlendPixel(dest+xp, coverage, sr, sg, sb);
7253 int ialpha = 255 - coverage;
7254 dest[xp] = INTERPOLATE_PIXEL_255(c, coverage, dest[xp], ialpha);
7258 } // for (i -> line.count)
7259 } // for (yp -> bottom)
7265 static void qt_alphargbblit_quint32(QRasterBuffer *rasterBuffer,
7266 int x, int y, quint32 color,
7267 const uint *src, int mapWidth, int mapHeight, int srcStride,
7268 const QClipData *clip)
7270 const quint32 c = color;
7272 int sr = qRed(color);
7273 int sg = qGreen(color);
7274 int sb = qBlue(color);
7275 int sa = qAlpha(color);
7277 sr = qt_pow_rgb_gamma[sr];
7278 sg = qt_pow_rgb_gamma[sg];
7279 sb = qt_pow_rgb_gamma[sb];
7285 quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
7286 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
7287 while (mapHeight--) {
7288 for (int i = 0; i < mapWidth; ++i) {
7289 const uint coverage = src[i];
7290 if (coverage == 0xffffffff) {
7292 } else if (coverage != 0xff000000) {
7293 rgbBlendPixel(dst+i, coverage, sr, sg, sb);
7301 int bottom = qMin(y + mapHeight, rasterBuffer->height());
7303 int top = qMax(y, 0);
7304 src += (top - y) * srcStride;
7306 const_cast<QClipData *>(clip)->initialize();
7307 for (int yp = top; yp<bottom; ++yp) {
7308 const QClipData::ClipLine &line = clip->m_clipLines[yp];
7310 quint32 *dst = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
7312 for (int i=0; i<line.count; ++i) {
7313 const QSpan &clip = line.spans[i];
7315 int start = qMax<int>(x, clip.x);
7316 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
7318 for (int xp=start; xp<end; ++xp) {
7319 const uint coverage = src[xp - x];
7320 if (coverage == 0xffffffff) {
7322 } else if (coverage != 0xff000000) {
7323 rgbBlendPixel(dst+xp, coverage, sr, sg, sb);
7326 } // for (i -> line.count)
7328 } // for (yp -> bottom)
7334 inline void qt_rectfill_template(QRasterBuffer *rasterBuffer,
7335 int x, int y, int width, int height,
7336 quint32 color, T dummy = 0)
7340 qt_rectfill<T>(reinterpret_cast<T*>(rasterBuffer->buffer()),
7341 qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0),
7342 x, y, width, height, rasterBuffer->bytesPerLine());
7345 #define QT_RECTFILL(T) \
7346 inline static void qt_rectfill_##T(QRasterBuffer *rasterBuffer, \
7347 int x, int y, int width, int height, \
7350 qt_rectfill_template<T>(rasterBuffer, x, y, width, height, color); \
7353 QT_RECTFILL(quint32)
7354 QT_RECTFILL(quint16)
7355 QT_RECTFILL(qargb8565)
7356 QT_RECTFILL(qrgb666)
7357 QT_RECTFILL(qargb6666)
7358 QT_RECTFILL(qrgb555)
7359 QT_RECTFILL(qargb8555)
7360 QT_RECTFILL(qrgb888)
7361 QT_RECTFILL(qrgb444)
7362 QT_RECTFILL(qargb4444)
7365 inline static void qt_rectfill_nonpremul_quint32(QRasterBuffer *rasterBuffer,
7366 int x, int y, int width, int height,
7369 qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
7370 INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine());
7374 // Map table for destination image format. Contains function pointers
7375 // for blends of various types unto the destination
7377 DrawHelper qDrawHelper[QImage::NImageFormats] =
7380 { 0, 0, 0, 0, 0, 0 },
7383 blend_color_generic,
7384 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7389 blend_color_generic,
7390 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7395 blend_color_generic,
7396 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7402 qt_gradient_quint32,
7403 qt_bitmapblit_quint32,
7404 qt_alphamapblit_quint32,
7405 qt_alphargbblit_quint32,
7410 blend_color_generic,
7411 qt_gradient_quint32,
7412 qt_bitmapblit_quint32,
7413 qt_alphamapblit_quint32,
7414 qt_alphargbblit_quint32,
7415 qt_rectfill_nonpremul_quint32
7417 // Format_ARGB32_Premultiplied
7420 qt_gradient_quint32,
7421 qt_bitmapblit_quint32,
7422 qt_alphamapblit_quint32,
7423 qt_alphargbblit_quint32,
7429 qt_gradient_quint16,
7430 qt_bitmapblit_quint16,
7431 qt_alphamapblit_quint16,
7435 // Format_ARGB8565_Premultiplied
7437 SPANFUNC_POINTER_BLENDCOLOR(qargb8565),
7438 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7440 qt_rectfill_qargb8565
7444 SPANFUNC_POINTER_BLENDCOLOR(qrgb666),
7445 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7449 // Format_ARGB6666_Premultiplied
7451 SPANFUNC_POINTER_BLENDCOLOR(qargb6666),
7452 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7454 qt_rectfill_qargb6666
7458 SPANFUNC_POINTER_BLENDCOLOR(qrgb555),
7459 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7463 // Format_ARGB8555_Premultiplied
7465 SPANFUNC_POINTER_BLENDCOLOR(qargb8555),
7466 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7468 qt_rectfill_qargb8555
7472 SPANFUNC_POINTER_BLENDCOLOR(qrgb888),
7473 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7479 SPANFUNC_POINTER_BLENDCOLOR(qrgb444),
7480 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7484 // Format_ARGB4444_Premultiplied
7486 SPANFUNC_POINTER_BLENDCOLOR(qargb4444),
7487 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7489 qt_rectfill_qargb4444
7493 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
7494 DrawHelper qDrawHelperCallback[QImage::NImageFormats] =
7497 { 0, 0, 0, 0, 0, 0 },
7500 blend_color_generic_callback,
7501 blend_src_generic<CallbackSpans>,
7506 blend_color_generic_callback,
7507 blend_src_generic<CallbackSpans>,
7512 blend_color_generic_callback,
7513 blend_src_generic<CallbackSpans>,
7518 blend_color_generic_callback,
7519 blend_src_generic<CallbackSpans>,
7524 blend_color_generic_callback,
7525 blend_src_generic<CallbackSpans>,
7528 // Format_ARGB32_Premultiplied
7530 blend_color_generic_callback,
7531 blend_src_generic<CallbackSpans>,
7536 blend_color_generic_callback,
7537 blend_src_generic<CallbackSpans>,
7540 // Format_ARGB8565_Premultiplied
7542 blend_color_generic_callback,
7543 blend_src_generic<CallbackSpans>,
7548 blend_color_generic_callback,
7549 blend_src_generic<CallbackSpans>,
7552 // Format_ARGB6666_Premultiplied
7554 blend_color_generic_callback,
7555 blend_src_generic<CallbackSpans>,
7560 blend_color_generic_callback,
7561 blend_src_generic<CallbackSpans>,
7564 // Format_ARGB8555_Premultiplied
7566 blend_color_generic_callback,
7567 blend_src_generic<CallbackSpans>,
7572 blend_color_generic_callback,
7573 blend_src_generic<CallbackSpans>,
7578 blend_color_generic_callback,
7579 blend_src_generic<CallbackSpans>,
7582 // Format_ARGB4444_Premultiplied
7584 blend_color_generic_callback,
7585 blend_src_generic<CallbackSpans>,
7593 #if defined(Q_CC_MSVC) && !defined(_MIPS_)
7594 template <class DST, class SRC>
7595 inline void qt_memfill_template(DST *dest, SRC color, int count)
7597 const DST c = qt_colorConvert<DST, SRC>(color, 0);
7604 template <class DST, class SRC>
7605 inline void qt_memfill_template(DST *dest, SRC color, int count)
7607 const DST c = qt_colorConvert<DST, SRC>(color, 0);
7608 int n = (count + 7) / 8;
7609 switch (count & 0x07)
7611 case 0: do { *dest++ = c;
7612 case 7: *dest++ = c;
7613 case 6: *dest++ = c;
7614 case 5: *dest++ = c;
7615 case 4: *dest++ = c;
7616 case 3: *dest++ = c;
7617 case 2: *dest++ = c;
7618 case 1: *dest++ = c;
7624 inline void qt_memfill_template(quint16 *dest, quint16 value, int count)
7628 case 2: *dest++ = value;
7629 case 1: *dest = value;
7634 const int align = (quintptr)(dest) & 0x3;
7636 case 2: *dest++ = value; --count;
7639 const quint32 value32 = (value << 16) | value;
7640 qt_memfill(reinterpret_cast<quint32*>(dest), value32, count / 2);
7642 dest[count - 1] = value;
7646 static void qt_memfill_quint16(quint16 *dest, quint16 color, int count)
7648 qt_memfill_template<quint16, quint16>(dest, color, count);
7651 typedef void (*qt_memfill32_func)(quint32 *dest, quint32 value, int count);
7652 typedef void (*qt_memfill16_func)(quint16 *dest, quint16 value, int count);
7653 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count);
7654 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count);
7656 qt_memfill32_func qt_memfill32 = qt_memfill32_setup;
7657 qt_memfill16_func qt_memfill16 = qt_memfill16_setup;
7659 void qInitDrawhelperAsm()
7662 qt_memfill32 = qt_memfill_template<quint32, quint32>;
7663 qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16, quint16>;
7665 CompositionFunction *functionForModeAsm = 0;
7666 CompositionFunctionSolid *functionForModeSolidAsm = 0;
7668 const uint features = qDetectCPUFeatures();
7671 } else if (features & SSE2) {
7672 qt_memfill32 = qt_memfill32_sse2;
7673 qt_memfill16 = qt_memfill16_sse2;
7674 qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2;
7675 qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2;
7676 qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2;
7677 qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2;
7680 } else if (features & SSE) {
7681 // qt_memfill32 = qt_memfill32_sse;
7682 qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse;
7683 #ifdef QT_HAVE_3DNOW
7684 if (features & MMX3DNOW) {
7685 qt_memfill32 = qt_memfill32_sse3dnow;
7686 qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse3dnow;
7692 if (features & MMX) {
7693 functionForModeAsm = qt_functionForMode_MMX;
7695 functionForModeSolidAsm = qt_functionForModeSolid_MMX;
7696 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx;
7697 #ifdef QT_HAVE_3DNOW
7698 if (features & MMX3DNOW) {
7699 functionForModeAsm = qt_functionForMode_MMX3DNOW;
7700 functionForModeSolidAsm = qt_functionForModeSolid_MMX3DNOW;
7701 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx3dnow;
7705 extern void qt_blend_rgb32_on_rgb32_mmx(uchar *destPixels, int dbpl,
7706 const uchar *srcPixels, int sbpl,
7709 extern void qt_blend_argb32_on_argb32_mmx(uchar *destPixels, int dbpl,
7710 const uchar *srcPixels, int sbpl,
7714 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mmx;
7715 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mmx;
7716 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mmx;
7717 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mmx;
7723 if (features & SSE) {
7724 extern void qt_blend_rgb32_on_rgb32_sse(uchar *destPixels, int dbpl,
7725 const uchar *srcPixels, int sbpl,
7728 extern void qt_blend_argb32_on_argb32_sse(uchar *destPixels, int dbpl,
7729 const uchar *srcPixels, int sbpl,
7733 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
7734 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
7735 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
7736 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
7741 if (features & SSE2) {
7742 extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
7743 const uchar *srcPixels, int sbpl,
7746 extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
7747 const uchar *srcPixels, int sbpl,
7751 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
7752 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
7753 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
7754 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
7756 extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
7757 int y, int x, int length);
7759 qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2;
7762 #ifdef QT_HAVE_SSSE3
7763 if (features & SSSE3) {
7764 extern void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
7765 const uchar *srcPixels, int sbpl,
7769 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
7770 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
7777 if (features & SSE) {
7778 functionForModeAsm = qt_functionForMode_SSE;
7779 functionForModeSolidAsm = qt_functionForModeSolid_SSE;
7780 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse;
7781 #ifdef QT_HAVE_3DNOW
7782 if (features & MMX3DNOW) {
7783 functionForModeAsm = qt_functionForMode_SSE3DNOW;
7784 functionForModeSolidAsm = qt_functionForModeSolid_SSE3DNOW;
7785 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse3dnow;
7791 if (features & SSE2) {
7792 extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels,
7793 const uint *srcPixels,
7796 extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha);
7797 extern void QT_FASTCALL comp_func_Plus_sse2(uint *dst, const uint *src, int length, uint const_alpha);
7798 extern void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, uint const_alpha);
7800 functionForModeAsm[0] = comp_func_SourceOver_sse2;
7801 functionForModeAsm[QPainter::CompositionMode_Source] = comp_func_Source_sse2;
7802 functionForModeAsm[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2;
7803 functionForModeSolidAsm[0] = comp_func_solid_SourceOver_sse2;
7807 #elif defined(QT_HAVE_SSE2)
7808 // this is the special case when SSE2 is usable but MMX/SSE is not usable (e.g.: Windows x64 + visual studio)
7809 if (features & SSE2) {
7810 functionForModeAsm = qt_functionForMode_onlySSE2;
7811 functionForModeSolidAsm = qt_functionForModeSolid_onlySSE2;
7815 #ifdef QT_HAVE_IWMMXT
7816 if (features & IWMMXT) {
7817 functionForModeAsm = qt_functionForMode_IWMMXT;
7818 functionForModeSolidAsm = qt_functionForModeSolid_IWMMXT;
7819 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_iwmmxt;
7823 #if defined(QT_HAVE_ARM_SIMD)
7824 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_arm_simd;
7825 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_arm_simd;
7826 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_arm_simd;
7827 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_arm_simd;
7828 #elif defined(QT_HAVE_NEON)
7829 if (features & NEON) {
7830 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
7831 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
7832 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7833 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7834 qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon;
7835 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon;
7836 qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon;
7838 qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon;
7839 qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon;
7841 qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon;
7842 qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon;
7844 qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon;
7846 functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon;
7847 functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon;
7848 functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon;
7849 destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
7850 destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
7852 qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
7853 qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
7854 qt_memfill32 = qt_memfill32_neon;
7856 extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data,
7857 int y, int x, int length);
7859 qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon;
7863 if (functionForModeSolidAsm) {
7864 const int destinationMode = QPainter::CompositionMode_Destination;
7865 functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode];
7867 // use the default qdrawhelper implementation for the
7868 // extended composition modes
7869 for (int mode = 12; mode < 24; ++mode)
7870 functionForModeSolidAsm[mode] = functionForModeSolid_C[mode];
7872 functionForModeSolid = functionForModeSolidAsm;
7874 if (functionForModeAsm)
7875 functionForMode = functionForModeAsm;
7877 qt_build_pow_tables();
7880 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count)
7882 qInitDrawhelperAsm();
7883 qt_memfill32(dest, value, count);
7886 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count)
7888 qInitDrawhelperAsm();
7889 qt_memfill16(dest, value, count);
7892 #ifdef QT_QWS_DEPTH_GENERIC
7895 int qrgb::len_red = 0;
7896 int qrgb::len_green = 0;
7897 int qrgb::len_blue = 0;
7898 int qrgb::len_alpha = 0;
7899 int qrgb::off_red = 0;
7900 int qrgb::off_green = 0;
7901 int qrgb::off_blue = 0;
7902 int qrgb::off_alpha = 0;
7904 template <typename SRC>
7905 Q_STATIC_TEMPLATE_FUNCTION inline void qt_rectconvert_rgb(qrgb *dest, const SRC *src,
7906 int x, int y, int width, int height,
7907 int dstStride, int srcStride)
7909 quint8 *dest8 = reinterpret_cast<quint8*>(dest)
7910 + y * dstStride + x * qrgb::bpp;
7912 srcStride = srcStride / sizeof(SRC) - width;
7913 dstStride -= (width * qrgb::bpp);
7915 for (int j = 0; j < height; ++j) {
7916 for (int i = 0; i < width; ++i) {
7917 const quint32 v = qt_convertToRgb<SRC>(*src++);
7918 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
7919 for (int j = qrgb::bpp - 1; j >= 0; --j)
7920 *dest8++ = (v >> (8 * j)) & 0xff;
7922 for (int j = 0; j < qrgb::bpp; ++j)
7923 *dest8++ = (v >> (8 * j)) & 0xff;
7933 void qt_rectconvert(qrgb *dest, const quint32 *src,
7934 int x, int y, int width, int height,
7935 int dstStride, int srcStride)
7937 qt_rectconvert_rgb<quint32>(dest, src, x, y, width, height,
7938 dstStride, srcStride);
7942 void qt_rectconvert(qrgb *dest, const quint16 *src,
7943 int x, int y, int width, int height,
7944 int dstStride, int srcStride)
7946 qt_rectconvert_rgb<quint16>(dest, src, x, y, width, height,
7947 dstStride, srcStride);
7950 #endif // QT_QWS_DEPTH_GENERIC