Qt 4.8
qdrawhelper.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <private/qdrawhelper_p.h>
43 #include <private/qpaintengine_raster_p.h>
44 #include <private/qpainter_p.h>
45 #include <private/qdrawhelper_x86_p.h>
46 #ifdef QT_HAVE_ARM_SIMD
47 #include <private/qdrawhelper_arm_simd_p.h>
48 #endif
49 #include <private/qdrawhelper_neon_p.h>
50 #include <private/qmath_p.h>
51 #include <qmath.h>
52 
54 
55 
56 #define MASK(src, a) src = BYTE_MUL(src, a)
57 
58 #if defined(Q_OS_IRIX) && defined(Q_CC_GNU) && __GNUC__ == 3 && __GNUC__ < 4 && QT_POINTER_SIZE == 8
59 #define Q_IRIX_GCC3_3_WORKAROUND
60 //
61 // work around http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14484
62 //
63 static uint gccBug(uint value) __attribute__((noinline));
64 static uint gccBug(uint value)
65 {
66  return value;
67 }
68 #endif
69 
70 /*
71  constants and structures
72 */
73 
74 enum {
75  fixed_scale = 1 << 16,
76  half_point = 1 << 15
77 };
78 
79 // must be multiple of 4 for easier SIMD implementations
80 static const int buffer_size = 2048;
81 
82 /*
83  Destination fetch. This is simple as we don't have to do bounds checks or
84  transformations
85 */
86 
87 static uint * QT_FASTCALL destFetchMono(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
88 {
89  uchar *data = (uchar *)rasterBuffer->scanLine(y);
90  uint *start = buffer;
91  const uint *end = buffer + length;
92  while (buffer < end) {
93  *buffer = data[x>>3] & (0x80 >> (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
94  ++buffer;
95  ++x;
96  }
97  return start;
98 }
99 
100 static uint * QT_FASTCALL destFetchMonoLsb(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
101 {
102  uchar *data = (uchar *)rasterBuffer->scanLine(y);
103  uint *start = buffer;
104  const uint *end = buffer + length;
105  while (buffer < end) {
106  *buffer = data[x>>3] & (0x1 << (x & 7)) ? rasterBuffer->destColor1 : rasterBuffer->destColor0;
107  ++buffer;
108  ++x;
109  }
110  return start;
111 }
112 
113 static uint * QT_FASTCALL destFetchARGB32(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
114 {
115  const uint *data = (const uint *)rasterBuffer->scanLine(y) + x;
116  for (int i = 0; i < length; ++i)
117  buffer[i] = PREMUL(data[i]);
118  return buffer;
119 }
120 
121 static uint * QT_FASTCALL destFetchARGB32P(uint *, QRasterBuffer *rasterBuffer, int x, int y, int)
122 {
123  return (uint *)rasterBuffer->scanLine(y) + x;
124 }
125 
126 static uint * QT_FASTCALL destFetchRGB16(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
127 {
128  const ushort *data = (const ushort *)rasterBuffer->scanLine(y) + x;
129  for (int i = 0; i < length; ++i)
130  buffer[i] = qConvertRgb16To32(data[i]);
131  return buffer;
132 }
133 
134 template <class DST>
136  int x, int y, int length)
137 {
138  const DST *src = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
139  quint32 *dest = reinterpret_cast<quint32*>(buffer);
140  while (length--)
141  *dest++ = *src++;
142  return buffer;
143 }
144 
145 # define SPANFUNC_POINTER_DESTFETCH(Arg) destFetch<Arg>
146 
147 static DestFetchProc destFetchProc[QImage::NImageFormats] =
148 {
149  0, // Format_Invalid
150  destFetchMono, // Format_Mono,
151  destFetchMonoLsb, // Format_MonoLSB
152  0, // Format_Indexed8
153  destFetchARGB32P, // Format_RGB32
154  destFetchARGB32, // Format_ARGB32,
155  destFetchARGB32P, // Format_ARGB32_Premultiplied
156  destFetchRGB16, // Format_RGB16
157  SPANFUNC_POINTER_DESTFETCH(qargb8565), // Format_ARGB8565_Premultiplied
158  SPANFUNC_POINTER_DESTFETCH(qrgb666), // Format_RGB666
159  SPANFUNC_POINTER_DESTFETCH(qargb6666), // Format_ARGB6666_Premultiplied
160  SPANFUNC_POINTER_DESTFETCH(qrgb555), // Format_RGB555
161  SPANFUNC_POINTER_DESTFETCH(qargb8555), // Format_ARGB8555_Premultiplied
162  SPANFUNC_POINTER_DESTFETCH(qrgb888), // Format_RGB888
163  SPANFUNC_POINTER_DESTFETCH(qrgb444), // Format_RGB444
164  SPANFUNC_POINTER_DESTFETCH(qargb4444) // Format_ARGB4444_Premultiplied
165 };
166 
167 /*
168  Returns the color in the mono destination color table
169  that is the "nearest" to /color/.
170 */
171 static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
172 {
173  QRgb color_0 = PREMUL(rbuf->destColor0);
174  QRgb color_1 = PREMUL(rbuf->destColor1);
175  color = PREMUL(color);
176 
177  int r = qRed(color);
178  int g = qGreen(color);
179  int b = qBlue(color);
180  int rx, gx, bx;
181  int dist_0, dist_1;
182 
183  rx = r - qRed(color_0);
184  gx = g - qGreen(color_0);
185  bx = b - qBlue(color_0);
186  dist_0 = rx*rx + gx*gx + bx*bx;
187 
188  rx = r - qRed(color_1);
189  gx = g - qGreen(color_1);
190  bx = b - qBlue(color_1);
191  dist_1 = rx*rx + gx*gx + bx*bx;
192 
193  if (dist_0 < dist_1)
194  return color_0;
195  return color_1;
196 }
197 
198 /*
199  Destination store.
200 */
201 
202 static void QT_FASTCALL destStoreMono(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
203 {
204  uchar *data = (uchar *)rasterBuffer->scanLine(y);
205  if (rasterBuffer->monoDestinationWithClut) {
206  for (int i = 0; i < length; ++i) {
207  if (buffer[i] == rasterBuffer->destColor0) {
208  data[x >> 3] &= ~(0x80 >> (x & 7));
209  } else if (buffer[i] == rasterBuffer->destColor1) {
210  data[x >> 3] |= 0x80 >> (x & 7);
211  } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
212  data[x >> 3] &= ~(0x80 >> (x & 7));
213  } else {
214  data[x >> 3] |= 0x80 >> (x & 7);
215  }
216  ++x;
217  }
218  } else {
219  for (int i = 0; i < length; ++i) {
220  if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
221  data[x >> 3] |= 0x80 >> (x & 7);
222  else
223  data[x >> 3] &= ~(0x80 >> (x & 7));
224  ++x;
225  }
226  }
227 }
228 
229 static void QT_FASTCALL destStoreMonoLsb(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
230 {
231  uchar *data = (uchar *)rasterBuffer->scanLine(y);
232  if (rasterBuffer->monoDestinationWithClut) {
233  for (int i = 0; i < length; ++i) {
234  if (buffer[i] == rasterBuffer->destColor0) {
235  data[x >> 3] &= ~(1 << (x & 7));
236  } else if (buffer[i] == rasterBuffer->destColor1) {
237  data[x >> 3] |= 1 << (x & 7);
238  } else if (findNearestColor(buffer[i], rasterBuffer) == rasterBuffer->destColor0) {
239  data[x >> 3] &= ~(1 << (x & 7));
240  } else {
241  data[x >> 3] |= 1 << (x & 7);
242  }
243  ++x;
244  }
245  } else {
246  for (int i = 0; i < length; ++i) {
247  if (qGray(buffer[i]) < int(qt_bayer_matrix[y & 15][x & 15]))
248  data[x >> 3] |= 1 << (x & 7);
249  else
250  data[x >> 3] &= ~(1 << (x & 7));
251  ++x;
252  }
253  }
254 }
255 
256 static void QT_FASTCALL destStoreARGB32(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
257 {
258  uint *data = (uint *)rasterBuffer->scanLine(y) + x;
259  for (int i = 0; i < length; ++i) {
260  int p = buffer[i];
261  int alpha = qAlpha(p);
262  if (alpha == 255)
263  data[i] = p;
264  else if (alpha == 0)
265  data[i] = 0;
266  else {
267  int inv_alpha = 0xff0000/qAlpha(buffer[i]);
268  data[i] = (p & 0xff000000)
269  | ((qRed(p)*inv_alpha) & 0xff0000)
270  | (((qGreen(p)*inv_alpha) >> 8) & 0xff00)
271  | ((qBlue(p)*inv_alpha) >> 16);
272  }
273  }
274 }
275 
276 static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
277 {
278  quint16 *data = (quint16*)rasterBuffer->scanLine(y) + x;
279  qt_memconvert<quint16, quint32>(data, buffer, length);
280 }
281 
282 template <class DST>
284  int x, int y,
285  const uint *buffer, int length)
286 {
287  DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
288  const quint32p *src = reinterpret_cast<const quint32p*>(buffer);
289  while (length--)
290  *dest++ = DST(*src++);
291 }
292 
293 # define SPANFUNC_POINTER_DESTSTORE(DEST) destStore<DEST>
294 
295 static DestStoreProc destStoreProc[QImage::NImageFormats] =
296 {
297  0, // Format_Invalid
298  destStoreMono, // Format_Mono,
299  destStoreMonoLsb, // Format_MonoLSB
300  0, // Format_Indexed8
301  0, // Format_RGB32
302  destStoreARGB32, // Format_ARGB32,
303  0, // Format_ARGB32_Premultiplied
304  destStoreRGB16, // Format_RGB16
305  SPANFUNC_POINTER_DESTSTORE(qargb8565), // Format_ARGB8565_Premultiplied
306  SPANFUNC_POINTER_DESTSTORE(qrgb666), // Format_RGB666
307  SPANFUNC_POINTER_DESTSTORE(qargb6666), // Format_ARGB6666_Premultiplied
308  SPANFUNC_POINTER_DESTSTORE(qrgb555), // Format_RGB555
309  SPANFUNC_POINTER_DESTSTORE(qargb8555), // Format_ARGB8555_Premultiplied
310  SPANFUNC_POINTER_DESTSTORE(qrgb888), // Format_RGB888
311  SPANFUNC_POINTER_DESTSTORE(qrgb444), // Format_RGB444
312  SPANFUNC_POINTER_DESTSTORE(qargb4444) // Format_ARGB4444_Premultiplied
313 };
314 
315 /*
316  Source fetches
317 
318  This is a bit more complicated, as we need several fetch routines for every surface type
319 
320  We need 5 fetch methods per surface type:
321  untransformed
322  transformed (tiled and not tiled)
323  transformed bilinear (tiled and not tiled)
324 
325  We don't need bounds checks for untransformed, but we need them for the other ones.
326 
327  The generic implementation does pixel by pixel fetches
328 */
329 
330 template <QImage::Format format>
332 
333 template<>
335 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Mono>(const uchar *scanLine,
336  int x, const QVector<QRgb> *rgb)
337 {
338  bool pixel = scanLine[x>>3] & (0x80 >> (x & 7));
339  if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
340  return pixel ? 0xff000000 : 0xffffffff;
341 }
342 
343 template<>
345 uint QT_FASTCALL qt_fetchPixel<QImage::Format_MonoLSB>(const uchar *scanLine,
346  int x, const QVector<QRgb> *rgb)
347 {
348  bool pixel = scanLine[x>>3] & (0x1 << (x & 7));
349  if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
350  return pixel ? 0xff000000 : 0xffffffff;
351 }
352 
353 template<>
355 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Indexed8>(const uchar *scanLine,
356  int x, const QVector<QRgb> *rgb)
357 {
358  return PREMUL(rgb->at(scanLine[x]));
359 }
360 
361 template<>
363 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32>(const uchar *scanLine,
364  int x, const QVector<QRgb> *)
365 {
366  return PREMUL(((const uint *)scanLine)[x]);
367 }
368 
369 template<>
371 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32_Premultiplied>(const uchar *scanLine,
372  int x, const QVector<QRgb> *)
373 {
374  return ((const uint *)scanLine)[x];
375 }
376 
377 template<>
379 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB16>(const uchar *scanLine,
380  int x, const QVector<QRgb> *)
381 {
382  return qConvertRgb16To32(((const ushort *)scanLine)[x]);
383 }
384 
385 template<>
387 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8565_Premultiplied>(const uchar *scanLine,
388  int x,
389  const QVector<QRgb> *)
390 {
391  const qargb8565 color = reinterpret_cast<const qargb8565*>(scanLine)[x];
392  return qt_colorConvert<quint32, qargb8565>(color, 0);
393 }
394 
395 template<>
397 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB666>(const uchar *scanLine,
398  int x,
399  const QVector<QRgb> *)
400 {
401  const qrgb666 color = reinterpret_cast<const qrgb666*>(scanLine)[x];
402  return qt_colorConvert<quint32, qrgb666>(color, 0);
403 }
404 
405 template<>
407 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB6666_Premultiplied>(const uchar *scanLine,
408  int x,
409  const QVector<QRgb> *)
410 {
411  const qargb6666 color = reinterpret_cast<const qargb6666*>(scanLine)[x];
412  return qt_colorConvert<quint32, qargb6666>(color, 0);
413 }
414 
415 template<>
417 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB555>(const uchar *scanLine,
418  int x,
419  const QVector<QRgb> *)
420 {
421  const qrgb555 color = reinterpret_cast<const qrgb555*>(scanLine)[x];
422  return qt_colorConvert<quint32, qrgb555>(color, 0);
423 }
424 
425 template<>
427 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8555_Premultiplied>(const uchar *scanLine,
428  int x,
429  const QVector<QRgb> *)
430 {
431  const qargb8555 color = reinterpret_cast<const qargb8555*>(scanLine)[x];
432  return qt_colorConvert<quint32, qargb8555>(color, 0);
433 }
434 
435 template<>
437 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB888>(const uchar *scanLine,
438  int x,
439  const QVector<QRgb> *)
440 {
441  const qrgb888 color = reinterpret_cast<const qrgb888*>(scanLine)[x];
442  return qt_colorConvert<quint32, qrgb888>(color, 0);
443 }
444 
445 template<>
447 uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB444>(const uchar *scanLine,
448  int x,
449  const QVector<QRgb> *)
450 {
451  const qrgb444 color = reinterpret_cast<const qrgb444*>(scanLine)[x];
452  return qt_colorConvert<quint32, qrgb444>(color, 0);
453 }
454 
455 template<>
457 uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB4444_Premultiplied>(const uchar *scanLine,
458  int x,
459  const QVector<QRgb> *)
460 {
461  const qargb4444 color = reinterpret_cast<const qargb4444*>(scanLine)[x];
462  return qt_colorConvert<quint32, qargb4444>(color, 0);
463 }
464 
465 template<>
467 uint QT_FASTCALL qt_fetchPixel<QImage::Format_Invalid>(const uchar *,
468  int ,
469  const QVector<QRgb> *)
470 {
471  return 0;
472 }
473 
474 typedef uint (QT_FASTCALL *FetchPixelProc)(const uchar *scanLine, int x, const QVector<QRgb> *);
475 
476 #define SPANFUNC_POINTER_FETCHPIXEL(Arg) qt_fetchPixel<QImage::Arg>
477 
478 
479 static const FetchPixelProc fetchPixelProc[QImage::NImageFormats] =
480 {
481  0,
482  SPANFUNC_POINTER_FETCHPIXEL(Format_Mono),
483  SPANFUNC_POINTER_FETCHPIXEL(Format_MonoLSB),
484  SPANFUNC_POINTER_FETCHPIXEL(Format_Indexed8),
485  SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
486  SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32),
487  SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
488  SPANFUNC_POINTER_FETCHPIXEL(Format_RGB16),
489  SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8565_Premultiplied),
490  SPANFUNC_POINTER_FETCHPIXEL(Format_RGB666),
491  SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB6666_Premultiplied),
492  SPANFUNC_POINTER_FETCHPIXEL(Format_RGB555),
493  SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8555_Premultiplied),
494  SPANFUNC_POINTER_FETCHPIXEL(Format_RGB888),
495  SPANFUNC_POINTER_FETCHPIXEL(Format_RGB444),
496  SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB4444_Premultiplied)
497 };
498 
507 };
508 
509 template <QImage::Format format>
511  int y, int x, int length)
512 {
513  const uchar *scanLine = data->texture.scanLine(y);
514  for (int i = 0; i < length; ++i)
515  buffer[i] = qt_fetchPixel<format>(scanLine, x + i, data->texture.colorTable);
516  return buffer;
517 }
518 
519 template <>
521 qt_fetchUntransformed<QImage::Format_ARGB32_Premultiplied>(uint *, const Operator *,
522  const QSpanData *data,
523  int y, int x, int)
524 {
525  const uchar *scanLine = data->texture.scanLine(y);
526  return ((const uint *)scanLine) + x;
527 }
528 
529 template<TextureBlendType blendType> /* either BlendTransformed or BlendTransformedTiled */
531 const uint * QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data,
532  int y, int x, int length)
533 {
534  FetchPixelProc fetch = fetchPixelProc[data->texture.format];
535 
536  int image_width = data->texture.width;
537  int image_height = data->texture.height;
538 
539  const qreal cx = x + qreal(0.5);
540  const qreal cy = y + qreal(0.5);
541 
542  const uint *end = buffer + length;
543  uint *b = buffer;
544  if (data->fast_matrix) {
545  // The increment pr x in the scanline
546  int fdx = (int)(data->m11 * fixed_scale);
547  int fdy = (int)(data->m12 * fixed_scale);
548 
549  int fx = int((data->m21 * cy
550  + data->m11 * cx + data->dx) * fixed_scale);
551  int fy = int((data->m22 * cy
552  + data->m12 * cx + data->dy) * fixed_scale);
553 
554  while (b < end) {
555  int px = fx >> 16;
556  int py = fy >> 16;
557 
558  if (blendType == BlendTransformedTiled) {
559  px %= image_width;
560  py %= image_height;
561  if (px < 0) px += image_width;
562  if (py < 0) py += image_height;
563 
564  const uchar *scanLine = data->texture.scanLine(py);
565  *b = fetch(scanLine, px, data->texture.colorTable);
566  } else {
567  if ((px < 0) || (px >= image_width)
568  || (py < 0) || (py >= image_height)) {
569  *b = uint(0);
570  } else {
571  const uchar *scanLine = data->texture.scanLine(py);
572  *b = fetch(scanLine, px, data->texture.colorTable);
573  }
574  }
575  fx += fdx;
576  fy += fdy;
577  ++b;
578  }
579  } else {
580  const qreal fdx = data->m11;
581  const qreal fdy = data->m12;
582  const qreal fdw = data->m13;
583 
584  qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
585  qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
586  qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
587 
588  while (b < end) {
589  const qreal iw = fw == 0 ? 1 : 1 / fw;
590  const qreal tx = fx * iw;
591  const qreal ty = fy * iw;
592  int px = int(tx) - (tx < 0);
593  int py = int(ty) - (ty < 0);
594 
595  if (blendType == BlendTransformedTiled) {
596  px %= image_width;
597  py %= image_height;
598  if (px < 0) px += image_width;
599  if (py < 0) py += image_height;
600 
601  const uchar *scanLine = data->texture.scanLine(py);
602  *b = fetch(scanLine, px, data->texture.colorTable);
603  } else {
604  if ((px < 0) || (px >= image_width)
605  || (py < 0) || (py >= image_height)) {
606  *b = uint(0);
607  } else {
608  const uchar *scanLine = data->texture.scanLine(py);
609  *b = fetch(scanLine, px, data->texture.colorTable);
610  }
611  }
612  fx += fdx;
613  fy += fdy;
614  fw += fdw;
615  //force increment to avoid /0
616  if (!fw) {
617  fw += fdw;
618  }
619  ++b;
620  }
621  }
622 
623  return buffer;
624 }
625 
630 static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, int distx, int disty)
631 {
632  uint distxy = distx * disty;
633  //idistx * disty = (16-distx) * disty = 16*disty - distxy
634  //idistx * idisty = (16-distx) * (16-disty) = 16*16 - 16*distx -16*dity + distxy
635  uint tlrb = (tl & 0x00ff00ff) * (16*16 - 16*distx - 16*disty + distxy);
636  uint tlag = ((tl & 0xff00ff00) >> 8) * (16*16 - 16*distx - 16*disty + distxy);
637  uint trrb = ((tr & 0x00ff00ff) * (distx*16 - distxy));
638  uint trag = (((tr & 0xff00ff00) >> 8) * (distx*16 - distxy));
639  uint blrb = ((bl & 0x00ff00ff) * (disty*16 - distxy));
640  uint blag = (((bl & 0xff00ff00) >> 8) * (disty*16 - distxy));
641  uint brrb = ((br & 0x00ff00ff) * (distxy));
642  uint brag = (((br & 0xff00ff00) >> 8) * (distxy));
643  return (((tlrb + trrb + blrb + brrb) >> 8) & 0x00ff00ff) | ((tlag + trag + blag + brag) & 0xff00ff00);
644 }
645 
646 #if defined(QT_ALWAYS_HAVE_SSE2)
647 #define interpolate_4_pixels_16_sse2(tl, tr, bl, br, distx, disty, colorMask, v_256, b) \
648 { \
649  const __m128i dxdy = _mm_mullo_epi16 (distx, disty); \
650  const __m128i distx_ = _mm_slli_epi16(distx, 4); \
651  const __m128i disty_ = _mm_slli_epi16(disty, 4); \
652  const __m128i idxidy = _mm_add_epi16(dxdy, _mm_sub_epi16(v_256, _mm_add_epi16(distx_, disty_))); \
653  const __m128i dxidy = _mm_sub_epi16(distx_, dxdy); \
654  const __m128i idxdy = _mm_sub_epi16(disty_, dxdy); \
655  \
656  __m128i tlAG = _mm_srli_epi16(tl, 8); \
657  __m128i tlRB = _mm_and_si128(tl, colorMask); \
658  __m128i trAG = _mm_srli_epi16(tr, 8); \
659  __m128i trRB = _mm_and_si128(tr, colorMask); \
660  __m128i blAG = _mm_srli_epi16(bl, 8); \
661  __m128i blRB = _mm_and_si128(bl, colorMask); \
662  __m128i brAG = _mm_srli_epi16(br, 8); \
663  __m128i brRB = _mm_and_si128(br, colorMask); \
664  \
665  tlAG = _mm_mullo_epi16(tlAG, idxidy); \
666  tlRB = _mm_mullo_epi16(tlRB, idxidy); \
667  trAG = _mm_mullo_epi16(trAG, dxidy); \
668  trRB = _mm_mullo_epi16(trRB, dxidy); \
669  blAG = _mm_mullo_epi16(blAG, idxdy); \
670  blRB = _mm_mullo_epi16(blRB, idxdy); \
671  brAG = _mm_mullo_epi16(brAG, dxdy); \
672  brRB = _mm_mullo_epi16(brRB, dxdy); \
673  \
674  /* Add the values, and shift to only keep 8 significant bits per colors */ \
675  __m128i rAG =_mm_add_epi16(_mm_add_epi16(tlAG, trAG), _mm_add_epi16(blAG, brAG)); \
676  __m128i rRB =_mm_add_epi16(_mm_add_epi16(tlRB, trRB), _mm_add_epi16(blRB, brRB)); \
677  rAG = _mm_andnot_si128(colorMask, rAG); \
678  rRB = _mm_srli_epi16(rRB, 8); \
679  _mm_storeu_si128((__m128i*)(b), _mm_or_si128(rAG, rRB)); \
680 }
681 #endif
682 
683 #if defined(QT_ALWAYS_HAVE_NEON)
684 #define interpolate_4_pixels_16_neon(tl, tr, bl, br, distx, disty, disty_, colorMask, invColorMask, v_256, b) \
685 { \
686  const int16x8_t dxdy = vmulq_s16(distx, disty); \
687  const int16x8_t distx_ = vshlq_n_s16(distx, 4); \
688  const int16x8_t idxidy = vaddq_s16(dxdy, vsubq_s16(v_256, vaddq_s16(distx_, disty_))); \
689  const int16x8_t dxidy = vsubq_s16(distx_, dxdy); \
690  const int16x8_t idxdy = vsubq_s16(disty_, dxdy); \
691  \
692  int16x8_t tlAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tl), 8)); \
693  int16x8_t tlRB = vandq_s16(tl, colorMask); \
694  int16x8_t trAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(tr), 8)); \
695  int16x8_t trRB = vandq_s16(tr, colorMask); \
696  int16x8_t blAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bl), 8)); \
697  int16x8_t blRB = vandq_s16(bl, colorMask); \
698  int16x8_t brAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(br), 8)); \
699  int16x8_t brRB = vandq_s16(br, colorMask); \
700  \
701  int16x8_t rAG = vmulq_s16(tlAG, idxidy); \
702  int16x8_t rRB = vmulq_s16(tlRB, idxidy); \
703  rAG = vmlaq_s16(rAG, trAG, dxidy); \
704  rRB = vmlaq_s16(rRB, trRB, dxidy); \
705  rAG = vmlaq_s16(rAG, blAG, idxdy); \
706  rRB = vmlaq_s16(rRB, blRB, idxdy); \
707  rAG = vmlaq_s16(rAG, brAG, dxdy); \
708  rRB = vmlaq_s16(rRB, brRB, dxdy); \
709  \
710  rAG = vandq_s16(invColorMask, rAG); \
711  rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8)); \
712  vst1q_s16((int16_t*)(b), vorrq_s16(rAG, rRB)); \
713 }
714 #endif
715 
716 template<TextureBlendType blendType>
717 Q_STATIC_TEMPLATE_FUNCTION inline void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2)
718 {
719  if (blendType == BlendTransformedBilinearTiled) {
720  v1 %= max;
721  if (v1 < 0) v1 += max;
722  v2 = v1 + 1;
723  v2 %= max;
724  } else {
725  if (v1 < l1) {
726  v2 = v1 = l1;
727  } else if (v1 >= l2) {
728  v2 = v1 = l2;
729  } else {
730  v2 = v1 + 1;
731  }
732  }
733 
734  Q_ASSERT(v1 >= 0 && v1 < max);
735  Q_ASSERT(v2 >= 0 && v2 < max);
736 }
737 
738 template<TextureBlendType blendType, QImage::Format format> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
740 const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *, const QSpanData *data,
741  int y, int x, int length)
742 {
743 #ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
744  FetchPixelProc fetch;
746  fetch = qt_fetchPixel<format>;
747  else
748  fetch = fetchPixelProc[data->texture.format];
749 #else
750  FetchPixelProc fetch = (format != QImage::Format_Invalid) ? FetchPixelProc(qt_fetchPixel<format>) : fetchPixelProc[data->texture.format];
751 #endif
752 
753  int image_width = data->texture.width;
754  int image_height = data->texture.height;
755 
756  int image_x1 = data->texture.x1;
757  int image_y1 = data->texture.y1;
758  int image_x2 = data->texture.x2 - 1;
759  int image_y2 = data->texture.y2 - 1;
760 
761  const qreal cx = x + qreal(0.5);
762  const qreal cy = y + qreal(0.5);
763 
764  uint *end = buffer + length;
765  uint *b = buffer;
766  if (data->fast_matrix) {
767  // The increment pr x in the scanline
768  int fdx = (int)(data->m11 * fixed_scale);
769  int fdy = (int)(data->m12 * fixed_scale);
770 
771  int fx = int((data->m21 * cy
772  + data->m11 * cx + data->dx) * fixed_scale);
773  int fy = int((data->m22 * cy
774  + data->m12 * cx + data->dy) * fixed_scale);
775 
776  fx -= half_point;
777  fy -= half_point;
778 
779  if (fdy == 0) { //simple scale, no rotation
780  int y1 = (fy >> 16);
781  int y2;
782  fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
783  const uchar *s1 = data->texture.scanLine(y1);
784  const uchar *s2 = data->texture.scanLine(y2);
785 
786  if (fdx <= fixed_scale && fdx > 0) { // scale up on X
787  int disty = (fy & 0x0000ffff) >> 8;
788  int idisty = 256 - disty;
789  int x = fx >> 16;
790 
791  // The idea is first to do the interpolation between the row s1 and the row s2
792  // into an intermediate buffer, then we interpolate between two pixel of this buffer.
793 
794  // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
795  // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG
796  quint32 intermediate_buffer[2][buffer_size + 2];
797  // count is the size used in the intermediate_buffer.
798  int count = qCeil(length * data->m11) + 2; //+1 for the last pixel to interpolate with, and +1 for rounding errors.
799  Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
800  int f = 0;
801  int lim = count;
802  if (blendType == BlendTransformedBilinearTiled) {
803  x %= image_width;
804  if (x < 0) x += image_width;
805  } else {
806  lim = qMin(count, image_x2-x+1);
807  if (x < image_x1) {
808  Q_ASSERT(x <= image_x2);
809  uint t = fetch(s1, image_x1, data->texture.colorTable);
810  uint b = fetch(s2, image_x1, data->texture.colorTable);
811  quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
812  quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
813  do {
814  intermediate_buffer[0][f] = rb;
815  intermediate_buffer[1][f] = ag;
816  f++;
817  x++;
818  } while (x < image_x1 && f < lim);
819  }
820  }
821 
822  if (blendType != BlendTransformedBilinearTiled &&
824 #if defined(QT_ALWAYS_HAVE_SSE2)
825  const __m128i disty_ = _mm_set1_epi16(disty);
826  const __m128i idisty_ = _mm_set1_epi16(idisty);
827  const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
828 
829  lim -= 3;
830  for (; f < lim; x += 4, f += 4) {
831  // Load 4 pixels from s1, and split the alpha-green and red-blue component
832  __m128i top = _mm_loadu_si128((__m128i*)((const uint *)(s1)+x));
833  __m128i topAG = _mm_srli_epi16(top, 8);
834  __m128i topRB = _mm_and_si128(top, colorMask);
835  // Multiplies each colour component by idisty
836  topAG = _mm_mullo_epi16 (topAG, idisty_);
837  topRB = _mm_mullo_epi16 (topRB, idisty_);
838 
839  // Same for the s2 vector
840  __m128i bottom = _mm_loadu_si128((__m128i*)((const uint *)(s2)+x));
841  __m128i bottomAG = _mm_srli_epi16(bottom, 8);
842  __m128i bottomRB = _mm_and_si128(bottom, colorMask);
843  bottomAG = _mm_mullo_epi16 (bottomAG, disty_);
844  bottomRB = _mm_mullo_epi16 (bottomRB, disty_);
845 
846  // Add the values, and shift to only keep 8 significant bits per colors
847  __m128i rAG =_mm_add_epi16(topAG, bottomAG);
848  rAG = _mm_srli_epi16(rAG, 8);
849  _mm_storeu_si128((__m128i*)(&intermediate_buffer[1][f]), rAG);
850  __m128i rRB =_mm_add_epi16(topRB, bottomRB);
851  rRB = _mm_srli_epi16(rRB, 8);
852  _mm_storeu_si128((__m128i*)(&intermediate_buffer[0][f]), rRB);
853  }
854 #elif defined(QT_ALWAYS_HAVE_NEON)
855  const int16x8_t disty_ = vdupq_n_s16(disty);
856  const int16x8_t idisty_ = vdupq_n_s16(idisty);
857  const int16x8_t colorMask = vdupq_n_s16(0x00ff);
858 
859  lim -= 3;
860  for (; f < lim; x += 4, f += 4) {
861  // Load 4 pixels from s1, and split the alpha-green and red-blue component
862  int16x8_t top = vld1q_s16((int16_t*)((const uint *)(s1)+x));
863  int16x8_t topAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(top), 8));
864  int16x8_t topRB = vandq_s16(top, colorMask);
865  // Multiplies each colour component by idisty
866  topAG = vmulq_s16(topAG, idisty_);
867  topRB = vmulq_s16(topRB, idisty_);
868 
869  // Same for the s2 vector
870  int16x8_t bottom = vld1q_s16((int16_t*)((const uint *)(s2)+x));
871  int16x8_t bottomAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bottom), 8));
872  int16x8_t bottomRB = vandq_s16(bottom, colorMask);
873  bottomAG = vmulq_s16(bottomAG, disty_);
874  bottomRB = vmulq_s16(bottomRB, disty_);
875 
876  // Add the values, and shift to only keep 8 significant bits per colors
877  int16x8_t rAG = vaddq_s16(topAG, bottomAG);
878  rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8));
879  vst1q_s16((int16_t*)(&intermediate_buffer[1][f]), rAG);
880  int16x8_t rRB = vaddq_s16(topRB, bottomRB);
881  rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8));
882  vst1q_s16((int16_t*)(&intermediate_buffer[0][f]), rRB);
883  }
884 #endif
885  }
886  for (; f < count; f++) { // Same as above but without sse2
887  if (blendType == BlendTransformedBilinearTiled) {
888  if (x >= image_width) x -= image_width;
889  } else {
890  x = qMin(x, image_x2);
891  }
892 
893  uint t = fetch(s1, x, data->texture.colorTable);
894  uint b = fetch(s2, x, data->texture.colorTable);
895 
896  intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
897  intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
898  x++;
899  }
900  // Now interpolate the values from the intermediate_buffer to get the final result.
901  fx &= fixed_scale - 1;
902  Q_ASSERT((fx >> 16) == 0);
903  while (b < end) {
904  register int x1 = (fx >> 16);
905  register int x2 = x1 + 1;
906  Q_ASSERT(x1 >= 0);
907  Q_ASSERT(x2 < count);
908 
909  register int distx = (fx & 0x0000ffff) >> 8;
910  register int idistx = 256 - distx;
911  int rb = ((intermediate_buffer[0][x1] * idistx + intermediate_buffer[0][x2] * distx) >> 8) & 0xff00ff;
912  int ag = (intermediate_buffer[1][x1] * idistx + intermediate_buffer[1][x2] * distx) & 0xff00ff00;
913  *b = rb | ag;
914  b++;
915  fx += fdx;
916  }
917  } else if ((fdx < 0 && fdx > -(fixed_scale / 8)) || fabs(data->m22) < (1./8.)) { // scale up more than 8x
918  int y1 = (fy >> 16);
919  int y2;
920  fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
921  const uchar *s1 = data->texture.scanLine(y1);
922  const uchar *s2 = data->texture.scanLine(y2);
923  int disty = (fy & 0x0000ffff) >> 8;
924  int idisty = 256 - disty;
925  while (b < end) {
926  int x1 = (fx >> 16);
927  int x2;
928  fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
929  uint tl = fetch(s1, x1, data->texture.colorTable);
930  uint tr = fetch(s1, x2, data->texture.colorTable);
931  uint bl = fetch(s2, x1, data->texture.colorTable);
932  uint br = fetch(s2, x2, data->texture.colorTable);
933 
934  int distx = (fx & 0x0000ffff) >> 8;
935  int idistx = 256 - distx;
936 
937  uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
938  uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
939  *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
940 
941  fx += fdx;
942  ++b;
943  }
944  } else { //scale down
945  int y1 = (fy >> 16);
946  int y2;
947  fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
948  const uchar *s1 = data->texture.scanLine(y1);
949  const uchar *s2 = data->texture.scanLine(y2);
950  int disty = (fy & 0x0000ffff) >> 12;
951 
952  if (blendType != BlendTransformedBilinearTiled &&
954 
955 #define BILINEAR_DOWNSCALE_BOUNDS_PROLOG \
956  while (b < end) { \
957  int x1 = (fx >> 16); \
958  int x2; \
959  fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); \
960  if (x1 != x2) \
961  break; \
962  uint tl = fetch(s1, x1, data->texture.colorTable); \
963  uint tr = fetch(s1, x2, data->texture.colorTable); \
964  uint bl = fetch(s2, x1, data->texture.colorTable); \
965  uint br = fetch(s2, x2, data->texture.colorTable); \
966  int distx = (fx & 0x0000ffff) >> 12; \
967  *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty); \
968  fx += fdx; \
969  ++b; \
970  } \
971  uint *boundedEnd; \
972  if (fdx > 0) \
973  boundedEnd = qMin(end, buffer + uint((image_x2 - (fx >> 16)) / data->m11)); \
974  else \
975  boundedEnd = qMin(end, buffer + uint((image_x1 - (fx >> 16)) / data->m11)); \
976  boundedEnd -= 3;
977 
978 #if defined(QT_ALWAYS_HAVE_SSE2)
980 
981  const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
982  const __m128i v_256 = _mm_set1_epi16(256);
983  const __m128i v_disty = _mm_set1_epi16(disty);
984  __m128i v_fdx = _mm_set1_epi32(fdx*4);
985 
986  ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
987 
988  union Vect_buffer { __m128i vect; quint32 i[4]; };
989  Vect_buffer v_fx;
990 
991  for (int i = 0; i < 4; i++) {
992  v_fx.i[i] = fx;
993  fx += fdx;
994  }
995 
996  while (b < boundedEnd) {
997 
998  Vect_buffer tl, tr, bl, br;
999 
1000  for (int i = 0; i < 4; i++) {
1001  int x1 = v_fx.i[i] >> 16;
1002  const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1003  const uint *addr_tr = addr_tl + 1;
1004  tl.i[i] = *addr_tl;
1005  tr.i[i] = *addr_tr;
1006  bl.i[i] = *(addr_tl+secondLine);
1007  br.i[i] = *(addr_tr+secondLine);
1008  }
1009  __m128i v_distx = _mm_srli_epi16(v_fx.vect, 12);
1010  v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1011  v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
1012 
1013  interpolate_4_pixels_16_sse2(tl.vect, tr.vect, bl.vect, br.vect, v_distx, v_disty, colorMask, v_256, b);
1014  b+=4;
1015  v_fx.vect = _mm_add_epi32(v_fx.vect, v_fdx);
1016  }
1017  fx = v_fx.i[0];
1018 #elif defined(QT_ALWAYS_HAVE_NEON)
1020 
1021  const int16x8_t colorMask = vdupq_n_s16(0x00ff);
1022  const int16x8_t invColorMask = vmvnq_s16(colorMask);
1023  const int16x8_t v_256 = vdupq_n_s16(256);
1024  const int16x8_t v_disty = vdupq_n_s16(disty);
1025  const int16x8_t v_disty_ = vshlq_n_s16(v_disty, 4);
1026  int32x4_t v_fdx = vdupq_n_s32(fdx*4);
1027 
1028  ptrdiff_t secondLine = reinterpret_cast<const uint *>(s2) - reinterpret_cast<const uint *>(s1);
1029 
1030  union Vect_buffer { int32x4_t vect; quint32 i[4]; };
1031  Vect_buffer v_fx;
1032 
1033  for (int i = 0; i < 4; i++) {
1034  v_fx.i[i] = fx;
1035  fx += fdx;
1036  }
1037 
1038  const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
1039 
1040  while (b < boundedEnd) {
1041 
1042  Vect_buffer tl, tr, bl, br;
1043 
1044  Vect_buffer v_fx_shifted;
1045  v_fx_shifted.vect = vshrq_n_s32(v_fx.vect, 16);
1046 
1047  int32x4_t v_distx = vshrq_n_s32(vandq_s32(v_fx.vect, v_ffff_mask), 12);
1048 
1049  for (int i = 0; i < 4; i++) {
1050  int x1 = v_fx_shifted.i[i];
1051  const uint *addr_tl = reinterpret_cast<const uint *>(s1) + x1;
1052  const uint *addr_tr = addr_tl + 1;
1053  tl.i[i] = *addr_tl;
1054  tr.i[i] = *addr_tr;
1055  bl.i[i] = *(addr_tl+secondLine);
1056  br.i[i] = *(addr_tr+secondLine);
1057  }
1058 
1059  v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
1060 
1061  interpolate_4_pixels_16_neon(vreinterpretq_s16_s32(tl.vect), vreinterpretq_s16_s32(tr.vect), vreinterpretq_s16_s32(bl.vect), vreinterpretq_s16_s32(br.vect), vreinterpretq_s16_s32(v_distx), v_disty, v_disty_, colorMask, invColorMask, v_256, b);
1062  b+=4;
1063  v_fx.vect = vaddq_s32(v_fx.vect, v_fdx);
1064  }
1065  fx = v_fx.i[0];
1066 #endif
1067  }
1068 
1069  while (b < end) {
1070  int x1 = (fx >> 16);
1071  int x2;
1072  fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1073  uint tl = fetch(s1, x1, data->texture.colorTable);
1074  uint tr = fetch(s1, x2, data->texture.colorTable);
1075  uint bl = fetch(s2, x1, data->texture.colorTable);
1076  uint br = fetch(s2, x2, data->texture.colorTable);
1077  int distx = (fx & 0x0000ffff) >> 12;
1078  *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1079  fx += fdx;
1080  ++b;
1081  }
1082  }
1083  } else { //rotation
1084  if (fabs(data->m11) > 8 || fabs(data->m22) > 8) {
1085  //if we are zooming more than 8 times, we use 8bit precision for the position.
1086  while (b < end) {
1087  int x1 = (fx >> 16);
1088  int x2;
1089  int y1 = (fy >> 16);
1090  int y2;
1091 
1092  fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1093  fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1094 
1095  const uchar *s1 = data->texture.scanLine(y1);
1096  const uchar *s2 = data->texture.scanLine(y2);
1097 
1098  uint tl = fetch(s1, x1, data->texture.colorTable);
1099  uint tr = fetch(s1, x2, data->texture.colorTable);
1100  uint bl = fetch(s2, x1, data->texture.colorTable);
1101  uint br = fetch(s2, x2, data->texture.colorTable);
1102 
1103  int distx = (fx & 0x0000ffff) >> 8;
1104  int disty = (fy & 0x0000ffff) >> 8;
1105  int idistx = 256 - distx;
1106  int idisty = 256 - disty;
1107 
1108  uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1109  uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1110  *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1111 
1112  fx += fdx;
1113  fy += fdy;
1114  ++b;
1115  }
1116  } else {
1117  //we are zooming less than 8x, use 4bit precision
1118  while (b < end) {
1119  int x1 = (fx >> 16);
1120  int x2;
1121  int y1 = (fy >> 16);
1122  int y2;
1123 
1124  fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1125  fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1126 
1127  const uchar *s1 = data->texture.scanLine(y1);
1128  const uchar *s2 = data->texture.scanLine(y2);
1129 
1130  uint tl = fetch(s1, x1, data->texture.colorTable);
1131  uint tr = fetch(s1, x2, data->texture.colorTable);
1132  uint bl = fetch(s2, x1, data->texture.colorTable);
1133  uint br = fetch(s2, x2, data->texture.colorTable);
1134 
1135  int distx = (fx & 0x0000ffff) >> 12;
1136  int disty = (fy & 0x0000ffff) >> 12;
1137 
1138  *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
1139 
1140  fx += fdx;
1141  fy += fdy;
1142  ++b;
1143  }
1144  }
1145  }
1146  } else {
1147  const qreal fdx = data->m11;
1148  const qreal fdy = data->m12;
1149  const qreal fdw = data->m13;
1150 
1151  qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
1152  qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
1153  qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
1154 
1155  while (b < end) {
1156  const qreal iw = fw == 0 ? 1 : 1 / fw;
1157  const qreal px = fx * iw - qreal(0.5);
1158  const qreal py = fy * iw - qreal(0.5);
1159 
1160  int x1 = int(px) - (px < 0);
1161  int x2;
1162  int y1 = int(py) - (py < 0);
1163  int y2;
1164 
1165  int distx = int((px - x1) * 256);
1166  int disty = int((py - y1) * 256);
1167  int idistx = 256 - distx;
1168  int idisty = 256 - disty;
1169 
1170  fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
1171  fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
1172 
1173  const uchar *s1 = data->texture.scanLine(y1);
1174  const uchar *s2 = data->texture.scanLine(y2);
1175 
1176  uint tl = fetch(s1, x1, data->texture.colorTable);
1177  uint tr = fetch(s1, x2, data->texture.colorTable);
1178  uint bl = fetch(s2, x1, data->texture.colorTable);
1179  uint br = fetch(s2, x2, data->texture.colorTable);
1180 
1181  uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
1182  uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
1183  *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
1184 
1185  fx += fdx;
1186  fy += fdy;
1187  fw += fdw;
1188  //force increment to avoid /0
1189  if (!fw) {
1190  fw += fdw;
1191  }
1192  ++b;
1193  }
1194  }
1195 
1196  return buffer;
1197 }
1198 
1199 #define SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Arg) qt_fetchUntransformed<QImage::Arg>
1200 
1201 static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = {
1202  // Untransformed
1203  {
1204  0, // Invalid
1205  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono), // Mono
1206  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB), // MonoLsb
1207  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8), // Indexed8
1208  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // RGB32
1209  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32), // ARGB32
1210  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // ARGB32_Premultiplied
1211  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16), // RGB16
1212  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
1213  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666), // RGB666
1214  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
1215  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555), // RGB555
1216  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
1217  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888), // RGB888
1218  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444), // RGB444
1219  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
1220  },
1221  // Tiled
1222  {
1223  0, // Invalid
1224  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono), // Mono
1225  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB), // MonoLsb
1226  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8), // Indexed8
1227  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // RGB32
1228  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32), // ARGB32
1229  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // ARGB32_Premultiplied
1230  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16), // RGB16
1231  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
1232  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666), // RGB666
1233  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
1234  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555), // RGB555
1235  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
1236  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888), // RGB888
1237  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444), // RGB444
1238  SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
1239  },
1240  // Transformed
1241  {
1242  0, // Invalid
1243  fetchTransformed<BlendTransformed>, // Mono
1244  fetchTransformed<BlendTransformed>, // MonoLsb
1245  fetchTransformed<BlendTransformed>, // Indexed8
1246  fetchTransformed<BlendTransformed>, // RGB32
1247  fetchTransformed<BlendTransformed>, // ARGB32
1248  fetchTransformed<BlendTransformed>, // ARGB32_Premultiplied
1249  fetchTransformed<BlendTransformed>, // RGB16
1250  fetchTransformed<BlendTransformed>, // ARGB8565_Premultiplied
1251  fetchTransformed<BlendTransformed>, // RGB666
1252  fetchTransformed<BlendTransformed>, // ARGB6666_Premultiplied
1253  fetchTransformed<BlendTransformed>, // RGB555
1254  fetchTransformed<BlendTransformed>, // ARGB8555_Premultiplied
1255  fetchTransformed<BlendTransformed>, // RGB888
1256  fetchTransformed<BlendTransformed>, // RGB444
1257  fetchTransformed<BlendTransformed>, // ARGB4444_Premultiplied
1258  },
1259  {
1260  0, // TransformedTiled
1261  fetchTransformed<BlendTransformedTiled>, // Mono
1262  fetchTransformed<BlendTransformedTiled>, // MonoLsb
1263  fetchTransformed<BlendTransformedTiled>, // Indexed8
1264  fetchTransformed<BlendTransformedTiled>, // RGB32
1265  fetchTransformed<BlendTransformedTiled>, // ARGB32
1266  fetchTransformed<BlendTransformedTiled>, // ARGB32_Premultiplied
1267  fetchTransformed<BlendTransformedTiled>, // RGB16
1268  fetchTransformed<BlendTransformedTiled>, // ARGB8565_Premultiplied
1269  fetchTransformed<BlendTransformedTiled>, // RGB666
1270  fetchTransformed<BlendTransformedTiled>, // ARGB6666_Premultiplied
1271  fetchTransformed<BlendTransformedTiled>, // RGB555
1272  fetchTransformed<BlendTransformedTiled>, // ARGB8555_Premultiplied
1273  fetchTransformed<BlendTransformedTiled>, // RGB888
1274  fetchTransformed<BlendTransformedTiled>, // RGB444
1275  fetchTransformed<BlendTransformedTiled>, // ARGB4444_Premultiplied
1276  },
1277  {
1278  0, // Bilinear
1279  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // Mono
1280  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // MonoLsb
1281  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // Indexed8
1282  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>, // RGB32
1283  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32>, // ARGB32
1284  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>, // ARGB32_Premultiplied
1285  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB16
1286  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB8565_Premultiplied
1287  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB666
1288  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB6666_Premultiplied
1289  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB555
1290  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB8555_Premultiplied
1291  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB888
1292  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB444
1293  fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid> // ARGB4444_Premultiplied
1294  },
1295  {
1296  0, // BilinearTiled
1297  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // Mono
1298  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // MonoLsb
1299  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // Indexed8
1300  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>, // RGB32
1301  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32>, // ARGB32
1302  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>, // ARGB32_Premultiplied
1303  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB16
1304  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB8565_Premultiplied
1305  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB666
1306  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB6666_Premultiplied
1307  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB555
1308  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB8555_Premultiplied
1309  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB888
1310  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB444
1311  fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid> // ARGB4444_Premultiplied
1312  },
1313 };
1314 
1315 #define FIXPT_BITS 8
1316 #define FIXPT_SIZE (1<<FIXPT_BITS)
1317 
1318 static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
1319 {
1320  int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
1321  return data->colorTable[qt_gradient_clamp(data, ipos)];
1322 }
1323 
1325 {
1326  v->dx = data->gradient.linear.end.x - data->gradient.linear.origin.x;
1327  v->dy = data->gradient.linear.end.y - data->gradient.linear.origin.y;
1328  v->l = v->dx * v->dx + v->dy * v->dy;
1329  v->off = 0;
1330  if (v->l != 0) {
1331  v->dx /= v->l;
1332  v->dy /= v->l;
1333  v->off = -v->dx * data->gradient.linear.origin.x - v->dy * data->gradient.linear.origin.y;
1334  }
1335 }
1336 
1337 static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data,
1338  int y, int x, int length)
1339 {
1340  const uint *b = buffer;
1341  qreal t, inc;
1342 
1343  bool affine = true;
1344  qreal rx=0, ry=0;
1345  if (op->linear.l == 0) {
1346  t = inc = 0;
1347  } else {
1348  rx = data->m21 * (y + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx;
1349  ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(0.5)) + data->dy;
1350  t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off;
1351  inc = op->linear.dx * data->m11 + op->linear.dy * data->m12;
1352  affine = !data->m13 && !data->m23;
1353 
1354  if (affine) {
1355  t *= (GRADIENT_STOPTABLE_SIZE - 1);
1356  inc *= (GRADIENT_STOPTABLE_SIZE - 1);
1357  }
1358  }
1359 
1360  const uint *end = buffer + length;
1361  if (affine) {
1362  if (inc > qreal(-1e-5) && inc < qreal(1e-5)) {
1363  QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE)));
1364  } else {
1365  if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) &&
1366  t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) {
1367  // we can use fixed point math
1368  int t_fixed = int(t * FIXPT_SIZE);
1369  int inc_fixed = int(inc * FIXPT_SIZE);
1370  while (buffer < end) {
1371  *buffer = qt_gradient_pixel_fixed(&data->gradient, t_fixed);
1372  t_fixed += inc_fixed;
1373  ++buffer;
1374  }
1375  } else {
1376  // we have to fall back to float math
1377  while (buffer < end) {
1378  *buffer = qt_gradient_pixel(&data->gradient, t/GRADIENT_STOPTABLE_SIZE);
1379  t += inc;
1380  ++buffer;
1381  }
1382  }
1383  }
1384  } else { // fall back to float math here as well
1385  qreal rw = data->m23 * (y + qreal(0.5)) + data->m13 * (x + qreal(0.5)) + data->m33;
1386  while (buffer < end) {
1387  qreal x = rx/rw;
1388  qreal y = ry/rw;
1389  t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off;
1390 
1391  *buffer = qt_gradient_pixel(&data->gradient, t);
1392  rx += data->m11;
1393  ry += data->m12;
1394  rw += data->m13;
1395  if (!rw) {
1396  rw += data->m13;
1397  }
1398  ++buffer;
1399  }
1400  }
1401 
1402  return b;
1403 }
1404 
1406 {
1407  v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x;
1408  v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y;
1409 
1410  v->dr = data->gradient.radial.center.radius - data->gradient.radial.focal.radius;
1412 
1413  v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy;
1414  v->inv2a = 1 / (2 * v->a);
1415 
1416  v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0;
1417 }
1418 
1420 {
1421 public:
1422  static inline void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det,
1423  qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b)
1424  {
1425  if (op->radial.extended) {
1426  while (buffer < end) {
1427  quint32 result = 0;
1428  if (det >= 0) {
1429  qreal w = qSqrt(det) - b;
1430  if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0)
1431  result = qt_gradient_pixel(&data->gradient, w);
1432  }
1433 
1434  *buffer = result;
1435 
1436  det += delta_det;
1437  delta_det += delta_delta_det;
1438  b += delta_b;
1439 
1440  ++buffer;
1441  }
1442  } else {
1443  while (buffer < end) {
1444  *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b);
1445 
1446  det += delta_det;
1447  delta_det += delta_delta_det;
1448  b += delta_b;
1449  }
1450  }
1451  }
1452 };
1453 
1454 const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data,
1455  int y, int x, int length)
1456 {
1457  return qt_fetch_radial_gradient_template<RadialFetchPlain>(buffer, op, data, y, x, length);
1458 }
1459 
1461 
1462 static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data,
1463  int y, int x, int length)
1464 {
1465  const uint *b = buffer;
1466  qreal rx = data->m21 * (y + qreal(0.5))
1467  + data->dx + data->m11 * (x + qreal(0.5));
1468  qreal ry = data->m22 * (y + qreal(0.5))
1469  + data->dy + data->m12 * (x + qreal(0.5));
1470  bool affine = !data->m13 && !data->m23;
1471 
1472  const uint *end = buffer + length;
1473  if (affine) {
1474  rx -= data->gradient.conical.center.x;
1475  ry -= data->gradient.conical.center.y;
1476  while (buffer < end) {
1477  qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle;
1478 
1479  *buffer = qt_gradient_pixel(&data->gradient, 1 - angle / (2*Q_PI));
1480 
1481  rx += data->m11;
1482  ry += data->m12;
1483  ++buffer;
1484  }
1485  } else {
1486  qreal rw = data->m23 * (y + qreal(0.5))
1487  + data->m33 + data->m13 * (x + qreal(0.5));
1488  if (!rw)
1489  rw = 1;
1490  while (buffer < end) {
1491  qreal angle = qAtan2(ry/rw - data->gradient.conical.center.x,
1492  rx/rw - data->gradient.conical.center.y)
1493  + data->gradient.conical.angle;
1494 
1495  *buffer = qt_gradient_pixel(&data->gradient, 1. - angle / (2*Q_PI));
1496 
1497  rx += data->m11;
1498  ry += data->m12;
1499  rw += data->m13;
1500  if (!rw) {
1501  rw += data->m13;
1502  }
1503  ++buffer;
1504  }
1505  }
1506  return b;
1507 }
1508 
1509 #if defined(Q_CC_RVCT)
1510 // Force ARM code generation for comp_func_* -methods
1511 # pragma push
1512 # pragma arm
1513 # if defined(QT_HAVE_ARMV6)
1514 static __forceinline void preload(const uint *start)
1515 {
1516  asm( "pld [start]" );
1517 }
1518 static const uint L2CacheLineLength = 32;
1519 static const uint L2CacheLineLengthInInts = L2CacheLineLength/sizeof(uint);
1520 # define PRELOAD_INIT(x) preload(x);
1521 # define PRELOAD_INIT2(x,y) PRELOAD_INIT(x) PRELOAD_INIT(y)
1522 # define PRELOAD_COND(x) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts);
1523 // Two consecutive preloads stall, so space them out a bit by using different modulus.
1524 # define PRELOAD_COND2(x,y) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); \
1525  if (((uint)&y[i])%L2CacheLineLength == 16) preload(&y[i] + L2CacheLineLengthInInts);
1526 # endif // QT_HAVE_ARMV6
1527 #endif // Q_CC_RVCT
1528 
1529 #if !defined(Q_CC_RVCT) || !defined(QT_HAVE_ARMV6)
1530 # define PRELOAD_INIT(x)
1531 # define PRELOAD_INIT2(x,y)
1532 # define PRELOAD_COND(x)
1533 # define PRELOAD_COND2(x,y)
1534 #endif
1535 
1536 /* The constant alpha factor describes an alpha factor that gets applied
1537  to the result of the composition operation combining it with the destination.
1538 
1539  The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1.
1540  we get the unmodified operation
1541 
1542  result = src op dest
1543  dest = result * const_alpha + dest * (1. - const_alpha)
1544 
1545  This means that in the comments below, the first line is the const_alpha==255 case, the
1546  second line the general one.
1547 
1548  In the lines below:
1549  s == src, sa == alpha(src), sia = 1 - alpha(src)
1550  d == dest, da == alpha(dest), dia = 1 - alpha(dest)
1551  ca = const_alpha, cia = 1 - const_alpha
1552 
1553  The methods exist in two variants. One where we have a constant source, the other
1554  where the source is an array of pixels.
1555 */
1556 
1557 /*
1558  result = 0
1559  d = d * cia
1560 */
1561 #define comp_func_Clear_impl(dest, length, const_alpha)\
1562 {\
1563  if (const_alpha == 255) {\
1564  QT_MEMFILL_UINT(dest, length, 0);\
1565  } else {\
1566  int ialpha = 255 - const_alpha;\
1567  PRELOAD_INIT(dest)\
1568  for (int i = 0; i < length; ++i) {\
1569  PRELOAD_COND(dest)\
1570  dest[i] = BYTE_MUL(dest[i], ialpha);\
1571  }\
1572  }\
1573 }
1574 
1575 void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
1576 {
1577  comp_func_Clear_impl(dest, length, const_alpha);
1578 }
1579 
1580 void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
1581 {
1582  comp_func_Clear_impl(dest, length, const_alpha);
1583 }
1584 
1585 /*
1586  result = s
1587  dest = s * ca + d * cia
1588 */
1589 void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha)
1590 {
1591  if (const_alpha == 255) {
1592  QT_MEMFILL_UINT(dest, length, color);
1593  } else {
1594  int ialpha = 255 - const_alpha;
1595  color = BYTE_MUL(color, const_alpha);
1596  PRELOAD_INIT(dest)
1597  for (int i = 0; i < length; ++i) {
1598  PRELOAD_COND(dest)
1599  dest[i] = color + BYTE_MUL(dest[i], ialpha);
1600  }
1601  }
1602 }
1603 
1604 void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length, uint const_alpha)
1605 {
1606  if (const_alpha == 255) {
1607  ::memcpy(dest, src, length * sizeof(uint));
1608  } else {
1609  int ialpha = 255 - const_alpha;
1610  PRELOAD_INIT2(dest, src)
1611  for (int i = 0; i < length; ++i) {
1612  PRELOAD_COND2(dest, src)
1613  dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha);
1614  }
1615  }
1616 }
1617 
1618 void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
1619 {
1620 }
1621 
1622 void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint)
1623 {
1624 }
1625 
1626 /*
1627  result = s + d * sia
1628  dest = (s + d * sia) * ca + d * cia
1629  = s * ca + d * (sia * ca + cia)
1630  = s * ca + d * (1 - sa*ca)
1631 */
1632 void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha)
1633 {
1634  if ((const_alpha & qAlpha(color)) == 255) {
1635  QT_MEMFILL_UINT(dest, length, color);
1636  } else {
1637  if (const_alpha != 255)
1638  color = BYTE_MUL(color, const_alpha);
1639  PRELOAD_INIT(dest)
1640  for (int i = 0; i < length; ++i) {
1641  PRELOAD_COND(dest)
1642  dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color));
1643  }
1644  }
1645 }
1646 
1647 void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha)
1648 {
1649  PRELOAD_INIT2(dest, src)
1650  if (const_alpha == 255) {
1651  for (int i = 0; i < length; ++i) {
1652  PRELOAD_COND2(dest, src)
1653  uint s = src[i];
1654  if (s >= 0xff000000)
1655  dest[i] = s;
1656  else if (s != 0)
1657  dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
1658  }
1659  } else {
1660  for (int i = 0; i < length; ++i) {
1661  PRELOAD_COND2(dest, src)
1662  uint s = BYTE_MUL(src[i], const_alpha);
1663  dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s));
1664  }
1665  }
1666 }
1667 
1668 /*
1669  result = d + s * dia
1670  dest = (d + s * dia) * ca + d * cia
1671  = d + s * dia * ca
1672 */
1673 void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha)
1674 {
1675  if (const_alpha != 255)
1676  color = BYTE_MUL(color, const_alpha);
1677  PRELOAD_INIT(dest)
1678  for (int i = 0; i < length; ++i) {
1679  PRELOAD_COND(dest)
1680  uint d = dest[i];
1681  dest[i] = d + BYTE_MUL(color, qAlpha(~d));
1682  }
1683 }
1684 
1685 void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha)
1686 {
1687  PRELOAD_INIT2(dest, src)
1688  if (const_alpha == 255) {
1689  for (int i = 0; i < length; ++i) {
1690  PRELOAD_COND2(dest, src)
1691  uint d = dest[i];
1692  dest[i] = d + BYTE_MUL(src[i], qAlpha(~d));
1693  }
1694  } else {
1695  for (int i = 0; i < length; ++i) {
1696  PRELOAD_COND2(dest, src)
1697  uint d = dest[i];
1698  uint s = BYTE_MUL(src[i], const_alpha);
1699  dest[i] = d + BYTE_MUL(s, qAlpha(~d));
1700  }
1701  }
1702 }
1703 
1704 /*
1705  result = s * da
1706  dest = s * da * ca + d * cia
1707 */
1708 void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha)
1709 {
1710  PRELOAD_INIT(dest)
1711  if (const_alpha == 255) {
1712  for (int i = 0; i < length; ++i) {
1713  PRELOAD_COND(dest)
1714  dest[i] = BYTE_MUL(color, qAlpha(dest[i]));
1715  }
1716  } else {
1717  color = BYTE_MUL(color, const_alpha);
1718  uint cia = 255 - const_alpha;
1719  for (int i = 0; i < length; ++i) {
1720  PRELOAD_COND(dest)
1721  uint d = dest[i];
1722  dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia);
1723  }
1724  }
1725 }
1726 
1727 void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha)
1728 {
1729  PRELOAD_INIT2(dest, src)
1730  if (const_alpha == 255) {
1731  for (int i = 0; i < length; ++i) {
1732  PRELOAD_COND2(dest, src)
1733  dest[i] = BYTE_MUL(src[i], qAlpha(dest[i]));
1734  }
1735  } else {
1736  uint cia = 255 - const_alpha;
1737  for (int i = 0; i < length; ++i) {
1738  PRELOAD_COND2(dest, src)
1739  uint d = dest[i];
1740  uint s = BYTE_MUL(src[i], const_alpha);
1741  dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia);
1742  }
1743  }
1744 }
1745 
1746 /*
1747  result = d * sa
1748  dest = d * sa * ca + d * cia
1749  = d * (sa * ca + cia)
1750 */
1751 void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha)
1752 {
1753  uint a = qAlpha(color);
1754  if (const_alpha != 255) {
1755  a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
1756  }
1757  PRELOAD_INIT(dest)
1758  for (int i = 0; i < length; ++i) {
1759  PRELOAD_COND(dest)
1760  dest[i] = BYTE_MUL(dest[i], a);
1761  }
1762 }
1763 
1764 void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha)
1765 {
1766  PRELOAD_INIT2(dest, src)
1767  if (const_alpha == 255) {
1768  for (int i = 0; i < length; ++i) {
1769  PRELOAD_COND2(dest, src)
1770  dest[i] = BYTE_MUL(dest[i], qAlpha(src[i]));
1771  }
1772  } else {
1773  int cia = 255 - const_alpha;
1774  for (int i = 0; i < length; ++i) {
1775  PRELOAD_COND2(dest, src)
1776  uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia;
1777  dest[i] = BYTE_MUL(dest[i], a);
1778  }
1779  }
1780 }
1781 
1782 /*
1783  result = s * dia
1784  dest = s * dia * ca + d * cia
1785 */
1786 
1787 void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha)
1788 {
1789  PRELOAD_INIT(dest)
1790  if (const_alpha == 255) {
1791  for (int i = 0; i < length; ++i) {
1792  PRELOAD_COND(dest)
1793  dest[i] = BYTE_MUL(color, qAlpha(~dest[i]));
1794  }
1795  } else {
1796  color = BYTE_MUL(color, const_alpha);
1797  int cia = 255 - const_alpha;
1798  for (int i = 0; i < length; ++i) {
1799  PRELOAD_COND(dest)
1800  uint d = dest[i];
1801  dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia);
1802  }
1803  }
1804 }
1805 
1806 void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha)
1807 {
1808  PRELOAD_INIT2(dest, src)
1809  if (const_alpha == 255) {
1810  for (int i = 0; i < length; ++i) {
1811  PRELOAD_COND2(dest, src)
1812  dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i]));
1813  }
1814  } else {
1815  int cia = 255 - const_alpha;
1816  for (int i = 0; i < length; ++i) {
1817  PRELOAD_COND2(dest, src)
1818  uint s = BYTE_MUL(src[i], const_alpha);
1819  uint d = dest[i];
1820  dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia);
1821  }
1822  }
1823 }
1824 
1825 /*
1826  result = d * sia
1827  dest = d * sia * ca + d * cia
1828  = d * (sia * ca + cia)
1829 */
1830 void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha)
1831 {
1832  uint a = qAlpha(~color);
1833  if (const_alpha != 255)
1834  a = BYTE_MUL(a, const_alpha) + 255 - const_alpha;
1835  PRELOAD_INIT(dest)
1836  for (int i = 0; i < length; ++i) {
1837  PRELOAD_COND(dest)
1838  dest[i] = BYTE_MUL(dest[i], a);
1839  }
1840 }
1841 
1842 void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha)
1843 {
1844  PRELOAD_INIT2(dest, src)
1845  if (const_alpha == 255) {
1846  for (int i = 0; i < length; ++i) {
1847  PRELOAD_COND2(dest, src)
1848  dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i]));
1849  }
1850  } else {
1851  int cia = 255 - const_alpha;
1852  for (int i = 0; i < length; ++i) {
1853  PRELOAD_COND2(dest, src)
1854  uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia;
1855  dest[i] = BYTE_MUL(dest[i], sia);
1856  }
1857  }
1858 }
1859 
1860 /*
1861  result = s*da + d*sia
1862  dest = s*da*ca + d*sia*ca + d *cia
1863  = s*ca * da + d * (sia*ca + cia)
1864  = s*ca * da + d * (1 - sa*ca)
1865 */
1866 void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha)
1867 {
1868  if (const_alpha != 255) {
1869  color = BYTE_MUL(color, const_alpha);
1870  }
1871  uint sia = qAlpha(~color);
1872  PRELOAD_INIT(dest)
1873  for (int i = 0; i < length; ++i) {
1874  PRELOAD_COND(dest)
1875  dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia);
1876  }
1877 }
1878 
1879 void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha)
1880 {
1881  PRELOAD_INIT2(dest, src)
1882  if (const_alpha == 255) {
1883  for (int i = 0; i < length; ++i) {
1884  PRELOAD_COND2(dest, src)
1885  uint s = src[i];
1886  uint d = dest[i];
1887  dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
1888  }
1889  } else {
1890  for (int i = 0; i < length; ++i) {
1891  PRELOAD_COND2(dest, src)
1892  uint s = BYTE_MUL(src[i], const_alpha);
1893  uint d = dest[i];
1894  dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s));
1895  }
1896  }
1897 }
1898 
1899 /*
1900  result = d*sa + s*dia
1901  dest = d*sa*ca + s*dia*ca + d *cia
1902  = s*ca * dia + d * (sa*ca + cia)
1903 */
1904 void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha)
1905 {
1906  uint a = qAlpha(color);
1907  if (const_alpha != 255) {
1908  color = BYTE_MUL(color, const_alpha);
1909  a = qAlpha(color) + 255 - const_alpha;
1910  }
1911  PRELOAD_INIT(dest)
1912  for (int i = 0; i < length; ++i) {
1913  PRELOAD_COND(dest)
1914  uint d = dest[i];
1915  dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d));
1916  }
1917 }
1918 
1919 void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha)
1920 {
1921  PRELOAD_INIT2(dest, src)
1922  if (const_alpha == 255) {
1923  for (int i = 0; i < length; ++i) {
1924  PRELOAD_COND2(dest, src)
1925  uint s = src[i];
1926  uint d = dest[i];
1927  dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d));
1928  }
1929  } else {
1930  int cia = 255 - const_alpha;
1931  for (int i = 0; i < length; ++i) {
1932  PRELOAD_COND2(dest, src)
1933  uint s = BYTE_MUL(src[i], const_alpha);
1934  uint d = dest[i];
1935  uint a = qAlpha(s) + cia;
1936  dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d));
1937  }
1938  }
1939 }
1940 
1941 /*
1942  result = d*sia + s*dia
1943  dest = d*sia*ca + s*dia*ca + d *cia
1944  = s*ca * dia + d * (sia*ca + cia)
1945  = s*ca * dia + d * (1 - sa*ca)
1946 */
1947 void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha)
1948 {
1949  if (const_alpha != 255)
1950  color = BYTE_MUL(color, const_alpha);
1951  uint sia = qAlpha(~color);
1952 
1953  PRELOAD_INIT(dest)
1954  for (int i = 0; i < length; ++i) {
1955  PRELOAD_COND(dest)
1956  uint d = dest[i];
1957  dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia);
1958  }
1959 }
1960 
1961 void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha)
1962 {
1963  PRELOAD_INIT2(dest, src)
1964  if (const_alpha == 255) {
1965  for (int i = 0; i < length; ++i) {
1966  PRELOAD_COND2(dest, src)
1967  uint d = dest[i];
1968  uint s = src[i];
1969  dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
1970  }
1971  } else {
1972  for (int i = 0; i < length; ++i) {
1973  PRELOAD_COND2(dest, src)
1974  uint d = dest[i];
1975  uint s = BYTE_MUL(src[i], const_alpha);
1976  dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s));
1977  }
1978  }
1979 }
1980 
1982  inline void store(uint *dest, const uint src) const
1983  {
1984  *dest = src;
1985  }
1986 };
1987 
1989  inline QPartialCoverage(uint const_alpha)
1990  : ca(const_alpha)
1991  , ica(255 - const_alpha)
1992  {
1993  }
1994 
1995  inline void store(uint *dest, const uint src) const
1996  {
1997  *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
1998  }
1999 
2000 private:
2001  const uint ca;
2002  const uint ica;
2003 };
2004 
2005 static inline int mix_alpha(int da, int sa)
2006 {
2007  return 255 - ((255 - sa) * (255 - da) >> 8);
2008 }
2009 
2010 /*
2011  Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
2012  = Sca + Dca
2013 */
2014 template <typename T>
2015 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage)
2016 {
2017  uint s = color;
2018 
2019  PRELOAD_INIT(dest)
2020  for (int i = 0; i < length; ++i) {
2021  PRELOAD_COND(dest)
2022  uint d = dest[i];
2023  d = comp_func_Plus_one_pixel(d, s);
2024  coverage.store(&dest[i], d);
2025  }
2026 }
2027 
2028 void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha)
2029 {
2030  if (const_alpha == 255)
2031  comp_func_solid_Plus_impl(dest, length, color, QFullCoverage());
2032  else
2033  comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha));
2034 }
2035 
2036 template <typename T>
2037 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *dest, const uint *src, int length, const T &coverage)
2038 {
2039  PRELOAD_INIT2(dest, src)
2040  for (int i = 0; i < length; ++i) {
2041  PRELOAD_COND2(dest, src)
2042  uint d = dest[i];
2043  uint s = src[i];
2044 
2045  d = comp_func_Plus_one_pixel(d, s);
2046 
2047  coverage.store(&dest[i], d);
2048  }
2049 }
2050 
2051 void QT_FASTCALL comp_func_Plus(uint *dest, const uint *src, int length, uint const_alpha)
2052 {
2053  if (const_alpha == 255)
2054  comp_func_Plus_impl(dest, src, length, QFullCoverage());
2055  else
2056  comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha));
2057 }
2058 
2059 /*
2060  Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2061 */
2062 static inline int multiply_op(int dst, int src, int da, int sa)
2063 {
2064  return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa));
2065 }
2066 
2067 template <typename T>
2068 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage)
2069 {
2070  int sa = qAlpha(color);
2071  int sr = qRed(color);
2072  int sg = qGreen(color);
2073  int sb = qBlue(color);
2074 
2075  PRELOAD_INIT(dest)
2076  for (int i = 0; i < length; ++i) {
2077  PRELOAD_COND(dest)
2078  uint d = dest[i];
2079  int da = qAlpha(d);
2080 
2081 #define OP(a, b) multiply_op(a, b, da, sa)
2082  int r = OP( qRed(d), sr);
2083  int b = OP( qBlue(d), sb);
2084  int g = OP(qGreen(d), sg);
2085  int a = mix_alpha(da, sa);
2086 #undef OP
2087 
2088  coverage.store(&dest[i], qRgba(r, g, b, a));
2089  }
2090 }
2091 
2092 void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha)
2093 {
2094  if (const_alpha == 255)
2095  comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
2096  else
2097  comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
2098 }
2099 
2100 template <typename T>
2101 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *dest, const uint *src, int length, const T &coverage)
2102 {
2103  PRELOAD_INIT2(dest, src)
2104  for (int i = 0; i < length; ++i) {
2105  PRELOAD_COND2(dest, src)
2106  uint d = dest[i];
2107  uint s = src[i];
2108 
2109  int da = qAlpha(d);
2110  int sa = qAlpha(s);
2111 
2112 #define OP(a, b) multiply_op(a, b, da, sa)
2113  int r = OP( qRed(d), qRed(s));
2114  int b = OP( qBlue(d), qBlue(s));
2115  int g = OP(qGreen(d), qGreen(s));
2116  int a = mix_alpha(da, sa);
2117 #undef OP
2118 
2119  coverage.store(&dest[i], qRgba(r, g, b, a));
2120  }
2121 }
2122 
2123 void QT_FASTCALL comp_func_Multiply(uint *dest, const uint *src, int length, uint const_alpha)
2124 {
2125  if (const_alpha == 255)
2126  comp_func_Multiply_impl(dest, src, length, QFullCoverage());
2127  else
2128  comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
2129 }
2130 
2131 /*
2132  Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2133  = Sca + Dca - Sca.Dca
2134 */
2135 template <typename T>
2136 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage)
2137 {
2138  int sa = qAlpha(color);
2139  int sr = qRed(color);
2140  int sg = qGreen(color);
2141  int sb = qBlue(color);
2142 
2143  PRELOAD_INIT(dest)
2144  for (int i = 0; i < length; ++i) {
2145  PRELOAD_COND(dest)
2146  uint d = dest[i];
2147  int da = qAlpha(d);
2148 
2149 #define OP(a, b) 255 - qt_div_255((255-a) * (255-b))
2150  int r = OP( qRed(d), sr);
2151  int b = OP( qBlue(d), sb);
2152  int g = OP(qGreen(d), sg);
2153  int a = mix_alpha(da, sa);
2154 #undef OP
2155 
2156  coverage.store(&dest[i], qRgba(r, g, b, a));
2157  }
2158 }
2159 
2160 void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha)
2161 {
2162  if (const_alpha == 255)
2163  comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
2164  else
2165  comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
2166 }
2167 
2168 template <typename T>
2169 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *dest, const uint *src, int length, const T &coverage)
2170 {
2171  PRELOAD_INIT2(dest, src)
2172  for (int i = 0; i < length; ++i) {
2173  PRELOAD_COND2(dest, src)
2174  uint d = dest[i];
2175  uint s = src[i];
2176 
2177  int da = qAlpha(d);
2178  int sa = qAlpha(s);
2179 
2180 #define OP(a, b) 255 - (((255-a) * (255-b)) >> 8)
2181  int r = OP( qRed(d), qRed(s));
2182  int b = OP( qBlue(d), qBlue(s));
2183  int g = OP(qGreen(d), qGreen(s));
2184  int a = mix_alpha(da, sa);
2185 #undef OP
2186 
2187  coverage.store(&dest[i], qRgba(r, g, b, a));
2188  }
2189 }
2190 
2191 void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha)
2192 {
2193  if (const_alpha == 255)
2194  comp_func_Screen_impl(dest, src, length, QFullCoverage());
2195  else
2196  comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
2197 }
2198 
2199 /*
2200  if 2.Dca < Da
2201  Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2202  otherwise
2203  Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2204 */
2205 static inline int overlay_op(int dst, int src, int da, int sa)
2206 {
2207  const int temp = src * (255 - da) + dst * (255 - sa);
2208  if (2 * dst < da)
2209  return qt_div_255(2 * src * dst + temp);
2210  else
2211  return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2212 }
2213 
2214 template <typename T>
2215 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage)
2216 {
2217  int sa = qAlpha(color);
2218  int sr = qRed(color);
2219  int sg = qGreen(color);
2220  int sb = qBlue(color);
2221 
2222  PRELOAD_INIT(dest)
2223  for (int i = 0; i < length; ++i) {
2224  PRELOAD_COND(dest)
2225  uint d = dest[i];
2226  int da = qAlpha(d);
2227 
2228 #define OP(a, b) overlay_op(a, b, da, sa)
2229  int r = OP( qRed(d), sr);
2230  int b = OP( qBlue(d), sb);
2231  int g = OP(qGreen(d), sg);
2232  int a = mix_alpha(da, sa);
2233 #undef OP
2234 
2235  coverage.store(&dest[i], qRgba(r, g, b, a));
2236  }
2237 }
2238 
2239 void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha)
2240 {
2241  if (const_alpha == 255)
2242  comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
2243  else
2244  comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
2245 }
2246 
2247 template <typename T>
2248 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *dest, const uint *src, int length, const T &coverage)
2249 {
2250  PRELOAD_INIT2(dest, src)
2251  for (int i = 0; i < length; ++i) {
2252  PRELOAD_COND2(dest, src)
2253  uint d = dest[i];
2254  uint s = src[i];
2255 
2256  int da = qAlpha(d);
2257  int sa = qAlpha(s);
2258 
2259 #define OP(a, b) overlay_op(a, b, da, sa)
2260  int r = OP( qRed(d), qRed(s));
2261  int b = OP( qBlue(d), qBlue(s));
2262  int g = OP(qGreen(d), qGreen(s));
2263  int a = mix_alpha(da, sa);
2264 #undef OP
2265 
2266  coverage.store(&dest[i], qRgba(r, g, b, a));
2267  }
2268 }
2269 
2270 void QT_FASTCALL comp_func_Overlay(uint *dest, const uint *src, int length, uint const_alpha)
2271 {
2272  if (const_alpha == 255)
2273  comp_func_Overlay_impl(dest, src, length, QFullCoverage());
2274  else
2275  comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
2276 }
2277 
2278 /*
2279  Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2280  Da' = Sa + Da - Sa.Da
2281 */
2282 static inline int darken_op(int dst, int src, int da, int sa)
2283 {
2284  return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2285 }
2286 
2287 template <typename T>
2288 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage)
2289 {
2290  int sa = qAlpha(color);
2291  int sr = qRed(color);
2292  int sg = qGreen(color);
2293  int sb = qBlue(color);
2294 
2295  PRELOAD_INIT(dest)
2296  for (int i = 0; i < length; ++i) {
2297  PRELOAD_COND(dest)
2298  uint d = dest[i];
2299  int da = qAlpha(d);
2300 
2301 #define OP(a, b) darken_op(a, b, da, sa)
2302  int r = OP( qRed(d), sr);
2303  int b = OP( qBlue(d), sb);
2304  int g = OP(qGreen(d), sg);
2305  int a = mix_alpha(da, sa);
2306 #undef OP
2307 
2308  coverage.store(&dest[i], qRgba(r, g, b, a));
2309  }
2310 }
2311 
2312 void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha)
2313 {
2314  if (const_alpha == 255)
2315  comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
2316  else
2317  comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
2318 }
2319 
2320 template <typename T>
2321 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *dest, const uint *src, int length, const T &coverage)
2322 {
2323  PRELOAD_INIT2(dest, src)
2324  for (int i = 0; i < length; ++i) {
2325  PRELOAD_COND2(dest, src)
2326  uint d = dest[i];
2327  uint s = src[i];
2328 
2329  int da = qAlpha(d);
2330  int sa = qAlpha(s);
2331 
2332 #define OP(a, b) darken_op(a, b, da, sa)
2333  int r = OP( qRed(d), qRed(s));
2334  int b = OP( qBlue(d), qBlue(s));
2335  int g = OP(qGreen(d), qGreen(s));
2336  int a = mix_alpha(da, sa);
2337 #undef OP
2338 
2339  coverage.store(&dest[i], qRgba(r, g, b, a));
2340  }
2341 }
2342 
2343 void QT_FASTCALL comp_func_Darken(uint *dest, const uint *src, int length, uint const_alpha)
2344 {
2345  if (const_alpha == 255)
2346  comp_func_Darken_impl(dest, src, length, QFullCoverage());
2347  else
2348  comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
2349 }
2350 
2351 /*
2352  Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2353  Da' = Sa + Da - Sa.Da
2354 */
2355 static inline int lighten_op(int dst, int src, int da, int sa)
2356 {
2357  return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
2358 }
2359 
2360 template <typename T>
2361 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage)
2362 {
2363  int sa = qAlpha(color);
2364  int sr = qRed(color);
2365  int sg = qGreen(color);
2366  int sb = qBlue(color);
2367 
2368  PRELOAD_INIT(dest)
2369  for (int i = 0; i < length; ++i) {
2370  PRELOAD_COND(dest)
2371  uint d = dest[i];
2372  int da = qAlpha(d);
2373 
2374 #define OP(a, b) lighten_op(a, b, da, sa)
2375  int r = OP( qRed(d), sr);
2376  int b = OP( qBlue(d), sb);
2377  int g = OP(qGreen(d), sg);
2378  int a = mix_alpha(da, sa);
2379 #undef OP
2380 
2381  coverage.store(&dest[i], qRgba(r, g, b, a));
2382  }
2383 }
2384 
2385 void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha)
2386 {
2387  if (const_alpha == 255)
2388  comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
2389  else
2390  comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
2391 }
2392 
2393 template <typename T>
2394 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *dest, const uint *src, int length, const T &coverage)
2395 {
2396  PRELOAD_INIT2(dest, src)
2397  for (int i = 0; i < length; ++i) {
2398  PRELOAD_COND2(dest, src)
2399  uint d = dest[i];
2400  uint s = src[i];
2401 
2402  int da = qAlpha(d);
2403  int sa = qAlpha(s);
2404 
2405 #define OP(a, b) lighten_op(a, b, da, sa)
2406  int r = OP( qRed(d), qRed(s));
2407  int b = OP( qBlue(d), qBlue(s));
2408  int g = OP(qGreen(d), qGreen(s));
2409  int a = mix_alpha(da, sa);
2410 #undef OP
2411 
2412  coverage.store(&dest[i], qRgba(r, g, b, a));
2413  }
2414 }
2415 
2416 void QT_FASTCALL comp_func_Lighten(uint *dest, const uint *src, int length, uint const_alpha)
2417 {
2418  if (const_alpha == 255)
2419  comp_func_Lighten_impl(dest, src, length, QFullCoverage());
2420  else
2421  comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
2422 }
2423 
2424 /*
2425  if Sca.Da + Dca.Sa >= Sa.Da
2426  Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
2427  otherwise
2428  Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
2429 */
2430 static inline int color_dodge_op(int dst, int src, int da, int sa)
2431 {
2432  const int sa_da = sa * da;
2433  const int dst_sa = dst * sa;
2434  const int src_da = src * da;
2435 
2436  const int temp = src * (255 - da) + dst * (255 - sa);
2437  if (src_da + dst_sa >= sa_da)
2438  return qt_div_255(sa_da + temp);
2439  else
2440  return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp);
2441 }
2442 
2443 template <typename T>
2444 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage)
2445 {
2446  int sa = qAlpha(color);
2447  int sr = qRed(color);
2448  int sg = qGreen(color);
2449  int sb = qBlue(color);
2450 
2451  PRELOAD_INIT(dest)
2452  for (int i = 0; i < length; ++i) {
2453  PRELOAD_COND(dest)
2454  uint d = dest[i];
2455  int da = qAlpha(d);
2456 
2457 #define OP(a,b) color_dodge_op(a, b, da, sa)
2458  int r = OP( qRed(d), sr);
2459  int b = OP( qBlue(d), sb);
2460  int g = OP(qGreen(d), sg);
2461  int a = mix_alpha(da, sa);
2462 #undef OP
2463 
2464  coverage.store(&dest[i], qRgba(r, g, b, a));
2465  }
2466 }
2467 
2468 void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha)
2469 {
2470  if (const_alpha == 255)
2471  comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
2472  else
2473  comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
2474 }
2475 
2476 template <typename T>
2477 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *dest, const uint *src, int length, const T &coverage)
2478 {
2479  PRELOAD_INIT2(dest, src)
2480  for (int i = 0; i < length; ++i) {
2481  PRELOAD_COND2(dest, src)
2482  uint d = dest[i];
2483  uint s = src[i];
2484 
2485  int da = qAlpha(d);
2486  int sa = qAlpha(s);
2487 
2488 #define OP(a, b) color_dodge_op(a, b, da, sa)
2489  int r = OP( qRed(d), qRed(s));
2490  int b = OP( qBlue(d), qBlue(s));
2491  int g = OP(qGreen(d), qGreen(s));
2492  int a = mix_alpha(da, sa);
2493 #undef OP
2494 
2495  coverage.store(&dest[i], qRgba(r, g, b, a));
2496  }
2497 }
2498 
2499 void QT_FASTCALL comp_func_ColorDodge(uint *dest, const uint *src, int length, uint const_alpha)
2500 {
2501  if (const_alpha == 255)
2502  comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
2503  else
2504  comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
2505 }
2506 
2507 /*
2508  if Sca.Da + Dca.Sa <= Sa.Da
2509  Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
2510  otherwise
2511  Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
2512 */
2513 static inline int color_burn_op(int dst, int src, int da, int sa)
2514 {
2515  const int src_da = src * da;
2516  const int dst_sa = dst * sa;
2517  const int sa_da = sa * da;
2518 
2519  const int temp = src * (255 - da) + dst * (255 - sa);
2520 
2521  if (src == 0 || src_da + dst_sa <= sa_da)
2522  return qt_div_255(temp);
2523  return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp);
2524 }
2525 
2526 template <typename T>
2527 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage)
2528 {
2529  int sa = qAlpha(color);
2530  int sr = qRed(color);
2531  int sg = qGreen(color);
2532  int sb = qBlue(color);
2533 
2534  PRELOAD_INIT(dest)
2535  for (int i = 0; i < length; ++i) {
2536  PRELOAD_COND(dest)
2537  uint d = dest[i];
2538  int da = qAlpha(d);
2539 
2540 #define OP(a, b) color_burn_op(a, b, da, sa)
2541  int r = OP( qRed(d), sr);
2542  int b = OP( qBlue(d), sb);
2543  int g = OP(qGreen(d), sg);
2544  int a = mix_alpha(da, sa);
2545 #undef OP
2546 
2547  coverage.store(&dest[i], qRgba(r, g, b, a));
2548  }
2549 }
2550 
2551 void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha)
2552 {
2553  if (const_alpha == 255)
2554  comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
2555  else
2556  comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
2557 }
2558 
2559 template <typename T>
2560 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *dest, const uint *src, int length, const T &coverage)
2561 {
2562  PRELOAD_INIT2(dest, src)
2563  for (int i = 0; i < length; ++i) {
2564  PRELOAD_COND2(dest, src)
2565  uint d = dest[i];
2566  uint s = src[i];
2567 
2568  int da = qAlpha(d);
2569  int sa = qAlpha(s);
2570 
2571 #define OP(a, b) color_burn_op(a, b, da, sa)
2572  int r = OP( qRed(d), qRed(s));
2573  int b = OP( qBlue(d), qBlue(s));
2574  int g = OP(qGreen(d), qGreen(s));
2575  int a = mix_alpha(da, sa);
2576 #undef OP
2577 
2578  coverage.store(&dest[i], qRgba(r, g, b, a));
2579  }
2580 }
2581 
2582 void QT_FASTCALL comp_func_ColorBurn(uint *dest, const uint *src, int length, uint const_alpha)
2583 {
2584  if (const_alpha == 255)
2585  comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
2586  else
2587  comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
2588 }
2589 
2590 /*
2591  if 2.Sca < Sa
2592  Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2593  otherwise
2594  Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2595 */
2596 static inline uint hardlight_op(int dst, int src, int da, int sa)
2597 {
2598  const uint temp = src * (255 - da) + dst * (255 - sa);
2599 
2600  if (2 * src < sa)
2601  return qt_div_255(2 * src * dst + temp);
2602  else
2603  return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2604 }
2605 
2606 template <typename T>
2607 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage)
2608 {
2609  int sa = qAlpha(color);
2610  int sr = qRed(color);
2611  int sg = qGreen(color);
2612  int sb = qBlue(color);
2613 
2614  PRELOAD_INIT(dest)
2615  for (int i = 0; i < length; ++i) {
2616  PRELOAD_COND(dest)
2617  uint d = dest[i];
2618  int da = qAlpha(d);
2619 
2620 #define OP(a, b) hardlight_op(a, b, da, sa)
2621  int r = OP( qRed(d), sr);
2622  int b = OP( qBlue(d), sb);
2623  int g = OP(qGreen(d), sg);
2624  int a = mix_alpha(da, sa);
2625 #undef OP
2626 
2627  coverage.store(&dest[i], qRgba(r, g, b, a));
2628  }
2629 }
2630 
2631 void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha)
2632 {
2633  if (const_alpha == 255)
2634  comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
2635  else
2636  comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2637 }
2638 
2639 template <typename T>
2640 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *dest, const uint *src, int length, const T &coverage)
2641 {
2642  PRELOAD_INIT2(dest, src)
2643  for (int i = 0; i < length; ++i) {
2644  PRELOAD_COND2(dest, src)
2645  uint d = dest[i];
2646  uint s = src[i];
2647 
2648  int da = qAlpha(d);
2649  int sa = qAlpha(s);
2650 
2651 #define OP(a, b) hardlight_op(a, b, da, sa)
2652  int r = OP( qRed(d), qRed(s));
2653  int b = OP( qBlue(d), qBlue(s));
2654  int g = OP(qGreen(d), qGreen(s));
2655  int a = mix_alpha(da, sa);
2656 #undef OP
2657 
2658  coverage.store(&dest[i], qRgba(r, g, b, a));
2659  }
2660 }
2661 
2662 void QT_FASTCALL comp_func_HardLight(uint *dest, const uint *src, int length, uint const_alpha)
2663 {
2664  if (const_alpha == 255)
2665  comp_func_HardLight_impl(dest, src, length, QFullCoverage());
2666  else
2667  comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2668 }
2669 
2670 /*
2671  if 2.Sca <= Sa
2672  Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
2673  otherwise if 2.Sca > Sa and 4.Dca <= Da
2674  Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2675  otherwise if 2.Sca > Sa and 4.Dca > Da
2676  Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2677 */
2678 static inline int soft_light_op(int dst, int src, int da, int sa)
2679 {
2680  const int src2 = src << 1;
2681  const int dst_np = da != 0 ? (255 * dst) / da : 0;
2682  const int temp = (src * (255 - da) + dst * (255 - sa)) * 255;
2683 
2684  if (src2 < sa)
2685  return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025;
2686  else if (4 * dst <= da)
2687  return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025;
2688  else {
2689 # ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
2690  return (dst * sa * 255 + da * (src2 - sa) * (qIntSqrtInt(dst_np * 255) - dst_np) + temp) / 65025;
2691 # else
2692  return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025;
2693 # endif
2694  }
2695 }
2696 
2697 template <typename T>
2698 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage)
2699 {
2700  int sa = qAlpha(color);
2701  int sr = qRed(color);
2702  int sg = qGreen(color);
2703  int sb = qBlue(color);
2704 
2705  PRELOAD_INIT(dest)
2706  for (int i = 0; i < length; ++i) {
2707  PRELOAD_COND(dest)
2708  uint d = dest[i];
2709  int da = qAlpha(d);
2710 
2711 #define OP(a, b) soft_light_op(a, b, da, sa)
2712  int r = OP( qRed(d), sr);
2713  int b = OP( qBlue(d), sb);
2714  int g = OP(qGreen(d), sg);
2715  int a = mix_alpha(da, sa);
2716 #undef OP
2717 
2718  coverage.store(&dest[i], qRgba(r, g, b, a));
2719  }
2720 }
2721 
2722 void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
2723 {
2724  if (const_alpha == 255)
2725  comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
2726  else
2727  comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2728 }
2729 
2730 template <typename T>
2731 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *dest, const uint *src, int length, const T &coverage)
2732 {
2733  PRELOAD_INIT2(dest, src)
2734  for (int i = 0; i < length; ++i) {
2735  PRELOAD_COND2(dest, src)
2736  uint d = dest[i];
2737  uint s = src[i];
2738 
2739  int da = qAlpha(d);
2740  int sa = qAlpha(s);
2741 
2742 #define OP(a, b) soft_light_op(a, b, da, sa)
2743  int r = OP( qRed(d), qRed(s));
2744  int b = OP( qBlue(d), qBlue(s));
2745  int g = OP(qGreen(d), qGreen(s));
2746  int a = mix_alpha(da, sa);
2747 #undef OP
2748 
2749  coverage.store(&dest[i], qRgba(r, g, b, a));
2750  }
2751 }
2752 
2753 void QT_FASTCALL comp_func_SoftLight(uint *dest, const uint *src, int length, uint const_alpha)
2754 {
2755  if (const_alpha == 255)
2756  comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
2757  else
2758  comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2759 }
2760 
2761 /*
2762  Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2763  = Sca + Dca - 2.min(Sca.Da, Dca.Sa)
2764 */
2765 static inline int difference_op(int dst, int src, int da, int sa)
2766 {
2767  return src + dst - qt_div_255(2 * qMin(src * da, dst * sa));
2768 }
2769 
2770 template <typename T>
2771 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage)
2772 {
2773  int sa = qAlpha(color);
2774  int sr = qRed(color);
2775  int sg = qGreen(color);
2776  int sb = qBlue(color);
2777 
2778  PRELOAD_INIT(dest)
2779  for (int i = 0; i < length; ++i) {
2780  PRELOAD_COND(dest)
2781  uint d = dest[i];
2782  int da = qAlpha(d);
2783 
2784 #define OP(a, b) difference_op(a, b, da, sa)
2785  int r = OP( qRed(d), sr);
2786  int b = OP( qBlue(d), sb);
2787  int g = OP(qGreen(d), sg);
2788  int a = mix_alpha(da, sa);
2789 #undef OP
2790 
2791  coverage.store(&dest[i], qRgba(r, g, b, a));
2792  }
2793 }
2794 
2795 void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha)
2796 {
2797  if (const_alpha == 255)
2798  comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
2799  else
2800  comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
2801 }
2802 
2803 template <typename T>
2804 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *dest, const uint *src, int length, const T &coverage)
2805 {
2806  PRELOAD_INIT2(dest, src)
2807  for (int i = 0; i < length; ++i) {
2808  PRELOAD_COND2(dest, src)
2809  uint d = dest[i];
2810  uint s = src[i];
2811 
2812  int da = qAlpha(d);
2813  int sa = qAlpha(s);
2814 
2815 #define OP(a, b) difference_op(a, b, da, sa)
2816  int r = OP( qRed(d), qRed(s));
2817  int b = OP( qBlue(d), qBlue(s));
2818  int g = OP(qGreen(d), qGreen(s));
2819  int a = mix_alpha(da, sa);
2820 #undef OP
2821 
2822  coverage.store(&dest[i], qRgba(r, g, b, a));
2823  }
2824 }
2825 
2826 void QT_FASTCALL comp_func_Difference(uint *dest, const uint *src, int length, uint const_alpha)
2827 {
2828  if (const_alpha == 255)
2829  comp_func_Difference_impl(dest, src, length, QFullCoverage());
2830  else
2831  comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
2832 }
2833 
2834 /*
2835  Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2836 */
2837 template <typename T>
2838 Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage)
2839 {
2840  int sa = qAlpha(color);
2841  int sr = qRed(color);
2842  int sg = qGreen(color);
2843  int sb = qBlue(color);
2844 
2845  PRELOAD_INIT(dest)
2846  for (int i = 0; i < length; ++i) {
2847  PRELOAD_COND(dest)
2848  uint d = dest[i];
2849  int da = qAlpha(d);
2850 
2851 #define OP(a, b) (a + b - qt_div_255(2*(a*b)))
2852  int r = OP( qRed(d), sr);
2853  int b = OP( qBlue(d), sb);
2854  int g = OP(qGreen(d), sg);
2855  int a = mix_alpha(da, sa);
2856 #undef OP
2857 
2858  coverage.store(&dest[i], qRgba(r, g, b, a));
2859  }
2860 }
2861 
2862 void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha)
2863 {
2864  if (const_alpha == 255)
2865  comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage());
2866  else
2867  comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
2868 }
2869 
2870 template <typename T>
2871 Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *dest, const uint *src, int length, const T &coverage)
2872 {
2873  PRELOAD_INIT2(dest, src)
2874  for (int i = 0; i < length; ++i) {
2875  PRELOAD_COND2(dest, src)
2876  uint d = dest[i];
2877  uint s = src[i];
2878 
2879  int da = qAlpha(d);
2880  int sa = qAlpha(s);
2881 
2882 #define OP(a, b) (a + b - ((a*b) >> 7))
2883  int r = OP( qRed(d), qRed(s));
2884  int b = OP( qBlue(d), qBlue(s));
2885  int g = OP(qGreen(d), qGreen(s));
2886  int a = mix_alpha(da, sa);
2887 #undef OP
2888 
2889  coverage.store(&dest[i], qRgba(r, g, b, a));
2890  }
2891 }
2892 
2893 void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int length, uint const_alpha)
2894 {
2895  if (const_alpha == 255)
2896  comp_func_Exclusion_impl(dest, src, length, QFullCoverage());
2897  else
2898  comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
2899 }
2900 
2901 #if defined(Q_CC_RVCT)
2902 // Restore pragma state from previous #pragma arm
2903 # pragma pop
2904 #endif
2905 
2907  int length,
2908  uint color,
2909  uint const_alpha)
2910 {
2911  Q_UNUSED(const_alpha);
2912  while (length--)
2913  *dest++ |= color;
2914 }
2915 
2917  const uint *src,
2918  int length,
2919  uint const_alpha)
2920 {
2921  Q_UNUSED(const_alpha);
2922  while (length--)
2923  *dest++ |= *src++;
2924 }
2925 
2927  int length,
2928  uint color,
2929  uint const_alpha)
2930 {
2931  Q_UNUSED(const_alpha);
2932  color |= 0xff000000;
2933  while (length--)
2934  *dest++ &= color;
2935 }
2936 
2938  const uint *src,
2939  int length,
2940  uint const_alpha)
2941 {
2942  Q_UNUSED(const_alpha);
2943  while (length--) {
2944  *dest = (*src & *dest) | 0xff000000;
2945  ++dest; ++src;
2946  }
2947 }
2948 
2950  int length,
2951  uint color,
2952  uint const_alpha)
2953 {
2954  Q_UNUSED(const_alpha);
2955  color &= 0x00ffffff;
2956  while (length--)
2957  *dest++ ^= color;
2958 }
2959 
2961  const uint *src,
2962  int length,
2963  uint const_alpha)
2964 {
2965  Q_UNUSED(const_alpha);
2966  while (length--) {
2967  *dest = (*src ^ *dest) | 0xff000000;
2968  ++dest; ++src;
2969  }
2970 }
2971 
2973  int length,
2974  uint color,
2975  uint const_alpha)
2976 {
2977  Q_UNUSED(const_alpha);
2978  color = ~color;
2979  while (length--) {
2980  *dest = (color & ~(*dest)) | 0xff000000;
2981  ++dest;
2982  }
2983 }
2984 
2986  const uint *src,
2987  int length,
2988  uint const_alpha)
2989 {
2990  Q_UNUSED(const_alpha);
2991  while (length--) {
2992  *dest = (~(*src) & ~(*dest)) | 0xff000000;
2993  ++dest; ++src;
2994  }
2995 }
2996 
2998  int length,
2999  uint color,
3000  uint const_alpha)
3001 {
3002  Q_UNUSED(const_alpha);
3003  color = ~color | 0xff000000;
3004  while (length--) {
3005  *dest = color | ~(*dest);
3006  ++dest;
3007  }
3008 }
3009 
3011  const uint *src,
3012  int length,
3013  uint const_alpha)
3014 {
3015  Q_UNUSED(const_alpha);
3016  while (length--) {
3017  *dest = ~(*src) | ~(*dest) | 0xff000000;
3018  ++dest; ++src;
3019  }
3020 }
3021 
3023  int length,
3024  uint color,
3025  uint const_alpha)
3026 {
3027  Q_UNUSED(const_alpha);
3028  color = ~color & 0x00ffffff;
3029  while (length--) {
3030  *dest = color ^ (*dest);
3031  ++dest;
3032  }
3033 }
3034 
3036  const uint *src,
3037  int length,
3038  uint const_alpha)
3039 {
3040  Q_UNUSED(const_alpha);
3041  while (length--) {
3042  *dest = ((~(*src)) ^ (*dest)) | 0xff000000;
3043  ++dest; ++src;
3044  }
3045 }
3046 
3047 void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length,
3048  uint color, uint const_alpha)
3049 {
3050  Q_UNUSED(const_alpha);
3051  qt_memfill(dest, ~color | 0xff000000, length);
3052 }
3053 
3054 void QT_FASTCALL rasterop_NotSource(uint *dest, const uint *src,
3055  int length, uint const_alpha)
3056 {
3057  Q_UNUSED(const_alpha);
3058  while (length--)
3059  *dest++ = ~(*src++) | 0xff000000;
3060 }
3061 
3063  int length,
3064  uint color,
3065  uint const_alpha)
3066 {
3067  Q_UNUSED(const_alpha);
3068  color = ~color | 0xff000000;
3069  while (length--) {
3070  *dest = color & *dest;
3071  ++dest;
3072  }
3073 }
3074 
3076  const uint *src,
3077  int length,
3078  uint const_alpha)
3079 {
3080  Q_UNUSED(const_alpha);
3081  while (length--) {
3082  *dest = (~(*src) & *dest) | 0xff000000;
3083  ++dest; ++src;
3084  }
3085 }
3086 
3088  int length,
3089  uint color,
3090  uint const_alpha)
3091 {
3092  Q_UNUSED(const_alpha);
3093  while (length--) {
3094  *dest = (color & ~(*dest)) | 0xff000000;
3095  ++dest;
3096  }
3097 }
3098 
3100  const uint *src,
3101  int length,
3102  uint const_alpha)
3103 {
3104  Q_UNUSED(const_alpha);
3105  while (length--) {
3106  *dest = (*src & ~(*dest)) | 0xff000000;
3107  ++dest; ++src;
3108  }
3109 }
3110 
3145 };
3146 
3148 
3161  comp_func_XOR,
3183 };
3184 
3186 
3188 {
3189  TextureBlendType ft;
3190  if (data->txop <= QTransform::TxTranslate)
3191  if (data->texture.type == QTextureData::Tiled)
3192  ft = BlendTiled;
3193  else
3194  ft = BlendUntransformed;
3195  else if (data->bilinear)
3196  if (data->texture.type == QTextureData::Tiled)
3198  else
3200  else
3201  if (data->texture.type == QTextureData::Tiled)
3202  ft = BlendTransformedTiled;
3203  else
3204  ft = BlendTransformed;
3205  return ft;
3206 }
3207 
3208 static inline Operator getOperator(const QSpanData *data, const QSpan *spans, int spanCount)
3209 {
3210  Operator op;
3211  bool solidSource = false;
3212 
3213  switch(data->type) {
3214  case QSpanData::Solid:
3215  solidSource = (qAlpha(data->solid.color) == 255);
3216  break;
3218  solidSource = !data->gradient.alphaColor;
3219  getLinearGradientValues(&op.linear, data);
3221  break;
3223  solidSource = !data->gradient.alphaColor;
3224  getRadialGradientValues(&op.radial, data);
3226  break;
3228  solidSource = !data->gradient.alphaColor;
3230  break;
3231  case QSpanData::Texture:
3232  op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format];
3233  solidSource = !data->texture.hasAlpha;
3234  default:
3235  break;
3236  }
3237 
3238  op.mode = data->rasterBuffer->compositionMode;
3239  if (op.mode == QPainter::CompositionMode_SourceOver && solidSource)
3241 
3242  op.dest_fetch = destFetchProc[data->rasterBuffer->format];
3244  switch (data->rasterBuffer->format) {
3245  case QImage::Format_RGB32:
3247  // don't clear dest_fetch as it sets up the pointer correctly to save one copy
3248  break;
3249  default: {
3250  const QSpan *lastSpan = spans + spanCount;
3251  bool alphaSpans = false;
3252  while (spans < lastSpan) {
3253  if (spans->coverage != 255) {
3254  alphaSpans = true;
3255  break;
3256  }
3257  ++spans;
3258  }
3259  if (!alphaSpans)
3260  op.dest_fetch = 0;
3261  }
3262  }
3263  }
3264 
3265  op.dest_store = destStoreProc[data->rasterBuffer->format];
3266 
3267  op.funcSolid = functionForModeSolid[op.mode];
3268  op.func = functionForMode[op.mode];
3269 
3270  return op;
3271 }
3272 
3273 
3274 
3275 // -------------------- blend methods ---------------------
3276 
3280 };
3281 
3282 #if !defined(Q_CC_SUN)
3283 static
3284 #endif
3285 void drawBufferSpan(QSpanData *data, const uint *buffer, int bufsize,
3286  int x, int y, int length, uint const_alpha)
3287 {
3288 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3289  data->rasterEngine->drawBufferSpan(buffer, bufsize, x, y, length, const_alpha);
3290 #else
3291  Q_UNUSED(data);
3292  Q_UNUSED(buffer);
3293  Q_UNUSED(bufsize);
3294  Q_UNUSED(x);
3295  Q_UNUSED(y);
3296  Q_UNUSED(length);
3297  Q_UNUSED(const_alpha);
3298 #endif
3299 }
3300 
3301 #if !defined(Q_CC_SUN)
3302 static
3303 #endif
3304 void blend_color_generic(int count, const QSpan *spans, void *userData)
3305 {
3306  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3307  uint buffer[buffer_size];
3308  Operator op = getOperator(data, spans, count);
3309 
3310  while (count--) {
3311  int x = spans->x;
3312  int length = spans->len;
3313  while (length) {
3314  int l = qMin(buffer_size, length);
3315  uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3316  op.funcSolid(dest, l, data->solid.color, spans->coverage);
3317  if (op.dest_store)
3318  op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3319  length -= l;
3320  x += l;
3321  }
3322  ++spans;
3323  }
3324 }
3325 
3326 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3327 static void blend_color_generic_callback(int count, const QSpan *spans, void *userData)
3328 {
3329  // ### Falcon
3330  Q_UNUSED(count);
3331  Q_UNUSED(spans);
3332  Q_UNUSED(userData);
3333 // QSpanData *data = reinterpret_cast<QSpanData*>(userData);
3334 // data->rasterEngine->drawColorSpans(spans, count, data->solid.color);
3335 }
3336 #endif // QT_NO_RASTERCALLBACKS
3337 
3338 static void blend_color_argb(int count, const QSpan *spans, void *userData)
3339 {
3340  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3341 
3342  Operator op = getOperator(data, spans, count);
3343 
3345  // inline for performance
3346  while (count--) {
3347  uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3348  if (spans->coverage == 255) {
3349  QT_MEMFILL_UINT(target, spans->len, data->solid.color);
3350  } else {
3351  uint c = BYTE_MUL(data->solid.color, spans->coverage);
3352  int ialpha = 255 - spans->coverage;
3353  for (int i = 0; i < spans->len; ++i)
3354  target[i] = c + BYTE_MUL(target[i], ialpha);
3355  }
3356  ++spans;
3357  }
3358  return;
3359  }
3360 
3361  while (count--) {
3362  uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3363  op.funcSolid(target, spans->len, data->solid.color, spans->coverage);
3364  ++spans;
3365  }
3366 }
3367 
3368 template <class T>
3369 Q_STATIC_TEMPLATE_FUNCTION void blendColor(int count, const QSpan *spans, void *userData)
3370 {
3371  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3372  Operator op = getOperator(data, spans, count);
3373 
3375  const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(data->solid.color), 0);
3376  while (count--) {
3377  T *target = ((T*)data->rasterBuffer->scanLine(spans->y))
3378  + spans->x;
3379  if (spans->coverage == 255) {
3380  qt_memfill(target, c, spans->len);
3381  } else {
3382  const quint8 alpha = T::alpha(spans->coverage);
3383  const T color = c.byte_mul(alpha);
3384  const int ialpha = T::ialpha(spans->coverage);
3385  const T *end = target + spans->len;
3386  while (target < end) {
3387  *target = color + target->byte_mul(ialpha);
3388  ++target;
3389  }
3390  }
3391  ++spans;
3392  }
3393  return;
3394  }
3395 
3397  while (count--) {
3398  const quint32 color = BYTE_MUL(data->solid.color, spans->coverage);
3399  const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0);
3400  const quint8 ialpha = T::alpha(qAlpha(~color));
3401  T *target = ((T*)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3402  const T *end = target + spans->len;
3403  while (target != end) {
3404  *target = c + target->byte_mul(ialpha);
3405  ++target;
3406  }
3407  ++spans;
3408  }
3409  return;
3410  }
3411 
3412  blend_color_generic(count, spans, userData);
3413 }
3414 
3415 #define SPANFUNC_POINTER_BLENDCOLOR(DST) blendColor<DST>
3416 
3417 static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
3418 {
3419  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3420 
3421  /*
3422  We duplicate a little logic from getOperator() and calculate the
3423  composition mode directly. This allows blend_color_rgb16 to be used
3424  from qt_gradient_quint16 with minimal overhead.
3425  */
3428  qAlpha(data->solid.color) == 255)
3430 
3431  if (mode == QPainter::CompositionMode_Source) {
3432  // inline for performance
3434  while (count--) {
3435  ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3436  if (spans->coverage == 255) {
3437  QT_MEMFILL_USHORT(target, spans->len, c);
3438  } else {
3439  ushort color = BYTE_MUL_RGB16(c, spans->coverage);
3440  int ialpha = 255 - spans->coverage;
3441  const ushort *end = target + spans->len;
3442  while (target < end) {
3443  *target = color + BYTE_MUL_RGB16(*target, ialpha);
3444  ++target;
3445  }
3446  }
3447  ++spans;
3448  }
3449  return;
3450  }
3451 
3453  while (count--) {
3454  uint color = BYTE_MUL(data->solid.color, spans->coverage);
3455  int ialpha = qAlpha(~color);
3456  ushort c = qConvertRgb32To16(color);
3457  ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
3458  int len = spans->len;
3459  bool pre = (((quintptr)target) & 0x3) != 0;
3460  bool post = false;
3461  if (pre) {
3462  // skip to word boundary
3463  *target = c + BYTE_MUL_RGB16(*target, ialpha);
3464  ++target;
3465  --len;
3466  }
3467  if (len & 0x1) {
3468  post = true;
3469  --len;
3470  }
3471  uint *target32 = (uint*)target;
3472  uint c32 = c | (c<<16);
3473  len >>= 1;
3474  uint salpha = (ialpha+1) >> 3; // calculate here rather than in loop
3475  while (len--) {
3476  // blend full words
3477  *target32 = c32 + BYTE_MUL_RGB16_32(*target32, salpha);
3478  ++target32;
3479  target += 2;
3480  }
3481  if (post) {
3482  // one last pixel beyond a full word
3483  *target = c + BYTE_MUL_RGB16(*target, ialpha);
3484  }
3485  ++spans;
3486  }
3487  return;
3488  }
3489 
3490  blend_color_generic(count, spans, userData);
3491 }
3492 
3493 template <typename T>
3494 void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
3495 {
3496  uint const_alpha = 256;
3497  if (data->type == QSpanData::Texture)
3498  const_alpha = data->texture.const_alpha;
3499 
3500  int coverage = 0;
3501  while (count) {
3502  int x = spans->x;
3503  const int y = spans->y;
3504  int right = x + spans->len;
3505 
3506  // compute length of adjacent spans
3507  for (int i = 1; i < count && spans[i].y == y && spans[i].x == right; ++i)
3508  right += spans[i].len;
3509  int length = right - x;
3510 
3511  while (length) {
3512  int l = qMin(buffer_size, length);
3513  length -= l;
3514 
3515  int process_length = l;
3516  int process_x = x;
3517 
3518  const uint *src = handler.fetch(process_x, y, process_length);
3519  int offset = 0;
3520  while (l > 0) {
3521  if (x == spans->x) // new span?
3522  coverage = (spans->coverage * const_alpha) >> 8;
3523 
3524  int right = spans->x + spans->len;
3525  int len = qMin(l, right - x);
3526 
3527  handler.process(x, y, len, coverage, src, offset);
3528 
3529  l -= len;
3530  x += len;
3531  offset += len;
3532 
3533  if (x == right) { // done with current span?
3534  ++spans;
3535  --count;
3536  }
3537  }
3538  handler.store(process_x, y, process_length);
3539  }
3540  }
3541 }
3542 
3544 {
3545  QBlendBase(QSpanData *d, Operator o)
3546  : data(d)
3547  , op(o)
3548  , dest(0)
3549  {
3550  }
3551 
3553  Operator op;
3554 
3555  uint *dest;
3556 
3557  uint buffer[buffer_size];
3558  uint src_buffer[buffer_size];
3559 };
3560 
3561 template <SpanMethod spanMethod>
3563 {
3564 public:
3566  : QBlendBase(d, o)
3567  {
3568  }
3569 
3570  const uint *fetch(int x, int y, int len)
3571  {
3572  if (spanMethod == RegularSpans)
3573  dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, y, len) : buffer;
3574 
3575  return op.src_fetch(src_buffer, &op, data, y, x, len);
3576  }
3577 
3578  void process(int x, int y, int len, int coverage, const uint *src, int offset)
3579  {
3580  if (spanMethod == RegularSpans)
3581  op.func(dest + offset, src + offset, len, coverage);
3582  else
3583  drawBufferSpan(data, src + offset, len, x, y, len, coverage);
3584  }
3585 
3586  void store(int x, int y, int len)
3587  {
3588  if (spanMethod == RegularSpans && op.dest_store) {
3589  op.dest_store(data->rasterBuffer, x, y, dest, len);
3590  }
3591  }
3592 };
3593 
3594 template <SpanMethod spanMethod>
3595 Q_STATIC_TEMPLATE_FUNCTION void blend_src_generic(int count, const QSpan *spans, void *userData)
3596 {
3597  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3598  BlendSrcGeneric<spanMethod> blend(data, getOperator(data, spans, count));
3599  handleSpans(count, spans, data, blend);
3600 }
3601 
3602 template <SpanMethod spanMethod>
3603 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
3604 {
3605  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3606 
3607  uint buffer[buffer_size];
3608  uint src_buffer[buffer_size];
3609  Operator op = getOperator(data, spans, count);
3610 
3611  const int image_width = data->texture.width;
3612  const int image_height = data->texture.height;
3613  int xoff = -qRound(-data->dx);
3614  int yoff = -qRound(-data->dy);
3615 
3616  while (count--) {
3617  int x = spans->x;
3618  int length = spans->len;
3619  int sx = xoff + x;
3620  int sy = yoff + spans->y;
3621  if (sy >= 0 && sy < image_height && sx < image_width) {
3622  if (sx < 0) {
3623  x -= sx;
3624  length += sx;
3625  sx = 0;
3626  }
3627  if (sx + length > image_width)
3628  length = image_width - sx;
3629  if (length > 0) {
3630  const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3631  while (length) {
3632  int l = qMin(buffer_size, length);
3633  const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
3634  if (spanMethod == RegularSpans) {
3635  uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
3636  op.func(dest, src, l, coverage);
3637  if (op.dest_store)
3638  op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
3639  } else {
3640  drawBufferSpan(data, src, l, x, spans->y,
3641  l, coverage);
3642  }
3643  x += l;
3644  sx += l;
3645  length -= l;
3646  }
3647  }
3648  }
3649  ++spans;
3650  }
3651 }
3652 
3653 template <SpanMethod spanMethod>
3654 Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
3655 {
3656  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
3658  && data->texture.format != QImage::Format_RGB32) {
3659  blend_untransformed_generic<spanMethod>(count, spans, userData);
3660  return;
3661  }
3662 
3663  Operator op = getOperator(data, spans, count);
3664 
3665  const int image_width = data->texture.width;
3666  const int image_height = data->texture.height;
3667  int xoff = -qRound(-data->dx);
3668  int yoff = -qRound(-data->dy);
3669 
3670  while (count--) {
3671  int x = spans->x;
3672  int length = spans->len;
3673  int sx = xoff + x;
3674  int sy = yoff + spans->y;
3675  if (sy >= 0 && sy < image_height && sx < image_width) {
3676  if (sx < 0) {
3677  x -= sx;
3678  length += sx;
3679  sx = 0;
3680  }
3681  if (sx + length > image_width)
3682  length = image_width - sx;
3683  if (length > 0) {
3684  const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
3685  const uint *src = (uint *)data->texture.scanLine(sy) + sx;
3686  if (spanMethod == RegularSpans) {
3687  uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
3688  op.func(dest, src, length, coverage);
3689  } else {
3690  drawBufferSpan(data, src, length, x,
3691  spans->y, length, coverage);
3692  }
3693  }
3694  }
3695  ++spans;
3696  }
3697 }
3698 
3700  quint16 y, quint8 b)
3701 {
3702  quint16 t = ((((x & 0x07e0) * a) + ((y & 0x07e0) * b)) >> 5) & 0x07e0;
3703  t |= ((((x & 0xf81f) * a) + ((y & 0xf81f) * b)) >> 5) & 0xf81f;
3704 
3705  return t;
3706 }
3707 
3709  quint32 y, quint8 b)
3710 {
3711  uint t;
3712  t = ((((x & 0xf81f07e0) >> 5) * a) + (((y & 0xf81f07e0) >> 5) * b)) & 0xf81f07e0;
3713  t |= ((((x & 0x07e0f81f) * a) + ((y & 0x07e0f81f) * b)) >> 5) & 0x07e0f81f;
3714  return t;
3715 }
3716 
3717 static inline void blend_sourceOver_rgb16_rgb16(quint16 *dest,
3718  const quint16 *src,
3719  int length,
3720  const quint8 alpha,
3721  const quint8 ialpha)
3722 {
3723  const int dstAlign = ((quintptr)dest) & 0x3;
3724  if (dstAlign) {
3725  *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
3726  ++dest;
3727  ++src;
3728  --length;
3729  }
3730  const int srcAlign = ((quintptr)src) & 0x3;
3731  int length32 = length >> 1;
3732  if (length32 && srcAlign == 0) {
3733  while (length32--) {
3734  const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3735  quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3736  *dest32 = interpolate_pixel_rgb16x2_255(*src32, alpha,
3737  *dest32, ialpha);
3738  dest += 2;
3739  src += 2;
3740  }
3741  length &= 0x1;
3742  }
3743  while (length--) {
3744  *dest = interpolate_pixel_rgb16_255(*src, alpha, *dest, ialpha);
3745  ++dest;
3746  ++src;
3747  }
3748 }
3749 
3750 template <class DST, class SRC>
3752 inline void madd_2(DST *dest, const quint16 alpha, const SRC *src)
3753 {
3754  Q_ASSERT((quintptr(dest) & 0x3) == 0);
3755  Q_ASSERT((quintptr(src) & 0x3) == 0);
3756  dest[0] = dest[0].byte_mul(alpha >> 8) + DST(src[0]);
3757  dest[1] = dest[1].byte_mul(alpha & 0xff) + DST(src[1]);
3758 }
3759 
3760 template <class DST, class SRC>
3762 inline void madd_4(DST *dest, const quint32 alpha, const SRC *src)
3763 {
3764  Q_ASSERT((quintptr(dest) & 0x3) == 0);
3765  Q_ASSERT((quintptr(src) & 0x3) == 0);
3766  dest[0] = dest[0].byte_mul(alpha >> 24) + DST(src[0]);
3767  dest[1] = dest[1].byte_mul((alpha >> 16) & 0xff) + DST(src[1]);
3768  dest[2] = dest[2].byte_mul((alpha >> 8) & 0xff) + DST(src[2]);
3769  dest[3] = dest[3].byte_mul(alpha & 0xff) + DST(src[3]);
3770 }
3771 
3772 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
3773 template <>
3775 inline void madd_4(qargb8565 *dest, const quint32 a, const qargb8565 *src)
3776 {
3777  Q_ASSERT((quintptr(dest) & 0x3) == 0);
3778  Q_ASSERT((quintptr(src) & 0x3) == 0);
3779 
3780  const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3781  quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3782  quint32 x, y, t;
3783  quint8 a8;
3784 
3785  {
3786  x = dest32[0];
3787  y = src32[0];
3788 
3789  a8 = a >> 24;
3790 
3791  // a0,g0
3792  t = ((((x & 0x0007e0ff) * a8) >> 5) & 0x0007e0ff) + (y & 0x0007c0f8);
3793 
3794  // r0,b0
3795  t |= ((((x & 0x00f81f00) * a8) >> 5) & 0x00f81f00) + (y & 0x00f81f00);
3796 
3797  a8 = (a >> 16) & 0xff;
3798 
3799  // a1
3800  t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
3801 
3802  dest32[0] = t;
3803  }
3804  {
3805  x = dest32[1];
3806  y = src32[1];
3807 
3808  // r1,b1
3809  t = ((((x & 0x0000f81f) * a8) >> 5) & 0x0000f81f) + (y & 0x0000f81f);
3810 
3811  // g1
3812  t |= ((((x & 0x000007e0) * a8) >> 5) & 0x000007e0) + (y & 0x000007c0);
3813 
3814  a8 = (a >> 8) & 0xff;
3815 
3816  // a2
3817  t |= ((((x & 0x00ff0000) * a8) >> 5) & 0x00ff0000) + (y & 0x00f80000);
3818 
3819  {
3820  // rgb2
3821  quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
3822  quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
3823  quint16 t16;
3824 
3825  t16 = ((((x16 & 0xf81f) * a8) >> 5) & 0xf81f) + (y16 & 0xf81f);
3826  t16 |= ((((x16 & 0x07e0) * a8) >> 5) & 0x07e0) + (y16 & 0x07c0);
3827 
3828  // rg2
3829  t |= ((t16 & 0x00ff) << 24);
3830 
3831  dest32[1] = t;
3832 
3833  x = dest32[2];
3834  y = src32[2];
3835 
3836  // gb2
3837  t = (t16 >> 8);
3838  }
3839  }
3840  {
3841  a8 = a & 0xff;
3842 
3843  // g3,a3
3844  t |= ((((x & 0x07e0ff00) * a8) >> 5) & 0x07e0ff00) + (y & 0x07c0f800);
3845 
3846  // r3,b3
3847  t |= ((((x & 0xf81f0000) >> 5) * a8) & 0xf81f0000)+ (y & 0xf81f0000);
3848 
3849  dest32[2] = t;
3850  }
3851 }
3852 #endif
3853 
3854 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
3855 template <>
3857 inline void madd_4(qargb8555 *dest, const quint32 a, const qargb8555 *src)
3858 {
3859  Q_ASSERT((quintptr(dest) & 0x3) == 0);
3860  Q_ASSERT((quintptr(src) & 0x3) == 0);
3861 
3862  const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3863  quint32 *dest32 = reinterpret_cast<quint32*>(dest);
3864  quint32 x, y, t;
3865  quint8 a8;
3866 
3867  {
3868  x = dest32[0];
3869  y = src32[0];
3870 
3871  a8 = a >> 24;
3872 
3873  // a0,g0
3874  t = ((((x & 0x0003e0ff) * a8) >> 5) & 0x0003e0ff) + (y & 0x0003e0f8);
3875 
3876  // r0,b0
3877  t |= ((((x & 0x007c1f00) * a8) >> 5) & 0x007c1f00) + (y & 0x007c1f00);
3878 
3879  a8 = (a >> 16) & 0xff;
3880 
3881  // a1
3882  t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
3883 
3884  dest32[0] = t;
3885  }
3886  {
3887  x = dest32[1];
3888  y = src32[1];
3889 
3890  // r1,b1
3891  t = ((((x & 0x00007c1f) * a8) >> 5) & 0x00007c1f) + (y & 0x00007c1f);
3892 
3893  // g1
3894  t |= ((((x & 0x000003e0) * a8) >> 5) & 0x000003e0) + (y & 0x000003e0);
3895 
3896  a8 = (a >> 8) & 0xff;
3897 
3898  // a2
3899  t |= ((((x & 0x00ff0000) * a8) >> 5) & 0x00ff0000) + (y & 0x00f80000);
3900 
3901  {
3902  // rgb2
3903  quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
3904  quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
3905  quint16 t16;
3906 
3907  t16 = ((((x16 & 0x7c1f) * a8) >> 5) & 0x7c1f) + (y16 & 0x7c1f);
3908  t16 |= ((((x16 & 0x03e0) * a8) >> 5) & 0x03e0) + (y16 & 0x03e0);
3909 
3910  // rg2
3911  t |= ((t16 & 0x00ff) << 24);
3912 
3913  dest32[1] = t;
3914 
3915  x = dest32[2];
3916  y = src32[2];
3917 
3918  // gb2
3919  t = (t16 >> 8);
3920  }
3921  }
3922  {
3923  a8 = a & 0xff;
3924 
3925  // g3,a3
3926  t |= ((((x & 0x03e0ff00) * a8) >> 5) & 0x03e0ff00) + (y & 0x03e0f800);
3927 
3928  // r3,b3
3929  t |= ((((x & 0x7c1f0000) >> 5) * a8) & 0x7c1f0000)+ (y & 0x7c1f0000);
3930 
3931  dest32[2] = t;
3932  }
3933 }
3934 #endif
3935 
3936 template <class T>
3938 inline quint16 alpha_2(const T *src)
3939 {
3940  Q_ASSERT((quintptr(src) & 0x3) == 0);
3941 
3942  if (T::hasAlpha())
3943  return (src[0].alpha() << 8) | src[1].alpha();
3944  else
3945  return 0xffff;
3946 }
3947 
3948 template <class T>
3950 inline quint32 alpha_4(const T *src)
3951 {
3952  Q_ASSERT((quintptr(src) & 0x3) == 0);
3953 
3954  if (T::hasAlpha()) {
3955  return (src[0].alpha() << 24) | (src[1].alpha() << 16)
3956  | (src[2].alpha() << 8) | src[3].alpha();
3957  } else {
3958  return 0xffffffff;
3959  }
3960 }
3961 
3962 template <>
3964 inline quint32 alpha_4(const qargb8565 *src)
3965 {
3966  const quint8 *src8 = reinterpret_cast<const quint8*>(src);
3967  return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
3968 }
3969 
3970 template <>
3972 inline quint32 alpha_4(const qargb6666 *src)
3973 {
3974  const quint8 *src8 = reinterpret_cast<const quint8*>(src);
3975  return ((src8[2] & 0xfc) | (src8[2] >> 6)) << 24
3976  | ((src8[5] & 0xfc) | (src8[5] >> 6)) << 16
3977  | ((src8[8] & 0xfc) | (src8[8] >> 6)) << 8
3978  | ((src8[11] & 0xfc) | (src8[11] >> 6));
3979 }
3980 
3981 template <>
3983 inline quint32 alpha_4(const qargb8555 *src)
3984 {
3985  Q_ASSERT((quintptr(src) & 0x3) == 0);
3986  const quint8 *src8 = reinterpret_cast<const quint8*>(src);
3987  return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
3988 }
3989 
3990 template <>
3992 inline quint16 alpha_2(const qargb4444 *src)
3993 {
3994  const quint32 *src32 = reinterpret_cast<const quint32*>(src);
3995  const quint32 t = (*src32 & 0xf000f000) |
3996  ((*src32 & 0xf000f000) >> 4);
3997  return (t >> 24) | (t & 0xff00);
3998 }
3999 
4000 template <class T>
4002 inline quint16 eff_alpha_2(quint16 alpha, const T*)
4003 {
4004  return (T::alpha((alpha >> 8) & 0xff) << 8)
4005  | T::alpha(alpha & 0xff);
4006 }
4007 
4008 template <>
4011 {
4012  return ((((a & 0xff00) + 0x0100) >> 3) & 0xff00)
4013  | ((((a & 0x00ff) + 0x0001) >> 3) & 0x00ff);
4014 }
4015 
4016 template <>
4019 {
4020  return (((a & 0x00ff) + 0x0001) >> 4)
4021  | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
4022 }
4023 
4024 template <>
4027 {
4028  return (((a & 0x00ff) + 0x0001) >> 4)
4029  | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
4030 }
4031 
4032 template <class T>
4034 inline quint16 eff_ialpha_2(quint16 alpha, const T*)
4035 {
4036  return (T::ialpha((alpha >> 8) & 0xff) << 8)
4037  | T::ialpha(alpha & 0xff);
4038 }
4039 
4040 template <>
4042 inline quint16 eff_ialpha_2(quint16 a, const qrgb565 *dummy)
4043 {
4044  return 0x2020 - eff_alpha_2(a, dummy);
4045 }
4046 
4047 template <>
4049 inline quint16 eff_ialpha_2(quint16 a, const qargb4444 *dummy)
4050 {
4051  return 0x1010 - eff_alpha_2(a, dummy);
4052 }
4053 
4054 template <>
4056 inline quint16 eff_ialpha_2(quint16 a, const qrgb444 *dummy)
4057 {
4058  return 0x1010 - eff_alpha_2(a, dummy);
4059 }
4060 
4061 template <class T>
4063 inline quint32 eff_alpha_4(quint32 alpha, const T*)
4064 {
4065  return (T::alpha(alpha >> 24) << 24)
4066  | (T::alpha((alpha >> 16) & 0xff) << 16)
4067  | (T::alpha((alpha >> 8) & 0xff) << 8)
4068  | T::alpha(alpha & 0xff);
4069 }
4070 
4071 template <>
4074 {
4075  return a;
4076 }
4077 
4078 template <>
4081 {
4082  return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
4083  | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
4084 }
4085 
4086 template <>
4089 {
4090  return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
4091  | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
4092 }
4093 
4094 template <>
4097 {
4098  return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
4099  | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
4100 }
4101 
4102 template <>
4105 {
4106  return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
4107  | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
4108 }
4109 
4110 template <class T>
4112 inline quint32 eff_ialpha_4(quint32 alpha, const T*)
4113 {
4114  return (T::ialpha(alpha >> 24) << 24)
4115  | (T::ialpha((alpha >> 16) & 0xff) << 16)
4116  | (T::ialpha((alpha >> 8) & 0xff) << 8)
4117  | T::ialpha(alpha & 0xff);
4118 }
4119 
4120 template <>
4123 {
4124  return ~a;
4125 }
4126 
4127 template <>
4129 inline quint32 eff_ialpha_4(quint32 a, const qargb8565 *dummy)
4130 {
4131  return 0x20202020 - eff_alpha_4(a, dummy);
4132 }
4133 
4134 template <>
4136 inline quint32 eff_ialpha_4(quint32 a, const qargb6666 *dummy)
4137 {
4138  return 0x40404040 - eff_alpha_4(a, dummy);
4139 }
4140 
4141 template <>
4143 inline quint32 eff_ialpha_4(quint32 a, const qrgb666 *dummy)
4144 {
4145  return 0x40404040 - eff_alpha_4(a, dummy);
4146 }
4147 
4148 template <>
4150 inline quint32 eff_ialpha_4(quint32 a, const qargb8555 *dummy)
4151 {
4152  return 0x20202020 - eff_alpha_4(a, dummy);
4153 }
4154 
4155 template <class DST, class SRC>
4156 inline void interpolate_pixel_unaligned_2(DST *dest, const SRC *src,
4157  quint16 alpha)
4158 {
4159  const quint16 a = eff_alpha_2(alpha, dest);
4160  const quint16 ia = eff_ialpha_2(alpha, dest);
4161  dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
4162  dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
4163 }
4164 
4165 template <class DST, class SRC>
4166 inline void interpolate_pixel_2(DST *dest, const SRC *src, quint16 alpha)
4167 {
4168  Q_ASSERT((quintptr(dest) & 0x3) == 0);
4169  Q_ASSERT((quintptr(src) & 0x3) == 0);
4170 
4171  const quint16 a = eff_alpha_2(alpha, dest);
4172  const quint16 ia = eff_ialpha_2(alpha, dest);
4173 
4174  dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
4175  dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
4176 }
4177 
4178 template <class DST, class SRC>
4179 inline void interpolate_pixel(DST &dest, quint8 a, const SRC &src, quint8 b)
4180 {
4181  if (SRC::hasAlpha() && !DST::hasAlpha())
4182  interpolate_pixel(dest, a, DST(src), b);
4183  else
4184  dest = dest.byte_mul(a) + DST(src).byte_mul(b);
4185 }
4186 
4187 template <>
4189  const qargb8565 &src, quint8 b)
4190 {
4191  quint8 *d = reinterpret_cast<quint8*>(&dest);
4192  const quint8 *s = reinterpret_cast<const quint8*>(&src);
4193  d[0] = (d[0] * a + s[0] * b) >> 5;
4194 
4195  const quint16 x = (d[2] << 8) | d[1];
4196  const quint16 y = (s[2] << 8) | s[1];
4197  quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
4198  t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
4199 
4200  d[1] = t & 0xff;
4201  d[2] = t >> 8;
4202 }
4203 
4204 template <>
4205 inline void interpolate_pixel(qrgb565 &dest, quint8 a,
4206  const qrgb565 &src, quint8 b)
4207 {
4208  const quint16 x = dest.rawValue();
4209  const quint16 y = src.rawValue();
4210  quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
4211  t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
4212  dest = t;
4213 }
4214 
4215 template <>
4216 inline void interpolate_pixel(qrgb555 &dest, quint8 a,
4217  const qrgb555 &src, quint8 b)
4218 {
4219  const quint16 x = dest.rawValue();
4220  const quint16 y = src.rawValue();
4221  quint16 t = (((x & 0x03e0) * a + (y & 0x03e0) * b) >> 5) & 0x03e0;
4222  t |= ((((x & 0x7c1f) * a) + ((y & 0x7c1f) * b)) >> 5) & 0x7c1f;
4223  dest = t;
4224 }
4225 
4226 template <>
4227 inline void interpolate_pixel(qrgb444 &dest, quint8 a,
4228  const qrgb444 &src, quint8 b)
4229 {
4230  const quint16 x = dest.rawValue();
4231  const quint16 y = src.rawValue();
4232  quint16 t = ((x & 0x00f0) * a + (y & 0x00f0) * b) & 0x0f00;
4233  t |= ((x & 0x0f0f) * a + (y & 0x0f0f) * b) & 0xf0f0;
4234  quint16 *d = reinterpret_cast<quint16*>(&dest);
4235  *d = (t >> 4);
4236 }
4237 
4238 template <class DST, class SRC>
4239 inline void interpolate_pixel_2(DST *dest, quint8 a,
4240  const SRC *src, quint8 b)
4241 {
4242  Q_ASSERT((quintptr(dest) & 0x3) == 0);
4243  Q_ASSERT((quintptr(src) & 0x3) == 0);
4244 
4245  Q_ASSERT(!SRC::hasAlpha());
4246 
4247  dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
4248  dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
4249 }
4250 
4251 template <>
4253  const qrgb565 *src, quint8 b)
4254 {
4255  quint32 *x = reinterpret_cast<quint32*>(dest);
4256  const quint32 *y = reinterpret_cast<const quint32*>(src);
4257  quint32 t = (((*x & 0xf81f07e0) >> 5) * a +
4258  ((*y & 0xf81f07e0) >> 5) * b) & 0xf81f07e0;
4259  t |= (((*x & 0x07e0f81f) * a
4260  + (*y & 0x07e0f81f) * b) >> 5) & 0x07e0f81f;
4261  *x = t;
4262 }
4263 
4264 template <>
4266  const qrgb555 *src, quint8 b)
4267 {
4268  quint32 *x = reinterpret_cast<quint32*>(dest);
4269  const quint32 *y = reinterpret_cast<const quint32*>(src);
4270  quint32 t = (((*x & 0x7c1f03e0) >> 5) * a +
4271  ((*y & 0x7c1f03e0) >> 5) * b) & 0x7c1f03e0;
4272  t |= (((*x & 0x03e07c1f) * a
4273  + (*y & 0x03e07c1f) * b) >> 5) & 0x03e07c1f;
4274  *x = t;
4275 }
4276 
4277 template <>
4279  const qrgb444 *src, quint8 b)
4280 {
4281  quint32 *x = reinterpret_cast<quint32*>(dest);
4282  const quint32 *y = reinterpret_cast<const quint32*>(src);
4283  quint32 t = ((*x & 0x0f0f0f0f) * a + (*y & 0x0f0f0f0f) * b) & 0xf0f0f0f0;
4284  t |= ((*x & 0x00f000f0) * a + (*y & 0x00f000f0) * b) & 0x0f000f00;
4285  *x = t >> 4;
4286 }
4287 
4288 template <class DST, class SRC>
4289 inline void interpolate_pixel_4(DST *dest, const SRC *src, quint32 alpha)
4290 {
4291  Q_ASSERT((quintptr(dest) & 0x3) == 0);
4292  Q_ASSERT((quintptr(src) & 0x3) == 0);
4293 
4294  const quint32 a = eff_alpha_4(alpha, dest);
4295  const quint32 ia = eff_ialpha_4(alpha, dest);
4296  dest[0] = DST(src[0]).byte_mul(a >> 24)
4297  + dest[0].byte_mul(ia >> 24);
4298  dest[1] = DST(src[1]).byte_mul((a >> 16) & 0xff)
4299  + dest[1].byte_mul((ia >> 16) & 0xff);
4300  dest[2] = DST(src[2]).byte_mul((a >> 8) & 0xff)
4301  + dest[2].byte_mul((ia >> 8) & 0xff);
4302  dest[3] = DST(src[3]).byte_mul(a & 0xff)
4303  + dest[3].byte_mul(ia & 0xff);
4304 }
4305 
4306 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4307 template <>
4308 inline void interpolate_pixel_4(qargb8565 *dest, const qargb8565 *src,
4309  quint32 alpha)
4310 {
4311  Q_ASSERT((quintptr(dest) & 0x3) == 0);
4312  Q_ASSERT((quintptr(src) & 0x3) == 0);
4313 
4314  const quint32 a = eff_alpha_4(alpha, dest);
4315  const quint32 ia = eff_ialpha_4(alpha, dest);
4316  const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4317  quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4318 
4319  quint32 x, y, t;
4320  quint8 a8, ia8;
4321  {
4322  x = src32[0];
4323  y = dest32[0];
4324 
4325  a8 = a >> 24;
4326  ia8 = ia >> 24;
4327 
4328  // a0,g0
4329  t = (((x & 0x0007e0ff) * a8 + (y & 0x0007e0ff) * ia8) >> 5)
4330  & 0x0007e0ff;
4331 
4332  // r0,b0
4333  t |= (((x & 0x00f81f00) * a8 + (y & 0x00f81f00) * ia8) >> 5)
4334  & 0x00f81f00;
4335 
4336  a8 = (a >> 16) & 0xff;
4337  ia8 = (ia >> 16) & 0xff;
4338 
4339  // a1
4340  t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
4341  & 0xff000000;
4342 
4343  dest32[0] = t;
4344  }
4345  {
4346  x = src32[1];
4347  y = dest32[1];
4348 
4349  // r1,b1
4350  t = (((x & 0x0000f81f) * a8 + (y & 0x0000f81f) * ia8) >> 5)
4351  & 0x0000f81f;
4352 
4353  // g1
4354  t |= (((x & 0x000007e0) * a8 + (y & 0x000007e0) * ia8) >> 5)
4355  & 0x000007e0;
4356 
4357  a8 = (a >> 8) & 0xff;
4358  ia8 = (ia >> 8) & 0xff;
4359 
4360  // a2
4361  t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
4362  & 0x00ff0000;
4363 
4364  {
4365  // rgb2
4366  quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
4367  quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
4368  quint16 t16;
4369 
4370  t16 = (((x16 & 0xf81f) * a8 + (y16 & 0xf81f) * ia8) >> 5) & 0xf81f;
4371  t16 |= (((x16 & 0x07e0) * a8 + (y16 & 0x07e0) * ia8) >> 5) & 0x07e0;
4372 
4373  // rg2
4374  t |= ((t16 & 0x00ff) << 24);
4375 
4376  dest32[1] = t;
4377 
4378  x = src32[2];
4379  y = dest32[2];
4380 
4381  // gb2
4382  t = (t16 >> 8);
4383  }
4384  }
4385  {
4386  a8 = a & 0xff;
4387  ia8 = ia & 0xff;
4388 
4389  // g3,a3
4390  t |= (((x & 0x07e0ff00) * a8 + (y & 0x07e0ff00) * ia8) >> 5)
4391  & 0x07e0ff00;
4392 
4393  // r3,b3
4394  t |= (((x & 0xf81f0000) >> 5) * a8 + ((y & 0xf81f0000) >> 5) * ia8)
4395  & 0xf81f0000;
4396 
4397  dest32[2] = t;
4398  }
4399 }
4400 #endif
4401 
4402 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4403 template <>
4404 inline void interpolate_pixel_4(qargb8555 *dest, const qargb8555 *src,
4405  quint32 alpha)
4406 {
4407  Q_ASSERT((quintptr(dest) & 0x3) == 0);
4408  Q_ASSERT((quintptr(src) & 0x3) == 0);
4409 
4410 
4411  const quint32 a = eff_alpha_4(alpha, dest);
4412  const quint32 ia = eff_ialpha_4(alpha, dest);
4413  const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4414  quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4415 
4416  quint32 x, y, t;
4417  quint8 a8, ia8;
4418  {
4419  x = src32[0];
4420  y = dest32[0];
4421 
4422  a8 = a >> 24;
4423  ia8 = ia >> 24;
4424 
4425  // a0,g0
4426  t = (((x & 0x0003e0ff) * a8 + (y & 0x0003e0ff) * ia8) >> 5)
4427  & 0x0003e0ff;
4428 
4429  // r0,b0
4430  t |= (((x & 0x007c1f00) * a8 + (y & 0x007c1f00) * ia8) >> 5)
4431  & 0x007c1f00;
4432 
4433  a8 = (a >> 16) & 0xff;
4434  ia8 = (ia >> 16) & 0xff;
4435 
4436  // a1
4437  t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
4438  & 0xff000000;
4439 
4440  dest32[0] = t;
4441  }
4442  {
4443  x = src32[1];
4444  y = dest32[1];
4445 
4446  // r1,b1
4447  t = (((x & 0x00007c1f) * a8 + (y & 0x00007c1f) * ia8) >> 5)
4448  & 0x00007c1f;
4449 
4450  // g1
4451  t |= (((x & 0x000003e0) * a8 + (y & 0x000003e0) * ia8) >> 5)
4452  & 0x000003e0;
4453 
4454  a8 = (a >> 8) & 0xff;
4455  ia8 = (ia >> 8) & 0xff;
4456 
4457  // a2
4458  t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
4459  & 0x00ff0000;
4460 
4461  {
4462  // rgb2
4463  quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
4464  quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
4465  quint16 t16;
4466 
4467  t16 = (((x16 & 0x7c1f) * a8 + (y16 & 0x7c1f) * ia8) >> 5) & 0x7c1f;
4468  t16 |= (((x16 & 0x03e0) * a8 + (y16 & 0x03e0) * ia8) >> 5) & 0x03e0;
4469 
4470  // rg2
4471  t |= ((t16 & 0x00ff) << 24);
4472 
4473  dest32[1] = t;
4474 
4475  x = src32[2];
4476  y = dest32[2];
4477 
4478  // gb2
4479  t = (t16 >> 8);
4480  }
4481  }
4482  {
4483  a8 = a & 0xff;
4484  ia8 = ia & 0xff;
4485 
4486  // g3,a3
4487  t |= (((x & 0x03e0ff00) * a8 + (y & 0x03e0ff00) * ia8) >> 5)
4488  & 0x03e0ff00;
4489 
4490  // r3,b3
4491  t |= (((x & 0x7c1f0000) >> 5) * a8 + ((y & 0x7c1f0000) >> 5) * ia8)
4492  & 0x7c1f0000;
4493 
4494  dest32[2] = t;
4495  }
4496 }
4497 #endif
4498 
4499 template <>
4500 inline void interpolate_pixel_4(qrgb888 *dest, const qrgb888 *src,
4501  quint32 alpha)
4502 {
4503  Q_ASSERT((quintptr(dest) & 0x3) == 0);
4504  Q_ASSERT((quintptr(src) & 0x3) == 0);
4505 
4506  const quint32 a = eff_alpha_4(alpha, dest);
4507  const quint32 ia = eff_ialpha_4(alpha, dest);
4508  const quint32 *src32 = reinterpret_cast<const quint32*>(src);
4509  quint32 *dest32 = reinterpret_cast<quint32*>(dest);
4510 
4511  {
4512  quint32 x = src32[0];
4513  quint32 y = dest32[0];
4514 
4515  quint32 t;
4516  t = ((x >> 8) & 0xff00ff) * (a >> 24)
4517  + ((y >> 8) & 0xff00ff) * (ia >> 24);
4518  t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4519  t &= 0xff00ff00;
4520 
4521  x = (x & 0xff0000) * (a >> 24)
4522  + (x & 0x0000ff) * ((a >> 16) & 0xff)
4523  + (y & 0xff0000) * (ia >> 24)
4524  + (y & 0x0000ff) * ((ia >> 16) & 0xff);
4525  x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4526  x &= 0x00ff00ff;
4527 
4528  dest32[0] = x | t;
4529  }
4530  {
4531  quint32 x = src32[1];
4532  quint32 y = dest32[1];
4533 
4534  quint32 t;
4535  t = ((x >> 8) & 0xff0000) * ((a >> 16) & 0xff)
4536  + ((x >> 8) & 0x0000ff) * ((a >> 8) & 0xff)
4537  + ((y >> 8) & 0xff0000) * ((ia >> 16) & 0xff)
4538  + ((y >> 8) & 0x0000ff) * ((ia >> 8) & 0xff);
4539  t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4540  t &= 0xff00ff00;
4541 
4542  x = (x & 0xff0000) * ((a >> 16) & 0xff)
4543  + (x & 0x0000ff) * ((a >> 8) & 0xff)
4544  + (y & 0xff0000) * ((ia >> 16) & 0xff)
4545  + (y & 0x0000ff) * ((ia >> 8) & 0xff);
4546  x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4547  x &= 0x00ff00ff;
4548 
4549  dest32[1] = x | t;
4550  }
4551  {
4552  quint32 x = src32[2];
4553  quint32 y = dest32[2];
4554 
4555  quint32 t;
4556  t = ((x >> 8) & 0xff0000) * ((a >> 8) & 0xff)
4557  + ((x >> 8) & 0x0000ff) * (a & 0xff)
4558  + ((y >> 8) & 0xff0000) * ((ia >> 8) & 0xff)
4559  + ((y >> 8) & 0x0000ff) * (ia & 0xff);
4560  t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
4561  t &= 0xff00ff00;
4562 
4563  x = (x & 0xff00ff) * (a & 0xff)
4564  + (y & 0xff00ff) * (ia & 0xff);
4565  x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
4566  x &= 0x00ff00ff;
4567 
4568  dest32[2] = x | t;
4569  }
4570 }
4571 
4572 template <class DST, class SRC>
4573 inline void interpolate_pixel_4(DST *dest, quint8 a,
4574  const SRC *src, quint8 b)
4575 {
4576  Q_ASSERT((quintptr(dest) & 0x3) == 0);
4577  Q_ASSERT((quintptr(src) & 0x3) == 0);
4578 
4579  dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
4580  dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
4581  dest[2] = dest[2].byte_mul(a) + DST(src[2]).byte_mul(b);
4582  dest[3] = dest[3].byte_mul(a) + DST(src[3]).byte_mul(b);
4583 }
4584 
4585 template <class DST, class SRC>
4586 inline void blend_sourceOver_4(DST *dest, const SRC *src)
4587 {
4588  Q_ASSERT((quintptr(dest) & 0x3) == 0);
4589  Q_ASSERT((quintptr(src) & 0x3) == 0);
4590 
4591  const quint32 a = alpha_4(src);
4592  if (a == 0xffffffff) {
4593  qt_memconvert(dest, src, 4);
4594  } else if (a > 0) {
4595  quint32 buf[3]; // array of quint32 to get correct alignment
4596  qt_memconvert((DST*)(void*)buf, src, 4);
4597  madd_4(dest, eff_ialpha_4(a, dest), (DST*)(void*)buf);
4598  }
4599 }
4600 
4601 template <>
4602 inline void blend_sourceOver_4(qargb8565 *dest, const qargb8565 *src)
4603 {
4604  Q_ASSERT((quintptr(dest) & 0x3) == 0);
4605  Q_ASSERT((quintptr(src) & 0x3) == 0);
4606 
4607  const quint32 a = alpha_4(src);
4608  if (a == 0xffffffff) {
4609  qt_memconvert(dest, src, 4);
4610  } else if (a > 0) {
4611  madd_4(dest, eff_ialpha_4(a, dest), src);
4612  }
4613 }
4614 
4615 template <>
4616 inline void blend_sourceOver_4(qargb8555 *dest, const qargb8555 *src)
4617 {
4618  Q_ASSERT((quintptr(dest) & 0x3) == 0);
4619  Q_ASSERT((quintptr(src) & 0x3) == 0);
4620 
4621  const quint32 a = alpha_4(src);
4622  if (a == 0xffffffff) {
4623  qt_memconvert(dest, src, 4);
4624  } else if (a > 0) {
4625  madd_4(dest, eff_ialpha_4(a, dest), src);
4626  }
4627 }
4628 
4629 template <>
4630 inline void blend_sourceOver_4(qargb6666 *dest, const qargb6666 *src)
4631 {
4632  Q_ASSERT((quintptr(dest) & 0x3) == 0);
4633  Q_ASSERT((quintptr(src) & 0x3) == 0);
4634 
4635  const quint32 a = alpha_4(src);
4636  if (a == 0xffffffff) {
4637  qt_memconvert(dest, src, 4);
4638  } else if (a > 0) {
4639  madd_4(dest, eff_ialpha_4(a, dest), src);
4640  }
4641 }
4642 
4643 template <class DST, class SRC>
4644 void QT_FASTCALL blendUntransformed_unaligned(DST *dest, const SRC *src,
4645  quint8 coverage, int length)
4646 {
4647  Q_ASSERT(coverage > 0);
4648 
4649  if (coverage < 255) {
4650  if (SRC::hasAlpha()) {
4651  for (int i = 0; i < length; ++i) {
4652  if (src[i].alpha()) {
4653  const quint8 alpha = qt_div_255(int(src[i].alpha()) * int(coverage));
4654  interpolate_pixel(dest[i], DST::ialpha(alpha),
4655  src[i], DST::alpha(alpha));
4656  }
4657  }
4658  } else {
4659  const quint8 alpha = DST::alpha(coverage);
4660  const quint8 ialpha = DST::ialpha(coverage);
4661  if (alpha) {
4662  for (int i = 0; i < length; ++i)
4663  interpolate_pixel(dest[i], ialpha, src[i], alpha);
4664  }
4665  }
4666  return;
4667  }
4668 
4669  Q_ASSERT(coverage == 0xff);
4670  Q_ASSERT(SRC::hasAlpha());
4671 
4672  if (SRC::hasAlpha()) {
4673  for (int i = 0; i < length; ++i) {
4674  const quint8 a = src->alpha();
4675  if (a == 0xff)
4676  *dest = DST(*src);
4677  else if (a > 0) {
4678  if (DST::hasAlpha())
4679  *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4680  else
4681  *dest = DST(SRC(*src).truncedAlpha()) + dest->byte_mul(DST::ialpha(a));
4682  }
4683  ++src;
4684  ++dest;
4685  }
4686  }
4687 }
4688 
4689 template <class DST, class SRC>
4690 void QT_FASTCALL blendUntransformed_dest16(DST *dest, const SRC *src,
4691  quint8 coverage, int length)
4692 {
4693  Q_ASSERT(sizeof(DST) == 2);
4694  Q_ASSERT(sizeof(SRC) == 2);
4695  Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
4696  Q_ASSERT(coverage > 0);
4697 
4698  const int align = quintptr(dest) & 0x3;
4699 
4700  if (coverage < 255) {
4701  // align
4702  if (align) {
4703  const quint8 alpha = SRC::hasAlpha()
4704  ? qt_div_255(int(src->alpha()) * int(coverage))
4705  : coverage;
4706  if (alpha) {
4707  interpolate_pixel(*dest, DST::ialpha(alpha),
4708  *src, DST::alpha(alpha));
4709  }
4710  ++dest;
4711  ++src;
4712  --length;
4713  }
4714 
4715  if (SRC::hasAlpha()) {
4716  while (length >= 2) {
4717  const quint16 alpha16 = BYTE_MUL(uint(alpha_2(src)), uint(coverage));
4718  interpolate_pixel_2(dest, src, alpha16);
4719  length -= 2;
4720  src += 2;
4721  dest += 2;
4722  }
4723  } else {
4724  const quint8 alpha = DST::alpha(coverage);
4725  const quint8 ialpha = DST::ialpha(coverage);
4726 
4727  while (length >= 2) {
4728  interpolate_pixel_2(dest, ialpha, src, alpha);
4729  length -= 2;
4730  src += 2;
4731  dest += 2;
4732  }
4733  }
4734 
4735  // tail
4736  if (length) {
4737  const quint8 alpha = SRC::hasAlpha()
4738  ? qt_div_255(int(src->alpha()) * int(coverage))
4739  : coverage;
4740  if (alpha) {
4741  interpolate_pixel(*dest, DST::ialpha(alpha),
4742  *src, DST::alpha(alpha));
4743  }
4744  }
4745 
4746  return;
4747  }
4748 
4749  Q_ASSERT(SRC::hasAlpha());
4750  if (SRC::hasAlpha()) {
4751  if (align) {
4752  const quint8 alpha = src->alpha();
4753  if (alpha == 0xff)
4754  *dest = DST(*src);
4755  else if (alpha > 0)
4756  *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
4757  ++dest;
4758  ++src;
4759  --length;
4760  }
4761 
4762  while (length >= 2) {
4763  Q_ASSERT((quintptr(dest) & 3) == 0);
4764  Q_ASSERT((quintptr(src) & 3) == 0);
4765 
4766  const quint16 a = alpha_2(src);
4767  if (a == 0xffff) {
4768  qt_memconvert(dest, src, 2);
4769  } else if (a > 0) {
4770  quint32 buf;
4771  if (sizeof(DST) == 2)
4772  qt_memconvert((DST*)(void*)&buf, src, 2);
4773  madd_2(dest, eff_ialpha_2(a, dest), (DST*)(void*)&buf);
4774  }
4775 
4776  length -= 2;
4777  src += 2;
4778  dest += 2;
4779  }
4780 
4781  if (length) {
4782  const quint8 alpha = src->alpha();
4783  if (alpha == 0xff)
4784  *dest = DST(*src);
4785  else if (alpha > 0)
4786  *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
4787  }
4788  }
4789 }
4790 
4791 template <class DST, class SRC>
4792 void QT_FASTCALL blendUntransformed_dest24(DST *dest, const SRC *src,
4793  quint8 coverage, int length)
4794 {
4795  Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
4796  Q_ASSERT(sizeof(DST) == 3);
4797  Q_ASSERT(coverage > 0);
4798 
4799  const int align = quintptr(dest) & 0x3;
4800 
4801  if (coverage < 255) {
4802  // align
4803  for (int i = 0; i < align; ++i) {
4804  if (SRC::hasAlpha()) {
4805  const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
4806  if (alpha)
4807  interpolate_pixel(*dest, DST::ialpha(alpha),
4808  *src, DST::alpha(alpha));
4809  } else {
4810  interpolate_pixel(*dest, DST::ialpha(coverage),
4811  *src, DST::alpha(coverage));
4812  }
4813  ++dest;
4814  ++src;
4815  --length;
4816  }
4817 
4818  if (SRC::hasAlpha()) {
4819  while (length >= 4) {
4820  const quint32 alpha = QT_PREPEND_NAMESPACE(BYTE_MUL)(uint(alpha_4(src)), uint(coverage));
4821  if (alpha)
4822  interpolate_pixel_4(dest, src, alpha);
4823  length -= 4;
4824  src += 4;
4825  dest += 4;
4826  }
4827  } else {
4828  const quint8 alpha = DST::alpha(coverage);
4829  const quint8 ialpha = DST::ialpha(coverage);
4830  while (length >= 4) {
4831  interpolate_pixel_4(dest, ialpha, src, alpha);
4832  length -= 4;
4833  src += 4;
4834  dest += 4;
4835  }
4836  }
4837 
4838  // tail
4839  while (length--) {
4840  if (SRC::hasAlpha()) {
4841  const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
4842  if (alpha)
4843  interpolate_pixel(*dest, DST::ialpha(alpha),
4844  *src, DST::alpha(alpha));
4845  } else {
4846  interpolate_pixel(*dest, DST::ialpha(coverage),
4847  *src, DST::alpha(coverage));
4848  }
4849  ++dest;
4850  ++src;
4851  }
4852 
4853  return;
4854  }
4855 
4856 
4857  Q_ASSERT(coverage == 255);
4858  Q_ASSERT(SRC::hasAlpha());
4859 
4860  if (SRC::hasAlpha()) {
4861  // align
4862  for (int i = 0; i < align; ++i) {
4863  const quint8 a = src->alpha();
4864  if (a == 0xff) {
4865  *dest = DST(*src);
4866  } else if (a > 0) {
4867  *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4868  }
4869  ++dest;
4870  ++src;
4871  --length;
4872  }
4873 
4874  while (length >= 4) {
4875  blend_sourceOver_4(dest, src);
4876  length -= 4;
4877  src += 4;
4878  dest += 4;
4879  }
4880 
4881  // tail
4882  while (length--) {
4883  const quint8 a = src->alpha();
4884  if (a == 0xff) {
4885  *dest = DST(*src);
4886  } else if (a > 0) {
4887  *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
4888  }
4889  ++dest;
4890  ++src;
4891  }
4892  }
4893 }
4894 
4895 template <class DST, class SRC>
4897 void QT_FASTCALL blendUntransformed(int count, const QSpan *spans, void *userData)
4898 {
4899  QSpanData *data = reinterpret_cast<QSpanData*>(userData);
4901 
4904  {
4905  blend_src_generic<RegularSpans>(count, spans, userData);
4906  return;
4907  }
4908 
4909  const bool modeSource = !SRC::hasAlpha() ||
4911  const int image_width = data->texture.width;
4912  const int image_height = data->texture.height;
4913  int xoff = -qRound(-data->dx);
4914  int yoff = -qRound(-data->dy);
4915 
4916  while (count--) {
4917  const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
4918  if (coverage == 0) {
4919  ++spans;
4920  continue;
4921  }
4922 
4923  int x = spans->x;
4924  int length = spans->len;
4925  int sx = xoff + x;
4926  int sy = yoff + spans->y;
4927  if (sy >= 0 && sy < image_height && sx < image_width) {
4928  if (sx < 0) {
4929  x -= sx;
4930  length += sx;
4931  sx = 0;
4932  }
4933  if (sx + length > image_width)
4934  length = image_width - sx;
4935  if (length > 0) {
4936  DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
4937  const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
4938  if (modeSource && coverage == 255) {
4939  qt_memconvert<DST, SRC>(dest, src, length);
4940  } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && length >= 3 &&
4941  (quintptr(dest) & 3) == (quintptr(src) & 3))
4942  {
4943  blendUntransformed_dest24(dest, src, coverage, length);
4944  } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && length >= 3 &&
4945  (quintptr(dest) & 3) == (quintptr(src) & 3))
4946  {
4947  blendUntransformed_dest16(dest, src, coverage, length);
4948  } else {
4949  blendUntransformed_unaligned(dest, src, coverage, length);
4950  }
4951  }
4952  }
4953  ++spans;
4954  }
4955 }
4956 
4957 static void blend_untransformed_rgb888(int count, const QSpan *spans,
4958  void *userData)
4959 {
4960 #if defined(QT_QWS_DEPTH_24)
4961  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4962 
4963  if (data->texture.format == QImage::Format_RGB888)
4964  blendUntransformed<qrgb888, qrgb888>(count, spans, userData);
4965  else
4966 #endif
4967  blend_untransformed_generic<RegularSpans>(count, spans, userData);
4968 }
4969 
4970 static void blend_untransformed_argb6666(int count, const QSpan *spans,
4971  void *userData)
4972 {
4973 #if defined(QT_QWS_DEPTH_18)
4974  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4975 
4977  blendUntransformed<qargb6666, qargb6666>(count, spans, userData);
4978  else if (data->texture.format == QImage::Format_RGB666)
4979  blendUntransformed<qargb6666, qrgb666>(count, spans, userData);
4980  else
4981 #endif
4982  blend_untransformed_generic<RegularSpans>(count, spans, userData);
4983 }
4984 
4985 static void blend_untransformed_rgb666(int count, const QSpan *spans,
4986  void *userData)
4987 {
4988 #if defined(QT_QWS_DEPTH_18)
4989  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
4990 
4992  blendUntransformed<qrgb666, qargb6666>(count, spans, userData);
4993  else if (data->texture.format == QImage::Format_RGB666)
4994  blendUntransformed<qrgb666, qrgb666>(count, spans, userData);
4995  else
4996 #endif
4997  blend_untransformed_generic<RegularSpans>(count, spans, userData);
4998 }
4999 
5000 static void blend_untransformed_argb8565(int count, const QSpan *spans,
5001  void *userData)
5002 {
5003 #if defined(QT_QWS_DEPTH_16)
5004  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5005 
5007  blendUntransformed<qargb8565, qargb8565>(count, spans, userData);
5008  else if (data->texture.format == QImage::Format_RGB16)
5009  blendUntransformed<qargb8565, qrgb565>(count, spans, userData);
5010  else
5011 #endif
5012  blend_untransformed_generic<RegularSpans>(count, spans, userData);
5013 }
5014 
5015 static void blend_untransformed_rgb565(int count, const QSpan *spans,
5016  void *userData)
5017 {
5018 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
5019  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5020 
5022  blendUntransformed<qrgb565, qargb8565>(count, spans, userData);
5023  else if (data->texture.format == QImage::Format_RGB16)
5024  blendUntransformed<qrgb565, qrgb565>(count, spans, userData);
5025  else
5026 #endif
5027  blend_untransformed_generic<RegularSpans>(count, spans, userData);
5028 }
5029 
5030 static void blend_untransformed_argb8555(int count, const QSpan *spans,
5031  void *userData)
5032 {
5033 #if defined(QT_QWS_DEPTH_15)
5034  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5035 
5037  blendUntransformed<qargb8555, qargb8555>(count, spans, userData);
5038  else if (data->texture.format == QImage::Format_RGB555)
5039  blendUntransformed<qargb8555, qrgb555>(count, spans, userData);
5040  else
5041 #endif
5042  blend_untransformed_generic<RegularSpans>(count, spans, userData);
5043 }
5044 
5045 static void blend_untransformed_rgb555(int count, const QSpan *spans,
5046  void *userData)
5047 {
5048 #if defined(QT_QWS_DEPTH_15)
5049  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5050 
5052  blendUntransformed<qrgb555, qargb8555>(count, spans, userData);
5053  else if (data->texture.format == QImage::Format_RGB555)
5054  blendUntransformed<qrgb555, qrgb555>(count, spans, userData);
5055  else
5056 #endif
5057  blend_untransformed_generic<RegularSpans>(count, spans, userData);
5058 }
5059 
5060 static void blend_untransformed_argb4444(int count, const QSpan *spans,
5061  void *userData)
5062 {
5063 #if defined(QT_QWS_DEPTH_12)
5064  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5065 
5067  blendUntransformed<qargb4444, qargb4444>(count, spans, userData);
5068  else if (data->texture.format == QImage::Format_RGB444)
5069  blendUntransformed<qargb4444, qrgb444>(count, spans, userData);
5070  else
5071 #endif
5072  blend_untransformed_generic<RegularSpans>(count, spans, userData);
5073 }
5074 
5075 static void blend_untransformed_rgb444(int count, const QSpan *spans,
5076  void *userData)
5077 {
5078 #if defined(QT_QWS_DEPTH_12)
5079  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5080 
5082  blendUntransformed<qrgb444, qargb4444>(count, spans, userData);
5083  else if (data->texture.format == QImage::Format_RGB444)
5084  blendUntransformed<qrgb444, qrgb444>(count, spans, userData);
5085  else
5086 #endif
5087  blend_untransformed_generic<RegularSpans>(count, spans, userData);
5088 }
5089 
5090 template <SpanMethod spanMethod>
5091 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_generic(int count, const QSpan *spans, void *userData)
5092 {
5093  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5094 
5095  uint buffer[buffer_size];
5096  uint src_buffer[buffer_size];
5097  Operator op = getOperator(data, spans, count);
5098 
5099  const int image_width = data->texture.width;
5100  const int image_height = data->texture.height;
5101  int xoff = -qRound(-data->dx) % image_width;
5102  int yoff = -qRound(-data->dy) % image_height;
5103 
5104  if (xoff < 0)
5105  xoff += image_width;
5106  if (yoff < 0)
5107  yoff += image_height;
5108 
5109  while (count--) {
5110  int x = spans->x;
5111  int length = spans->len;
5112  int sx = (xoff + spans->x) % image_width;
5113  int sy = (spans->y + yoff) % image_height;
5114  if (sx < 0)
5115  sx += image_width;
5116  if (sy < 0)
5117  sy += image_height;
5118 
5119  const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5120  while (length) {
5121  int l = qMin(image_width - sx, length);
5122  if (buffer_size < l)
5123  l = buffer_size;
5124  const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
5125  if (spanMethod == RegularSpans) {
5126  uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
5127  op.func(dest, src, l, coverage);
5128  if (op.dest_store)
5129  op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
5130  } else {
5131  drawBufferSpan(data, src, l, x, spans->y, l,
5132  coverage);
5133  }
5134  x += l;
5135  sx += l;
5136  length -= l;
5137  if (sx >= image_width)
5138  sx = 0;
5139  }
5140  ++spans;
5141  }
5142 }
5143 
5144 template <SpanMethod spanMethod>
5145 Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_argb(int count, const QSpan *spans, void *userData)
5146 {
5147  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5149  && data->texture.format != QImage::Format_RGB32) {
5150  blend_tiled_generic<spanMethod>(count, spans, userData);
5151  return;
5152  }
5153 
5154  Operator op = getOperator(data, spans, count);
5155 
5156  int image_width = data->texture.width;
5157  int image_height = data->texture.height;
5158  int xoff = -qRound(-data->dx) % image_width;
5159  int yoff = -qRound(-data->dy) % image_height;
5160 
5161  if (xoff < 0)
5162  xoff += image_width;
5163  if (yoff < 0)
5164  yoff += image_height;
5165 
5166  while (count--) {
5167  int x = spans->x;
5168  int length = spans->len;
5169  int sx = (xoff + spans->x) % image_width;
5170  int sy = (spans->y + yoff) % image_height;
5171  if (sx < 0)
5172  sx += image_width;
5173  if (sy < 0)
5174  sy += image_height;
5175 
5176  const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5177  while (length) {
5178  int l = qMin(image_width - sx, length);
5179  if (buffer_size < l)
5180  l = buffer_size;
5181  const uint *src = (uint *)data->texture.scanLine(sy) + sx;
5182  if (spanMethod == RegularSpans) {
5183  uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
5184  op.func(dest, src, l, coverage);
5185  } else {
5186  drawBufferSpan(data, src, buffer_size,
5187  x, spans->y, l, coverage);
5188  }
5189  x += l;
5190  length -= l;
5191  sx = 0;
5192  }
5193  ++spans;
5194  }
5195 }
5196 
5197 template <class DST, class SRC>
5198 Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *userData)
5199 {
5200  QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5202 
5205  {
5206  blend_src_generic<RegularSpans>(count, spans, userData);
5207  return;
5208  }
5209 
5210  const bool modeSource = !SRC::hasAlpha() ||
5212  const int image_width = data->texture.width;
5213  const int image_height = data->texture.height;
5214  int xoff = -qRound(-data->dx) % image_width;
5215  int yoff = -qRound(-data->dy) % image_height;
5216 
5217  if (xoff < 0)
5218  xoff += image_width;
5219  if (yoff < 0)
5220  yoff += image_height;
5221 
5222  while (count--) {
5223  const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5224  if (coverage == 0) {
5225  ++spans;
5226  continue;
5227  }
5228 
5229  int x = spans->x;
5230  int length = spans->len;
5231  int sx = (xoff + spans->x) % image_width;
5232  int sy = (spans->y + yoff) % image_height;
5233  if (sx < 0)
5234  sx += image_width;
5235  if (sy < 0)
5236  sy += image_height;
5237 
5238  if (modeSource && coverage == 255) {
5239  // Copy the first texture block
5240  length = qMin(image_width,length);
5241  int tx = x;
5242  while (length) {
5243  int l = qMin(image_width - sx, length);
5244  if (buffer_size < l)
5245  l = buffer_size;
5246  DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + tx;
5247  const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5248 
5249  qt_memconvert<DST, SRC>(dest, src, l);
5250  length -= l;
5251  tx += l;
5252  sx = 0;
5253  }
5254 
5255  // Now use the rasterBuffer as the source of the texture,
5256  // We can now progressively copy larger blocks
5257  // - Less cpu time in code figuring out what to copy
5258  // We are dealing with one block of data
5259  // - More likely to fit in the cache
5260  // - can use memcpy
5261  int copy_image_width = qMin(image_width, int(spans->len));
5262  length = spans->len - copy_image_width;
5263  DST *src = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5264  DST *dest = src + copy_image_width;
5265  while (copy_image_width < length) {
5266  qt_memconvert(dest, src, copy_image_width);
5267  dest += copy_image_width;
5268  length -= copy_image_width;
5269  copy_image_width *= 2;
5270  }
5271  if (length > 0)
5272  qt_memconvert(dest, src, length);
5273  } else {
5274  while (length) {
5275  int l = qMin(image_width - sx, length);
5276  if (buffer_size < l)
5277  l = buffer_size;
5278  DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
5279  const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
5280  if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5281  (quintptr(dest) & 3) == (quintptr(src) & 3))
5282  {
5283  blendUntransformed_dest24(dest, src, coverage, l);
5284  } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5285  (quintptr(dest) & 3) == (quintptr(src) & 3))
5286  {
5287  blendUntransformed_dest16(dest, src, coverage, l);
5288  } else {
5289  blendUntransformed_unaligned(dest, src, coverage, l);
5290  }
5291 
5292  x += l;
5293  length -= l;
5294  sx = 0;
5295  }
5296  }
5297  ++spans;
5298  }
5299 }
5300 
5301 static void blend_tiled_rgb888(int count, const QSpan *spans, void *userData)
5302 {
5303 #if defined(QT_QWS_DEPTH_24)
5304  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5305 
5306  if (data->texture.format == QImage::Format_RGB888)
5307  blendTiled<qrgb888, qrgb888>(count, spans, userData);
5308  else
5309 #endif
5310  blend_tiled_generic<RegularSpans>(count, spans, userData);
5311 }
5312 
5313 static void blend_tiled_argb6666(int count, const QSpan *spans, void *userData)
5314 {
5315 #if defined(QT_QWS_DEPTH_18)
5316  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5317 
5319  blendTiled<qargb6666, qargb6666>(count, spans, userData);
5320  else if (data->texture.format == QImage::Format_RGB666)
5321  blendTiled<qargb6666, qrgb666>(count, spans, userData);
5322  else
5323 #endif
5324  blend_tiled_generic<RegularSpans>(count, spans, userData);
5325 }
5326 
5327 static void blend_tiled_rgb666(int count, const QSpan *spans, void *userData)
5328 {
5329 #if defined(QT_QWS_DEPTH_18)
5330  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5331 
5333  blendTiled<qrgb666, qargb6666>(count, spans, userData);
5334  else if (data->texture.format == QImage::Format_RGB666)
5335  blendTiled<qrgb666, qrgb666>(count, spans, userData);
5336  else
5337 #endif
5338  blend_tiled_generic<RegularSpans>(count, spans, userData);
5339 }
5340 
5341 static void blend_tiled_argb8565(int count, const QSpan *spans, void *userData)
5342 {
5343 #if defined(QT_QWS_DEPTH_16)
5344  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5345 
5347  blendTiled<qargb8565, qargb8565>(count, spans, userData);
5348  else if (data->texture.format == QImage::Format_RGB16)
5349  blendTiled<qargb8565, qrgb565>(count, spans, userData);
5350  else
5351 #endif
5352  blend_tiled_generic<RegularSpans>(count, spans, userData);
5353 }
5354 
5355 static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
5356 {
5357 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
5358  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5359 
5361  blendTiled<qrgb565, qargb8565>(count, spans, userData);
5362  else if (data->texture.format == QImage::Format_RGB16)
5363  blendTiled<qrgb565, qrgb565>(count, spans, userData);
5364  else
5365 #endif
5366  blend_tiled_generic<RegularSpans>(count, spans, userData);
5367 }
5368 
5369 static void blend_tiled_argb8555(int count, const QSpan *spans, void *userData)
5370 {
5371 #if defined(QT_QWS_DEPTH_15)
5372  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5373 
5375  blendTiled<qargb8555, qargb8555>(count, spans, userData);
5376  else if (data->texture.format == QImage::Format_RGB555)
5377  blendTiled<qargb8555, qrgb555>(count, spans, userData);
5378  else
5379 #endif
5380  blend_tiled_generic<RegularSpans>(count, spans, userData);
5381 }
5382 
5383 static void blend_tiled_rgb555(int count, const QSpan *spans, void *userData)
5384 {
5385 #if defined(QT_QWS_DEPTH_15)
5386  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5387 
5389  blendTiled<qrgb555, qargb8555>(count, spans, userData);
5390  else if (data->texture.format == QImage::Format_RGB555)
5391  blendTiled<qrgb555, qrgb555>(count, spans, userData);
5392  else
5393 #endif
5394  blend_tiled_generic<RegularSpans>(count, spans, userData);
5395 }
5396 
5397 static void blend_tiled_argb4444(int count, const QSpan *spans, void *userData)
5398 {
5399 #if defined(QT_QWS_DEPTH_12)
5400  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5401 
5403  blendTiled<qargb4444, qargb4444>(count, spans, userData);
5404  else if (data->texture.format == QImage::Format_RGB444)
5405  blendTiled<qargb4444, qrgb444>(count, spans, userData);
5406  else
5407 #endif
5408  blend_tiled_generic<RegularSpans>(count, spans, userData);
5409 }
5410 
5411 static void blend_tiled_rgb444(int count, const QSpan *spans, void *userData)
5412 {
5413 #if defined(QT_QWS_DEPTH_12)
5414  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5415 
5417  blendTiled<qrgb444, qargb4444>(count, spans, userData);
5418  else if (data->texture.format == QImage::Format_RGB444)
5419  blendTiled<qrgb444, qrgb444>(count, spans, userData);
5420  else
5421 #endif
5422  blend_tiled_generic<RegularSpans>(count, spans, userData);
5423 }
5424 
5425 template <class DST, class SRC>
5427  void *userData)
5428 {
5429  QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5431 
5432 
5434  blend_src_generic<RegularSpans>(count, spans, userData);
5435  return;
5436  }
5437 
5438  SRC buffer[buffer_size];
5439 
5440  const int src_minx = data->texture.x1;
5441  const int src_miny = data->texture.y1;
5442  const int src_maxx = data->texture.x2 - 1;
5443  const int src_maxy = data->texture.y2 - 1;
5444 
5445  if (data->fast_matrix) {
5446  // The increment pr x in the scanline
5447  const int fdx = (int)(data->m11 * fixed_scale);
5448  const int fdy = (int)(data->m12 * fixed_scale);
5449 
5450  while (count--) {
5451  const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5452  if (coverage == 0) {
5453  ++spans;
5454  continue;
5455  }
5456 
5457  DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5458  + spans->x;
5459  const qreal cx = spans->x + qreal(0.5);
5460  const qreal cy = spans->y + qreal(0.5);
5461  int x = int((data->m21 * cy
5462  + data->m11 * cx + data->dx) * fixed_scale) - half_point;
5463  int y = int((data->m22 * cy
5464  + data->m12 * cx + data->dy) * fixed_scale) - half_point;
5465  int length = spans->len;
5466 
5467  while (length) {
5468  const int l = qMin(length, buffer_size);
5469 
5470  const SRC *end = buffer + l;
5471  SRC *b = buffer;
5472  while (b < end) {
5473  int x1 = (x >> 16);
5474  int x2;
5475  int y1 = (y >> 16);
5476  int y2;
5477 
5478  const int distx = (x & 0x0000ffff) >> 8;
5479  const int disty = (y & 0x0000ffff) >> 8;
5480 
5481  if (x1 < src_minx) {
5482  x2 = x1 = src_minx;
5483  } else if (x1 >= src_maxx) {
5484  x2 = x1 = src_maxx;
5485  } else {
5486  x2 = x1 + 1;
5487  }
5488  if (y1 < src_miny) {
5489  y2 = y1 = src_miny;
5490  } else if (y1 >= src_maxy) {
5491  y2 = y1 = src_maxy;
5492  } else {
5493  y2 = y1 + 1;
5494  }
5495 #if 0
5496  if (x1 == x2) {
5497  if (y1 == y2) {
5498  *b = ((SRC*)data->texture.scanLine(y1))[x1];
5499  } else {
5500  *b = ((SRC*)data->texture.scanLine(y1))[x1];
5501  const SRC t = data->texture.scanLine(y2)[x1];
5502  interpolate_pixel(*b, SRC::ialpha(disty),
5503  t, SRC::alpha(disty));
5504  }
5505  } else if (y1 == y2) {
5506  *b = ((SRC*)data->texture.scanLine(y1))[x1];
5507  const SRC t = ((SRC*)data->texture.scanLine(y1))[x2];
5508  interpolate_pixel(*b, SRC::ialpha(distx),
5509  t, SRC::alpha(distx));
5510  } else
5511 #endif
5512  {
5513  const SRC *src1 = (SRC*)data->texture.scanLine(y1);
5514  const SRC *src2 = (SRC*)data->texture.scanLine(y2);
5515  SRC tl = src1[x1];
5516  const SRC tr = src1[x2];
5517  SRC bl = src2[x1];
5518  const SRC br = src2[x2];
5519  const quint8 ax = SRC::alpha(distx);
5520  const quint8 iax = SRC::ialpha(distx);
5521 
5522  interpolate_pixel(tl, iax, tr, ax);
5523  interpolate_pixel(bl, iax, br, ax);
5524  interpolate_pixel(tl, SRC::ialpha(disty),
5525  bl, SRC::alpha(disty));
5526  *b = tl;
5527  }
5528  ++b;
5529 
5530  x += fdx;
5531  y += fdy;
5532  }
5533 
5534  if (!SRC::hasAlpha() && coverage == 255) {
5535  qt_memconvert(dest, buffer, l);
5536  } else if (sizeof(DST) == 3 && l >= 4 &&
5537  (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5538  {
5539  blendUntransformed_dest24(dest, buffer, coverage, l);
5540  } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5541  (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5542  blendUntransformed_dest16(dest, buffer, coverage, l);
5543  } else {
5544  blendUntransformed_unaligned(dest, buffer, coverage, l);
5545  }
5546 
5547  dest += l;
5548  length -= l;
5549  }
5550  ++spans;
5551  }
5552  } else {
5553  const qreal fdx = data->m11;
5554  const qreal fdy = data->m12;
5555  const qreal fdw = data->m13;
5556 
5557  while (count--) {
5558  const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5559  if (coverage == 0) {
5560  ++spans;
5561  continue;
5562  }
5563 
5564  DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5565  + spans->x;
5566 
5567  const qreal cx = spans->x + qreal(0.5);
5568  const qreal cy = spans->y + qreal(0.5);
5569 
5570  qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5571  qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5572  qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5573 
5574  int length = spans->len;
5575  while (length) {
5576  const int l = qMin(length, buffer_size);
5577  const SRC *end = buffer + l;
5578  SRC *b = buffer;
5579  while (b < end) {
5580  const qreal iw = w == 0 ? 1 : 1 / w;
5581  const qreal px = x * iw - qreal(0.5);
5582  const qreal py = y * iw - qreal(0.5);
5583 
5584  int x1 = int(px) - (px < 0);
5585  int x2;
5586  int y1 = int(py) - (py < 0);
5587  int y2;
5588 
5589  const int distx = int((px - x1) * 256);
5590  const int disty = int((py - y1) * 256);
5591 
5592  if (x1 < src_minx) {
5593  x2 = x1 = src_minx;
5594  } else if (x1 >= src_maxx) {
5595  x2 = x1 = src_maxx;
5596  } else {
5597  x2 = x1 + 1;
5598  }
5599  if (y1 < src_miny) {
5600  y2 = y1 = src_miny;
5601  } else if (y1 >= src_maxy) {
5602  y2 = y1 = src_maxy;
5603  } else {
5604  y2 = y1 + 1;
5605  }
5606 
5607  const SRC *src1 = (SRC*)data->texture.scanLine(y1);
5608  const SRC *src2 = (SRC*)data->texture.scanLine(y2);
5609  SRC tl = src1[x1];
5610  const SRC tr = src1[x2];
5611  SRC bl = src2[x1];
5612  const SRC br = src2[x2];
5613  const quint8 ax = SRC::alpha(distx);
5614  const quint8 iax = SRC::ialpha(distx);
5615 
5616  interpolate_pixel(tl, iax, tr, ax);
5617  interpolate_pixel(bl, iax, br, ax);
5618  interpolate_pixel(tl, SRC::ialpha(disty),
5619  bl, SRC::alpha(disty));
5620  *b = tl;
5621  ++b;
5622 
5623  x += fdx;
5624  y += fdy;
5625  w += fdw;
5626  }
5627  if (!SRC::hasAlpha() && coverage == 255) {
5628  qt_memconvert(dest, buffer, l);
5629  } else if (sizeof(DST) == 3 && l >= 4 &&
5630  (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5631  {
5632  blendUntransformed_dest24(dest, buffer, coverage, l);
5633  } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5634  (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5635  blendUntransformed_dest16(dest, buffer, coverage, l);
5636  } else {
5637  blendUntransformed_unaligned(dest, buffer, coverage, l);
5638  }
5639 
5640  dest += l;
5641  length -= l;
5642  }
5643  ++spans;
5644  }
5645  }
5646 }
5647 
5648 static void blend_transformed_bilinear_rgb888(int count, const QSpan *spans, void *userData)
5649 {
5650 #if defined(QT_QWS_DEPTH_24)
5651  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5652 
5653  if (data->texture.format == QImage::Format_RGB888)
5654  blendTransformedBilinear<qrgb888, qrgb888>(count, spans, userData);
5655  else
5656 #endif
5657  blend_src_generic<RegularSpans>(count, spans, userData);
5658 }
5659 
5660 static void blend_transformed_bilinear_argb6666(int count, const QSpan *spans, void *userData)
5661 {
5662 #if defined(QT_QWS_DEPTH_18)
5663  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5664 
5666  blendTransformedBilinear<qargb6666, qargb6666>(count, spans, userData);
5667  else if (data->texture.format == QImage::Format_RGB666)
5668  blendTransformedBilinear<qargb6666, qrgb666>(count, spans, userData);
5669  else
5670 #endif
5671  blend_src_generic<RegularSpans>(count, spans, userData);
5672 }
5673 
5674 static void blend_transformed_bilinear_rgb666(int count, const QSpan *spans, void *userData)
5675 {
5676 #if defined(QT_QWS_DEPTH_18)
5677  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5678 
5680  blendTransformedBilinear<qrgb666, qargb6666>(count, spans, userData);
5681  else if (data->texture.format == QImage::Format_RGB666)
5682  blendTransformedBilinear<qrgb666, qrgb666>(count, spans, userData);
5683  else
5684 #endif
5685  blend_src_generic<RegularSpans>(count, spans, userData);
5686 }
5687 
5688 static void blend_transformed_bilinear_argb8565(int count, const QSpan *spans, void *userData)
5689 {
5690 #if defined(QT_QWS_DEPTH_16)
5691  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5692 
5694  blendTransformedBilinear<qargb8565, qargb8565>(count, spans, userData);
5695  else if (data->texture.format == QImage::Format_RGB16)
5696  blendTransformedBilinear<qargb8565, qrgb565>(count, spans, userData);
5697  else
5698 #endif
5699  blend_src_generic<RegularSpans>(count, spans, userData);
5700 }
5701 
5702 static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans,
5703  void *userData)
5704 {
5705 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
5706  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5707 
5708  if (data->texture.format == QImage::Format_RGB16)
5709  blendTransformedBilinear<qrgb565, qrgb565>(count, spans, userData);
5711  blendTransformedBilinear<qrgb565, qargb8565>(count, spans, userData);
5712  else
5713 #endif
5714  blend_src_generic<RegularSpans>(count, spans, userData);
5715 }
5716 
5717 static void blend_transformed_bilinear_argb8555(int count, const QSpan *spans, void *userData)
5718 {
5719 #if defined(QT_QWS_DEPTH_15)
5720  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5721 
5723  blendTransformedBilinear<qargb8555, qargb8555>(count, spans, userData);
5724  else if (data->texture.format == QImage::Format_RGB555)
5725  blendTransformedBilinear<qargb8555, qrgb555>(count, spans, userData);
5726  else
5727 #endif
5728  blend_src_generic<RegularSpans>(count, spans, userData);
5729 }
5730 
5731 static void blend_transformed_bilinear_rgb555(int count, const QSpan *spans, void *userData)
5732 {
5733 #if defined(QT_QWS_DEPTH_15)
5734  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5735 
5737  blendTransformedBilinear<qrgb555, qargb8555>(count, spans, userData);
5738  else if (data->texture.format == QImage::Format_RGB555)
5739  blendTransformedBilinear<qrgb555, qrgb555>(count, spans, userData);
5740  else
5741 #endif
5742  blend_src_generic<RegularSpans>(count, spans, userData);
5743 }
5744 
5745 static void blend_transformed_bilinear_argb4444(int count, const QSpan *spans, void *userData)
5746 {
5747 #if defined(QT_QWS_DEPTH_12)
5748  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5749 
5751  blendTransformedBilinear<qargb4444, qargb4444>(count, spans, userData);
5752  else if (data->texture.format == QImage::Format_RGB444)
5753  blendTransformedBilinear<qargb4444, qrgb444>(count, spans, userData);
5754  else
5755 #endif
5756  blend_src_generic<RegularSpans>(count, spans, userData);
5757 }
5758 
5759 static void blend_transformed_bilinear_rgb444(int count, const QSpan *spans, void *userData)
5760 {
5761 #if defined(QT_QWS_DEPTH_12)
5762  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5763 
5765  blendTransformedBilinear<qrgb444, qargb4444>(count, spans, userData);
5766  else if (data->texture.format == QImage::Format_RGB444)
5767  blendTransformedBilinear<qrgb444, qrgb444>(count, spans, userData);
5768  else
5769 #endif
5770  blend_src_generic<RegularSpans>(count, spans, userData);
5771 }
5772 
5773 template <SpanMethod spanMethod>
5774 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *spans, void *userData)
5775 {
5776  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
5778  && data->texture.format != QImage::Format_RGB32) {
5779  blend_src_generic<spanMethod>(count, spans, userData);
5780  return;
5781  }
5782 
5783  CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
5784  uint buffer[buffer_size];
5785 
5786  int image_width = data->texture.width;
5787  int image_height = data->texture.height;
5788  const int scanline_offset = data->texture.bytesPerLine / 4;
5789 
5790  if (data->fast_matrix) {
5791  // The increment pr x in the scanline
5792  int fdx = (int)(data->m11 * fixed_scale);
5793  int fdy = (int)(data->m12 * fixed_scale);
5794 
5795  while (count--) {
5796  void *t = data->rasterBuffer->scanLine(spans->y);
5797 
5798  uint *target = ((uint *)t) + spans->x;
5799  uint *image_bits = (uint *)data->texture.imageData;
5800 
5801  const qreal cx = spans->x + qreal(0.5);
5802  const qreal cy = spans->y + qreal(0.5);
5803 
5804  int x = int((data->m21 * cy
5805  + data->m11 * cx + data->dx) * fixed_scale);
5806  int y = int((data->m22 * cy
5807  + data->m12 * cx + data->dy) * fixed_scale);
5808 
5809  int length = spans->len;
5810  const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5811  while (length) {
5812  int l = qMin(length, buffer_size);
5813  const uint *end = buffer + l;
5814  uint *b = buffer;
5815  while (b < end) {
5816  int px = x >> 16;
5817  int py = y >> 16;
5818 
5819  bool out = (px < 0) || (px >= image_width)
5820  || (py < 0) || (py >= image_height);
5821 
5822  int y_offset = py * scanline_offset;
5823  *b = out ? uint(0) : image_bits[y_offset + px];
5824  x += fdx;
5825  y += fdy;
5826  ++b;
5827  }
5828  if (spanMethod == RegularSpans)
5829  func(target, buffer, l, coverage);
5830  else
5831  drawBufferSpan(data, buffer, buffer_size,
5832  spans->x + spans->len - length,
5833  spans->y, l, coverage);
5834  target += l;
5835  length -= l;
5836  }
5837  ++spans;
5838  }
5839  } else {
5840  const qreal fdx = data->m11;
5841  const qreal fdy = data->m12;
5842  const qreal fdw = data->m13;
5843  while (count--) {
5844  void *t = data->rasterBuffer->scanLine(spans->y);
5845 
5846  uint *target = ((uint *)t) + spans->x;
5847  uint *image_bits = (uint *)data->texture.imageData;
5848 
5849  const qreal cx = spans->x + qreal(0.5);
5850  const qreal cy = spans->y + qreal(0.5);
5851 
5852  qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5853  qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5854  qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5855 
5856  int length = spans->len;
5857  const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
5858  while (length) {
5859  int l = qMin(length, buffer_size);
5860  const uint *end = buffer + l;
5861  uint *b = buffer;
5862  while (b < end) {
5863  const qreal iw = w == 0 ? 1 : 1 / w;
5864  const qreal tx = x * iw;
5865  const qreal ty = y * iw;
5866  const int px = int(tx) - (tx < 0);
5867  const int py = int(ty) - (ty < 0);
5868 
5869  bool out = (px < 0) || (px >= image_width)
5870  || (py < 0) || (py >= image_height);
5871 
5872  int y_offset = py * scanline_offset;
5873  *b = out ? uint(0) : image_bits[y_offset + px];
5874  x += fdx;
5875  y += fdy;
5876  w += fdw;
5877 
5878  ++b;
5879  }
5880  if (spanMethod == RegularSpans)
5881  func(target, buffer, l, coverage);
5882  else
5883  drawBufferSpan(data, buffer, buffer_size,
5884  spans->x + spans->len - length,
5885  spans->y, l, coverage);
5886  target += l;
5887  length -= l;
5888  }
5889  ++spans;
5890  }
5891  }
5892 }
5893 
5894 template <class DST, class SRC>
5895 Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans, void *userData)
5896 {
5897  QSpanData *data = reinterpret_cast<QSpanData*>(userData);
5899 
5901  blend_src_generic<RegularSpans>(count, spans, userData);
5902  return;
5903  }
5904 
5905  SRC buffer[buffer_size];
5906  const int image_width = data->texture.width;
5907  const int image_height = data->texture.height;
5908 
5909  if (data->fast_matrix) {
5910  // The increment pr x in the scanline
5911  const int fdx = (int)(data->m11 * fixed_scale);
5912  const int fdy = (int)(data->m12 * fixed_scale);
5913 
5914  while (count--) {
5915  const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5916  if (coverage == 0) {
5917  ++spans;
5918  continue;
5919  }
5920 
5921  DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5922  + spans->x;
5923  const qreal cx = spans->x + qreal(0.5);
5924  const qreal cy = spans->y + qreal(0.5);
5925  int x = int((data->m21 * cy
5926  + data->m11 * cx + data->dx) * fixed_scale);
5927  int y = int((data->m22 * cy
5928  + data->m12 * cx + data->dy) * fixed_scale);
5929  int length = spans->len;
5930 
5931  while (length) {
5932  const int l = qMin(length, buffer_size);
5933 
5934  const SRC *end = buffer + l;
5935  SRC *b = buffer;
5936  while (b < end) {
5937  const int px = (x >> 16);
5938  const int py = (y >> 16);
5939 
5940  if ((px < 0) || (px >= image_width) ||
5941  (py < 0) || (py >= image_height))
5942  {
5943  *b = 0;
5944  } else {
5945  *b = ((SRC*)data->texture.scanLine(py))[px];
5946  }
5947  ++b;
5948 
5949  x += fdx;
5950  y += fdy;
5951  }
5952 
5953  if (!SRC::hasAlpha() && coverage == 255) {
5954  qt_memconvert(dest, buffer, l);
5955  } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
5956  (quintptr(dest) & 3) == (quintptr(buffer) & 3))
5957  {
5958  blendUntransformed_dest24(dest, buffer, coverage, l);
5959  } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
5960  (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
5961  blendUntransformed_dest16(dest, buffer, coverage, l);
5962  } else {
5963  blendUntransformed_unaligned(dest, buffer, coverage, l);
5964  }
5965 
5966  dest += l;
5967  length -= l;
5968  }
5969  ++spans;
5970  }
5971  } else {
5972  const qreal fdx = data->m11;
5973  const qreal fdy = data->m12;
5974  const qreal fdw = data->m13;
5975 
5976  while (count--) {
5977  const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
5978  if (coverage == 0) {
5979  ++spans;
5980  continue;
5981  }
5982 
5983  DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
5984  + spans->x;
5985 
5986  const qreal cx = spans->x + qreal(0.5);
5987  const qreal cy = spans->y + qreal(0.5);
5988 
5989  qreal x = data->m21 * cy + data->m11 * cx + data->dx;
5990  qreal y = data->m22 * cy + data->m12 * cx + data->dy;
5991  qreal w = data->m23 * cy + data->m13 * cx + data->m33;
5992 
5993  int length = spans->len;
5994  while (length) {
5995  const int l = qMin(length, buffer_size);
5996  const SRC *end = buffer + l;
5997  SRC *b = buffer;
5998  while (b < end) {
5999  const qreal iw = w == 0 ? 1 : 1 / w;
6000  const qreal tx = x * iw;
6001  const qreal ty = y * iw;
6002 
6003  const int px = int(tx) - (tx < 0);
6004  const int py = int(ty) - (ty < 0);
6005 
6006  if ((px < 0) || (px >= image_width) ||
6007  (py < 0) || (py >= image_height))
6008  {
6009  *b = 0;
6010  } else {
6011  *b = ((SRC*)data->texture.scanLine(py))[px];
6012  }
6013  ++b;
6014 
6015  x += fdx;
6016  y += fdy;
6017  w += fdw;
6018  }
6019  if (!SRC::hasAlpha() && coverage == 255) {
6020  qt_memconvert(dest, buffer, l);
6021  } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6022  (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6023  {
6024  blendUntransformed_dest24(dest, buffer, coverage, l);
6025  } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6026  (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6027  blendUntransformed_dest16(dest, buffer, coverage, l);
6028  } else {
6029  blendUntransformed_unaligned(dest, buffer, coverage, l);
6030  }
6031 
6032  dest += l;
6033  length -= l;
6034  }
6035  ++spans;
6036  }
6037  }
6038 }
6039 
6040 static void blend_transformed_rgb888(int count, const QSpan *spans,
6041  void *userData)
6042 {
6043 #if defined(QT_QWS_DEPTH_24)
6044  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6045 
6046  if (data->texture.format == QImage::Format_RGB888)
6047  blendTransformed<qrgb888, qrgb888>(count, spans, userData);
6048  else
6049 #endif
6050  blend_src_generic<RegularSpans>(count, spans, userData);
6051 }
6052 
6053 static void blend_transformed_argb6666(int count, const QSpan *spans,
6054  void *userData)
6055 {
6056 #if defined(QT_QWS_DEPTH_18)
6057  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6058 
6060  blendTransformed<qargb6666, qargb6666>(count, spans, userData);
6061  else if (data->texture.format == QImage::Format_RGB666)
6062  blendTransformed<qargb6666, qrgb666>(count, spans, userData);
6063  else
6064 #endif
6065  blend_src_generic<RegularSpans>(count, spans, userData);
6066 }
6067 
6068 static void blend_transformed_rgb666(int count, const QSpan *spans,
6069  void *userData)
6070 {
6071 #if defined(QT_QWS_DEPTH_18)
6072  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6073 
6075  blendTransformed<qrgb666, qargb6666>(count, spans, userData);
6076  else if (data->texture.format == QImage::Format_RGB666)
6077  blendTransformed<qrgb666, qrgb666>(count, spans, userData);
6078  else
6079 #endif
6080  blend_src_generic<RegularSpans>(count, spans, userData);
6081 }
6082 
6083 static void blend_transformed_argb8565(int count, const QSpan *spans,
6084  void *userData)
6085 {
6086 #if defined(QT_QWS_DEPTH_16)
6087  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6088 
6090  blendTransformed<qargb8565, qargb8565>(count, spans, userData);
6091  else if (data->texture.format == QImage::Format_RGB16)
6092  blendTransformed<qargb8565, qrgb565>(count, spans, userData);
6093  else
6094 #endif
6095  blend_src_generic<RegularSpans>(count, spans, userData);
6096 }
6097 
6098 static void blend_transformed_rgb565(int count, const QSpan *spans,
6099  void *userData)
6100 {
6101 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
6102  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6103 
6105  blendTransformed<qrgb565, qargb8565>(count, spans, userData);
6106  else if (data->texture.format == QImage::Format_RGB16)
6107  blendTransformed<qrgb565, qrgb565>(count, spans, userData);
6108  else
6109 #endif
6110  blend_src_generic<RegularSpans>(count, spans, userData);
6111 }
6112 
6113 static void blend_transformed_argb8555(int count, const QSpan *spans,
6114  void *userData)
6115 {
6116 #if defined(QT_QWS_DEPTH_15)
6117  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6118 
6120  blendTransformed<qargb8555, qargb8555>(count, spans, userData);
6121  else if (data->texture.format == QImage::Format_RGB555)
6122  blendTransformed<qargb8555, qrgb555>(count, spans, userData);
6123  else
6124 #endif
6125  blend_src_generic<RegularSpans>(count, spans, userData);
6126 }
6127 
6128 static void blend_transformed_rgb555(int count, const QSpan *spans,
6129  void *userData)
6130 {
6131 #if defined(QT_QWS_DEPTH_15)
6132  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6133 
6135  blendTransformed<qrgb555, qargb8555>(count, spans, userData);
6136  else if (data->texture.format == QImage::Format_RGB555)
6137  blendTransformed<qrgb555, qrgb555>(count, spans, userData);
6138  else
6139 #endif
6140  blend_src_generic<RegularSpans>(count, spans, userData);
6141 }
6142 
6143 static void blend_transformed_argb4444(int count, const QSpan *spans,
6144  void *userData)
6145 {
6146 #if defined(QT_QWS_DEPTH_12)
6147  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6148 
6150  blendTransformed<qargb4444, qargb4444>(count, spans, userData);
6151  else if (data->texture.format == QImage::Format_RGB444)
6152  blendTransformed<qargb4444, qrgb444>(count, spans, userData);
6153  else
6154 #endif
6155  blend_src_generic<RegularSpans>(count, spans, userData);
6156 }
6157 
6158 static void blend_transformed_rgb444(int count, const QSpan *spans,
6159  void *userData)
6160 {
6161 #if defined(QT_QWS_DEPTH_12)
6162  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6163 
6165  blendTransformed<qrgb444, qargb4444>(count, spans, userData);
6166  else if (data->texture.format == QImage::Format_RGB444)
6167  blendTransformed<qrgb444, qrgb444>(count, spans, userData);
6168  else
6169 #endif
6170  blend_src_generic<RegularSpans>(count, spans, userData);
6171 }
6172 
6173 template <SpanMethod spanMethod>
6174 Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QSpan *spans, void *userData)
6175 {
6176  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6178  && data->texture.format != QImage::Format_RGB32) {
6179  blend_src_generic<spanMethod>(count, spans, userData);
6180  return;
6181  }
6182 
6183  CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
6184  uint buffer[buffer_size];
6185 
6186  int image_width = data->texture.width;
6187  int image_height = data->texture.height;
6188  const int scanline_offset = data->texture.bytesPerLine / 4;
6189 
6190  if (data->fast_matrix) {
6191  // The increment pr x in the scanline
6192  int fdx = (int)(data->m11 * fixed_scale);
6193  int fdy = (int)(data->m12 * fixed_scale);
6194 
6195  while (count--) {
6196  void *t = data->rasterBuffer->scanLine(spans->y);
6197 
6198  uint *target = ((uint *)t) + spans->x;
6199  uint *image_bits = (uint *)data->texture.imageData;
6200 
6201  const qreal cx = spans->x + qreal(0.5);
6202  const qreal cy = spans->y + qreal(0.5);
6203 
6204  int x = int((data->m21 * cy
6205  + data->m11 * cx + data->dx) * fixed_scale);
6206  int y = int((data->m22 * cy
6207  + data->m12 * cx + data->dy) * fixed_scale);
6208 
6209  const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
6210  int length = spans->len;
6211  while (length) {
6212  int l = qMin(length, buffer_size);
6213  const uint *end = buffer + l;
6214  uint *b = buffer;
6215  while (b < end) {
6216  int px = x >> 16;
6217  int py = y >> 16;
6218  px %= image_width;
6219  py %= image_height;
6220  if (px < 0) px += image_width;
6221  if (py < 0) py += image_height;
6222  int y_offset = py * scanline_offset;
6223 
6224  Q_ASSERT(px >= 0 && px < image_width);
6225  Q_ASSERT(py >= 0 && py < image_height);
6226 
6227  *b = image_bits[y_offset + px];
6228  x += fdx;
6229  y += fdy;
6230  ++b;
6231  }
6232  if (spanMethod == RegularSpans)
6233  func(target, buffer, l, coverage);
6234  else
6235  drawBufferSpan(data, buffer, buffer_size,
6236  spans->x + spans->len - length,
6237  spans->y, l, coverage);
6238  target += l;
6239  length -= l;
6240  }
6241  ++spans;
6242  }
6243  } else {
6244  const qreal fdx = data->m11;
6245  const qreal fdy = data->m12;
6246  const qreal fdw = data->m13;
6247  while (count--) {
6248  void *t = data->rasterBuffer->scanLine(spans->y);
6249 
6250  uint *target = ((uint *)t) + spans->x;
6251  uint *image_bits = (uint *)data->texture.imageData;
6252 
6253  const qreal cx = spans->x + qreal(0.5);
6254  const qreal cy = spans->y + qreal(0.5);
6255 
6256  qreal x = data->m21 * cy + data->m11 * cx + data->dx;
6257  qreal y = data->m22 * cy + data->m12 * cx + data->dy;
6258  qreal w = data->m23 * cy + data->m13 * cx + data->m33;
6259 
6260  const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
6261  int length = spans->len;
6262  while (length) {
6263  int l = qMin(length, buffer_size);
6264  const uint *end = buffer + l;
6265  uint *b = buffer;
6266  while (b < end) {
6267  const qreal iw = w == 0 ? 1 : 1 / w;
6268  const qreal tx = x * iw;
6269  const qreal ty = y * iw;
6270  int px = int(tx) - (tx < 0);
6271  int py = int(ty) - (ty < 0);
6272 
6273  px %= image_width;
6274  py %= image_height;
6275  if (px < 0) px += image_width;
6276  if (py < 0) py += image_height;
6277  int y_offset = py * scanline_offset;
6278 
6279  Q_ASSERT(px >= 0 && px < image_width);
6280  Q_ASSERT(py >= 0 && py < image_height);
6281 
6282  *b = image_bits[y_offset + px];
6283  x += fdx;
6284  y += fdy;
6285  w += fdw;
6286  //force increment to avoid /0
6287  if (!w) {
6288  w += fdw;
6289  }
6290  ++b;
6291  }
6292  if (spanMethod == RegularSpans)
6293  func(target, buffer, l, coverage);
6294  else
6295  drawBufferSpan(data, buffer, buffer_size,
6296  spans->x + spans->len - length,
6297  spans->y, l, coverage);
6298  target += l;
6299  length -= l;
6300  }
6301  ++spans;
6302  }
6303  }
6304 }
6305 
6306 template <class DST, class SRC>
6307 Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *spans, void *userData)
6308 {
6309  QSpanData *data = reinterpret_cast<QSpanData*>(userData);
6311 
6313  blend_src_generic<RegularSpans>(count, spans, userData);
6314  return;
6315  }
6316 
6317  SRC buffer[buffer_size];
6318  const int image_width = data->texture.width;
6319  const int image_height = data->texture.height;
6320 
6321  if (data->fast_matrix) {
6322  // The increment pr x in the scanline
6323  const int fdx = (int)(data->m11 * fixed_scale);
6324  const int fdy = (int)(data->m12 * fixed_scale);
6325 
6326  while (count--) {
6327  const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
6328  if (coverage == 0) {
6329  ++spans;
6330  continue;
6331  }
6332 
6333  DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
6334  + spans->x;
6335  const qreal cx = spans->x + qreal(0.5);
6336  const qreal cy = spans->y + qreal(0.5);
6337  int x = int((data->m21 * cy
6338  + data->m11 * cx + data->dx) * fixed_scale);
6339  int y = int((data->m22 * cy
6340  + data->m12 * cx + data->dy) * fixed_scale);
6341  int length = spans->len;
6342 
6343  while (length) {
6344  const int l = qMin(length, buffer_size);
6345 
6346  const SRC *end = buffer + l;
6347  SRC *b = buffer;
6348  while (b < end) {
6349  int px = (x >> 16) % image_width;
6350  int py = (y >> 16) % image_height;
6351 
6352  if (px < 0)
6353  px += image_width;
6354  if (py < 0)
6355  py += image_height;
6356 
6357  *b = ((SRC*)data->texture.scanLine(py))[px];
6358  ++b;
6359 
6360  x += fdx;
6361  y += fdy;
6362  }
6363 
6364  if (!SRC::hasAlpha() && coverage == 255) {
6365  qt_memconvert(dest, buffer, l);
6366  } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6367  (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6368  {
6369  blendUntransformed_dest24(dest, buffer, coverage, l);
6370  } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6371  (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6372  blendUntransformed_dest16(dest, buffer, coverage, l);
6373  } else {
6374  blendUntransformed_unaligned(dest, buffer, coverage, l);
6375  }
6376 
6377  dest += l;
6378  length -= l;
6379  }
6380  ++spans;
6381  }
6382  } else {
6383  const qreal fdx = data->m11;
6384  const qreal fdy = data->m12;
6385  const qreal fdw = data->m13;
6386 
6387  while (count--) {
6388  const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
6389  if (coverage == 0) {
6390  ++spans;
6391  continue;
6392  }
6393 
6394  DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
6395  + spans->x;
6396 
6397  const qreal cx = spans->x + qreal(0.5);
6398  const qreal cy = spans->y + qreal(0.5);
6399 
6400  qreal x = data->m21 * cy + data->m11 * cx + data->dx;
6401  qreal y = data->m22 * cy + data->m12 * cx + data->dy;
6402  qreal w = data->m23 * cy + data->m13 * cx + data->m33;
6403 
6404  int length = spans->len;
6405  while (length) {
6406  const int l = qMin(length, buffer_size);
6407  const SRC *end = buffer + l;
6408  SRC *b = buffer;
6409  while (b < end) {
6410  const qreal iw = w == 0 ? 1 : 1 / w;
6411  const qreal tx = x * iw;
6412  const qreal ty = y * iw;
6413 
6414  int px = int(tx) - (tx < 0);
6415  int py = int(ty) - (ty < 0);
6416 
6417  px %= image_width;
6418  py %= image_height;
6419  if (px < 0)
6420  px += image_width;
6421  if (py < 0)
6422  py += image_height;
6423 
6424  *b = ((SRC*)data->texture.scanLine(py))[px];
6425  ++b;
6426 
6427  x += fdx;
6428  y += fdy;
6429  w += fdw;
6430  // force increment to avoid /0
6431  if (!w)
6432  w += fdw;
6433  }
6434  if (!SRC::hasAlpha() && coverage == 255) {
6435  qt_memconvert(dest, buffer, l);
6436  } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
6437  (quintptr(dest) & 3) == (quintptr(buffer) & 3))
6438  {
6439  blendUntransformed_dest24(dest, buffer, coverage, l);
6440  } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
6441  (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
6442  blendUntransformed_dest16(dest, buffer, coverage, l);
6443  } else {
6444  blendUntransformed_unaligned(dest, buffer, coverage, l);
6445  }
6446 
6447  dest += l;
6448  length -= l;
6449  }
6450  ++spans;
6451  }
6452  }
6453 }
6454 
6455 static void blend_transformed_tiled_rgb888(int count, const QSpan *spans,
6456  void *userData)
6457 {
6458 #if defined(QT_QWS_DEPTH_24)
6459  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6460 
6461  if (data->texture.format == QImage::Format_RGB888)
6462  blendTransformedTiled<qrgb888, qrgb888>(count, spans, userData);
6463  else
6464 #endif
6465  blend_src_generic<RegularSpans>(count, spans, userData);
6466 }
6467 
6468 static void blend_transformed_tiled_argb6666(int count, const QSpan *spans,
6469  void *userData)
6470 {
6471 #if defined(QT_QWS_DEPTH_18)
6472  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6473 
6475  blendTransformedTiled<qargb6666, qargb6666>(count, spans, userData);
6476  else if (data->texture.format == QImage::Format_RGB666)
6477  blendTransformedTiled<qargb6666, qrgb666>(count, spans, userData);
6478  else
6479 #endif
6480  blend_src_generic<RegularSpans>(count, spans, userData);
6481 }
6482 
6483 static void blend_transformed_tiled_rgb666(int count, const QSpan *spans,
6484  void *userData)
6485 {
6486 #if defined(QT_QWS_DEPTH_18)
6487  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6488 
6490  blendTransformedTiled<qrgb666, qargb6666>(count, spans, userData);
6491  else if (data->texture.format == QImage::Format_RGB666)
6492  blendTransformedTiled<qrgb666, qrgb666>(count, spans, userData);
6493  else
6494 #endif
6495  blend_src_generic<RegularSpans>(count, spans, userData);
6496 }
6497 
6498 static void blend_transformed_tiled_argb8565(int count, const QSpan *spans,
6499  void *userData)
6500 {
6501 #if defined(QT_QWS_DEPTH_16)
6502  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6503 
6505  blendTransformedTiled<qargb8565, qargb8565>(count, spans, userData);
6506  else if (data->texture.format == QImage::Format_RGB16)
6507  blendTransformedTiled<qargb8565, qrgb565>(count, spans, userData);
6508  else
6509 #endif
6510  blend_src_generic<RegularSpans>(count, spans, userData);
6511 }
6512 
6513 static void blend_transformed_tiled_rgb565(int count, const QSpan *spans,
6514  void *userData)
6515 {
6516 #if !defined(Q_WS_QWS) || defined(QT_QWS_DEPTH_16)
6517  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6518 
6520  blendTransformedTiled<qrgb565, qargb8565>(count, spans, userData);
6521  else if (data->texture.format == QImage::Format_RGB16)
6522  blendTransformedTiled<qrgb565, qrgb565>(count, spans, userData);
6523  else
6524 #endif
6525  blend_src_generic<RegularSpans>(count, spans, userData);
6526 }
6527 
6528 static void blend_transformed_tiled_argb8555(int count, const QSpan *spans,
6529  void *userData)
6530 {
6531 #if defined(QT_QWS_DEPTH_15)
6532  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6533 
6535  blendTransformedTiled<qargb8555, qargb8555>(count, spans, userData);
6536  else if (data->texture.format == QImage::Format_RGB555)
6537  blendTransformedTiled<qargb8555, qrgb555>(count, spans, userData);
6538  else
6539 #endif
6540  blend_src_generic<RegularSpans>(count, spans, userData);
6541 }
6542 
6543 static void blend_transformed_tiled_rgb555(int count, const QSpan *spans,
6544  void *userData)
6545 {
6546 #if defined(QT_QWS_DEPTH_15)
6547  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6548 
6550  blendTransformedTiled<qrgb555, qargb8555>(count, spans, userData);
6551  else if (data->texture.format == QImage::Format_RGB555)
6552  blendTransformedTiled<qrgb555, qrgb555>(count, spans, userData);
6553  else
6554 #endif
6555  blend_src_generic<RegularSpans>(count, spans, userData);
6556 }
6557 
6558 static void blend_transformed_tiled_argb4444(int count, const QSpan *spans,
6559  void *userData)
6560 {
6561 #if defined(QT_QWS_DEPTH_12)
6562  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6563 
6565  blendTransformedTiled<qargb4444, qargb4444>(count, spans, userData);
6566  else if (data->texture.format == QImage::Format_RGB444)
6567  blendTransformedTiled<qargb4444, qrgb444>(count, spans, userData);
6568  else
6569 #endif
6570  blend_src_generic<RegularSpans>(count, spans, userData);
6571 }
6572 
6573 static void blend_transformed_tiled_rgb444(int count, const QSpan *spans,
6574  void *userData)
6575 {
6576 #if defined(QT_QWS_DEPTH_12)
6577  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6578 
6580  blendTransformedTiled<qrgb444, qargb4444>(count, spans, userData);
6581  else if (data->texture.format == QImage::Format_RGB444)
6582  blendTransformedTiled<qrgb444, qrgb444>(count, spans, userData);
6583  else
6584 #endif
6585  blend_src_generic<RegularSpans>(count, spans, userData);
6586 }
6587 
6588 # define SPANFUNC_POINTER(Name, Arg) Name<Arg>
6589 
6590 
6591 /* Image formats here are target formats */
6592 static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats] = {
6593  // Untransformed
6594  {
6595  0, // Invalid
6601  SPANFUNC_POINTER(blend_untransformed_argb, RegularSpans), // ARGB32_Premultiplied
6611  },
6612  // Tiled
6613  {
6614  0, // Invalid
6620  SPANFUNC_POINTER(blend_tiled_argb, RegularSpans), // ARGB32_Premultiplied
6630  },
6631  // Transformed
6632  {
6633  0, // Invalid
6639  SPANFUNC_POINTER(blend_transformed_argb, RegularSpans), // ARGB32_Premultiplied
6649  },
6650  // TransformedTiled
6651  {
6652  0,
6668  },
6669  // Bilinear
6670  {
6671  0,
6677  SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
6687  },
6688  // BilinearTiled
6689  {
6690  0,
6696  SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
6698  SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8565_Premultiplied
6700  SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB6666_Premultiplied
6702  SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8555_Premultiplied
6705  SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB4444_Premultiplied
6706  }
6707 };
6708 
6709 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
6710 static const ProcessSpans processTextureSpansCallback[NBlendTypes][QImage::NImageFormats] = {
6711  // Untransformed
6712  {
6713  0, // Invalid
6714  blend_untransformed_generic<CallbackSpans>, // Mono
6715  blend_untransformed_generic<CallbackSpans>, // MonoLsb
6716  blend_untransformed_generic<CallbackSpans>, // Indexed8
6717  blend_untransformed_generic<CallbackSpans>, // RGB32
6718  blend_untransformed_generic<CallbackSpans>, // ARGB32
6719  blend_untransformed_argb<CallbackSpans>, // ARGB32_Premultiplied
6720  blend_untransformed_generic<CallbackSpans>, // RGB16
6721  blend_untransformed_generic<CallbackSpans>, // ARGB8565_Premultiplied
6722  blend_untransformed_generic<CallbackSpans>, // RGB666
6723  blend_untransformed_generic<CallbackSpans>, // ARGB6666_Premultiplied
6724  blend_untransformed_generic<CallbackSpans>, // RGB555
6725  blend_untransformed_generic<CallbackSpans>, // ARGB8555_Premultiplied
6726  blend_untransformed_generic<CallbackSpans>, // RGB888
6727  blend_untransformed_generic<CallbackSpans>, // RGB444
6728  blend_untransformed_generic<CallbackSpans> // ARGB4444_Premultiplied
6729  },
6730  // Tiled
6731  {
6732  0, // Invalid
6733  blend_tiled_generic<CallbackSpans>, // Mono
6734  blend_tiled_generic<CallbackSpans>, // MonoLsb
6735  blend_tiled_generic<CallbackSpans>, // Indexed8
6736  blend_tiled_generic<CallbackSpans>, // RGB32
6737  blend_tiled_generic<CallbackSpans>, // ARGB32
6738  blend_tiled_argb<CallbackSpans>, // ARGB32_Premultiplied
6739  blend_tiled_generic<CallbackSpans>, // RGB16
6740  blend_tiled_generic<CallbackSpans>, // ARGB8565_Premultiplied
6741  blend_tiled_generic<CallbackSpans>, // RGB666
6742  blend_tiled_generic<CallbackSpans>, // ARGB6666_Premultiplied
6743  blend_tiled_generic<CallbackSpans>, // RGB555
6744  blend_tiled_generic<CallbackSpans>, // ARGB8555_Premultiplied
6745  blend_tiled_generic<CallbackSpans>, // RGB888
6746  blend_tiled_generic<CallbackSpans>, // RGB444
6747  blend_tiled_generic<CallbackSpans> // ARGB4444_Premultiplied
6748  },
6749  // Transformed
6750  {
6751  0, // Invalid
6752  blend_src_generic<CallbackSpans>, // Mono
6753  blend_src_generic<CallbackSpans>, // MonoLsb
6754  blend_src_generic<CallbackSpans>, // Indexed8
6755  blend_src_generic<CallbackSpans>, // RGB32
6756  blend_src_generic<CallbackSpans>, // ARGB32
6757  blend_transformed_argb<CallbackSpans>, // ARGB32_Premultiplied
6758  blend_src_generic<CallbackSpans>, // RGB16
6759  blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6760  blend_src_generic<CallbackSpans>, // RGB666
6761  blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6762  blend_src_generic<CallbackSpans>, // RGB555
6763  blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6764  blend_src_generic<CallbackSpans>, // RGB888
6765  blend_src_generic<CallbackSpans>, // RGB444
6766  blend_src_generic<CallbackSpans>, // ARGB4444_Premultiplied
6767  },
6768  // TransformedTiled
6769  {
6770  0,
6771  blend_src_generic<CallbackSpans>, // Mono
6772  blend_src_generic<CallbackSpans>, // MonoLsb
6773  blend_src_generic<CallbackSpans>, // Indexed8
6774  blend_src_generic<CallbackSpans>, // RGB32
6775  blend_src_generic<CallbackSpans>, // ARGB32
6776  blend_transformed_tiled_argb<CallbackSpans>, // ARGB32_Premultiplied
6777  blend_src_generic<CallbackSpans>, // RGB16
6778  blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6779  blend_src_generic<CallbackSpans>, // RGB666
6780  blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6781  blend_src_generic<CallbackSpans>, // RGB555
6782  blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6783  blend_src_generic<CallbackSpans>, // RGB888
6784  blend_src_generic<CallbackSpans>, // RGB444
6785  blend_src_generic<CallbackSpans> // ARGB4444_Premultiplied
6786  },
6787  // Bilinear
6788  {
6789  0,
6790  blend_src_generic<CallbackSpans>, // Mono
6791  blend_src_generic<CallbackSpans>, // MonoLsb
6792  blend_src_generic<CallbackSpans>, // Indexed8
6793  blend_src_generic<CallbackSpans>, // RGB32
6794  blend_src_generic<CallbackSpans>, // ARGB32
6795  blend_src_generic<CallbackSpans>, // ARGB32_Premultiplied
6796  blend_src_generic<CallbackSpans>, // RGB16
6797  blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6798  blend_src_generic<CallbackSpans>, // RGB666
6799  blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6800  blend_src_generic<CallbackSpans>, // RGB555
6801  blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6802  blend_src_generic<CallbackSpans>, // RGB888
6803  blend_src_generic<CallbackSpans>, // RGB444
6804  blend_src_generic<CallbackSpans> // ARGB4444_Premultiplied
6805  },
6806  // BilinearTiled
6807  {
6808  0,
6809  blend_src_generic<CallbackSpans>, // Mono
6810  blend_src_generic<CallbackSpans>, // MonoLsb
6811  blend_src_generic<CallbackSpans>, // Indexed8
6812  blend_src_generic<CallbackSpans>, // RGB32
6813  blend_src_generic<CallbackSpans>, // ARGB32
6814  blend_src_generic<CallbackSpans>, // ARGB32_Premultiplied
6815  blend_src_generic<CallbackSpans>, // RGB16
6816  blend_src_generic<CallbackSpans>, // ARGB8565_Premultiplied
6817  blend_src_generic<CallbackSpans>, // RGB666
6818  blend_src_generic<CallbackSpans>, // ARGB6666_Premultiplied
6819  blend_src_generic<CallbackSpans>, // RGB555
6820  blend_src_generic<CallbackSpans>, // ARGB8555_Premultiplied
6821  blend_src_generic<CallbackSpans>, // RGB888
6822  blend_src_generic<CallbackSpans>, // RGB444
6823  blend_src_generic<CallbackSpans> // ARGB4444_Premultiplied
6824  }
6825 };
6826 #endif // QT_NO_RASTERCALLBACKS
6827 
6828 void qBlendTexture(int count, const QSpan *spans, void *userData)
6829 {
6830  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6831  ProcessSpans proc = processTextureSpans[getBlendType(data)][data->rasterBuffer->format];
6832  proc(count, spans, userData);
6833 }
6834 
6835 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
6836 void qBlendTextureCallback(int count, const QSpan *spans, void *userData)
6837 {
6838  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6839  ProcessSpans proc = processTextureSpansCallback[getBlendType(data)][data->rasterBuffer->format];
6840  proc(count, spans, userData);
6841 }
6842 #endif // QT_NO_RASTERCALLBACKS
6843 
6844 template <class DST>
6845 inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
6846  int x, int y, quint32 color,
6847  const uchar *map,
6848  int mapWidth, int mapHeight, int mapStride,
6849  DST dummy = 0)
6850 {
6851  Q_UNUSED(dummy);
6852  const DST c = qt_colorConvert<DST, quint32>(color, 0);
6853  DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
6854  const int destStride = rasterBuffer->bytesPerLine() / sizeof(DST);
6855 
6856  if (mapWidth > 8) {
6857  while (mapHeight--) {
6858  int x0 = 0;
6859  int n = 0;
6860  for (int x = 0; x < mapWidth; x += 8) {
6861  uchar s = map[x >> 3];
6862  for (int i = 0; i < 8; ++i) {
6863  if (s & 0x80) {
6864  ++n;
6865  } else {
6866  if (n) {
6867  qt_memfill(dest + x0, c, n);
6868  x0 += n + 1;
6869  n = 0;
6870  } else {
6871  ++x0;
6872  }
6873  if (!s) {
6874  x0 += 8 - 1 - i;
6875  break;
6876  }
6877  }
6878  s <<= 1;
6879  }
6880  }
6881  if (n)
6882  qt_memfill(dest + x0, c, n);
6883  dest += destStride;
6884  map += mapStride;
6885  }
6886  } else {
6887  while (mapHeight--) {
6888  int x0 = 0;
6889  int n = 0;
6890  for (uchar s = *map; s; s <<= 1) {
6891  if (s & 0x80) {
6892  ++n;
6893  } else if (n) {
6894  qt_memfill(dest + x0, c, n);
6895  x0 += n + 1;
6896  n = 0;
6897  } else {
6898  ++x0;
6899  }
6900  }
6901  if (n)
6902  qt_memfill(dest + x0, c, n);
6903  dest += destStride;
6904  map += mapStride;
6905  }
6906  }
6907 }
6908 
6909 static void qt_gradient_quint32(int count, const QSpan *spans, void *userData)
6910 {
6911  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6912 
6913  bool isVerticalGradient =
6914  data->txop <= QTransform::TxScale &&
6915  data->type == QSpanData::LinearGradient &&
6916  data->gradient.linear.end.x == data->gradient.linear.origin.x;
6917 
6918  if (isVerticalGradient) {
6919  LinearGradientValues linear;
6920  getLinearGradientValues(&linear, data);
6921 
6922  CompositionFunctionSolid funcSolid =
6923  functionForModeSolid[data->rasterBuffer->compositionMode];
6924 
6925  /*
6926  The logic for vertical gradient calculations is a mathematically
6927  reduced copy of that in fetchLinearGradient() - which is basically:
6928 
6929  qreal ry = data->m22 * (y + 0.5) + data->dy;
6930  qreal t = linear.dy*ry + linear.off;
6931  t *= (GRADIENT_STOPTABLE_SIZE - 1);
6932  quint32 color =
6933  qt_gradient_pixel_fixed(&data->gradient,
6934  int(t * FIXPT_SIZE));
6935 
6936  This has then been converted to fixed point to improve performance.
6937  */
6938  const int gss = GRADIENT_STOPTABLE_SIZE - 1;
6939  int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
6940  int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
6941 
6942  while (count--) {
6943  int y = spans->y;
6944  int x = spans->x;
6945 
6946  quint32 *dst = (quint32 *)(data->rasterBuffer->scanLine(y)) + x;
6947  quint32 color =
6948  qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
6949 
6950  funcSolid(dst, spans->len, color, spans->coverage);
6951  ++spans;
6952  }
6953 
6954  } else {
6955  blend_src_generic<RegularSpans>(count, spans, userData);
6956  }
6957 }
6958 
6959 static void qt_gradient_quint16(int count, const QSpan *spans, void *userData)
6960 {
6961  QSpanData *data = reinterpret_cast<QSpanData *>(userData);
6962 
6963  bool isVerticalGradient =
6964  data->txop <= QTransform::TxScale &&
6965  data->type == QSpanData::LinearGradient &&
6966  data->gradient.linear.end.x == data->gradient.linear.origin.x;
6967 
6968  if (isVerticalGradient) {
6969 
6970  LinearGradientValues linear;
6971  getLinearGradientValues(&linear, data);
6972 
6973  /*
6974  The logic for vertical gradient calculations is a mathematically
6975  reduced copy of that in fetchLinearGradient() - which is basically:
6976 
6977  qreal ry = data->m22 * (y + 0.5) + data->dy;
6978  qreal t = linear.dy*ry + linear.off;
6979  t *= (GRADIENT_STOPTABLE_SIZE - 1);
6980  quint32 color =
6981  qt_gradient_pixel_fixed(&data->gradient,
6982  int(t * FIXPT_SIZE));
6983 
6984  This has then been converted to fixed point to improve performance.
6985  */
6986  const int gss = GRADIENT_STOPTABLE_SIZE - 1;
6987  int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
6988  int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
6989 
6990  uint oldColor = data->solid.color;
6991  while (count--) {
6992  int y = spans->y;
6993 
6994  quint32 color = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
6995 
6996  data->solid.color = color;
6997  blend_color_rgb16(1, spans, userData);
6998  ++spans;
6999  }
7000  data->solid.color = oldColor;
7001 
7002  } else {
7003  blend_src_generic<RegularSpans>(count, spans, userData);
7004  }
7005 }
7006 
7007 inline static void qt_bitmapblit_quint32(QRasterBuffer *rasterBuffer,
7008  int x, int y, quint32 color,
7009  const uchar *map,
7010  int mapWidth, int mapHeight, int mapStride)
7011 {
7012  qt_bitmapblit_template<quint32>(rasterBuffer, x, y, color,
7013  map, mapWidth, mapHeight, mapStride);
7014 }
7015 
7016 inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
7017  int x, int y, quint32 color,
7018  const uchar *map,
7019  int mapWidth, int mapHeight, int mapStride)
7020 {
7021  qt_bitmapblit_template<quint16>(rasterBuffer, x, y, color,
7022  map, mapWidth, mapHeight, mapStride);
7023 }
7024 
7025 
7026 uchar qt_pow_rgb_gamma[256];
7028 
7029 uint qt_pow_gamma[256];
7030 uchar qt_pow_invgamma[2048];
7031 
7032 static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
7033  int x, int y, quint32 color,
7034  const uchar *map,
7035  int mapWidth, int mapHeight, int mapStride,
7036  const QClipData *)
7037 {
7038  const quint16 c = qt_colorConvert<quint16, quint32>(color, 0);
7039  quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
7040  const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
7041 
7042  while (mapHeight--) {
7043  for (int i = 0; i < mapWidth; ++i) {
7044  const int coverage = map[i];
7045 
7046  if (coverage == 0) {
7047  // nothing
7048  } else if (coverage == 255) {
7049  dest[i] = c;
7050  } else {
7051  int ialpha = 255 - coverage;
7052  dest[i] = BYTE_MUL_RGB16(c, coverage)
7053  + BYTE_MUL_RGB16(dest[i], ialpha);
7054  }
7055  }
7056  dest += destStride;
7057  map += mapStride;
7058  }
7059 }
7060 
7062  qreal smoothing = qreal(1.7);
7063 
7064 #ifdef Q_WS_MAC
7065  // decided by testing a few things on an iMac, should probably get this from the
7066  // system...
7067  smoothing = qreal(2.0);
7068 #endif
7069 
7070 #ifdef Q_WS_WIN
7071  extern qreal qt_fontsmoothing_gamma; // qapplication_win.cpp
7072  smoothing = qt_fontsmoothing_gamma;
7073 #endif
7074 
7075 #ifdef Q_WS_X11
7076  Q_UNUSED(smoothing);
7077  for (int i=0; i<256; ++i) {
7078  qt_pow_rgb_gamma[i] = uchar(i);
7079  qt_pow_rgb_invgamma[i] = uchar(i);
7080  }
7081 #else
7082  for (int i=0; i<256; ++i) {
7083  qt_pow_rgb_gamma[i] = uchar(qRound(qPow(i / qreal(255.0), smoothing) * 255));
7084  qt_pow_rgb_invgamma[i] = uchar(qRound(qPow(i / qreal(255.), 1 / smoothing) * 255));
7085  }
7086 #endif
7087 
7088 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7089  const qreal gray_gamma = 2.31;
7090  for (int i=0; i<256; ++i)
7091  qt_pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047));
7092  for (int i=0; i<2048; ++i)
7093  qt_pow_invgamma[i] = uchar(qRound(qPow(i / qreal(2047.0), 1 / gray_gamma) * 255));
7094 #endif
7095 }
7096 
7097 static inline void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
7098 {
7099  // Do a gray alphablend...
7100  int da = qAlpha(*dst);
7101  int dr = qRed(*dst);
7102  int dg = qGreen(*dst);
7103  int db = qBlue(*dst);
7104 
7105  if (da != 255
7106 #if defined (Q_WS_WIN)
7107  // Work around GDI messing up alpha channel
7108  && qRed(*dst) <= da && qBlue(*dst) <= da && qGreen(*dst) <= da
7109 #endif
7110  ) {
7111 
7112  int a = qGray(coverage);
7113  sr = qt_div_255(qt_pow_rgb_invgamma[sr] * a);
7114  sg = qt_div_255(qt_pow_rgb_invgamma[sg] * a);
7115  sb = qt_div_255(qt_pow_rgb_invgamma[sb] * a);
7116 
7117  int ia = 255 - a;
7118  dr = qt_div_255(dr * ia);
7119  dg = qt_div_255(dg * ia);
7120  db = qt_div_255(db * ia);
7121 
7122  *dst = ((a + qt_div_255((255 - a) * da)) << 24)
7123  | ((sr + dr) << 16)
7124  | ((sg + dg) << 8)
7125  | ((sb + db));
7126  return;
7127  }
7128 
7129  int mr = qRed(coverage);
7130  int mg = qGreen(coverage);
7131  int mb = qBlue(coverage);
7132 
7133  dr = qt_pow_rgb_gamma[dr];
7134  dg = qt_pow_rgb_gamma[dg];
7135  db = qt_pow_rgb_gamma[db];
7136 
7137  int nr = qt_div_255((sr - dr) * mr) + dr;
7138  int ng = qt_div_255((sg - dg) * mg) + dg;
7139  int nb = qt_div_255((sb - db) * mb) + db;
7140 
7141  nr = qt_pow_rgb_invgamma[nr];
7142  ng = qt_pow_rgb_invgamma[ng];
7143  nb = qt_pow_rgb_invgamma[nb];
7144 
7145  *dst = qRgb(nr, ng, nb);
7146 }
7147 
7148 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7149 static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
7150 {
7151  // Do a gammacorrected gray alphablend...
7152  int dr = qRed(*dst);
7153  int dg = qGreen(*dst);
7154  int db = qBlue(*dst);
7155 
7156  dr = qt_pow_gamma[dr];
7157  dg = qt_pow_gamma[dg];
7158  db = qt_pow_gamma[db];
7159 
7160  int alpha = coverage;
7161  int ialpha = 255 - alpha;
7162  int nr = (sr * alpha + ialpha * dr) / 255;
7163  int ng = (sg * alpha + ialpha * dg) / 255;
7164  int nb = (sb * alpha + ialpha * db) / 255;
7165 
7166  nr = qt_pow_invgamma[nr];
7167  ng = qt_pow_invgamma[ng];
7168  nb = qt_pow_invgamma[nb];
7169 
7170  *dst = qRgb(nr, ng, nb);
7171 }
7172 #endif
7173 
7174 static void qt_alphamapblit_quint32(QRasterBuffer *rasterBuffer,
7175  int x, int y, quint32 color,
7176  const uchar *map,
7177  int mapWidth, int mapHeight, int mapStride,
7178  const QClipData *clip)
7179 {
7180  const quint32 c = color;
7181  const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
7182 
7183 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7184  int sr = qRed(color);
7185  int sg = qGreen(color);
7186  int sb = qBlue(color);
7187 
7188  sr = qt_pow_gamma[sr];
7189  sg = qt_pow_gamma[sg];
7190  sb = qt_pow_gamma[sb];
7191  bool opaque_src = (qAlpha(color) == 255);
7192 #endif
7193 
7194  if (!clip) {
7195  quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
7196  while (mapHeight--) {
7197  for (int i = 0; i < mapWidth; ++i) {
7198  const int coverage = map[i];
7199 
7200  if (coverage == 0) {
7201  // nothing
7202  } else if (coverage == 255) {
7203  dest[i] = c;
7204  } else {
7205 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7206  if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
7207  && qAlpha(dest[i]) == 255) {
7208  grayBlendPixel(dest+i, coverage, sr, sg, sb);
7209  } else
7210 #endif
7211  {
7212  int ialpha = 255 - coverage;
7213  dest[i] = INTERPOLATE_PIXEL_255(c, coverage, dest[i], ialpha);
7214  }
7215  }
7216  }
7217  dest += destStride;
7218  map += mapStride;
7219  }
7220  } else {
7221  int bottom = qMin(y + mapHeight, rasterBuffer->height());
7222 
7223  int top = qMax(y, 0);
7224  map += (top - y) * mapStride;
7225 
7226  const_cast<QClipData *>(clip)->initialize();
7227  for (int yp = top; yp<bottom; ++yp) {
7228  const QClipData::ClipLine &line = clip->m_clipLines[yp];
7229 
7230  quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
7231 
7232  for (int i=0; i<line.count; ++i) {
7233  const QSpan &clip = line.spans[i];
7234 
7235  int start = qMax<int>(x, clip.x);
7236  int end = qMin<int>(x + mapWidth, clip.x + clip.len);
7237 
7238  for (int xp=start; xp<end; ++xp) {
7239  const int coverage = map[xp - x];
7240 
7241  if (coverage == 0) {
7242  // nothing
7243  } else if (coverage == 255) {
7244  dest[xp] = c;
7245  } else {
7246 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
7247  if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && opaque_src
7248  && qAlpha(dest[xp]) == 255) {
7249  grayBlendPixel(dest+xp, coverage, sr, sg, sb);
7250  } else
7251 #endif
7252  {
7253  int ialpha = 255 - coverage;
7254  dest[xp] = INTERPOLATE_PIXEL_255(c, coverage, dest[xp], ialpha);
7255  }
7256  }
7257 
7258  } // for (i -> line.count)
7259  } // for (yp -> bottom)
7260  map += mapStride;
7261  }
7262  }
7263 }
7264 
7265 static void qt_alphargbblit_quint32(QRasterBuffer *rasterBuffer,
7266  int x, int y, quint32 color,
7267  const uint *src, int mapWidth, int mapHeight, int srcStride,
7268  const QClipData *clip)
7269 {
7270  const quint32 c = color;
7271 
7272  int sr = qRed(color);
7273  int sg = qGreen(color);
7274  int sb = qBlue(color);
7275  int sa = qAlpha(color);
7276 
7277  sr = qt_pow_rgb_gamma[sr];
7278  sg = qt_pow_rgb_gamma[sg];
7279  sb = qt_pow_rgb_gamma[sb];
7280 
7281  if (sa == 0)
7282  return;
7283 
7284  if (!clip) {
7285  quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
7286  const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
7287  while (mapHeight--) {
7288  for (int i = 0; i < mapWidth; ++i) {
7289  const uint coverage = src[i];
7290  if (coverage == 0xffffffff) {
7291  dst[i] = c;
7292  } else if (coverage != 0xff000000) {
7293  rgbBlendPixel(dst+i, coverage, sr, sg, sb);
7294  }
7295  }
7296 
7297  dst += destStride;
7298  src += srcStride;
7299  }
7300  } else {
7301  int bottom = qMin(y + mapHeight, rasterBuffer->height());
7302 
7303  int top = qMax(y, 0);
7304  src += (top - y) * srcStride;
7305 
7306  const_cast<QClipData *>(clip)->initialize();
7307  for (int yp = top; yp<bottom; ++yp) {
7308  const QClipData::ClipLine &line = clip->m_clipLines[yp];
7309 
7310  quint32 *dst = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
7311 
7312  for (int i=0; i<line.count; ++i) {
7313  const QSpan &clip = line.spans[i];
7314 
7315  int start = qMax<int>(x, clip.x);
7316  int end = qMin<int>(x + mapWidth, clip.x + clip.len);
7317 
7318  for (int xp=start; xp<end; ++xp) {
7319  const uint coverage = src[xp - x];
7320  if (coverage == 0xffffffff) {
7321  dst[xp] = c;
7322  } else if (coverage != 0xff000000) {
7323  rgbBlendPixel(dst+xp, coverage, sr, sg, sb);
7324  }
7325  }
7326  } // for (i -> line.count)
7327  src += srcStride;
7328  } // for (yp -> bottom)
7329 
7330  }
7331 }
7332 
7333 template <class T>
7334 inline void qt_rectfill_template(QRasterBuffer *rasterBuffer,
7335  int x, int y, int width, int height,
7336  quint32 color, T dummy = 0)
7337 {
7338  Q_UNUSED(dummy);
7339 
7340  qt_rectfill<T>(reinterpret_cast<T*>(rasterBuffer->buffer()),
7341  qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0),
7342  x, y, width, height, rasterBuffer->bytesPerLine());
7343 }
7344 
7345 #define QT_RECTFILL(T) \
7346  inline static void qt_rectfill_##T(QRasterBuffer *rasterBuffer, \
7347  int x, int y, int width, int height, \
7348  quint32 color) \
7349  { \
7350  qt_rectfill_template<T>(rasterBuffer, x, y, width, height, color); \
7351  }
7352 
7363 #undef QT_RECTFILL
7364 
7365 inline static void qt_rectfill_nonpremul_quint32(QRasterBuffer *rasterBuffer,
7366  int x, int y, int width, int height,
7367  quint32 color)
7368 {
7369  qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
7370  INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine());
7371 }
7372 
7373 
7374 // Map table for destination image format. Contains function pointers
7375 // for blends of various types unto the destination
7376 
7377 DrawHelper qDrawHelper[QImage::NImageFormats] =
7378 {
7379  // Format_Invalid,
7380  { 0, 0, 0, 0, 0, 0 },
7381  // Format_Mono,
7382  {
7385  0, 0, 0, 0
7386  },
7387  // Format_MonoLSB,
7388  {
7391  0, 0, 0, 0
7392  },
7393  // Format_Indexed8,
7394  {
7397  0, 0, 0, 0
7398  },
7399  // Format_RGB32,
7400  {
7406  qt_rectfill_quint32
7407  },
7408  // Format_ARGB32,
7409  {
7416  },
7417  // Format_ARGB32_Premultiplied
7418  {
7424  qt_rectfill_quint32
7425  },
7426  // Format_RGB16
7427  {
7432  0,
7433  qt_rectfill_quint16
7434  },
7435  // Format_ARGB8565_Premultiplied
7436  {
7439  0, 0, 0,
7440  qt_rectfill_qargb8565
7441  },
7442  // Format_RGB666
7443  {
7446  0, 0, 0,
7447  qt_rectfill_qrgb666
7448  },
7449  // Format_ARGB6666_Premultiplied
7450  {
7453  0, 0, 0,
7454  qt_rectfill_qargb6666
7455  },
7456  // Format_RGB555
7457  {
7460  0, 0, 0,
7461  qt_rectfill_qrgb555
7462  },
7463  // Format_ARGB8555_Premultiplied
7464  {
7467  0, 0, 0,
7468  qt_rectfill_qargb8555
7469  },
7470  // Format_RGB888
7471  {
7474  0, 0, 0,
7475  qt_rectfill_qrgb888
7476  },
7477  // Format_RGB444
7478  {
7481  0, 0, 0,
7482  qt_rectfill_qrgb444
7483  },
7484  // Format_ARGB4444_Premultiplied
7485  {
7488  0, 0, 0,
7489  qt_rectfill_qargb4444
7490  }
7491 };
7492 
7493 #if defined (Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
7494 DrawHelper qDrawHelperCallback[QImage::NImageFormats] =
7495 {
7496  // Format_Invalid,
7497  { 0, 0, 0, 0, 0, 0 },
7498  // Format_Mono,
7499  {
7501  blend_src_generic<CallbackSpans>,
7502  0, 0, 0, 0
7503  },
7504  // Format_MonoLSB,
7505  {
7507  blend_src_generic<CallbackSpans>,
7508  0, 0, 0, 0
7509  },
7510  // Format_Indexed8,
7511  {
7513  blend_src_generic<CallbackSpans>,
7514  0, 0, 0, 0
7515  },
7516  // Format_RGB32,
7517  {
7519  blend_src_generic<CallbackSpans>,
7520  0, 0, 0, 0
7521  },
7522  // Format_ARGB32,
7523  {
7525  blend_src_generic<CallbackSpans>,
7526  0, 0, 0, 0
7527  },
7528  // Format_ARGB32_Premultiplied
7529  {
7531  blend_src_generic<CallbackSpans>,
7532  0, 0, 0, 0
7533  },
7534  // Format_RGB16
7535  {
7537  blend_src_generic<CallbackSpans>,
7538  0, 0, 0, 0
7539  },
7540  // Format_ARGB8565_Premultiplied
7541  {
7543  blend_src_generic<CallbackSpans>,
7544  0, 0, 0, 0
7545  },
7546  // Format_RGB666
7547  {
7549  blend_src_generic<CallbackSpans>,
7550  0, 0, 0, 0
7551  },
7552  // Format_ARGB6666_Premultiplied
7553  {
7555  blend_src_generic<CallbackSpans>,
7556  0, 0, 0, 0
7557  },
7558  // Format_RGB555
7559  {
7561  blend_src_generic<CallbackSpans>,
7562  0, 0, 0, 0
7563  },
7564  // Format_ARGB8555_Premultiplied
7565  {
7567  blend_src_generic<CallbackSpans>,
7568  0, 0, 0, 0
7569  },
7570  // Format_RGB888
7571  {
7573  blend_src_generic<CallbackSpans>,
7574  0, 0, 0, 0
7575  },
7576  // Format_RGB444
7577  {
7579  blend_src_generic<CallbackSpans>,
7580  0, 0, 0, 0
7581  },
7582  // Format_ARGB4444_Premultiplied
7583  {
7585  blend_src_generic<CallbackSpans>,
7586  0, 0, 0, 0
7587  }
7588 };
7589 #endif
7590 
7591 
7592 
7593 #if defined(Q_CC_MSVC) && !defined(_MIPS_)
7594 template <class DST, class SRC>
7595 inline void qt_memfill_template(DST *dest, SRC color, int count)
7596 {
7597  const DST c = qt_colorConvert<DST, SRC>(color, 0);
7598  while (count--)
7599  *dest++ = c;
7600 }
7601 
7602 #else
7603 
7604 template <class DST, class SRC>
7605 inline void qt_memfill_template(DST *dest, SRC color, int count)
7606 {
7607  const DST c = qt_colorConvert<DST, SRC>(color, 0);
7608  int n = (count + 7) / 8;
7609  switch (count & 0x07)
7610  {
7611  case 0: do { *dest++ = c;
7612  case 7: *dest++ = c;
7613  case 6: *dest++ = c;
7614  case 5: *dest++ = c;
7615  case 4: *dest++ = c;
7616  case 3: *dest++ = c;
7617  case 2: *dest++ = c;
7618  case 1: *dest++ = c;
7619  } while (--n > 0);
7620  }
7621 }
7622 
7623 template <>
7624 inline void qt_memfill_template(quint16 *dest, quint16 value, int count)
7625 {
7626  if (count < 3) {
7627  switch (count) {
7628  case 2: *dest++ = value;
7629  case 1: *dest = value;
7630  }
7631  return;
7632  }
7633 
7634  const int align = (quintptr)(dest) & 0x3;
7635  switch (align) {
7636  case 2: *dest++ = value; --count;
7637  }
7638 
7639  const quint32 value32 = (value << 16) | value;
7640  qt_memfill(reinterpret_cast<quint32*>(dest), value32, count / 2);
7641  if (count & 0x1)
7642  dest[count - 1] = value;
7643 }
7644 #endif
7645 
7646 static void qt_memfill_quint16(quint16 *dest, quint16 color, int count)
7647 {
7648  qt_memfill_template<quint16, quint16>(dest, color, count);
7649 }
7650 
7651 typedef void (*qt_memfill32_func)(quint32 *dest, quint32 value, int count);
7652 typedef void (*qt_memfill16_func)(quint16 *dest, quint16 value, int count);
7653 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count);
7654 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count);
7655 
7658 
7660 {
7661 
7662  qt_memfill32 = qt_memfill_template<quint32, quint32>;
7663  qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16, quint16>;
7664 
7665  CompositionFunction *functionForModeAsm = 0;
7666  CompositionFunctionSolid *functionForModeSolidAsm = 0;
7667 
7668  const uint features = qDetectCPUFeatures();
7669  if (false) {
7670 #ifdef QT_HAVE_SSE2
7671  } else if (features & SSE2) {
7672  qt_memfill32 = qt_memfill32_sse2;
7673  qt_memfill16 = qt_memfill16_sse2;
7674  qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2;
7675  qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2;
7676  qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2;
7677  qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2;
7678 #endif
7679 #ifdef QT_HAVE_SSE
7680  } else if (features & SSE) {
7681 // qt_memfill32 = qt_memfill32_sse;
7682  qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse;
7683 #ifdef QT_HAVE_3DNOW
7684  if (features & MMX3DNOW) {
7685  qt_memfill32 = qt_memfill32_sse3dnow;
7686  qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse3dnow;
7687  }
7688 #endif
7689 #endif // SSE
7690  }
7691 #ifdef QT_HAVE_MMX
7692  if (features & MMX) {
7693  functionForModeAsm = qt_functionForMode_MMX;
7694 
7695  functionForModeSolidAsm = qt_functionForModeSolid_MMX;
7696  qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx;
7697 #ifdef QT_HAVE_3DNOW
7698  if (features & MMX3DNOW) {
7699  functionForModeAsm = qt_functionForMode_MMX3DNOW;
7700  functionForModeSolidAsm = qt_functionForModeSolid_MMX3DNOW;
7701  qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_mmx3dnow;
7702  }
7703 #endif // 3DNOW
7704 
7705  extern void qt_blend_rgb32_on_rgb32_mmx(uchar *destPixels, int dbpl,
7706  const uchar *srcPixels, int sbpl,
7707  int w, int h,
7708  int const_alpha);
7709  extern void qt_blend_argb32_on_argb32_mmx(uchar *destPixels, int dbpl,
7710  const uchar *srcPixels, int sbpl,
7711  int w, int h,
7712  int const_alpha);
7713 
7714  qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mmx;
7718 
7719  }
7720 #endif // MMX
7721 
7722 #ifdef QT_HAVE_SSE
7723  if (features & SSE) {
7724  extern void qt_blend_rgb32_on_rgb32_sse(uchar *destPixels, int dbpl,
7725  const uchar *srcPixels, int sbpl,
7726  int w, int h,
7727  int const_alpha);
7728  extern void qt_blend_argb32_on_argb32_sse(uchar *destPixels, int dbpl,
7729  const uchar *srcPixels, int sbpl,
7730  int w, int h,
7731  int const_alpha);
7732 
7733  qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse;
7737  }
7738 #endif // SSE
7739 
7740 #ifdef QT_HAVE_SSE2
7741  if (features & SSE2) {
7742  extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
7743  const uchar *srcPixels, int sbpl,
7744  int w, int h,
7745  int const_alpha);
7746  extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
7747  const uchar *srcPixels, int sbpl,
7748  int w, int h,
7749  int const_alpha);
7750 
7751  qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
7755 
7756  extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
7757  int y, int x, int length);
7758 
7759  qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2;
7760  }
7761 
7762 #ifdef QT_HAVE_SSSE3
7763  if (features & SSSE3) {
7764  extern void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
7765  const uchar *srcPixels, int sbpl,
7766  int w, int h,
7767  int const_alpha);
7768 
7769  qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
7771  }
7772 #endif // SSSE3
7773 
7774 #endif // SSE2
7775 
7776 #ifdef QT_HAVE_SSE
7777  if (features & SSE) {
7778  functionForModeAsm = qt_functionForMode_SSE;
7779  functionForModeSolidAsm = qt_functionForModeSolid_SSE;
7780  qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse;
7781 #ifdef QT_HAVE_3DNOW
7782  if (features & MMX3DNOW) {
7783  functionForModeAsm = qt_functionForMode_SSE3DNOW;
7784  functionForModeSolidAsm = qt_functionForModeSolid_SSE3DNOW;
7785  qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse3dnow;
7786  }
7787 #endif // 3DNOW
7788 
7789 
7790 #ifdef QT_HAVE_SSE2
7791  if (features & SSE2) {
7792  extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels,
7793  const uint *srcPixels,
7794  int length,
7795  uint const_alpha);
7796  extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha);
7797  extern void QT_FASTCALL comp_func_Plus_sse2(uint *dst, const uint *src, int length, uint const_alpha);
7798  extern void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, uint const_alpha);
7799 
7800  functionForModeAsm[0] = comp_func_SourceOver_sse2;
7801  functionForModeAsm[QPainter::CompositionMode_Source] = comp_func_Source_sse2;
7802  functionForModeAsm[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2;
7803  functionForModeSolidAsm[0] = comp_func_solid_SourceOver_sse2;
7804  }
7805 #endif
7806  }
7807 #elif defined(QT_HAVE_SSE2)
7808  // this is the special case when SSE2 is usable but MMX/SSE is not usable (e.g.: Windows x64 + visual studio)
7809  if (features & SSE2) {
7810  functionForModeAsm = qt_functionForMode_onlySSE2;
7811  functionForModeSolidAsm = qt_functionForModeSolid_onlySSE2;
7812  }
7813 #endif
7814 
7815 #ifdef QT_HAVE_IWMMXT
7816  if (features & IWMMXT) {
7817  functionForModeAsm = qt_functionForMode_IWMMXT;
7818  functionForModeSolidAsm = qt_functionForModeSolid_IWMMXT;
7819  qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_iwmmxt;
7820  }
7821 #endif // IWMMXT
7822 
7823 #if defined(QT_HAVE_ARM_SIMD)
7824  qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_arm_simd;
7825  qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_arm_simd;
7826  qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_arm_simd;
7828 #elif defined(QT_HAVE_NEON)
7829  if (features & NEON) {
7830  qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon;
7836  qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon;
7837 
7838  qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon;
7839  qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon;
7840 
7841  qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon;
7842  qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon;
7843 
7844  qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon;
7845 
7846  functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon;
7847  functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon;
7848  functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon;
7849  destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
7850  destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
7851 
7852  qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
7853  qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
7854  qt_memfill32 = qt_memfill32_neon;
7855 
7856  extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data,
7857  int y, int x, int length);
7858 
7859  qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon;
7860  }
7861 #endif
7862 
7863  if (functionForModeSolidAsm) {
7864  const int destinationMode = QPainter::CompositionMode_Destination;
7865  functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode];
7866 
7867  // use the default qdrawhelper implementation for the
7868  // extended composition modes
7869  for (int mode = 12; mode < 24; ++mode)
7870  functionForModeSolidAsm[mode] = functionForModeSolid_C[mode];
7871 
7872  functionForModeSolid = functionForModeSolidAsm;
7873  }
7874  if (functionForModeAsm)
7875  functionForMode = functionForModeAsm;
7876 
7878 }
7879 
7880 static void qt_memfill32_setup(quint32 *dest, quint32 value, int count)
7881 {
7883  qt_memfill32(dest, value, count);
7884 }
7885 
7886 static void qt_memfill16_setup(quint16 *dest, quint16 value, int count)
7887 {
7889  qt_memfill16(dest, value, count);
7890 }
7891 
7892 #ifdef QT_QWS_DEPTH_GENERIC
7893 
7894 int qrgb::bpp = 0;
7895 int qrgb::len_red = 0;
7896 int qrgb::len_green = 0;
7897 int qrgb::len_blue = 0;
7898 int qrgb::len_alpha = 0;
7899 int qrgb::off_red = 0;
7900 int qrgb::off_green = 0;
7901 int qrgb::off_blue = 0;
7902 int qrgb::off_alpha = 0;
7903 
7904 template <typename SRC>
7905 Q_STATIC_TEMPLATE_FUNCTION inline void qt_rectconvert_rgb(qrgb *dest, const SRC *src,
7906  int x, int y, int width, int height,
7907  int dstStride, int srcStride)
7908 {
7909  quint8 *dest8 = reinterpret_cast<quint8*>(dest)
7910  + y * dstStride + x * qrgb::bpp;
7911 
7912  srcStride = srcStride / sizeof(SRC) - width;
7913  dstStride -= (width * qrgb::bpp);
7914 
7915  for (int j = 0; j < height; ++j) {
7916  for (int i = 0; i < width; ++i) {
7917  const quint32 v = qt_convertToRgb<SRC>(*src++);
7918 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
7919  for (int j = qrgb::bpp - 1; j >= 0; --j)
7920  *dest8++ = (v >> (8 * j)) & 0xff;
7921 #else
7922  for (int j = 0; j < qrgb::bpp; ++j)
7923  *dest8++ = (v >> (8 * j)) & 0xff;
7924 #endif
7925  }
7926 
7927  dest8 += dstStride;
7928  src += srcStride;
7929  }
7930 }
7931 
7932 template <>
7933 void qt_rectconvert(qrgb *dest, const quint32 *src,
7934  int x, int y, int width, int height,
7935  int dstStride, int srcStride)
7936 {
7937  qt_rectconvert_rgb<quint32>(dest, src, x, y, width, height,
7938  dstStride, srcStride);
7939 }
7940 
7941 template <>
7942 void qt_rectconvert(qrgb *dest, const quint16 *src,
7943  int x, int y, int width, int height,
7944  int dstStride, int srcStride)
7945 {
7946  qt_rectconvert_rgb<quint16>(dest, src, x, y, width, height,
7947  dstStride, srcStride);
7948 }
7949 
7950 #endif // QT_QWS_DEPTH_GENERIC
7951 
qt_memfill16_func qt_memfill16
void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
Q_STATIC_TEMPLATE_FUNCTION void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2)
const uint *QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length)
double d
Definition: qnumeric_p.h:62
Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_argb(int count, const QSpan *spans, void *userData)
void qBlendTextureCallback(int count, const QSpan *spans, void *userData)
void(* qt_memfill32_func)(quint32 *dest, quint32 value, int count)
static uint *QT_FASTCALL destFetchARGB32P(uint *, QRasterBuffer *rasterBuffer, int x, int y, int)
static void blend_transformed_tiled_rgb666(int count, const QSpan *spans, void *userData)
DestStoreProc dest_store
const uint *(QT_FASTCALL * SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length)
static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_Overlay_impl(uint *dest, const uint *src, int length, const T &coverage)
Q_STATIC_INLINE_FUNCTION uint BYTE_MUL_RGB16(uint x, uint a)
Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans, void *userData)
QImage::Format format
unsigned int QRgb
Definition: qrgb.h:53
static void blend_color_argb(int count, const QSpan *spans, void *userData)
qt_memfill32_func qt_memfill32
void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, int length, uint color, uint const_alpha)
Q_STATIC_TEMPLATE_FUNCTION uint QT_FASTCALL qt_fetchPixel(const uchar *scanLine, int x, const QVector< QRgb > *rgb)
double qreal
Definition: qglobal.h:1193
QIntegerForSizeof< void * >::Unsigned quintptr
Definition: qglobal.h:986
AlphamapBlitFunc alphamapBlit
void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha)
static uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, int distx, int disty)
void interpolate_pixel_4(DST *dest, const SRC *src, quint32 alpha)
unsigned char c[8]
Definition: qnumeric_p.h:62
void qt_rectconvert(DST *dest, const SRC *src, int x, int y, int width, int height, int dstStride, int srcStride)
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
unsigned char coverage
static void blend_tiled_rgb666(int count, const QSpan *spans, void *userData)
void QT_FASTCALL comp_func_Difference(uint *dest, const uint *src, int length, uint const_alpha)
#define GRADIENT_STOPTABLE_SIZE
Q_STATIC_TEMPLATE_SPECIALIZATION void madd_4(DST *dest, const quint32 alpha, const SRC *src)
static void blend_untransformed_argb8565(int count, const QSpan *spans, void *userData)
uchar qt_pow_rgb_gamma[256]
static const ProcessSpans processTextureSpansCallback[NBlendTypes][QImage::NImageFormats]
static void blend_tiled_rgb888(int count, const QSpan *spans, void *userData)
CompositionMode
Defines the modes supported for digital image compositing.
Definition: qpainter.h:138
void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha)
static void blend_transformed_tiled_rgb888(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_Multiply_impl(uint *dest, const uint *src, int length, const T &coverage)
int qCeil(qreal v)
Definition: qmath.h:63
static Operator getOperator(const QSpanData *data, const QSpan *spans, int spanCount)
static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage)
static const uint *QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length)
quint16 rawValue() const
Q_GUI_EXPORT_INLINE int qAlpha(QRgb rgb)
Definition: qrgb.h:66
BitmapBlitFunc bitmapBlit
unsigned short len
void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha)
static int lighten_op(int dst, int src, int da, int sa)
Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *spans, void *userData)
static int multiply_op(int dst, int src, int da, int sa)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_HardLight_impl(uint *dest, const uint *src, int length, const T &coverage)
#define SPANFUNC_POINTER(Name, Arg)
static void blend_transformed_tiled_argb6666(int count, const QSpan *spans, void *userData)
static void qt_rectfill_nonpremul_quint32(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, quint32 color)
Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_generic(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_Difference_impl(uint *dest, const uint *src, int length, const T &coverage)
void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha)
void(QT_FASTCALL * DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
static SourceFetchProc qt_fetch_radial_gradient
static quint16 interpolate_pixel_rgb16_255(quint16 x, quint8 a, quint16 y, quint8 b)
static const FetchPixelProc fetchPixelProc[QImage::NImageFormats]
void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha)
QSpanData * data
static void qt_memfill_quint16(quint16 *dest, quint16 color, int count)
#define Q_WS_WIN
Defined on Windows.
Definition: qglobal.h:921
const uint * fetch(int x, int y, int len)
static void blend_transformed_bilinear_argb8565(int count, const QSpan *spans, void *userData)
void store(uint *dest, const uint src) const
void qt_bitmapblit_template(QRasterBuffer *rasterBuffer, int x, int y, quint32 color, const uchar *map, int mapWidth, int mapHeight, int mapStride, DST dummy=0)
#define QT_MEMFILL_USHORT(dest, length, color)
Q_STATIC_TEMPLATE_SPECIALIZATION quint32 eff_alpha_4(quint32 alpha, const T *)
static int overlay_op(int dst, int src, int da, int sa)
void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha)
QT_FT_SpanFunc ProcessSpans
Definition: qsimd_p.h:217
static void blend_transformed_bilinear_argb6666(int count, const QSpan *spans, void *userData)
void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest, int length, uint color, uint const_alpha)
#define BILINEAR_DOWNSCALE_BOUNDS_PROLOG
static CompositionFunction functionForMode_C[]
uint qt_pow_gamma[256]
static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage)
void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha)
void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_ColorBurn_impl(uint *dest, const uint *src, int length, const T &coverage)
void QT_FASTCALL rasterop_SourceXorDestination(uint *dest, const uint *src, int length, uint const_alpha)
static uint hardlight_op(int dst, int src, int da, int sa)
static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
long ASN1_INTEGER_get ASN1_INTEGER * a
unsigned char quint8
Definition: qglobal.h:934
SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats]
void QT_FASTCALL blendUntransformed_unaligned(DST *dest, const SRC *src, quint8 coverage, int length)
void process(int x, int y, int len, int coverage, const uint *src, int offset)
#define OP(a, b)
MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3]
Definition: qmemrotate.cpp:627
static void blend_transformed_argb6666(int count, const QSpan *spans, void *userData)
void qt_build_pow_tables()
static const WinVersion WindowsVersion
the version of the Windows operating system on which the application is run (Windows only) ...
Definition: qglobal.h:1613
#define Q_STATIC_TEMPLATE_FUNCTION
Definition: qdrawhelper_p.h:85
int bytesPerLine() const
void interpolate_pixel_unaligned_2(DST *dest, const SRC *src, quint16 alpha)
QBlendBase(QSpanData *d, Operator o)
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
static uint qt_gradient_pixel(const QGradientData *data, qreal pos)
void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha)
void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha)
QSolidData solid
int qIntSqrtInt(int v)
Definition: qmath_p.h:65
void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha)
void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint)
void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *dest, const uint *src, int length, uint const_alpha)
static uint qt_gradient_clamp(const QGradientData *data, int ipos)
#define QT_FASTCALL
Definition: qglobal.h:1161
void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha)
static void blend_transformed_rgb444(int count, const QSpan *spans, void *userData)
static uint *QT_FASTCALL destFetchARGB32(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
int qRed(QRgb rgb)
Returns the red component of the ARGB quadruplet rgb.
Definition: qrgb.h:57
void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest, int length, uint color, uint const_alpha)
static void qt_bitmapblit_quint32(QRasterBuffer *rasterBuffer, int x, int y, quint32 color, const uchar *map, int mapWidth, int mapHeight, int mapStride)
static void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb)
static quint32 interpolate_pixel_rgb16x2_255(quint32 x, quint8 a, quint32 y, quint8 b)
QPainter::CompositionMode compositionMode
static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage)
Q_CORE_EXPORT QTextStream & right(QTextStream &s)
#define SPANFUNC_POINTER_FETCHPIXEL(Arg)
void QT_FASTCALL rasterop_SourceOrDestination(uint *dest, const uint *src, int length, uint const_alpha)
static void blend_transformed_tiled_argb4444(int count, const QSpan *spans, void *userData)
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha)
static void blend_tiled_argb8565(int count, const QSpan *spans, void *userData)
ProcessSpans blendColor
Q_GUI_EXPORT_INLINE int qRed(QRgb rgb)
Definition: qrgb.h:57
void QT_FASTCALL comp_func_HardLight(uint *dest, const uint *src, int length, uint const_alpha)
struct QConicalGradientData::@233 center
const uchar * imageData
static int difference_op(int dst, int src, int da, int sa)
int qAlpha(QRgb rgba)
Returns the alpha component of the ARGB quadruplet rgba.
Definition: qrgb.h:66
Definition: qsimd_p.h:212
void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha)
#define QT_MEMFILL_UINT(dest, length, color)
static const CompositionFunctionSolid * functionForModeSolid
static uint *QT_FASTCALL destFetchMonoLsb(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
Q_STATIC_TEMPLATE_SPECIALIZATION void madd_2(DST *dest, const quint16 alpha, const SRC *src)
void qBlendTexture(int count, const QSpan *spans, void *userData)
CompositionFunction func
unsigned char uchar
Definition: qglobal.h:994
void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha)
quint16 rawValue() const
#define Q_STATIC_TEMPLATE_SPECIALIZATION
Definition: qdrawhelper_p.h:77
QPartialCoverage(uint const_alpha)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage)
Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b)
Q_STATIC_INLINE_FUNCTION uint BYTE_MUL(uint x, uint a)
QFuture< void > map(Sequence &sequence, MapFunction function)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static uint *QT_FASTCALL destFetchRGB16(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
Q_GUI_EXPORT_INLINE QRgb qRgba(int r, int g, int b, int a)
Definition: qrgb.h:72
SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFormats]
#define QT_RECTFILL(T)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_Lighten_impl(uint *dest, const uint *src, int length, const T &coverage)
static void blend_tiled_argb6666(int count, const QSpan *spans, void *userData)
static void qt_gradient_quint16(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage)
static DestStoreProc destStoreProc[QImage::NImageFormats]
Q_STATIC_TEMPLATE_FUNCTION void blend_src_generic(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_Exclusion_impl(uint *dest, const uint *src, int length, const T &coverage)
static void blend_transformed_bilinear_rgb555(int count, const QSpan *spans, void *userData)
void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
void QT_FASTCALL blendUntransformed_dest24(DST *dest, const SRC *src, quint8 coverage, int length)
void QT_FASTCALL rasterop_NotSourceXorDestination(uint *dest, const uint *src, int length, uint const_alpha)
Q_STATIC_INLINE_FUNCTION uint PREMUL(uint x)
void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha)
static int mix_alpha(int da, int sa)
static void blend_transformed_tiled_argb8555(int count, const QSpan *spans, void *userData)
void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *dest, const uint *src, int length, uint const_alpha)
struct QClipData::ClipLine * m_clipLines
Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b)
void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha)
static void blend_transformed_bilinear_argb8555(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_SPECIALIZATION quint16 alpha_2(const T *src)
Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *spans, void *userData)
#define SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Arg)
RadialGradientValues radial
void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha)
#define QT_PREPEND_NAMESPACE(name)
This macro qualifies identifier with the full namespace.
Definition: qglobal.h:87
static void QT_FASTCALL destStoreARGB32(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
static void blend_untransformed_rgb444(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_SPECIALIZATION void QT_FASTCALL blendUntransformed(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan *spans, void *userData)
unsigned short quint16
Definition: qglobal.h:936
static void blend_untransformed_rgb565(int count, const QSpan *spans, void *userData)
void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha)
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
#define FIXPT_BITS
Q_STATIC_TEMPLATE_FUNCTION void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage)
static void QT_FASTCALL destStoreMono(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
Q_GUI_EXPORT qreal qt_fontsmoothing_gamma
qreal qAtan2(qreal x, qreal y)
Definition: qmath.h:189
void QT_FASTCALL comp_func_Multiply(uint *dest, const uint *src, int length, uint const_alpha)
static TextureBlendType getBlendType(const QSpanData *data)
void store(uint *dest, const uint src) const
static void blend_tiled_rgb555(int count, const QSpan *spans, void *userData)
int qGray(int r, int g, int b)
Definition: qrgb.h:75
static void drawBufferSpan(QSpanData *data, const uint *buffer, int bufsize, int x, int y, int length, uint const_alpha)
void QT_FASTCALL comp_func_ColorDodge(uint *dest, const uint *src, int length, uint const_alpha)
static void blend_transformed_argb8565(int count, const QSpan *spans, void *userData)
void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha)
uchar * scanLine(int y)
static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
DrawHelper qDrawHelper[QImage::NImageFormats]
static void qt_alphamapblit_quint32(QRasterBuffer *rasterBuffer, int x, int y, quint32 color, const uchar *map, int mapWidth, int mapHeight, int mapStride, const QClipData *clip)
#define PRELOAD_INIT(x)
Q_STATIC_TEMPLATE_SPECIALIZATION quint16 eff_ialpha_2(quint16 alpha, const T *)
static void blend_transformed_rgb555(int count, const QSpan *spans, void *userData)
Q_GUI_EXPORT_INLINE int qBlue(QRgb rgb)
Definition: qrgb.h:63
#define PRELOAD_COND(x)
qreal qPow(qreal x, qreal y)
Definition: qmath.h:244
QConicalGradientData conical
static void blend_sourceOver_rgb16_rgb16(quint16 *dest, const quint16 *src, int length, const quint8 alpha, const quint8 ialpha)
Q_STATIC_TEMPLATE_FUNCTION void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
static void blend_transformed_argb8555(int count, const QSpan *spans, void *userData)
static DestFetchProc destFetchProc[QImage::NImageFormats]
static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats]
void interpolate_pixel(DST &dest, quint8 a, const SRC &src, quint8 b)
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha)
DrawHelper qDrawHelperCallback[QImage::NImageFormats]
BlendSrcGeneric(QSpanData *d, Operator o)
#define rgb(r, g, b)
Definition: qcolor_p.cpp:130
Q_STATIC_TEMPLATE_FUNCTION void comp_func_Screen_impl(uint *dest, const uint *src, int length, const T &coverage)
static void blend_color_generic_callback(int count, const QSpan *spans, void *userData)
static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer, int x, int y, quint32 color, const uchar *map, int mapWidth, int mapHeight, int mapStride)
DestFetchProc dest_fetch
QRgb qConvertRgb16To32(uint c)
static void qt_memfill32_setup(quint32 *dest, quint32 value, int count)
const uint qt_bayer_matrix[16][16]
static void blend_transformed_tiled_argb8565(int count, const QSpan *spans, void *userData)
Q_GUI_EXPORT_INLINE int qGray(int r, int g, int b)
Definition: qrgb.h:75
void QT_FASTCALL comp_func_Overlay(uint *dest, const uint *src, int length, uint const_alpha)
static void blend_transformed_bilinear_argb4444(int count, const QSpan *spans, void *userData)
void QT_FASTCALL comp_func_ColorBurn(uint *dest, const uint *src, int length, uint const_alpha)
static void blend_untransformed_argb8555(int count, const QSpan *spans, void *userData)
qreal angle(const QPointF &p1, const QPointF &p2)
const uchar * scanLine(int y) const
static const uint *QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data, int y, int x, int length)
uint(QT_FASTCALL * FetchPixelProc)(const uchar *scanLine, int x, const QVector< QRgb > *)
#define SPANFUNC_POINTER_DESTFETCH(Arg)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage)
void QT_FASTCALL comp_func_Plus(uint *dest, const uint *src, int length, uint const_alpha)
void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest, int length, uint color, uint const_alpha)
#define FIXPT_SIZE
static void blend_untransformed_rgb666(int count, const QSpan *spans, void *userData)
virtual void drawBufferSpan(const uint *buffer, int bufsize, int x, int y, int length, uint const_alpha)
Draws the given buffer.
#define PRELOAD_COND2(x, y)
QRasterPaintEngine * rasterEngine
void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha)
Operator op
Q_STATIC_TEMPLATE_FUNCTION void blendColor(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage)
Q_STATIC_INLINE_FUNCTION quint32p fromRawData(quint32 v)
QRasterBuffer * rasterBuffer
void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int length, uint const_alpha)
void qt_memconvert(DST *dest, const SRC *src, int count)
uint qDetectCPUFeatures()
Definition: qsimd.cpp:382
void QT_FASTCALL comp_func_Darken(uint *dest, const uint *src, int length, uint const_alpha)
unsigned short ushort
Definition: qglobal.h:995
Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
void(QT_FASTCALL * CompositionFunction)(uint *dest, const uint *src, int length, uint const_alpha)
void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
struct QLinearGradientData::@229 origin
static void blend_transformed_bilinear_rgb666(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION uint *QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
Q_GUI_EXPORT_INLINE QRgb qRgb(int r, int g, int b)
Definition: qrgb.h:69
void QT_FASTCALL blendUntransformed_dest16(DST *dest, const SRC *src, quint8 coverage, int length)
static void qt_alphargbblit_quint32(QRasterBuffer *rasterBuffer, int x, int y, quint32 color, const uint *src, int mapWidth, int mapHeight, int srcStride, const QClipData *clip)
void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha)
QGradientData gradient
void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest, int length, uint color, uint const_alpha)
struct QRadialGradientData::@232 focal
void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest, int length, uint color, uint const_alpha)
static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer, int x, int y, quint32 color, const uchar *map, int mapWidth, int mapHeight, int mapStride, const QClipData *)
unsigned int quint32
Definition: qglobal.h:938
void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha)
static void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det, qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b)
SpanMethod
Q_STATIC_TEMPLATE_FUNCTION void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage)
Definition: qsimd_p.h:222
static CompositionFunctionSolid functionForModeSolid_C[]
void QT_FASTCALL rasterop_NotSource(uint *dest, const uint *src, int length, uint const_alpha)
#define PRELOAD_INIT2(x, y)
void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha)
if(void) toggleToolbarShown
void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha)
static void blend_color_generic(int count, const QSpan *spans, void *userData)
static void blend_transformed_tiled_rgb555(int count, const QSpan *spans, void *userData)
static int color_burn_op(int dst, int src, int da, int sa)
QFactoryLoader * l
Q_STATIC_TEMPLATE_FUNCTION void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage)
ushort qConvertRgb32To16(uint c)
void(QT_FASTCALL * CompositionFunctionSolid)(uint *dest, int length, uint color, uint const_alpha)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_ColorDodge_impl(uint *dest, const uint *src, int length, const T &coverage)
static const int buffer_size
Definition: qdrawhelper.cpp:80
quint16 rawValue() const
int comp_func_Plus_one_pixel(uint d, const uint s)
uchar qt_pow_invgamma[2048]
Q_STATIC_TEMPLATE_FUNCTION void comp_func_SoftLight_impl(uint *dest, const uint *src, int length, const T &coverage)
void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_Plus_impl(uint *dest, const uint *src, int length, const T &coverage)
Q_GUI_EXPORT_INLINE int qGreen(QRgb rgb)
Definition: qrgb.h:60
void qt_rectfill_template(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, quint32 color, T dummy=0)
LinearGradientValues linear
void(* qt_memfill16_func)(quint16 *dest, quint16 value, int count)
void QT_FASTCALL rasterop_SourceAndNotDestination(uint *dest, const uint *src, int length, uint const_alpha)
#define SPANFUNC_POINTER_BLENDCOLOR(DST)
Q_STATIC_INLINE_FUNCTION int qt_div_255(int x)
#define comp_func_Clear_impl(dest, length, const_alpha)
void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha)
SourceFetchProc src_fetch
const QVector< QRgb > * colorTable
QRadialGradientData radial
struct QLinearGradientData::@230 end
static void blend_transformed_rgb888(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_SPECIALIZATION quint16 eff_alpha_2(quint16 alpha, const T *)
static Q_DECL_CONSTEXPR bool qFuzzyIsNull(double d)
Definition: qglobal.h:2043
void qInitDrawhelperAsm()
CompositionFunctionSolid funcSolid
Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha)
uchar * buffer() const
void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest, int length, uint color, uint const_alpha)
void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest, int length, uint color, uint const_alpha)
static void blend_transformed_rgb666(int count, const QSpan *spans, void *userData)
static const CompositionFunction * functionForMode
void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length, uint color, uint const_alpha)
static void blend_transformed_argb4444(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_Darken_impl(uint *dest, const uint *src, int length, const T &coverage)
#define INV_PREMUL(p)
static void blend_untransformed_rgb555(int count, const QSpan *spans, void *userData)
static void QT_FASTCALL destStoreMonoLsb(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
Q_STATIC_TEMPLATE_FUNCTION const uint *QT_FASTCALL qt_fetchUntransformed(uint *buffer, const Operator *, const QSpanData *data, int y, int x, int length)
Q_STATIC_TEMPLATE_FUNCTION const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *, const QSpanData *data, int y, int x, int length)
void blend_sourceOver_4(DST *dest, const SRC *src)
Definition: qsimd_p.h:220
void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length, uint const_alpha)
void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha)
static int soft_light_op(int dst, int src, int da, int sa)
static void blend_transformed_bilinear_rgb888(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QSpan *spans, void *userData)
void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha)
static void blend_tiled_argb4444(int count, const QSpan *spans, void *userData)
static void blend_transformed_bilinear_rgb444(int count, const QSpan *spans, void *userData)
int qGreen(QRgb rgb)
Returns the green component of the ARGB quadruplet rgb.
Definition: qrgb.h:60
static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
static void blend_transformed_tiled_rgb444(int count, const QSpan *spans, void *userData)
static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats]
uchar qt_pow_rgb_invgamma[256]
void QT_FASTCALL rasterop_NotSourceAndDestination(uint *dest, const uint *src, int length, uint const_alpha)
QImageIOHandler * handler
static QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
QLinearGradientData linear
Q_STATIC_TEMPLATE_FUNCTION void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage)
int qBlue(QRgb rgb)
Returns the blue component of the ARGB quadruplet rgb.
Definition: qrgb.h:63
static void qt_memfill16_setup(quint16 *dest, quint16 value, int count)
static const KeyPair *const end
void interpolate_pixel_2(DST *dest, const SRC *src, quint16 alpha)
void QT_FASTCALL comp_func_Lighten(uint *dest, const uint *src, int length, uint const_alpha)
Q_STATIC_TEMPLATE_FUNCTION const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data, int y, int x, int length)
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
qreal qSqrt(qreal v)
Definition: qmath.h:205
void store(int x, int y, int len)
enum QSpanData::Type type
struct QRadialGradientData::@231 center
static void blend_tiled_rgb444(int count, const QSpan *spans, void *userData)
static void blend_untransformed_rgb888(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_SPECIALIZATION quint32 eff_ialpha_4(quint32 alpha, const T *)
#define INT_MAX
static void blend_untransformed_argb6666(int count, const QSpan *spans, void *userData)
static int color_dodge_op(int dst, int src, int da, int sa)
void qt_memfill_template(DST *dest, SRC color, int count)
SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats]
Q_STATIC_INLINE_FUNCTION uint BYTE_MUL_RGB16_32(uint x, uint a)
static int darken_op(int dst, int src, int da, int sa)
static uint *QT_FASTCALL destFetchMono(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
Definition: qdrawhelper.cpp:87
Definition: qsimd_p.h:216
Q_DECL_CONSTEXPR int qRound(qreal d)
Definition: qglobal.h:1203
static void blend_tiled_argb8555(int count, const QSpan *spans, void *userData)
void QT_FASTCALL rasterop_SourceAndDestination(uint *dest, const uint *src, int length, uint const_alpha)
#define SPANFUNC_POINTER_DESTSTORE(DEST)
static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void *userData)
QImage::Format format
TextureBlendType
QPainter::CompositionMode mode
void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha)
void qt_memfill(T *dest, T value, int count)
static void qt_gradient_quint32(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_SPECIALIZATION quint32 alpha_4(const T *src)
QTextureData texture
uint *QT_FASTCALL * DestFetchProc(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *userData)
Q_STATIC_TEMPLATE_FUNCTION void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage)
void QT_FASTCALL comp_func_SoftLight(uint *dest, const uint *src, int length, uint const_alpha)
static void blend_untransformed_argb4444(int count, const QSpan *spans, void *userData)
static void blend_transformed_rgb565(int count, const QSpan *spans, void *userData)
static const qreal Q_PI
Definition: qmath_p.h:61