diff options
Diffstat (limited to 'src/gui/painting')
-rw-r--r-- | src/gui/painting/painting.pri | 3 | ||||
-rw-r--r-- | src/gui/painting/qcolor.cpp | 88 | ||||
-rw-r--r-- | src/gui/painting/qcolor.h | 8 | ||||
-rw-r--r-- | src/gui/painting/qcompositionfunctions.cpp | 2197 | ||||
-rw-r--r-- | src/gui/painting/qcosmeticstroker.cpp | 3 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper.cpp | 3546 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_neon.cpp | 7 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_neon_p.h | 2 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_p.h | 214 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_sse2.cpp | 103 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_x86_p.h | 6 | ||||
-rw-r--r-- | src/gui/painting/qmatrix.cpp | 24 | ||||
-rw-r--r-- | src/gui/painting/qmatrix.h | 2 | ||||
-rw-r--r-- | src/gui/painting/qpaintengine_raster.cpp | 102 | ||||
-rw-r--r-- | src/gui/painting/qpainter_p.h | 1 | ||||
-rw-r--r-- | src/gui/painting/qrgba64.h | 204 | ||||
-rw-r--r-- | src/gui/painting/qrgba64.qdoc | 241 | ||||
-rw-r--r-- | src/gui/painting/qrgba64_p.h | 120 | ||||
-rw-r--r-- | src/gui/painting/qtransform.cpp | 24 | ||||
-rw-r--r-- | src/gui/painting/qtransform.h | 2 |
20 files changed, 4686 insertions, 2211 deletions
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index a861516821..791b5f1a9a 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -43,6 +43,8 @@ HEADERS += \ painting/qrasterizer_p.h \ painting/qregion.h \ painting/qrgb.h \ + painting/qrgba64.h \ + painting/qrgba64_p.h \ painting/qstroker_p.h \ painting/qtextureglyphcache_p.h \ painting/qtransform.h \ @@ -58,6 +60,7 @@ SOURCES += \ painting/qbrush.cpp \ painting/qcolor.cpp \ painting/qcolor_p.cpp \ + painting/qcompositionfunctions.cpp \ painting/qcosmeticstroker.cpp \ painting/qcssutil.cpp \ painting/qdrawhelper.cpp \ diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index a6b44cde15..b33d7a74fc 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -416,6 +416,18 @@ QColor::QColor(QRgb color) ct.argb.pad = 0; } +/*! + \since 5.6 + + Constructs a color with the value \a rgba64. + + \sa fromRgba64() +*/ + +QColor::QColor(QRgba64 rgba64) +{ + setRgba64(rgba64); +} /*! \internal @@ -941,7 +953,7 @@ void QColor::setRgb(int r, int g, int b, int a) For an invalid color, the alpha value of the returned color is unspecified. - \sa setRgba(), rgb() + \sa setRgba(), rgb(), rgba64() */ QRgb QColor::rgba() const @@ -954,7 +966,7 @@ QRgb QColor::rgba() const /*! Sets the RGB value to \a rgba, including its alpha. - \sa rgba(), rgb() + \sa rgba(), rgb(), setRgba64() */ void QColor::setRgba(QRgb rgba) { @@ -967,6 +979,40 @@ void QColor::setRgba(QRgb rgba) } /*! + \since 5.6 + + Returns the RGB64 value of the color, including its alpha. + + For an invalid color, the alpha value of the returned color is unspecified. + + \sa setRgba64(), rgba(), rgb() +*/ + +QRgba64 QColor::rgba64() const +{ + if (cspec != Invalid && cspec != Rgb) + return toRgb().rgba64(); + return qRgba64(ct.argb.red, ct.argb.green, ct.argb.blue, ct.argb.alpha); +} + +/*! + \since 5.6 + + Sets the RGB64 value to \a rgba, including its alpha. + + \sa \setRgba(), rgba64() +*/ +void QColor::setRgba64(QRgba64 rgba) +{ + cspec = Rgb; + ct.argb.alpha = rgba.alpha(); + ct.argb.red = rgba.red(); + ct.argb.green = rgba.green(); + ct.argb.blue = rgba.blue(); + ct.argb.pad = 0; +} + +/*! \fn QRgb QColor::rgb() const Returns the RGB value of the color. The alpha value is opaque. @@ -1850,7 +1896,7 @@ QColor QColor::fromRgb(QRgb rgb) Unlike the fromRgb() function, the alpha-channel specified by the given QRgb value is included. - \sa fromRgb(), isValid() + \sa fromRgb(), fromRgba64(), isValid() */ QColor QColor::fromRgba(QRgb rgba) @@ -1865,7 +1911,7 @@ QColor QColor::fromRgba(QRgb rgba) All the values must be in the range 0-255. - \sa toRgb(), fromRgbF(), isValid() + \sa toRgb(), fromRgba64(), fromRgbF(), isValid() */ QColor QColor::fromRgb(int r, int g, int b, int a) { @@ -1894,7 +1940,7 @@ QColor QColor::fromRgb(int r, int g, int b, int a) All the values must be in the range 0.0-1.0. - \sa fromRgb(), toRgb(), isValid() + \sa fromRgb(), fromRgba64(), toRgb(), isValid() */ QColor QColor::fromRgbF(qreal r, qreal g, qreal b, qreal a) { @@ -1916,6 +1962,38 @@ QColor QColor::fromRgbF(qreal r, qreal g, qreal b, qreal a) return color; } + +/*! + \since 5.6 + + Static convenience function that returns a QColor constructed from the RGBA64 + color values, \a r (red), \a g (green), \a b (blue), and \a a + (alpha-channel, i.e. transparency). + + \sa fromRgb(), fromRgbF(), toRgb(), isValid() +*/ +QColor QColor::fromRgba64(ushort r, ushort g, ushort b, ushort a) +{ + QColor color; + color.setRgba64(qRgba64(r, g, b, a)); + return color; +} + +/*! + \since 5.6 + + Static convenience function that returns a QColor constructed from the + given QRgba64 value \a rgba64. + + \sa fromRgb(), fromRgbF(), toRgb(), isValid() +*/ +QColor QColor::fromRgba64(QRgba64 rgba64) +{ + QColor color; + color.setRgba64(rgba64); + return color; +} + /*! Static convenience function that returns a QColor constructed from the HSV color values, \a h (hue), \a s (saturation), \a v (value), and \a a diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h index 06c218365b..9175875310 100644 --- a/src/gui/painting/qcolor.h +++ b/src/gui/painting/qcolor.h @@ -37,6 +37,7 @@ #include <QtGui/qrgb.h> #include <QtCore/qnamespace.h> #include <QtCore/qstringlist.h> +#include <QtGui/qrgba64.h> QT_BEGIN_NAMESPACE @@ -63,6 +64,7 @@ public: QColor(Qt::GlobalColor color); QColor(int r, int g, int b, int a = 255); QColor(QRgb rgb); + QColor(QRgba64 rgba64); QColor(const QString& name); QColor(const char *name); QColor(const QColor &color); // ### Qt 6: remove, the trivial one is fine. @@ -109,6 +111,9 @@ public: QRgb rgba() const; void setRgba(QRgb rgba); + QRgba64 rgba64() const; + void setRgba64(QRgba64 rgba); + QRgb rgb() const; void setRgb(QRgb rgb); @@ -173,6 +178,9 @@ public: static QColor fromRgb(int r, int g, int b, int a = 255); static QColor fromRgbF(qreal r, qreal g, qreal b, qreal a = 1.0); + static QColor fromRgba64(ushort r, ushort g, ushort b, ushort a = USHRT_MAX); + static QColor fromRgba64(QRgba64 rgba); + static QColor fromHsv(int h, int s, int v, int a = 255); static QColor fromHsvF(qreal h, qreal s, qreal v, qreal a = 1.0); diff --git a/src/gui/painting/qcompositionfunctions.cpp b/src/gui/painting/qcompositionfunctions.cpp new file mode 100644 index 0000000000..ba428a7938 --- /dev/null +++ b/src/gui/painting/qcompositionfunctions.cpp @@ -0,0 +1,2197 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qglobal.h> +#include <private/qdrawhelper_p.h> +#include <private/qrgba64_p.h> + +QT_BEGIN_NAMESPACE + +# define PRELOAD_INIT(x) +# define PRELOAD_INIT2(x,y) +# define PRELOAD_COND(x) +# define PRELOAD_COND2(x,y) + +/* The constant alpha factor describes an alpha factor that gets applied + to the result of the composition operation combining it with the destination. + + The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1. + we get the unmodified operation + + result = src op dest + dest = result * const_alpha + dest * (1. - const_alpha) + + This means that in the comments below, the first line is the const_alpha==255 case, the + second line the general one. + + In the lines below: + s == src, sa == alpha(src), sia = 1 - alpha(src) + d == dest, da == alpha(dest), dia = 1 - alpha(dest) + ca = const_alpha, cia = 1 - const_alpha + + The methods exist in two variants. One where we have a constant source, the other + where the source is an array of pixels. +*/ + +/* + result = 0 + d = d * cia +*/ +#define comp_func_Clear_impl(dest, length, const_alpha)\ +{\ + if (const_alpha == 255) {\ + QT_MEMFILL_UINT(dest, length, 0);\ + } else {\ + int ialpha = 255 - const_alpha;\ + PRELOAD_INIT(dest)\ + for (int i = 0; i < length; ++i) {\ + PRELOAD_COND(dest)\ + dest[i] = BYTE_MUL(dest[i], ialpha);\ + }\ + }\ +} + +void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha) +{ + comp_func_Clear_impl(dest, length, const_alpha); +} + +void QT_FASTCALL comp_func_solid_Clear_rgb64(QRgba64 *dest, int length, QRgba64, uint const_alpha) +{ + if (const_alpha == 255) + qt_memfill64((quint64*)dest, 0, length); + else { + int ialpha = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha255(dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha) +{ + comp_func_Clear_impl(dest, length, const_alpha); +} + +void QT_FASTCALL comp_func_Clear_rgb64(QRgba64 *dest, const QRgba64 *, int length, uint const_alpha) +{ + if (const_alpha == 255) + qt_memfill64((quint64*)dest, 0, length); + else { + int ialpha = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha255(dest[i], ialpha); + } + } +} + +/* + result = s + dest = s * ca + d * cia +*/ +void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) { + QT_MEMFILL_UINT(dest, length, color); + } else { + int ialpha = 255 - const_alpha; + color = BYTE_MUL(color, const_alpha); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = color + BYTE_MUL(dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_solid_Source_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) + qt_memfill64((quint64*)dest, color, length); + else { + int ialpha = 255 - const_alpha; + color = multiplyAlpha255(color, const_alpha); + for (int i = 0; i < length; ++i) { + dest[i] = color + multiplyAlpha255(dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + ::memcpy(dest, src, length * sizeof(uint)); + } else { + int ialpha = 255 - const_alpha; + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_Source_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + ::memcpy(dest, src, length * sizeof(quint64)); + else { + int ialpha = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + dest[i] = interpolate255(src[i], const_alpha, dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint) +{ +} + +void QT_FASTCALL comp_func_solid_Destination_rgb64(QRgba64 *, int, QRgba64, uint) +{ +} + +void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint) +{ +} + +void QT_FASTCALL comp_func_Destination_rgb64(QRgba64 *, const QRgba64 *, int, uint) +{ +} + +/* + result = s + d * sia + dest = (s + d * sia) * ca + d * cia + = s * ca + d * (sia * ca + cia) + = s * ca + d * (1 - sa*ca) +*/ +void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha) +{ + if ((const_alpha & qAlpha(color)) == 255) { + QT_MEMFILL_UINT(dest, length, color); + } else { + if (const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color)); + } + } +} + +void QT_FASTCALL comp_func_solid_SourceOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255 && color.isOpaque()) { + qt_memfill64((quint64*)dest, color, length); + } else { + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + for (int i = 0; i < length; ++i) { + dest[i] = color + multiplyAlpha65535(dest[i], 65535 - color.alpha()); + } + } +} + +void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = src[i]; + if (s >= 0xff000000) + dest[i] = s; + else if (s != 0) + dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); + } + } +} + +void QT_FASTCALL comp_func_SourceOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 s = src[i]; + if (s.isOpaque()) + dest[i] = s; + else if (!s.isTransparent()) + dest[i] = s + multiplyAlpha65535(dest[i], 65535 - s.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + dest[i] = s + multiplyAlpha65535(dest[i], 65535 - s.alpha()); + } + } +} + +/* + result = d + s * dia + dest = (d + s * dia) * ca + d * cia + = d + s * dia * ca +*/ +void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = d + BYTE_MUL(color, qAlpha(~d)); + } +} + +void QT_FASTCALL comp_func_solid_DestinationOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = d + multiplyAlpha65535(color, 65535 - d.alpha()); + } +} + +void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + dest[i] = d + BYTE_MUL(src[i], qAlpha(~d)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = d + BYTE_MUL(s, qAlpha(~d)); + } + } +} + +void QT_FASTCALL comp_func_DestinationOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = d + multiplyAlpha65535(src[i], 65535 - d.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + dest[i] = d + multiplyAlpha65535(s, 65535 - d.alpha()); + } + } +} + +/* + result = s * da + dest = s * da * ca + d * cia +*/ +void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha) +{ + PRELOAD_INIT(dest) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(color, qAlpha(dest[i])); + } + } else { + color = BYTE_MUL(color, const_alpha); + uint cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_solid_SourceIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(color, dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + color = multiplyAlpha65535(color, ca); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, d.alpha(), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(src[i], qAlpha(dest[i])); + } + } else { + uint cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(src[i], dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha65535(src[i], ca); + dest[i] = interpolate65535(s, d.alpha(), d, cia); + } + } +} + +/* + result = d * sa + dest = d * sa * ca + d * cia + = d * (sa * ca + cia) +*/ +void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha) +{ + uint a = qAlpha(color); + if (const_alpha != 255) { + a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; + } + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(dest[i], a); + } +} + +void QT_FASTCALL comp_func_solid_DestinationIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = color.alpha(); + uint ca64k = const_alpha * 257; + if (const_alpha != 255) + a = qt_div_65535(a * ca64k) + 65535 - ca64k; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], a); + } +} + +void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(dest[i], qAlpha(src[i])); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia; + dest[i] = BYTE_MUL(dest[i], a); + } + } +} + +void QT_FASTCALL comp_func_DestinationIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], src[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + uint a = qt_div_65535(src[i].alpha() * ca) + cia; + dest[i] = multiplyAlpha65535(dest[i], a); + } + } +} + +/* + result = s * dia + dest = s * dia * ca + d * cia +*/ + +void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha) +{ + PRELOAD_INIT(dest) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(color, qAlpha(~dest[i])); + } + } else { + color = BYTE_MUL(color, const_alpha); + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_solid_SourceOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(color, 65535 - dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + color = multiplyAlpha65535(color, ca); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, 65535 - d.alpha(), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i])); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(src[i], 65535 - dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha65535(src[i], ca); + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, cia); + } + } +} + +/* + result = d * sia + dest = d * sia * ca + d * cia + = d * (sia * ca + cia) +*/ +void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha) +{ + uint a = qAlpha(~color); + if (const_alpha != 255) + a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(dest[i], a); + } +} + +void QT_FASTCALL comp_func_solid_DestinationOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = 65535 - color.alpha(); + uint ca64k = const_alpha * 257; + if (const_alpha != 255) + a = qt_div_65535(a * ca64k) + 65535 - ca64k; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], a); + } +} + +void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i])); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia; + dest[i] = BYTE_MUL(dest[i], sia); + } + } +} + +void QT_FASTCALL comp_func_DestinationOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], 65535 - src[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + uint a = qt_div_65535((65535 - src[i].alpha()) * ca) + cia; + dest[i] = multiplyAlpha65535(dest[i], a); + } + } +} + +/* + result = s*da + d*sia + dest = s*da*ca + d*sia*ca + d *cia + = s*ca * da + d * (sia*ca + cia) + = s*ca * da + d * (1 - sa*ca) +*/ +void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha != 255) { + color = BYTE_MUL(color, const_alpha); + } + uint sia = qAlpha(~color); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia); + } +} + +void QT_FASTCALL comp_func_solid_SourceAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + uint sia = 65535 - color.alpha(); + for (int i = 0; i < length; ++i) { + dest[i] = interpolate65535(color, dest[i].alpha(), dest[i], sia); + } +} + +void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = src[i]; + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); + } + } +} + +void QT_FASTCALL comp_func_SourceAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 s = src[i]; + QRgba64 d = dest[i]; + dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + QRgba64 d = dest[i]; + dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); + } + } +} + +/* + result = d*sa + s*dia + dest = d*sa*ca + s*dia*ca + d *cia + = s*ca * dia + d * (sa*ca + cia) +*/ +void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha) +{ + uint a = qAlpha(color); + if (const_alpha != 255) { + color = BYTE_MUL(color, const_alpha); + a = qAlpha(color) + 255 - const_alpha; + } + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d)); + } +} + +void QT_FASTCALL comp_func_solid_DestinationAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = color.alpha(); + if (const_alpha != 255) { + color = multiplyAlpha255(color, const_alpha); + a = color.alpha() + 65535 - (const_alpha * 257); + } + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(d, a, color, 65535 - d.alpha()); + } +} + +void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = src[i]; + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d)); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + uint d = dest[i]; + uint a = qAlpha(s) + cia; + dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d)); + } + } +} + +void QT_FASTCALL comp_func_DestinationAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 s = src[i]; + QRgba64 d = dest[i]; + dest[i] = interpolate65535(d, s.alpha(), s, 65535 - d.alpha()); + } + } else { + int ca = const_alpha * 257; + int cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 s = multiplyAlpha65535(src[i], ca); + QRgba64 d = dest[i]; + uint a = s.alpha() + cia; + dest[i] = interpolate65535(d, a, s, 65535 - d.alpha()); + } + } +} + +/* + result = d*sia + s*dia + dest = d*sia*ca + s*dia*ca + d *cia + = s*ca * dia + d * (sia*ca + cia) + = s*ca * dia + d * (1 - sa*ca) +*/ +void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + uint sia = qAlpha(~color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia); + } +} + +void QT_FASTCALL comp_func_solid_XOR_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + uint sia = 65535 - color.alpha(); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, 65535 - d.alpha(), d, sia); + } +} + +void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); + } + } +} + +void QT_FASTCALL comp_func_XOR_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = src[i]; + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, 65535 - s.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, 65535 - s.alpha()); + } + } +} + +struct QFullCoverage { + inline void store(uint *dest, const uint src) const + { + *dest = src; + } +}; + +struct QPartialCoverage { + inline QPartialCoverage(uint const_alpha) + : ca(const_alpha) + , ica(255 - const_alpha) + { + } + + inline void store(uint *dest, const uint src) const + { + *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica); + } + +private: + const uint ca; + const uint ica; +}; + +static inline int mix_alpha(int da, int sa) +{ + return 255 - ((255 - sa) * (255 - da) >> 8); +} + +/* + Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa) + = Sca + Dca +*/ +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage) +{ + uint s = color; + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + d = comp_func_Plus_one_pixel(d, s); + coverage.store(&dest[i], d); + } +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl_rgb64(QRgba64 *dest, int length, QRgba64 color, const T &coverage) +{ + QRgba64 s = color; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + d = comp_func_Plus_one_pixel(d, s); + coverage.store(&dest[i], d); + } +} + +void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Plus_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +void QT_FASTCALL comp_func_solid_Plus_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = addWithSaturation(dest[i], color); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = addWithSaturation(dest[i], color); + dest[i] = interpolate255(d, const_alpha, dest[i], 255 - const_alpha); + } + } +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + d = comp_func_Plus_one_pixel(d, s); + + coverage.store(&dest[i], d); + } +} + +void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Plus_impl(dest, src, length, QFullCoverage()); + else + comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +void QT_FASTCALL comp_func_Plus_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = addWithSaturation(dest[i], src[i]); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = addWithSaturation(dest[i], src[i]); + dest[i] = interpolate255(d, const_alpha, dest[i], 255 - const_alpha); + } + } +} + +/* + Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int multiply_op(int dst, int src, int da, int sa) +{ + return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) multiply_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) multiply_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Multiply(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Multiply_impl(dest, src, length, QFullCoverage()); + else + comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) + = Sca + Dca - Sca.Dca +*/ +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) 255 - qt_div_255((255-a) * (255-b)) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Screen_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) 255 - (((255-a) * (255-b)) >> 8) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Screen_impl(dest, src, length, QFullCoverage()); + else + comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if 2.Dca < Da + Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int overlay_op(int dst, int src, int da, int sa) +{ + const int temp = src * (255 - da) + dst * (255 - sa); + if (2 * dst < da) + return qt_div_255(2 * src * dst + temp); + else + return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) overlay_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) overlay_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Overlay(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Overlay_impl(dest, src, length, QFullCoverage()); + else + comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) + Da' = Sa + Da - Sa.Da +*/ +static inline int darken_op(int dst, int src, int da, int sa) +{ + return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) darken_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Darken_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) darken_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Darken(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Darken_impl(dest, src, length, QFullCoverage()); + else + comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) + Da' = Sa + Da - Sa.Da +*/ +static inline int lighten_op(int dst, int src, int da, int sa) +{ + return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) lighten_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) lighten_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Lighten(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Lighten_impl(dest, src, length, QFullCoverage()); + else + comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if Sca.Da + Dca.Sa >= Sa.Da + Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int color_dodge_op(int dst, int src, int da, int sa) +{ + const int sa_da = sa * da; + const int dst_sa = dst * sa; + const int src_da = src * da; + + const int temp = src * (255 - da) + dst * (255 - sa); + if (src_da + dst_sa >= sa_da) + return qt_div_255(sa_da + temp); + else + return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a,b) color_dodge_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) color_dodge_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_ColorDodge(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_ColorDodge_impl(dest, src, length, QFullCoverage()); + else + comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if Sca.Da + Dca.Sa <= Sa.Da + Dca' = Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int color_burn_op(int dst, int src, int da, int sa) +{ + const int src_da = src * da; + const int dst_sa = dst * sa; + const int sa_da = sa * da; + + const int temp = src * (255 - da) + dst * (255 - sa); + + if (src == 0 || src_da + dst_sa <= sa_da) + return qt_div_255(temp); + return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) color_burn_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) color_burn_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_ColorBurn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_ColorBurn_impl(dest, src, length, QFullCoverage()); + else + comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if 2.Sca < Sa + Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline uint hardlight_op(int dst, int src, int da, int sa) +{ + const uint temp = src * (255 - da) + dst * (255 - sa); + + if (2 * src < sa) + return qt_div_255(2 * src * dst + temp); + else + return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) hardlight_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) hardlight_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_HardLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_HardLight_impl(dest, src, length, QFullCoverage()); + else + comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if 2.Sca <= Sa + Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise if 2.Sca > Sa and 4.Dca <= Da + 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) + otherwise if 2.Sca > Sa and 4.Dca > Da + Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int soft_light_op(int dst, int src, int da, int sa) +{ + const int src2 = src << 1; + const int dst_np = da != 0 ? (255 * dst) / da : 0; + const int temp = (src * (255 - da) + dst * (255 - sa)) * 255; + + if (src2 < sa) + return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025; + else if (4 * dst <= da) + return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025; + else { + return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025; + } +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) soft_light_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) soft_light_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_SoftLight_impl(dest, src, length, QFullCoverage()); + else + comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa) + = Sca + Dca - 2.min(Sca.Da, Dca.Sa) +*/ +static inline int difference_op(int dst, int src, int da, int sa) +{ + return src + dst - qt_div_255(2 * qMin(src * da, dst * sa)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) difference_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Difference_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) difference_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Difference(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Difference_impl(dest, src, length, QFullCoverage()); + else + comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) (a + b - qt_div_255(2*(a*b))) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template <typename T> +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) (a + b - ((a*b) >> 7)) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Exclusion(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Exclusion_impl(dest, src, length, QFullCoverage()); + else + comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) + *dest++ |= color; +} + +void QT_FASTCALL rasterop_SourceOrDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) + *dest++ |= *src++; +} + +void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color |= 0xff000000; + while (length--) + *dest++ &= color; +} + +void QT_FASTCALL rasterop_SourceAndDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src & *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color &= 0x00ffffff; + while (length--) + *dest++ ^= color; +} + +void QT_FASTCALL rasterop_SourceXorDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src ^ *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color; + while (length--) { + *dest = (color & ~(*dest)) | 0xff000000; + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (~(*src) & ~(*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color | 0xff000000; + while (length--) { + *dest = color | ~(*dest); + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = ~(*src) | ~(*dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color & 0x00ffffff; + while (length--) { + *dest = color ^ (*dest); + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceXorDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = ((~(*src)) ^ (*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length, + uint color, uint const_alpha) +{ + Q_UNUSED(const_alpha); + qt_memfill(dest, ~color | 0xff000000, length); +} + +void QT_FASTCALL rasterop_NotSource(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, + int length, uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) + *dest++ = ~(*src++) | 0xff000000; +} + +void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color | 0xff000000; + while (length--) { + *dest = color & *dest; + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceAndDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (~(*src) & *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (color & ~(*dest)) | 0xff000000; + ++dest; + } +} + +void QT_FASTCALL rasterop_SourceAndNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src & ~(*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (~(*src) | *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color | 0xff000000; + while (length--) + *dest++ |= color; +} + +void QT_FASTCALL rasterop_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src | ~(*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (color | ~(*dest)) | 0xff000000; + ++dest; + } +} + +void QT_FASTCALL rasterop_ClearDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(src); + comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); +} + +void QT_FASTCALL rasterop_solid_ClearDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(color); + comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); +} + +void QT_FASTCALL rasterop_SetDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(src); + comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); +} + +void QT_FASTCALL rasterop_solid_SetDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(color); + comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); +} + +void QT_FASTCALL rasterop_NotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(src); + rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); +} + +void QT_FASTCALL rasterop_solid_NotDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(color); + rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); +} + +CompositionFunctionSolid qt_functionForModeSolid_C[] = { + comp_func_solid_SourceOver, + comp_func_solid_DestinationOver, + comp_func_solid_Clear, + comp_func_solid_Source, + comp_func_solid_Destination, + comp_func_solid_SourceIn, + comp_func_solid_DestinationIn, + comp_func_solid_SourceOut, + comp_func_solid_DestinationOut, + comp_func_solid_SourceAtop, + comp_func_solid_DestinationAtop, + comp_func_solid_XOR, + comp_func_solid_Plus, + comp_func_solid_Multiply, + comp_func_solid_Screen, + comp_func_solid_Overlay, + comp_func_solid_Darken, + comp_func_solid_Lighten, + comp_func_solid_ColorDodge, + comp_func_solid_ColorBurn, + comp_func_solid_HardLight, + comp_func_solid_SoftLight, + comp_func_solid_Difference, + comp_func_solid_Exclusion, + rasterop_solid_SourceOrDestination, + rasterop_solid_SourceAndDestination, + rasterop_solid_SourceXorDestination, + rasterop_solid_NotSourceAndNotDestination, + rasterop_solid_NotSourceOrNotDestination, + rasterop_solid_NotSourceXorDestination, + rasterop_solid_NotSource, + rasterop_solid_NotSourceAndDestination, + rasterop_solid_SourceAndNotDestination, + rasterop_solid_NotSourceOrDestination, + rasterop_solid_SourceOrNotDestination, + rasterop_solid_ClearDestination, + rasterop_solid_SetDestination, + rasterop_solid_NotDestination +}; + +CompositionFunctionSolid64 qt_functionForModeSolid64_C[] = { + comp_func_solid_SourceOver_rgb64, + comp_func_solid_DestinationOver_rgb64, + comp_func_solid_Clear_rgb64, + comp_func_solid_Source_rgb64, + comp_func_solid_Destination_rgb64, + comp_func_solid_SourceIn_rgb64, + comp_func_solid_DestinationIn_rgb64, + comp_func_solid_SourceOut_rgb64, + comp_func_solid_DestinationOut_rgb64, + comp_func_solid_SourceAtop_rgb64, + comp_func_solid_DestinationAtop_rgb64, + comp_func_solid_XOR_rgb64, + comp_func_solid_Plus_rgb64, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +CompositionFunction qt_functionForMode_C[] = { + comp_func_SourceOver, + comp_func_DestinationOver, + comp_func_Clear, + comp_func_Source, + comp_func_Destination, + comp_func_SourceIn, + comp_func_DestinationIn, + comp_func_SourceOut, + comp_func_DestinationOut, + comp_func_SourceAtop, + comp_func_DestinationAtop, + comp_func_XOR, + comp_func_Plus, + comp_func_Multiply, + comp_func_Screen, + comp_func_Overlay, + comp_func_Darken, + comp_func_Lighten, + comp_func_ColorDodge, + comp_func_ColorBurn, + comp_func_HardLight, + comp_func_SoftLight, + comp_func_Difference, + comp_func_Exclusion, + rasterop_SourceOrDestination, + rasterop_SourceAndDestination, + rasterop_SourceXorDestination, + rasterop_NotSourceAndNotDestination, + rasterop_NotSourceOrNotDestination, + rasterop_NotSourceXorDestination, + rasterop_NotSource, + rasterop_NotSourceAndDestination, + rasterop_SourceAndNotDestination, + rasterop_NotSourceOrDestination, + rasterop_SourceOrNotDestination, + rasterop_ClearDestination, + rasterop_SetDestination, + rasterop_NotDestination +}; + +CompositionFunction64 qt_functionForMode64_C[] = { + comp_func_SourceOver_rgb64, + comp_func_DestinationOver_rgb64, + comp_func_Clear_rgb64, + comp_func_Source_rgb64, + comp_func_Destination_rgb64, + comp_func_SourceIn_rgb64, + comp_func_DestinationIn_rgb64, + comp_func_SourceOut_rgb64, + comp_func_DestinationOut_rgb64, + comp_func_SourceAtop_rgb64, + comp_func_DestinationAtop_rgb64, + comp_func_XOR_rgb64, + comp_func_Plus_rgb64, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +QT_END_NAMESPACE diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp index 8fb5f4fd3f..61d57ca3f8 100644 --- a/src/gui/painting/qcosmeticstroker.cpp +++ b/src/gui/painting/qcosmeticstroker.cpp @@ -33,6 +33,7 @@ #include "qcosmeticstroker_p.h" #include "private/qpainterpath_p.h" +#include "private/qrgba64_p.h" #include <qdebug.h> QT_BEGIN_NAMESPACE @@ -280,7 +281,7 @@ void QCosmeticStroker::setup() drawCaps = state->lastPen.capStyle() != Qt::FlatCap; if (strokeSelection & FastDraw) { - color = INTERPOLATE_PIXEL_256(state->penData.solid.color, opacity, 0, 0); + color = multiplyAlpha256(state->penData.solid.color, opacity).toArgb32(); QRasterBuffer *buffer = state->penData.rasterBuffer; pixels = (uint *)buffer->buffer(); ppl = buffer->bytesPerLine()>>2; diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 2817a4a145..b3f9fd9f60 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -51,6 +51,7 @@ #include <private/qdrawhelper_mips_dsp_p.h> #endif #include <private/qguiapplication_p.h> +#include <private/qrgba64_p.h> #include <qmath.h> QT_BEGIN_NAMESPACE @@ -184,6 +185,36 @@ static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int } template<QImage::Format Format> +static const QRgba64 *QT_FASTCALL convertToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); + + Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; + + for (int i = 0; i < count; ++i) { + uint red = (src[i] >> redShift<Format>()) & redMask; + uint green = (src[i] >> greenShift<Format>()) & greenMask; + uint blue = (src[i] >> blueShift<Format>()) & blueMask; + + red = ((red << redLeftShift) | (red >> redRightShift)) << 16; + green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8; + blue = (blue << blueLeftShift) | (blue >> blueRightShift); + buffer[i] = QRgba64::fromRgba(red, green, blue, 255); + } + + return buffer; +} + +template<QImage::Format Format> static const uint *QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -219,6 +250,41 @@ static const uint *QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, const uint } template<QImage::Format Format> +static const QRgba64 *QT_FASTCALL convertARGBPMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + Q_CONSTEXPR uint alphaMask = ((1 << alphaWidth<Format>()) - 1); + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + + Q_CONSTEXPR uchar alphaLeftShift = 8 - alphaWidth<Format>(); + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); + + Q_CONSTEXPR uchar alphaRightShift = 2 * alphaWidth<Format>() - 8; + Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; + + for (int i = 0; i < count; ++i) { + uint alpha = (src[i] >> alphaShift<Format>()) & alphaMask; + uint red = (src[i] >> redShift<Format>()) & redMask; + uint green = (src[i] >> greenShift<Format>()) & greenMask; + uint blue = (src[i] >> blueShift<Format>()) & blueMask; + + alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift); + red = qMin(alpha, (red << redLeftShift) | (red >> redRightShift)); + green = qMin(alpha, (green << greenLeftShift) | (green >> greenRightShift)); + blue = qMin(alpha, (blue << blueLeftShift) | (blue >> blueRightShift)); + buffer[i] = QRgba64::fromRgba(red, green, blue, alpha); + } + + return buffer; +} + +template<QImage::Format Format> static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -320,7 +386,8 @@ template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixe false, bitsPerPixel<Format>(), convertToRGB32<Format>, convertRGBFromARGB32PM<Format>, - convertRGBFromRGB32<Format> + convertRGBFromRGB32<Format>, + convertToRGB64<Format> }; } @@ -334,7 +401,8 @@ template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixe true, bitsPerPixel<Format>(), convertARGBPMToARGB32PM<Format>, convertARGBPMFromARGB32PM<Format>, - convertARGBPMFromRGB32<Format> + convertARGBPMFromRGB32<Format>, + convertARGBPMToARGB64PM<Format> }; } @@ -349,6 +417,14 @@ static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint return buffer; } +static const QRgba64 *QT_FASTCALL convertIndexedToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *clut) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(clut[src[i]]).premultiplied(); + return buffer; +} + static const uint *QT_FASTCALL convertPassThrough(uint *, const uint *src, int, const QPixelLayout *, const QRgb *) { @@ -391,6 +467,22 @@ static const uint *QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, const uint return buffer; } +static const QRgba64 *QT_FASTCALL convertAlpha8ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromRgba(0, 0, 0, src[i]); + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertGrayscale8ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromRgba(src[i], src[i], src[i], 255); + return buffer; +} + static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -407,6 +499,111 @@ static const uint *QT_FASTCALL convertRGBA8888PMFromARGB32PM(uint *buffer, const return buffer; } +#ifdef __SSE2__ +template<bool RGBA, bool maskAlpha> +static inline void qConvertARGB32PMToARGB64PM_sse2(QRgba64 *buffer, const uint *src, int count) +{ + const __m128i amask = _mm_set1_epi32(0xff000000); + int i = 0; + if (((uintptr_t)buffer & 0xf) && count > 0) { + uint s = *src++; + if (RGBA) + s = RGBA2ARGB(s); + *buffer++ = QRgba64::fromArgb32(s); + i++; + } + for (; i < count-3; i += 4) { + __m128i vs = _mm_loadu_si128((const __m128i*)src); + if (maskAlpha) + vs = _mm_or_si128(vs, amask); + src += 4; + __m128i v1 = _mm_unpacklo_epi8(vs, vs); + __m128i v2 = _mm_unpackhi_epi8(vs, vs); + if (!RGBA) { + v1 = _mm_shufflelo_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2)); + v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2)); + v1 = _mm_shufflehi_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2)); + v2 = _mm_shufflehi_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2)); + } + _mm_store_si128((__m128i*)(buffer), v1); + buffer += 2; + _mm_store_si128((__m128i*)(buffer), v2); + buffer += 2; + } + + for (; i < count; ++i) { + uint s = *src++; + if (RGBA) + s = RGBA2ARGB(s); + *buffer++ = QRgba64::fromArgb32(s); + } +} +#endif + +static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2<false, true>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertARGB32ToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2<false, false>(buffer, src, count); + for (int i = 0; i < count; ++i) + buffer[i] = buffer[i].premultiplied(); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied(); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertARGB32PMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2<false, false>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(src[i]); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertRGBA8888ToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2<true, false>(buffer, src, count); + for (int i = 0; i < count; ++i) + buffer[i] = buffer[i].premultiplied(); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied(); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertRGBA8888PMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2<true, false>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])); +#endif + return buffer; +} + static const uint *QT_FASTCALL convertRGBA8888FromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -440,6 +637,60 @@ static const uint *QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, const ui return buffer; } +#ifdef __SSE2__ +template<QtPixelOrder PixelOrder> +static inline void qConvertA2RGB30PMToARGB64PM_sse2(QRgba64 *buffer, const uint *src, int count) +{ + const __m128i rmask = _mm_set1_epi32(0x3ff00000); + const __m128i gmask = _mm_set1_epi32(0x000ffc00); + const __m128i bmask = _mm_set1_epi32(0x000003ff); + const __m128i afactor = _mm_set1_epi16(0x5555); + int i = 0; + if (((uintptr_t)buffer & 0xf) && count > 0) { + *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++); + i++; + } + for (; i < count-3; i += 4) { + __m128i vs = _mm_loadu_si128((const __m128i*)src); + src += 4; + __m128i va = _mm_srli_epi32(vs, 30); + __m128i vr = _mm_and_si128(vs, rmask); + __m128i vb = _mm_and_si128(vs, bmask); + __m128i vg = _mm_and_si128(vs, gmask); + va = _mm_mullo_epi16(va, afactor); + vr = _mm_or_si128(_mm_srli_epi32(vr, 14), _mm_srli_epi32(vr, 24)); + vg = _mm_or_si128(_mm_srli_epi32(vg, 4), _mm_srli_epi32(vg, 14)); + vb = _mm_or_si128(_mm_slli_epi32(vb, 6), _mm_srli_epi32(vb, 4)); + __m128i vrb; + if (PixelOrder == PixelOrderRGB) + vrb = _mm_or_si128(vr, _mm_slli_si128(vb, 2)); + else + vrb = _mm_or_si128(vb, _mm_slli_si128(vr, 2)); + __m128i vga = _mm_or_si128(vg, _mm_slli_si128(va, 2)); + _mm_store_si128((__m128i*)(buffer), _mm_unpacklo_epi16(vrb, vga)); + buffer += 2; + _mm_store_si128((__m128i*)(buffer), _mm_unpackhi_epi16(vrb, vga)); + buffer += 2; + } + + for (; i < count; ++i) + *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++); +} +#endif + +template<QtPixelOrder PixelOrder> +static const QRgba64 *QT_FASTCALL convertA2RGB30PMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertA2RGB30PMToARGB64PM_sse2<PixelOrder>(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]); +#endif + return buffer; +} + template<QtPixelOrder PixelOrder> static const uint *QT_FASTCALL convertA2RGB30PMFromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) @@ -601,15 +852,15 @@ inline void QT_FASTCALL storePixels<QPixelLayout::BPP32>(uchar *dest, const uint // convertFromArgb32() assumes that no color channel is more than 8 bits. // QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits. QPixelLayout qPixelLayouts[QImage::NImageFormats] = { - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0, 0 }, // Format_Invalid - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0, 0 }, // Format_Mono - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0, 0 }, // Format_MonoLSB - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0, 0 }, // Format_Indexed8 + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0, 0, 0 }, // Format_Invalid + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Mono + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_MonoLSB + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Indexed8 // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong, // but everywhere this generic conversion would be wrong is currently overloaded. - { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough }, // Format_RGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, convertPassThrough }, // Format_ARGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough }, // Format_ARGB32_Premultiplied + { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough, convertRGB32ToRGB64 }, // Format_RGB32 + { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, convertPassThrough, convertARGB32ToARGB64PM }, // Format_ARGB32 + { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough, convertARGB32PMToARGB64PM }, // Format_ARGB32_Premultiplied #ifdef Q_COMPILER_CONSTEXPR pixelLayoutRGB<QImage::Format_RGB16>(), pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(), @@ -624,55 +875,73 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = { { 5, 11, 6, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32<QImage::Format_RGB16>, convertRGBFromARGB32PM<QImage::Format_RGB16>, - convertRGBFromRGB32<QImage::Format_RGB16>}, + convertRGBFromRGB32<QImage::Format_RGB16>, + convertToRGB64<QImage::Format_RGB16>, + }, { 5, 19, 6, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertARGBPMToARGB32PM<QImage::Format_ARGB8565_Premultiplied>, convertARGBPMFromARGB32PM<QImage::Format_ARGB8565_Premultiplied>, - convertARGBPMFromRGB32<QImage::Format_ARGB8565_Premultiplied>}, + convertARGBPMFromRGB32<QImage::Format_ARGB8565_Premultiplied>, + convertARGBPMToARGB64PM<QImage::Format_ARGB8565_Premultiplied>, + }, { 6, 12, 6, 6, 6, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32<QImage::Format_RGB666>, convertRGBFromARGB32PM<QImage::Format_RGB666>, - convertRGBFromRGB32<QImage::Format_RGB666>}, + convertRGBFromRGB32<QImage::Format_RGB666>, + convertToRGB64<QImage::Format_RGB666>, + }, { 6, 12, 6, 6, 6, 0, 6, 18, true, QPixelLayout::BPP24, convertARGBPMToARGB32PM<QImage::Format_ARGB6666_Premultiplied>, convertARGBPMFromARGB32PM<QImage::Format_ARGB6666_Premultiplied>, - convertARGBPMFromRGB32<QImage::Format_ARGB6666_Premultiplied>}, + convertARGBPMFromRGB32<QImage::Format_ARGB6666_Premultiplied>, + convertARGBPMToARGB64PM<QImage::Format_ARGB6666_Premultiplied>, + }, { 5, 10, 5, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32<QImage::Format_RGB555>, convertRGBFromARGB32PM<QImage::Format_RGB555>, - convertRGBFromRGB32<QImage::Format_RGB555> }, + convertRGBFromRGB32<QImage::Format_RGB555>, + convertToRGB64<QImage::Format_RGB555>, + }, { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertARGBPMToARGB32PM<QImage::Format_ARGB8555_Premultiplied>, convertARGBPMFromARGB32PM<QImage::Format_ARGB8555_Premultiplied>, - convertARGBPMFromRGB32<QImage::Format_ARGB8555_Premultiplied>}, + convertARGBPMFromRGB32<QImage::Format_ARGB8555_Premultiplied>, + convertARGBPMToARGB64PM<QImage::Format_ARGB8555_Premultiplied>, + }, { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32<QImage::Format_RGB888>, convertRGBFromARGB32PM<QImage::Format_RGB888>, - convertRGBFromRGB32<QImage::Format_RGB888>}, + convertRGBFromRGB32<QImage::Format_RGB888>, + convertToRGB64<QImage::Format_RGB888>, + }, { 4, 8, 4, 4, 4, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32<QImage::Format_RGB444>, convertRGBFromARGB32PM<QImage::Format_RGB444>, - convertRGBFromRGB32<QImage::Format_RGB444>}, + convertRGBFromRGB32<QImage::Format_RGB444>, + convertToRGB64<QImage::Format_RGB444>, + }, { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, convertARGBPMToARGB32PM<QImage::Format_ARGB4444_Premultiplied>, convertARGBPMFromARGB32PM<QImage::Format_ARGB4444_Premultiplied>, - convertARGBPMFromRGB32<QImage::Format_ARGB4444_Premultiplied>}, + convertARGBPMFromRGB32<QImage::Format_ARGB4444_Premultiplied>, + convertARGBPMToARGB64PM<QImage::Format_ARGB4444_Premultiplied>, + }, #endif #if Q_BYTE_ORDER == Q_BIG_ENDIAN - { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBX8888 - { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888 - { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32}, // Format_RGBA8888_Premultiplied + { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888 + { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888 + { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM}, // Format_RGBA8888_Premultiplied #else - { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBX8888 - { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888 (ABGR32) - { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888_Premultiplied + { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888 + { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888 (ABGR32) + { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBA8888_Premultiplied #endif - { 10, 20, 10, 10, 10, 0, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertRGB30FromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR> }, // Format_BGR30 - { 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR> }, // Format_A2BGR30_Premultiplied - { 10, 0, 10, 10, 10, 20, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertRGB30FromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB> }, // Format_RGB30 - { 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB> }, // Format_A2RGB30_Premultiplied - { 0, 0, 0, 0, 0, 0, 8, 0, false, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0 }, // Format_Alpha8 - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32 } // Format_Grayscale8 + { 10, 20, 10, 10, 10, 0, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertRGB30FromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_BGR30 + { 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_A2BGR30_Premultiplied + { 10, 0, 10, 10, 10, 20, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertRGB30FromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_RGB30 + { 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_A2RGB30_Premultiplied + { 0, 0, 0, 0, 0, 0, 8, 0, false, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0, convertAlpha8ToRGB64 }, // Format_Alpha8 + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32, convertGrayscale8ToRGB64 } // Format_Grayscale8 }; FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = { @@ -758,6 +1027,20 @@ static uint *QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer, in return const_cast<uint *>(layout->convertToARGB32PM(buffer, ptr, length, layout, 0)); } +static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) +{ + const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; + uint buffer32[buffer_size]; + const uint *ptr = qFetchPixels[layout->bpp](buffer32, rasterBuffer->scanLine(y), x, length); + return const_cast<QRgba64 *>(layout->convertToARGB64PM(buffer, ptr, length, layout, 0)); +} + +static QRgba64 *QT_FASTCALL destFetch64uint32(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) +{ + const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; + const uint *src = ((const uint *)rasterBuffer->scanLine(y)) + x; + return const_cast<QRgba64 *>(layout->convertToARGB64PM(buffer, src, length, layout, 0)); +} static DestFetchProc destFetchProc[QImage::NImageFormats] = { @@ -788,6 +1071,35 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] = destFetch, // Format_Grayscale8 }; +static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = +{ + 0, // Format_Invalid + destFetch64, // Format_Mono, + destFetch64, // Format_MonoLSB + 0, // Format_Indexed8 + destFetch64uint32, // Format_RGB32 + destFetch64uint32, // Format_ARGB32, + destFetch64uint32, // Format_ARGB32_Premultiplied + destFetch64, // Format_RGB16 + destFetch64, // Format_ARGB8565_Premultiplied + destFetch64, // Format_RGB666 + destFetch64, // Format_ARGB6666_Premultiplied + destFetch64, // Format_RGB555 + destFetch64, // Format_ARGB8555_Premultiplied + destFetch64, // Format_RGB888 + destFetch64, // Format_RGB444 + destFetch64, // Format_ARGB4444_Premultiplied + destFetch64uint32, // Format_RGBX8888 + destFetch64uint32, // Format_RGBA8888 + destFetch64uint32, // Format_RGBA8888_Premultiplied + destFetch64uint32, // Format_BGR30 + destFetch64uint32, // Format_A2BGR30_Premultiplied + destFetch64uint32, // Format_RGB30 + destFetch64uint32, // Format_A2RGB30_Premultiplied + destFetch64, // Format_Alpha8 + destFetch64, // Format_Grayscale8 +}; + /* Returns the color in the mono destination color table that is the "nearest" to /color/. @@ -904,6 +1216,97 @@ static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, con } } +static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int length) +{ + for (int i = 0; i < length; ++i) { + dest[i] = src[i].toArgb32(); + } +} + +static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + uint buf[buffer_size]; + const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; + StorePixelsFunc store = qStorePixels[layout->bpp]; + uchar *dest = rasterBuffer->scanLine(y); + while (length) { + int l = qMin(length, buffer_size); + const uint *ptr = 0; + convertFromRgb64(buf, buffer, l); + if (!layout->premultiplied && !layout->alphaWidth) + ptr = layout->convertFromRGB32(buf, buf, l, layout, 0); + else + ptr = layout->convertFromARGB32PM(buf, buf, l, layout, 0); + store(dest, ptr, x, l); + length -= l; + buffer += l; + x += l; + } +} + +#ifdef __SSE2__ +template<QtPixelOrder PixelOrder> +static inline void qConvertARGB64PMToA2RGB30PM_sse2(uint *dest, const QRgba64 *buffer, int count) +{ + const __m128i gmask = _mm_set1_epi32(0x000ffc00); + const __m128i cmask = _mm_set1_epi32(0x000003ff); + int i = 0; + __m128i vr, vg, vb, va; + for (; i < count-1; i += 2) { + __m128i vs = _mm_loadu_si128((const __m128i*)buffer); + buffer += 2; + vr = _mm_srli_epi64(vs, 6); + vg = _mm_srli_epi64(vs, 16 + 6 - 10); + vb = _mm_srli_epi64(vs, 32 + 6); + vr = _mm_and_si128(vr, cmask); + vg = _mm_and_si128(vg, gmask); + vb = _mm_and_si128(vb, cmask); + va = _mm_srli_epi64(vs, 48 + 14); + if (PixelOrder == PixelOrderRGB) + vr = _mm_slli_epi32(vr, 20); + else + vb = _mm_slli_epi32(vb, 20); + va = _mm_slli_epi32(va, 30); + __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va)); + vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0)); + _mm_storel_epi64((__m128i*)dest, vd); + dest += 2; + } + + for (; i < count; ++i) + *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++); +} +#endif + +static void QT_FASTCALL destStore64ARGB32(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + uint *dest = (uint*)rasterBuffer->scanLine(y) + x; + for (int i = 0; i < length; ++i) { + dest[i] = buffer[i].unpremultiplied().toArgb32(); + } +} + +static void QT_FASTCALL destStore64RGBA8888(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + uint *dest = (uint*)rasterBuffer->scanLine(y) + x; + for (int i = 0; i < length; ++i) { + dest[i] = ARGB2RGBA(buffer[i].unpremultiplied().toArgb32()); + } +} + +template<QtPixelOrder PixelOrder> +static void QT_FASTCALL destStore64RGB30(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + uint *dest = (uint*)rasterBuffer->scanLine(y) + x; +#ifdef __SSE2__ + qConvertARGB64PMToA2RGB30PM_sse2<PixelOrder>(dest, buffer, length); +#else + for (int i = 0; i < length; ++i) { + dest[i] = qConvertRgb64ToRgb30<PixelOrder>(buffer[i]); + } +#endif +} + static DestStoreProc destStoreProc[QImage::NImageFormats] = { 0, // Format_Invalid @@ -933,6 +1336,35 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] = destStore, // Format_Grayscale8 }; +static DestStoreProc64 destStoreProc64[QImage::NImageFormats] = +{ + 0, // Format_Invalid + destStore64, // Format_Mono, + destStore64, // Format_MonoLSB + 0, // Format_Indexed8 + destStore64, // Format_RGB32 + destStore64ARGB32, // Format_ARGB32, + destStore64, // Format_ARGB32_Premultiplied + destStore64, // Format_RGB16 + destStore64, // Format_ARGB8565_Premultiplied + destStore64, // Format_RGB666 + destStore64, // Format_ARGB6666_Premultiplied + destStore64, // Format_RGB555 + destStore64, // Format_ARGB8555_Premultiplied + destStore64, // Format_RGB888 + destStore64, // Format_RGB444 + destStore64, // Format_ARGB4444_Premultiplied + destStore64, // Format_RGBX8888 + destStore64RGBA8888, // Format_RGBA8888 + destStore64, // Format_RGBA8888_Premultiplied + destStore64RGB30<PixelOrderBGR>, // Format_BGR30 + destStore64RGB30<PixelOrderBGR>, // Format_A2BGR30_Premultiplied + destStore64RGB30<PixelOrderRGB>, // Format_RGB30 + destStore64RGB30<PixelOrderRGB>, // Format_A2RGB30_Premultiplied + destStore64, // Format_Alpha8 + destStore64, // Format_Grayscale8 +}; + /* Source fetches @@ -988,6 +1420,21 @@ static const uint *QT_FASTCALL fetchUntransformedRGB16(uint *buffer, const Opera return buffer; } +static const QRgba64 *QT_FASTCALL fetchUntransformed64(QRgba64 *buffer, const Operator *, + const QSpanData *data, int y, int x, int length) +{ + const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; + const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0; + if (layout->bpp != QPixelLayout::BPP32) { + uint buffer32[buffer_size]; + const uint *ptr = qFetchPixels[layout->bpp](buffer32, data->texture.scanLine(y), x, length); + return layout->convertToARGB64PM(buffer, ptr, length, layout, clut); + } else { + const uint *src = (const uint *)data->texture.scanLine(y) + x; + return layout->convertToARGB64PM(buffer, src, length, layout, clut); + } +} + // blendType is either BlendTransformed or BlendTransformedTiled template<TextureBlendType blendType> static const uint *QT_FASTCALL fetchTransformedARGB32PM(uint *buffer, const Operator *, const QSpanData *data, @@ -1155,6 +1602,111 @@ static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, return layout->convertToARGB32PM(buffer, buffer, length, layout, clut); } +template<TextureBlendType blendType> /* either BlendTransformed or BlendTransformedTiled */ +static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) +{ + int image_width = data->texture.width; + int image_height = data->texture.height; + + const qreal cx = x + qreal(0.5); + const qreal cy = y + qreal(0.5); + + const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0; + + uint buffer32[buffer_size]; + QRgba64 *b = buffer; + if (data->fast_matrix) { + // The increment pr x in the scanline + int fdx = (int)(data->m11 * fixed_scale); + int fdy = (int)(data->m12 * fixed_scale); + + int fx = int((data->m21 * cy + + data->m11 * cx + data->dx) * fixed_scale); + int fy = int((data->m22 * cy + + data->m12 * cx + data->dy) * fixed_scale); + + int i = 0, j = 0; + while (i < length) { + if (j == buffer_size) { + layout->convertToARGB64PM(b, buffer32, buffer_size, layout, clut); + b += buffer_size; + j = 0; + } + int px = fx >> 16; + int py = fy >> 16; + + if (blendType == BlendTransformedTiled) { + px %= image_width; + py %= image_height; + if (px < 0) px += image_width; + if (py < 0) py += image_height; + } else { + px = qBound(0, px, image_width - 1); + py = qBound(0, py, image_height - 1); + } + buffer32[j] = fetch(data->texture.scanLine(py), px); + + fx += fdx; + fy += fdy; + ++i; ++j; + } + if (j > 0) { + layout->convertToARGB64PM(b, buffer32, j, layout, clut); + b += j; + } + } else { + const qreal fdx = data->m11; + const qreal fdy = data->m12; + const qreal fdw = data->m13; + + qreal fx = data->m21 * cy + data->m11 * cx + data->dx; + qreal fy = data->m22 * cy + data->m12 * cx + data->dy; + qreal fw = data->m23 * cy + data->m13 * cx + data->m33; + + int i = 0, j = 0; + while (i < length) { + if (j == buffer_size) { + layout->convertToARGB64PM(b, buffer32, buffer_size, layout, clut); + b += buffer_size; + j = 0; + } + const qreal iw = fw == 0 ? 1 : 1 / fw; + const qreal tx = fx * iw; + const qreal ty = fy * iw; + int px = int(tx) - (tx < 0); + int py = int(ty) - (ty < 0); + + if (blendType == BlendTransformedTiled) { + px %= image_width; + py %= image_height; + if (px < 0) px += image_width; + if (py < 0) py += image_height; + } else { + px = qBound(0, px, image_width - 1); + py = qBound(0, py, image_height - 1); + } + buffer32[j] = fetch(data->texture.scanLine(py), px); + + fx += fdx; + fy += fdy; + fw += fdw; + //force increment to avoid /0 + if (!fw) { + fw += fdw; + } + ++i; ++j; + } + if (j > 0) { + layout->convertToARGB64PM(b, buffer32, j, layout, clut); + b += j; + } + } + return buffer; +} + /** \internal interpolate 4 argb pixels with the distx and disty factor. distx and disty bust be between 0 and 16 @@ -1245,6 +1797,42 @@ static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, i } #endif +#if defined(__SSE2__) +static inline QRgba64 interpolate_4_pixels_rgb64(QRgba64 t[], QRgba64 b[], uint distx, uint disty) +{ + const __m128i vdistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(distx), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vidistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(0x10000 - distx), _MM_SHUFFLE(0, 0, 0, 0)); + + __m128i vt = _mm_loadu_si128((const __m128i*)t); + if (disty) { + __m128i vb = _mm_loadu_si128((const __m128i*)b); + vt = _mm_mulhi_epu16(vt, _mm_set1_epi16(0x10000 - disty)); + vb = _mm_mulhi_epu16(vb, _mm_set1_epi16(disty)); + vt = _mm_add_epi16(vt, vb); + } + vt = _mm_mulhi_epu16(vt, _mm_unpacklo_epi64(vidistx, vdistx)); + vt = _mm_add_epi16(vt, _mm_srli_si128(vt, 8)); +#ifdef Q_PROCESSOR_X86_64 + return QRgba64::fromRgba64(_mm_cvtsi128_si64(vt)); +#else + QRgba64 out; + _mm_storel_epi64((__m128i*)&out, vt); + return out; +#endif +} +#else +static inline QRgba64 interpolate_4_pixels_rgb64(QRgba64 t[], QRgba64 b[], uint distx, uint disty) +{ + const uint dx = distx>>8; + const uint dy = disty>>8; + const uint idx = 256 - dx; + const uint idy = 256 - dy; + QRgba64 xtop = interpolate256(t[0], idx, t[1], dx); + QRgba64 xbot = interpolate256(b[0], idx, b[1], dx); + return interpolate256(xtop, idy, xbot, dy); +} +#endif + template<TextureBlendType blendType> void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2); @@ -2130,6 +2718,349 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper return buffer; } +template<TextureBlendType blendType> +static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, const Operator *, + const QSpanData *data, int y, int x, int length) +{ + const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; + const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0; + + int image_width = data->texture.width; + int image_height = data->texture.height; + + int image_x1 = data->texture.x1; + int image_y1 = data->texture.y1; + int image_x2 = data->texture.x2 - 1; + int image_y2 = data->texture.y2 - 1; + + const qreal cx = x + qreal(0.5); + const qreal cy = y + qreal(0.5); + + const qreal fdx = data->m11; + const qreal fdy = data->m12; + const qreal fdw = data->m13; + + if (data->fast_matrix) { + // The increment pr x in the scanline + int fdx = (int)(data->m11 * fixed_scale); + int fdy = (int)(data->m12 * fixed_scale); + + int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale); + int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale); + + fx -= half_point; + fy -= half_point; + + if (fdy == 0) { //simple scale, no rotation + int y1 = (fy >> 16); + int y2; + fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2); + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + uint sbuf1[buffer_size]; + uint sbuf2[buffer_size]; + QRgba64 buf1[buffer_size]; + QRgba64 buf2[buffer_size]; + QRgba64 *b = buffer; + while (length) { + int len = qMin(length, buffer_size / 2); + int fracX = fx; + int i = 0; + int disty = (fy & 0x0000ffff); +#if defined(__SSE2__) + const __m128i vdy = _mm_set1_epi16(disty); + const __m128i vidy = _mm_set1_epi16(0x10000 - disty); + if (blendType != BlendTransformedBilinearTiled && layout->bpp == QPixelLayout::BPP32) { + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); + if (x1 != x2) + break; + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + fx += fdx; + } + + const __m128i v_fdx = _mm_set1_epi32(fdx*4); + __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx); + for (; i < len-3; i+=4) { + int offset = _mm_extract_epi16(v_fx, 1); + sbuf1[i * 2 + 0] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[offset + 1]; + offset = _mm_extract_epi16(v_fx, 3); + sbuf1[i * 2 + 2] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 3] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 2] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 3] = ((const uint*)s2)[offset + 1]; + offset = _mm_extract_epi16(v_fx, 5); + sbuf1[i * 2 + 4] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 5] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 4] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 5] = ((const uint*)s2)[offset + 1]; + offset = _mm_extract_epi16(v_fx, 7); + sbuf1[i * 2 + 6] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 7] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 6] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 7] = ((const uint*)s2)[offset + 1]; + v_fx = _mm_add_epi32(v_fx, v_fdx); + } + fx = _mm_cvtsi128_si32(v_fx); + } +#endif + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); + + if (layout->bpp == QPixelLayout::BPP32) { + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + + } else { + sbuf1[i * 2 + 0] = fetch(s1, x1); + sbuf1[i * 2 + 1] = fetch(s1, x2); + sbuf2[i * 2 + 0] = fetch(s2, x1); + sbuf2[i * 2 + 1] = fetch(s2, x2); + } + + fx += fdx; + } + layout->convertToARGB64PM(buf1, sbuf1, len * 2, layout, clut); + if (disty) + layout->convertToARGB64PM(buf2, sbuf2, len * 2, layout, clut); + + for (int i = 0; i < len; ++i) { + int distx = (fracX & 0x0000ffff); +#if defined(__SSE2__) + const __m128i vdistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(distx), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vidistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(0x10000 - distx), _MM_SHUFFLE(0, 0, 0, 0)); + __m128i vt = _mm_loadu_si128((const __m128i*)(buf1 + i*2)); + if (disty) { + __m128i vb = _mm_loadu_si128((const __m128i*)(buf2 + i*2)); + vt = _mm_mulhi_epu16(vt, vidy); + vb = _mm_mulhi_epu16(vb, vdy); + vt = _mm_add_epi16(vt, vb); + } + vt = _mm_mulhi_epu16(vt, _mm_unpacklo_epi64(vidistx, vdistx)); + vt = _mm_add_epi16(vt, _mm_srli_si128(vt, 8)); + _mm_storel_epi64((__m128i*)(b+i), vt); +#else + b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty); +#endif + fracX += fdx; + } + length -= len; + b += len; + } + } else { //rotation + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + uint sbuf1[buffer_size]; + uint sbuf2[buffer_size]; + QRgba64 buf1[buffer_size]; + QRgba64 buf2[buffer_size]; + QRgba64 *end = buffer + length; + QRgba64 *b = buffer; + + while (b < end) { + int len = qMin(length, buffer_size / 2); + int fracX = fx; + int fracY = fy; + int i = 0; +#if defined(__SSE2__) + if (blendType != BlendTransformedBilinearTiled && layout->bpp == QPixelLayout::BPP32) { + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + int y1 = (fy >> 16); + int y2; + fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); + fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2); + if (x1 != x2 && y1 != y2) + break; + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + fx += fdx; + fy += fdy; + } + + const __m128i v_fdx = _mm_set1_epi32(fdx*4); + const __m128i v_fdy = _mm_set1_epi32(fdy*4); + __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx); + __m128i v_fy = _mm_setr_epi32(fy, fy + fdy, fy + fdy + fdy, fy + fdy + fdy + fdy); + const int bytesPerLine = data->texture.bytesPerLine; + const uchar *s1 = data->texture.imageData; + const uchar *s2 = s1 + bytesPerLine; + const __m128i vbpl = _mm_shufflelo_epi16(_mm_cvtsi32_si128(bytesPerLine/4), _MM_SHUFFLE(0, 0, 0, 0)); + for (; i < len-3; i+=4) { + if (fdx > 0 && (short)_mm_extract_epi16(v_fx, 7) >= image_x2) + break; + if (fdx < 0 && (short)_mm_extract_epi16(v_fx, 7) < image_x1) + break; + if (fdy > 0 && (short)_mm_extract_epi16(v_fy, 7) >= image_y2) + break; + if (fdy < 0 && (short)_mm_extract_epi16(v_fy, 7) < image_y1) + break; + const __m128i vy = _mm_packs_epi32(_mm_srai_epi32(v_fy, 16), _mm_setzero_si128()); + __m128i voffset = _mm_unpacklo_epi16(_mm_mullo_epi16(vy, vbpl), _mm_mulhi_epu16(vy, vbpl)); + voffset = _mm_add_epi32(voffset, _mm_srli_epi32(v_fx, 16)); + + int offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4); + sbuf1[i * 2 + 0] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[offset + 1]; + offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4); + sbuf1[i * 2 + 2] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 3] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 2] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 3] = ((const uint*)s2)[offset + 1]; + offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4); + sbuf1[i * 2 + 4] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 5] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 4] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 5] = ((const uint*)s2)[offset + 1]; + offset = _mm_cvtsi128_si32(voffset); + sbuf1[i * 2 + 6] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 7] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 6] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 7] = ((const uint*)s2)[offset + 1]; + + v_fx = _mm_add_epi32(v_fx, v_fdx); + v_fy = _mm_add_epi32(v_fy, v_fdy); + } + fx = _mm_cvtsi128_si32(v_fx); + fy = _mm_cvtsi128_si32(v_fy); + } +#endif + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + int y1 = (fy >> 16); + int y2; + fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); + fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2); + + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + + if (layout->bpp == QPixelLayout::BPP32) { + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + + } else { + sbuf1[i * 2 + 0] = fetch(s1, x1); + sbuf1[i * 2 + 1] = fetch(s1, x2); + sbuf2[i * 2 + 0] = fetch(s2, x1); + sbuf2[i * 2 + 1] = fetch(s2, x2); + } + + fx += fdx; + fy += fdy; + } + layout->convertToARGB64PM(buf1, sbuf1, len * 2, layout, clut); + layout->convertToARGB64PM(buf2, sbuf2, len * 2, layout, clut); + + for (int i = 0; i < len; ++i) { + int distx = (fracX & 0x0000ffff); + int disty = (fracY & 0x0000ffff); + b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty); + fracX += fdx; + fracY += fdy; + } + + length -= len; + b += len; + } + } + } else { + qreal fx = data->m21 * cy + data->m11 * cx + data->dx; + qreal fy = data->m22 * cy + data->m12 * cx + data->dy; + qreal fw = data->m23 * cy + data->m13 * cx + data->m33; + + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + uint sbuf1[buffer_size]; + uint sbuf2[buffer_size]; + QRgba64 buf1[buffer_size]; + QRgba64 buf2[buffer_size]; + QRgba64 *b = buffer; + + int distxs[buffer_size / 2]; + int distys[buffer_size / 2]; + + while (length) { + int len = qMin(length, buffer_size / 2); + for (int i = 0; i < len; ++i) { + const qreal iw = fw == 0 ? 1 : 1 / fw; + const qreal px = fx * iw - qreal(0.5); + const qreal py = fy * iw - qreal(0.5); + + int x1 = int(px) - (px < 0); + int x2; + int y1 = int(py) - (py < 0); + int y2; + + distxs[i] = int((px - x1) * (1<<16)); + distys[i] = int((py - y1) * (1<<16)); + + fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); + fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2); + + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + + if (layout->bpp == QPixelLayout::BPP32) { + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + + } else { + sbuf1[i * 2 + 0] = fetch(s1, x1); + sbuf1[i * 2 + 1] = fetch(s1, x2); + sbuf2[i * 2 + 0] = fetch(s2, x1); + sbuf2[i * 2 + 1] = fetch(s2, x2); + } + + fx += fdx; + fy += fdy; + fw += fdw; + //force increment to avoid /0 + if (!fw) + fw += fdw; + } + + layout->convertToARGB64PM(buf1, sbuf1, len * 2, layout, clut); + layout->convertToARGB64PM(buf2, sbuf2, len * 2, layout, clut); + + for (int i = 0; i < len; ++i) { + int distx = distxs[i]; + int disty = distys[i]; + b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty); + } + + length -= len; + b += len; + } + } + + return buffer; +} + static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { // Untransformed { @@ -2298,12 +3229,186 @@ static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { }, }; +static SourceFetchProc64 sourceFetch64[NBlendTypes][QImage::NImageFormats] = { + // Untransformed + { + 0, // Invalid + fetchUntransformed64, // Mono + fetchUntransformed64, // MonoLsb + fetchUntransformed64, // Indexed8 + fetchUntransformed64, // RGB32 + fetchUntransformed64, // ARGB32 + fetchUntransformed64, // ARGB32_Premultiplied + fetchUntransformed64, // RGB16 + fetchUntransformed64, // ARGB8565_Premultiplied + fetchUntransformed64, // RGB666 + fetchUntransformed64, // ARGB6666_Premultiplied + fetchUntransformed64, // RGB555 + fetchUntransformed64, // ARGB8555_Premultiplied + fetchUntransformed64, // RGB888 + fetchUntransformed64, // RGB444 + fetchUntransformed64, // ARGB4444_Premultiplied + fetchUntransformed64, // RGBX8888 + fetchUntransformed64, // RGBA8888 + fetchUntransformed64, // RGBA8888_Premultiplied + fetchUntransformed64, // Format_BGR30 + fetchUntransformed64, // Format_A2BGR30_Premultiplied + fetchUntransformed64, // Format_RGB30 + fetchUntransformed64, // Format_A2RGB30_Premultiplied + fetchUntransformed64, // Alpha8 + fetchUntransformed64, // Grayscale8 + }, + // Tiled + { + 0, // Invalid + fetchUntransformed64, // Mono + fetchUntransformed64, // MonoLsb + fetchUntransformed64, // Indexed8 + fetchUntransformed64, // RGB32 + fetchUntransformed64, // ARGB32 + fetchUntransformed64, // ARGB32_Premultiplied + fetchUntransformed64, // RGB16 + fetchUntransformed64, // ARGB8565_Premultiplied + fetchUntransformed64, // RGB666 + fetchUntransformed64, // ARGB6666_Premultiplied + fetchUntransformed64, // RGB555 + fetchUntransformed64, // ARGB8555_Premultiplied + fetchUntransformed64, // RGB888 + fetchUntransformed64, // RGB444 + fetchUntransformed64, // ARGB4444_Premultiplied + fetchUntransformed64, // RGBX8888 + fetchUntransformed64, // RGBA8888 + fetchUntransformed64, // RGBA8888_Premultiplied + fetchUntransformed64, // BGR30 + fetchUntransformed64, // A2BGR30_Premultiplied + fetchUntransformed64, // RGB30 + fetchUntransformed64, // A2RGB30_Premultiplied + fetchUntransformed64, // Alpha8 + fetchUntransformed64, // Grayscale8 + }, + // Transformed + { + 0, // Invalid + fetchTransformed64<BlendTransformed>, // Mono + fetchTransformed64<BlendTransformed>, // MonoLsb + fetchTransformed64<BlendTransformed>, // Indexed8 + fetchTransformed64<BlendTransformed>, // RGB32 + fetchTransformed64<BlendTransformed>, // ARGB32 + fetchTransformed64<BlendTransformed>, // ARGB32_Premultiplied + fetchTransformed64<BlendTransformed>, // RGB16 + fetchTransformed64<BlendTransformed>, // ARGB8565_Premultiplied + fetchTransformed64<BlendTransformed>, // RGB666 + fetchTransformed64<BlendTransformed>, // ARGB6666_Premultiplied + fetchTransformed64<BlendTransformed>, // RGB555 + fetchTransformed64<BlendTransformed>, // ARGB8555_Premultiplied + fetchTransformed64<BlendTransformed>, // RGB888 + fetchTransformed64<BlendTransformed>, // RGB444 + fetchTransformed64<BlendTransformed>, // ARGB4444_Premultiplied + fetchTransformed64<BlendTransformed>, // RGBX8888 + fetchTransformed64<BlendTransformed>, // RGBA8888 + fetchTransformed64<BlendTransformed>, // RGBA8888_Premultiplied + fetchTransformed64<BlendTransformed>, // BGR30 + fetchTransformed64<BlendTransformed>, // A2BGR30_Premultiplied + fetchTransformed64<BlendTransformed>, // RGB30 + fetchTransformed64<BlendTransformed>, // A2RGB30_Premultiplied + fetchTransformed64<BlendTransformed>, // Alpah8 + fetchTransformed64<BlendTransformed>, // Grayscale8 + }, + { + 0, // TransformedTiled + fetchTransformed64<BlendTransformedTiled>, // Mono + fetchTransformed64<BlendTransformedTiled>, // MonoLsb + fetchTransformed64<BlendTransformedTiled>, // Indexed8 + fetchTransformed64<BlendTransformedTiled>, // RGB32 + fetchTransformed64<BlendTransformedTiled>, // ARGB32 + fetchTransformed64<BlendTransformedTiled>, // ARGB32_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGB16 + fetchTransformed64<BlendTransformedTiled>, // ARGB8565_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGB666 + fetchTransformed64<BlendTransformedTiled>, // ARGB6666_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGB555 + fetchTransformed64<BlendTransformedTiled>, // ARGB8555_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGB888 + fetchTransformed64<BlendTransformedTiled>, // RGB444 + fetchTransformed64<BlendTransformedTiled>, // ARGB4444_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGBX8888 + fetchTransformed64<BlendTransformedTiled>, // RGBA8888 + fetchTransformed64<BlendTransformedTiled>, // RGBA8888_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // BGR30 + fetchTransformed64<BlendTransformedTiled>, // A2BGR30_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // RGB30 + fetchTransformed64<BlendTransformedTiled>, // A2RGB30_Premultiplied + fetchTransformed64<BlendTransformedTiled>, // Alpha8 + fetchTransformed64<BlendTransformedTiled>, // Grayscale8 + }, + { + 0, // Bilinear + fetchTransformedBilinear64<BlendTransformedBilinear>, // Mono + fetchTransformedBilinear64<BlendTransformedBilinear>, // MonoLsb + fetchTransformedBilinear64<BlendTransformedBilinear>, // Indexed8 + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB32 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB32 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB32_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB16 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB8565_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB666 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB6666_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB555 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB8555_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB888 + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB444 + fetchTransformedBilinear64<BlendTransformedBilinear>, // ARGB4444_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGBX8888 + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGBA8888 + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGBA8888_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // BGR30 + fetchTransformedBilinear64<BlendTransformedBilinear>, // A2BGR30_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // RGB30 + fetchTransformedBilinear64<BlendTransformedBilinear>, // A2RGB30_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinear>, // Alpha8 + fetchTransformedBilinear64<BlendTransformedBilinear>, // Grayscale8 + }, + { + 0, // BilinearTiled + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Mono + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // MonoLsb + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Indexed8 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB32 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB32 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB32_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB16 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB8565_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB666 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB6666_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB555 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB8555_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB888 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB444 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // ARGB4444_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGBX8888 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGBA8888 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGBA8888_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // BGR30 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // A2BGR30_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // RGB30 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // A2RGB30_Premultiplied + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Alpha8 + fetchTransformedBilinear64<BlendTransformedBilinearTiled>, // Grayscale8 + }, +}; + #define FIXPT_BITS 8 #define FIXPT_SIZE (1<<FIXPT_BITS) static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos) { int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; + return data->colorTable[qt_gradient_clamp(data, ipos)].toArgb32(); +} + +static const QRgba64& qt_gradient_pixel64_fixed(const QGradientData *data, int fixed_pos) +{ + int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; return data->colorTable[qt_gradient_clamp(data, ipos)]; } @@ -2320,10 +3425,50 @@ static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const Q } } -static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +class GradientBase32 { - const uint *b = buffer; +public: + typedef uint Type; + static Type null() { return 0; } + static Type fetchSingle(const QGradientData& gradient, qreal v) + { + return qt_gradient_pixel(&gradient, v); + } + static Type fetchSingle(const QGradientData& gradient, int v) + { + return qt_gradient_pixel_fixed(&gradient, v); + } + static void memfill(Type *buffer, Type fill, int length) + { + qt_memfill32(buffer, fill, length); + } +}; + +class GradientBase64 +{ +public: + typedef QRgba64 Type; + static Type null() { return QRgba64::fromRgba64(0); } + static Type fetchSingle(const QGradientData& gradient, qreal v) + { + return qt_gradient_pixel64(&gradient, v); + } + static Type fetchSingle(const QGradientData& gradient, int v) + { + return qt_gradient_pixel64_fixed(&gradient, v); + } + static void memfill(Type *buffer, Type fill, int length) + { + qt_memfill64((quint64*)buffer, fill, length); + } +}; + +template<class GradientBase, typename BlendType> +static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template( + BlendType *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + const BlendType *b = buffer; qreal t, inc; bool affine = true; @@ -2343,10 +3488,10 @@ static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Ope } } - const uint *end = buffer + length; + const BlendType *end = buffer + length; if (affine) { if (inc > qreal(-1e-5) && inc < qreal(1e-5)) { - QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE))); + GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, int(t * FIXPT_SIZE)), length); } else { if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) && t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) { @@ -2354,14 +3499,14 @@ static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Ope int t_fixed = int(t * FIXPT_SIZE); int inc_fixed = int(inc * FIXPT_SIZE); while (buffer < end) { - *buffer = qt_gradient_pixel_fixed(&data->gradient, t_fixed); + *buffer = GradientBase::fetchSingle(data->gradient, t_fixed); t_fixed += inc_fixed; ++buffer; } } else { // we have to fall back to float math while (buffer < end) { - *buffer = qt_gradient_pixel(&data->gradient, t/GRADIENT_STOPTABLE_SIZE); + *buffer = GradientBase::fetchSingle(data->gradient, t/GRADIENT_STOPTABLE_SIZE); t += inc; ++buffer; } @@ -2374,7 +3519,7 @@ static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Ope qreal y = ry/rw; t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off; - *buffer = qt_gradient_pixel(&data->gradient, t); + *buffer = GradientBase::fetchSingle(data->gradient, t); rx += data->m11; ry += data->m12; rw += data->m13; @@ -2388,6 +3533,18 @@ static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Ope return b; } +static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_linear_gradient_template<GradientBase32, uint>(buffer, op, data, y, x, length); +} + +static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_linear_gradient_template<GradientBase64, QRgba64>(buffer, op, data, y, x, length); +} + static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data) { v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x; @@ -2402,19 +3559,22 @@ static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const Q v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0; } -class RadialFetchPlain +template <class GradientBase> +class RadialFetchPlain : public GradientBase { public: - static inline 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) + typedef typename GradientBase::Type BlendType; + static void fetch(BlendType *buffer, BlendType *end, + const Operator *op, const QSpanData *data, qreal det, + qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) { if (op->radial.extended) { while (buffer < end) { - quint32 result = 0; + BlendType result = GradientBase::null(); if (det >= 0) { qreal w = qSqrt(det) - b; if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0) - result = qt_gradient_pixel(&data->gradient, w); + result = GradientBase::fetchSingle(data->gradient, w); } *buffer = result; @@ -2427,7 +3587,7 @@ public: } } else { while (buffer < end) { - *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b); + *buffer++ = GradientBase::fetchSingle(data->gradient, qSqrt(det) - b); det += delta_det; delta_det += delta_delta_det; @@ -2440,15 +3600,23 @@ public: const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { - return qt_fetch_radial_gradient_template<RadialFetchPlain>(buffer, op, data, y, x, length); + return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBase32>, uint>(buffer, op, data, y, x, length); } static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain; -static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data, - int y, int x, int length) +const QRgba64 * QT_FASTCALL qt_fetch_radial_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBase64>, QRgba64>(buffer, op, data, y, x, length); +} + +template <class GradientBase, typename BlendType> +static inline const BlendType * QT_FASTCALL qt_fetch_conical_gradient_template( + BlendType *buffer, const QSpanData *data, + int y, int x, int length) { - const uint *b = buffer; + const BlendType *b = buffer; qreal rx = data->m21 * (y + qreal(0.5)) + data->dx + data->m11 * (x + qreal(0.5)); qreal ry = data->m22 * (y + qreal(0.5)) @@ -2457,14 +3625,14 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op const qreal inv2pi = M_1_PI / 2.0; - const uint *end = buffer + length; + const BlendType *end = buffer + length; if (affine) { rx -= data->gradient.conical.center.x; ry -= data->gradient.conical.center.y; while (buffer < end) { qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle; - *buffer = qt_gradient_pixel(&data->gradient, 1 - angle * inv2pi); + *buffer = GradientBase::fetchSingle(data->gradient, 1 - angle * inv2pi); rx += data->m11; ry += data->m12; @@ -2480,7 +3648,7 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op rx/rw - data->gradient.conical.center.y) + data->gradient.conical.angle; - *buffer = qt_gradient_pixel(&data->gradient, 1 - angle * inv2pi); + *buffer = GradientBase::fetchSingle(data->gradient, 1 - angle * inv2pi); rx += data->m11; ry += data->m12; @@ -2494,1763 +3662,29 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op return b; } -# define PRELOAD_INIT(x) -# define PRELOAD_INIT2(x,y) -# define PRELOAD_COND(x) -# define PRELOAD_COND2(x,y) - -/* The constant alpha factor describes an alpha factor that gets applied - to the result of the composition operation combining it with the destination. - - The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1. - we get the unmodified operation - - result = src op dest - dest = result * const_alpha + dest * (1. - const_alpha) - - This means that in the comments below, the first line is the const_alpha==255 case, the - second line the general one. - - In the lines below: - s == src, sa == alpha(src), sia = 1 - alpha(src) - d == dest, da == alpha(dest), dia = 1 - alpha(dest) - ca = const_alpha, cia = 1 - const_alpha - - The methods exist in two variants. One where we have a constant source, the other - where the source is an array of pixels. -*/ - -/* - result = 0 - d = d * cia -*/ -#define comp_func_Clear_impl(dest, length, const_alpha)\ -{\ - if (const_alpha == 255) {\ - QT_MEMFILL_UINT(dest, length, 0);\ - } else {\ - int ialpha = 255 - const_alpha;\ - PRELOAD_INIT(dest)\ - for (int i = 0; i < length; ++i) {\ - PRELOAD_COND(dest)\ - dest[i] = BYTE_MUL(dest[i], ialpha);\ - }\ - }\ -} - -void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha) -{ - comp_func_Clear_impl(dest, length, const_alpha); -} - -void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha) -{ - comp_func_Clear_impl(dest, length, const_alpha); -} - -/* - result = s - dest = s * ca + d * cia -*/ -void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) { - QT_MEMFILL_UINT(dest, length, color); - } else { - int ialpha = 255 - const_alpha; - color = BYTE_MUL(color, const_alpha); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = color + BYTE_MUL(dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - ::memcpy(dest, src, length * sizeof(uint)); - } else { - int ialpha = 255 - const_alpha; - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint) -{ -} - -void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint) -{ -} - -/* - result = s + d * sia - dest = (s + d * sia) * ca + d * cia - = s * ca + d * (sia * ca + cia) - = s * ca + d * (1 - sa*ca) -*/ -void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha) -{ - if ((const_alpha & qAlpha(color)) == 255) { - QT_MEMFILL_UINT(dest, length, color); - } else { - if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color)); - } - } -} - -void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = src[i]; - if (s >= 0xff000000) - dest[i] = s; - else if (s != 0) - dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); - } - } -} - -/* - result = d + s * dia - dest = (d + s * dia) * ca + d * cia - = d + s * dia * ca -*/ -void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = d + BYTE_MUL(color, qAlpha(~d)); - } -} - -void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - dest[i] = d + BYTE_MUL(src[i], qAlpha(~d)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = d + BYTE_MUL(s, qAlpha(~d)); - } - } -} - -/* - result = s * da - dest = s * da * ca + d * cia -*/ -void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha) -{ - PRELOAD_INIT(dest) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(color, qAlpha(dest[i])); - } - } else { - color = BYTE_MUL(color, const_alpha); - uint cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia); - } - } -} - -void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(src[i], qAlpha(dest[i])); - } - } else { - uint cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia); - } - } -} - -/* - result = d * sa - dest = d * sa * ca + d * cia - = d * (sa * ca + cia) -*/ -void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha) -{ - uint a = qAlpha(color); - if (const_alpha != 255) { - a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - } - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(dest[i], a); - } -} - -void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(dest[i], qAlpha(src[i])); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia; - dest[i] = BYTE_MUL(dest[i], a); - } - } -} - -/* - result = s * dia - dest = s * dia * ca + d * cia -*/ - -void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha) -{ - PRELOAD_INIT(dest) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(color, qAlpha(~dest[i])); - } - } else { - color = BYTE_MUL(color, const_alpha); - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia); - } - } -} - -void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i])); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia); - } - } -} - -/* - result = d * sia - dest = d * sia * ca + d * cia - = d * (sia * ca + cia) -*/ -void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha) -{ - uint a = qAlpha(~color); - if (const_alpha != 255) - a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(dest[i], a); - } -} - -void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i])); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia; - dest[i] = BYTE_MUL(dest[i], sia); - } - } -} - -/* - result = s*da + d*sia - dest = s*da*ca + d*sia*ca + d *cia - = s*ca * da + d * (sia*ca + cia) - = s*ca * da + d * (1 - sa*ca) -*/ -void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha != 255) { - color = BYTE_MUL(color, const_alpha); - } - uint sia = qAlpha(~color); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia); - } -} - -void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = src[i]; - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); - } - } -} - -/* - result = d*sa + s*dia - dest = d*sa*ca + s*dia*ca + d *cia - = s*ca * dia + d * (sa*ca + cia) -*/ -void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha) -{ - uint a = qAlpha(color); - if (const_alpha != 255) { - color = BYTE_MUL(color, const_alpha); - a = qAlpha(color) + 255 - const_alpha; - } - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d)); - } -} - -void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = src[i]; - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d)); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - uint a = qAlpha(s) + cia; - dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d)); - } - } -} - -/* - result = d*sia + s*dia - dest = d*sia*ca + s*dia*ca + d *cia - = s*ca * dia + d * (sia*ca + cia) - = s*ca * dia + d * (1 - sa*ca) -*/ -void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); - uint sia = qAlpha(~color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia); - } -} - -void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); - } - } -} - -struct QFullCoverage { - inline void store(uint *dest, const uint src) const - { - *dest = src; - } -}; - -struct QPartialCoverage { - inline QPartialCoverage(uint const_alpha) - : ca(const_alpha) - , ica(255 - const_alpha) - { - } - - inline void store(uint *dest, const uint src) const - { - *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica); - } - -private: - const uint ca; - const uint ica; -}; - -static inline int mix_alpha(int da, int sa) -{ - return 255 - ((255 - sa) * (255 - da) >> 8); -} - -/* - Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa) - = Sca + Dca -*/ -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage) -{ - uint s = color; - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - d = comp_func_Plus_one_pixel(d, s); - coverage.store(&dest[i], d); - } -} - -void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Plus_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - d = comp_func_Plus_one_pixel(d, s); - - coverage.store(&dest[i], d); - } -} - -void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Plus_impl(dest, src, length, QFullCoverage()); - else - comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int multiply_op(int dst, int src, int da, int sa) -{ - return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) multiply_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) multiply_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Multiply(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Multiply_impl(dest, src, length, QFullCoverage()); - else - comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) - = Sca + Dca - Sca.Dca -*/ -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) 255 - qt_div_255((255-a) * (255-b)) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Screen_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) 255 - (((255-a) * (255-b)) >> 8) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Screen_impl(dest, src, length, QFullCoverage()); - else - comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if 2.Dca < Da - Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int overlay_op(int dst, int src, int da, int sa) -{ - const int temp = src * (255 - da) + dst * (255 - sa); - if (2 * dst < da) - return qt_div_255(2 * src * dst + temp); - else - return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) overlay_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) overlay_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Overlay(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Overlay_impl(dest, src, length, QFullCoverage()); - else - comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) - Da' = Sa + Da - Sa.Da -*/ -static inline int darken_op(int dst, int src, int da, int sa) -{ - return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) darken_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Darken_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) darken_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Darken(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Darken_impl(dest, src, length, QFullCoverage()); - else - comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) - Da' = Sa + Da - Sa.Da -*/ -static inline int lighten_op(int dst, int src, int da, int sa) -{ - return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) lighten_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) lighten_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Lighten(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Lighten_impl(dest, src, length, QFullCoverage()); - else - comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if Sca.Da + Dca.Sa >= Sa.Da - Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int color_dodge_op(int dst, int src, int da, int sa) -{ - const int sa_da = sa * da; - const int dst_sa = dst * sa; - const int src_da = src * da; - - const int temp = src * (255 - da) + dst * (255 - sa); - if (src_da + dst_sa >= sa_da) - return qt_div_255(sa_da + temp); - else - return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a,b) color_dodge_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) color_dodge_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_ColorDodge(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_ColorDodge_impl(dest, src, length, QFullCoverage()); - else - comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if Sca.Da + Dca.Sa <= Sa.Da - Dca' = Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int color_burn_op(int dst, int src, int da, int sa) -{ - const int src_da = src * da; - const int dst_sa = dst * sa; - const int sa_da = sa * da; - - const int temp = src * (255 - da) + dst * (255 - sa); - - if (src == 0 || src_da + dst_sa <= sa_da) - return qt_div_255(temp); - return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) color_burn_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) color_burn_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_ColorBurn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_ColorBurn_impl(dest, src, length, QFullCoverage()); - else - comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if 2.Sca < Sa - Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline uint hardlight_op(int dst, int src, int da, int sa) -{ - const uint temp = src * (255 - da) + dst * (255 - sa); - - if (2 * src < sa) - return qt_div_255(2 * src * dst + temp); - else - return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) hardlight_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) hardlight_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_HardLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_HardLight_impl(dest, src, length, QFullCoverage()); - else - comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if 2.Sca <= Sa - Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise if 2.Sca > Sa and 4.Dca <= Da - 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) - otherwise if 2.Sca > Sa and 4.Dca > Da - Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int soft_light_op(int dst, int src, int da, int sa) -{ - const int src2 = src << 1; - const int dst_np = da != 0 ? (255 * dst) / da : 0; - const int temp = (src * (255 - da) + dst * (255 - sa)) * 255; - - if (src2 < sa) - return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025; - else if (4 * dst <= da) - return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025; - else { - return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025; - } -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) soft_light_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) soft_light_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_SoftLight_impl(dest, src, length, QFullCoverage()); - else - comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa) - = Sca + Dca - 2.min(Sca.Da, Dca.Sa) -*/ -static inline int difference_op(int dst, int src, int da, int sa) -{ - return src + dst - qt_div_255(2 * qMin(src * da, dst * sa)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) difference_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Difference_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) difference_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Difference(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Difference_impl(dest, src, length, QFullCoverage()); - else - comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) (a + b - qt_div_255(2*(a*b))) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template <typename T> -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) (a + b - ((a*b) >> 7)) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Exclusion(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Exclusion_impl(dest, src, length, QFullCoverage()); - else - comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) - *dest++ |= color; -} - -void QT_FASTCALL rasterop_SourceOrDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) - *dest++ |= *src++; -} - -void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color |= 0xff000000; - while (length--) - *dest++ &= color; -} - -void QT_FASTCALL rasterop_SourceAndDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src & *dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color &= 0x00ffffff; - while (length--) - *dest++ ^= color; -} - -void QT_FASTCALL rasterop_SourceXorDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src ^ *dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color; - while (length--) { - *dest = (color & ~(*dest)) | 0xff000000; - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (~(*src) & ~(*dest)) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color | 0xff000000; - while (length--) { - *dest = color | ~(*dest); - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = ~(*src) | ~(*dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color & 0x00ffffff; - while (length--) { - *dest = color ^ (*dest); - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceXorDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = ((~(*src)) ^ (*dest)) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length, - uint color, uint const_alpha) -{ - Q_UNUSED(const_alpha); - qt_memfill(dest, ~color | 0xff000000, length); -} - -void QT_FASTCALL rasterop_NotSource(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, - int length, uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) - *dest++ = ~(*src++) | 0xff000000; -} - -void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color | 0xff000000; - while (length--) { - *dest = color & *dest; - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceAndDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (~(*src) & *dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (color & ~(*dest)) | 0xff000000; - ++dest; - } -} - -void QT_FASTCALL rasterop_SourceAndNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src & ~(*dest)) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (~(*src) | *dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) +static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) { - Q_UNUSED(const_alpha); - color = ~color | 0xff000000; - while (length--) - *dest++ |= color; + return qt_fetch_conical_gradient_template<GradientBase32, uint>(buffer, data, y, x, length); } -void QT_FASTCALL rasterop_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) +static const QRgba64 * QT_FASTCALL qt_fetch_conical_gradient_rgb64(QRgba64 *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) { - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src | ~(*dest)) | 0xff000000; - ++dest; ++src; - } + return qt_fetch_conical_gradient_template<GradientBase64, QRgba64>(buffer, data, y, x, length); } -void QT_FASTCALL rasterop_solid_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (color | ~(*dest)) | 0xff000000; - ++dest; - } -} +extern CompositionFunctionSolid qt_functionForModeSolid_C[]; +extern CompositionFunctionSolid64 qt_functionForModeSolid64_C[]; -void QT_FASTCALL rasterop_ClearDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(src); - comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); -} - -void QT_FASTCALL rasterop_solid_ClearDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(color); - comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); -} - -void QT_FASTCALL rasterop_SetDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(src); - comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); -} - -void QT_FASTCALL rasterop_solid_SetDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(color); - comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); -} - -void QT_FASTCALL rasterop_NotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(src); - rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); -} - -void QT_FASTCALL rasterop_solid_NotDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(color); - rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); -} - -static CompositionFunctionSolid functionForModeSolid_C[] = { - comp_func_solid_SourceOver, - comp_func_solid_DestinationOver, - comp_func_solid_Clear, - comp_func_solid_Source, - comp_func_solid_Destination, - comp_func_solid_SourceIn, - comp_func_solid_DestinationIn, - comp_func_solid_SourceOut, - comp_func_solid_DestinationOut, - comp_func_solid_SourceAtop, - comp_func_solid_DestinationAtop, - comp_func_solid_XOR, - comp_func_solid_Plus, - comp_func_solid_Multiply, - comp_func_solid_Screen, - comp_func_solid_Overlay, - comp_func_solid_Darken, - comp_func_solid_Lighten, - comp_func_solid_ColorDodge, - comp_func_solid_ColorBurn, - comp_func_solid_HardLight, - comp_func_solid_SoftLight, - comp_func_solid_Difference, - comp_func_solid_Exclusion, - rasterop_solid_SourceOrDestination, - rasterop_solid_SourceAndDestination, - rasterop_solid_SourceXorDestination, - rasterop_solid_NotSourceAndNotDestination, - rasterop_solid_NotSourceOrNotDestination, - rasterop_solid_NotSourceXorDestination, - rasterop_solid_NotSource, - rasterop_solid_NotSourceAndDestination, - rasterop_solid_SourceAndNotDestination, - rasterop_solid_NotSourceOrDestination, - rasterop_solid_SourceOrNotDestination, - rasterop_solid_ClearDestination, - rasterop_solid_SetDestination, - rasterop_solid_NotDestination -}; +static const CompositionFunctionSolid *functionForModeSolid = qt_functionForModeSolid_C; +static const CompositionFunctionSolid64 *functionForModeSolid64 = qt_functionForModeSolid64_C; -static const CompositionFunctionSolid *functionForModeSolid = functionForModeSolid_C; - -static CompositionFunction functionForMode_C[] = { - comp_func_SourceOver, - comp_func_DestinationOver, - comp_func_Clear, - comp_func_Source, - comp_func_Destination, - comp_func_SourceIn, - comp_func_DestinationIn, - comp_func_SourceOut, - comp_func_DestinationOut, - comp_func_SourceAtop, - comp_func_DestinationAtop, - comp_func_XOR, - comp_func_Plus, - comp_func_Multiply, - comp_func_Screen, - comp_func_Overlay, - comp_func_Darken, - comp_func_Lighten, - comp_func_ColorDodge, - comp_func_ColorBurn, - comp_func_HardLight, - comp_func_SoftLight, - comp_func_Difference, - comp_func_Exclusion, - rasterop_SourceOrDestination, - rasterop_SourceAndDestination, - rasterop_SourceXorDestination, - rasterop_NotSourceAndNotDestination, - rasterop_NotSourceOrNotDestination, - rasterop_NotSourceXorDestination, - rasterop_NotSource, - rasterop_NotSourceAndDestination, - rasterop_SourceAndNotDestination, - rasterop_NotSourceOrDestination, - rasterop_SourceOrNotDestination, - rasterop_ClearDestination, - rasterop_SetDestination, - rasterop_NotDestination -}; +extern CompositionFunction qt_functionForMode_C[]; +extern CompositionFunction64 qt_functionForMode64_C[]; -static const CompositionFunction *functionForMode = functionForMode_C; +static const CompositionFunction *functionForMode = qt_functionForMode_C; +static const CompositionFunction64 *functionForMode64 = qt_functionForMode64_C; static TextureBlendType getBlendType(const QSpanData *data) { @@ -4280,26 +3714,34 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in switch(data->type) { case QSpanData::Solid: - solidSource = (qAlpha(data->solid.color) == 255); + solidSource = data->solid.color.isOpaque(); + op.srcFetch = 0; + op.srcFetch64 = 0; break; case QSpanData::LinearGradient: solidSource = !data->gradient.alphaColor; getLinearGradientValues(&op.linear, data); - op.src_fetch = qt_fetch_linear_gradient; + op.srcFetch = qt_fetch_linear_gradient; + op.srcFetch64 = qt_fetch_linear_gradient_rgb64; break; case QSpanData::RadialGradient: solidSource = !data->gradient.alphaColor; getRadialGradientValues(&op.radial, data); - op.src_fetch = qt_fetch_radial_gradient; + op.srcFetch = qt_fetch_radial_gradient; + op.srcFetch64 = qt_fetch_radial_gradient_rgb64; break; case QSpanData::ConicalGradient: solidSource = !data->gradient.alphaColor; - op.src_fetch = qt_fetch_conical_gradient; + op.srcFetch = qt_fetch_conical_gradient; + op.srcFetch64 = qt_fetch_conical_gradient_rgb64; break; case QSpanData::Texture: - op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format]; solidSource = !data->texture.hasAlpha; + op.srcFetch = sourceFetch[getBlendType(data)][data->texture.format]; + op.srcFetch64 = sourceFetch64[getBlendType(data)][data->texture.format]; + break; default: + Q_UNREACHABLE(); break; } @@ -4307,12 +3749,13 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in if (op.mode == QPainter::CompositionMode_SourceOver && solidSource) op.mode = QPainter::CompositionMode_Source; - op.dest_fetch = destFetchProc[data->rasterBuffer->format]; + op.destFetch = destFetchProc[data->rasterBuffer->format]; + op.destFetch64 = destFetchProc64[data->rasterBuffer->format]; if (op.mode == QPainter::CompositionMode_Source) { switch (data->rasterBuffer->format) { case QImage::Format_RGB32: case QImage::Format_ARGB32_Premultiplied: - // don't clear dest_fetch as it sets up the pointer correctly to save one copy + // don't clear destFetch as it sets up the pointer correctly to save one copy break; default: { if (data->type == QSpanData::Texture && data->texture.const_alpha != 256) @@ -4327,15 +3770,18 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in ++spans; } if (!alphaSpans) - op.dest_fetch = 0; + op.destFetch = 0; } } } - op.dest_store = destStoreProc[data->rasterBuffer->format]; + op.destStore = destStoreProc[data->rasterBuffer->format]; + op.destStore64 = destStoreProc64[data->rasterBuffer->format]; op.funcSolid = functionForModeSolid[op.mode]; + op.funcSolid64 = functionForModeSolid64[op.mode]; op.func = functionForMode[op.mode]; + op.func64 = functionForMode64[op.mode]; return op; } @@ -4352,16 +3798,17 @@ void blend_color_generic(int count, const QSpan *spans, void *userData) QSpanData *data = reinterpret_cast<QSpanData *>(userData); uint buffer[buffer_size]; Operator op = getOperator(data, spans, count); + const uint color = data->solid.color.toArgb32(); while (count--) { int x = spans->x; int length = spans->len; while (length) { int l = qMin(buffer_size, length); - uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; - op.funcSolid(dest, l, data->solid.color, spans->coverage); - if (op.dest_store) - op.dest_store(data->rasterBuffer, x, spans->y, dest, l); + uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; + op.funcSolid(dest, l, color, spans->coverage); + if (op.destStore) + op.destStore(data->rasterBuffer, x, spans->y, dest, l); length -= l; x += l; } @@ -4374,15 +3821,16 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData) QSpanData *data = reinterpret_cast<QSpanData *>(userData); Operator op = getOperator(data, spans, count); + const uint color = data->solid.color.toArgb32(); if (op.mode == QPainter::CompositionMode_Source) { // inline for performance while (count--) { uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x; if (spans->coverage == 255) { - QT_MEMFILL_UINT(target, spans->len, data->solid.color); + QT_MEMFILL_UINT(target, spans->len, color); } else { - uint c = BYTE_MUL(data->solid.color, spans->coverage); + uint c = BYTE_MUL(color, spans->coverage); int ialpha = 255 - spans->coverage; for (int i = 0; i < spans->len; ++i) target[i] = c + BYTE_MUL(target[i], ialpha); @@ -4394,7 +3842,34 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData) while (count--) { uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x; - op.funcSolid(target, spans->len, data->solid.color, spans->coverage); + op.funcSolid(target, spans->len, color, spans->coverage); + ++spans; + } +} + +void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData) +{ + QSpanData *data = reinterpret_cast<QSpanData *>(userData); + Operator op = getOperator(data, spans, count); + if (!op.funcSolid64) { + qDebug() << Q_FUNC_INFO << "unsupported 64bit blend attempted"; + return blend_color_generic(count, spans, userData); + } + + QRgba64 buffer[buffer_size]; + const QRgba64 color = data->solid.color; + + while (count--) { + int x = spans->x; + int length = spans->len; + while (length) { + int l = qMin(buffer_size, length); + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); + op.funcSolid64(dest, l, color, spans->coverage); + op.destStore64(data->rasterBuffer, x, spans->y, dest, l); + length -= l; + x += l; + } ++spans; } } @@ -4409,13 +3884,12 @@ static void blend_color_rgb16(int count, const QSpan *spans, void *userData) from qt_gradient_quint16 with minimal overhead. */ QPainter::CompositionMode mode = data->rasterBuffer->compositionMode; - if (mode == QPainter::CompositionMode_SourceOver && - qAlpha(data->solid.color) == 255) + if (mode == QPainter::CompositionMode_SourceOver && data->solid.color.isOpaque()) mode = QPainter::CompositionMode_Source; if (mode == QPainter::CompositionMode_Source) { // inline for performance - ushort c = qConvertRgb32To16(data->solid.color); + ushort c = data->solid.color.toRgb16(); while (count--) { ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x; if (spans->coverage == 255) { @@ -4436,7 +3910,7 @@ static void blend_color_rgb16(int count, const QSpan *spans, void *userData) if (mode == QPainter::CompositionMode_SourceOver) { while (count--) { - uint color = BYTE_MUL(data->solid.color, spans->coverage); + uint color = BYTE_MUL(data->solid.color.toArgb32(), spans->coverage); int ialpha = qAlpha(~color); ushort c = qConvertRgb32To16(color); ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x; @@ -4500,7 +3974,7 @@ void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handle int process_length = l; int process_x = x; - const uint *src = handler.fetch(process_x, y, process_length); + const typename T::BlendType *src = handler.fetch(process_x, y, process_length); int offset = 0; while (l > 0) { if (x == spans->x) // new span? @@ -4525,8 +3999,10 @@ void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handle } } +template<typename T> struct QBlendBase { + typedef T BlendType; QBlendBase(QSpanData *d, Operator o) : data(d) , op(o) @@ -4537,24 +4013,24 @@ struct QBlendBase QSpanData *data; Operator op; - uint *dest; + BlendType *dest; - uint buffer[buffer_size]; - uint src_buffer[buffer_size]; + BlendType buffer[buffer_size]; + BlendType src_buffer[buffer_size]; }; -class BlendSrcGeneric : public QBlendBase +class BlendSrcGeneric : public QBlendBase<uint> { public: BlendSrcGeneric(QSpanData *d, Operator o) - : QBlendBase(d, o) + : QBlendBase<uint>(d, o) { } const uint *fetch(int x, int y, int len) { - dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, y, len) : buffer; - return op.src_fetch(src_buffer, &op, data, y, x, len); + dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, y, len) : buffer; + return op.srcFetch(src_buffer, &op, data, y, x, len); } void process(int, int, int len, int coverage, const uint *src, int offset) @@ -4564,8 +4040,38 @@ public: void store(int x, int y, int len) { - if (op.dest_store) - op.dest_store(data->rasterBuffer, x, y, dest, len); + if (op.destStore) + op.destStore(data->rasterBuffer, x, y, dest, len); + } +}; + +class BlendSrcGenericRGB64 : public QBlendBase<QRgba64> +{ +public: + BlendSrcGenericRGB64(QSpanData *d, Operator o) + : QBlendBase<QRgba64>(d, o) + { + } + + bool isSupported() const + { + return op.func64 && op.destFetch64 && op.destStore64; + } + + const QRgba64 *fetch(int x, int y, int len) + { + dest = op.destFetch64(buffer, data->rasterBuffer, x, y, len); + return op.srcFetch64(src_buffer, &op, data, y, x, len); + } + + void process(int, int, int len, int coverage, const QRgba64 *src, int offset) + { + op.func64(dest + offset, src + offset, len, coverage); + } + + void store(int x, int y, int len) + { + op.destStore64(data->rasterBuffer, x, y, dest, len); } }; @@ -4576,6 +4082,20 @@ static void blend_src_generic(int count, const QSpan *spans, void *userData) handleSpans(count, spans, data, blend); } +static void blend_src_generic_rgb64(int count, const QSpan *spans, void *userData) +{ + QSpanData *data = reinterpret_cast<QSpanData *>(userData); + Operator op = getOperator(data, spans, count); + BlendSrcGenericRGB64 blend64(data, op); + if (blend64.isSupported()) + handleSpans(count, spans, data, blend64); + else { + qDebug("blend_src_generic_rgb64: unsupported 64-bit blend attempted"); + BlendSrcGeneric blend32(data, op); + handleSpans(count, spans, data, blend32); + } +} + static void blend_untransformed_generic(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); @@ -4606,11 +4126,59 @@ static void blend_untransformed_generic(int count, const QSpan *spans, void *use const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { int l = qMin(buffer_size, length); - const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l); - uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; + const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l); + uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; op.func(dest, src, l, coverage); - if (op.dest_store) - op.dest_store(data->rasterBuffer, x, spans->y, dest, l); + if (op.destStore) + op.destStore(data->rasterBuffer, x, spans->y, dest, l); + x += l; + sx += l; + length -= l; + } + } + } + ++spans; + } +} + +static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, void *userData) +{ + QSpanData *data = reinterpret_cast<QSpanData *>(userData); + + Operator op = getOperator(data, spans, count); + if (!op.func64) { + qWarning() << Q_FUNC_INFO << "Unsupported blend"; + return blend_untransformed_generic(count, spans, userData); + } + QRgba64 buffer[buffer_size]; + QRgba64 src_buffer[buffer_size]; + + const int image_width = data->texture.width; + const int image_height = data->texture.height; + int xoff = -qRound(-data->dx); + int yoff = -qRound(-data->dy); + + while (count--) { + int x = spans->x; + int length = spans->len; + int sx = xoff + x; + int sy = yoff + spans->y; + if (sy >= 0 && sy < image_height && sx < image_width) { + if (sx < 0) { + x -= sx; + length += sx; + sx = 0; + } + if (sx + length > image_width) + length = image_width - sx; + if (length > 0) { + const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; + while (length) { + int l = qMin(buffer_size, length); + const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l); + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); + op.func64(dest, src, l, coverage); + op.destStore64(data->rasterBuffer, x, spans->y, dest, l); x += l; sx += l; length -= l; @@ -4799,11 +4367,62 @@ static void blend_tiled_generic(int count, const QSpan *spans, void *userData) int l = qMin(image_width - sx, length); if (buffer_size < l) l = buffer_size; - const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l); - uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; + const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l); + uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; op.func(dest, src, l, coverage); - if (op.dest_store) - op.dest_store(data->rasterBuffer, x, spans->y, dest, l); + if (op.destStore) + op.destStore(data->rasterBuffer, x, spans->y, dest, l); + x += l; + sx += l; + length -= l; + if (sx >= image_width) + sx = 0; + } + ++spans; + } +} + +static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userData) +{ + QSpanData *data = reinterpret_cast<QSpanData *>(userData); + + Operator op = getOperator(data, spans, count); + if (!op.func64) { + qDebug("unsupported rgb64 blend"); + return blend_tiled_generic(count, spans, userData); + } + QRgba64 buffer[buffer_size]; + QRgba64 src_buffer[buffer_size]; + + const int image_width = data->texture.width; + const int image_height = data->texture.height; + int xoff = -qRound(-data->dx) % image_width; + int yoff = -qRound(-data->dy) % image_height; + + if (xoff < 0) + xoff += image_width; + if (yoff < 0) + yoff += image_height; + + while (count--) { + int x = spans->x; + int length = spans->len; + int sx = (xoff + spans->x) % image_width; + int sy = (spans->y + yoff) % image_height; + if (sx < 0) + sx += image_width; + if (sy < 0) + sy += image_height; + + const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; + while (length) { + int l = qMin(image_width - sx, length); + if (buffer_size < l) + l = buffer_size; + const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l); + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); + op.func64(dest, src, l, coverage); + op.destStore64(data->rasterBuffer, x, spans->y, dest, l); x += l; sx += l; length -= l; @@ -5684,10 +5303,10 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_untransformed_generic, blend_untransformed_generic, blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, - blend_untransformed_generic, + blend_untransformed_generic_rgb64, + blend_untransformed_generic_rgb64, + blend_untransformed_generic_rgb64, + blend_untransformed_generic_rgb64, blend_untransformed_generic, blend_untransformed_generic, }, @@ -5712,10 +5331,10 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_tiled_generic, blend_tiled_generic, blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, - blend_tiled_generic, + blend_tiled_generic_rgb64, + blend_tiled_generic_rgb64, + blend_tiled_generic_rgb64, + blend_tiled_generic_rgb64, blend_tiled_generic, blend_tiled_generic, }, @@ -5740,10 +5359,10 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, blend_src_generic, blend_src_generic, - blend_src_generic, - blend_src_generic, - blend_src_generic, - blend_src_generic, + blend_src_generic_rgb64, + blend_src_generic_rgb64, + blend_src_generic_rgb64, + blend_src_generic_rgb64, blend_src_generic, blend_src_generic, }, @@ -5767,12 +5386,12 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, blend_src_generic, blend_src_generic, + blend_src_generic_rgb64, + blend_src_generic_rgb64, + blend_src_generic_rgb64, + blend_src_generic_rgb64, blend_src_generic, blend_src_generic, - blend_src_generic, - blend_src_generic, - blend_src_generic, - blend_src_generic }, // Bilinear { @@ -5795,10 +5414,10 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, blend_src_generic, blend_src_generic, - blend_src_generic, - blend_src_generic, - blend_src_generic, - blend_src_generic, + blend_src_generic_rgb64, + blend_src_generic_rgb64, + blend_src_generic_rgb64, + blend_src_generic_rgb64, blend_src_generic, blend_src_generic, }, @@ -5823,10 +5442,10 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, // RGBX8888 blend_src_generic, // RGBA8888 blend_src_generic, // RGBA8888_Premultiplied - blend_src_generic, // BGR30 - blend_src_generic, // A2BGR30_Premultiplied - blend_src_generic, // RGB30 - blend_src_generic, // A2RGB30_Premultiplied + blend_src_generic_rgb64, // BGR30 + blend_src_generic_rgb64, // A2BGR30_Premultiplied + blend_src_generic_rgb64, // RGB30 + blend_src_generic_rgb64, // A2RGB30_Premultiplied blend_src_generic, // Alpha8 blend_src_generic, // Grayscale8 } @@ -5982,13 +5601,11 @@ static void qt_gradient_quint16(int count, const QSpan *spans, void *userData) int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE); int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE)); - uint oldColor = data->solid.color; + QRgba64 oldColor = data->solid.color; while (count--) { int y = spans->y; - quint32 color = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off); - - data->solid.color = color; + data->solid.color = QRgba64::fromArgb32(qt_gradient_pixel_fixed(&data->gradient, yinc * y + off)); blend_color_rgb16(1, spans, userData); ++spans; } @@ -6000,39 +5617,49 @@ static void qt_gradient_quint16(int count, const QSpan *spans, void *userData) } inline static void qt_bitmapblit_argb32(QRasterBuffer *rasterBuffer, - int x, int y, quint32 color, + int x, int y, const QRgba64 &color, const uchar *map, int mapWidth, int mapHeight, int mapStride) { - qt_bitmapblit_template<quint32>(rasterBuffer, x, y, color, + qt_bitmapblit_template<quint32>(rasterBuffer, x, y, color.toArgb32(), map, mapWidth, mapHeight, mapStride); } inline static void qt_bitmapblit_rgba8888(QRasterBuffer *rasterBuffer, - int x, int y, quint32 color, + int x, int y, const QRgba64 &color, const uchar *map, int mapWidth, int mapHeight, int mapStride) { - qt_bitmapblit_template<quint32>(rasterBuffer, x, y, ARGB2RGBA(color), + qt_bitmapblit_template<quint32>(rasterBuffer, x, y, ARGB2RGBA(color.toArgb32()), + map, mapWidth, mapHeight, mapStride); +} + +template<QtPixelOrder PixelOrder> +inline static void qt_bitmapblit_rgb30(QRasterBuffer *rasterBuffer, + int x, int y, const QRgba64 &color, + const uchar *map, + int mapWidth, int mapHeight, int mapStride) +{ + qt_bitmapblit_template<quint32>(rasterBuffer, x, y, qConvertRgb64ToRgb30<PixelOrder>(color), map, mapWidth, mapHeight, mapStride); } inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer, - int x, int y, quint32 color, + int x, int y, const QRgba64 &color, const uchar *map, int mapWidth, int mapHeight, int mapStride) { - qt_bitmapblit_template<quint16>(rasterBuffer, x, y, qConvertRgb32To16(color), + qt_bitmapblit_template<quint16>(rasterBuffer, x, y, color.toRgb16(), map, mapWidth, mapHeight, mapStride); } static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer, - int x, int y, quint32 color, + int x, int y, const QRgba64 &color, const uchar *map, int mapWidth, int mapHeight, int mapStride, const QClipData *) { - const quint16 c = qConvertRgb32To16(color); + const quint16 c = color.toRgb16(); quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x; const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16); @@ -6130,7 +5757,7 @@ static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, in } #endif -static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer, +static void qt_alphamapblit_uint32(QRasterBuffer *rasterBuffer, int x, int y, quint32 color, const uchar *map, int mapWidth, int mapHeight, int mapStride, @@ -6226,28 +5853,38 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer, } } + +static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer, + int x, int y, const QRgba64 &color, + const uchar *map, + int mapWidth, int mapHeight, int mapStride, + const QClipData *clip) +{ + qt_alphamapblit_uint32(rasterBuffer, x, y, color.toArgb32(), map, mapWidth, mapHeight, mapStride, clip); +} + #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN static void qt_alphamapblit_rgba8888(QRasterBuffer *rasterBuffer, - int x, int y, quint32 color, + int x, int y, const QRgba64 &color, const uchar *map, int mapWidth, int mapHeight, int mapStride, const QClipData *clip) { - qt_alphamapblit_argb32(rasterBuffer, x, y, ARGB2RGBA(color), map, mapWidth, mapHeight, mapStride, clip); + qt_alphamapblit_uint32(rasterBuffer, x, y, ARGB2RGBA(color.toArgb32()), map, mapWidth, mapHeight, mapStride, clip); } #endif static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer, - int x, int y, quint32 color, + int x, int y, const QRgba64 &color, const uint *src, int mapWidth, int mapHeight, int srcStride, const QClipData *clip) { - const quint32 c = color; + const quint32 c = color.toArgb32(); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - int sa = qAlpha(color); + int sr = qRed(c); + int sg = qGreen(c); + int sb = qBlue(c); + int sa = qAlpha(c); const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables(); if (!tables) @@ -6314,58 +5951,67 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer, static void qt_rectfill_argb32(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, - quint32 color) + const QRgba64 &color) { qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), - color, x, y, width, height, rasterBuffer->bytesPerLine()); + color.toArgb32(), x, y, width, height, rasterBuffer->bytesPerLine()); } static void qt_rectfill_quint16(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, - quint32 color) + const QRgba64 &color) { qt_rectfill<quint16>(reinterpret_cast<quint16 *>(rasterBuffer->buffer()), - qConvertRgb32To16(color), x, y, width, height, rasterBuffer->bytesPerLine()); + color.toRgb16(), x, y, width, height, rasterBuffer->bytesPerLine()); } static void qt_rectfill_nonpremul_argb32(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, - quint32 color) + const QRgba64 &color) { qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), - qUnpremultiply(color), x, y, width, height, rasterBuffer->bytesPerLine()); + color.unpremultiplied().toArgb32(), x, y, width, height, rasterBuffer->bytesPerLine()); } static void qt_rectfill_rgba(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, - quint32 color) + const QRgba64 &color) { qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), - ARGB2RGBA(color), x, y, width, height, rasterBuffer->bytesPerLine()); + ARGB2RGBA(color.toArgb32()), x, y, width, height, rasterBuffer->bytesPerLine()); } static void qt_rectfill_nonpremul_rgba(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, - quint32 color) + const QRgba64 &color) +{ + qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), + ARGB2RGBA(color.unpremultiplied().toArgb32()), x, y, width, height, rasterBuffer->bytesPerLine()); +} + +template<QtPixelOrder PixelOrder> +static void qt_rectfill_rgb30(QRasterBuffer *rasterBuffer, + int x, int y, int width, int height, + const QRgba64 &color) { qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), - ARGB2RGBA(qUnpremultiply(color)), x, y, width, height, rasterBuffer->bytesPerLine()); + qConvertRgb64ToRgb30<PixelOrder>(color), x, y, width, height, rasterBuffer->bytesPerLine()); } static void qt_rectfill_alpha(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, - quint32 color) + const QRgba64 &color) { qt_rectfill<quint8>(reinterpret_cast<quint8 *>(rasterBuffer->buffer()), - qAlpha(color), x, y, width, height, rasterBuffer->bytesPerLine()); + color.alpha() >> 8, x, y, width, height, rasterBuffer->bytesPerLine()); } static void qt_rectfill_gray(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, - quint32 color) + const QRgba64 &color) { qt_rectfill<quint8>(reinterpret_cast<quint8 *>(rasterBuffer->buffer()), - qGray(color), x, y, width, height, rasterBuffer->bytesPerLine()); + qGray(color.toArgb32()), x, y, width, height, rasterBuffer->bytesPerLine()); } // Map table for destination image format. Contains function pointers @@ -6518,39 +6164,39 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = }, // Format_BGR30 { - blend_color_generic, - blend_src_generic, - 0, + blend_color_generic_rgb64, + blend_src_generic_rgb64, + qt_bitmapblit_rgb30<PixelOrderBGR>, 0, 0, - 0 + qt_rectfill_rgb30<PixelOrderBGR> }, // Format_A2BGR30_Premultiplied { - blend_color_generic, - blend_src_generic, - 0, + blend_color_generic_rgb64, + blend_src_generic_rgb64, + qt_bitmapblit_rgb30<PixelOrderBGR>, 0, 0, - 0 + qt_rectfill_rgb30<PixelOrderBGR> }, // Format_RGB30 { - blend_color_generic, - blend_src_generic, - 0, + blend_color_generic_rgb64, + blend_src_generic_rgb64, + qt_bitmapblit_rgb30<PixelOrderRGB>, 0, 0, - 0 + qt_rectfill_rgb30<PixelOrderRGB> }, // Format_A2RGB30_Premultiplied { - blend_color_generic, - blend_src_generic, - 0, + blend_color_generic_rgb64, + blend_src_generic_rgb64, + qt_bitmapblit_rgb30<PixelOrderRGB>, 0, 0, - 0 + qt_rectfill_rgb30<PixelOrderRGB> }, // Format_Alpha8 { @@ -6619,6 +6265,11 @@ inline void qt_memfill_template(quint16 *dest, quint16 value, int count) } #endif +void qt_memfill64(quint64 *dest, quint64 color, int count) +{ + qt_memfill_template<quint64>(dest, color, count); +} + #if !defined(__SSE2__) void qt_memfill16(quint16 *dest, quint16 color, int count) { @@ -6642,9 +6293,6 @@ void qt_memfill32(quint32 *dest, quint32 color, int count) void qInitDrawhelperAsm() { - CompositionFunction *functionForModeAsm = 0; - CompositionFunctionSolid *functionForModeSolidAsm = 0; - const uint features = qCpuFeatures(); Q_UNUSED(features); #ifdef __SSE2__ @@ -6727,9 +6375,15 @@ void qInitDrawhelperAsm() qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_avx2; } #endif + extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha); + extern void QT_FASTCALL comp_func_Source_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_Plus_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_sse2; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_sse2; + qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_sse2; + qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2; - functionForModeAsm = qt_functionForMode_SSE2; - functionForModeSolidAsm = qt_functionForModeSolid_SSE2; #endif // SSE2 #if defined(__ARM_NEON__) && !defined(Q_OS_IOS) @@ -6755,9 +6409,9 @@ void qInitDrawhelperAsm() qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon; - functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon; - functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon; - functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon; + qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon; + qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon; destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon; destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon; @@ -6777,25 +6431,25 @@ void qInitDrawhelperAsm() #if defined(QT_COMPILER_SUPPORTS_MIPS_DSP) || defined(QT_COMPILER_SUPPORTS_MIPS_DSPR2) if (features & (DSP | DSPR2)) { // Composition functions are all DSP r1 - functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_asm_mips_dsp; - functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationOver] = comp_func_DestinationOver_mips_dsp; - functionForMode_C[QPainter::CompositionMode_SourceIn] = comp_func_SourceIn_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationIn] = comp_func_DestinationIn_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationOut] = comp_func_DestinationOut_mips_dsp; - functionForMode_C[QPainter::CompositionMode_SourceAtop] = comp_func_SourceAtop_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationAtop] = comp_func_DestinationAtop_mips_dsp; - functionForMode_C[QPainter::CompositionMode_Xor] = comp_func_XOR_mips_dsp; - functionForMode_C[QPainter::CompositionMode_SourceOut] = comp_func_SourceOut_mips_dsp; - - functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_DestinationOver] = comp_func_solid_DestinationOver_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_SourceIn] = comp_func_solid_SourceIn_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_DestinationIn] = comp_func_solid_DestinationIn_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_SourceAtop] = comp_func_solid_SourceAtop_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_DestinationAtop] = comp_func_solid_DestinationAtop_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_Xor] = comp_func_solid_XOR_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_SourceOut] = comp_func_solid_SourceOut_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_asm_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationOver] = comp_func_DestinationOver_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceIn] = comp_func_SourceIn_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationIn] = comp_func_DestinationIn_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationOut] = comp_func_DestinationOut_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceAtop] = comp_func_SourceAtop_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationAtop] = comp_func_DestinationAtop_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_Xor] = comp_func_XOR_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceOut] = comp_func_SourceOut_mips_dsp; + + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationOver] = comp_func_solid_DestinationOver_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceIn] = comp_func_solid_SourceIn_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationIn] = comp_func_solid_DestinationIn_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceAtop] = comp_func_solid_SourceAtop_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationAtop] = comp_func_solid_DestinationAtop_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_Xor] = comp_func_solid_XOR_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOut] = comp_func_solid_SourceOut_mips_dsp; qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp; @@ -6822,20 +6476,6 @@ void qInitDrawhelperAsm() #endif // QT_COMPILER_SUPPORTS_MIPS_DSPR2 } #endif // QT_COMPILER_SUPPORTS_MIPS_DSP || QT_COMPILER_SUPPORTS_MIPS_DSPR2 - - if (functionForModeSolidAsm) { - const int destinationMode = QPainter::CompositionMode_Destination; - functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode]; - - // use the default qdrawhelper implementation for the - // extended composition modes - for (int mode = 12; mode < 24; ++mode) - functionForModeSolidAsm[mode] = functionForModeSolid_C[mode]; - - functionForModeSolid = functionForModeSolidAsm; - } - if (functionForModeAsm) - functionForMode = functionForModeAsm; } QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 7e12e62151..08e564f017 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -466,7 +466,7 @@ void qt_blend_rgb32_on_rgb32_neon(uchar *destPixels, int dbpl, } void qt_alphamapblit_quint16_neon(QRasterBuffer *rasterBuffer, - int x, int y, quint32 color, + int x, int y, const QRgba64 &color, const uchar *bitmap, int mapWidth, int mapHeight, int mapStride, const QClipData *) @@ -475,8 +475,9 @@ void qt_alphamapblit_quint16_neon(QRasterBuffer *rasterBuffer, const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16); uchar *mask = const_cast<uchar *>(bitmap); + const uint c = color.toArgb32(); - pixman_composite_over_n_8_0565_asm_neon(mapWidth, mapHeight, dest, destStride, color, 0, mask, mapStride); + pixman_composite_over_n_8_0565_asm_neon(mapWidth, mapHeight, dest, destStride, c, 0, mask, mapStride); } extern "C" void blend_8_pixels_rgb16_on_rgb16_neon(quint16 *dst, const quint16 *src, int const_alpha); @@ -985,7 +986,7 @@ public: const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { - return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdNeon> >(buffer, op, data, y, x, length); + return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdNeon>,uint>(buffer, op, data, y, x, length); } QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper_neon_p.h b/src/gui/painting/qdrawhelper_neon_p.h index bd030a8bf3..37e060f147 100644 --- a/src/gui/painting/qdrawhelper_neon_p.h +++ b/src/gui/painting/qdrawhelper_neon_p.h @@ -82,7 +82,7 @@ void qt_blend_rgb16_on_rgb16_neon(uchar *destPixels, int dbpl, int const_alpha); void qt_alphamapblit_quint16_neon(QRasterBuffer *rasterBuffer, - int x, int y, quint32 color, + int x, int y, const QRgba64 &color, const uchar *bitmap, int mapWidth, int mapHeight, int mapStride, const QClipData *clip); diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 0d391b2cec..f8865a6f7e 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -50,6 +50,7 @@ #include "QtGui/qcolor.h" #include "QtGui/qpainter.h" #include "QtGui/qimage.h" +#include "QtGui/qrgba64.h" #ifndef QT_FT_BEGIN_HEADER #define QT_FT_BEGIN_HEADER #define QT_FT_END_HEADER @@ -99,25 +100,25 @@ class QRasterPaintEngineState; typedef QT_FT_SpanFunc ProcessSpans; typedef void (*BitmapBlitFunc)(QRasterBuffer *rasterBuffer, - int x, int y, quint32 color, + int x, int y, const QRgba64 &color, const uchar *bitmap, int mapWidth, int mapHeight, int mapStride); typedef void (*AlphamapBlitFunc)(QRasterBuffer *rasterBuffer, - int x, int y, quint32 color, + int x, int y, const QRgba64 &color, const uchar *bitmap, int mapWidth, int mapHeight, int mapStride, const QClipData *clip); typedef void (*AlphaRGBBlitFunc)(QRasterBuffer *rasterBuffer, - int x, int y, quint32 color, + int x, int y, const QRgba64 &color, const uint *rgbmask, int mapWidth, int mapHeight, int mapStride, const QClipData *clip); typedef void (*RectFillFunc)(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, - quint32 color); + const QRgba64 &color); typedef void (*SrcOverBlendFunc)(uchar *destPixels, int dbpl, const uchar *src, int spbl, @@ -158,11 +159,14 @@ extern MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3]; extern DrawHelper qDrawHelper[QImage::NImageFormats]; void qBlendTexture(int count, const QSpan *spans, void *userData); +extern void qt_memfill64(quint64 *dest, quint64 value, int count); extern void qt_memfill32(quint32 *dest, quint32 value, int count); extern void qt_memfill16(quint16 *dest, quint16 value, int count); typedef void (QT_FASTCALL *CompositionFunction)(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha); +typedef void (QT_FASTCALL *CompositionFunction64)(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha); typedef void (QT_FASTCALL *CompositionFunctionSolid)(uint *dest, int length, uint color, uint const_alpha); +typedef void (QT_FASTCALL *CompositionFunctionSolid64)(QRgba64 *dest, int length, QRgba64 color, uint const_alpha); struct LinearGradientValues { @@ -185,17 +189,27 @@ struct RadialGradientValues struct Operator; typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length); +typedef QRgba64* (QT_FASTCALL *DestFetchProc64)(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length); typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length); +typedef void (QT_FASTCALL *DestStoreProc64)(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length); typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length); +typedef const QRgba64* (QT_FASTCALL *SourceFetchProc64)(QRgba64 *buffer, const Operator *o, const QSpanData *data, int y, int x, int length); struct Operator { QPainter::CompositionMode mode; - DestFetchProc dest_fetch; - DestStoreProc dest_store; - SourceFetchProc src_fetch; + DestFetchProc destFetch; + DestStoreProc destStore; + SourceFetchProc srcFetch; CompositionFunctionSolid funcSolid; CompositionFunction func; + + DestFetchProc64 destFetch64; + DestStoreProc64 destStore64; + SourceFetchProc64 srcFetch64; + CompositionFunctionSolid64 funcSolid64; + CompositionFunction64 func64; + union { LinearGradientValues linear; RadialGradientValues radial; @@ -208,7 +222,7 @@ class QRasterPaintEngine; struct QSolidData { - uint color; + QRgba64 color; }; struct QLinearGradientData @@ -259,7 +273,7 @@ struct QGradientData #define GRADIENT_STOPTABLE_SIZE 1024 #define GRADIENT_STOPTABLE_SIZE_SHIFT 10 - uint* colorTable; //[GRADIENT_STOPTABLE_SIZE]; + QRgba64* colorTable; //[GRADIENT_STOPTABLE_SIZE]; uint alphaColor : 1; }; @@ -367,6 +381,12 @@ static inline uint qt_gradient_clamp(const QGradientData *data, int ipos) static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos) { int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5)); + return data->colorTable[qt_gradient_clamp(data, ipos)].toArgb32(); +} + +static inline const QRgba64& qt_gradient_pixel64(const QGradientData *data, qreal pos) +{ + int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5)); return data->colorTable[qt_gradient_clamp(data, ipos)]; } @@ -375,24 +395,24 @@ static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c) return (b * b) - (4 * a * c); } -template <class RadialFetchFunc> Q_STATIC_TEMPLATE_FUNCTION -const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +template <class RadialFetchFunc, typename BlendType> static +const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffer, const Operator *op, + const QSpanData *data, int y, int x, int length) { // avoid division by zero if (qFuzzyIsNull(op->radial.a)) { - qt_memfill32(buffer, 0, length); + RadialFetchFunc::memfill(buffer, RadialFetchFunc::null(), length); return buffer; } - const uint *b = buffer; + const BlendType *b = buffer; qreal rx = data->m21 * (y + qreal(0.5)) + data->dx + data->m11 * (x + qreal(0.5)); qreal ry = data->m22 * (y + qreal(0.5)) + data->dy + data->m12 * (x + qreal(0.5)); bool affine = !data->m13 && !data->m23; - uint *end = buffer + length; + BlendType *end = buffer + length; if (affine) { rx -= data->gradient.radial.focal.x; ry -= data->gradient.radial.focal.y; @@ -439,7 +459,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + gx*op->radial.dx + gy*op->radial.dy); qreal det = qRadialDeterminant(op->radial.a, b, op->radial.sqrfr - (gx*gx + gy*gy)); - quint32 result = 0; + BlendType result = RadialFetchFunc::null(); if (det >= 0) { qreal detSqrt = qSqrt(det); @@ -449,7 +469,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O qreal s = qMax(s0, s1); if (data->gradient.radial.focal.radius + op->radial.dr * s >= 0) - result = qt_gradient_pixel(&data->gradient, s); + result = RadialFetchFunc::fetchSingle(data->gradient, s); } *buffer = result; @@ -470,6 +490,15 @@ template <class Simd> class QRadialFetchSimd { public: + static uint null() { return 0; } + static uint fetchSingle(const QGradientData& gradient, qreal v) + { + return qt_gradient_pixel(&gradient, v); + } + static void memfill(uint *buffer, uint fill, int length) + { + qt_memfill32(buffer, fill, length); + } 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) { @@ -526,7 +555,7 @@ public: delta_det4_vec.v = Simd::v_add(delta_det4_vec.v, v_delta_delta_det16); \ b_vec.v = Simd::v_add(b_vec.v, v_delta_b4); \ for (int i = 0; i < 4; ++i) \ - *buffer++ = (extended_mask | v_buffer_mask.i[i]) & data->gradient.colorTable[index_vec.i[i]]; \ + *buffer++ = (extended_mask | v_buffer_mask.i[i]) & data->gradient.colorTable[index_vec.i[i]].toArgb32(); \ } #define FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP) \ @@ -680,7 +709,8 @@ static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16_32(uint x, uint a) { return t; } -static Q_ALWAYS_INLINE int qt_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; } +static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE int qt_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; } +static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_div_65535(uint x) { return (x + (x>>16) + 0x8000U) >> 16; } static Q_ALWAYS_INLINE uint BYTE_MUL_RGB30(uint x, uint a) { uint xa = x >> 30; @@ -723,6 +753,11 @@ inline quint24::operator uint() const template <class T> Q_STATIC_TEMPLATE_FUNCTION void qt_memfill(T *dest, T value, int count); +template<> inline void qt_memfill(quint64 *dest, quint64 color, int count) +{ + qt_memfill64(dest, color, count); +} + template<> inline void qt_memfill(quint32 *dest, quint32 color, int count) { qt_memfill32(dest, color, count); @@ -907,6 +942,64 @@ inline QRgb qConvertA2rgb30ToArgb32<PixelOrderRGB>(uint c) | ((c >> 2) & 0x000000ff); } +template<enum QtPixelOrder> inline QRgba64 qConvertA2rgb30ToRgb64(uint rgb); + +template<> +inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderBGR>(uint rgb) +{ + quint16 alpha = rgb >> 30; + quint16 blue = (rgb >> 20) & 0x3ff; + quint16 green = (rgb >> 10) & 0x3ff; + quint16 red = rgb & 0x3ff; + // Expand the range. + alpha |= (alpha << 2); + alpha |= (alpha << 4); + alpha |= (alpha << 8); + red = (red << 6) | (red >> 4); + green = (green << 6) | (green >> 4); + blue = (blue << 6) | (blue >> 4); + return qRgba64(red, green, blue, alpha); +} + +template<> +inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderRGB>(uint rgb) +{ + quint16 alpha = rgb >> 30; + quint16 red = (rgb >> 20) & 0x3ff; + quint16 green = (rgb >> 10) & 0x3ff; + quint16 blue = rgb & 0x3ff; + // Expand the range. + alpha |= (alpha << 2); + alpha |= (alpha << 4); + alpha |= (alpha << 8); + red = (red << 6) | (red >> 4); + green = (green << 6) | (green >> 4); + blue = (blue << 6) | (blue >> 4); + return qRgba64(red, green, blue, alpha); +} + +template<enum QtPixelOrder> inline unsigned int qConvertRgb64ToRgb30(QRgba64); + +template<> +inline unsigned int qConvertRgb64ToRgb30<PixelOrderBGR>(QRgba64 c) +{ + const uint a = c.alpha() >> 14; + const uint r = c.red() >> 6; + const uint g = c.green() >> 6; + const uint b = c.blue() >> 6; + return (a << 30) | (b << 20) | (g << 10) | r; +} + +template<> +inline unsigned int qConvertRgb64ToRgb30<PixelOrderRGB>(QRgba64 c) +{ + const uint a = c.alpha() >> 14; + const uint r = c.red() >> 6; + const uint g = c.green() >> 6; + const uint b = c.blue() >> 6; + return (a << 30) | (r << 20) | (g << 10) | b; +} + inline uint qRgbSwapRgb30(uint c) { const uint ag = c & 0xc00ffc00; @@ -1008,89 +1101,11 @@ inline int comp_func_Plus_one_pixel(uint d, const uint s) #undef MIX #undef AMIX -// prototypes of all the composition functions -void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha); -void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint); -void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Plus(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Multiply(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Overlay(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Darken(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Lighten(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_ColorDodge(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_ColorBurn(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_HardLight(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_SoftLight(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Difference(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceOrDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceAndDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceXorDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceXorDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSource(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceAndDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceAndNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceOrDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceOrNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_ClearDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SetDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotDestination(uint *dest, const uint *src, int length, uint const_alpha); -// prototypes of all the solid composition functions -void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Destination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_DestinationIn(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); -void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceOrDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceOrNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_ClearDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SetDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotDestination(uint *dest, int length, uint color, uint const_alpha); - - struct QPixelLayout; typedef const uint *(QT_FASTCALL *ConvertFunc)(uint *buffer, const uint *src, int count, const QPixelLayout *layout, const QRgb *clut); +typedef const QRgba64 *(QT_FASTCALL *ConvertFunc64)(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *layout, const QRgb *clut); struct QPixelLayout { @@ -1120,6 +1135,7 @@ struct QPixelLayout ConvertFunc convertToARGB32PM; ConvertFunc convertFromARGB32PM; ConvertFunc convertFromRGB32; + ConvertFunc64 convertToARGB64PM; }; typedef const uint *(QT_FASTCALL *FetchPixelsFunc)(uint *buffer, const uchar *src, int index, int count); diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index 84eb3b7909..d7f3686e54 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -311,90 +311,6 @@ void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, u } } -#ifndef QDRAWHELPER_AVX -CompositionFunctionSolid qt_functionForModeSolid_SSE2[numCompositionFunctions] = { - comp_func_solid_SourceOver_sse2, - comp_func_solid_DestinationOver, - comp_func_solid_Clear, - comp_func_solid_Source, - comp_func_solid_Destination, - comp_func_solid_SourceIn, - comp_func_solid_DestinationIn, - comp_func_solid_SourceOut, - comp_func_solid_DestinationOut, - comp_func_solid_SourceAtop, - comp_func_solid_DestinationAtop, - comp_func_solid_XOR, - comp_func_solid_Plus, - comp_func_solid_Multiply, - comp_func_solid_Screen, - comp_func_solid_Overlay, - comp_func_solid_Darken, - comp_func_solid_Lighten, - comp_func_solid_ColorDodge, - comp_func_solid_ColorBurn, - comp_func_solid_HardLight, - comp_func_solid_SoftLight, - comp_func_solid_Difference, - comp_func_solid_Exclusion, - rasterop_solid_SourceOrDestination, - rasterop_solid_SourceAndDestination, - rasterop_solid_SourceXorDestination, - rasterop_solid_NotSourceAndNotDestination, - rasterop_solid_NotSourceOrNotDestination, - rasterop_solid_NotSourceXorDestination, - rasterop_solid_NotSource, - rasterop_solid_NotSourceAndDestination, - rasterop_solid_SourceAndNotDestination, - rasterop_solid_NotSourceOrDestination, - rasterop_solid_SourceOrNotDestination, - rasterop_solid_ClearDestination, - rasterop_solid_SetDestination, - rasterop_solid_NotDestination -}; - -CompositionFunction qt_functionForMode_SSE2[numCompositionFunctions] = { - comp_func_SourceOver_sse2, - comp_func_DestinationOver, - comp_func_Clear, - comp_func_Source_sse2, - comp_func_Destination, - comp_func_SourceIn, - comp_func_DestinationIn, - comp_func_SourceOut, - comp_func_DestinationOut, - comp_func_SourceAtop, - comp_func_DestinationAtop, - comp_func_XOR, - comp_func_Plus_sse2, - comp_func_Multiply, - comp_func_Screen, - comp_func_Overlay, - comp_func_Darken, - comp_func_Lighten, - comp_func_ColorDodge, - comp_func_ColorBurn, - comp_func_HardLight, - comp_func_SoftLight, - comp_func_Difference, - comp_func_Exclusion, - rasterop_SourceOrDestination, - rasterop_SourceAndDestination, - rasterop_SourceXorDestination, - rasterop_NotSourceAndNotDestination, - rasterop_NotSourceOrNotDestination, - rasterop_NotSourceXorDestination, - rasterop_NotSource, - rasterop_NotSourceAndDestination, - rasterop_SourceAndNotDestination, - rasterop_NotSourceOrDestination, - rasterop_SourceOrNotDestination, - rasterop_ClearDestination, - rasterop_SetDestination, - rasterop_NotDestination -}; -#endif - void qt_memfill16(quint16 *dest, quint16 value, int count) { if (count < 3) { @@ -417,7 +333,7 @@ void qt_memfill16(quint16 *dest, quint16 value, int count) dest[count - 1] = value; } -void qt_bitmapblit32_sse2(QRasterBuffer *rasterBuffer, int x, int y, +void qt_bitmapblit32_sse2_base(QRasterBuffer *rasterBuffer, int x, int y, quint32 color, const uchar *src, int width, int height, int stride) { @@ -468,18 +384,25 @@ void qt_bitmapblit32_sse2(QRasterBuffer *rasterBuffer, int x, int y, } } +void qt_bitmapblit32_sse2(QRasterBuffer *rasterBuffer, int x, int y, + const QRgba64 &color, + const uchar *src, int width, int height, int stride) +{ + qt_bitmapblit32_sse2_base(rasterBuffer, x, y, color.toArgb32(), src, width, height, stride); +} + void qt_bitmapblit8888_sse2(QRasterBuffer *rasterBuffer, int x, int y, - quint32 color, + const QRgba64 &color, const uchar *src, int width, int height, int stride) { - qt_bitmapblit32_sse2(rasterBuffer, x, y, ARGB2RGBA(color), src, width, height, stride); + qt_bitmapblit32_sse2_base(rasterBuffer, x, y, ARGB2RGBA(color.toArgb32()), src, width, height, stride); } void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y, - quint32 color, + const QRgba64 &color, const uchar *src, int width, int height, int stride) { - const quint16 c = qConvertRgb32To16(color); + const quint16 c = qConvertRgb32To16(color.toArgb32()); quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x; const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16); @@ -543,7 +466,7 @@ public: const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { - return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdSse2> >(buffer, op, data, y, x, length); + return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdSse2>,uint>(buffer, op, data, y, x, length); } void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, diff --git a/src/gui/painting/qdrawhelper_x86_p.h b/src/gui/painting/qdrawhelper_x86_p.h index 4d203c4f9d..50ee83aa2c 100644 --- a/src/gui/painting/qdrawhelper_x86_p.h +++ b/src/gui/painting/qdrawhelper_x86_p.h @@ -53,13 +53,13 @@ QT_BEGIN_NAMESPACE void qt_memfill32(quint32 *dest, quint32 value, int count); void qt_memfill16(quint16 *dest, quint16 value, int count); void qt_bitmapblit32_sse2(QRasterBuffer *rasterBuffer, int x, int y, - quint32 color, + const QRgba64 &color, const uchar *src, int width, int height, int stride); void qt_bitmapblit8888_sse2(QRasterBuffer *rasterBuffer, int x, int y, - quint32 color, + const QRgba64 &color, const uchar *src, int width, int height, int stride); void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y, - quint32 color, + const QRgba64 &color, const uchar *src, int width, int height, int stride); void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, diff --git a/src/gui/painting/qmatrix.cpp b/src/gui/painting/qmatrix.cpp index acedc6a7ba..e4d756c18d 100644 --- a/src/gui/painting/qmatrix.cpp +++ b/src/gui/painting/qmatrix.cpp @@ -31,9 +31,11 @@ ** ****************************************************************************/ +#include "qmatrix.h" + #include "qdatastream.h" #include "qdebug.h" -#include "qmatrix.h" +#include "qhashfunctions.h" #include "qregion.h" #include "qpainterpath.h" #include "qpainterpath_p.h" @@ -972,6 +974,26 @@ bool QMatrix::operator==(const QMatrix &m) const _dy == m._dy; } + +/*! + \since 5.6 + \relates QMatrix + + Returns the hash value for \a key, using + \a seed to seed the calculation. +*/ +uint qHash(const QMatrix &key, uint seed) Q_DECL_NOTHROW +{ + QtPrivate::QHashCombine hash; + seed = hash(key.m11(), seed); + seed = hash(key.m12(), seed); + seed = hash(key.m21(), seed); + seed = hash(key.m22(), seed); + seed = hash(key.dx(), seed); + seed = hash(key.dy(), seed); + return seed; +} + /*! \fn bool QMatrix::operator!=(const QMatrix &matrix) const diff --git a/src/gui/painting/qmatrix.h b/src/gui/painting/qmatrix.h index ddffa8a8b9..c036e4df93 100644 --- a/src/gui/painting/qmatrix.h +++ b/src/gui/painting/qmatrix.h @@ -126,6 +126,8 @@ private: }; Q_DECLARE_TYPEINFO(QMatrix, Q_MOVABLE_TYPE); +Q_GUI_EXPORT Q_DECL_CONST_FUNCTION uint qHash(const QMatrix &key, uint seed = 0) Q_DECL_NOTHROW; + // mathematical semantics inline QPoint operator*(const QPoint &p, const QMatrix &m) { return m.map(p); } diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 18522cb6d0..882a088d5c 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -42,7 +42,6 @@ #include <qpainterpath.h> #include <qdebug.h> -#include <qhash.h> #include <qbitmap.h> #include <qmath.h> @@ -57,6 +56,7 @@ #include <private/qstatictext_p.h> #include <private/qcosmeticstroker_p.h> #include "qmemrotate_p.h" +#include "qrgba64_p.h" #include "qpaintengine_raster_p.h" // #include "qbezier_p.h" @@ -830,7 +830,7 @@ void QRasterPaintEngine::updateRasterState() && s->intOpacity == 256 && (mode == QPainter::CompositionMode_Source || (mode == QPainter::CompositionMode_SourceOver - && qAlpha(s->penData.solid.color) == 255)); + && s->penData.solid.color.isOpaque())); } s->dirty = 0; @@ -1412,10 +1412,9 @@ static void fillRect_normalized(const QRect &r, QSpanData *data, if (data->fillRect && (mode == QPainter::CompositionMode_Source || (mode == QPainter::CompositionMode_SourceOver - && qAlpha(data->solid.color) == 255))) + && data->solid.color.isOpaque()))) { - data->fillRect(data->rasterBuffer, x1, y1, width, height, - data->solid.color); + data->fillRect(data->rasterBuffer, x1, y1, width, height, data->solid.color); return; } } @@ -1773,8 +1772,9 @@ void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color) Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); - d->solid_color_filler.solid.color = qPremultiply(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity)); - if ((d->solid_color_filler.solid.color & 0xff000000) == 0 + d->solid_color_filler.solid.color = qPremultiply(combineAlpha256(color.rgba64(), s->intOpacity)); + + if (d->solid_color_filler.solid.color.isTransparent() && s->composition_mode == QPainter::CompositionMode_SourceOver) { return; } @@ -2219,19 +2219,15 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe case QImage::Format_A2BGR30_Premultiplied: case QImage::Format_A2RGB30_Premultiplied: // Combine premultiplied color with the opacity set on the painter. - d->solid_color_filler.solid.color = - ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff) - | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00); + d->solid_color_filler.solid.color = multiplyAlpha256(QRgba64::fromArgb32(color), s->intOpacity); break; default: - d->solid_color_filler.solid.color = qPremultiply(ARGB_COMBINE_ALPHA(color, s->intOpacity)); + d->solid_color_filler.solid.color = qPremultiply(combineAlpha256(QRgba64::fromArgb32(color), s->intOpacity)); break; } - if ((d->solid_color_filler.solid.color & 0xff000000) == 0 - && s->composition_mode == QPainter::CompositionMode_SourceOver) { + if (d->solid_color_filler.solid.color.isTransparent() && s->composition_mode == QPainter::CompositionMode_SourceOver) return; - } d->solid_color_filler.clip = d->clip(); d->solid_color_filler.adjustSpanMethods(); @@ -4137,7 +4133,7 @@ class QGradientCache { inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) : stops(s), opacity(op), interpolationMode(mode) {} - uint buffer[GRADIENT_STOPTABLE_SIZE]; + QRgba64 buffer[GRADIENT_STOPTABLE_SIZE]; QGradientStops stops; int opacity; QGradient::InterpolationMode interpolationMode; @@ -4146,12 +4142,12 @@ class QGradientCache typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash; public: - inline const uint *getBuffer(const QGradient &gradient, int opacity) { + inline const QRgba64 *getBuffer(const QGradient &gradient, int opacity) { quint64 hash_val = 0; QGradientStops stops = gradient.stops(); for (int i = 0; i < stops.size() && i <= 2; i++) - hash_val += stops[i].second.rgba(); + hash_val += stops[i].second.rgba64(); QMutexLocker lock(&mutex); QGradientColorTableHash::const_iterator it = cache.constFind(hash_val); @@ -4174,9 +4170,9 @@ public: protected: inline int maxCacheSize() const { return 60; } inline void generateGradientColorTable(const QGradient& g, - uint *colorTable, + QRgba64 *colorTable, int size, int opacity) const; - uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) { + QRgba64 *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) { if (cache.size() == maxCacheSize()) { // may remove more than 1, but OK cache.erase(cache.begin() + (qrand() % maxCacheSize())); @@ -4190,7 +4186,7 @@ protected: QMutex mutex; }; -void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const +void QGradientCache::generateGradientColorTable(const QGradient& gradient, QRgba64 *colorTable, int size, int opacity) const { QGradientStops stops = gradient.stops(); int stopCount = stops.count(); @@ -4199,14 +4195,16 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); if (stopCount == 2) { - uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity); - uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity); + QRgba64 first_color = combineAlpha256(stops[0].second.rgba64(), opacity); + QRgba64 second_color = combineAlpha256(stops[1].second.rgba64(), opacity); qreal first_stop = stops[0].first; qreal second_stop = stops[1].first; if (second_stop < first_stop) { - qSwap(first_color, second_color); + quint64 tmp = first_color; + first_color = second_color; + second_color = tmp; qSwap(first_stop, second_stop); } @@ -4218,15 +4216,15 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1)); int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1)); - uint red_first = qRed(first_color) << 16; - uint green_first = qGreen(first_color) << 16; - uint blue_first = qBlue(first_color) << 16; - uint alpha_first = qAlpha(first_color) << 16; + uint red_first = uint(first_color.red()) << 16; + uint green_first = uint(first_color.green()) << 16; + uint blue_first = uint(first_color.blue()) << 16; + uint alpha_first = uint(first_color.alpha()) << 16; - uint red_second = qRed(second_color) << 16; - uint green_second = qGreen(second_color) << 16; - uint blue_second = qBlue(second_color) << 16; - uint alpha_second = qAlpha(second_color) << 16; + uint red_second = uint(second_color.red()) << 16; + uint green_second = uint(second_color.green()) << 16; + uint blue_second = uint(second_color.blue()) << 16; + uint alpha_second = uint(second_color.alpha()) << 16; int i = 0; for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) { @@ -4239,10 +4237,10 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (i < second_index) { qreal reciprocal = qreal(1) / (second_index - first_index); - int red_delta = qRound(int(red_second - red_first) * reciprocal); - int green_delta = qRound(int(green_second - green_first) * reciprocal); - int blue_delta = qRound(int(blue_second - blue_first) * reciprocal); - int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal); + int red_delta = qRound((qreal(red_second) - red_first) * reciprocal); + int green_delta = qRound((qreal(green_second) - green_first) * reciprocal); + int blue_delta = qRound((qreal(blue_second) - blue_first) * reciprocal); + int alpha_delta = qRound((qreal(alpha_second) - alpha_first) * reciprocal); // rounding red_first += 1 << 15; @@ -4256,8 +4254,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint blue_first += blue_delta; alpha_first += alpha_delta; - const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000) - | ((green_first >> 8) & 0xff00) | (blue_first >> 16); + const QRgba64 color = qRgba64(red_first >> 16, green_first >> 16, blue_first >> 16, alpha_first >> 16); if (colorInterpolation) colorTable[i] = color; @@ -4276,7 +4273,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint return; } - uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity); + QRgba64 current_color = combineAlpha256(stops[0].second.rgba64(), opacity); if (stopCount == 1) { current_color = qPremultiply(current_color); for (int i = 0; i < size; ++i) @@ -4289,7 +4286,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint qreal end_pos = stops[stopCount-1].first; int pos = 0; // The position in the color table. - uint next_color; + QRgba64 next_color; qreal incr = 1 / qreal(size); // the double increment. qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1) @@ -4313,8 +4310,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint ++current_stop; if (current_stop != 0) - current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity); - next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity); + current_color = combineAlpha256(stops[current_stop].second.rgba64(), opacity); + next_color = combineAlpha256(stops[current_stop+1].second.rgba64(), opacity); if (colorInterpolation) { current_color = qPremultiply(current_color); @@ -4333,9 +4330,9 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint int idist = 256 - dist; if (colorInterpolation) - colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist); + colorTable[pos] = interpolate256(current_color, idist, next_color, dist); else - colorTable[pos] = qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); + colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist)); ++pos; dpos += incr; @@ -4354,8 +4351,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (skip == 1) current_color = next_color; else - current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity); - next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity); + current_color = combineAlpha256(stops[current_stop].second.rgba64(), opacity); + next_color = combineAlpha256(stops[current_stop+1].second.rgba64(), opacity); if (colorInterpolation) { if (skip != 1) @@ -4372,7 +4369,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint } // After last point - current_color = qPremultiply(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity)); + current_color = qPremultiply(combineAlpha256(stops[stopCount - 1].second.rgba64(), opacity)); while (pos < size - 1) { colorTable[pos] = current_color; ++pos; @@ -4405,12 +4402,9 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode case Qt::SolidPattern: { type = Solid; QColor c = qbrush_color(brush); - QRgb rgba = c.rgba(); - solid.color = qPremultiply(ARGB_COMBINE_ALPHA(rgba, alpha)); - if ((solid.color & 0xff000000) == 0 - && compositionMode == QPainter::CompositionMode_SourceOver) { + solid.color = qPremultiply(combineAlpha256(c.rgba64(), alpha)); + if (solid.color.isTransparent() && compositionMode == QPainter::CompositionMode_SourceOver) type = None; - } break; } @@ -4419,7 +4413,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode type = LinearGradient; const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient()); gradient.alphaColor = !brush.isOpaque() || alpha != 256; - gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha)); + gradient.colorTable = const_cast<QRgba64*>(qt_gradient_cache()->getBuffer(*g, alpha)); gradient.spread = g->spread(); QLinearGradientData &linearData = gradient.linear; @@ -4436,7 +4430,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode type = RadialGradient; const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient()); gradient.alphaColor = !brush.isOpaque() || alpha != 256; - gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha)); + gradient.colorTable = const_cast<QRgba64*>(qt_gradient_cache()->getBuffer(*g, alpha)); gradient.spread = g->spread(); QRadialGradientData &radialData = gradient.radial; @@ -4457,7 +4451,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode type = ConicalGradient; const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient()); gradient.alphaColor = !brush.isOpaque() || alpha != 256; - gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha)); + gradient.colorTable = const_cast<QRgba64*>(qt_gradient_cache()->getBuffer(*g, alpha)); gradient.spread = QGradient::RepeatSpread; QConicalGradientData &conicalData = gradient.conical; diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 7c32dc1694..3ea4e35b8d 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -53,7 +53,6 @@ #include "QtGui/qpainter.h" #include "QtGui/qpainterpath.h" #include "QtGui/qpaintengine.h" -#include <QtCore/qhash.h> #include <private/qpen_p.h> diff --git a/src/gui/painting/qrgba64.h b/src/gui/painting/qrgba64.h new file mode 100644 index 0000000000..51ce4ab10d --- /dev/null +++ b/src/gui/painting/qrgba64.h @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRGBA64_H +#define QRGBA64_H + +#include <QtCore/qglobal.h> +#include <QtCore/qprocessordetection.h> + +QT_BEGIN_NAMESPACE + +class QRgba64 { + union { + struct { + quint16 red; + quint16 green; + quint16 blue; + quint16 alpha; + } c; + quint64 rgba; + }; +public: + // No constructors are allowed, since this needs to be usable in a union in no-c++11 mode. + // When c++11 is mandatory, we can add all but a copy constructor. + Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha) + { + QRgba64 rgba64 +#ifdef Q_COMPILER_UNIFORM_INIT + = {} +#endif + ; + + rgba64.c.red = red; + rgba64.c.green = green; + rgba64.c.blue = blue; + rgba64.c.alpha = alpha; + return rgba64; + } + Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromRgba64(quint64 c) + { + QRgba64 rgba64 +#ifdef Q_COMPILER_UNIFORM_INIT + = {} +#endif + ; + rgba64.rgba = c; + return rgba64; + } + Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha) + { + QRgba64 rgb64 = fromRgba64(red, green, blue, alpha); + // Expand the range so that 0x00 maps to 0x0000 and 0xff maps to 0xffff. + rgb64.rgba |= rgb64.rgba << 8; + return rgb64; + } + Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromArgb32(uint rgb) + { + return fromRgba(rgb >> 16, rgb >> 8, rgb, rgb >> 24); + } + + Q_DECL_CONSTEXPR bool isOpaque() const { return c.alpha == 0xffff; } + Q_DECL_CONSTEXPR bool isTransparent() const { return c.alpha == 0; } + + Q_DECL_CONSTEXPR quint16 red() const { return c.red; } + Q_DECL_CONSTEXPR quint16 green() const { return c.green; } + Q_DECL_CONSTEXPR quint16 blue() const { return c.blue; } + Q_DECL_CONSTEXPR quint16 alpha() const { return c.alpha; } + void setRed(quint16 _red) { c.red = _red; } + void setGreen(quint16 _green) { c.green = _green; } + void setBlue(quint16 _blue) { c.blue = _blue; } + void setAlpha(quint16 _alpha) { c.alpha = _alpha; } + + Q_DECL_CONSTEXPR quint8 red8() const { return div_257(c.red); } + Q_DECL_CONSTEXPR quint8 green8() const { return div_257(c.green); } + Q_DECL_CONSTEXPR quint8 blue8() const { return div_257(c.blue); } + Q_DECL_CONSTEXPR quint8 alpha8() const { return div_257(c.alpha); } + Q_DECL_CONSTEXPR uint toArgb32() const + { + return (alpha8() << 24) | (red8() << 16) | (green8() << 8) | blue8(); + } + Q_DECL_CONSTEXPR ushort toRgb16() const + { + return (c.red & 0xf800) | ((c.green >> 10) << 5) | (c.blue >> 11); + } + + Q_DECL_RELAXED_CONSTEXPR QRgba64 premultiplied() const + { + const quint32 a = c.alpha; + const quint16 r = div_65535(c.red * a); + const quint16 g = div_65535(c.green * a); + const quint16 b = div_65535(c.blue * a); + return fromRgba64(r, g, b, a); + } + + Q_DECL_RELAXED_CONSTEXPR QRgba64 unpremultiplied() const + { +#if Q_PROCESSOR_WORDSIZE < 8 + return unpremultiplied_32bit(); +#else + return unpremultiplied_64bit(); +#endif + } + + Q_DECL_CONSTEXPR operator quint64() const + { + return rgba; + } + + QRgba64 operator=(quint64 _rgba) + { + rgba = _rgba; + return *this; + } + +private: + static Q_DECL_CONSTEXPR uint div_257_floor(uint x) { return (x - (x >> 8)) >> 8; } + static Q_DECL_CONSTEXPR uint div_257(uint x) { return div_257_floor(x + 128); } + static Q_DECL_CONSTEXPR uint div_65535(uint x) { return (x + (x>>16) + 0x8000U) >> 16; } + Q_DECL_RELAXED_CONSTEXPR QRgba64 unpremultiplied_32bit() const + { + if (c.alpha == 0xffff || c.alpha == 0) + return *this; + const quint16 r = (quint32(c.red) * 0xffff + c.alpha/2) / c.alpha; + const quint16 g = (quint32(c.green) * 0xffff + c.alpha/2) / c.alpha; + const quint16 b = (quint32(c.blue) * 0xffff + c.alpha/2) / c.alpha; + return fromRgba64(r, g, b, c.alpha); + } + Q_DECL_RELAXED_CONSTEXPR QRgba64 unpremultiplied_64bit() const + { + if (c.alpha == 0xffff || c.alpha == 0) + return *this; + const quint64 fa = (Q_UINT64_C(0xffff00008000) + c.alpha/2) / c.alpha; + const quint16 r = (c.red * fa + 0x80000000) >> 32; + const quint16 g = (c.green * fa + 0x80000000) >> 32; + const quint16 b = (c.blue * fa + 0x80000000) >> 32; + return fromRgba64(r, g, b, c.alpha); + } +}; + +Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a) +{ + return QRgba64::fromRgba64(r, g, b, a); +} + +Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qRgba64(quint64 c) +{ + return QRgba64::fromRgba64(c); +} + +Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qPremultiply(QRgba64 c) +{ + return c.premultiplied(); +} + +Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qUnpremultiply(QRgba64 c) +{ + return c.unpremultiplied(); +} + +inline Q_DECL_CONSTEXPR uint qRed(QRgba64 rgb) +{ return rgb.red8(); } + +inline Q_DECL_CONSTEXPR uint qGreen(QRgba64 rgb) +{ return rgb.green8(); } + +inline Q_DECL_CONSTEXPR uint qBlue(QRgba64 rgb) +{ return rgb.blue8(); } + +inline Q_DECL_CONSTEXPR uint qAlpha(QRgba64 rgb) +{ return rgb.alpha8(); } + +QT_END_NAMESPACE + +#endif // QRGBA64_H diff --git a/src/gui/painting/qrgba64.qdoc b/src/gui/painting/qrgba64.qdoc new file mode 100644 index 0000000000..29da0aa390 --- /dev/null +++ b/src/gui/painting/qrgba64.qdoc @@ -0,0 +1,241 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QRgba64 + \brief The QRgba64 struct contains a 64-bit RGB color. + \since 5.6 + + \ingroup painting + \inmodule QtGui + + QRgba64 is a 64-bit data-structure containing four 16-bit color channels: Red, green, blue and alpha. + + QRgba64 can be used a replacement for QRgb when higher precision is needed. In particular a + premultiplied QRgba64 can operate on unpremultipled QRgb without loss of precision except + for alpha 0. + + \sa QRgb, QColor +*/ + +/*! + \fn static QRgba64 QRgba64::fromRgba64(quint16 r, quint16 g, quint16 b, quint16 a) + + Returns the QRgba64 quadruplet (\a{r}, \a{g}, \a{b}, \a{a}). + + \sa fromRgba() +*/ + +/*! + \fn static QRgba64 QRgba64::fromRgba64(quint64 c) + + Returns \a c as a QRgba64 struct. + + \sa fromArgb32() +*/ + +/*! + \fn static QRgba64 QRgba64::fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha) + + Constructs a QRgba64 value from the four 8-bit color channels \a red, \a green, \a blue and \a alpha. + + \sa fromArgb32() +*/ + +/*! + \fn static QRgba64 QRgba64::fromArgb32(uint rgb) + + Constructs a QRgba64 value from the 32bit ARGB value \a rgb. + + \sa fromRgba() +*/ + +/*! + \fn quint16 QRgba64::red() const + + Returns the 16-bit red color component. +*/ + +/*! + \fn quint16 QRgba64::green() const + + Returns the 16-bit green color component. +*/ + +/*! + \fn quint16 QRgba64::blue() const + + Returns the 16-bit blue color component. +*/ + +/*! + \fn quint16 QRgba64::alpha() const + + Returns the 16-bit alpha channel. +*/ + +/*! + \fn quint8 QRgba64::red8() const + + Returns the red color component as an 8-bit. +*/ + +/*! + \fn quint8 QRgba64::green8() const + + Returns the green color component as an 8-bit. +*/ + +/*! + \fn quint8 QRgba64::blue8() const + + Returns the blue color component as an 8-bit. +*/ + +/*! + \fn quint8 QRgba64::alpha8() const + + Returns the alpha channel as an 8-bit. +*/ + +/*! + \fn uint QRgba64::toArgb32() const + + Returns the color as a 32-bit ARGB value. + + \sa fromArgb32() +*/ + +/*! + \fn ushort QRgba64::toRgb16() const + + Returns the color as a 16-bit RGB value. + + \sa toArgb32() +*/ + +/*! + \fn QRgba64 QRgba64::premultiplied() const + + Returns the color with the alpha premultiplied. + + \sa unpremultiplied() +*/ + +/*! + \fn QRgba64 QRgba64::unpremultiplied() const + + Returns the color with the alpha unpremultiplied. + + \sa premultiplied() +*/ + +/*! + \fn QRgba64::operator quint64() const + + Returns the color as a 64bit unsigned integer +*/ + +/*! + \fn QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a) + \relates QColor + \since 5.6 + + Returns the QRgba64 quadruplet (\a{r}, \a{g}, \a{b}, \a{a}). + + \sa qRgba() +*/ + +/*! + \fn QRgba64 qRgba64(quint64 c) + \relates QColor + \since 5.6 + + Returns \a c as a QRgba64 struct. + + \sa qRgba() +*/ + +/*! + \fn QRgba64 qPremultiply(QRgba64 rgba64) + \since 5.6 + \relates QColor + + Converts an unpremultiplied QRgba64 quadruplet \a rgba64 into a premultiplied QRgba64 quadruplet. + + \sa QRgba64::premultiplied(), qUnpremultiply() +*/ + +/*! + \fn QRgba64 qUnpremultiply(QRgba64 rgba64) + \since 5.6 + \relates QColor + + Converts a premultiplied QRgba64 quadruplet \a rgba64 into an unpremultiplied QRgba64 quadruplet. + + \sa QRgba64::unpremultiplied(), qPremultiply() +*/ + +/*! + \fn uint qRed(QRgba64 rgba64) + \since 5.6 + \relates QColor + + Returns the red component of \a rgba64 as an 8-bit value. + + \sa QRgba64::red8(), QColor::red() +*/ + +/*! + \fn uint qGreen(QRgba64 rgba64) + \since 5.6 + \relates QColor + + Returns the green component of \a rgba64 as an 8-bit value. + + \sa QRgba64::green8(), QColor::green() +*/ + +/*! + \fn uint qBlue(QRgba64 rgba64) + \since 5.6 + \relates QColor + + Returns the blue component of \a rgba64 as an 8-bit value. + + \sa QRgba64::blue8(), QColor::blue() +*/ + +/*! + \fn uint qAlpha(QRgba64 rgba64) + \since 5.6 + \relates QColor + + Returns the alpha component of \a rgba64 as an 8-bit value. + + \sa QRgba64::alpha8(), QColor::alpha() +*/ diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h new file mode 100644 index 0000000000..c6cbe666ac --- /dev/null +++ b/src/gui/painting/qrgba64_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRGBA64_P_H +#define QRGBA64_P_H + +#include <QtGui/qrgba64.h> +#include <QtGui/private/qdrawhelper_p.h> +#include <private/qsimd_p.h> + +QT_BEGIN_NAMESPACE + +inline QRgba64 combineAlpha256(QRgba64 rgba64, uint alpha256) +{ + return QRgba64::fromRgba64(rgba64.red(), rgba64.green(), rgba64.blue(), (rgba64.alpha() * alpha256) >> 8); +} + +inline QRgba64 multiplyAlpha256(QRgba64 rgba64, uint alpha256) +{ + return QRgba64::fromRgba64((rgba64.red() * alpha256) >> 8, + (rgba64.green() * alpha256) >> 8, + (rgba64.blue() * alpha256) >> 8, + (rgba64.alpha() * alpha256) >> 8); +} + +inline QRgba64 multiplyAlpha65535(QRgba64 rgba64, uint alpha65535) +{ +#ifdef __SSE2__ + const __m128i va = _mm_shufflelo_epi16(_mm_cvtsi32_si128(alpha65535), _MM_SHUFFLE(0, 0, 0, 0)); + __m128i vs = _mm_loadl_epi64((__m128i*)&rgba64); + vs = _mm_unpacklo_epi16(_mm_mullo_epi16(vs, va), _mm_mulhi_epu16(vs, va)); + vs = _mm_add_epi32(vs, _mm_srli_epi32(vs, 16)); + vs = _mm_add_epi32(vs, _mm_set1_epi32(0x8000)); + vs = _mm_srai_epi32(vs, 16); + vs = _mm_packs_epi32(vs, _mm_setzero_si128()); + _mm_storel_epi64((__m128i*)&rgba64, vs); + return rgba64; +#else + return QRgba64::fromRgba64(qt_div_65535(rgba64.red() * alpha65535), + qt_div_65535(rgba64.green() * alpha65535), + qt_div_65535(rgba64.blue() * alpha65535), + qt_div_65535(rgba64.alpha() * alpha65535)); +#endif +} + +inline QRgba64 multiplyAlpha255(QRgba64 rgba64, uint alpha255) +{ +#ifdef __SSE2__ + return multiplyAlpha65535(rgba64, alpha255 * 257); +#else + return QRgba64::fromRgba64(qt_div_255(rgba64.red() * alpha255), + qt_div_255(rgba64.green() * alpha255), + qt_div_255(rgba64.blue() * alpha255), + qt_div_255(rgba64.alpha() * alpha255)); +#endif +} + +inline QRgba64 interpolate256(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) +{ + return QRgba64::fromRgba64(multiplyAlpha256(x, alpha1) + multiplyAlpha256(y, alpha2)); +} + +inline QRgba64 interpolate255(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) +{ + return QRgba64::fromRgba64(multiplyAlpha255(x, alpha1) + multiplyAlpha255(y, alpha2)); +} + +inline QRgba64 interpolate65535(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) +{ + return QRgba64::fromRgba64(multiplyAlpha65535(x, alpha1) + multiplyAlpha65535(y, alpha2)); +} + +inline QRgba64 addWithSaturation(QRgba64 a, QRgba64 b) +{ +#if defined(__SSE2__) && defined(Q_PROCESSOR_X86_64) + __m128i va = _mm_cvtsi64_si128((quint64)a); + __m128i vb = _mm_cvtsi64_si128((quint64)b); + va = _mm_adds_epu16(va, vb); + return QRgba64::fromRgba64(_mm_cvtsi128_si64(va)); +#else + return QRgba64::fromRgba64(qMin(a.red() + b.red(), 65535), + qMin(a.green() + b.green(), 65535), + qMin(a.blue() + b.blue(), 65535), + qMin(a.alpha() + b.alpha(), 65535)); +#endif +} + +QT_END_NAMESPACE + +#endif // QRGBA64_P_H diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 31d7a2300b..4b3f0b30dc 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -34,6 +34,7 @@ #include "qdatastream.h" #include "qdebug.h" +#include "qhashfunctions.h" #include "qmatrix.h" #include "qregion.h" #include "qpainterpath.h" @@ -776,6 +777,29 @@ bool QTransform::operator==(const QTransform &o) const } /*! + \since 5.6 + \relates QTransform + + Returns the hash value for \a key, using + \a seed to seed the calculation. +*/ +uint qHash(const QTransform &key, uint seed) Q_DECL_NOTHROW +{ + QtPrivate::QHashCombine hash; + seed = hash(key.m11(), seed); + seed = hash(key.m12(), seed); + seed = hash(key.m21(), seed); + seed = hash(key.m22(), seed); + seed = hash(key.dx(), seed); + seed = hash(key.dy(), seed); + seed = hash(key.m13(), seed); + seed = hash(key.m23(), seed); + seed = hash(key.m33(), seed); + return seed; +} + + +/*! \fn bool QTransform::operator!=(const QTransform &matrix) const Returns \c true if this matrix is not equal to the given \a matrix, otherwise returns \c false. diff --git a/src/gui/painting/qtransform.h b/src/gui/painting/qtransform.h index cf8d4d1970..65f543144d 100644 --- a/src/gui/painting/qtransform.h +++ b/src/gui/painting/qtransform.h @@ -180,6 +180,8 @@ private: }; Q_DECLARE_TYPEINFO(QTransform, Q_MOVABLE_TYPE); +Q_GUI_EXPORT Q_DECL_CONST_FUNCTION uint qHash(const QTransform &key, uint seed = 0) Q_DECL_NOTHROW; + /******* inlines *****/ inline QTransform::TransformationType QTransform::inline_type() const { |