1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <qglobal.h>
41#include "qdrawhelper_p.h"
42#include "qrgba64_p.h"
43
44QT_BEGIN_NAMESPACE
45
46/* The constant alpha factor describes an alpha factor that gets applied
47 to the result of the composition operation combining it with the destination.
48
49 The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1.
50 we get the unmodified operation
51
52 result = src op dest
53 dest = result * const_alpha + dest * (1. - const_alpha)
54
55 This means that in the comments below, the first line is the const_alpha==255 case, the
56 second line the general one.
57
58 In the lines below:
59 s == src, sa == alpha(src), sia = 1 - alpha(src)
60 d == dest, da == alpha(dest), dia = 1 - alpha(dest)
61 ca = const_alpha, cia = 1 - const_alpha
62
63 The methods exist in two variants. One where we have a constant source, the other
64 where the source is an array of pixels.
65*/
66
67struct Argb32OperationsC
68{
69 typedef QRgb Type;
70 typedef quint8 Scalar;
71 typedef QRgb OptimalType;
72 typedef quint8 OptimalScalar;
73
74 static const Type clear;
75 static bool isOpaque(Type val)
76 { return qAlpha(val) == 255; }
77 static bool isTransparent(Type val)
78 { return qAlpha(val) == 0; }
79 static Scalar scalarFrom8bit(uint8_t a)
80 { return a; }
81 static void memfill(Type *ptr, Type value, qsizetype len)
82 { qt_memfill32(ptr, value, len); }
83 static void memcpy(Type *Q_DECL_RESTRICT dest, const Type *Q_DECL_RESTRICT src, qsizetype len)
84 { ::memcpy(dest, src, len * sizeof(Type)); }
85
86 static OptimalType load(const Type *ptr)
87 { return *ptr; }
88 static OptimalType convert(const Type &val)
89 { return val; }
90 static void store(Type *ptr, OptimalType value)
91 { *ptr = value; }
92 static OptimalType add(OptimalType a, OptimalType b)
93 { return a + b; }
94 static OptimalScalar add(OptimalScalar a, OptimalScalar b)
95 { return a + b; }
96 static OptimalType plus(OptimalType a, OptimalType b)
97 { return comp_func_Plus_one_pixel(a, b); }
98 static OptimalScalar alpha(OptimalType val)
99 { return qAlpha(val); }
100 static OptimalScalar invAlpha(OptimalScalar c)
101 { return 255 - c; }
102 static OptimalScalar invAlpha(OptimalType val)
103 { return alpha(~val); }
104 static OptimalScalar scalar(Scalar v)
105 { return v; }
106 static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a)
107 { return BYTE_MUL(val, a); }
108 static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2)
109 { return INTERPOLATE_PIXEL_255(x, a1, y, a2); }
110 static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a)
111 { return BYTE_MUL(val, a); }
112 static OptimalScalar multiplyAlpha8bit(OptimalScalar val, uint8_t a)
113 { return qt_div_255(val * a); }
114 static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2)
115 { return INTERPOLATE_PIXEL_255(x, a1, y, a2); }
116};
117
118const Argb32OperationsC::Type Argb32OperationsC::clear = 0;
119
120struct Rgba64OperationsBase
121{
122 typedef QRgba64 Type;
123 typedef quint16 Scalar;
124
125 static const Type clear;
126
127 static bool isOpaque(Type val)
128 { return val.isOpaque(); }
129 static bool isTransparent(Type val)
130 { return val.isTransparent(); }
131 static Scalar scalarFrom8bit(uint8_t a)
132 { return a * 257; }
133
134 static void memfill(Type *ptr, Type value, qsizetype len)
135 { qt_memfill64((quint64*)ptr, value, len); }
136 static void memcpy(Type *Q_DECL_RESTRICT dest, const Type *Q_DECL_RESTRICT src, qsizetype len)
137 { ::memcpy(dest, src, len * sizeof(Type)); }
138};
139
140#if QT_CONFIG(raster_64bit)
141const Rgba64OperationsBase::Type Rgba64OperationsBase::clear = QRgba64::fromRgba64(0);
142
143struct Rgba64OperationsC : public Rgba64OperationsBase
144{
145 typedef QRgba64 OptimalType;
146 typedef quint16 OptimalScalar;
147
148 static OptimalType load(const Type *ptr)
149 { return *ptr; }
150 static OptimalType convert(const Type &val)
151 { return val; }
152 static void store(Type *ptr, OptimalType value)
153 { *ptr = value; }
154 static OptimalType add(OptimalType a, OptimalType b)
155 { return QRgba64::fromRgba64((quint64)a + (quint64)b); }
156 static OptimalScalar add(OptimalScalar a, OptimalScalar b)
157 { return a + b; }
158 static OptimalType plus(OptimalType a, OptimalType b)
159 { return addWithSaturation(a, b); }
160 static OptimalScalar alpha(OptimalType val)
161 { return val.alpha(); }
162 static OptimalScalar invAlpha(Scalar c)
163 { return 65535 - c; }
164 static OptimalScalar invAlpha(OptimalType val)
165 { return 65535 - alpha(val); }
166 static OptimalScalar scalar(Scalar v)
167 { return v; }
168 static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a)
169 { return multiplyAlpha255(val, a); }
170 static OptimalScalar multiplyAlpha8bit(OptimalScalar val, uint8_t a)
171 { return qt_div_255(val * a); }
172 static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2)
173 { return interpolate255(x, a1, y, a2); }
174 static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a)
175 { return multiplyAlpha65535(val, a); }
176 static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2)
177 { return interpolate65535(x, a1, y, a2); }
178};
179
180#if defined(__SSE2__)
181struct Rgba64OperationsSSE2 : public Rgba64OperationsBase
182{
183 typedef __m128i OptimalType;
184 typedef __m128i OptimalScalar;
185
186 static OptimalType load(const Type *ptr)
187 {
188 return _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
189 }
190 static OptimalType convert(const Type &value)
191 {
192#ifdef Q_PROCESSOR_X86_64
193 return _mm_cvtsi64_si128(value);
194#else
195 return load(&value);
196#endif
197 }
198 static void store(Type *ptr, OptimalType value)
199 {
200 _mm_storel_epi64(reinterpret_cast<__m128i *>(ptr), value);
201 }
202 static OptimalType add(OptimalType a, OptimalType b)
203 {
204 return _mm_add_epi16(a, b);
205 }
206// same as above:
207// static OptimalScalar add(OptimalScalar a, OptimalScalar b)
208 static OptimalType plus(OptimalType a, OptimalType b)
209 {
210 return _mm_adds_epu16(a, b);
211 }
212 static OptimalScalar alpha(OptimalType c)
213 {
214 return _mm_shufflelo_epi16(c, _MM_SHUFFLE(3, 3, 3, 3));
215 }
216 static OptimalScalar invAlpha(Scalar c)
217 {
218 return scalar(65535 - c);
219 }
220 static OptimalScalar invAlpha(OptimalType c)
221 {
222 return _mm_xor_si128(_mm_set1_epi16(-1), alpha(c));
223 }
224 static OptimalScalar scalar(Scalar n)
225 {
226 return _mm_shufflelo_epi16(_mm_cvtsi32_si128(n), _MM_SHUFFLE(0, 0, 0, 0));
227 }
228 static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a)
229 {
230 return multiplyAlpha255(val, a);
231 }
232// same as above:
233// static OptimalScalar multiplyAlpha8bit(OptimalScalar a, uint8_t a)
234 static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2)
235 {
236 return interpolate255(x, a1, y, a2);
237 }
238 static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a)
239 {
240 return multiplyAlpha65535(val, a);
241 }
242 // a2 is const-ref because otherwise MSVC2015@x86 complains that it can't 16-byte align the argument.
243 static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, const OptimalScalar &a2)
244 {
245 return interpolate65535(x, a1, y, a2);
246 }
247};
248#endif
249
250#if defined(__ARM_NEON__)
251struct Rgba64OperationsNEON : public Rgba64OperationsBase
252{
253 typedef uint16x4_t OptimalType;
254 typedef uint16x4_t OptimalScalar;
255
256 static OptimalType load(const Type *ptr)
257 {
258 return vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(ptr)));
259 }
260 static OptimalType convert(const Type &val)
261 {
262 return vreinterpret_u16_u64(vmov_n_u64(val));
263 }
264 static void store(Type *ptr, OptimalType value)
265 {
266 vst1_u64(reinterpret_cast<uint64_t *>(ptr), vreinterpret_u64_u16(value));
267 }
268 static OptimalType add(OptimalType a, OptimalType b)
269 {
270 return vadd_u16(a, b);
271 }
272// same as above:
273// static OptimalScalar add(OptimalScalar a, OptimalScalar b)
274 static OptimalType plus(OptimalType a, OptimalType b)
275 {
276 return vqadd_u16(a, b);
277 }
278 static OptimalScalar alpha(OptimalType c)
279 {
280 return vdup_lane_u16(c, 3);
281 }
282 static OptimalScalar invAlpha(Scalar c)
283 {
284 return scalar(65535 - c);
285 }
286 static OptimalScalar invAlpha(OptimalType c)
287 {
288 return vmvn_u16(alpha(c));
289 }
290 static OptimalScalar scalar(Scalar n)
291 {
292 return vdup_n_u16(n);
293 }
294 static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a)
295 {
296 return multiplyAlpha255(val, a);
297 }
298// same as above:
299// static OptimalScalar multiplyAlpha8bit(OptimalScalar a, uint8_t a)
300 static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2)
301 {
302 return interpolate255(x, a1, y, a2);
303 }
304 static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a)
305 {
306 return multiplyAlpha65535(val, a);
307 }
308 static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2)
309 {
310 return interpolate65535(x, a1, y, a2);
311 }
312};
313#endif
314
315#if defined(__SSE2__)
316typedef Rgba64OperationsSSE2 Rgba64Operations;
317#elif defined(__ARM_NEON__)
318typedef Rgba64OperationsNEON Rgba64Operations;
319#else
320typedef Rgba64OperationsC Rgba64Operations;
321#endif
322#endif // QT_CONFIG(raster_64bit)
323
324typedef Argb32OperationsC Argb32Operations;
325
326/*
327 result = 0
328 d = d * cia
329*/
330template<class Ops>
331inline static void comp_func_Clear_template(typename Ops::Type *dest, int length, uint const_alpha)
332{
333 if (const_alpha == 255)
334 Ops::memfill(dest, Ops::clear, length);
335 else {
336 uint ialpha = 255 - const_alpha;
337 for (int i = 0; i < length; ++i) {
338 Ops::store(&dest[i], Ops::multiplyAlpha8bit(Ops::load(&dest[i]), ialpha));
339 }
340 }
341}
342
343void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha)
344{
345 comp_func_Clear_template<Argb32Operations>(dest, length, const_alpha);
346}
347
348void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha)
349{
350 comp_func_Clear_template<Argb32Operations>(dest, length, const_alpha);
351}
352
353#if QT_CONFIG(raster_64bit)
354void QT_FASTCALL comp_func_solid_Clear_rgb64(QRgba64 *dest, int length, QRgba64, uint const_alpha)
355{
356 comp_func_Clear_template<Rgba64Operations>(dest, length, const_alpha);
357}
358
359void QT_FASTCALL comp_func_Clear_rgb64(QRgba64 *dest, const QRgba64 *, int length, uint const_alpha)
360{
361 comp_func_Clear_template<Rgba64Operations>(dest, length, const_alpha);
362}
363#endif
364
365
366/*
367 result = s
368 dest = s * ca + d * cia
369*/
370template<class Ops>
371inline static void comp_func_solid_Source_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha)
372{
373 if (const_alpha == 255)
374 Ops::memfill(dest, color, length);
375 else {
376 const uint ialpha = 255 - const_alpha;
377 auto s = Ops::multiplyAlpha8bit(Ops::convert(color), const_alpha);
378 for (int i = 0; i < length; ++i) {
379 auto d = Ops::multiplyAlpha8bit(Ops::load(&dest[i]), ialpha);
380 Ops::store(&dest[i], Ops::add(s, d));
381 }
382 }
383}
384
385template<class Ops>
386inline static void comp_func_Source_template(typename Ops::Type *Q_DECL_RESTRICT dest,
387 const typename Ops::Type *Q_DECL_RESTRICT src,
388 int length, uint const_alpha)
389{
390 if (const_alpha == 255)
391 Ops::memcpy(dest, src, length);
392 else {
393 const uint ialpha = 255 - const_alpha;
394 for (int i = 0; i < length; ++i) {
395 auto s = Ops::load(src + i);
396 auto d = Ops::load(dest + i);
397 Ops::store(&dest[i], Ops::interpolate8bit(s, const_alpha, d, ialpha));
398 }
399 }
400}
401
402void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha)
403{
404 comp_func_solid_Source_template<Argb32Operations>(dest, length, color, const_alpha);
405}
406
407void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
408{
409 comp_func_Source_template<Argb32Operations>(dest, src, length, const_alpha);
410}
411
412#if QT_CONFIG(raster_64bit)
413void QT_FASTCALL comp_func_solid_Source_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
414{
415 comp_func_solid_Source_template<Rgba64Operations>(dest, length, color, const_alpha);
416}
417
418void QT_FASTCALL comp_func_Source_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
419{
420 comp_func_Source_template<Rgba64Operations>(dest, src, length, const_alpha);
421}
422#endif
423
424void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
425{
426}
427
428void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint)
429{
430}
431
432#if QT_CONFIG(raster_64bit)
433void QT_FASTCALL comp_func_solid_Destination_rgb64(QRgba64 *, int, QRgba64, uint)
434{
435}
436
437void QT_FASTCALL comp_func_Destination_rgb64(QRgba64 *, const QRgba64 *, int, uint)
438{
439}
440#endif
441
442/*
443 result = s + d * sia
444 dest = (s + d * sia) * ca + d * cia
445 = s * ca + d * (sia * ca + cia)
446 = s * ca + d * (1 - sa*ca)
447*/
448template<class Ops>
449inline static void comp_func_solid_SourceOver_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha)
450{
451 if (const_alpha == 255 && Ops::isOpaque(color))
452 Ops::memfill(dest, color, length);
453 else {
454 auto c = Ops::convert(color);
455 if (const_alpha != 255)
456 c = Ops::multiplyAlpha8bit(c, const_alpha);
457 auto cAlpha = Ops::invAlpha(c);
458 for (int i = 0; i < length; ++i) {
459 auto d = Ops::multiplyAlpha(Ops::load(&dest[i]), cAlpha);
460 Ops::store(&dest[i], Ops::add(c, d));
461 }
462 }
463}
464
465template<class Ops>
466inline static void comp_func_SourceOver_template(typename Ops::Type *Q_DECL_RESTRICT dest,
467 const typename Ops::Type *Q_DECL_RESTRICT src,
468 int length, uint const_alpha)
469{
470 if (const_alpha == 255) {
471 for (int i = 0; i < length; ++i) {
472 auto c = src[i];
473 if (Ops::isOpaque(c))
474 Ops::store(&dest[i], Ops::convert(c));
475 else if (!Ops::isTransparent(c)) {
476 auto s = Ops::convert(c);
477 auto d = Ops::multiplyAlpha(Ops::load(&dest[i]), Ops::invAlpha(s));
478 Ops::store(&dest[i], Ops::add(s, d));
479 }
480 }
481 } else {
482 for (int i = 0; i < length; ++i) {
483 auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha);
484 auto d = Ops::multiplyAlpha(Ops::load(&dest[i]), Ops::invAlpha(s));
485 Ops::store(&dest[i], Ops::add(s, d));
486 }
487 }
488}
489
490void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha)
491{
492 comp_func_solid_SourceOver_template<Argb32Operations>(dest, length, color, const_alpha);
493}
494
495void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
496{
497 comp_func_SourceOver_template<Argb32Operations>(dest, src, length, const_alpha);
498}
499
500#if QT_CONFIG(raster_64bit)
501void QT_FASTCALL comp_func_solid_SourceOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
502{
503 comp_func_solid_SourceOver_template<Rgba64Operations>(dest, length, color, const_alpha);
504}
505
506void QT_FASTCALL comp_func_SourceOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
507{
508 comp_func_SourceOver_template<Rgba64Operations>(dest, src, length, const_alpha);
509}
510#endif
511
512/*
513 result = d + s * dia
514 dest = (d + s * dia) * ca + d * cia
515 = d + s * dia * ca
516*/
517template<class Ops>
518inline static void comp_func_solid_DestinationOver_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha)
519{
520 auto c = Ops::convert(color);
521 if (const_alpha != 255)
522 c = Ops::multiplyAlpha8bit(c, const_alpha);
523 for (int i = 0; i < length; ++i) {
524 auto d = Ops::load(&dest[i]);
525 auto s = Ops::multiplyAlpha(c, Ops::invAlpha(d));
526 Ops::store(&dest[i], Ops::add(s, d));
527 }
528}
529
530template<class Ops>
531inline static void comp_func_DestinationOver_template(typename Ops::Type *Q_DECL_RESTRICT dest,
532 const typename Ops::Type *Q_DECL_RESTRICT src,
533 int length, uint const_alpha)
534{
535 if (const_alpha == 255) {
536 for (int i = 0; i < length; ++i) {
537 auto d = Ops::load(&dest[i]);
538 auto s = Ops::multiplyAlpha(Ops::load(&src[i]), Ops::invAlpha(d));
539 Ops::store(&dest[i], Ops::add(s, d));
540 }
541 } else {
542 for (int i = 0; i < length; ++i) {
543 auto d = Ops::load(&dest[i]);
544 auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha);
545 s = Ops::multiplyAlpha(s, Ops::invAlpha(d));
546 Ops::store(&dest[i], Ops::add(s, d));
547 }
548 }
549}
550
551void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha)
552{
553 comp_func_solid_DestinationOver_template<Argb32Operations>(dest, length, color, const_alpha);
554}
555
556void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
557{
558 comp_func_DestinationOver_template<Argb32Operations>(dest, src, length, const_alpha);
559}
560
561#if QT_CONFIG(raster_64bit)
562void QT_FASTCALL comp_func_solid_DestinationOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
563{
564 comp_func_solid_DestinationOver_template<Rgba64Operations>(dest, length, color, const_alpha);
565}
566
567void QT_FASTCALL comp_func_DestinationOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
568{
569 comp_func_DestinationOver_template<Rgba64Operations>(dest, src, length, const_alpha);
570}
571#endif
572
573/*
574 result = s * da
575 dest = s * da * ca + d * cia
576*/
577template<class Ops>
578inline static void comp_func_solid_SourceIn_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha)
579{
580 if (const_alpha == 255) {
581 auto c = Ops::convert(color);
582 for (int i = 0; i < length; ++i) {
583 Ops::store(&dest[i], Ops::multiplyAlpha(c, Ops::alpha(Ops::load(&dest[i]))));
584 }
585 } else {
586 auto c = Ops::multiplyAlpha8bit(Ops::convert(color), const_alpha);
587 auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha));
588 for (int i = 0; i < length; ++i) {
589 auto d = Ops::load(&dest[i]);
590 Ops::store(&dest[i], Ops::interpolate(c, Ops::alpha(d), d, cia));
591 }
592 }
593}
594
595template<class Ops>
596inline static void comp_func_SourceIn_template(typename Ops::Type *Q_DECL_RESTRICT dest,
597 const typename Ops::Type *Q_DECL_RESTRICT src,
598 int length, uint const_alpha)
599{
600 if (const_alpha == 255) {
601 for (int i = 0; i < length; ++i) {
602 auto s = Ops::load(&src[i]);
603 Ops::store(&dest[i], Ops::multiplyAlpha(s, Ops::alpha(Ops::load(&dest[i]))));
604 }
605 } else {
606 auto ca = Ops::scalarFrom8bit(const_alpha);
607 auto cia = Ops::invAlpha(ca);
608 auto cav = Ops::scalar(ca);
609 for (int i = 0; i < length; ++i) {
610 auto d = Ops::load(&dest[i]);
611 auto s = Ops::multiplyAlpha(Ops::load(&src[i]), cav);
612 Ops::store(&dest[i], Ops::interpolate(s, Ops::alpha(d), d, cia));
613 }
614 }
615}
616
617void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha)
618{
619 comp_func_solid_SourceIn_template<Argb32Operations>(dest, length, color, const_alpha);
620}
621
622void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
623{
624 comp_func_SourceIn_template<Argb32Operations>(dest, src, length, const_alpha);
625}
626
627#if QT_CONFIG(raster_64bit)
628void QT_FASTCALL comp_func_solid_SourceIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
629{
630 comp_func_solid_SourceIn_template<Rgba64Operations>(dest, length, color, const_alpha);
631}
632
633void QT_FASTCALL comp_func_SourceIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
634{
635 comp_func_SourceIn_template<Rgba64Operations>(dest, src, length, const_alpha);
636}
637#endif
638
639/*
640 result = d * sa
641 dest = d * sa * ca + d * cia
642 = d * (sa * ca + cia)
643*/
644template<class Ops>
645inline static void comp_func_solid_DestinationIn_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha)
646{
647 auto sa = Ops::alpha(Ops::convert(color));
648 if (const_alpha != 255) {
649 sa = Ops::multiplyAlpha8bit(sa, const_alpha);
650 sa = Ops::add(sa, Ops::invAlpha(Ops::scalarFrom8bit(const_alpha)));
651 }
652
653 for (int i = 0; i < length; ++i) {
654 Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), sa));
655 }
656}
657
658template<class Ops>
659inline static void comp_func_DestinationIn_template(typename Ops::Type *Q_DECL_RESTRICT dest,
660 const typename Ops::Type *Q_DECL_RESTRICT src,
661 int length, uint const_alpha)
662{
663 if (const_alpha == 255) {
664 for (int i = 0; i < length; ++i) {
665 auto a = Ops::alpha(Ops::load(&src[i]));
666 Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), a));
667 }
668 } else {
669 auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha));
670 for (int i = 0; i < length; ++i) {
671 auto sa = Ops::multiplyAlpha8bit(Ops::alpha(Ops::load(&src[i])), const_alpha);
672 sa = Ops::add(sa, cia);
673 Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), sa));
674 }
675 }
676}
677
678void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha)
679{
680 comp_func_solid_DestinationIn_template<Argb32Operations>(dest, length, color, const_alpha);
681}
682
683void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
684{
685 comp_func_DestinationIn_template<Argb32Operations>(dest, src, length, const_alpha);
686}
687
688#if QT_CONFIG(raster_64bit)
689void QT_FASTCALL comp_func_solid_DestinationIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
690{
691 comp_func_solid_DestinationIn_template<Rgba64Operations>(dest, length, color, const_alpha);
692}
693
694void QT_FASTCALL comp_func_DestinationIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
695{
696 comp_func_DestinationIn_template<Rgba64Operations>(dest, src, length, const_alpha);
697}
698#endif
699
700/*
701 result = s * dia
702 dest = s * dia * ca + d * cia
703*/
704template<class Ops>
705inline static void comp_func_solid_SourceOut_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha)
706{
707 auto c = Ops::convert(color);
708 if (const_alpha == 255) {
709 for (int i = 0; i < length; ++i)
710 Ops::store(&dest[i], Ops::multiplyAlpha(c, Ops::invAlpha(Ops::load(&dest[i]))));
711 } else {
712 auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha));
713 c = Ops::multiplyAlpha8bit(c, const_alpha);
714 for (int i = 0; i < length; ++i) {
715 auto d = Ops::load(&dest[i]);
716 Ops::store(&dest[i], Ops::interpolate(c, Ops::invAlpha(d), d, cia));
717 }
718 }
719}
720
721template<class Ops>
722inline static void comp_func_SourceOut_template(typename Ops::Type *Q_DECL_RESTRICT dest,
723 const typename Ops::Type *Q_DECL_RESTRICT src,
724 int length, uint const_alpha)
725{
726 if (const_alpha == 255) {
727 for (int i = 0; i < length; ++i) {
728 auto s = Ops::load(&src[i]);
729 auto d = Ops::load(&dest[i]);
730 Ops::store(&dest[i], Ops::multiplyAlpha(s, Ops::invAlpha(d)));
731 }
732 } else {
733 auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha));
734 for (int i = 0; i < length; ++i) {
735 auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha);
736 auto d = Ops::load(&dest[i]);
737 Ops::store(&dest[i], Ops::interpolate(s, Ops::invAlpha(d), d, cia));
738 }
739 }
740}
741
742void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha)
743{
744 comp_func_solid_SourceOut_template<Argb32Operations>(dest, length, color, const_alpha);
745}
746
747void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
748{
749 comp_func_SourceOut_template<Argb32Operations>(dest, src, length, const_alpha);
750}
751
752#if QT_CONFIG(raster_64bit)
753void QT_FASTCALL comp_func_solid_SourceOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
754{
755 comp_func_solid_SourceOut_template<Rgba64Operations>(dest, length, color, const_alpha);
756}
757
758void QT_FASTCALL comp_func_SourceOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
759{
760 comp_func_SourceOut_template<Rgba64Operations>(dest, src, length, const_alpha);
761}
762#endif
763
764/*
765 result = d * sia
766 dest = d * sia * ca + d * cia
767 = d * (sia * ca + cia)
768*/
769template<class Ops>
770inline static void comp_func_solid_DestinationOut_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha)
771{
772 auto sai = Ops::invAlpha(Ops::convert(color));
773 if (const_alpha != 255) {
774 sai = Ops::multiplyAlpha8bit(sai, const_alpha);
775 sai = Ops::add(sai, Ops::invAlpha(Ops::scalarFrom8bit(const_alpha)));
776 }
777
778 for (int i = 0; i < length; ++i) {
779 Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), sai));
780 }
781}
782
783template<class Ops>
784inline static void comp_func_DestinationOut_template(typename Ops::Type *Q_DECL_RESTRICT dest,
785 const typename Ops::Type *Q_DECL_RESTRICT src,
786 int length, uint const_alpha)
787{
788 if (const_alpha == 255) {
789 for (int i = 0; i < length; ++i) {
790 auto sia = Ops::invAlpha(Ops::load(&src[i]));
791 Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), sia));
792 }
793 } else {
794 auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha));
795 for (int i = 0; i < length; ++i) {
796 auto sia = Ops::multiplyAlpha8bit(Ops::invAlpha(Ops::load(&src[i])), const_alpha);
797 sia = Ops::add(sia, cia);
798 Ops::store(&dest[i], Ops::multiplyAlpha(Ops::load(&dest[i]), sia));
799 }
800 }
801}
802
803void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha)
804{
805 comp_func_solid_DestinationOut_template<Argb32Operations>(dest, length, color, const_alpha);
806}
807
808void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
809{
810 comp_func_DestinationOut_template<Argb32Operations>(dest, src, length, const_alpha);
811}
812
813#if QT_CONFIG(raster_64bit)
814void QT_FASTCALL comp_func_solid_DestinationOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
815{
816 comp_func_solid_DestinationOut_template<Rgba64Operations>(dest, length, color, const_alpha);
817}
818
819void QT_FASTCALL comp_func_DestinationOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
820{
821 comp_func_DestinationOut_template<Rgba64Operations>(dest, src, length, const_alpha);
822}
823#endif
824
825/*
826 result = s*da + d*sia
827 dest = s*da*ca + d*sia*ca + d *cia
828 = s*ca * da + d * (sia*ca + cia)
829 = s*ca * da + d * (1 - sa*ca)
830*/
831template<class Ops>
832inline static void comp_func_solid_SourceAtop_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha)
833{
834 auto c = Ops::convert(color);
835 if (const_alpha != 255)
836 c = Ops::multiplyAlpha8bit(c, const_alpha);
837 auto sia = Ops::invAlpha(c);
838 for (int i = 0; i < length; ++i) {
839 auto d = Ops::load(&dest[i]);
840 Ops::store(&dest[i], Ops::interpolate(c, Ops::alpha(d), d, sia));
841 }
842}
843
844template<class Ops>
845inline static void comp_func_SourceAtop_template(typename Ops::Type *Q_DECL_RESTRICT dest,
846 const typename Ops::Type *Q_DECL_RESTRICT src,
847 int length, uint const_alpha)
848{
849 if (const_alpha == 255) {
850 for (int i = 0; i < length; ++i) {
851 auto s = Ops::load(&src[i]);
852 auto d = Ops::load(&dest[i]);
853 Ops::store(&dest[i], Ops::interpolate(s, Ops::alpha(d), d, Ops::invAlpha(s)));
854 }
855 } else {
856 for (int i = 0; i < length; ++i) {
857 auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha);
858 auto d = Ops::load(&dest[i]);
859 Ops::store(&dest[i], Ops::interpolate(s, Ops::alpha(d), d, Ops::invAlpha(s)));
860 }
861 }
862}
863
864void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha)
865{
866 comp_func_solid_SourceAtop_template<Argb32Operations>(dest, length, color, const_alpha);
867}
868
869void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
870{
871 comp_func_SourceAtop_template<Argb32Operations>(dest, src, length, const_alpha);
872}
873
874#if QT_CONFIG(raster_64bit)
875void QT_FASTCALL comp_func_solid_SourceAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
876{
877 comp_func_solid_SourceAtop_template<Rgba64Operations>(dest, length, color, const_alpha);
878}
879
880void QT_FASTCALL comp_func_SourceAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
881{
882 comp_func_SourceAtop_template<Rgba64Operations>(dest, src, length, const_alpha);
883}
884#endif
885
886/*
887 result = d*sa + s*dia
888 dest = d*sa*ca + s*dia*ca + d *cia
889 = s*ca * dia + d * (sa*ca + cia)
890*/
891template<class Ops>
892inline static void comp_func_solid_DestinationAtop_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha)
893{
894 auto c = Ops::convert(color);
895 auto sa = Ops::alpha(c);
896 if (const_alpha != 255) {
897 c = Ops::multiplyAlpha8bit(c, const_alpha);
898 auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha));
899 sa = Ops::add(Ops::alpha(c), cia);
900 }
901
902 for (int i = 0; i < length; ++i) {
903 auto d = Ops::load(&dest[i]);
904 Ops::store(&dest[i], Ops::interpolate(c, Ops::invAlpha(d), d, sa));
905 }
906}
907
908template<class Ops>
909inline static void comp_func_DestinationAtop_template(typename Ops::Type *Q_DECL_RESTRICT dest,
910 const typename Ops::Type *Q_DECL_RESTRICT src,
911 int length, uint const_alpha)
912{
913 if (const_alpha == 255) {
914 for (int i = 0; i < length; ++i) {
915 auto s = Ops::load(&src[i]);
916 auto d = Ops::load(&dest[i]);
917 Ops::store(&dest[i], Ops::interpolate(s, Ops::invAlpha(d), d, Ops::alpha(s)));
918 }
919 } else {
920 auto cia = Ops::invAlpha(Ops::scalarFrom8bit(const_alpha));
921 for (int i = 0; i < length; ++i) {
922 auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha);
923 auto d = Ops::load(&dest[i]);
924 auto sa = Ops::add(Ops::alpha(s), cia);
925 Ops::store(&dest[i], Ops::interpolate(s, Ops::invAlpha(d), d, sa));
926 }
927 }
928}
929
930void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha)
931{
932 comp_func_solid_DestinationAtop_template<Argb32Operations>(dest, length, color, const_alpha);
933}
934
935void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
936{
937 comp_func_DestinationAtop_template<Argb32Operations>(dest, src, length, const_alpha);
938}
939
940#if QT_CONFIG(raster_64bit)
941void QT_FASTCALL comp_func_solid_DestinationAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
942{
943 comp_func_solid_DestinationAtop_template<Rgba64Operations>(dest, length, color, const_alpha);
944}
945
946void QT_FASTCALL comp_func_DestinationAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
947{
948 comp_func_DestinationAtop_template<Rgba64Operations>(dest, src, length, const_alpha);
949}
950#endif
951
952/*
953 result = d*sia + s*dia
954 dest = d*sia*ca + s*dia*ca + d *cia
955 = s*ca * dia + d * (sia*ca + cia)
956 = s*ca * dia + d * (1 - sa*ca)
957*/
958template<class Ops>
959inline static void comp_func_solid_XOR_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha)
960{
961 auto c = Ops::convert(color);
962 if (const_alpha != 255)
963 c = Ops::multiplyAlpha8bit(c, const_alpha);
964
965 auto sia = Ops::invAlpha(c);
966 for (int i = 0; i < length; ++i) {
967 auto d = Ops::load(&dest[i]);
968 Ops::store(&dest[i], Ops::interpolate(c, Ops::invAlpha(d), d, sia));
969 }
970}
971
972template<class Ops>
973inline static void comp_func_XOR_template(typename Ops::Type *Q_DECL_RESTRICT dest,
974 const typename Ops::Type *Q_DECL_RESTRICT src,
975 int length, uint const_alpha)
976{
977 if (const_alpha == 255) {
978 for (int i = 0; i < length; ++i) {
979 auto d = Ops::load(&dest[i]);
980 auto s = Ops::load(&src[i]);
981 Ops::store(&dest[i], Ops::interpolate(s, Ops::invAlpha(d), d, Ops::invAlpha(s)));
982 }
983 } else {
984 for (int i = 0; i < length; ++i) {
985 auto d = Ops::load(&dest[i]);
986 auto s = Ops::multiplyAlpha8bit(Ops::load(&src[i]), const_alpha);
987 Ops::store(&dest[i], Ops::interpolate(s, Ops::invAlpha(d), d, Ops::invAlpha(s)));
988 }
989 }
990}
991
992void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha)
993{
994 comp_func_solid_XOR_template<Argb32Operations>(dest, length, color, const_alpha);
995}
996
997void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
998{
999 comp_func_XOR_template<Argb32Operations>(dest, src, length, const_alpha);
1000}
1001
1002#if QT_CONFIG(raster_64bit)
1003void QT_FASTCALL comp_func_solid_XOR_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
1004{
1005 comp_func_solid_XOR_template<Rgba64Operations>(dest, length, color, const_alpha);
1006}
1007
1008void QT_FASTCALL comp_func_XOR_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
1009{
1010 comp_func_XOR_template<Rgba64Operations>(dest, src, length, const_alpha);
1011}
1012#endif
1013
1014struct QFullCoverage {
1015 inline void store(uint *dest, const uint src) const
1016 {
1017 *dest = src;
1018 }
1019 inline void store(QRgba64 *dest, const QRgba64 src) const
1020 {
1021 *dest = src;
1022 }
1023};
1024
1025struct QPartialCoverage {
1026 inline QPartialCoverage(uint const_alpha)
1027 : ca(const_alpha)
1028 , ica(255 - const_alpha)
1029 {
1030 }
1031
1032 inline void store(uint *dest, const uint src) const
1033 {
1034 *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
1035 }
1036 inline void store(QRgba64 *dest, const QRgba64 src) const
1037 {
1038 *dest = interpolate255(src, ca, *dest, ica);
1039 }
1040
1041private:
1042 const uint ca;
1043 const uint ica;
1044};
1045
1046static inline int mix_alpha(int da, int sa)
1047{
1048 return 255 - ((255 - sa) * (255 - da) >> 8);
1049}
1050
1051static inline uint mix_alpha_rgb64(uint da, uint sa)
1052{
1053 return 65535 - ((65535 - sa) * (65535 - da) >> 16);
1054}
1055
1056/*
1057 Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
1058 = Sca + Dca
1059*/
1060template<class Ops>
1061inline static void comp_func_solid_Plus_template(typename Ops::Type *dest, int length, typename Ops::Type color, uint const_alpha)
1062{
1063 auto c = Ops::convert(color);
1064 if (const_alpha == 255) {
1065 for (int i = 0; i < length; ++i) {
1066 auto d = Ops::load(&dest[i]);
1067 d = Ops::plus(d, c);
1068 Ops::store(&dest[i], d);
1069 }
1070 } else {
1071 uint ia = 255 - const_alpha;
1072 for (int i = 0; i < length; ++i) {
1073 auto d = Ops::load(&dest[i]);
1074 d = Ops::interpolate8bit(Ops::plus(d, c), const_alpha, d, ia);
1075 Ops::store(&dest[i], d);
1076 }
1077 }
1078}
1079
1080template<class Ops>
1081inline static void comp_func_Plus_template(typename Ops::Type *Q_DECL_RESTRICT dest,
1082 const typename Ops::Type *Q_DECL_RESTRICT src,
1083 int length, uint const_alpha)
1084{
1085 if (const_alpha == 255) {
1086 for (int i = 0; i < length; ++i) {
1087 auto d = Ops::load(&dest[i]);
1088 auto s = Ops::load(&src[i]);
1089 d = Ops::plus(d, s);
1090 Ops::store(&dest[i], d);
1091 }
1092 } else {
1093 uint ia = 255 - const_alpha;
1094 for (int i = 0; i < length; ++i) {
1095 auto d = Ops::load(&dest[i]);
1096 auto s = Ops::load(&src[i]);
1097 d = Ops::interpolate8bit(Ops::plus(d, s), const_alpha, d, ia);
1098 Ops::store(&dest[i], d);
1099 }
1100 }
1101}
1102
1103void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha)
1104{
1105 comp_func_solid_Plus_template<Argb32Operations>(dest, length, color, const_alpha);
1106}
1107
1108void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
1109{
1110 comp_func_Plus_template<Argb32Operations>(dest, src, length, const_alpha);
1111}
1112
1113#if QT_CONFIG(raster_64bit)
1114void QT_FASTCALL comp_func_solid_Plus_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
1115{
1116 comp_func_solid_Plus_template<Rgba64Operations>(dest, length, color, const_alpha);
1117}
1118
1119void QT_FASTCALL comp_func_Plus_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
1120{
1121 comp_func_Plus_template<Rgba64Operations>(dest, src, length, const_alpha);
1122}
1123#endif
1124
1125/*
1126 Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
1127*/
1128static inline int multiply_op(int dst, int src, int da, int sa)
1129{
1130 return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa));
1131}
1132
1133template <typename T>
1134static inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage)
1135{
1136 int sa = qAlpha(color);
1137 int sr = qRed(color);
1138 int sg = qGreen(color);
1139 int sb = qBlue(color);
1140
1141 for (int i = 0; i < length; ++i) {
1142 uint d = dest[i];
1143 int da = qAlpha(d);
1144
1145#define OP(a, b) multiply_op(a, b, da, sa)
1146 int r = OP( qRed(d), sr);
1147 int b = OP( qBlue(d), sb);
1148 int g = OP(qGreen(d), sg);
1149 int a = mix_alpha(da, sa);
1150#undef OP
1151
1152 coverage.store(&dest[i], qRgba(r, g, b, a));
1153 }
1154}
1155
1156void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha)
1157{
1158 if (const_alpha == 255)
1159 comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
1160 else
1161 comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
1162}
1163
1164#if QT_CONFIG(raster_64bit)
1165static inline uint multiply_op_rgb64(uint dst, uint src, uint da, uint sa)
1166{
1167 return qt_div_65535(src * dst + src * (65535 - da) + dst * (65535 - sa));
1168}
1169
1170template <typename T>
1171static inline void comp_func_solid_Multiply_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
1172{
1173 uint sa = color.alpha();
1174 uint sr = color.red();
1175 uint sg = color.green();
1176 uint sb = color.blue();
1177
1178 for (int i = 0; i < length; ++i) {
1179 QRgba64 d = dest[i];
1180 uint da = d.alpha();
1181
1182#define OP(a, b) multiply_op_rgb64(a, b, da, sa)
1183 uint r = OP( d.red(), sr);
1184 uint b = OP( d.blue(), sb);
1185 uint g = OP(d.green(), sg);
1186 uint a = mix_alpha_rgb64(da, sa);
1187#undef OP
1188
1189 coverage.store(&dest[i], qRgba64(r, g, b, a));
1190 }
1191}
1192
1193void QT_FASTCALL comp_func_solid_Multiply_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
1194{
1195 if (const_alpha == 255)
1196 comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
1197 else
1198 comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
1199}
1200#endif
1201
1202template <typename T>
1203static inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
1204{
1205 for (int i = 0; i < length; ++i) {
1206 uint d = dest[i];
1207 uint s = src[i];
1208
1209 int da = qAlpha(d);
1210 int sa = qAlpha(s);
1211
1212#define OP(a, b) multiply_op(a, b, da, sa)
1213 int r = OP( qRed(d), qRed(s));
1214 int b = OP( qBlue(d), qBlue(s));
1215 int g = OP(qGreen(d), qGreen(s));
1216 int a = mix_alpha(da, sa);
1217#undef OP
1218
1219 coverage.store(&dest[i], qRgba(r, g, b, a));
1220 }
1221}
1222
1223void QT_FASTCALL comp_func_Multiply(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
1224{
1225 if (const_alpha == 255)
1226 comp_func_Multiply_impl(dest, src, length, QFullCoverage());
1227 else
1228 comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
1229}
1230
1231#if QT_CONFIG(raster_64bit)
1232template <typename T>
1233static inline void comp_func_Multiply_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
1234{
1235 for (int i = 0; i < length; ++i) {
1236 QRgba64 d = dest[i];
1237 QRgba64 s = src[i];
1238
1239 uint da = d.alpha();
1240 uint sa = s.alpha();
1241
1242#define OP(a, b) multiply_op_rgb64(a, b, da, sa)
1243 uint r = OP( d.red(), s.red());
1244 uint b = OP( d.blue(), s.blue());
1245 uint g = OP(d.green(), s.green());
1246 uint a = mix_alpha_rgb64(da, sa);
1247#undef OP
1248
1249 coverage.store(&dest[i], qRgba64(r, g, b, a));
1250 }
1251}
1252
1253void QT_FASTCALL comp_func_Multiply_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
1254{
1255 if (const_alpha == 255)
1256 comp_func_Multiply_impl(dest, src, length, QFullCoverage());
1257 else
1258 comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
1259}
1260#endif
1261
1262/*
1263 Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
1264 = Sca + Dca - Sca.Dca
1265*/
1266template <typename T>
1267static inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage)
1268{
1269 int sa = qAlpha(color);
1270 int sr = qRed(color);
1271 int sg = qGreen(color);
1272 int sb = qBlue(color);
1273
1274 for (int i = 0; i < length; ++i) {
1275 uint d = dest[i];
1276 int da = qAlpha(d);
1277
1278#define OP(a, b) 255 - qt_div_255((255-a) * (255-b))
1279 int r = OP( qRed(d), sr);
1280 int b = OP( qBlue(d), sb);
1281 int g = OP(qGreen(d), sg);
1282 int a = mix_alpha(da, sa);
1283#undef OP
1284
1285 coverage.store(&dest[i], qRgba(r, g, b, a));
1286 }
1287}
1288
1289void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha)
1290{
1291 if (const_alpha == 255)
1292 comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
1293 else
1294 comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
1295}
1296
1297#if QT_CONFIG(raster_64bit)
1298template <typename T>
1299static inline void comp_func_solid_Screen_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
1300{
1301 uint sa = color.alpha();
1302 uint sr = color.red();
1303 uint sg = color.green();
1304 uint sb = color.blue();
1305
1306 for (int i = 0; i < length; ++i) {
1307 QRgba64 d = dest[i];
1308 uint da = d.alpha();
1309
1310#define OP(a, b) 65535 - qt_div_65535((65535-a) * (65535-b))
1311 uint r = OP( d.red(), sr);
1312 uint b = OP( d.blue(), sb);
1313 uint g = OP(d.green(), sg);
1314 uint a = mix_alpha_rgb64(da, sa);
1315#undef OP
1316
1317 coverage.store(&dest[i], qRgba64(r, g, b, a));
1318 }
1319}
1320
1321void QT_FASTCALL comp_func_solid_Screen_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
1322{
1323 if (const_alpha == 255)
1324 comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
1325 else
1326 comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
1327}
1328#endif
1329
1330template <typename T>
1331static inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
1332{
1333 for (int i = 0; i < length; ++i) {
1334 uint d = dest[i];
1335 uint s = src[i];
1336
1337 int da = qAlpha(d);
1338 int sa = qAlpha(s);
1339
1340#define OP(a, b) 255 - (((255-a) * (255-b)) >> 8)
1341 int r = OP( qRed(d), qRed(s));
1342 int b = OP( qBlue(d), qBlue(s));
1343 int g = OP(qGreen(d), qGreen(s));
1344 int a = mix_alpha(da, sa);
1345#undef OP
1346
1347 coverage.store(&dest[i], qRgba(r, g, b, a));
1348 }
1349}
1350
1351void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha)
1352{
1353 if (const_alpha == 255)
1354 comp_func_Screen_impl(dest, src, length, QFullCoverage());
1355 else
1356 comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
1357}
1358
1359#if QT_CONFIG(raster_64bit)
1360template <typename T>
1361static inline void comp_func_Screen_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
1362{
1363 for (int i = 0; i < length; ++i) {
1364 QRgba64 d = dest[i];
1365 QRgba64 s = src[i];
1366
1367 uint da = d.alpha();
1368 uint sa = s.alpha();
1369
1370#define OP(a, b) 65535 - (((65535-a) * (65535-b)) >> 16)
1371 uint r = OP( d.red(), s.red());
1372 uint b = OP( d.blue(), s.blue());
1373 uint g = OP(d.green(), s.green());
1374 uint a = mix_alpha_rgb64(da, sa);
1375#undef OP
1376
1377 coverage.store(&dest[i], qRgba64(r, g, b, a));
1378 }
1379}
1380
1381void QT_FASTCALL comp_func_Screen_rgb64(QRgba64 *dest, const QRgba64 *src, int length, uint const_alpha)
1382{
1383 if (const_alpha == 255)
1384 comp_func_Screen_impl(dest, src, length, QFullCoverage());
1385 else
1386 comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
1387}
1388#endif
1389
1390/*
1391 if 2.Dca < Da
1392 Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
1393 otherwise
1394 Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
1395*/
1396static inline int overlay_op(int dst, int src, int da, int sa)
1397{
1398 const int temp = src * (255 - da) + dst * (255 - sa);
1399 if (2 * dst < da)
1400 return qt_div_255(2 * src * dst + temp);
1401 else
1402 return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
1403}
1404
1405template <typename T>
1406static inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage)
1407{
1408 int sa = qAlpha(color);
1409 int sr = qRed(color);
1410 int sg = qGreen(color);
1411 int sb = qBlue(color);
1412
1413 for (int i = 0; i < length; ++i) {
1414 uint d = dest[i];
1415 int da = qAlpha(d);
1416
1417#define OP(a, b) overlay_op(a, b, da, sa)
1418 int r = OP( qRed(d), sr);
1419 int b = OP( qBlue(d), sb);
1420 int g = OP(qGreen(d), sg);
1421 int a = mix_alpha(da, sa);
1422#undef OP
1423
1424 coverage.store(&dest[i], qRgba(r, g, b, a));
1425 }
1426}
1427
1428void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha)
1429{
1430 if (const_alpha == 255)
1431 comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
1432 else
1433 comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
1434}
1435
1436#if QT_CONFIG(raster_64bit)
1437static inline uint overlay_op_rgb64(uint dst, uint src, uint da, uint sa)
1438{
1439 const uint temp = src * (65535 - da) + dst * (65535 - sa);
1440 if (2 * dst < da)
1441 return qt_div_65535(2 * src * dst + temp);
1442 else
1443 return qt_div_65535(sa * da - 2 * (da - dst) * (sa - src) + temp);
1444}
1445
1446template <typename T>
1447static inline void comp_func_solid_Overlay_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
1448{
1449 uint sa = color.alpha();
1450 uint sr = color.red();
1451 uint sg = color.green();
1452 uint sb = color.blue();
1453
1454 for (int i = 0; i < length; ++i) {
1455 QRgba64 d = dest[i];
1456 uint da = d.alpha();
1457
1458#define OP(a, b) overlay_op_rgb64(a, b, da, sa)
1459 uint r = OP( d.red(), sr);
1460 uint b = OP( d.blue(), sb);
1461 uint g = OP(d.green(), sg);
1462 uint a = mix_alpha_rgb64(da, sa);
1463#undef OP
1464
1465 coverage.store(&dest[i], qRgba64(r, g, b, a));
1466 }
1467}
1468
1469void QT_FASTCALL comp_func_solid_Overlay_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
1470{
1471 if (const_alpha == 255)
1472 comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
1473 else
1474 comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
1475}
1476#endif
1477
1478template <typename T>
1479static inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
1480{
1481 for (int i = 0; i < length; ++i) {
1482 uint d = dest[i];
1483 uint s = src[i];
1484
1485 int da = qAlpha(d);
1486 int sa = qAlpha(s);
1487
1488#define OP(a, b) overlay_op(a, b, da, sa)
1489 int r = OP( qRed(d), qRed(s));
1490 int b = OP( qBlue(d), qBlue(s));
1491 int g = OP(qGreen(d), qGreen(s));
1492 int a = mix_alpha(da, sa);
1493#undef OP
1494
1495 coverage.store(&dest[i], qRgba(r, g, b, a));
1496 }
1497}
1498
1499void QT_FASTCALL comp_func_Overlay(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
1500{
1501 if (const_alpha == 255)
1502 comp_func_Overlay_impl(dest, src, length, QFullCoverage());
1503 else
1504 comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
1505}
1506
1507#if QT_CONFIG(raster_64bit)
1508template <typename T>
1509static inline void comp_func_Overlay_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
1510{
1511 for (int i = 0; i < length; ++i) {
1512 QRgba64 d = dest[i];
1513 QRgba64 s = src[i];
1514
1515 uint da = d.alpha();
1516 uint sa = s.alpha();
1517
1518#define OP(a, b) overlay_op_rgb64(a, b, da, sa)
1519 uint r = OP( d.red(), s.red());
1520 uint b = OP( d.blue(), s.blue());
1521 uint g = OP(d.green(), s.green());
1522 uint a = mix_alpha_rgb64(da, sa);
1523#undef OP
1524
1525 coverage.store(&dest[i], qRgba64(r, g, b, a));
1526 }
1527}
1528
1529void QT_FASTCALL comp_func_Overlay_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
1530{
1531 if (const_alpha == 255)
1532 comp_func_Overlay_impl(dest, src, length, QFullCoverage());
1533 else
1534 comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
1535}
1536#endif
1537
1538/*
1539 Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
1540 Da' = Sa + Da - Sa.Da
1541*/
1542static inline int darken_op(int dst, int src, int da, int sa)
1543{
1544 return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
1545}
1546
1547template <typename T>
1548static inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage)
1549{
1550 int sa = qAlpha(color);
1551 int sr = qRed(color);
1552 int sg = qGreen(color);
1553 int sb = qBlue(color);
1554
1555 for (int i = 0; i < length; ++i) {
1556 uint d = dest[i];
1557 int da = qAlpha(d);
1558
1559#define OP(a, b) darken_op(a, b, da, sa)
1560 int r = OP( qRed(d), sr);
1561 int b = OP( qBlue(d), sb);
1562 int g = OP(qGreen(d), sg);
1563 int a = mix_alpha(da, sa);
1564#undef OP
1565
1566 coverage.store(&dest[i], qRgba(r, g, b, a));
1567 }
1568}
1569
1570void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha)
1571{
1572 if (const_alpha == 255)
1573 comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
1574 else
1575 comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
1576}
1577
1578#if QT_CONFIG(raster_64bit)
1579static inline uint darken_op_rgb64(uint dst, uint src, uint da, uint sa)
1580{
1581 return qt_div_65535(qMin(src * da, dst * sa) + src * (65535 - da) + dst * (65535 - sa));
1582}
1583
1584template <typename T>
1585static inline void comp_func_solid_Darken_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
1586{
1587 uint sa = color.alpha();
1588 uint sr = color.red();
1589 uint sg = color.green();
1590 uint sb = color.blue();
1591
1592 for (int i = 0; i < length; ++i) {
1593 QRgba64 d = dest[i];
1594 uint da = d.alpha();
1595
1596#define OP(a, b) darken_op_rgb64(a, b, da, sa)
1597 uint r = OP( d.red(), sr);
1598 uint b = OP( d.blue(), sb);
1599 uint g = OP(d.green(), sg);
1600 uint a = mix_alpha_rgb64(da, sa);
1601#undef OP
1602
1603 coverage.store(&dest[i], qRgba64(r, g, b, a));
1604 }
1605}
1606
1607void QT_FASTCALL comp_func_solid_Darken_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
1608{
1609 if (const_alpha == 255)
1610 comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
1611 else
1612 comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
1613}
1614#endif
1615
1616template <typename T>
1617static inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
1618{
1619 for (int i = 0; i < length; ++i) {
1620 uint d = dest[i];
1621 uint s = src[i];
1622
1623 int da = qAlpha(d);
1624 int sa = qAlpha(s);
1625
1626#define OP(a, b) darken_op(a, b, da, sa)
1627 int r = OP( qRed(d), qRed(s));
1628 int b = OP( qBlue(d), qBlue(s));
1629 int g = OP(qGreen(d), qGreen(s));
1630 int a = mix_alpha(da, sa);
1631#undef OP
1632
1633 coverage.store(&dest[i], qRgba(r, g, b, a));
1634 }
1635}
1636
1637void QT_FASTCALL comp_func_Darken(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
1638{
1639 if (const_alpha == 255)
1640 comp_func_Darken_impl(dest, src, length, QFullCoverage());
1641 else
1642 comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
1643}
1644
1645#if QT_CONFIG(raster_64bit)
1646template <typename T>
1647static inline void comp_func_Darken_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
1648{
1649 for (int i = 0; i < length; ++i) {
1650 QRgba64 d = dest[i];
1651 QRgba64 s = src[i];
1652
1653 uint da = d.alpha();
1654 uint sa = s.alpha();
1655
1656#define OP(a, b) darken_op_rgb64(a, b, da, sa)
1657 uint r = OP( d.red(), s.red());
1658 uint b = OP( d.blue(), s.blue());
1659 uint g = OP(d.green(), s.green());
1660 uint a = mix_alpha_rgb64(da, sa);
1661#undef OP
1662
1663 coverage.store(&dest[i], qRgba64(r, g, b, a));
1664 }
1665}
1666
1667void QT_FASTCALL comp_func_Darken_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
1668{
1669 if (const_alpha == 255)
1670 comp_func_Darken_impl(dest, src, length, QFullCoverage());
1671 else
1672 comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
1673}
1674#endif
1675
1676/*
1677 Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
1678 Da' = Sa + Da - Sa.Da
1679*/
1680static inline int lighten_op(int dst, int src, int da, int sa)
1681{
1682 return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
1683}
1684
1685template <typename T>
1686static inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage)
1687{
1688 int sa = qAlpha(color);
1689 int sr = qRed(color);
1690 int sg = qGreen(color);
1691 int sb = qBlue(color);
1692
1693 for (int i = 0; i < length; ++i) {
1694 uint d = dest[i];
1695 int da = qAlpha(d);
1696
1697#define OP(a, b) lighten_op(a, b, da, sa)
1698 int r = OP( qRed(d), sr);
1699 int b = OP( qBlue(d), sb);
1700 int g = OP(qGreen(d), sg);
1701 int a = mix_alpha(da, sa);
1702#undef OP
1703
1704 coverage.store(&dest[i], qRgba(r, g, b, a));
1705 }
1706}
1707
1708void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha)
1709{
1710 if (const_alpha == 255)
1711 comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
1712 else
1713 comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
1714}
1715
1716
1717#if QT_CONFIG(raster_64bit)
1718static inline uint lighten_op_rgb64(uint dst, uint src, uint da, uint sa)
1719{
1720 return qt_div_65535(qMax(src * da, dst * sa) + src * (65535 - da) + dst * (65535 - sa));
1721}
1722
1723template <typename T>
1724static inline void comp_func_solid_Lighten_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
1725{
1726 uint sa = color.alpha();
1727 uint sr = color.red();
1728 uint sg = color.green();
1729 uint sb = color.blue();
1730
1731 for (int i = 0; i < length; ++i) {
1732 QRgba64 d = dest[i];
1733 uint da = d.alpha();
1734
1735#define OP(a, b) lighten_op_rgb64(a, b, da, sa)
1736 uint r = OP( d.red(), sr);
1737 uint b = OP( d.blue(), sb);
1738 uint g = OP(d.green(), sg);
1739 uint a = mix_alpha_rgb64(da, sa);
1740#undef OP
1741
1742 coverage.store(&dest[i], qRgba64(r, g, b, a));
1743 }
1744}
1745
1746void QT_FASTCALL comp_func_solid_Lighten_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
1747{
1748 if (const_alpha == 255)
1749 comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
1750 else
1751 comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
1752}
1753#endif
1754
1755template <typename T>
1756static inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
1757{
1758 for (int i = 0; i < length; ++i) {
1759 uint d = dest[i];
1760 uint s = src[i];
1761
1762 int da = qAlpha(d);
1763 int sa = qAlpha(s);
1764
1765#define OP(a, b) lighten_op(a, b, da, sa)
1766 int r = OP( qRed(d), qRed(s));
1767 int b = OP( qBlue(d), qBlue(s));
1768 int g = OP(qGreen(d), qGreen(s));
1769 int a = mix_alpha(da, sa);
1770#undef OP
1771
1772 coverage.store(&dest[i], qRgba(r, g, b, a));
1773 }
1774}
1775
1776void QT_FASTCALL comp_func_Lighten(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
1777{
1778 if (const_alpha == 255)
1779 comp_func_Lighten_impl(dest, src, length, QFullCoverage());
1780 else
1781 comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
1782}
1783
1784#if QT_CONFIG(raster_64bit)
1785template <typename T>
1786static inline void comp_func_Lighten_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
1787{
1788 for (int i = 0; i < length; ++i) {
1789 QRgba64 d = dest[i];
1790 QRgba64 s = src[i];
1791
1792 uint da = d.alpha();
1793 uint sa = s.alpha();
1794
1795#define OP(a, b) lighten_op_rgb64(a, b, da, sa)
1796 uint r = OP( d.red(), s.red());
1797 uint b = OP( d.blue(), s.blue());
1798 uint g = OP(d.green(), s.green());
1799 uint a = mix_alpha_rgb64(da, sa);
1800#undef OP
1801
1802 coverage.store(&dest[i], qRgba64(r, g, b, a));
1803 }
1804}
1805
1806void QT_FASTCALL comp_func_Lighten_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
1807{
1808 if (const_alpha == 255)
1809 comp_func_Lighten_impl(dest, src, length, QFullCoverage());
1810 else
1811 comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
1812}
1813#endif
1814
1815/*
1816 if Sca.Da + Dca.Sa >= Sa.Da
1817 Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
1818 otherwise
1819 Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
1820*/
1821static inline int color_dodge_op(int dst, int src, int da, int sa)
1822{
1823 const int sa_da = sa * da;
1824 const int dst_sa = dst * sa;
1825 const int src_da = src * da;
1826
1827 const int temp = src * (255 - da) + dst * (255 - sa);
1828 if (src_da + dst_sa >= sa_da)
1829 return qt_div_255(sa_da + temp);
1830 else
1831 return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp);
1832}
1833
1834template <typename T>
1835static inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage)
1836{
1837 int sa = qAlpha(color);
1838 int sr = qRed(color);
1839 int sg = qGreen(color);
1840 int sb = qBlue(color);
1841
1842 for (int i = 0; i < length; ++i) {
1843 uint d = dest[i];
1844 int da = qAlpha(d);
1845
1846#define OP(a,b) color_dodge_op(a, b, da, sa)
1847 int r = OP( qRed(d), sr);
1848 int b = OP( qBlue(d), sb);
1849 int g = OP(qGreen(d), sg);
1850 int a = mix_alpha(da, sa);
1851#undef OP
1852
1853 coverage.store(&dest[i], qRgba(r, g, b, a));
1854 }
1855}
1856
1857void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha)
1858{
1859 if (const_alpha == 255)
1860 comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
1861 else
1862 comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
1863}
1864
1865#if QT_CONFIG(raster_64bit)
1866static inline uint color_dodge_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa)
1867{
1868 const qint64 sa_da = sa * da;
1869 const qint64 dst_sa = dst * sa;
1870 const qint64 src_da = src * da;
1871
1872 const qint64 temp = src * (65535 - da) + dst * (65535 - sa);
1873 if (src_da + dst_sa >= sa_da)
1874 return qt_div_65535(sa_da + temp);
1875 else
1876 return qt_div_65535(65535 * dst_sa / (65535 - 65535 * src / sa) + temp);
1877}
1878
1879template <typename T>
1880static inline void comp_func_solid_ColorDodge_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
1881{
1882 uint sa = color.alpha();
1883 uint sr = color.red();
1884 uint sg = color.green();
1885 uint sb = color.blue();
1886
1887 for (int i = 0; i < length; ++i) {
1888 QRgba64 d = dest[i];
1889 uint da = d.alpha();
1890
1891#define OP(a,b) color_dodge_op_rgb64(a, b, da, sa)
1892 uint r = OP( d.red(), sr);
1893 uint b = OP( d.blue(), sb);
1894 uint g = OP(d.green(), sg);
1895 uint a = mix_alpha_rgb64(da, sa);
1896#undef OP
1897
1898 coverage.store(&dest[i], qRgba64(r, g, b, a));
1899 }
1900}
1901
1902void QT_FASTCALL comp_func_solid_ColorDodge_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
1903{
1904 if (const_alpha == 255)
1905 comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
1906 else
1907 comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
1908}
1909#endif
1910
1911template <typename T>
1912static inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
1913{
1914 for (int i = 0; i < length; ++i) {
1915 uint d = dest[i];
1916 uint s = src[i];
1917
1918 int da = qAlpha(d);
1919 int sa = qAlpha(s);
1920
1921#define OP(a, b) color_dodge_op(a, b, da, sa)
1922 int r = OP( qRed(d), qRed(s));
1923 int b = OP( qBlue(d), qBlue(s));
1924 int g = OP(qGreen(d), qGreen(s));
1925 int a = mix_alpha(da, sa);
1926#undef OP
1927
1928 coverage.store(&dest[i], qRgba(r, g, b, a));
1929 }
1930}
1931
1932void QT_FASTCALL comp_func_ColorDodge(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
1933{
1934 if (const_alpha == 255)
1935 comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
1936 else
1937 comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
1938}
1939
1940#if QT_CONFIG(raster_64bit)
1941template <typename T>
1942static inline void comp_func_ColorDodge_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
1943{
1944 for (int i = 0; i < length; ++i) {
1945 QRgba64 d = dest[i];
1946 QRgba64 s = src[i];
1947
1948 uint da = d.alpha();
1949 uint sa = s.alpha();
1950
1951#define OP(a, b) color_dodge_op_rgb64(a, b, da, sa)
1952 uint r = OP( d.red(), s.red());
1953 uint b = OP( d.blue(), s.blue());
1954 uint g = OP(d.green(), s.green());
1955 uint a = mix_alpha_rgb64(da, sa);
1956#undef OP
1957
1958 coverage.store(&dest[i], qRgba64(r, g, b, a));
1959 }
1960}
1961
1962void QT_FASTCALL comp_func_ColorDodge_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
1963{
1964 if (const_alpha == 255)
1965 comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
1966 else
1967 comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
1968}
1969#endif
1970
1971/*
1972 if Sca.Da + Dca.Sa <= Sa.Da
1973 Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
1974 otherwise
1975 Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
1976*/
1977static inline int color_burn_op(int dst, int src, int da, int sa)
1978{
1979 const int src_da = src * da;
1980 const int dst_sa = dst * sa;
1981 const int sa_da = sa * da;
1982
1983 const int temp = src * (255 - da) + dst * (255 - sa);
1984
1985 if (src == 0 || src_da + dst_sa <= sa_da)
1986 return qt_div_255(temp);
1987 return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp);
1988}
1989
1990template <typename T>
1991static inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage)
1992{
1993 int sa = qAlpha(color);
1994 int sr = qRed(color);
1995 int sg = qGreen(color);
1996 int sb = qBlue(color);
1997
1998 for (int i = 0; i < length; ++i) {
1999 uint d = dest[i];
2000 int da = qAlpha(d);
2001
2002#define OP(a, b) color_burn_op(a, b, da, sa)
2003 int r = OP( qRed(d), sr);
2004 int b = OP( qBlue(d), sb);
2005 int g = OP(qGreen(d), sg);
2006 int a = mix_alpha(da, sa);
2007#undef OP
2008
2009 coverage.store(&dest[i], qRgba(r, g, b, a));
2010 }
2011}
2012
2013void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha)
2014{
2015 if (const_alpha == 255)
2016 comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
2017 else
2018 comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
2019}
2020
2021#if QT_CONFIG(raster_64bit)
2022static inline uint color_burn_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa)
2023{
2024 const qint64 src_da = src * da;
2025 const qint64 dst_sa = dst * sa;
2026 const qint64 sa_da = sa * da;
2027
2028 const qint64 temp = src * (65535 - da) + dst * (65535 - sa);
2029
2030 if (src == 0 || src_da + dst_sa <= sa_da)
2031 return qt_div_65535(temp);
2032 return qt_div_65535(sa * (src_da + dst_sa - sa_da) / src + temp);
2033}
2034
2035template <typename T>
2036static inline void comp_func_solid_ColorBurn_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
2037{
2038 uint sa = color.alpha();
2039 uint sr = color.red();
2040 uint sg = color.green();
2041 uint sb = color.blue();
2042
2043 for (int i = 0; i < length; ++i) {
2044 QRgba64 d = dest[i];
2045 uint da = d.alpha();
2046
2047#define OP(a, b) color_burn_op_rgb64(a, b, da, sa)
2048 uint r = OP( d.red(), sr);
2049 uint b = OP( d.blue(), sb);
2050 uint g = OP(d.green(), sg);
2051 uint a = mix_alpha_rgb64(da, sa);
2052#undef OP
2053
2054 coverage.store(&dest[i], qRgba64(r, g, b, a));
2055 }
2056}
2057
2058void QT_FASTCALL comp_func_solid_ColorBurn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
2059{
2060 if (const_alpha == 255)
2061 comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
2062 else
2063 comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
2064}
2065#endif
2066
2067template <typename T>
2068static inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2069{
2070 for (int i = 0; i < length; ++i) {
2071 uint d = dest[i];
2072 uint s = src[i];
2073
2074 int da = qAlpha(d);
2075 int sa = qAlpha(s);
2076
2077#define OP(a, b) color_burn_op(a, b, da, sa)
2078 int r = OP( qRed(d), qRed(s));
2079 int b = OP( qBlue(d), qBlue(s));
2080 int g = OP(qGreen(d), qGreen(s));
2081 int a = mix_alpha(da, sa);
2082#undef OP
2083
2084 coverage.store(&dest[i], qRgba(r, g, b, a));
2085 }
2086}
2087
2088void QT_FASTCALL comp_func_ColorBurn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2089{
2090 if (const_alpha == 255)
2091 comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
2092 else
2093 comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
2094}
2095
2096#if QT_CONFIG(raster_64bit)
2097template <typename T>
2098static inline void comp_func_ColorBurn_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
2099{
2100 for (int i = 0; i < length; ++i) {
2101 QRgba64 d = dest[i];
2102 QRgba64 s = src[i];
2103
2104 uint da = d.alpha();
2105 uint sa = s.alpha();
2106
2107#define OP(a, b) color_burn_op_rgb64(a, b, da, sa)
2108 uint r = OP( d.red(), s.red());
2109 uint b = OP( d.blue(), s.blue());
2110 uint g = OP(d.green(), s.green());
2111 uint a = mix_alpha_rgb64(da, sa);
2112#undef OP
2113
2114 coverage.store(&dest[i], qRgba64(r, g, b, a));
2115 }
2116}
2117
2118void QT_FASTCALL comp_func_ColorBurn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
2119{
2120 if (const_alpha == 255)
2121 comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
2122 else
2123 comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
2124}
2125#endif
2126
2127/*
2128 if 2.Sca < Sa
2129 Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
2130 otherwise
2131 Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
2132*/
2133static inline uint hardlight_op(int dst, int src, int da, int sa)
2134{
2135 const uint temp = src * (255 - da) + dst * (255 - sa);
2136
2137 if (2 * src < sa)
2138 return qt_div_255(2 * src * dst + temp);
2139 else
2140 return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
2141}
2142
2143template <typename T>
2144static inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage)
2145{
2146 int sa = qAlpha(color);
2147 int sr = qRed(color);
2148 int sg = qGreen(color);
2149 int sb = qBlue(color);
2150
2151 for (int i = 0; i < length; ++i) {
2152 uint d = dest[i];
2153 int da = qAlpha(d);
2154
2155#define OP(a, b) hardlight_op(a, b, da, sa)
2156 int r = OP( qRed(d), sr);
2157 int b = OP( qBlue(d), sb);
2158 int g = OP(qGreen(d), sg);
2159 int a = mix_alpha(da, sa);
2160#undef OP
2161
2162 coverage.store(&dest[i], qRgba(r, g, b, a));
2163 }
2164}
2165
2166void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha)
2167{
2168 if (const_alpha == 255)
2169 comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
2170 else
2171 comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2172}
2173
2174#if QT_CONFIG(raster_64bit)
2175static inline uint hardlight_op_rgb64(uint dst, uint src, uint da, uint sa)
2176{
2177 const uint temp = src * (65535 - da) + dst * (65535 - sa);
2178
2179 if (2 * src < sa)
2180 return qt_div_65535(2 * src * dst + temp);
2181 else
2182 return qt_div_65535(sa * da - 2 * (da - dst) * (sa - src) + temp);
2183}
2184
2185template <typename T>
2186static inline void comp_func_solid_HardLight_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
2187{
2188 uint sa = color.alpha();
2189 uint sr = color.red();
2190 uint sg = color.green();
2191 uint sb = color.blue();
2192
2193 for (int i = 0; i < length; ++i) {
2194 QRgba64 d = dest[i];
2195 uint da = d.alpha();
2196
2197#define OP(a, b) hardlight_op_rgb64(a, b, da, sa)
2198 uint r = OP( d.red(), sr);
2199 uint b = OP( d.blue(), sb);
2200 uint g = OP(d.green(), sg);
2201 uint a = mix_alpha_rgb64(da, sa);
2202#undef OP
2203
2204 coverage.store(&dest[i], qRgba64(r, g, b, a));
2205 }
2206}
2207
2208void QT_FASTCALL comp_func_solid_HardLight_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
2209{
2210 if (const_alpha == 255)
2211 comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
2212 else
2213 comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2214}
2215#endif
2216
2217template <typename T>
2218static inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2219{
2220 for (int i = 0; i < length; ++i) {
2221 uint d = dest[i];
2222 uint s = src[i];
2223
2224 int da = qAlpha(d);
2225 int sa = qAlpha(s);
2226
2227#define OP(a, b) hardlight_op(a, b, da, sa)
2228 int r = OP( qRed(d), qRed(s));
2229 int b = OP( qBlue(d), qBlue(s));
2230 int g = OP(qGreen(d), qGreen(s));
2231 int a = mix_alpha(da, sa);
2232#undef OP
2233
2234 coverage.store(&dest[i], qRgba(r, g, b, a));
2235 }
2236}
2237
2238void QT_FASTCALL comp_func_HardLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2239{
2240 if (const_alpha == 255)
2241 comp_func_HardLight_impl(dest, src, length, QFullCoverage());
2242 else
2243 comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2244}
2245
2246#if QT_CONFIG(raster_64bit)
2247template <typename T>
2248static inline void comp_func_HardLight_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
2249{
2250 for (int i = 0; i < length; ++i) {
2251 QRgba64 d = dest[i];
2252 QRgba64 s = src[i];
2253
2254 uint da = d.alpha();
2255 uint sa = s.alpha();
2256
2257#define OP(a, b) hardlight_op_rgb64(a, b, da, sa)
2258 uint r = OP( d.red(), s.red());
2259 uint b = OP( d.blue(), s.blue());
2260 uint g = OP(d.green(), s.green());
2261 uint a = mix_alpha_rgb64(da, sa);
2262#undef OP
2263
2264 coverage.store(&dest[i], qRgba64(r, g, b, a));
2265 }
2266}
2267
2268void QT_FASTCALL comp_func_HardLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
2269{
2270 if (const_alpha == 255)
2271 comp_func_HardLight_impl(dest, src, length, QFullCoverage());
2272 else
2273 comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2274}
2275#endif
2276
2277/*
2278 if 2.Sca <= Sa
2279 Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
2280 otherwise if 2.Sca > Sa and 4.Dca <= Da
2281 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)
2282 otherwise if 2.Sca > Sa and 4.Dca > Da
2283 Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2284*/
2285static inline int soft_light_op(int dst, int src, int da, int sa)
2286{
2287 const int src2 = src << 1;
2288 const int dst_np = da != 0 ? (255 * dst) / da : 0;
2289 const int temp = (src * (255 - da) + dst * (255 - sa)) * 255;
2290
2291 if (src2 < sa)
2292 return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025;
2293 else if (4 * dst <= da)
2294 return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025;
2295 else {
2296 return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025;
2297 }
2298}
2299
2300template <typename T>
2301static inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage)
2302{
2303 int sa = qAlpha(color);
2304 int sr = qRed(color);
2305 int sg = qGreen(color);
2306 int sb = qBlue(color);
2307
2308 for (int i = 0; i < length; ++i) {
2309 uint d = dest[i];
2310 int da = qAlpha(d);
2311
2312#define OP(a, b) soft_light_op(a, b, da, sa)
2313 int r = OP( qRed(d), sr);
2314 int b = OP( qBlue(d), sb);
2315 int g = OP(qGreen(d), sg);
2316 int a = mix_alpha(da, sa);
2317#undef OP
2318
2319 coverage.store(&dest[i], qRgba(r, g, b, a));
2320 }
2321}
2322
2323#if QT_CONFIG(raster_64bit)
2324static inline uint soft_light_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa)
2325{
2326 const qint64 src2 = src << 1;
2327 const qint64 dst_np = da != 0 ? (65535 * dst) / da : 0;
2328 const qint64 temp = (src * (65535 - da) + dst * (65535 - sa)) * 65535;
2329 const qint64 factor = qint64(65535) * 65535;
2330
2331 if (src2 < sa)
2332 return (dst * (sa * 65535 + (src2 - sa) * (65535 - dst_np)) + temp) / factor;
2333 else if (4 * dst <= da)
2334 return (dst * sa * 65535 + da * (src2 - sa) * ((((16 * dst_np - 12 * 65535) * dst_np + 3 * factor) * dst_np) / factor) + temp) / factor;
2335 else {
2336 return (dst * sa * 65535 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 65535))) - dst_np) + temp) / factor;
2337 }
2338}
2339
2340template <typename T>
2341static inline void comp_func_solid_SoftLight_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
2342{
2343 uint sa = color.alpha();
2344 uint sr = color.red();
2345 uint sg = color.green();
2346 uint sb = color.blue();
2347
2348 for (int i = 0; i < length; ++i) {
2349 QRgba64 d = dest[i];
2350 uint da = d.alpha();
2351
2352#define OP(a, b) soft_light_op_rgb64(a, b, da, sa)
2353 uint r = OP( d.red(), sr);
2354 uint b = OP( d.blue(), sb);
2355 uint g = OP(d.green(), sg);
2356 uint a = mix_alpha_rgb64(da, sa);
2357#undef OP
2358
2359 coverage.store(&dest[i], qRgba64(r, g, b, a));
2360 }
2361}
2362#endif
2363
2364void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
2365{
2366 if (const_alpha == 255)
2367 comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
2368 else
2369 comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2370}
2371
2372template <typename T>
2373static inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2374{
2375 for (int i = 0; i < length; ++i) {
2376 uint d = dest[i];
2377 uint s = src[i];
2378
2379 int da = qAlpha(d);
2380 int sa = qAlpha(s);
2381
2382#define OP(a, b) soft_light_op(a, b, da, sa)
2383 int r = OP( qRed(d), qRed(s));
2384 int b = OP( qBlue(d), qBlue(s));
2385 int g = OP(qGreen(d), qGreen(s));
2386 int a = mix_alpha(da, sa);
2387#undef OP
2388
2389 coverage.store(&dest[i], qRgba(r, g, b, a));
2390 }
2391}
2392
2393void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2394{
2395 if (const_alpha == 255)
2396 comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
2397 else
2398 comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2399}
2400
2401#if QT_CONFIG(raster_64bit)
2402void QT_FASTCALL comp_func_solid_SoftLight_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
2403{
2404 if (const_alpha == 255)
2405 comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
2406 else
2407 comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
2408}
2409
2410template <typename T>
2411static inline void comp_func_SoftLight_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
2412{
2413 for (int i = 0; i < length; ++i) {
2414 QRgba64 d = dest[i];
2415 QRgba64 s = src[i];
2416
2417 uint da = d.alpha();
2418 uint sa = s.alpha();
2419
2420#define OP(a, b) soft_light_op_rgb64(a, b, da, sa)
2421 uint r = OP( d.red(), s.red());
2422 uint b = OP( d.blue(), s.blue());
2423 uint g = OP(d.green(), s.green());
2424 uint a = mix_alpha_rgb64(da, sa);
2425#undef OP
2426
2427 coverage.store(&dest[i], qRgba64(r, g, b, a));
2428 }
2429}
2430
2431void QT_FASTCALL comp_func_SoftLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
2432{
2433 if (const_alpha == 255)
2434 comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
2435 else
2436 comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
2437}
2438#endif
2439
2440/*
2441 Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
2442 = Sca + Dca - 2.min(Sca.Da, Dca.Sa)
2443*/
2444static inline int difference_op(int dst, int src, int da, int sa)
2445{
2446 return src + dst - qt_div_255(2 * qMin(src * da, dst * sa));
2447}
2448
2449template <typename T>
2450static inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage)
2451{
2452 int sa = qAlpha(color);
2453 int sr = qRed(color);
2454 int sg = qGreen(color);
2455 int sb = qBlue(color);
2456
2457 for (int i = 0; i < length; ++i) {
2458 uint d = dest[i];
2459 int da = qAlpha(d);
2460
2461#define OP(a, b) difference_op(a, b, da, sa)
2462 int r = OP( qRed(d), sr);
2463 int b = OP( qBlue(d), sb);
2464 int g = OP(qGreen(d), sg);
2465 int a = mix_alpha(da, sa);
2466#undef OP
2467
2468 coverage.store(&dest[i], qRgba(r, g, b, a));
2469 }
2470}
2471
2472void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha)
2473{
2474 if (const_alpha == 255)
2475 comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
2476 else
2477 comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
2478}
2479
2480#if QT_CONFIG(raster_64bit)
2481static inline uint difference_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa)
2482{
2483 return src + dst - qt_div_65535(2 * qMin(src * da, dst * sa));
2484}
2485
2486template <typename T>
2487static inline void comp_func_solid_Difference_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
2488{
2489 uint sa = color.alpha();
2490 uint sr = color.red();
2491 uint sg = color.green();
2492 uint sb = color.blue();
2493
2494 for (int i = 0; i < length; ++i) {
2495 QRgba64 d = dest[i];
2496 uint da = d.alpha();
2497
2498#define OP(a, b) difference_op_rgb64(a, b, da, sa)
2499 uint r = OP( d.red(), sr);
2500 uint b = OP( d.blue(), sb);
2501 uint g = OP(d.green(), sg);
2502 uint a = mix_alpha_rgb64(da, sa);
2503#undef OP
2504
2505 coverage.store(&dest[i], qRgba64(r, g, b, a));
2506 }
2507}
2508
2509void QT_FASTCALL comp_func_solid_Difference_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
2510{
2511 if (const_alpha == 255)
2512 comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
2513 else
2514 comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
2515}
2516#endif
2517
2518template <typename T>
2519static inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
2520{
2521 for (int i = 0; i < length; ++i) {
2522 uint d = dest[i];
2523 uint s = src[i];
2524
2525 int da = qAlpha(d);
2526 int sa = qAlpha(s);
2527
2528#define OP(a, b) difference_op(a, b, da, sa)
2529 int r = OP( qRed(d), qRed(s));
2530 int b = OP( qBlue(d), qBlue(s));
2531 int g = OP(qGreen(d), qGreen(s));
2532 int a = mix_alpha(da, sa);
2533#undef OP
2534
2535 coverage.store(&dest[i], qRgba(r, g, b, a));
2536 }
2537}
2538
2539void QT_FASTCALL comp_func_Difference(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
2540{
2541 if (const_alpha == 255)
2542 comp_func_Difference_impl(dest, src, length, QFullCoverage());
2543 else
2544 comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
2545}
2546
2547#if QT_CONFIG(raster_64bit)
2548template <typename T>
2549static inline void comp_func_Difference_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
2550{
2551 for (int i = 0; i < length; ++i) {
2552 QRgba64 d = dest[i];
2553 QRgba64 s = src[i];
2554
2555 uint da = d.alpha();
2556 uint sa = s.alpha();
2557
2558#define OP(a, b) difference_op_rgb64(a, b, da, sa)
2559 uint r = OP( d.red(), s.red());
2560 uint b = OP( d.blue(), s.blue());
2561 uint g = OP(d.green(), s.green());
2562 uint a = mix_alpha_rgb64(da, sa);
2563#undef OP
2564
2565 coverage.store(&dest[i], qRgba64(r, g, b, a));
2566 }
2567}
2568
2569void QT_FASTCALL comp_func_Difference_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
2570{
2571 if (const_alpha == 255)
2572 comp_func_Difference_impl(dest, src, length, QFullCoverage());
2573 else
2574 comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
2575}
2576#endif
2577
2578/*
2579 Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
2580*/
2581template <typename T>
2582static inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage)
2583{
2584 int sa = qAlpha(