1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include <private/qdrawhelper_p.h>
43 #include <private/qpaintengine_raster_p.h>
44 #include <private/qpainter_p.h>
45 #include <private/qdrawhelper_x86_p.h>
46 #ifdef QT_HAVE_ARM_SIMD
47 #include <private/qdrawhelper_arm_simd_p.h>
49 #include <private/qdrawhelper_neon_p.h>
50 #include <private/qmath_p.h>
56 #define MASK(src, a) src = BYTE_MUL(src, a)
58 #if defined(Q_OS_IRIX) && defined(Q_CC_GNU) && __GNUC__ == 3 && __GNUC__ < 4 && QT_POINTER_SIZE == 8
59 #define Q_IRIX_GCC3_3_WORKAROUND
61 // work around http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14484
63 static uint gccBug(uint value) __attribute__((noinline));
64 static uint gccBug(uint value)
71 constants and structures
75 fixed_scale = 1 << 16,
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;
1409 v->a = data->gradient.radial.radius*data->gradient.radial.radius - v->dx*v->dx - v->dy*v->dy;
1412 class RadialFetchPlain
1415 static inline void fetch(uint *buffer, uint *end, const QSpanData *data, qreal det, qreal delta_det,
1416 qreal delta_delta_det, qreal b, qreal delta_b)
1418 while (buffer < end) {
1419 *buffer = qt_gradient_pixel(&data->gradient, (det > 0 ? qSqrt(det) : 0) - b);
1422 delta_det += delta_delta_det;
1430 const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data,
1431 int y, int x, int length)
1433 return qt_fetch_radial_gradient_template<RadialFetchPlain>(buffer, op, data, y, x, length);
1436 static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain;
1438 static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data,
1439 int y, int x, int length)
1441 const uint *b = buffer;
1442 qreal rx = data->m21 * (y + qreal(0.5))
1443 + data->dx + data->m11 * (x + qreal(0.5));
1444 qreal ry = data->m22 * (y + qreal(0.5))
1445 + data->dy + data->m12 * (x + qreal(0.5));
1446 bool affine = !data->m13 && !data->m23;
1448 const uint *end = buffer + length;
1450 rx -= data->gradient.conical.center.x;
1451 ry -= data->gradient.conical.center.y;
1452 while (buffer < end) {
1453 qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle;
1455 *buffer = qt_gradient_pixel(&data->gradient, 1 - angle / (2*Q_PI));
1462 qreal rw = data->m23 * (y + qreal(0.5))
1463 + data->m33 + data->m13 * (x + qreal(0.5));
1466 while (buffer < end) {
1467 qreal angle = qAtan2(ry/rw - data->gradient.conical.center.x,
1468 rx/rw - data->gradient.conical.center.y)
1469 + data->gradient.conical.angle;
1471 *buffer = qt_gradient_pixel(&data->gradient, 1. - angle / (2*Q_PI));
1485 #if defined(Q_CC_RVCT)
1486 // Force ARM code generation for comp_func_* -methods
1489 # if defined(QT_HAVE_ARMV6)
1490 static __forceinline void preload(const uint *start)
1492 asm( "pld [start]" );
1494 static const uint L2CacheLineLength = 32;
1495 static const uint L2CacheLineLengthInInts = L2CacheLineLength/sizeof(uint);
1496 # define PRELOAD_INIT(x) preload(x);
1497 # define PRELOAD_INIT2(x,y) PRELOAD_INIT(x) PRELOAD_INIT(y)
1498 # define PRELOAD_COND(x) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts);
1499 // Two consecutive preloads stall, so space them out a bit by using different modulus.
1500 # define PRELOAD_COND2(x,y) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); \
1501 if (((uint)&y[i])%L2CacheLineLength == 16) preload(&y[i] + L2CacheLineLengthInInts);
1502 # endif // QT_HAVE_ARMV6
1505 #if !defined(Q_CC_RVCT) || !defined(QT_HAVE_ARMV6)
1506 # define PRELOAD_INIT(x)
1507 # define PRELOAD_INIT2(x,y)
1508 # define PRELOAD_COND(x)
1509 # define PRELOAD_COND2(x,y)
1512 /* The constant alpha factor describes an alpha factor that gets applied
1513 to the result of the composition operation combining it with the destination.
1515 The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1.
1516 we get the unmodified operation
1518 result = src op dest
1519 dest = result * const_alpha + dest * (1. - const_alpha)
1521 This means that in the comments below, the first line is the const_alpha==255 case, the
1522 second line the general one.
1525 s == src, sa == alpha(src), sia = 1 - alpha(src)
1526 d == dest, da == alpha(dest), dia = 1 - alpha(dest)
1527 ca = const_alpha, cia = 1 - const_alpha
1529 The methods exist in two variants. One where we have a constant source, the other
1530 where the source is an array of pixels.
1537 #define comp_func_Clear_impl(dest, length, const_alpha)\
1539 if (const_alpha == 255) {\
1540 QT_MEMFILL_UINT(dest, length, 0);\
1542 int ialpha = 255 - const_alpha;\
1544 for (int i = 0; i < length; ++i) {\
1546 dest[i] = BYTE_MUL(dest[i], ialpha);\
1551 void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
1553 comp_func_Clear_impl(dest, length, const_alpha);
1556 void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
1558 comp_func_Clear_impl(dest, length, const_alpha);
1563 dest = s * ca + d * cia
1565 void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha)
1567 if (const_alpha == 255) {
1568 QT_MEMFILL_UINT(dest, length, color);
1570 int ialpha = 255 - const_alpha;
1571 color = BYTE_MUL(color, const_alpha);
1573 for (int i = 0; i < length; ++i) {
1575 dest[i] = color + BYTE_MUL(dest[i], ialpha);
1580 void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length, uint const_alpha)
1582 if (const_alpha == 255) {
1583 ::memcpy(dest, src, length * sizeof(uint));
1585 int ialpha = 255 - const_alpha;
1586 PRELOAD_INIT2(dest, src)
1587 for (int i = 0; i < length; ++i) {
1588 PRELOAD_COND2(dest, src)
1589 dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha);
1594 void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
1598 void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint)
1603 result = s + d * sia
1604 dest = (s + d * sia) * ca + d * cia
1605 = s * ca + d * (sia * ca + cia)
1606 = s * ca + d * (1 - sa*ca)
1608 void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha)
1610 if ((const_alpha & qAlpha(color)) == 255) {
1611 QT_MEMFILL_UINT(dest, length, color);
1613 if (const_alpha != 255)
1614 color = BYTE_MUL(color, const_alpha);
1616 for (int i = 0; i < length; ++i) {
1618 dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color));
1623 void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha)
1625 PRELOAD_INIT2(dest, src)
1626 if (const_alpha == 255) {
1627 for (int i = 0; i < length; ++i) {
1628 PRELOAD_COND2(dest, src)
1630 if (s >= 0xff000000)
1633 dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
1636 for (int i = 0; i < length; ++i) {
1637 PRELOAD_COND2(dest, src)
1638 uint s = BYTE_MUL(src[i], const_alpha);
1639 dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
1645 result = d + s * dia
1646 dest = (d + s * dia) * ca + d * cia
1649 void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha)
1651 if (const_alpha != 255)
1652 color = BYTE_MUL(color, const_alpha);
1654 for (int i = 0; i < length; ++i) {
1657 dest[i] = d + BYTE_MUL(color, qAlpha(~d));
1661 void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha)
1663 PRELOAD_INIT2(dest, src)
1664 if (const_alpha == 255) {
1665 for (int i = 0; i < length; ++i) {
1666 PRELOAD_COND2(dest, src)
1668 dest[i] = d + BYTE_MUL(src[i], qAlpha(~d));
1671 for (int i = 0; i < length; ++i) {
1672 PRELOAD_COND2(dest, src)
1674 uint s = BYTE_MUL(src[i], const_alpha);
1675 dest[i] = d + BYTE_MUL(s, qAlpha(~d));
1682 dest = s * da * ca + d * cia
1684 void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha)
1687 if (const_alpha == 255) {
1688 for (int i = 0; i < length; ++i) {
1690 dest[i] = BYTE_MUL(color, qAlpha(dest[i]));
1693 color = BYTE_MUL(color, const_alpha);
1694 uint cia = 255 - const_alpha;
1695 for (int i = 0; i < length; ++i) {
1698 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia);
1703 void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha)
1705 PRELOAD_INIT2(dest, src)
1706 if (const_alpha == 255) {
1707 for (int i = 0; i < length; ++i) {
1708 PRELOAD_COND2(dest, src)
1709 dest[i] = BYTE_MUL(src[i], qAlpha(dest[i]));
1712 uint cia = 255 - const_alpha;
1713 for (int i = 0; i < length; ++i) {
1714 PRELOAD_COND2(dest, src)
1716 uint s = BYTE_MUL(src[i], const_alpha);
1717 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia);
1724 dest = d * sa * ca + d * cia
1725 = d * (sa * ca + cia)
1727 void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha)
1729 uint a = qAlpha(color);
1730 if (const_alpha != 255) {
1731 a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
1734 for (int i = 0; i < length; ++i) {
1736 dest[i] = BYTE_MUL(dest[i], a);
1740 void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha)
1742 PRELOAD_INIT2(dest, src)
1743 if (const_alpha == 255) {
1744 for (int i = 0; i < length; ++i) {
1745 PRELOAD_COND2(dest, src)
1746 dest[i] = BYTE_MUL(dest[i], qAlpha(src[i]));
1749 int cia = 255 - const_alpha;
1750 for (int i = 0; i < length; ++i) {
1751 PRELOAD_COND2(dest, src)
1752 uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia;
1753 dest[i] = BYTE_MUL(dest[i], a);
1760 dest = s * dia * ca + d * cia
1763 void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha)
1766 if (const_alpha == 255) {
1767 for (int i = 0; i < length; ++i) {
1769 dest[i] = BYTE_MUL(color, qAlpha(~dest[i]));
1772 color = BYTE_MUL(color, const_alpha);
1773 int cia = 255 - const_alpha;
1774 for (int i = 0; i < length; ++i) {
1777 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia);
1782 void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha)
1784 PRELOAD_INIT2(dest, src)
1785 if (const_alpha == 255) {
1786 for (int i = 0; i < length; ++i) {
1787 PRELOAD_COND2(dest, src)
1788 dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i]));
1791 int cia = 255 - const_alpha;
1792 for (int i = 0; i < length; ++i) {
1793 PRELOAD_COND2(dest, src)
1794 uint s = BYTE_MUL(src[i], const_alpha);
1796 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia);
1803 dest = d * sia * ca + d * cia
1804 = d * (sia * ca + cia)
1806 void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha)
1808 uint a = qAlpha(~color);
1809 if (const_alpha != 255)
1810 a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
1812 for (int i = 0; i < length; ++i) {
1814 dest[i] = BYTE_MUL(dest[i], a);
1818 void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha)
1820 PRELOAD_INIT2(dest, src)
1821 if (const_alpha == 255) {
1822 for (int i = 0; i < length; ++i) {
1823 PRELOAD_COND2(dest, src)
1824 dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i]));
1827 int cia = 255 - const_alpha;
1828 for (int i = 0; i < length; ++i) {
1829 PRELOAD_COND2(dest, src)
1830 uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia;
1831 dest[i] = BYTE_MUL(dest[i], sia);
1837 result = s*da + d*sia
1838 dest = s*da*ca + d*sia*ca + d *cia
1839 = s*ca * da + d * (sia*ca + cia)
1840 = s*ca * da + d * (1 - sa*ca)
1842 void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha)
1844 if (const_alpha != 255) {
1845 color = BYTE_MUL(color, const_alpha);
1847 uint sia = qAlpha(~color);
1849 for (int i = 0; i < length; ++i) {
1851 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia);
1855 void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha)
1857 PRELOAD_INIT2(dest, src)
1858 if (const_alpha == 255) {
1859 for (int i = 0; i < length; ++i) {
1860 PRELOAD_COND2(dest, src)
1863 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
1866 for (int i = 0; i < length; ++i) {
1867 PRELOAD_COND2(dest, src)
1868 uint s = BYTE_MUL(src[i], const_alpha);
1870 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
1876 result = d*sa + s*dia
1877 dest = d*sa*ca + s*dia*ca + d *cia
1878 = s*ca * dia + d * (sa*ca + cia)
1880 void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha)
1882 uint a = qAlpha(color);
1883 if (const_alpha != 255) {
1884 color = BYTE_MUL(color, const_alpha);
1885 a = qAlpha(color) + 255 - const_alpha;
1888 for (int i = 0; i < length; ++i) {
1891 dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d));
1895 void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha)
1897 PRELOAD_INIT2(dest, src)
1898 if (const_alpha == 255) {
1899 for (int i = 0; i < length; ++i) {
1900 PRELOAD_COND2(dest, src)
1903 dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d));
1906 int cia = 255 - const_alpha;
1907 for (int i = 0; i < length; ++i) {
1908 PRELOAD_COND2(dest, src)
1909 uint s = BYTE_MUL(src[i], const_alpha);
1911 uint a = qAlpha(s) + cia;
1912 dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d));
1918 result = d*sia + s*dia
1919 dest = d*sia*ca + s*dia*ca + d *cia
1920 = s*ca * dia + d * (sia*ca + cia)
1921 = s*ca * dia + d * (1 - sa*ca)
1923 void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha)
1925 if (const_alpha != 255)
1926 color = BYTE_MUL(color, const_alpha);
1927 uint sia = qAlpha(~color);
1930 for (int i = 0; i < length; ++i) {
1933 dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia);
1937 void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha)
1939 PRELOAD_INIT2(dest, src)
1940 if (const_alpha == 255) {
1941 for (int i = 0; i < length; ++i) {
1942 PRELOAD_COND2(dest, src)
1945 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
1948 for (int i = 0; i < length; ++i) {
1949 PRELOAD_COND2(dest, src)
1951 uint s = BYTE_MUL(src[i], const_alpha);
1952 dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
1957 struct QFullCoverage {
1958 inline void store(uint *dest, const uint src) const
1964 struct QPartialCoverage {
1965 inline QPartialCoverage(uint const_alpha)
1967 , ica(255 - const_alpha)
1971 inline void store(uint *dest, const uint src) const
1973 *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
1981 static inline int mix_alpha(int da, int sa)
1983 return 255 - ((255 - sa) * (255 - da) >> 8);
1987 Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
1990 template <typename T>
1991 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage)
1996 for (int i = 0; i < length; ++i) {
1999 d = comp_func_Plus_one_pixel(d, s);
2000 coverage.store(&dest[i], d);
2004 void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha)
2006 if (const_alpha == 255)
2007 comp_func_solid_Plus_impl(dest, length, color, QFullCoverage());
2009 comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha));
2012 template <typename T>
2013 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *dest, const uint *src, int length, const T &coverage)
2015 PRELOAD_INIT2(dest, src)
2016 for (int i = 0; i < length; ++i) {
2017 PRELOAD_COND2(dest, src)
2021 d = comp_func_Plus_one_pixel(d, s);
2023 coverage.store(&dest[i], d);
2027 void QT_FASTCALL comp_func_Plus(uint *dest, const uint *src, int length, uint const_alpha)
2029 if (const_alpha == 255)
2030 comp_func_Plus_impl(dest, src, length, QFullCoverage());
2032 comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha));
2036 Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2038 static inline int multiply_op(int dst, int src, int da, int sa)
2040 return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa));
2043 template <typename T>
2044 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage)
2046 int sa = qAlpha(color);
2047 int sr = qRed(color);
2048 int sg = qGreen(color);
2049 int sb = qBlue(color);
2052 for (int i = 0; i < length; ++i) {
2057 #define OP(a, b) multiply_op(a, b, da, sa)
2058 int r = OP( qRed(d), sr);
2059 int b = OP( qBlue(d), sb);
2060 int g = OP(qGreen(d), sg);
2061 int a = mix_alpha(da, sa);
2064 coverage.store(&dest[i], qRgba(r, g, b, a));
2068 void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha)
2070 if (const_alpha == 255)
2071 comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
2073 comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
2076 template <typename T>
2077 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *dest, const uint *src, int length, const T &coverage)
2079 PRELOAD_INIT2(dest, src)
2080 for (int i = 0; i < length; ++i) {
2081 PRELOAD_COND2(dest, src)
2088 #define OP(a, b) multiply_op(a, b, da, sa)
2089 int r = OP( qRed(d), qRed(s));
2090 int b = OP( qBlue(d), qBlue(s));
2091 int g = OP(qGreen(d), qGreen(s));
2092 int a = mix_alpha(da, sa);
2095 coverage.store(&dest[i], qRgba(r, g, b, a));
2099 void QT_FASTCALL comp_func_Multiply(uint *dest, const uint *src, int length, uint const_alpha)
2101 if (const_alpha == 255)
2102 comp_func_Multiply_impl(dest, src, length, QFullCoverage());
2104 comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
2108 Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2109 = Sca + Dca - Sca.Dca
2111 template <typename T>
2112 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage)
2114 int sa = qAlpha(color);
2115 int sr = qRed(color);
2116 int sg = qGreen(color);
2117 int sb = qBlue(color);
2120 for (int i = 0; i < length; ++i) {
2125 #define OP(a, b) 255 - qt_div_255((255-a) * (255-b))
2126 int r = OP( qRed(d), sr);
2127 int b = OP( qBlue(d), sb);
2128 int g = OP(qGreen(d), sg);
2129 int a = mix_alpha(da, sa);
2132 coverage.store(&dest[i], qRgba(r, g, b, a));
2136 void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha)
2138 if (const_alpha == 255)
2139 comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
2141 comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
2144 template <typename T>
2145 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *dest, const uint *src, int length, const T &coverage)
2147 PRELOAD_INIT2(dest, src)
2148 for (int i = 0; i < length; ++i) {
2149 PRELOAD_COND2(dest, src)
2156 #define OP(a, b) 255 - (((255-a) * (255-b)) >> 8)
2157 int r = OP( qRed(d), qRed(s));
2158 int b = OP( qBlue(d), qBlue(s));
2159 int g = OP(qGreen(d), qGreen(s));
2160 int a = mix_alpha(da, sa);
2163 coverage.store(&dest[i], qRgba(r, g, b, a));
2167 void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha)
2169 if (const_alpha == 255)
2170 comp_func_Screen_impl(dest, src, length, QFullCoverage());
2172 comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
2177 Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2179 Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2181 static inline int overlay_op(int dst, int src, int da, int sa)
2183 const int temp = src * (255 - da) + dst * (255 - sa);
2185 return qt_div_255(2 * src * dst + temp);
2187 return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2190 template <typename T>
2191 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage)
2193 int sa = qAlpha(color);
2194 int sr = qRed(color);
2195 int sg = qGreen(color);
2196 int sb = qBlue(color);
2199 for (int i = 0; i < length; ++i) {
2204 #define OP(a, b) overlay_op(a, b, da, sa)
2205 int r = OP( qRed(d), sr);
2206 int b = OP( qBlue(d), sb);
2207 int g = OP(qGreen(d), sg);
2208 int a = mix_alpha(da, sa);
2211 coverage.store(&dest[i], qRgba(r, g, b, a));
2215 void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha)
2217 if (const_alpha == 255)
2218 comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
2220 comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
2223 template <typename T>
2224 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *dest, const uint *src, int length, const T &coverage)
2226 PRELOAD_INIT2(dest, src)
2227 for (int i = 0; i < length; ++i) {
2228 PRELOAD_COND2(dest, src)
2235 #define OP(a, b) overlay_op(a, b, da, sa)
2236 int r = OP( qRed(d), qRed(s));
2237 int b = OP( qBlue(d), qBlue(s));
2238 int g = OP(qGreen(d), qGreen(s));
2239 int a = mix_alpha(da, sa);
2242 coverage.store(&dest[i], qRgba(r, g, b, a));
2246 void QT_FASTCALL comp_func_Overlay(uint *dest, const uint *src, int length, uint const_alpha)
2248 if (const_alpha == 255)
2249 comp_func_Overlay_impl(dest, src, length, QFullCoverage());
2251 comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
2255 Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2256 Da' = Sa + Da - Sa.Da
2258 static inline int darken_op(int dst, int src, int da, int sa)
2260 return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2263 template <typename T>
2264 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage)
2266 int sa = qAlpha(color);
2267 int sr = qRed(color);
2268 int sg = qGreen(color);
2269 int sb = qBlue(color);
2272 for (int i = 0; i < length; ++i) {
2277 #define OP(a, b) darken_op(a, b, da, sa)
2278 int r = OP( qRed(d), sr);
2279 int b = OP( qBlue(d), sb);
2280 int g = OP(qGreen(d), sg);
2281 int a = mix_alpha(da, sa);
2284 coverage.store(&dest[i], qRgba(r, g, b, a));
2288 void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha)
2290 if (const_alpha == 255)
2291 comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
2293 comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
2296 template <typename T>
2297 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *dest, const uint *src, int length, const T &coverage)
2299 PRELOAD_INIT2(dest, src)
2300 for (int i = 0; i < length; ++i) {
2301 PRELOAD_COND2(dest, src)
2308 #define OP(a, b) darken_op(a, b, da, sa)
2309 int r = OP( qRed(d), qRed(s));
2310 int b = OP( qBlue(d), qBlue(s));
2311 int g = OP(qGreen(d), qGreen(s));
2312 int a = mix_alpha(da, sa);
2315 coverage.store(&dest[i], qRgba(r, g, b, a));
2319 void QT_FASTCALL comp_func_Darken(uint *dest, const uint *src, int length, uint const_alpha)
2321 if (const_alpha == 255)
2322 comp_func_Darken_impl(dest, src, length, QFullCoverage());
2324 comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
2328 Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2329 Da' = Sa + Da - Sa.Da
2331 static inline int lighten_op(int dst, int src, int da, int sa)
2333 return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2336 template <typename T>
2337 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage)
2339 int sa = qAlpha(color);
2340 int sr = qRed(color);
2341 int sg = qGreen(color);
2342 int sb = qBlue(color);
2345 for (int i = 0; i < length; ++i) {
2350 #define OP(a, b) lighten_op(a, b, da, sa)
2351 int r = OP( qRed(d), sr);
2352 int b = OP( qBlue(d), sb);
2353 int g = OP(qGreen(d), sg);
2354 int a = mix_alpha(da, sa);
2357 coverage.store(&dest[i], qRgba(r, g, b, a));
2361 void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha)
2363 if (const_alpha == 255)
2364 comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
2366 comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
2369 template <typename T>
2370 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *dest, const uint *src, int length, const T &coverage)
2372 PRELOAD_INIT2(dest, src)
2373 for (int i = 0; i < length; ++i) {
2374 PRELOAD_COND2(dest, src)
2381 #define OP(a, b) lighten_op(a, b, da, sa)
2382 int r = OP( qRed(d), qRed(s));
2383 int b = OP( qBlue(d), qBlue(s));
2384 int g = OP(qGreen(d), qGreen(s));
2385 int a = mix_alpha(da, sa);
2388 coverage.store(&dest[i], qRgba(r, g, b, a));
2392 void QT_FASTCALL comp_func_Lighten(uint *dest, const uint *src, int length, uint const_alpha)
2394 if (const_alpha == 255)
2395 comp_func_Lighten_impl(dest, src, length, QFullCoverage());
2397 comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
2401 if Sca.Da + Dca.Sa >= Sa.Da
2402 Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
2404 Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2406 static inline int color_dodge_op(int dst, int src, int da, int sa)
2408 const int sa_da = sa * da;
2409 const int dst_sa = dst * sa;
2410 const int src_da = src * da;
2412 const int temp = src * (255 - da) + dst * (255 - sa);
2413 if (src_da + dst_sa >= sa_da)
2414 return qt_div_255(sa_da + temp);
2416 return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp);
2419 template <typename T>
2420 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage)
2422 int sa = qAlpha(color);
2423 int sr = qRed(color);
2424 int sg = qGreen(color);
2425 int sb = qBlue(color);
2428 for (int i = 0; i < length; ++i) {
2433 #define OP(a,b) color_dodge_op(a, b, da, sa)
2434 int r = OP( qRed(d), sr);
2435 int b = OP( qBlue(d), sb);
2436 int g = OP(qGreen(d), sg);
2437 int a = mix_alpha(da, sa);
2440 coverage.store(&dest[i], qRgba(r, g, b, a));
2444 void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha)
2446 if (const_alpha == 255)
2447 comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
2449 comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
2452 template <typename T>
2453 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *dest, const uint *src, int length, const T &coverage)
2455 PRELOAD_INIT2(dest, src)
2456 for (int i = 0; i < length; ++i) {
2457 PRELOAD_COND2(dest, src)
2464 #define OP(a, b) color_dodge_op(a, b, da, sa)
2465 int r = OP( qRed(d), qRed(s));
2466 int b = OP( qBlue(d), qBlue(s));
2467 int g = OP(qGreen(d), qGreen(s));
2468 int a = mix_alpha(da, sa);
2471 coverage.store(&dest[i], qRgba(r, g, b, a));
2475 void QT_FASTCALL comp_func_ColorDodge(uint *dest, const uint *src, int length, uint const_alpha)
2477 if (const_alpha == 255)
2478 comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
2480 comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
2484 if Sca.Da + Dca.Sa <= Sa.Da
2485 Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
2487 Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
2489 static inline int color_burn_op(int dst, int src, int da, int sa)
2491 const int src_da = src * da;
2492 const int dst_sa = dst * sa;
2493 const int sa_da = sa * da;
2495 const int temp = src * (255 - da) + dst * (255 - sa);
2497 if (src == 0 || src_da + dst_sa <= sa_da)
2498 return qt_div_255(temp);
2499 return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp);
2502 template <typename T>
2503 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage)
2505 int sa = qAlpha(color);
2506 int sr = qRed(color);
2507 int sg = qGreen(color);
2508 int sb = qBlue(color);
2511 for (int i = 0; i < length; ++i) {
2516 #define OP(a, b) color_burn_op(a, b, da, sa)
2517 int r = OP( qRed(d), sr);
2518 int b = OP( qBlue(d), sb);
2519 int g = OP(qGreen(d), sg);
2520 int a = mix_alpha(da, sa);
2523 coverage.store(&dest[i], qRgba(r, g, b, a));
2527 void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha)
2529 if (const_alpha == 255)
2530 comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
2532 comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
2535 template <typename T>
2536 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *dest, const uint *src, int length, const T &coverage)
2538 PRELOAD_INIT2(dest, src)
2539 for (int i = 0; i < length; ++i) {
2540 PRELOAD_COND2(dest, src)
2547 #define OP(a, b) color_burn_op(a, b, da, sa)
2548 int r = OP( qRed(d), qRed(s));
2549 int b = OP( qBlue(d), qBlue(s));
2550 int g = OP(qGreen(d), qGreen(s));
2551 int a = mix_alpha(da, sa);
2554 coverage.store(&dest[i], qRgba(r, g, b, a));
2558 void QT_FASTCALL comp_func_ColorBurn(uint *dest, const uint *src, int length, uint const_alpha)
2560 if (const_alpha == 255)
2561 comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
2563 comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
2568 Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2570 Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2572 static inline uint hardlight_op(int dst, int src, int da, int sa)
2574 const uint temp = src * (255 - da) + dst * (255 - sa);
2577 return qt_div_255(2 * src * dst + temp);
2579 return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2582 template <typename T>
2583 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage)
2585 int sa = qAlpha(color);
2586 int sr = qRed(color);
2587 int sg = qGreen(color);
2588 int sb = qBlue(color);
2591 for (int i = 0; i < length; ++i) {
2596 #define OP(a, b) hardlight_op(a, b, da, sa)
2597 int r = OP( qRed(d), sr);
2598 int b = OP( qBlue(d), sb);
2599 int g = OP(qGreen(d), sg);
2600 int a = mix_alpha(da, sa);
2603 coverage.store(&dest[i], qRgba(r, g, b, a));
2607 void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha)
2609 if (const_alpha == 255)
2610 comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
2612 comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2615 template <typename T>
2616 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *dest, const uint *src, int length, const T &coverage)
2618 PRELOAD_INIT2(dest, src)
2619 for (int i = 0; i < length; ++i) {
2620 PRELOAD_COND2(dest, src)
2627 #define OP(a, b) hardlight_op(a, b, da, sa)
2628 int r = OP( qRed(d), qRed(s));
2629 int b = OP( qBlue(d), qBlue(s));
2630 int g = OP(qGreen(d), qGreen(s));
2631 int a = mix_alpha(da, sa);
2634 coverage.store(&dest[i], qRgba(r, g, b, a));
2638 void QT_FASTCALL comp_func_HardLight(uint *dest, const uint *src, int length, uint const_alpha)
2640 if (const_alpha == 255)
2641 comp_func_HardLight_impl(dest, src, length, QFullCoverage());
2643 comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2648 Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
2649 otherwise if 2.Sca > Sa and 4.Dca <= Da
2650 Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2651 otherwise if 2.Sca > Sa and 4.Dca > Da
2652 Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2654 static inline int soft_light_op(int dst, int src, int da, int sa)
2656 const int src2 = src << 1;
2657 const int dst_np = da != 0 ? (255 * dst) / da : 0;
2658 const int temp = (src * (255 - da) + dst * (255 - sa)) * 255;
2661 return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025;
2662 else if (4 * dst <= da)
2663 return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025;
2665 # ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
2666 return (dst * sa * 255 + da * (src2 - sa) * (qIntSqrtInt(dst_np * 255) - dst_np) + temp) / 65025;
2668 return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025;
2673 template <typename T>
2674 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage)
2676 int sa = qAlpha(color);
2677 int sr = qRed(color);
2678 int sg = qGreen(color);
2679 int sb = qBlue(color);
2682 for (int i = 0; i < length; ++i) {
2687 #define OP(a, b) soft_light_op(a, b, da, sa)
2688 int r = OP( qRed(d), sr);
2689 int b = OP( qBlue(d), sb);
2690 int g = OP(qGreen(d), sg);
2691 int a = mix_alpha(da, sa);
2694 coverage.store(&dest[i], qRgba(r, g, b, a));
2698 void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
2700 if (const_alpha == 255)
2701 comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
2703 comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2706 template <typename T>
2707 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *dest, const uint *src, int length, const T &coverage)
2709 PRELOAD_INIT2(dest, src)
2710 for (int i = 0; i < length; ++i) {
2711 PRELOAD_COND2(dest, src)
2718 #define OP(a, b) soft_light_op(a, b, da, sa)
2719 int r = OP( qRed(d), qRed(s));
2720 int b = OP( qBlue(d), qBlue(s));
2721 int g = OP(qGreen(d), qGreen(s));
2722 int a = mix_alpha(da, sa);
2725 coverage.store(&dest[i], qRgba(r, g, b, a));
2729 void QT_FASTCALL comp_func_SoftLight(uint *dest, const uint *src, int length, uint const_alpha)
2731 if (const_alpha == 255)
2732 comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
2734 comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2738 Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2739 = Sca + Dca - 2.min(Sca.Da, Dca.Sa)
2741 static inline int difference_op(int dst, int src, int da, int sa)
2743 return src + dst - qt_div_255(2 * qMin(src * da, dst * sa));
2746 template <typename T>
2747 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage)
2749 int sa = qAlpha(color);
2750 int sr = qRed(color);
2751 int sg = qGreen(color);
2752 int sb = qBlue(color);
2755 for (int i = 0; i < length; ++i) {
2760 #define OP(a, b) difference_op(a, b, da, sa)
2761 int r = OP( qRed(d), sr);
2762 int b = OP( qBlue(d), sb);
2763 int g = OP(qGreen(d), sg);
2764 int a = mix_alpha(da, sa);
2767 coverage.store(&dest[i], qRgba(r, g, b, a));
2771 void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha)
2773 if (const_alpha == 255)
2774 comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
2776 comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
2779 template <typename T>
2780 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *dest, const uint *src, int length, const T &coverage)
2782 PRELOAD_INIT2(dest, src)
2783 for (int i = 0; i < length; ++i) {
2784 PRELOAD_COND2(dest, src)
2791 #define OP(a, b) difference_op(a, b, da, sa)
2792 int r = OP( qRed(d), qRed(s));
2793 int b = OP( qBlue(d), qBlue(s));
2794 int g = OP(qGreen(d), qGreen(s));
2795 int a = mix_alpha(da, sa);
2798 coverage.store(&dest[i], qRgba(r, g, b, a));
2802 void QT_FASTCALL comp_func_Difference(uint *dest, const uint *src, int length, uint const_alpha)
2804 if (const_alpha == 255)
2805 comp_func_Difference_impl(dest, src, length, QFullCoverage());
2807 comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
2811 Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2813 template <typename T>
2814 Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage)
2816 int sa = qAlpha(color);
2817 int sr = qRed(color);
2818 int sg = qGreen(color);
2819 int sb = qBlue(color);
2822 for (int i = 0; i < length; ++i) {
2827 #define OP(a, b) (a + b - qt_div_255(2*(a*b)))
2828 int r = OP( qRed(d), sr);
2829 int b = OP( qBlue(d), sb);
2830 int g = OP(qGreen(d), sg);
2831 int a = mix_alpha(da, sa);
2834 coverage.store(&dest[i], qRgba(r, g, b, a));
2838 void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha)
2840 if (const_alpha == 255)
2841 comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage());
2843 comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
2846 template <typename T>
2847 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *dest, const uint *src, int length, const T &coverage)
2849 PRELOAD_INIT2(dest, src)
2850 for (int i = 0; i < length; ++i) {
2851 PRELOAD_COND2(dest, src)
2858 #define OP(a, b) (a + b - ((a*b) >> 7))
2859 int r = OP( qRed(d), qRed(s));
2860 int b = OP( qBlue(d), qBlue(s));
2861 int g = OP(qGreen(d), qGreen(s));
2862 int a = mix_alpha(da, sa);
2865 coverage.store(&dest[i], qRgba(r, g, b, a));
2869 void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int length, uint const_alpha)
2871 if (const_alpha == 255)
2872 comp_func_Exclusion_impl(dest, src, length, QFullCoverage());
2874 comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
2877 #if defined(Q_CC_RVCT)
2878 // Restore pragma state from previous #pragma arm
2882 void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest,
2887 Q_UNUSED(const_alpha);
2892 void QT_FASTCALL rasterop_SourceOrDestination(uint *dest,
2897 Q_UNUSED(const_alpha);
2902 void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest,
2907 Q_UNUSED(const_alpha);
2908 color |= 0xff000000;
2913 void QT_FASTCALL rasterop_SourceAndDestination(uint *dest,
2918 Q_UNUSED(const_alpha);
2920 *dest = (*src & *dest) | 0xff000000;
2925 void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest,
2930 Q_UNUSED(const_alpha);
2931 color &= 0x00ffffff;
2936 void QT_FASTCALL rasterop_SourceXorDestination(uint *dest,
2941 Q_UNUSED(const_alpha);
2943 *dest = (*src ^ *dest) | 0xff000000;
2948 void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest,
2953 Q_UNUSED(const_alpha);
2956 *dest = (color & ~(*dest)) | 0xff000000;
2961 void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *dest,
2966 Q_UNUSED(const_alpha);
2968 *dest = (~(*src) & ~(*dest)) | 0xff000000;
2973 void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest,
2978 Q_UNUSED(const_alpha);
2979 color = ~color | 0xff000000;
2981 *dest = color | ~(*dest);
2986 void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *dest,
2991 Q_UNUSED(const_alpha);
2993 *dest = ~(*src) | ~(*dest) | 0xff000000;
2998 void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest,
3003 Q_UNUSED(const_alpha);
3004 color = ~color & 0x00ffffff;
3006 *dest = color ^ (*dest);
3011 void QT_FASTCALL rasterop_NotSourceXorDestination(uint *dest,
3016 Q_UNUSED(const_alpha);
3018 *dest = ((~(*src)) ^ (*dest)) | 0xff000000;
3023 void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length,
3024 uint color, uint const_alpha)
3026 Q_UNUSED(const_alpha);
3027 qt_memfill(dest, ~color | 0xff000000, length);
3030 void QT_FASTCALL rasterop_NotSource(uint *dest, const uint *src,
3031 int length, uint const_alpha)
3033 Q_UNUSED(const_alpha);
3035 *dest++ = ~(*src++) | 0xff000000;
3038 void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest,
3043 Q_UNUSED(const_alpha);
3044 color = ~color | 0xff000000;
3046 *dest = color & *dest;
3051 void QT_FASTCALL rasterop_NotSourceAndDestination(uint *dest,
3056 Q_UNUSED(const_alpha);
3058 *dest = (~(*src) & *dest) | 0xff000000;
3063 void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest,
3068 Q_UNUSED(const_alpha);
3070 *dest = (color & ~(*dest)) | 0xff000000;
3075 void QT_FASTCALL rasterop_SourceAndNotDestination(uint *dest,
3080 Q_UNUSED(const_alpha);
3082 *dest = (*src & ~(*dest)) | 0xff000000;
3087 static CompositionFunctionSolid functionForModeSolid_C[] = {
3088 comp_func_solid_SourceOver,
3089 comp_func_solid_DestinationOver,
3090 comp_func_solid_Clear,
3091 comp_func_solid_Source,
3092 comp_func_solid_Destination,
3093 comp_func_solid_SourceIn,
3094 comp_func_solid_DestinationIn,
3095 comp_func_solid_SourceOut,
3096 comp_func_solid_DestinationOut,
3097 comp_func_solid_SourceAtop,
3098 comp_func_solid_DestinationAtop,
3099 comp_func_solid_XOR,
3100 comp_func_solid_Plus,
3101 comp_func_solid_Multiply,
3102 comp_func_solid_Screen,
3103 comp_func_solid_Overlay,
3104 comp_func_solid_Darken,
3105 comp_func_solid_Lighten,
3106 comp_func_solid_ColorDodge,
3107 comp_func_solid_ColorBurn,
3108 comp_func_solid_HardLight,
3109 comp_func_solid_SoftLight,
3110 comp_func_solid_Difference,
3111 comp_func_solid_Exclusion,
3112 rasterop_solid_SourceOrDestination,
3113 rasterop_solid_SourceAndDestination,
3114 rasterop_solid_SourceXorDestination,
3115 rasterop_solid_NotSourceAndNotDestination,
3116 rasterop_solid_NotSourceOrNotDestination,
3117 rasterop_solid_NotSourceXorDestination,
3118 rasterop_solid_NotSource,
3119 rasterop_solid_NotSourceAndDestination,
3120 rasterop_solid_SourceAndNotDestination
3123 static const CompositionFunctionSolid *functionForModeSolid = functionForModeSolid_C;
3125 static CompositionFunction functionForMode_C[] = {
3126 comp_func_SourceOver,
3127 comp_func_DestinationOver,
3130 comp_func_Destination,
3132 comp_func_DestinationIn,
3133 comp_func_SourceOut,
3134 comp_func_DestinationOut,
3135 comp_func_SourceAtop,
3136 comp_func_DestinationAtop,
3144 comp_func_ColorDodge,
3145 comp_func_ColorBurn,
3146 comp_func_HardLight,
3147 comp_func_SoftLight,
3148 comp_func_Difference,
3149 comp_func_Exclusion,
3150 rasterop_SourceOrDestination,
3151 rasterop_SourceAndDestination,
3152 rasterop_SourceXorDestination,
3153 rasterop_NotSourceAndNotDestination,
3154 rasterop_NotSourceOrNotDestination,
3155 rasterop_NotSourceXorDestination,
3157 rasterop_NotSourceAndDestination,
3158 rasterop_SourceAndNotDestination
3161 static const CompositionFunction *functionForMode = functionForMode_C;
3163 static TextureBlendType getBlendType(const QSpanData *data)
3165 TextureBlendType ft;
3166 if (data->txop <= QTransform::TxTranslate)
3167 if (data->texture.type == QTextureData::Tiled)
3170 ft = BlendUntransformed;
3171 else if (data->bilinear)
3172 if (data->texture.type == QTextureData::Tiled)
3173 ft = BlendTransformedBilinearTiled;
3175 ft = BlendTransformedBilinear;
3177 if (data->texture.type == QTextureData::Tiled)
3178 ft = BlendTransformedTiled;
3180 ft = BlendTransformed;
3184 static inline Operator getOperator(const QSpanData *data, const QSpan *spans, int spanCount)
3187 bool solidSource = false;
3189 switch(data->type) {
3190 case QSpanData::Solid:
3191 solidSource = (qAlpha(data->solid.color) == 255);
3193 case QSpanData::LinearGradient:
3194 solidSource = !data->gradient.alphaColor;
3195 getLinearGradientValues(&op.linear, data);
3196 op.src_fetch = qt_fetch_linear_gradient;
3198 case QSpanData::RadialGradient:
3199 solidSource = !data->gradient.alphaColor;
3200 getRadialGradientValues(&op.radial, data);
3201 op.src_fetch = qt_fetch_radial_gradient;
3203 case QSpanData::ConicalGradient:
3204 solidSource = !data->gradient.alphaColor;
3205 op.src_fetch = qt_fetch_conical_gradient;
3207 case QSpanData::Texture:
3208 op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format];
3209 solidSource = !data->texture.hasAlpha;
3214 op.mode = data->rasterBuffer->compositionMode;
3215 if (op.mode == QPainter::CompositionMode_SourceOver && solidSource)
3216 op.mode = QPainter::CompositionMode_Source;
3218 op.dest_fetch = destFetchProc[data->rasterBuffer->format];
3219 if (op.mode == QPainter::CompositionMode_Source) {
3220 switch (data->rasterBuffer->format) {
3221 case QImage::Format_RGB32:
3222 case QImage::Format_ARGB32_Premultiplied:
3223 // don't clear dest_fetch as it sets up the pointer correctly to save one copy
3226 const QSpan *lastSpan = spans + spanCount;
3227 bool alphaSpans = false;
3228 while (spans < lastSpan) {
3229 if (spans->coverage != 255) {
3241 op.dest_store = destStoreProc[data->rasterBuffer->format];
3243 op.funcSolid = functionForModeSolid[op.mode];
3244 op.func = functionForMode[op.mode];
3251 // -------------------- blend methods ---------------------
3258 #if !defined(Q_CC_SUN)
3261 void drawBufferSpan(QSpanData *data, const uint *buffer, int bufsize,
3262 int x, int y, int length, uint const_alpha)
3264 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3265 data->rasterEngine->drawBufferSpan(buffer, bufsize, x, y, length, const_alpha);
3273 Q_UNUSED(const_alpha);
3277 #if !defined(Q_CC_SUN)
3280 void blend_color_generic(int count, const QSpan *spans, void *userData)
3282 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3283 uint buffer[buffer_size];
3284 Operator op = getOperator(data, spans, count);
3288 int length = spans->len;
3290 int l = qMin(buffer_size, length);
3291 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3292 op.funcSolid(dest, l, data->solid.color, spans->coverage);
3294 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3302 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3303 static void blend_color_generic_callback(int count, const QSpan *spans, void *userData)
3309 // QSpanData *data = reinterpret_cast<QSpanData*>(userData);
3310 // data->rasterEngine->drawColorSpans(spans, count, data->solid.color);
3312 #endif // QT_NO_RASTERCALLBACKS
3314 static void blend_color_argb(int count, const QSpan *spans, void *userData)
3316 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3318 Operator op = getOperator(data, spans, count);
3320 if (op.mode == QPainter::CompositionMode_Source) {
3321 // inline for performance
3323 uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3324 if (spans->coverage == 255) {
3325 QT_MEMFILL_UINT(target, spans->len, data->solid.color);
3327 uint c = BYTE_MUL(data->solid.color, spans->coverage);
3328 int ialpha = 255 - spans->coverage;
3329 for (int i = 0; i < spans->len; ++i)
3330 target[i] = c + BYTE_MUL(target[i], ialpha);
3338 uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3339 op.funcSolid(target, spans->len, data->solid.color, spans->coverage);
3345 Q_STATIC_TEMPLATE_FUNCTION void blendColor(int count, const QSpan *spans, void *userData)
3347 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3348 Operator op = getOperator(data, spans, count);
3350 if (op.mode == QPainter::CompositionMode_Source) {
3351 const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(data->solid.color), 0);
3353 T *target = ((T*)data->rasterBuffer->scanLine(spans->y))
3355 if (spans->coverage == 255) {
3356 qt_memfill(target, c, spans->len);
3358 const quint8 alpha = T::alpha(spans->coverage);
3359 const T color = c.byte_mul(alpha);
3360 const int ialpha = T::ialpha(spans->coverage);
3361 const T *end = target + spans->len;
3362 while (target < end) {
3363 *target = color + target->byte_mul(ialpha);
3372 if (op.mode == QPainter::CompositionMode_SourceOver) {
3374 const quint32 color = BYTE_MUL(data->solid.color, spans->coverage);
3375 const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0);
3376 const quint8 ialpha = T::alpha(qAlpha(~color));
3377 T *target = ((T*)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3378 const T *end = target + spans->len;
3379 while (target != end) {
3380 *target = c + target->byte_mul(ialpha);
3388 blend_color_generic(count, spans, userData);
3391 #define SPANFUNC_POINTER_BLENDCOLOR(DST) blendColor<DST>
3393 static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
3395 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3398 We duplicate a little logic from getOperator() and calculate the
3399 composition mode directly. This allows blend_color_rgb16 to be used
3400 from qt_gradient_quint16 with minimal overhead.
3402 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
3403 if (mode == QPainter::CompositionMode_SourceOver &&
3404 qAlpha(data->solid.color) == 255)
3405 mode = QPainter::CompositionMode_Source;
3407 if (mode == QPainter::CompositionMode_Source) {
3408 // inline for performance
3409 ushort c = qConvertRgb32To16(data->solid.color);
3411 ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3412 if (spans->coverage == 255) {
3413 QT_MEMFILL_USHORT(target, spans->len, c);
3415 ushort color = BYTE_MUL_RGB16(c, spans->coverage);
3416 int ialpha = 255 - spans->coverage;
3417 const ushort *end = target + spans->len;
3418 while (target < end) {
3419 *target = color + BYTE_MUL_RGB16(*target, ialpha);
3428 if (mode == QPainter::CompositionMode_SourceOver) {
3430 uint color = BYTE_MUL(data->solid.color, spans->coverage);
3431 int ialpha = qAlpha(~color);
3432 ushort c = qConvertRgb32To16(color);
3433 ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3434 int len = spans->len;
3435 bool pre = (((quintptr)target) & 0x3) != 0;
3438 // skip to word boundary
3439 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3447 uint *target32 = (uint*)target;
3448 uint c32 = c | (c<<16);
3450 uint salpha = (ialpha+1) >> 3; // calculate here rather than in loop
3453 *target32 = c32 + BYTE_MUL_RGB16_32(*target32, salpha);
3458 // one last pixel beyond a full word
3459 *target = c + BYTE_MUL_RGB16(*target, ialpha);
3466 blend_color_generic(count, spans, userData);
3469 template <typename T>
3470 void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
3472 uint const_alpha = 256;
3473 if (data->type == QSpanData::Texture)
3474 const_alpha = data->texture.const_alpha;
3479 const int y = spans->y;
3480 int right = x + spans->len;
3482 // compute length of adjacent spans
3483 for (int i = 1; i < count && spans[i].y == y && spans[i].x == right; ++i)
3484 right += spans[i].len;
3485 int length = right - x;
3488 int l = qMin(buffer_size, length);
3491 int process_length = l;
3494 const uint *src = handler.fetch(process_x, y, process_length);
3497 if (x == spans->x) // new span?
3498 coverage = (spans->coverage * const_alpha) >> 8;
3500 int right = spans->x + spans->len;
3501 int len = qMin(l, right - x);
3503 handler.process(x, y, len, coverage, src, offset);
3509 if (x == right) { // done with current span?
3514 handler.store(process_x, y, process_length);
3521 QBlendBase(QSpanData *d, Operator o)
3533 uint buffer[buffer_size];
3534 uint src_buffer[buffer_size];
3537 template <SpanMethod spanMethod>
3538 class BlendSrcGeneric : public QBlendBase
3541 BlendSrcGeneric(QSpanData *d, Operator o)
3546 const uint *fetch(int x, int y, int len)
3548 if (spanMethod == RegularSpans)
3549 dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, y, len) : buffer;
3551 return op.src_fetch(src_buffer, &op, data, y, x, len);
3554 void process(int x, int y, int len, int coverage, const uint *src, int offset)
3556 if (spanMethod == RegularSpans)
3557 op.func(dest + offset, src + offset, len, coverage);
3559 drawBufferSpan(data, src + offset, len, x, y, len, coverage);
3562 void store(int x, int y, int len)
3564 if (spanMethod == RegularSpans && op.dest_store) {
3565 op.dest_store(data->rasterBuffer, x, y, dest, len);
3570 template <SpanMethod spanMethod>
3571 Q_STATIC_TEMPLATE_FUNCTION void blend_src_generic(int count, const QSpan *spans, void *userData)
3573 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3574 BlendSrcGeneric<spanMethod> blend(data, getOperator(data, spans, count));
3575 handleSpans(count, spans, data, blend);
3578 template <SpanMethod spanMethod>
3579 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
3581 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3583 uint buffer[buffer_size];
3584 uint src_buffer[buffer_size];
3585 Operator op = getOperator(data, spans, count);
3587 const int image_width = data->texture.width;
3588 const int image_height = data->texture.height;
3589 int xoff = -qRound(-data->dx);
3590 int yoff = -qRound(-data->dy);
3594 int length = spans->len;
3596 int sy = yoff + spans->y;
3597 if (sy >= 0 && sy < image_height && sx < image_width) {
3603 if (sx + length > image_width)
3604 length = image_width - sx;
3606 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3608 int l = qMin(buffer_size, length);
3609 const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
3610 if (spanMethod == RegularSpans) {
3611 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3612 op.func(dest, src, l, coverage);
3614 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3616 drawBufferSpan(data, src, l, x, spans->y,
3629 template <SpanMethod spanMethod>
3630 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
3632 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3633 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
3634 && data->texture.format != QImage::Format_RGB32) {
3635 blend_untransformed_generic<spanMethod>(count, spans, userData);
3639 Operator op = getOperator(data, spans, count);
3641 const int image_width = data->texture.width;
3642 const int image_height = data->texture.height;
3643 int xoff = -qRound(-data->dx);
3644 int yoff = -qRound(-data->dy);
3648 int length = spans->len;
3650 int sy = yoff + spans->y;
3651 if (sy >= 0 && sy < image_height && sx < image_width) {
3657 if (sx + length > image_width)
3658 length = image_width - sx;
3660 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3661 const uint *src = (uint *)data->texture.scanLine(sy) + sx;
3662 if (spanMethod == RegularSpans) {
3663 uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
3664 op.func(dest, src, length, coverage);
3666 drawBufferSpan(data, src, length, x,
3667 spans->y, length, coverage);
3675 static inline quint16 interpolate_pixel_rgb16_255(quint16 x, quint8 a,
3676 quint16 y, quint8 b)
3678 quint16 t = ((((x & 0x07e0) * a) + ((y & 0x07e0) * b)) >> 5) & 0x07e0;
3679 t |= ((((x & 0xf81f) * a) + ((y & 0xf81f) * b)) >> 5) & 0xf81f;
3684 static inline quint32 interpolate_pixel_rgb16x2_255(quint32 x, quint8 a,
3685 quint32 y, quint8 b)
3688 t = ((((x & 0xf81f07e0) >> 5) * a) + (((y & 0xf81f07e0) >> 5) * b)) & 0xf81f07e0;
3689 t |= ((((x & 0x07e0f81f) * a) + ((y & 0x07e0f81f) * b)) >> 5) & 0x07e0f81f;
3693 static inline void blend_sourceOver_rgb16_rgb16(quint16 *dest,
3697 const quint8 ialpha)
3699 const int dstAlign = ((quintptr)dest) & 0x3;
3701 *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
3706 const int srcAlign = ((quintptr)src) & 0x3;
3707 int length32 = length >> 1;
3708 if (length32 && srcAlign == 0) {
3709 while (length32--) {
3710 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3711 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3712 *dest32 = interpolate_pixel_rgb16x2_255(*src32, alpha,
3720 *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
3726 template <class DST, class SRC>
3727 Q_STATIC_TEMPLATE_SPECIALIZATION
3728 inline void madd_2(DST *dest, const quint16 alpha, const SRC *src)
3730 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3731 Q_ASSERT((quintptr(src) & 0x3) == 0);
3732 dest[0] = dest[0].byte_mul(alpha >> 8) + DST(src[0]);
3733 dest[1] = dest[1].byte_mul(alpha & 0xff) + DST(src[1]);
3736 template <class DST, class SRC>
3737 Q_STATIC_TEMPLATE_SPECIALIZATION
3738 inline void madd_4(DST *dest, const quint32 alpha, const SRC *src)
3740 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3741 Q_ASSERT((quintptr(src) & 0x3) == 0);
3742 dest[0] = dest[0].byte_mul(alpha >> 24) + DST(src[0]);
3743 dest[1] = dest[1].byte_mul((alpha >> 16) & 0xff) + DST(src[1]);
3744 dest[2] = dest[2].byte_mul((alpha >> 8) & 0xff) + DST(src[2]);
3745 dest[3] = dest[3].byte_mul(alpha & 0xff) + DST(src[3]);
3748 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
3750 Q_STATIC_TEMPLATE_SPECIALIZATION
3751 inline void madd_4(qargb8565 *dest, const quint32 a, const qargb8565 *src)
3753 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3754 Q_ASSERT((quintptr(src) & 0x3) == 0);
3756 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3757 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3768 t = ((((x & 0x0007e0ff) * a8) >> 5) & 0x0007e0ff) + (y & 0x0007c0f8);
3771 t |= ((((x & 0x00f81f00) * a8) >> 5) & 0x00f81f00) + (y & 0x00f81f00);
3773 a8 = (a >> 16) & 0xff;
3776 t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
3785 t = ((((x & 0x0000f81f) * a8) >> 5) & 0x0000f81f) + (y & 0x0000f81f);
3788 t |= ((((x & 0x000007e0) * a8) >> 5) & 0x000007e0) + (y & 0x000007c0);
3790 a8 = (a >> 8) & 0xff;
3793 t |= ((((x & 0x00ff0000) * a8) >> 5) & 0x00ff0000) + (y & 0x00f80000);
3797 quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
3798 quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
3801 t16 = ((((x16 & 0xf81f) * a8) >> 5) & 0xf81f) + (y16 & 0xf81f);
3802 t16 |= ((((x16 & 0x07e0) * a8) >> 5) & 0x07e0) + (y16 & 0x07c0);
3805 t |= ((t16 & 0x00ff) << 24);
3820 t |= ((((x & 0x07e0ff00) * a8) >> 5) & 0x07e0ff00) + (y & 0x07c0f800);
3823 t |= ((((x & 0xf81f0000) >> 5) * a8) & 0xf81f0000)+ (y & 0xf81f0000);
3830 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
3832 Q_STATIC_TEMPLATE_SPECIALIZATION
3833 inline void madd_4(qargb8555 *dest, const quint32 a, const qargb8555 *src)
3835 Q_ASSERT((quintptr(dest) & 0x3) == 0);
3836 Q_ASSERT((quintptr(src) & 0x3) == 0);
3838 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3839 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3850 t = ((((x & 0x0003e0ff) * a8) >> 5) & 0x0003e0ff) + (y & 0x0003e0f8);
3853 t |= ((((x & 0x007c1f00) * a8) >> 5) & 0x007c1f00) + (y & 0x007c1f00);
3855 a8 = (a >> 16) & 0xff;
3858 t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
3867 t = ((((x & 0x00007c1f) * a8) >> 5) & 0x00007c1f) + (y & 0x00007c1f);
3870 t |= ((((x & 0x000003e0) * a8) >> 5) & 0x000003e0) + (y & 0x000003e0);
3872 a8 = (a >> 8) & 0xff;
3875 t |= ((((x & 0x00ff0000) * a8) >> 5) & 0x00ff0000) + (y & 0x00f80000);
3879 quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
3880 quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
3883 t16 = ((((x16 & 0x7c1f) * a8) >> 5) & 0x7c1f) + (y16 & 0x7c1f);
3884 t16 |= ((((x16 & 0x03e0) * a8) >> 5) & 0x03e0) + (y16 & 0x03e0);
3887 t |= ((t16 & 0x00ff) << 24);
3902 t |= ((((x & 0x03e0ff00) * a8) >> 5) & 0x03e0ff00) + (y & 0x03e0f800);
3905 t |= ((((x & 0x7c1f0000) >> 5) * a8) & 0x7c1f0000)+ (y & 0x7c1f0000);
3913 Q_STATIC_TEMPLATE_SPECIALIZATION
3914 inline quint16 alpha_2(const T *src)
3916 Q_ASSERT((quintptr(src) & 0x3) == 0);
3919 return (src[0].alpha() << 8) | src[1].alpha();
3925 Q_STATIC_TEMPLATE_SPECIALIZATION
3926 inline quint32 alpha_4(const T *src)
3928 Q_ASSERT((quintptr(src) & 0x3) == 0);
3930 if (T::hasAlpha()) {
3931 return (src[0].alpha() << 24) | (src[1].alpha() << 16)
3932 | (src[2].alpha() << 8) | src[3].alpha();
3939 Q_STATIC_TEMPLATE_SPECIALIZATION
3940 inline quint32 alpha_4(const qargb8565 *src)
3942 const quint8 *src8 = reinterpret_cast<const quint8*>(src);
3943 return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
3947 Q_STATIC_TEMPLATE_SPECIALIZATION
3948 inline quint32 alpha_4(const qargb6666 *src)
3950 const quint8 *src8 = reinterpret_cast<const quint8*>(src);
3951 return ((src8[2] & 0xfc) | (src8[2] >> 6)) << 24
3952 | ((src8[5] & 0xfc) | (src8[5] >> 6)) << 16
3953 | ((src8[8] & 0xfc) | (src8[8] >> 6)) << 8
3954 | ((src8[11] & 0xfc) | (src8[11] >> 6));
3958 Q_STATIC_TEMPLATE_SPECIALIZATION
3959 inline quint32 alpha_4(const qargb8555 *src)
3961 Q_ASSERT((quintptr(src) & 0x3) == 0);
3962 const quint8 *src8 = reinterpret_cast<const quint8*>(src);
3963 return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
3967 Q_STATIC_TEMPLATE_SPECIALIZATION
3968 inline quint16 alpha_2(const qargb4444 *src)
3970 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3971 const quint32 t = (*src32 & 0xf000f000) |
3972 ((*src32 & 0xf000f000) >> 4);
3973 return (t >> 24) | (t & 0xff00);
3977 Q_STATIC_TEMPLATE_SPECIALIZATION
3978 inline quint16 eff_alpha_2(quint16 alpha, const T*)
3980 return (T::alpha((alpha >> 8) & 0xff) << 8)
3981 | T::alpha(alpha & 0xff);
3985 Q_STATIC_TEMPLATE_SPECIALIZATION
3986 inline quint16 eff_alpha_2(quint16 a, const qrgb565*)
3988 return ((((a & 0xff00) + 0x0100) >> 3) & 0xff00)
3989 | ((((a & 0x00ff) + 0x0001) >> 3) & 0x00ff);
3993 Q_STATIC_TEMPLATE_SPECIALIZATION
3994 inline quint16 eff_alpha_2(quint16 a, const qrgb444*)
3996 return (((a & 0x00ff) + 0x0001) >> 4)
3997 | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
4001 Q_STATIC_TEMPLATE_SPECIALIZATION
4002 inline quint16 eff_alpha_2(quint16 a, const qargb4444*)
4004 return (((a & 0x00ff) + 0x0001) >> 4)
4005 | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
4009 Q_STATIC_TEMPLATE_SPECIALIZATION
4010 inline quint16 eff_ialpha_2(quint16 alpha, const T*)
4012 return (T::ialpha((alpha >> 8) & 0xff) << 8)
4013 | T::ialpha(alpha & 0xff);
4017 Q_STATIC_TEMPLATE_SPECIALIZATION
4018 inline quint16 eff_ialpha_2(quint16 a, const qrgb565 *dummy)
4020 return 0x2020 - eff_alpha_2(a, dummy);
4024 Q_STATIC_TEMPLATE_SPECIALIZATION
4025 inline quint16 eff_ialpha_2(quint16 a, const qargb4444 *dummy)
4027 return 0x1010 - eff_alpha_2(a, dummy);
4031 Q_STATIC_TEMPLATE_SPECIALIZATION
4032 inline quint16 eff_ialpha_2(quint16 a, const qrgb444 *dummy)
4034 return 0x1010 - eff_alpha_2(a, dummy);
4038 Q_STATIC_TEMPLATE_SPECIALIZATION
4039 inline quint32 eff_alpha_4(quint32 alpha, const T*)
4041 return (T::alpha(alpha >> 24) << 24)
4042 | (T::alpha((alpha >> 16) & 0xff) << 16)
4043 | (T::alpha((alpha >> 8) & 0xff) << 8)
4044 | T::alpha(alpha & 0xff);
4048 Q_STATIC_TEMPLATE_SPECIALIZATION
4049 inline quint32 eff_alpha_4(quint32 a, const qrgb888*)
4055 Q_STATIC_TEMPLATE_SPECIALIZATION
4056 inline quint32 eff_alpha_4(quint32 a, const qargb8565*)
4058 return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
4059 | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
4063 Q_STATIC_TEMPLATE_SPECIALIZATION
4064 inline quint32 eff_alpha_4(quint32 a, const qargb6666*)
4066 return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
4067 | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
4071 Q_STATIC_TEMPLATE_SPECIALIZATION
4072 inline quint32 eff_alpha_4(quint32 a, const qrgb666*)
4074 return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
4075 | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
4079 Q_STATIC_TEMPLATE_SPECIALIZATION
4080 inline quint32 eff_alpha_4(quint32 a, const qargb8555*)
4082 return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
4083 | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
4087 Q_STATIC_TEMPLATE_SPECIALIZATION
4088 inline quint32 eff_ialpha_4(quint32 alpha, const T*)
4090 return (T::ialpha(alpha >> 24) << 24)
4091 | (T::ialpha((alpha >> 16) & 0xff) << 16)
4092 | (T::ialpha((alpha >> 8) & 0xff) << 8)
4093 | T::ialpha(alpha & 0xff);
4097 Q_STATIC_TEMPLATE_SPECIALIZATION
4098 inline quint32 eff_ialpha_4(quint32 a, const qrgb888*)
4104 Q_STATIC_TEMPLATE_SPECIALIZATION
4105 inline quint32 eff_ialpha_4(quint32 a, const qargb8565 *dummy)
4107 return 0x20202020 - eff_alpha_4(a, dummy);
4111 Q_STATIC_TEMPLATE_SPECIALIZATION
4112 inline quint32 eff_ialpha_4(quint32 a, const qargb6666 *dummy)
4114 return 0x40404040 - eff_alpha_4(a, dummy);
4118 Q_STATIC_TEMPLATE_SPECIALIZATION
4119 inline quint32 eff_ialpha_4(quint32 a, const qrgb666 *dummy)
4121 return 0x40404040 - eff_alpha_4(a, dummy);
4125 Q_STATIC_TEMPLATE_SPECIALIZATION
4126 inline quint32 eff_ialpha_4(quint32 a, const qargb8555 *dummy)
4128 return 0x20202020 - eff_alpha_4(a, dummy);
4131 template <class DST, class SRC>
4132 inline void interpolate_pixel_unaligned_2(DST *dest, const SRC *src,
4135 const quint16 a = eff_alpha_2(alpha, dest);
4136 const quint16 ia = eff_ialpha_2(alpha, dest);
4137 dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
4138 dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
4141 template <class DST, class SRC>
4142 inline void interpolate_pixel_2(DST *dest, const SRC *src, quint16 alpha)
4144 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4145 Q_ASSERT((quintptr(src) & 0x3) == 0);
4147 const quint16 a = eff_alpha_2(alpha, dest);
4148 const quint16 ia = eff_ialpha_2(alpha, dest);
4150 dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
4151 dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
4154 template <class DST, class SRC>
4155 inline void interpolate_pixel(DST &dest, quint8 a, const SRC &src, quint8 b)
4157 if (SRC::hasAlpha() && !DST::hasAlpha())
4158 interpolate_pixel(dest, a, DST(src), b);
4160 dest = dest.byte_mul(a) + DST(src).byte_mul(b);
4164 inline void interpolate_pixel(qargb8565 &dest, quint8 a,
4165 const qargb8565 &src, quint8 b)
4167 quint8 *d = reinterpret_cast<quint8*>(&dest);
4168 const quint8 *s = reinterpret_cast<const quint8*>(&src);
4169 d[0] = (d[0] * a + s[0] * b) >> 5;
4171 const quint16 x = (d[2] << 8) | d[1];
4172 const quint16 y = (s[2] << 8) | s[1];
4173 quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
4174 t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
4181 inline void interpolate_pixel(qrgb565 &dest, quint8 a,
4182 const qrgb565 &src, quint8 b)
4184 const quint16 x = dest.rawValue();
4185 const quint16 y = src.rawValue();
4186 quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
4187 t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
4192 inline void interpolate_pixel(qrgb555 &dest, quint8 a,
4193 const qrgb555 &src, quint8 b)
4195 const quint16 x = dest.rawValue();
4196 const quint16 y = src.rawValue();
4197 quint16 t = (((x & 0x03e0) * a + (y & 0x03e0) * b) >> 5) & 0x03e0;
4198 t |= ((((x & 0x7c1f) * a) + ((y & 0x7c1f) * b)) >> 5) & 0x7c1f;
4203 inline void interpolate_pixel(qrgb444 &dest, quint8 a,
4204 const qrgb444 &src, quint8 b)
4206 const quint16 x = dest.rawValue();
4207 const quint16 y = src.rawValue();
4208 quint16 t = ((x & 0x00f0) * a + (y & 0x00f0) * b) & 0x0f00;
4209 t |= ((x & 0x0f0f) * a + (y & 0x0f0f) * b) & 0xf0f0;
4210 quint16 *d = reinterpret_cast<quint16*>(&dest);
4214 template <class DST, class SRC>
4215 inline void interpolate_pixel_2(DST *dest, quint8 a,
4216 const SRC *src, quint8 b)
4218 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4219 Q_ASSERT((quintptr(src) & 0x3) == 0);
4221 Q_ASSERT(!SRC::hasAlpha());
4223 dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
4224 dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
4228 inline void interpolate_pixel_2(qrgb565 *dest, quint8 a,
4229 const qrgb565 *src, quint8 b)
4231 quint32 *x = reinterpret_cast<quint32*>(dest);
4232 const quint32 *y = reinterpret_cast<const quint32*>(src);
4233 quint32 t = (((*x & 0xf81f07e0) >> 5) * a +
4234 ((*y & 0xf81f07e0) >> 5) * b) & 0xf81f07e0;
4235 t |= (((*x & 0x07e0f81f) * a
4236 + (*y & 0x07e0f81f) * b) >> 5) & 0x07e0f81f;
4241 inline void interpolate_pixel_2(qrgb555 *dest, quint8 a,
4242 const qrgb555 *src, quint8 b)
4244 quint32 *x = reinterpret_cast<quint32*>(dest);
4245 const quint32 *y = reinterpret_cast<const quint32*>(src);
4246 quint32 t = (((*x & 0x7c1f03e0) >> 5) * a +
4247 ((*y & 0x7c1f03e0) >> 5) * b) & 0x7c1f03e0;
4248 t |= (((*x & 0x03e07c1f) * a
4249 + (*y & 0x03e07c1f) * b) >> 5) & 0x03e07c1f;
4254 inline void interpolate_pixel_2(qrgb444 *dest, quint8 a,
4255 const qrgb444 *src, quint8 b)
4257 quint32 *x = reinterpret_cast<quint32*>(dest);
4258 const quint32 *y = reinterpret_cast<const quint32*>(src);
4259 quint32 t = ((*x & 0x0f0f0f0f) * a + (*y & 0x0f0f0f0f) * b) & 0xf0f0f0f0;
4260 t |= ((*x & 0x00f000f0) * a + (*y & 0x00f000f0) * b) & 0x0f000f00;
4264 template <class DST, class SRC>
4265 inline void interpolate_pixel_4(DST *dest, const SRC *src, quint32 alpha)
4267 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4268 Q_ASSERT((quintptr(src) & 0x3) == 0);
4270 const quint32 a = eff_alpha_4(alpha, dest);
4271 const quint32 ia = eff_ialpha_4(alpha, dest);
4272 dest[0] = DST(src[0]).byte_mul(a >> 24)
4273 + dest[0].byte_mul(ia >> 24);
4274 dest[1] = DST(src[1]).byte_mul((a >> 16) & 0xff)
4275 + dest[1].byte_mul((ia >> 16) & 0xff);
4276 dest[2] = DST(src[2]).byte_mul((a >> 8) & 0xff)
4277 + dest[2].byte_mul((ia >> 8) & 0xff);
4278 dest[3] = DST(src[3]).byte_mul(a & 0xff)
4279 + dest[3].byte_mul(ia & 0xff);
4282 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4284 inline void interpolate_pixel_4(qargb8565 *dest, const qargb8565 *src,
4287 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4288 Q_ASSERT((quintptr(src) & 0x3) == 0);
4290 const quint32 a = eff_alpha_4(alpha, dest);
4291 const quint32 ia = eff_ialpha_4(alpha, dest);
4292 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4293 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4305 t = (((x & 0x0007e0ff) * a8 + (y & 0x0007e0ff) * ia8) >> 5)
4309 t |= (((x & 0x00f81f00) * a8 + (y & 0x00f81f00) * ia8) >> 5)
4312 a8 = (a >> 16) & 0xff;
4313 ia8 = (ia >> 16) & 0xff;
4316 t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
4326 t = (((x & 0x0000f81f) * a8 + (y & 0x0000f81f) * ia8) >> 5)
4330 t |= (((x & 0x000007e0) * a8 + (y & 0x000007e0) * ia8) >> 5)
4333 a8 = (a >> 8) & 0xff;
4334 ia8 = (ia >> 8) & 0xff;
4337 t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
4342 quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
4343 quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
4346 t16 = (((x16 & 0xf81f) * a8 + (y16 & 0xf81f) * ia8) >> 5) & 0xf81f;
4347 t16 |= (((x16 & 0x07e0) * a8 + (y16 & 0x07e0) * ia8) >> 5) & 0x07e0;
4350 t |= ((t16 & 0x00ff) << 24);
4366 t |= (((x & 0x07e0ff00) * a8 + (y & 0x07e0ff00) * ia8) >> 5)
4370 t |= (((x & 0xf81f0000) >> 5) * a8 + ((y & 0xf81f0000) >> 5) * ia8)
4378 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4380 inline void interpolate_pixel_4(qargb8555 *dest, const qargb8555 *src,
4383 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4384 Q_ASSERT((quintptr(src) & 0x3) == 0);
4387 const quint32 a = eff_alpha_4(alpha, dest);
4388 const quint32 ia = eff_ialpha_4(alpha, dest);
4389 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4390 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4402 t = (((x & 0x0003e0ff) * a8 + (y & 0x0003e0ff) * ia8) >> 5)
4406 t |= (((x & 0x007c1f00) * a8 + (y & 0x007c1f00) * ia8) >> 5)
4409 a8 = (a >> 16) & 0xff;
4410 ia8 = (ia >> 16) & 0xff;
4413 t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
4423 t = (((x & 0x00007c1f) * a8 + (y & 0x00007c1f) * ia8) >> 5)
4427 t |= (((x & 0x000003e0) * a8 + (y & 0x000003e0) * ia8) >> 5)
4430 a8 = (a >> 8) & 0xff;
4431 ia8 = (ia >> 8) & 0xff;
4434 t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
4439 quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
4440 quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
4443 t16 = (((x16 & 0x7c1f) * a8 + (y16 & 0x7c1f) * ia8) >> 5) & 0x7c1f;
4444 t16 |= (((x16 & 0x03e0) * a8 + (y16 & 0x03e0) * ia8) >> 5) & 0x03e0;
4447 t |= ((t16 & 0x00ff) << 24);
4463 t |= (((x & 0x03e0ff00) * a8 + (y & 0x03e0ff00) * ia8) >> 5)
4467 t |= (((x & 0x7c1f0000) >> 5) * a8 + ((y & 0x7c1f0000) >> 5) * ia8)
4476 inline void interpolate_pixel_4(qrgb888 *dest, const qrgb888 *src,
4479 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4480 Q_ASSERT((quintptr(src) & 0x3) == 0);
4482 const quint32 a = eff_alpha_4(alpha, dest);
4483 const quint32 ia = eff_ialpha_4(alpha, dest);
4484 const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4485 quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4488 quint32 x = src32[0];
4489 quint32 y = dest32[0];
4492 t = ((x >> 8) & 0xff00ff) * (a >> 24)
4493 + ((y >> 8) & 0xff00ff) * (ia >> 24);
4494 t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4497 x = (x & 0xff0000) * (a >> 24)
4498 + (x & 0x0000ff) * ((a >> 16) & 0xff)
4499 + (y & 0xff0000) * (ia >> 24)
4500 + (y & 0x0000ff) * ((ia >> 16) & 0xff);
4501 x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4507 quint32 x = src32[1];
4508 quint32 y = dest32[1];
4511 t = ((x >> 8) & 0xff0000) * ((a >> 16) & 0xff)
4512 + ((x >> 8) & 0x0000ff) * ((a >> 8) & 0xff)
4513 + ((y >> 8) & 0xff0000) * ((ia >> 16) & 0xff)
4514 + ((y >> 8) & 0x0000ff) * ((ia >> 8) & 0xff);
4515 t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4518 x = (x & 0xff0000) * ((a >> 16) & 0xff)
4519 + (x & 0x0000ff) * ((a >> 8) & 0xff)
4520 + (y & 0xff0000) * ((ia >> 16) & 0xff)
4521 + (y & 0x0000ff) * ((ia >> 8) & 0xff);
4522 x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4528 quint32 x = src32[2];
4529 quint32 y = dest32[2];
4532 t = ((x >> 8) & 0xff0000) * ((a >> 8) & 0xff)
4533 + ((x >> 8) & 0x0000ff) * (a & 0xff)
4534 + ((y >> 8) & 0xff0000) * ((ia >> 8) & 0xff)
4535 + ((y >> 8) & 0x0000ff) * (ia & 0xff);
4536 t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4539 x = (x & 0xff00ff) * (a & 0xff)
4540 + (y & 0xff00ff) * (ia & 0xff);
4541 x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4548 template <class DST, class SRC>
4549 inline void interpolate_pixel_4(DST *dest, quint8 a,
4550 const SRC *src, quint8 b)
4552 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4553 Q_ASSERT((quintptr(src) & 0x3) == 0);
4555 dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
4556 dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
4557 dest[2] = dest[2].byte_mul(a) + DST(src[2]).byte_mul(b);
4558 dest[3] = dest[3].byte_mul(a) + DST(src[3]).byte_mul(b);
4561 template <class DST, class SRC>
4562 inline void blend_sourceOver_4(DST *dest, const SRC *src)
4564 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4565 Q_ASSERT((quintptr(src) & 0x3) == 0);
4567 const quint32 a = alpha_4(src);
4568 if (a == 0xffffffff) {
4569 qt_memconvert(dest, src, 4);
4571 quint32 buf[3]; // array of quint32 to get correct alignment
4572 qt_memconvert((DST*)(void*)buf, src, 4);
4573 madd_4(dest, eff_ialpha_4(a, dest), (DST*)(void*)buf);
4578 inline void blend_sourceOver_4(qargb8565 *dest, const qargb8565 *src)
4580 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4581 Q_ASSERT((quintptr(src) & 0x3) == 0);
4583 const quint32 a = alpha_4(src);
4584 if (a == 0xffffffff) {
4585 qt_memconvert(dest, src, 4);
4587 madd_4(dest, eff_ialpha_4(a, dest), src);
4592 inline void blend_sourceOver_4(qargb8555 *dest, const qargb8555 *src)
4594 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4595 Q_ASSERT((quintptr(src) & 0x3) == 0);
4597 const quint32 a = alpha_4(src);
4598 if (a == 0xffffffff) {
4599 qt_memconvert(dest, src, 4);
4601 madd_4(dest, eff_ialpha_4(a, dest), src);
4606 inline void blend_sourceOver_4(qargb6666 *dest, const qargb6666 *src)
4608 Q_ASSERT((quintptr(dest) & 0x3) == 0);
4609 Q_ASSERT((quintptr(src) & 0x3) == 0);
4611 const quint32 a = alpha_4(src);
4612 if (a == 0xffffffff) {
4613 qt_memconvert(dest, src, 4);
4615 madd_4(dest, eff_ialpha_4(a, dest), src);
4619 template <class DST, class SRC>
4620 void QT_FASTCALL blendUntransformed_unaligned(DST *dest, const SRC *src,
4621 quint8 coverage, int length)
4623 Q_ASSERT(coverage > 0);
4625 if (coverage < 255) {
4626 if (SRC::hasAlpha()) {
4627 for (int i = 0; i < length; ++i) {
4628 if (src[i].alpha()) {
4629 const quint8 alpha = qt_div_255(int(src[i].alpha()) * int(coverage));
4630 interpolate_pixel(dest[i], DST::ialpha(alpha),
4631 src[i], DST::alpha(alpha));
4635 const quint8 alpha = DST::alpha(coverage);
4636 const quint8 ialpha = DST::ialpha(coverage);
4638 for (int i = 0; i < length; ++i)
4639 interpolate_pixel(dest[i], ialpha, src[i], alpha);
4645 Q_ASSERT(coverage == 0xff);
4646 Q_ASSERT(SRC::hasAlpha());
4648 if (SRC::hasAlpha()) {
4649 for (int i = 0; i < length; ++i) {
4650 const quint8 a = src->alpha();
4654 if (DST::hasAlpha())
4655 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4657 *dest = DST(SRC(*src).truncedAlpha()) + dest->byte_mul(DST::ialpha(a));
4665 template <class DST, class SRC>
4666 void QT_FASTCALL blendUntransformed_dest16(DST *dest, const SRC *src,
4667 quint8 coverage, int length)
4669 Q_ASSERT(sizeof(DST) == 2);
4670 Q_ASSERT(sizeof(SRC) == 2);
4671 Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
4672 Q_ASSERT(coverage > 0);
4674 const int align = quintptr(dest) & 0x3;
4676 if (coverage < 255) {
4679 const quint8 alpha = SRC::hasAlpha()
4680 ? qt_div_255(int(src->alpha()) * int(coverage))
4683 interpolate_pixel(*dest, DST::ialpha(alpha),
4684 *src, DST::alpha(alpha));
4691 if (SRC::hasAlpha()) {
4692 while (length >= 2) {
4693 const quint16 alpha16 = BYTE_MUL(uint(alpha_2(src)), uint(coverage));
4694 interpolate_pixel_2(dest, src, alpha16);
4700 const quint8 alpha = DST::alpha(coverage);
4701 const quint8 ialpha = DST::ialpha(coverage);
4703 while (length >= 2) {
4704 interpolate_pixel_2(dest, ialpha, src, alpha);
4713 const quint8 alpha = SRC::hasAlpha()
4714 ? qt_div_255(int(src->alpha()) * int(coverage))
4717 interpolate_pixel(*dest, DST::ialpha(alpha),
4718 *src, DST::alpha(alpha));
4725 Q_ASSERT(SRC::hasAlpha());
4726 if (SRC::hasAlpha()) {
4728 const quint8 alpha = src->alpha();
4732 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
4738 while (length >= 2) {
4739 Q_ASSERT((quintptr(dest) & 3) == 0);
4740 Q_ASSERT((quintptr(src) & 3) == 0);
4742 const quint16 a = alpha_2(src);
4744 qt_memconvert(dest, src, 2);
4747 if (sizeof(DST) == 2)
4748 qt_memconvert((DST*)(void*)&buf, src, 2);
4749 madd_2(dest, eff_ialpha_2(a, dest), (DST*)(void*)&buf);
4758 const quint8 alpha = src->alpha();
4762 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
4767 template <class DST, class SRC>
4768 void QT_FASTCALL blendUntransformed_dest24(DST *dest, const SRC *src,
4769 quint8 coverage, int length)
4771 Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
4772 Q_ASSERT(sizeof(DST) == 3);
4773 Q_ASSERT(coverage > 0);
4775 const int align = quintptr(dest) & 0x3;
4777 if (coverage < 255) {
4779 for (int i = 0; i < align; ++i) {
4780 if (SRC::hasAlpha()) {
4781 const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
4783 interpolate_pixel(*dest, DST::ialpha(alpha),
4784 *src, DST::alpha(alpha));
4786 interpolate_pixel(*dest, DST::ialpha(coverage),
4787 *src, DST::alpha(coverage));
4794 if (SRC::hasAlpha()) {
4795 while (length >= 4) {
4796 const quint32 alpha = QT_PREPEND_NAMESPACE(BYTE_MUL)(uint(alpha_4(src)), uint(coverage));
4798 interpolate_pixel_4(dest, src, alpha);
4804 const quint8 alpha = DST::alpha(coverage);
4805 const quint8 ialpha = DST::ialpha(coverage);
4806 while (length >= 4) {
4807 interpolate_pixel_4(dest, ialpha, src, alpha);
4816 if (SRC::hasAlpha()) {
4817 const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
4819 interpolate_pixel(*dest, DST::ialpha(alpha),
4820 *src, DST::alpha(alpha));
4822 interpolate_pixel(*dest, DST::ialpha(coverage),
4823 *src, DST::alpha(coverage));
4833 Q_ASSERT(coverage == 255);
4834 Q_ASSERT(SRC::hasAlpha());
4836 if (SRC::hasAlpha()) {
4838 for (int i = 0; i < align; ++i) {
4839 const quint8 a = src->alpha();
4843 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4850 while (length >= 4) {
4851 blend_sourceOver_4(dest, src);
4859 const quint8 a = src->alpha();
4863 *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4871 template <class DST, class SRC>
4872 Q_STATIC_TEMPLATE_SPECIALIZATION
4873 void QT_FASTCALL blendUntransformed(int count, const QSpan *spans, void *userData)
4875 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4876 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
4878 if (mode != QPainter::CompositionMode_SourceOver &&
4879 mode != QPainter::CompositionMode_Source)
4881 blend_src_generic<RegularSpans>(count, spans, userData);
4885 const bool modeSource = !SRC::hasAlpha() ||
4886 mode == QPainter::CompositionMode_Source;
4887 const int image_width = data->texture.width;
4888 const int image_height = data->texture.height;
4889 int xoff = -qRound(-data->dx);
4890 int yoff = -qRound(-data->dy);
4893 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4894 if (coverage == 0) {
4900 int length = spans->len;
4902 int sy = yoff + spans->y;
4903 if (sy >= 0 && sy < image_height && sx < image_width) {
4909 if (sx + length > image_width)
4910 length = image_width - sx;
4912 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
4913 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
4914 if (modeSource && coverage == 255) {
4915 qt_memconvert<DST, SRC>(dest, src, length);
4916 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && length >= 3 &&
4917 (quintptr(dest) & 3) == (quintptr(src) & 3))
4919 blendUntransformed_dest24(dest, src, coverage, length);
4920 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && length >= 3 &&
4921 (quintptr(dest) & 3) == (quintptr(src) & 3))
4923 blendUntransformed_dest16(dest, src, coverage, length);
4925 blendUntransformed_unaligned(dest, src, coverage, length);
4933 static void blend_untransformed_rgb888(int count, const QSpan *spans,
4936 #if defined(QT_QWS_DEPTH_24)
4937 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4939 if (data->texture.format == QImage::Format_RGB888)
4940 blendUntransformed<qrgb888, qrgb888>(count, spans, userData);
4943 blend_untransformed_generic<RegularSpans>(count, spans, userData);
4946 static void blend_untransformed_argb6666(int count, const QSpan *spans,
4949 #if defined(QT_QWS_DEPTH_18)
4950 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4952 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
4953 blendUntransformed<qargb6666, qargb6666>(count, spans, userData);
4954 else if (data->texture.format == QImage::Format_RGB666)
4955 blendUntransformed<qargb6666, qrgb666>(count, spans, userData);
4958 blend_untransformed_generic<RegularSpans>(count, spans, userData);
4961 static void blend_untransformed_rgb666(int count, const QSpan *spans,
4964 #if defined(QT_QWS_DEPTH_18)
4965 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4967 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
4968 blendUntransformed<qrgb666, qargb6666>(count, spans, userData);
4969 else if (data->texture.format == QImage::Format_RGB666)
4970 blendUntransformed<qrgb666, qrgb666>(count, spans, userData);
4973 blend_untransformed_generic<RegularSpans>(count, spans, userData);
4976 static void blend_untransformed_argb8565(int count, const QSpan *spans,
4979 #if defined(QT_QWS_DEPTH_16)
4980 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4982 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
4983 blendUntransformed<qargb8565, qargb8565>(count, spans, userData);
4984 else if (data->texture.format == QImage::Format_RGB16)
4985 blendUntransformed<qargb8565, qrgb565>(count, spans, userData);
4988 blend_untransformed_generic<RegularSpans>(count, spans, userData);
4991 static void blend_untransformed_rgb565(int count, const QSpan *spans,
4994 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
4995 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4997 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
4998 blendUntransformed<qrgb565, qargb8565>(count, spans, userData);
4999 else if (data->texture.format == QImage::Format_RGB16)
5000 blendUntransformed<qrgb565, qrgb565>(count, spans, userData);
5003 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5006 static void blend_untransformed_argb8555(int count, const QSpan *spans,
5009 #if defined(QT_QWS_DEPTH_15)
5010 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5012 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5013 blendUntransformed<qargb8555, qargb8555>(count, spans, userData);
5014 else if (data->texture.format == QImage::Format_RGB555)
5015 blendUntransformed<qargb8555, qrgb555>(count, spans, userData);
5018 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5021 static void blend_untransformed_rgb555(int count, const QSpan *spans,
5024 #if defined(QT_QWS_DEPTH_15)
5025 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5027 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5028 blendUntransformed<qrgb555, qargb8555>(count, spans, userData);
5029 else if (data->texture.format == QImage::Format_RGB555)
5030 blendUntransformed<qrgb555, qrgb555>(count, spans, userData);
5033 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5036 static void blend_untransformed_argb4444(int count, const QSpan *spans,
5039 #if defined(QT_QWS_DEPTH_12)
5040 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5042 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5043 blendUntransformed<qargb4444, qargb4444>(count, spans, userData);
5044 else if (data->texture.format == QImage::Format_RGB444)
5045 blendUntransformed<qargb4444, qrgb444>(count, spans, userData);
5048 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5051 static void blend_untransformed_rgb444(int count, const QSpan *spans,
5054 #if defined(QT_QWS_DEPTH_12)
5055 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5057 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5058 blendUntransformed<qrgb444, qargb4444>(count, spans, userData);
5059 else if (data->texture.format == QImage::Format_RGB444)
5060 blendUntransformed<qrgb444, qrgb444>(count, spans, userData);
5063 blend_untransformed_generic<RegularSpans>(count, spans, userData);
5066 template <SpanMethod spanMethod>
5067 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_generic(int count, const QSpan *spans, void *userData)
5069 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5071 uint buffer[buffer_size];
5072 uint src_buffer[buffer_size];
5073 Operator op = getOperator(data, spans, count);
5075 const int image_width = data->texture.width;
5076 const int image_height = data->texture.height;
5077 int xoff = -qRound(-data->dx) % image_width;
5078 int yoff = -qRound(-data->dy) % image_height;
5081 xoff += image_width;
5083 yoff += image_height;
5087 int length = spans->len;
5088 int sx = (xoff + spans->x) % image_width;
5089 int sy = (spans->y + yoff) % image_height;
5095 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5097 int l = qMin(image_width - sx, length);
5098 if (buffer_size < l)
5100 const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
5101 if (spanMethod == RegularSpans) {
5102 uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
5103 op.func(dest, src, l, coverage);
5105 op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
5107 drawBufferSpan(data, src, l, x, spans->y, l,
5113 if (sx >= image_width)
5120 template <SpanMethod spanMethod>
5121 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_argb(int count, const QSpan *spans, void *userData)
5123 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5124 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
5125 && data->texture.format != QImage::Format_RGB32) {
5126 blend_tiled_generic<spanMethod>(count, spans, userData);
5130 Operator op = getOperator(data, spans, count);
5132 int image_width = data->texture.width;
5133 int image_height = data->texture.height;
5134 int xoff = -qRound(-data->dx) % image_width;
5135 int yoff = -qRound(-data->dy) % image_height;
5138 xoff += image_width;
5140 yoff += image_height;
5144 int length = spans->len;
5145 int sx = (xoff + spans->x) % image_width;
5146 int sy = (spans->y + yoff) % image_height;
5152 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5154 int l = qMin(image_width - sx, length);
5155 if (buffer_size < l)
5157 const uint *src = (uint *)data->texture.scanLine(sy) + sx;
5158 if (spanMethod == RegularSpans) {
5159 uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
5160 op.func(dest, src, l, coverage);
5162 drawBufferSpan(data, src, buffer_size,
5163 x, spans->y, l, coverage);
5173 template <class DST, class SRC>
5174 Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *userData)
5176 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5177 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5179 if (mode != QPainter::CompositionMode_SourceOver &&
5180 mode != QPainter::CompositionMode_Source)
5182 blend_src_generic<RegularSpans>(count, spans, userData);
5186 const bool modeSource = !SRC::hasAlpha() ||
5187 mode == QPainter::CompositionMode_Source;
5188 const int image_width = data->texture.width;
5189 const int image_height = data->texture.height;
5190 int xoff = -qRound(-data->dx) % image_width;
5191 int yoff = -qRound(-data->dy) % image_height;
5194 xoff += image_width;
5196 yoff += image_height;
5199 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5200 if (coverage == 0) {
5206 int length = spans->len;
5207 int sx = (xoff + spans->x) % image_width;
5208 int sy = (spans->y + yoff) % image_height;
5214 if (modeSource && coverage == 255) {
5215 // Copy the first texture block
5216 length = qMin(image_width,length);
5219 int l = qMin(image_width - sx, length);
5220 if (buffer_size < l)
5222 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + tx;
5223 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5225 qt_memconvert<DST, SRC>(dest, src, l);
5231 // Now use the rasterBuffer as the source of the texture,
5232 // We can now progressively copy larger blocks
5233 // - Less cpu time in code figuring out what to copy
5234 // We are dealing with one block of data
5235 // - More likely to fit in the cache
5237 int copy_image_width = qMin(image_width, int(spans->len));
5238 length = spans->len - copy_image_width;
5239 DST *src = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5240 DST *dest = src + copy_image_width;
5241 while (copy_image_width < length) {
5242 qt_memconvert(dest, src, copy_image_width);
5243 dest += copy_image_width;
5244 length -= copy_image_width;
5245 copy_image_width *= 2;
5248 qt_memconvert(dest, src, length);
5251 int l = qMin(image_width - sx, length);
5252 if (buffer_size < l)
5254 DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5255 const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5256 if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5257 (quintptr(dest) & 3) == (quintptr(src) & 3))
5259 blendUntransformed_dest24(dest, src, coverage, l);
5260 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5261 (quintptr(dest) & 3) == (quintptr(src) & 3))
5263 blendUntransformed_dest16(dest, src, coverage, l);
5265 blendUntransformed_unaligned(dest, src, coverage, l);
5277 static void blend_tiled_rgb888(int count, const QSpan *spans, void *userData)
5279 #if defined(QT_QWS_DEPTH_24)
5280 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5282 if (data->texture.format == QImage::Format_RGB888)
5283 blendTiled<qrgb888, qrgb888>(count, spans, userData);
5286 blend_tiled_generic<RegularSpans>(count, spans, userData);
5289 static void blend_tiled_argb6666(int count, const QSpan *spans, void *userData)
5291 #if defined(QT_QWS_DEPTH_18)
5292 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5294 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
5295 blendTiled<qargb6666, qargb6666>(count, spans, userData);
5296 else if (data->texture.format == QImage::Format_RGB666)
5297 blendTiled<qargb6666, qrgb666>(count, spans, userData);
5300 blend_tiled_generic<RegularSpans>(count, spans, userData);
5303 static void blend_tiled_rgb666(int count, const QSpan *spans, void *userData)
5305 #if defined(QT_QWS_DEPTH_18)
5306 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5308 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
5309 blendTiled<qrgb666, qargb6666>(count, spans, userData);
5310 else if (data->texture.format == QImage::Format_RGB666)
5311 blendTiled<qrgb666, qrgb666>(count, spans, userData);
5314 blend_tiled_generic<RegularSpans>(count, spans, userData);
5317 static void blend_tiled_argb8565(int count, const QSpan *spans, void *userData)
5319 #if defined(QT_QWS_DEPTH_16)
5320 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5322 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5323 blendTiled<qargb8565, qargb8565>(count, spans, userData);
5324 else if (data->texture.format == QImage::Format_RGB16)
5325 blendTiled<qargb8565, qrgb565>(count, spans, userData);
5328 blend_tiled_generic<RegularSpans>(count, spans, userData);
5331 static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
5333 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
5334 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5336 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5337 blendTiled<qrgb565, qargb8565>(count, spans, userData);
5338 else if (data->texture.format == QImage::Format_RGB16)
5339 blendTiled<qrgb565, qrgb565>(count, spans, userData);
5342 blend_tiled_generic<RegularSpans>(count, spans, userData);
5345 static void blend_tiled_argb8555(int count, const QSpan *spans, void *userData)
5347 #if defined(QT_QWS_DEPTH_15)
5348 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5350 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5351 blendTiled<qargb8555, qargb8555>(count, spans, userData);
5352 else if (data->texture.format == QImage::Format_RGB555)
5353 blendTiled<qargb8555, qrgb555>(count, spans, userData);
5356 blend_tiled_generic<RegularSpans>(count, spans, userData);
5359 static void blend_tiled_rgb555(int count, const QSpan *spans, void *userData)
5361 #if defined(QT_QWS_DEPTH_15)
5362 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5364 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5365 blendTiled<qrgb555, qargb8555>(count, spans, userData);
5366 else if (data->texture.format == QImage::Format_RGB555)
5367 blendTiled<qrgb555, qrgb555>(count, spans, userData);
5370 blend_tiled_generic<RegularSpans>(count, spans, userData);
5373 static void blend_tiled_argb4444(int count, const QSpan *spans, void *userData)
5375 #if defined(QT_QWS_DEPTH_12)
5376 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5378 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5379 blendTiled<qargb4444, qargb4444>(count, spans, userData);
5380 else if (data->texture.format == QImage::Format_RGB444)
5381 blendTiled<qargb4444, qrgb444>(count, spans, userData);
5384 blend_tiled_generic<RegularSpans>(count, spans, userData);
5387 static void blend_tiled_rgb444(int count, const QSpan *spans, void *userData)
5389 #if defined(QT_QWS_DEPTH_12)
5390 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5392 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5393 blendTiled<qrgb444, qargb4444>(count, spans, userData);
5394 else if (data->texture.format == QImage::Format_RGB444)
5395 blendTiled<qrgb444, qrgb444>(count, spans, userData);
5398 blend_tiled_generic<RegularSpans>(count, spans, userData);
5401 template <class DST, class SRC>
5402 Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan *spans,
5405 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5406 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5409 if (mode != QPainter::CompositionMode_SourceOver) {
5410 blend_src_generic<RegularSpans>(count, spans, userData);
5414 SRC buffer[buffer_size];
5416 const int src_minx = data->texture.x1;
5417 const int src_miny = data->texture.y1;
5418 const int src_maxx = data->texture.x2 - 1;
5419 const int src_maxy = data->texture.y2 - 1;
5421 if (data->fast_matrix) {
5422 // The increment pr x in the scanline
5423 const int fdx = (int)(data->m11 * fixed_scale);
5424 const int fdy = (int)(data->m12 * fixed_scale);
5427 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5428 if (coverage == 0) {
5433 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5435 const qreal cx = spans->x + qreal(0.5);
5436 const qreal cy = spans->y + qreal(0.5);
5437 int x = int((data->m21 * cy
5438 + data->m11 * cx + data->dx) * fixed_scale) - half_point;
5439 int y = int((data->m22 * cy
5440 + data->m12 * cx + data->dy) * fixed_scale) - half_point;
5441 int length = spans->len;
5444 const int l = qMin(length, buffer_size);
5446 const SRC *end = buffer + l;
5454 const int distx = (x & 0x0000ffff) >> 8;
5455 const int disty = (y & 0x0000ffff) >> 8;
5457 if (x1 < src_minx) {
5459 } else if (x1 >= src_maxx) {
5464 if (y1 < src_miny) {
5466 } else if (y1 >= src_maxy) {
5474 *b = ((SRC*)data->texture.scanLine(y1))[x1];
5476 *b = ((SRC*)data->texture.scanLine(y1))[x1];
5477 const SRC t = data->texture.scanLine(y2)[x1];
5478 interpolate_pixel(*b, SRC::ialpha(disty),
5479 t, SRC::alpha(disty));
5481 } else if (y1 == y2) {
5482 *b = ((SRC*)data->texture.scanLine(y1))[x1];
5483 const SRC t = ((SRC*)data->texture.scanLine(y1))[x2];
5484 interpolate_pixel(*b, SRC::ialpha(distx),
5485 t, SRC::alpha(distx));
5489 const SRC *src1 = (SRC*)data->texture.scanLine(y1);
5490 const SRC *src2 = (SRC*)data->texture.scanLine(y2);
5492 const SRC tr = src1[x2];
5494 const SRC br = src2[x2];
5495 const quint8 ax = SRC::alpha(distx);
5496 const quint8 iax = SRC::ialpha(distx);
5498 interpolate_pixel(tl, iax, tr, ax);
5499 interpolate_pixel(bl, iax, br, ax);
5500 interpolate_pixel(tl, SRC::ialpha(disty),
5501 bl, SRC::alpha(disty));
5510 if (!SRC::hasAlpha() && coverage == 255) {
5511 qt_memconvert(dest, buffer, l);
5512 } else if (sizeof(DST) == 3 && l >= 4 &&
5513 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5515 blendUntransformed_dest24(dest, buffer, coverage, l);
5516 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5517 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5518 blendUntransformed_dest16(dest, buffer, coverage, l);
5520 blendUntransformed_unaligned(dest, buffer, coverage, l);
5529 const qreal fdx = data->m11;
5530 const qreal fdy = data->m12;
5531 const qreal fdw = data->m13;
5534 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5535 if (coverage == 0) {
5540 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5543 const qreal cx = spans->x + qreal(0.5);
5544 const qreal cy = spans->y + qreal(0.5);
5546 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5547 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5548 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5550 int length = spans->len;
5552 const int l = qMin(length, buffer_size);
5553 const SRC *end = buffer + l;
5556 const qreal iw = w == 0 ? 1 : 1 / w;
5557 const qreal px = x * iw - qreal(0.5);
5558 const qreal py = y * iw - qreal(0.5);
5560 int x1 = int(px) - (px < 0);
5562 int y1 = int(py) - (py < 0);
5565 const int distx = int((px - x1) * 256);
5566 const int disty = int((py - y1) * 256);
5568 if (x1 < src_minx) {
5570 } else if (x1 >= src_maxx) {
5575 if (y1 < src_miny) {
5577 } else if (y1 >= src_maxy) {
5583 const SRC *src1 = (SRC*)data->texture.scanLine(y1);
5584 const SRC *src2 = (SRC*)data->texture.scanLine(y2);
5586 const SRC tr = src1[x2];
5588 const SRC br = src2[x2];
5589 const quint8 ax = SRC::alpha(distx);
5590 const quint8 iax = SRC::ialpha(distx);
5592 interpolate_pixel(tl, iax, tr, ax);
5593 interpolate_pixel(bl, iax, br, ax);
5594 interpolate_pixel(tl, SRC::ialpha(disty),
5595 bl, SRC::alpha(disty));
5603 if (!SRC::hasAlpha() && coverage == 255) {
5604 qt_memconvert(dest, buffer, l);
5605 } else if (sizeof(DST) == 3 && l >= 4 &&
5606 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5608 blendUntransformed_dest24(dest, buffer, coverage, l);
5609 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5610 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5611 blendUntransformed_dest16(dest, buffer, coverage, l);
5613 blendUntransformed_unaligned(dest, buffer, coverage, l);
5624 static void blend_transformed_bilinear_rgb888(int count, const QSpan *spans, void *userData)
5626 #if defined(QT_QWS_DEPTH_24)
5627 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5629 if (data->texture.format == QImage::Format_RGB888)
5630 blendTransformedBilinear<qrgb888, qrgb888>(count, spans, userData);
5633 blend_src_generic<RegularSpans>(count, spans, userData);
5636 static void blend_transformed_bilinear_argb6666(int count, const QSpan *spans, void *userData)
5638 #if defined(QT_QWS_DEPTH_18)
5639 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5641 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
5642 blendTransformedBilinear<qargb6666, qargb6666>(count, spans, userData);
5643 else if (data->texture.format == QImage::Format_RGB666)
5644 blendTransformedBilinear<qargb6666, qrgb666>(count, spans, userData);
5647 blend_src_generic<RegularSpans>(count, spans, userData);
5650 static void blend_transformed_bilinear_rgb666(int count, const QSpan *spans, void *userData)
5652 #if defined(QT_QWS_DEPTH_18)
5653 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5655 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
5656 blendTransformedBilinear<qrgb666, qargb6666>(count, spans, userData);
5657 else if (data->texture.format == QImage::Format_RGB666)
5658 blendTransformedBilinear<qrgb666, qrgb666>(count, spans, userData);
5661 blend_src_generic<RegularSpans>(count, spans, userData);
5664 static void blend_transformed_bilinear_argb8565(int count, const QSpan *spans, void *userData)
5666 #if defined(QT_QWS_DEPTH_16)
5667 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5669 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5670 blendTransformedBilinear<qargb8565, qargb8565>(count, spans, userData);
5671 else if (data->texture.format == QImage::Format_RGB16)
5672 blendTransformedBilinear<qargb8565, qrgb565>(count, spans, userData);
5675 blend_src_generic<RegularSpans>(count, spans, userData);
5678 static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans,
5681 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
5682 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5684 if (data->texture.format == QImage::Format_RGB16)
5685 blendTransformedBilinear<qrgb565, qrgb565>(count, spans, userData);
5686 else if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
5687 blendTransformedBilinear<qrgb565, qargb8565>(count, spans, userData);
5690 blend_src_generic<RegularSpans>(count, spans, userData);
5693 static void blend_transformed_bilinear_argb8555(int count, const QSpan *spans, void *userData)
5695 #if defined(QT_QWS_DEPTH_15)
5696 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5698 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5699 blendTransformedBilinear<qargb8555, qargb8555>(count, spans, userData);
5700 else if (data->texture.format == QImage::Format_RGB555)
5701 blendTransformedBilinear<qargb8555, qrgb555>(count, spans, userData);
5704 blend_src_generic<RegularSpans>(count, spans, userData);
5707 static void blend_transformed_bilinear_rgb555(int count, const QSpan *spans, void *userData)
5709 #if defined(QT_QWS_DEPTH_15)
5710 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5712 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
5713 blendTransformedBilinear<qrgb555, qargb8555>(count, spans, userData);
5714 else if (data->texture.format == QImage::Format_RGB555)
5715 blendTransformedBilinear<qrgb555, qrgb555>(count, spans, userData);
5718 blend_src_generic<RegularSpans>(count, spans, userData);
5721 static void blend_transformed_bilinear_argb4444(int count, const QSpan *spans, void *userData)
5723 #if defined(QT_QWS_DEPTH_12)
5724 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5726 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5727 blendTransformedBilinear<qargb4444, qargb4444>(count, spans, userData);
5728 else if (data->texture.format == QImage::Format_RGB444)
5729 blendTransformedBilinear<qargb4444, qrgb444>(count, spans, userData);
5732 blend_src_generic<RegularSpans>(count, spans, userData);
5735 static void blend_transformed_bilinear_rgb444(int count, const QSpan *spans, void *userData)
5737 #if defined(QT_QWS_DEPTH_12)
5738 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5740 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
5741 blendTransformedBilinear<qrgb444, qargb4444>(count, spans, userData);
5742 else if (data->texture.format == QImage::Format_RGB444)
5743 blendTransformedBilinear<qrgb444, qrgb444>(count, spans, userData);
5746 blend_src_generic<RegularSpans>(count, spans, userData);
5749 template <SpanMethod spanMethod>
5750 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *spans, void *userData)
5752 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5753 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
5754 && data->texture.format != QImage::Format_RGB32) {
5755 blend_src_generic<spanMethod>(count, spans, userData);
5759 CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
5760 uint buffer[buffer_size];
5762 int image_width = data->texture.width;
5763 int image_height = data->texture.height;
5764 const int scanline_offset = data->texture.bytesPerLine / 4;
5766 if (data->fast_matrix) {
5767 // The increment pr x in the scanline
5768 int fdx = (int)(data->m11 * fixed_scale);
5769 int fdy = (int)(data->m12 * fixed_scale);
5772 void *t = data->rasterBuffer->scanLine(spans->y);
5774 uint *target = ((uint *)t) + spans->x;
5775 uint *image_bits = (uint *)data->texture.imageData;
5777 const qreal cx = spans->x + qreal(0.5);
5778 const qreal cy = spans->y + qreal(0.5);
5780 int x = int((data->m21 * cy
5781 + data->m11 * cx + data->dx) * fixed_scale);
5782 int y = int((data->m22 * cy
5783 + data->m12 * cx + data->dy) * fixed_scale);
5785 int length = spans->len;
5786 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5788 int l = qMin(length, buffer_size);
5789 const uint *end = buffer + l;
5795 bool out = (px < 0) || (px >= image_width)
5796 || (py < 0) || (py >= image_height);
5798 int y_offset = py * scanline_offset;
5799 *b = out ? uint(0) : image_bits[y_offset + px];
5804 if (spanMethod == RegularSpans)
5805 func(target, buffer, l, coverage);
5807 drawBufferSpan(data, buffer, buffer_size,
5808 spans->x + spans->len - length,
5809 spans->y, l, coverage);
5816 const qreal fdx = data->m11;
5817 const qreal fdy = data->m12;
5818 const qreal fdw = data->m13;
5820 void *t = data->rasterBuffer->scanLine(spans->y);
5822 uint *target = ((uint *)t) + spans->x;
5823 uint *image_bits = (uint *)data->texture.imageData;
5825 const qreal cx = spans->x + qreal(0.5);
5826 const qreal cy = spans->y + qreal(0.5);
5828 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5829 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5830 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5832 int length = spans->len;
5833 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5835 int l = qMin(length, buffer_size);
5836 const uint *end = buffer + l;
5839 const qreal iw = w == 0 ? 1 : 1 / w;
5840 const qreal tx = x * iw;
5841 const qreal ty = y * iw;
5842 const int px = int(tx) - (tx < 0);
5843 const int py = int(ty) - (ty < 0);
5845 bool out = (px < 0) || (px >= image_width)
5846 || (py < 0) || (py >= image_height);
5848 int y_offset = py * scanline_offset;
5849 *b = out ? uint(0) : image_bits[y_offset + px];
5856 if (spanMethod == RegularSpans)
5857 func(target, buffer, l, coverage);
5859 drawBufferSpan(data, buffer, buffer_size,
5860 spans->x + spans->len - length,
5861 spans->y, l, coverage);
5870 template <class DST, class SRC>
5871 Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans, void *userData)
5873 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5874 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
5876 if (mode != QPainter::CompositionMode_SourceOver) {
5877 blend_src_generic<RegularSpans>(count, spans, userData);
5881 SRC buffer[buffer_size];
5882 const int image_width = data->texture.width;
5883 const int image_height = data->texture.height;
5885 if (data->fast_matrix) {
5886 // The increment pr x in the scanline
5887 const int fdx = (int)(data->m11 * fixed_scale);
5888 const int fdy = (int)(data->m12 * fixed_scale);
5891 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5892 if (coverage == 0) {
5897 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5899 const qreal cx = spans->x + qreal(0.5);
5900 const qreal cy = spans->y + qreal(0.5);
5901 int x = int((data->m21 * cy
5902 + data->m11 * cx + data->dx) * fixed_scale);
5903 int y = int((data->m22 * cy
5904 + data->m12 * cx + data->dy) * fixed_scale);
5905 int length = spans->len;
5908 const int l = qMin(length, buffer_size);
5910 const SRC *end = buffer + l;
5913 const int px = (x >> 16);
5914 const int py = (y >> 16);
5916 if ((px < 0) || (px >= image_width) ||
5917 (py < 0) || (py >= image_height))
5921 *b = ((SRC*)data->texture.scanLine(py))[px];
5929 if (!SRC::hasAlpha() && coverage == 255) {
5930 qt_memconvert(dest, buffer, l);
5931 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5932 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5934 blendUntransformed_dest24(dest, buffer, coverage, l);
5935 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5936 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5937 blendUntransformed_dest16(dest, buffer, coverage, l);
5939 blendUntransformed_unaligned(dest, buffer, coverage, l);
5948 const qreal fdx = data->m11;
5949 const qreal fdy = data->m12;
5950 const qreal fdw = data->m13;
5953 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5954 if (coverage == 0) {
5959 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5962 const qreal cx = spans->x + qreal(0.5);
5963 const qreal cy = spans->y + qreal(0.5);
5965 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5966 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5967 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5969 int length = spans->len;
5971 const int l = qMin(length, buffer_size);
5972 const SRC *end = buffer + l;
5975 const qreal iw = w == 0 ? 1 : 1 / w;
5976 const qreal tx = x * iw;
5977 const qreal ty = y * iw;
5979 const int px = int(tx) - (tx < 0);
5980 const int py = int(ty) - (ty < 0);
5982 if ((px < 0) || (px >= image_width) ||
5983 (py < 0) || (py >= image_height))
5987 *b = ((SRC*)data->texture.scanLine(py))[px];
5995 if (!SRC::hasAlpha() && coverage == 255) {
5996 qt_memconvert(dest, buffer, l);
5997 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5998 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6000 blendUntransformed_dest24(dest, buffer, coverage, l);
6001 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6002 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6003 blendUntransformed_dest16(dest, buffer, coverage, l);
6005 blendUntransformed_unaligned(dest, buffer, coverage, l);
6016 static void blend_transformed_rgb888(int count, const QSpan *spans,
6019 #if defined(QT_QWS_DEPTH_24)
6020 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6022 if (data->texture.format == QImage::Format_RGB888)
6023 blendTransformed<qrgb888, qrgb888>(count, spans, userData);
6026 blend_src_generic<RegularSpans>(count, spans, userData);
6029 static void blend_transformed_argb6666(int count, const QSpan *spans,
6032 #if defined(QT_QWS_DEPTH_18)
6033 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6035 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
6036 blendTransformed<qargb6666, qargb6666>(count, spans, userData);
6037 else if (data->texture.format == QImage::Format_RGB666)
6038 blendTransformed<qargb6666, qrgb666>(count, spans, userData);
6041 blend_src_generic<RegularSpans>(count, spans, userData);
6044 static void blend_transformed_rgb666(int count, const QSpan *spans,
6047 #if defined(QT_QWS_DEPTH_18)
6048 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6050 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
6051 blendTransformed<qrgb666, qargb6666>(count, spans, userData);
6052 else if (data->texture.format == QImage::Format_RGB666)
6053 blendTransformed<qrgb666, qrgb666>(count, spans, userData);
6056 blend_src_generic<RegularSpans>(count, spans, userData);
6059 static void blend_transformed_argb8565(int count, const QSpan *spans,
6062 #if defined(QT_QWS_DEPTH_16)
6063 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6065 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
6066 blendTransformed<qargb8565, qargb8565>(count, spans, userData);
6067 else if (data->texture.format == QImage::Format_RGB16)
6068 blendTransformed<qargb8565, qrgb565>(count, spans, userData);
6071 blend_src_generic<RegularSpans>(count, spans, userData);
6074 static void blend_transformed_rgb565(int count, const QSpan *spans,
6077 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
6078 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6080 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
6081 blendTransformed<qrgb565, qargb8565>(count, spans, userData);
6082 else if (data->texture.format == QImage::Format_RGB16)
6083 blendTransformed<qrgb565, qrgb565>(count, spans, userData);
6086 blend_src_generic<RegularSpans>(count, spans, userData);
6089 static void blend_transformed_argb8555(int count, const QSpan *spans,
6092 #if defined(QT_QWS_DEPTH_15)
6093 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6095 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
6096 blendTransformed<qargb8555, qargb8555>(count, spans, userData);
6097 else if (data->texture.format == QImage::Format_RGB555)
6098 blendTransformed<qargb8555, qrgb555>(count, spans, userData);
6101 blend_src_generic<RegularSpans>(count, spans, userData);
6104 static void blend_transformed_rgb555(int count, const QSpan *spans,
6107 #if defined(QT_QWS_DEPTH_15)
6108 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6110 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
6111 blendTransformed<qrgb555, qargb8555>(count, spans, userData);
6112 else if (data->texture.format == QImage::Format_RGB555)
6113 blendTransformed<qrgb555, qrgb555>(count, spans, userData);
6116 blend_src_generic<RegularSpans>(count, spans, userData);
6119 static void blend_transformed_argb4444(int count, const QSpan *spans,
6122 #if defined(QT_QWS_DEPTH_12)
6123 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6125 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
6126 blendTransformed<qargb4444, qargb4444>(count, spans, userData);
6127 else if (data->texture.format == QImage::Format_RGB444)
6128 blendTransformed<qargb4444, qrgb444>(count, spans, userData);
6131 blend_src_generic<RegularSpans>(count, spans, userData);
6134 static void blend_transformed_rgb444(int count, const QSpan *spans,
6137 #if defined(QT_QWS_DEPTH_12)
6138 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6140 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
6141 blendTransformed<qrgb444, qargb4444>(count, spans, userData);
6142 else if (data->texture.format == QImage::Format_RGB444)
6143 blendTransformed<qrgb444, qrgb444>(count, spans, userData);
6146 blend_src_generic<RegularSpans>(count, spans, userData);
6149 template <SpanMethod spanMethod>
6150 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QSpan *spans, void *userData)
6152 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6153 if (data->texture.format != QImage::Format_ARGB32_Premultiplied
6154 && data->texture.format != QImage::Format_RGB32) {
6155 blend_src_generic<spanMethod>(count, spans, userData);
6159 CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
6160 uint buffer[buffer_size];
6162 int image_width = data->texture.width;
6163 int image_height = data->texture.height;
6164 const int scanline_offset = data->texture.bytesPerLine / 4;
6166 if (data->fast_matrix) {
6167 // The increment pr x in the scanline
6168 int fdx = (int)(data->m11 * fixed_scale);
6169 int fdy = (int)(data->m12 * fixed_scale);
6172 void *t = data->rasterBuffer->scanLine(spans->y);
6174 uint *target = ((uint *)t) + spans->x;
6175 uint *image_bits = (uint *)data->texture.imageData;
6177 const qreal cx = spans->x + qreal(0.5);
6178 const qreal cy = spans->y + qreal(0.5);
6180 int x = int((data->m21 * cy
6181 + data->m11 * cx + data->dx) * fixed_scale);
6182 int y = int((data->m22 * cy
6183 + data->m12 * cx + data->dy) * fixed_scale);
6185 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
6186 int length = spans->len;
6188 int l = qMin(length, buffer_size);
6189 const uint *end = buffer + l;
6196 if (px < 0) px += image_width;
6197 if (py < 0) py += image_height;
6198 int y_offset = py * scanline_offset;
6200 Q_ASSERT(px >= 0 && px < image_width);
6201 Q_ASSERT(py >= 0 && py < image_height);
6203 *b = image_bits[y_offset + px];
6208 if (spanMethod == RegularSpans)
6209 func(target, buffer, l, coverage);
6211 drawBufferSpan(data, buffer, buffer_size,
6212 spans->x + spans->len - length,
6213 spans->y, l, coverage);
6220 const qreal fdx = data->m11;
6221 const qreal fdy = data->m12;
6222 const qreal fdw = data->m13;
6224 void *t = data->rasterBuffer->scanLine(spans->y);
6226 uint *target = ((uint *)t) + spans->x;
6227 uint *image_bits = (uint *)data->texture.imageData;
6229 const qreal cx = spans->x + qreal(0.5);
6230 const qreal cy = spans->y + qreal(0.5);
6232 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
6233 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
6234 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
6236 const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
6237 int length = spans->len;
6239 int l = qMin(length, buffer_size);
6240 const uint *end = buffer + l;
6243 const qreal iw = w == 0 ? 1 : 1 / w;
6244 const qreal tx = x * iw;
6245 const qreal ty = y * iw;
6246 int px = int(tx) - (tx < 0);
6247 int py = int(ty) - (ty < 0);
6251 if (px < 0) px += image_width;
6252 if (py < 0) py += image_height;
6253 int y_offset = py * scanline_offset;
6255 Q_ASSERT(px >= 0 && px < image_width);
6256 Q_ASSERT(py >= 0 && py < image_height);
6258 *b = image_bits[y_offset + px];
6262 //force increment to avoid /0
6268 if (spanMethod == RegularSpans)
6269 func(target, buffer, l, coverage);
6271 drawBufferSpan(data, buffer, buffer_size,
6272 spans->x + spans->len - length,
6273 spans->y, l, coverage);
6282 template <class DST, class SRC>
6283 Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *spans, void *userData)
6285 QSpanData *data = reinterpret_cast<QSpanData*>(userData);
6286 QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
6288 if (mode != QPainter::CompositionMode_SourceOver) {
6289 blend_src_generic<RegularSpans>(count, spans, userData);
6293 SRC buffer[buffer_size];
6294 const int image_width = data->texture.width;
6295 const int image_height = data->texture.height;
6297 if (data->fast_matrix) {
6298 // The increment pr x in the scanline
6299 const int fdx = (int)(data->m11 * fixed_scale);
6300 const int fdy = (int)(data->m12 * fixed_scale);
6303 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
6304 if (coverage == 0) {
6309 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
6311 const qreal cx = spans->x + qreal(0.5);
6312 const qreal cy = spans->y + qreal(0.5);
6313 int x = int((data->m21 * cy
6314 + data->m11 * cx + data->dx) * fixed_scale);
6315 int y = int((data->m22 * cy
6316 + data->m12 * cx + data->dy) * fixed_scale);
6317 int length = spans->len;
6320 const int l = qMin(length, buffer_size);
6322 const SRC *end = buffer + l;
6325 int px = (x >> 16) % image_width;
6326 int py = (y >> 16) % image_height;
6333 *b = ((SRC*)data->texture.scanLine(py))[px];
6340 if (!SRC::hasAlpha() && coverage == 255) {
6341 qt_memconvert(dest, buffer, l);
6342 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6343 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6345 blendUntransformed_dest24(dest, buffer, coverage, l);
6346 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6347 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6348 blendUntransformed_dest16(dest, buffer, coverage, l);
6350 blendUntransformed_unaligned(dest, buffer, coverage, l);
6359 const qreal fdx = data->m11;
6360 const qreal fdy = data->m12;
6361 const qreal fdw = data->m13;
6364 const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
6365 if (coverage == 0) {
6370 DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
6373 const qreal cx = spans->x + qreal(0.5);
6374 const qreal cy = spans->y + qreal(0.5);
6376 qreal x = data->m21 * cy + data->m11 * cx + data->dx;
6377 qreal y = data->m22 * cy + data->m12 * cx + data->dy;
6378 qreal w = data->m23 * cy + data->m13 * cx + data->m33;
6380 int length = spans->len;
6382 const int l = qMin(length, buffer_size);
6383 const SRC *end = buffer + l;
6386 const qreal iw = w == 0 ? 1 : 1 / w;
6387 const qreal tx = x * iw;
6388 const qreal ty = y * iw;
6390 int px = int(tx) - (tx < 0);
6391 int py = int(ty) - (ty < 0);
6400 *b = ((SRC*)data->texture.scanLine(py))[px];
6406 // force increment to avoid /0
6410 if (!SRC::hasAlpha() && coverage == 255) {
6411 qt_memconvert(dest, buffer, l);
6412 } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6413 (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6415 blendUntransformed_dest24(dest, buffer, coverage, l);
6416 } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6417 (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6418 blendUntransformed_dest16(dest, buffer, coverage, l);
6420 blendUntransformed_unaligned(dest, buffer, coverage, l);
6431 static void blend_transformed_tiled_rgb888(int count, const QSpan *spans,
6434 #if defined(QT_QWS_DEPTH_24)
6435 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6437 if (data->texture.format == QImage::Format_RGB888)
6438 blendTransformedTiled<qrgb888, qrgb888>(count, spans, userData);
6441 blend_src_generic<RegularSpans>(count, spans, userData);
6444 static void blend_transformed_tiled_argb6666(int count, const QSpan *spans,
6447 #if defined(QT_QWS_DEPTH_18)
6448 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6450 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
6451 blendTransformedTiled<qargb6666, qargb6666>(count, spans, userData);
6452 else if (data->texture.format == QImage::Format_RGB666)
6453 blendTransformedTiled<qargb6666, qrgb666>(count, spans, userData);
6456 blend_src_generic<RegularSpans>(count, spans, userData);
6459 static void blend_transformed_tiled_rgb666(int count, const QSpan *spans,
6462 #if defined(QT_QWS_DEPTH_18)
6463 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6465 if (data->texture.format == QImage::Format_ARGB6666_Premultiplied)
6466 blendTransformedTiled<qrgb666, qargb6666>(count, spans, userData);
6467 else if (data->texture.format == QImage::Format_RGB666)
6468 blendTransformedTiled<qrgb666, qrgb666>(count, spans, userData);
6471 blend_src_generic<RegularSpans>(count, spans, userData);
6474 static void blend_transformed_tiled_argb8565(int count, const QSpan *spans,
6477 #if defined(QT_QWS_DEPTH_16)
6478 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6480 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
6481 blendTransformedTiled<qargb8565, qargb8565>(count, spans, userData);
6482 else if (data->texture.format == QImage::Format_RGB16)
6483 blendTransformedTiled<qargb8565, qrgb565>(count, spans, userData);
6486 blend_src_generic<RegularSpans>(count, spans, userData);
6489 static void blend_transformed_tiled_rgb565(int count, const QSpan *spans,
6492 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
6493 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6495 if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
6496 blendTransformedTiled<qrgb565, qargb8565>(count, spans, userData);
6497 else if (data->texture.format == QImage::Format_RGB16)
6498 blendTransformedTiled<qrgb565, qrgb565>(count, spans, userData);
6501 blend_src_generic<RegularSpans>(count, spans, userData);
6504 static void blend_transformed_tiled_argb8555(int count, const QSpan *spans,
6507 #if defined(QT_QWS_DEPTH_15)
6508 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6510 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
6511 blendTransformedTiled<qargb8555, qargb8555>(count, spans, userData);
6512 else if (data->texture.format == QImage::Format_RGB555)
6513 blendTransformedTiled<qargb8555, qrgb555>(count, spans, userData);
6516 blend_src_generic<RegularSpans>(count, spans, userData);
6519 static void blend_transformed_tiled_rgb555(int count, const QSpan *spans,
6522 #if defined(QT_QWS_DEPTH_15)
6523 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6525 if (data->texture.format == QImage::Format_ARGB8555_Premultiplied)
6526 blendTransformedTiled<qrgb555, qargb8555>(count, spans, userData);
6527 else if (data->texture.format == QImage::Format_RGB555)
6528 blendTransformedTiled<qrgb555, qrgb555>(count, spans, userData);
6531 blend_src_generic<RegularSpans>(count, spans, userData);
6534 static void blend_transformed_tiled_argb4444(int count, const QSpan *spans,
6537 #if defined(QT_QWS_DEPTH_12)
6538 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6540 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
6541 blendTransformedTiled<qargb4444, qargb4444>(count, spans, userData);
6542 else if (data->texture.format == QImage::Format_RGB444)
6543 blendTransformedTiled<qargb4444, qrgb444>(count, spans, userData);
6546 blend_src_generic<RegularSpans>(count, spans, userData);
6549 static void blend_transformed_tiled_rgb444(int count, const QSpan *spans,
6552 #if defined(QT_QWS_DEPTH_12)
6553 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6555 if (data->texture.format == QImage::Format_ARGB4444_Premultiplied)
6556 blendTransformedTiled<qrgb444, qargb4444>(count, spans, userData);
6557 else if (data->texture.format == QImage::Format_RGB444)
6558 blendTransformedTiled<qrgb444, qrgb444>(count, spans, userData);
6561 blend_src_generic<RegularSpans>(count, spans, userData);
6564 # define SPANFUNC_POINTER(Name, Arg) Name<Arg>
6567 /* Image formats here are target formats */
6568 static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats] = {
6572 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Mono
6573 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // MonoLsb
6574 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Indexed8
6575 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // RGB32
6576 SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // ARGB32
6577 SPANFUNC_POINTER(blend_untransformed_argb, RegularSpans), // ARGB32_Premultiplied
6578 blend_untransformed_rgb565,
6579 blend_untransformed_argb8565,
6580 blend_untransformed_rgb666,
6581 blend_untransformed_argb6666,
6582 blend_untransformed_rgb555,
6583 blend_untransformed_argb8555,
6584 blend_untransformed_rgb888,
6585 blend_untransformed_rgb444,
6586 blend_untransformed_argb4444,
6591 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Mono
6592 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // MonoLsb
6593 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Indexed8
6594 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // RGB32
6595 SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // ARGB32
6596 SPANFUNC_POINTER(blend_tiled_argb, RegularSpans), // ARGB32_Premultiplied
6598 blend_tiled_argb8565,
6600 blend_tiled_argb6666,
6602 blend_tiled_argb8555,
6605 blend_tiled_argb4444,
6610 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6611 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6612 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6613 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6614 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6615 SPANFUNC_POINTER(blend_transformed_argb, RegularSpans), // ARGB32_Premultiplied
6616 blend_transformed_rgb565,
6617 blend_transformed_argb8565,
6618 blend_transformed_rgb666,
6619 blend_transformed_argb6666,
6620 blend_transformed_rgb555,
6621 blend_transformed_argb8555,
6622 blend_transformed_rgb888,
6623 blend_transformed_rgb444,
6624 blend_transformed_argb4444,
6629 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6630 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6631 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6632 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6633 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6634 SPANFUNC_POINTER(blend_transformed_tiled_argb, RegularSpans), // ARGB32_Premultiplied
6635 blend_transformed_tiled_rgb565,
6636 blend_transformed_tiled_argb8565,
6637 blend_transformed_tiled_rgb666,
6638 blend_transformed_tiled_argb6666,
6639 blend_transformed_tiled_rgb555,
6640 blend_transformed_tiled_argb8555,
6641 blend_transformed_tiled_rgb888,
6642 blend_transformed_tiled_rgb444,
6643 blend_transformed_tiled_argb4444
6648 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6649 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6650 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6651 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6652 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6653 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
6654 blend_transformed_bilinear_rgb565,
6655 blend_transformed_bilinear_argb8565,
6656 blend_transformed_bilinear_rgb666,
6657 blend_transformed_bilinear_argb6666,
6658 blend_transformed_bilinear_rgb555,
6659 blend_transformed_bilinear_argb8555,
6660 blend_transformed_bilinear_rgb888,
6661 blend_transformed_bilinear_rgb444,
6662 blend_transformed_bilinear_argb4444,
6667 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
6668 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
6669 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
6670 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
6671 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
6672 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
6673 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB16
6674 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8565_Premultiplied
6675 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB666
6676 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB6666_Premultiplied
6677 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB555
6678 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8555_Premultiplied
6679 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB888
6680 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB444
6681 SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB4444_Premultiplied
6685 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
6686 static const ProcessSpans processTextureSpansCallback[NBlendTypes][QImage::NImageFormats] = {
6690 blend_untransformed_generic<CallbackSpans>, // Mono
6691 blend_untransformed_generic<CallbackSpans>, // MonoLsb
6692 blend_untransformed_generic<CallbackSpans>, // Indexed8
6693 blend_untransformed_generic<CallbackSpans>, // RGB32
6694 blend_untransformed_generic<CallbackSpans>, // ARGB32
6695 blend_untransformed_argb<CallbackSpans>, // ARGB32_Premultiplied
6696 blend_untransformed_generic<CallbackSpans>, // RGB16
6697 blend_untransformed_generic<CallbackSpans>, // ARGB8565_Premultiplied
6698 blend_untransformed_generic<CallbackSpans>, // RGB666
6699 blend_untransformed_generic<CallbackSpans>, // ARGB6666_Premultiplied
6700 blend_untransformed_generic<CallbackSpans>, // RGB555
6701 blend_untransformed_generic<CallbackSpans>, // ARGB8555_Premultiplied
6702 blend_untransformed_generic<CallbackSpans>, // RGB888
6703 blend_untransformed_generic<CallbackSpans>, // RGB444
6704 blend_untransformed_generic<CallbackSpans> // ARGB4444_Premultiplied
6709 blend_tiled_generic<CallbackSpans>, // Mono
6710 blend_tiled_generic<CallbackSpans>, // MonoLsb
6711 blend_tiled_generic<CallbackSpans>, // Indexed8
6712 blend_tiled_generic<CallbackSpans>, // RGB32
6713 blend_tiled_generic<CallbackSpans>, // ARGB32
6714 blend_tiled_argb<CallbackSpans>, // ARGB32_Premultiplied
6715 blend_tiled_generic<CallbackSpans>, // RGB16
6716 blend_tiled_generic<CallbackSpans>, // ARGB8565_Premultiplied
6717 blend_tiled_generic<CallbackSpans>, // RGB666
6718 blend_tiled_generic<CallbackSpans>, // ARGB6666_Premultiplied
6719 blend_tiled_generic<CallbackSpans>, // RGB555
6720 blend_tiled_generic<CallbackSpans>, // ARGB8555_Premultiplied
6721 blend_tiled_generic<CallbackSpans>, // RGB888
6722 blend_tiled_generic<CallbackSpans>, // RGB444
6723 blend_tiled_generic<CallbackSpans> // ARGB4444_Premultiplied
6728 blend_src_generic<CallbackSpans>, // Mono
6729 blend_src_generic<CallbackSpans>, // MonoLsb
6730 blend_src_generic<CallbackSpans>, // Indexed8
6731 blend_src_generic<CallbackSpans>, // RGB32
6732 blend_src_generic<CallbackSpans>, // ARGB32
6733 blend_transformed_argb<CallbackSpans>, // ARGB32_Premultiplied
6734 blend_src_generic<CallbackSpans>, // RGB16
6735 blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6736 blend_src_generic<CallbackSpans>, // RGB666
6737 blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6738 blend_src_generic<CallbackSpans>, // RGB555
6739 blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6740 blend_src_generic<CallbackSpans>, // RGB888
6741 blend_src_generic<CallbackSpans>, // RGB444
6742 blend_src_generic<CallbackSpans>, // ARGB4444_Premultiplied
6747 blend_src_generic<CallbackSpans>, // Mono
6748 blend_src_generic<CallbackSpans>, // MonoLsb
6749 blend_src_generic<CallbackSpans>, // Indexed8
6750 blend_src_generic<CallbackSpans>, // RGB32
6751 blend_src_generic<CallbackSpans>, // ARGB32
6752 blend_transformed_tiled_argb<CallbackSpans>, // ARGB32_Premultiplied
6753 blend_src_generic<CallbackSpans>, // RGB16
6754 blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6755 blend_src_generic<CallbackSpans>, // RGB666
6756 blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6757 blend_src_generic<CallbackSpans>, // RGB555
6758 blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6759 blend_src_generic<CallbackSpans>, // RGB888
6760 blend_src_generic<CallbackSpans>, // RGB444
6761 blend_src_generic<CallbackSpans> // ARGB4444_Premultiplied
6766 blend_src_generic<CallbackSpans>, // Mono
6767 blend_src_generic<CallbackSpans>, // MonoLsb
6768 blend_src_generic<CallbackSpans>, // Indexed8
6769 blend_src_generic<CallbackSpans>, // RGB32
6770 blend_src_generic<CallbackSpans>, // ARGB32
6771 blend_src_generic<CallbackSpans>, // ARGB32_Premultiplied
6772 blend_src_generic<CallbackSpans>, // RGB16
6773 blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6774 blend_src_generic<CallbackSpans>, // RGB666
6775 blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6776 blend_src_generic<CallbackSpans>, // RGB555
6777 blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6778 blend_src_generic<CallbackSpans>, // RGB888
6779 blend_src_generic<CallbackSpans>, // RGB444
6780 blend_src_generic<CallbackSpans> // ARGB4444_Premultiplied
6785 blend_src_generic<CallbackSpans>, // Mono
6786 blend_src_generic<CallbackSpans>, // MonoLsb
6787 blend_src_generic<CallbackSpans>, // Indexed8
6788 blend_src_generic<CallbackSpans>, // RGB32
6789 blend_src_generic<CallbackSpans>, // ARGB32
6790 blend_src_generic<CallbackSpans>, // ARGB32_Premultiplied
6791 blend_src_generic<CallbackSpans>, // RGB16
6792 blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6793 blend_src_generic<CallbackSpans>, // RGB666
6794 blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6795 blend_src_generic<CallbackSpans>, // RGB555
6796 blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6797 blend_src_generic<CallbackSpans>, // RGB888
6798 blend_src_generic<CallbackSpans>, // RGB444
6799 blend_src_generic<CallbackSpans> // ARGB4444_Premultiplied
6802 #endif // QT_NO_RASTERCALLBACKS
6804 void qBlendTexture(int count, const QSpan *spans, void *userData)
6806 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6807 ProcessSpans proc = processTextureSpans[getBlendType(data)][data->rasterBuffer->format];
6808 proc(count, spans, userData);
6811 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
6812 void qBlendTextureCallback(int count, const QSpan *spans, void *userData)
6814 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6815 ProcessSpans proc = processTextureSpansCallback[getBlendType(data)][data->rasterBuffer->format];
6816 proc(count, spans, userData);
6818 #endif // QT_NO_RASTERCALLBACKS
6820 template <class DST>
6821 inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
6822 int x, int y, quint32 color,
6824 int mapWidth, int mapHeight, int mapStride,
6828 const DST c = qt_colorConvert<DST, quint32>(color, 0);
6829 DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
6830 const int destStride = rasterBuffer->bytesPerLine() / sizeof(DST);
6833 while (mapHeight--) {
6836 for (int x = 0; x < mapWidth; x += 8) {
6837 uchar s = map[x >> 3];
6838 for (int i = 0; i < 8; ++i) {
6843 qt_memfill(dest + x0, c, n);
6858 qt_memfill(dest + x0, c, n);
6863 while (mapHeight--) {
6866 for (uchar s = *map; s; s <<= 1) {
6870 qt_memfill(dest + x0, c, n);
6878 qt_memfill(dest + x0, c, n);
6885 static void qt_gradient_quint32(int count, const QSpan *spans, void *userData)
6887 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6889 bool isVerticalGradient =
6890 data->txop <= QTransform::TxScale &&
6891 data->type == QSpanData::LinearGradient &&
6892 data->gradient.linear.end.x == data->gradient.linear.origin.x;
6894 if (isVerticalGradient) {
6895 LinearGradientValues linear;
6896 getLinearGradientValues(&linear, data);
6898 CompositionFunctionSolid funcSolid =
6899 functionForModeSolid[data->rasterBuffer->compositionMode];
6902 The logic for vertical gradient calculations is a mathematically
6903 reduced copy of that in fetchLinearGradient() - which is basically:
6905 qreal ry = data->m22 * (y + 0.5) + data->dy;
6906 qreal t = linear.dy*ry + linear.off;
6907 t *= (GRADIENT_STOPTABLE_SIZE - 1);
6909 qt_gradient_pixel_fixed(&data->gradient,
6910 int(t * FIXPT_SIZE));
6912 This has then been converted to fixed point to improve performance.
6914 const int gss = GRADIENT_STOPTABLE_SIZE - 1;
6915 int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
6916 int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
6922 quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x;
6924 qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
6926 funcSolid(dst, spans->len, color, spans->coverage);
6931 blend_src_generic<RegularSpans>(count, spans, userData);
6935 static void qt_gradient_quint16(int count, const QSpan *spans, void *userData)
6937 QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6939 bool isVerticalGradient =
6940 data->txop <= QTransform::TxScale &&
6941 data->type == QSpanData::LinearGradient &&
6942 data->gradient.linear.end.x == data->gradient.linear.origin.x;
6944 if (isVerticalGradient) {
6946 LinearGradientValues linear;
6947 getLinearGradientValues(&linear, data);
6950 The logic for vertical gradient calculations is a mathematically
6951 reduced copy of that in fetchLinearGradient() - which is basically:
6953 qreal ry = data->m22 * (y + 0.5) + data->dy;
6954 qreal t = linear.dy*ry + linear.off;
6955 t *= (GRADIENT_STOPTABLE_SIZE - 1);
6957 qt_gradient_pixel_fixed(&data->gradient,
6958 int(t * FIXPT_SIZE));
6960 This has then been converted to fixed point to improve performance.
6962 const int gss = GRADIENT_STOPTABLE_SIZE - 1;
6963 int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
6964 int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
6966 uint oldColor = data->solid.color;
6970 quint32 color = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
6972 data->solid.color = color;
6973 blend_color_rgb16(1, spans, userData);
6976 data->solid.color = oldColor;
6979 blend_src_generic<RegularSpans>(count, spans, userData);
6983 inline static void qt_bitmapblit_quint32(QRasterBuffer *rasterBuffer,
6984 int x, int y, quint32 color,
6986 int mapWidth, int mapHeight, int mapStride)
6988 qt_bitmapblit_template<quint32>(rasterBuffer, x, y, color,
6989 map, mapWidth, mapHeight, mapStride);
6992 inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
6993 int x, int y, quint32 color,
6995 int mapWidth, int mapHeight, int mapStride)
6997 qt_bitmapblit_template<quint16>(rasterBuffer, x, y, color,
6998 map, mapWidth, mapHeight, mapStride);
7002 uchar qt_pow_rgb_gamma[256];
7003 uchar qt_pow_rgb_invgamma[256];
7005 uint qt_pow_gamma[256];
7006 uchar qt_pow_invgamma[2048];
7008 static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
7009 int x, int y, quint32 color,
7011 int mapWidth, int mapHeight, int mapStride,
7014 const quint16 c = qt_colorConvert<quint16, quint32>(color, 0);
7015 quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
7016 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
7018 while (mapHeight--) {
7019 for (int i = 0; i < mapWidth; ++i) {
7020 const int coverage = map[i];
7022 if (coverage == 0) {
7024 } else if (coverage == 255) {
7027 int ialpha = 255 - coverage;
7028 dest[i] = BYTE_MUL_RGB16(c, coverage)
7029 + BYTE_MUL_RGB16(dest[i], ialpha);
7037 void qt_build_pow_tables() {
7038 qreal smoothing = qreal(1.7);
7041 // decided by testing a few things on an iMac, should probably get this from the
7043 smoothing = qreal(2.0);
7047 extern qreal qt_fontsmoothing_gamma; // qapplication_win.cpp
7048 smoothing = qt_fontsmoothing_gamma;
7052 Q_UNUSED(smoothing);
7053 for (int i=0; i<256; ++i) {
7054 qt_pow_rgb_gamma[i] = uchar(i);
7055 qt_pow_rgb_invgamma[i] = uchar(i);
7058 for (int i=0; i<256; ++i) {
7059 qt_pow_rgb_gamma[i] = uchar(qRound(qPow(i / qreal(255.0), smoothing) * 255));
7060 qt_pow_rgb_invgamma[i] = uchar(qRound(qPow(i / qreal(255.), 1 / smoothing) * 255));
7064 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7065 const qreal gray_gamma = 2.31;
7066 for (int i=0; i<256; ++i)
7067 qt_pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047));
7068 for (int i=0; i<2048; ++i)
7069 qt_pow_invgamma[i] = uchar(qRound(qPow(i / qreal(2047.0), 1 / gray_gamma) * 255));
7073 static inline void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
7075 // Do a gray alphablend...
7076 int da = qAlpha(*dst);
7077 int dr = qRed(*dst);
7078 int dg = qGreen(*dst);
7079 int db = qBlue(*dst);
7082 #if defined (Q_WS_WIN)
7083 // Work around GDI messing up alpha channel
7084 && qRed(*dst) <= da && qBlue(*dst) <= da && qGreen(*dst) <= da
7088 int a = qGray(coverage);
7089 sr = qt_div_255(qt_pow_rgb_invgamma[sr] * a);
7090 sg = qt_div_255(qt_pow_rgb_invgamma[sg] * a);
7091 sb = qt_div_255(qt_pow_rgb_invgamma[sb] * a);
7094 dr = qt_div_255(dr * ia);
7095 dg = qt_div_255(dg * ia);
7096 db = qt_div_255(db * ia);
7098 *dst = ((a + qt_div_255((255 - a) * da)) << 24)
7105 int mr = qRed(coverage);
7106 int mg = qGreen(coverage);
7107 int mb = qBlue(coverage);
7109 dr = qt_pow_rgb_gamma[dr];
7110 dg = qt_pow_rgb_gamma[dg];
7111 db = qt_pow_rgb_gamma[db];
7113 int nr = qt_div_255((sr - dr) * mr) + dr;
7114 int ng = qt_div_255((sg - dg) * mg) + dg;
7115 int nb = qt_div_255((sb - db) * mb) + db;
7117 nr = qt_pow_rgb_invgamma[nr];
7118 ng = qt_pow_rgb_invgamma[ng];
7119 nb = qt_pow_rgb_invgamma[nb];
7121 *dst = qRgb(nr, ng, nb);
7124 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7125 static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
7127 // Do a gammacorrected gray alphablend...
7128 int dr = qRed(*dst);
7129 int dg = qGreen(*dst);
7130 int db = qBlue(*dst);
7132 dr = qt_pow_gamma[dr];
7133 dg = qt_pow_gamma[dg];
7134 db = qt_pow_gamma[db];
7136 int alpha = coverage;
7137 int ialpha = 255 - alpha;
7138 int nr = (sr * alpha + ialpha * dr) / 255;
7139 int ng = (sg * alpha + ialpha * dg) / 255;
7140 int nb = (sb * alpha + ialpha * db) / 255;
7142 nr = qt_pow_invgamma[nr];
7143 ng = qt_pow_invgamma[ng];
7144 nb = qt_pow_invgamma[nb];
7146 *dst = qRgb(nr, ng, nb);
7150 static void qt_alphamapblit_quint32(QRasterBuffer *rasterBuffer,
7151 int x, int y, quint32 color,
7153 int mapWidth, int mapHeight, int mapStride,
7154 const QClipData *clip)
7156 const quint32 c = color;
7157 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
7159 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7160 int sr = qRed(color);
7161 int sg = qGreen(color);
7162 int sb = qBlue(color);
7164 sr = qt_pow_gamma[sr];
7165 sg = qt_pow_gamma[sg];
7166 sb = qt_pow_gamma[sb];
7167 bool opaque_src = (qAlpha(color) == 255);
7171 quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
7172 while (mapHeight--) {
7173 for (int i = 0; i < mapWidth; ++i) {
7174 const int coverage = map[i];
7176 if (coverage == 0) {
7178 } else if (coverage == 255) {
7181 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7182 if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
7183 && qAlpha(dest[i]) == 255) {
7184 grayBlendPixel(dest+i, coverage, sr, sg, sb);
7188 int ialpha = 255 - coverage;
7189 dest[i] = INTERPOLATE_PIXEL_255(c, coverage, dest[i], ialpha);
7197 int bottom = qMin(y + mapHeight, rasterBuffer->height());
7199 int top = qMax(y, 0);
7200 map += (top - y) * mapStride;
7202 const_cast<QClipData *>(clip)->initialize();
7203 for (int yp = top; yp<bottom; ++yp) {
7204 const QClipData::ClipLine &line = clip->m_clipLines[yp];
7206 quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
7208 for (int i=0; i<line.count; ++i) {
7209 const QSpan &clip = line.spans[i];
7211 int start = qMax<int>(x, clip.x);
7212 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
7214 for (int xp=start; xp<end; ++xp) {
7215 const int coverage = map[xp - x];
7217 if (coverage == 0) {
7219 } else if (coverage == 255) {
7222 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7223 if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
7224 && qAlpha(dest[xp]) == 255) {
7225 grayBlendPixel(dest+xp, coverage, sr, sg, sb);
7229 int ialpha = 255 - coverage;
7230 dest[xp] = INTERPOLATE_PIXEL_255(c, coverage, dest[xp], ialpha);
7234 } // for (i -> line.count)
7235 } // for (yp -> bottom)
7241 static void qt_alphargbblit_quint32(QRasterBuffer *rasterBuffer,
7242 int x, int y, quint32 color,
7243 const uint *src, int mapWidth, int mapHeight, int srcStride,
7244 const QClipData *clip)
7246 const quint32 c = color;
7248 int sr = qRed(color);
7249 int sg = qGreen(color);
7250 int sb = qBlue(color);
7251 int sa = qAlpha(color);
7253 sr = qt_pow_rgb_gamma[sr];
7254 sg = qt_pow_rgb_gamma[sg];
7255 sb = qt_pow_rgb_gamma[sb];
7261 quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
7262 const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
7263 while (mapHeight--) {
7264 for (int i = 0; i < mapWidth; ++i) {
7265 const uint coverage = src[i];
7266 if (coverage == 0xffffffff) {
7268 } else if (coverage != 0xff000000) {
7269 rgbBlendPixel(dst+i, coverage, sr, sg, sb);
7277 int bottom = qMin(y + mapHeight, rasterBuffer->height());
7279 int top = qMax(y, 0);
7280 src += (top - y) * srcStride;
7282 const_cast<QClipData *>(clip)->initialize();
7283 for (int yp = top; yp<bottom; ++yp) {
7284 const QClipData::ClipLine &line = clip->m_clipLines[yp];
7286 quint32 *dst = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
7288 for (int i=0; i<line.count; ++i) {
7289 const QSpan &clip = line.spans[i];
7291 int start = qMax<int>(x, clip.x);
7292 int end = qMin<int>(x + mapWidth, clip.x + clip.len);
7294 for (int xp=start; xp<end; ++xp) {
7295 const uint coverage = src[xp - x];
7296 if (coverage == 0xffffffff) {
7298 } else if (coverage != 0xff000000) {
7299 rgbBlendPixel(dst+xp, coverage, sr, sg, sb);
7302 } // for (i -> line.count)
7304 } // for (yp -> bottom)
7310 inline void qt_rectfill_template(QRasterBuffer *rasterBuffer,
7311 int x, int y, int width, int height,
7312 quint32 color, T dummy = 0)
7316 qt_rectfill<T>(reinterpret_cast<T*>(rasterBuffer->buffer()),
7317 qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0),
7318 x, y, width, height, rasterBuffer->bytesPerLine());
7321 #define QT_RECTFILL(T) \
7322 inline static void qt_rectfill_##T(QRasterBuffer *rasterBuffer, \
7323 int x, int y, int width, int height, \
7326 qt_rectfill_template<T>(rasterBuffer, x, y, width, height, color); \
7329 QT_RECTFILL(quint32)
7330 QT_RECTFILL(quint16)
7331 QT_RECTFILL(qargb8565)
7332 QT_RECTFILL(qrgb666)
7333 QT_RECTFILL(qargb6666)
7334 QT_RECTFILL(qrgb555)
7335 QT_RECTFILL(qargb8555)
7336 QT_RECTFILL(qrgb888)
7337 QT_RECTFILL(qrgb444)
7338 QT_RECTFILL(qargb4444)
7341 inline static void qt_rectfill_nonpremul_quint32(QRasterBuffer *rasterBuffer,
7342 int x, int y, int width, int height,
7345 qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
7346 INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine());
7350 // Map table for destination image format. Contains function pointers
7351 // for blends of various types unto the destination
7353 DrawHelper qDrawHelper[QImage::NImageFormats] =
7356 { 0, 0, 0, 0, 0, 0 },
7359 blend_color_generic,
7360 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7365 blend_color_generic,
7366 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7371 blend_color_generic,
7372 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7378 qt_gradient_quint32,
7379 qt_bitmapblit_quint32,
7380 qt_alphamapblit_quint32,
7381 qt_alphargbblit_quint32,
7386 blend_color_generic,
7387 qt_gradient_quint32,
7388 qt_bitmapblit_quint32,
7389 qt_alphamapblit_quint32,
7390 qt_alphargbblit_quint32,
7391 qt_rectfill_nonpremul_quint32
7393 // Format_ARGB32_Premultiplied
7396 qt_gradient_quint32,
7397 qt_bitmapblit_quint32,
7398 qt_alphamapblit_quint32,
7399 qt_alphargbblit_quint32,
7405 qt_gradient_quint16,
7406 qt_bitmapblit_quint16,
7407 qt_alphamapblit_quint16,
7411 // Format_ARGB8565_Premultiplied
7413 SPANFUNC_POINTER_BLENDCOLOR(qargb8565),
7414 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7416 qt_rectfill_qargb8565
7420 SPANFUNC_POINTER_BLENDCOLOR(qrgb666),
7421 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7425 // Format_ARGB6666_Premultiplied
7427 SPANFUNC_POINTER_BLENDCOLOR(qargb6666),
7428 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7430 qt_rectfill_qargb6666
7434 SPANFUNC_POINTER_BLENDCOLOR(qrgb555),
7435 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7439 // Format_ARGB8555_Premultiplied
7441 SPANFUNC_POINTER_BLENDCOLOR(qargb8555),
7442 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7444 qt_rectfill_qargb8555
7448 SPANFUNC_POINTER_BLENDCOLOR(qrgb888),
7449 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7455 SPANFUNC_POINTER_BLENDCOLOR(qrgb444),
7456 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7460 // Format_ARGB4444_Premultiplied
7462 SPANFUNC_POINTER_BLENDCOLOR(qargb4444),
7463 SPANFUNC_POINTER(blend_src_generic, RegularSpans),
7465 qt_rectfill_qargb4444
7469 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
7470 DrawHelper qDrawHelperCallback[QImage::NImageFormats] =
7473 { 0, 0, 0, 0, 0, 0 },
7476 blend_color_generic_callback,
7477 blend_src_generic<CallbackSpans>,
7482 blend_color_generic_callback,
7483 blend_src_generic<CallbackSpans>,
7488 blend_color_generic_callback,
7489 blend_src_generic<CallbackSpans>,
7494 blend_color_generic_callback,
7495 blend_src_generic<CallbackSpans>,
7500 blend_color_generic_callback,
7501 blend_src_generic<CallbackSpans>,
7504 // Format_ARGB32_Premultiplied
7506 blend_color_generic_callback,
7507 blend_src_generic<CallbackSpans>,
7512 blend_color_generic_callback,
7513 blend_src_generic<CallbackSpans>,
7516 // Format_ARGB8565_Premultiplied
7518 blend_color_generic_callback,
7519 blend_src_generic<CallbackSpans>,
7524 blend_color_generic_callback,
7525 blend_src_generic<CallbackSpans>,
7528 // Format_ARGB6666_Premultiplied
7530 blend_color_generic_callback,
7531 blend_src_generic<CallbackSpans>,
7536 blend_color_generic_callback,
7537 blend_src_generic<CallbackSpans>,
7540 // Format_ARGB8555_Premultiplied
7542 blend_color_generic_callback,
7543 blend_src_generic<CallbackSpans>,
7548 blend_color_generic_callback,
7549 blend_src_generic<CallbackSpans>,
7554 blend_color_generic_callback,
7555 blend_src_generic<CallbackSpans>,
7558 // Format_ARGB4444_Premultiplied
7560 blend_color_generic_callback,
7561 blend_src_generic<CallbackSpans>,
7569 #if defined(Q_CC_MSVC) && !defined(_MIPS_)
7570 template <class DST, class SRC>
7571 inline void qt_memfill_template(DST *dest, SRC color, int count)
7573 const DST c = qt_colorConvert<DST, SRC>(color, 0);
7580 template <class DST, class SRC>
7581 inline void qt_memfill_template(DST *dest, SRC color, int count)
7583 const DST c = qt_colorConvert<DST, SRC>(color, 0);
7584 int n = (count + 7) / 8;
7585 switch (count & 0x07)
7587 case 0: do { *dest++ = c;
7588 case 7: *dest++ = c;
7589 case 6: *dest++ = c;
7590 case 5: *dest++ = c;
7591 case 4: *dest++ = c;
7592 case 3: *dest++ = c;
7593 case 2: *dest++ = c;
7594 case 1: *dest++ = c;
7600 inline void qt_memfill_template(quint16 *dest, quint16 value, int count)
7604 case 2: *dest++ = value;
7605 case 1: *dest = value;
7610 const int align = (quintptr)(dest) & 0x3;
7612 case 2: *dest++ = value; --count;
7615 const quint32 value32 = (value << 16) | value;
7616 qt_memfill(reinterpret_cast<quint32*>(dest), value32, count / 2);
7618 dest[count - 1] = value;
7622 static void qt_memfill_quint16(quint16 *dest, quint16 color, int count)
7624 qt_memfill_template<quint16, quint16>(dest, color, count);
7627 typedef void (*qt_memfill32_func)(quint32 *dest, quint32 value, int count);
7628 typedef void (*qt_memfill16_func)(quint16 *dest, quint16 value, int count);
7629 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count);
7630 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count);
7632 qt_memfill32_func qt_memfill32 = qt_memfill32_setup;
7633 qt_memfill16_func qt_memfill16 = qt_memfill16_setup;
7635 void qInitDrawhelperAsm()
7638 qt_memfill32 = qt_memfill_template<quint32, quint32>;
7639 qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16, quint16>;
7641 CompositionFunction *functionForModeAsm = 0;
7642 CompositionFunctionSolid *functionForModeSolidAsm = 0;
7644 const uint features = qDetectCPUFeatures();
7647 } else if (features & SSE2) {
7648 qt_memfill32 = qt_memfill32_sse2;
7649 qt_memfill16 = qt_memfill16_sse2;
7650 qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2;
7651 qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2;
7652 qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2;
7653 qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2;
7656 } else if (features & SSE) {
7657 // qt_memfill32 = qt_memfill32_sse;
7658 qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse;
7659 #ifdef QT_HAVE_3DNOW
7660 if (features & MMX3DNOW) {
7661 qt_memfill32 = qt_memfill32_sse3dnow;
7662 qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse3dnow;
7668 if (features & MMX) {
7669 functionForModeAsm = qt_functionForMode_MMX;
7671 functionForModeSolidAsm = qt_functionForModeSolid_MMX;
7672 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx;
7673 #ifdef QT_HAVE_3DNOW
7674 if (features & MMX3DNOW) {
7675 functionForModeAsm = qt_functionForMode_MMX3DNOW;
7676 functionForModeSolidAsm = qt_functionForModeSolid_MMX3DNOW;
7677 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx3dnow;
7681 extern void qt_blend_rgb32_on_rgb32_mmx(uchar *destPixels, int dbpl,
7682 const uchar *srcPixels, int sbpl,
7685 extern void qt_blend_argb32_on_argb32_mmx(uchar *destPixels, int dbpl,
7686 const uchar *srcPixels, int sbpl,
7690 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mmx;
7691 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mmx;
7692 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mmx;
7693 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mmx;
7699 if (features & SSE) {
7700 extern void qt_blend_rgb32_on_rgb32_sse(uchar *destPixels, int dbpl,
7701 const uchar *srcPixels, int sbpl,
7704 extern void qt_blend_argb32_on_argb32_sse(uchar *destPixels, int dbpl,
7705 const uchar *srcPixels, int sbpl,
7709 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
7710 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
7711 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
7712 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse;
7717 if (features & SSE2) {
7718 extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
7719 const uchar *srcPixels, int sbpl,
7722 extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
7723 const uchar *srcPixels, int sbpl,
7727 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
7728 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
7729 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
7730 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
7732 extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
7733 int y, int x, int length);
7735 qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2;
7738 #ifdef QT_HAVE_SSSE3
7739 if (features & SSSE3) {
7740 extern void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
7741 const uchar *srcPixels, int sbpl,
7745 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
7746 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
7753 if (features & SSE) {
7754 functionForModeAsm = qt_functionForMode_SSE;
7755 functionForModeSolidAsm = qt_functionForModeSolid_SSE;
7756 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse;
7757 #ifdef QT_HAVE_3DNOW
7758 if (features & MMX3DNOW) {
7759 functionForModeAsm = qt_functionForMode_SSE3DNOW;
7760 functionForModeSolidAsm = qt_functionForModeSolid_SSE3DNOW;
7761 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse3dnow;
7767 if (features & SSE2) {
7768 extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels,
7769 const uint *srcPixels,
7772 extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha);
7773 extern void QT_FASTCALL comp_func_Plus_sse2(uint *dst, const uint *src, int length, uint const_alpha);
7774 extern void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, uint const_alpha);
7776 functionForModeAsm[0] = comp_func_SourceOver_sse2;
7777 functionForModeAsm[QPainter::CompositionMode_Source] = comp_func_Source_sse2;
7778 functionForModeAsm[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2;
7779 functionForModeSolidAsm[0] = comp_func_solid_SourceOver_sse2;
7783 #elif defined(QT_HAVE_SSE2)
7784 // this is the special case when SSE2 is usable but MMX/SSE is not usable (e.g.: Windows x64 + visual studio)
7785 if (features & SSE2) {
7786 functionForModeAsm = qt_functionForMode_onlySSE2;
7787 functionForModeSolidAsm = qt_functionForModeSolid_onlySSE2;
7791 #ifdef QT_HAVE_IWMMXT
7792 if (features & IWMMXT) {
7793 functionForModeAsm = qt_functionForMode_IWMMXT;
7794 functionForModeSolidAsm = qt_functionForModeSolid_IWMMXT;
7795 qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_iwmmxt;
7799 #if defined(QT_HAVE_ARM_SIMD)
7800 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_arm_simd;
7801 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_arm_simd;
7802 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_arm_simd;
7803 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_arm_simd;
7804 #elif defined(QT_HAVE_NEON)
7805 if (features & NEON) {
7806 qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
7807 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
7808 qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7809 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon;
7810 qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon;
7811 qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon;
7812 qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon;
7814 qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon;
7815 qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon;
7817 qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon;
7818 qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon;
7820 qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon;
7822 functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon;
7823 functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon;
7824 functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon;
7825 destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
7826 destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
7828 qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
7829 qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
7830 qt_memfill32 = qt_memfill32_neon;
7832 extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data,
7833 int y, int x, int length);
7835 qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon;
7839 if (functionForModeSolidAsm) {
7840 const int destinationMode = QPainter::CompositionMode_Destination;
7841 functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode];
7843 // use the default qdrawhelper implementation for the
7844 // extended composition modes
7845 for (int mode = 12; mode < 24; ++mode)
7846 functionForModeSolidAsm[mode] = functionForModeSolid_C[mode];
7848 functionForModeSolid = functionForModeSolidAsm;
7850 if (functionForModeAsm)
7851 functionForMode = functionForModeAsm;
7853 qt_build_pow_tables();
7856 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count)
7858 qInitDrawhelperAsm();
7859 qt_memfill32(dest, value, count);
7862 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count)
7864 qInitDrawhelperAsm();
7865 qt_memfill16(dest, value, count);
7868 #ifdef QT_QWS_DEPTH_GENERIC
7871 int qrgb::len_red = 0;
7872 int qrgb::len_green = 0;
7873 int qrgb::len_blue = 0;
7874 int qrgb::len_alpha = 0;
7875 int qrgb::off_red = 0;
7876 int qrgb::off_green = 0;
7877 int qrgb::off_blue = 0;
7878 int qrgb::off_alpha = 0;
7880 template <typename SRC>
7881 Q_STATIC_TEMPLATE_FUNCTION inline void qt_rectconvert_rgb(qrgb *dest, const SRC *src,
7882 int x, int y, int width, int height,
7883 int dstStride, int srcStride)
7885 quint8 *dest8 = reinterpret_cast<quint8*>(dest)
7886 + y * dstStride + x * qrgb::bpp;
7888 srcStride = srcStride / sizeof(SRC) - width;
7889 dstStride -= (width * qrgb::bpp);
7891 for (int j = 0; j < height; ++j) {
7892 for (int i = 0; i < width; ++i) {
7893 const quint32 v = qt_convertToRgb<SRC>(*src++);
7894 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
7895 for (int j = qrgb::bpp - 1; j >= 0; --j)
7896 *dest8++ = (v >> (8 * j)) & 0xff;
7898 for (int j = 0; j < qrgb::bpp; ++j)
7899 *dest8++ = (v >> (8 * j)) & 0xff;
7909 void qt_rectconvert(qrgb *dest, const quint32 *src,
7910 int x, int y, int width, int height,
7911 int dstStride, int srcStride)
7913 qt_rectconvert_rgb<quint32>(dest, src, x, y, width, height,
7914 dstStride, srcStride);
7918 void qt_rectconvert(qrgb *dest, const quint16 *src,
7919 int x, int y, int width, int height,
7920 int dstStride, int srcStride)
7922 qt_rectconvert_rgb<quint16>(dest, src, x, y, width, height,
7923 dstStride, srcStride);
7926 #endif // QT_QWS_DEPTH_GENERIC