Introduce QRgba64 structure for 64bit RGBA values

This structure is meant to replace QRgb where higher precision is
needed.

Change-Id: I49d441e2133371a8b91c2e6af0c137bcc5fcb9ed
Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
This commit is contained in:
Allan Sandfeld Jensen 2015-02-11 11:12:43 +01:00
parent 395e205f2f
commit e2c91dd77b
6 changed files with 603 additions and 6 deletions

View File

@ -43,6 +43,7 @@ HEADERS += \
painting/qrasterizer_p.h \ painting/qrasterizer_p.h \
painting/qregion.h \ painting/qregion.h \
painting/qrgb.h \ painting/qrgb.h \
painting/qrgba64.h \
painting/qstroker_p.h \ painting/qstroker_p.h \
painting/qtextureglyphcache_p.h \ painting/qtextureglyphcache_p.h \
painting/qtransform.h \ painting/qtransform.h \

View File

@ -416,6 +416,18 @@ QColor::QColor(QRgb color)
ct.argb.pad = 0; ct.argb.pad = 0;
} }
/*!
\since 5.6
Constructs a color with the value \a rgba64.
\sa fromRgba64()
*/
QColor::QColor(QRgba64 rgba64)
{
setRgba64(rgba64);
}
/*! /*!
\internal \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. For an invalid color, the alpha value of the returned color is unspecified.
\sa setRgba(), rgb() \sa setRgba(), rgb(), rgba64()
*/ */
QRgb QColor::rgba() const QRgb QColor::rgba() const
@ -954,7 +966,7 @@ QRgb QColor::rgba() const
/*! /*!
Sets the RGB value to \a rgba, including its alpha. Sets the RGB value to \a rgba, including its alpha.
\sa rgba(), rgb() \sa rgba(), rgb(), setRgba64()
*/ */
void QColor::setRgba(QRgb rgba) void QColor::setRgba(QRgb rgba)
{ {
@ -966,6 +978,40 @@ void QColor::setRgba(QRgb rgba)
ct.argb.pad = 0; ct.argb.pad = 0;
} }
/*!
\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 \fn QRgb QColor::rgb() const
@ -1850,7 +1896,7 @@ QColor QColor::fromRgb(QRgb rgb)
Unlike the fromRgb() function, the alpha-channel specified by the given Unlike the fromRgb() function, the alpha-channel specified by the given
QRgb value is included. QRgb value is included.
\sa fromRgb(), isValid() \sa fromRgb(), fromRgba64(), isValid()
*/ */
QColor QColor::fromRgba(QRgb rgba) QColor QColor::fromRgba(QRgb rgba)
@ -1865,7 +1911,7 @@ QColor QColor::fromRgba(QRgb rgba)
All the values must be in the range 0-255. 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) 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. 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) 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; 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 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 color values, \a h (hue), \a s (saturation), \a v (value), and \a a

View File

@ -37,6 +37,7 @@
#include <QtGui/qrgb.h> #include <QtGui/qrgb.h>
#include <QtCore/qnamespace.h> #include <QtCore/qnamespace.h>
#include <QtCore/qstringlist.h> #include <QtCore/qstringlist.h>
#include <QtGui/qrgba64.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -63,6 +64,7 @@ public:
QColor(Qt::GlobalColor color); QColor(Qt::GlobalColor color);
QColor(int r, int g, int b, int a = 255); QColor(int r, int g, int b, int a = 255);
QColor(QRgb rgb); QColor(QRgb rgb);
QColor(QRgba64 rgba64);
QColor(const QString& name); QColor(const QString& name);
QColor(const char *name); QColor(const char *name);
QColor(const QColor &color); // ### Qt 6: remove, the trivial one is fine. QColor(const QColor &color); // ### Qt 6: remove, the trivial one is fine.
@ -109,6 +111,9 @@ public:
QRgb rgba() const; QRgb rgba() const;
void setRgba(QRgb rgba); void setRgba(QRgb rgba);
QRgba64 rgba64() const;
void setRgba64(QRgba64 rgba);
QRgb rgb() const; QRgb rgb() const;
void setRgb(QRgb rgb); void setRgb(QRgb rgb);
@ -173,6 +178,9 @@ public:
static QColor fromRgb(int r, int g, int b, int a = 255); 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 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 fromHsv(int h, int s, int v, int a = 255);
static QColor fromHsvF(qreal h, qreal s, qreal v, qreal a = 1.0); static QColor fromHsvF(qreal h, qreal s, qreal v, qreal a = 1.0);

186
src/gui/painting/qrgba64.h Normal file
View File

@ -0,0 +1,186 @@
/****************************************************************************
**
** 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;
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;
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 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;
}
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

View File

@ -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()
*/

View File

@ -38,6 +38,7 @@
#include <qcolor.h> #include <qcolor.h>
#include <qdebug.h> #include <qdebug.h>
#include <qrgba64.h>
#include <private/qdrawingprimitive_sse2_p.h> #include <private/qdrawingprimitive_sse2_p.h>
class tst_QColor : public QObject class tst_QColor : public QObject
@ -105,6 +106,9 @@ private slots:
void premultiply(); void premultiply();
void unpremultiply_sse4(); void unpremultiply_sse4();
void qrgba64();
void qrgba64Premultiply();
void qrgba64Equivalence();
#ifdef Q_DEAD_CODE_FROM_QT4_X11 #ifdef Q_DEAD_CODE_FROM_QT4_X11
void setallowX11ColorNames(); void setallowX11ColorNames();
@ -1455,7 +1459,7 @@ void tst_QColor::unpremultiply_sse4()
for (uint a = 0; a < 256; a++) { for (uint a = 0; a < 256; a++) {
for (uint c = 0; c <= a; c++) { for (uint c = 0; c <= a; c++) {
QRgb p = qRgba(c, a-c, c, a); QRgb p = qRgba(c, a-c, c, a);
QCOMPARE(qUnpremultiply(p), qUnpremultiply_sse4(p)); QCOMPARE(qUnpremultiply_sse4(p), qUnpremultiply(p));
} }
} }
return; return;
@ -1464,5 +1468,84 @@ void tst_QColor::unpremultiply_sse4()
QSKIP("SSE4 not supported on this CPU."); QSKIP("SSE4 not supported on this CPU.");
} }
void tst_QColor::qrgba64()
{
QRgba64 rgb64 = QRgba64::fromRgba(0x22, 0x33, 0x44, 0xff);
QCOMPARE(rgb64.red(), quint16(0x2222));
QCOMPARE(rgb64.green(), quint16(0x3333));
QCOMPARE(rgb64.blue(), quint16(0x4444));
QCOMPARE(rgb64.alpha(), quint16(0xffff));
QColor c(rgb64);
QCOMPARE(c.red(), 0x22);
QCOMPARE(c.green(), 0x33);
QCOMPARE(c.blue(), 0x44);
QCOMPARE(c.rgba64(), rgb64);
QColor c2 = QColor::fromRgb(0x22, 0x33, 0x44, 0xff);
QCOMPARE(c, c2);
QCOMPARE(c2.rgba64(), rgb64);
rgb64.setAlpha(0x8000);
rgb64.setGreen(0x8844);
rgb64 = rgb64.premultiplied();
QCOMPARE(rgb64.red(), quint16(0x1111));
QCOMPARE(rgb64.blue(), quint16(0x2222));
QCOMPARE(rgb64.green(), quint16(0x4422));
}
void tst_QColor::qrgba64Premultiply()
{
// Tests that qPremultiply(qUnpremultiply(rgba64)) returns rgba64.
for (uint a = 0; a < 0x10000; a+=7) {
const uint step = std::max(a/1024, 1u);
for (uint c = 0; c <= a; c+=step) {
QRgba64 p = qRgba64(c, a-c, a-c/2, a);
QRgba64 pp = qPremultiply(qUnpremultiply(p));
QCOMPARE(pp, p);
}
}
}
void tst_QColor::qrgba64Equivalence()
{
// Any ARGB32 converted back and forth.
for (uint a = 0; a < 256; a++) {
for (uint c = 0; c < 256; c++) {
QRgb p1 = qRgba(c, 255-c, 255-c, a);
QRgba64 p64 = QRgba64::fromArgb32(p1);
QCOMPARE(p64.toArgb32(), p1);
}
}
// Any unpremultiplied ARGB32 value premultipled in RGB64 (except alpha 0).
for (uint a = 1; a < 256; a++) {
for (uint c = 0; c < 256; c++) {
QRgb p1 = qRgba(c, 255-c, 255-c, a);
QRgb pp1 = qPremultiply(p1);
QRgba64 pp64 = qPremultiply(QRgba64::fromArgb32(p1));
QRgb pp2 = pp64.toArgb32();
// 64bit premultiplied is more accurate than 32bit, so allow slight difference.
QCOMPARE(qAlpha(pp2), qAlpha(pp1));
QVERIFY(qAbs(qRed(pp2)-qRed(pp1)) <= 1);
QVERIFY(qAbs(qGreen(pp2)-qGreen(pp1)) <= 1);
QVERIFY(qAbs(qBlue(pp2)-qBlue(pp1)) <= 1);
// But verify the added accuracy means we can return to accurate unpremultiplied ARGB32.
QRgba64 pu64 = qUnpremultiply(pp64);
QRgb p2 = pu64.toArgb32();
QCOMPARE(p2, p1);
}
}
// Any premultiplied ARGB32 value unpremultipled in RGB64.
for (uint a = 0; a < 256; a++) {
for (uint c = 0; c <= a; c++) {
QRgb pp = qRgba(c, a-c, a-c, a);
QRgb pu = qUnpremultiply(pp);
QRgba64 pu64 = qUnpremultiply(QRgba64::fromArgb32(pp));
QCOMPARE(pu64.toArgb32(), pu);
}
}
}
QTEST_MAIN(tst_QColor) QTEST_MAIN(tst_QColor)
#include "tst_qcolor.moc" #include "tst_qcolor.moc"