Export optimized premultiply and unpremultiply methods

This patch optimizes the unpremultiply method further by using a
lookup table to avoid any divisions at all.

The opportunity is taken to export both premultiply and unpremultiply
since they are commonly used methods relevant to the exported QRgb type
that can be both premultiplied and unpremultipled ARGB.

[ChangeLog][QtGui][QColor] Exported highly optimized methods for
premultiply and unpremultiply of QRgb values.

Change-Id: I658bcf57b0bc73c34c1765b64617d43b63ae820b
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
bb10
Allan Sandfeld Jensen 2014-01-29 11:41:31 +01:00 committed by The Qt Project
parent 143d591aab
commit a7b8ef0841
13 changed files with 168 additions and 98 deletions

View File

@ -331,8 +331,7 @@
the size of the register). On some architectures where a pointer could be
smaller than the register, the macro is defined above.
Try our best to define it to a literal, so it can be used in the preprocessor,
but fall back to sizeof(void*) on practically every 32-bit build.
Falls back to QT_POINTER_SIZE if not set explicitly for the platform.
*/
#ifndef Q_PROCESSOR_WORDSIZE
# ifdef __SIZEOF_POINTER__
@ -341,7 +340,7 @@
# elif defined(_LP64) || defined(__LP64__) || defined(WIN64) || defined(_WIN64)
# define Q_PROCESSOR_WORDSIZE 8
# else
# define Q_PROCESSOR_WORDSIZE sizeof(void*)
# define Q_PROCESSOR_WORDSIZE QT_POINTER_SIZE
# endif
#endif

View File

@ -1719,7 +1719,7 @@ void QImage::fill(const QColor &color)
if (d->depth == 32) {
uint pixel = color.rgba();
if (d->format == QImage::Format_ARGB32_Premultiplied || d->format == QImage::Format_RGBA8888_Premultiplied)
pixel = PREMUL(pixel);
pixel = qPremultiply(pixel);
fill((uint) pixel);
} else if (d->format == QImage::Format_RGB16) {
@ -2204,17 +2204,17 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
case Format_RGB32:
//make sure alpha is 255, we depend on it in qdrawhelper for cases
// when image is set as a texture pattern on a qbrush
((uint *)s)[x] = uint(255 << 24) | index_or_rgb;
((uint *)s)[x] = 0xff000000 | index_or_rgb;
return;
case Format_ARGB32:
case Format_ARGB32_Premultiplied:
((uint *)s)[x] = index_or_rgb;
return;
case Format_RGB16:
((quint16 *)s)[x] = qConvertRgb32To16(INV_PREMUL(index_or_rgb));
((quint16 *)s)[x] = qConvertRgb32To16(qUnpremultiply(index_or_rgb));
return;
case Format_RGBX8888:
((uint *)s)[x] = ARGB2RGBA(index_or_rgb | 0xff000000);
((uint *)s)[x] = ARGB2RGBA(0xff000000 | index_or_rgb);
return;
case Format_RGBA8888:
case Format_RGBA8888_Premultiplied:

View File

@ -77,7 +77,7 @@ static const uchar bitflip[256] = {
15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
};
const uchar *qt_get_bitflip_array() // called from QPixmap code
const uchar *qt_get_bitflip_array()
{
return bitflip;
}
@ -187,7 +187,7 @@ static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt:
for (int i = 0; i < src->height; ++i) {
const QRgb *end = src_data + src->width;
while (src_data < end) {
*dest_data = PREMUL(*src_data);
*dest_data = qPremultiply(*src_data);
++src_data;
++dest_data;
}
@ -304,7 +304,7 @@ static void convert_ARGB_to_RGBA_PM(QImageData *dest, const QImageData *src, Qt:
for (int i = 0; i < src->height; ++i) {
const quint32 *end = src_data + src->width;
while (src_data < end) {
*dest_data = ARGB2RGBA(PREMUL(*src_data));
*dest_data = ARGB2RGBA(qPremultiply(*src_data));
++src_data;
++dest_data;
}
@ -376,7 +376,7 @@ static void convert_RGBA_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt:
for (int i = 0; i < src->height; ++i) {
const quint32 *end = src_data + src->width;
while (src_data < end) {
*dest_data = PREMUL(RGBA2ARGB(*src_data));
*dest_data = qPremultiply(RGBA2ARGB(*src_data));
++src_data;
++dest_data;
}
@ -395,7 +395,7 @@ static bool convert_RGBA_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversio
for (int i = 0; i < data->height; ++i) {
const QRgb *end = rgb_data + data->width;
while (rgb_data < end) {
*rgb_data = PREMUL(RGBA2ARGB(*rgb_data));
*rgb_data = qPremultiply(RGBA2ARGB(*rgb_data));
++rgb_data;
}
rgb_data += pad;
@ -429,7 +429,7 @@ static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConve
data->colortable[i] = qRgb(i, i, i);
} else {
for (int i = 0; i < data->colortable.size(); ++i)
data->colortable[i] = PREMUL(data->colortable.at(i));
data->colortable[i] = qPremultiply(data->colortable.at(i));
// Fill the rest of the table in case src_data > colortable.size()
const int oldSize = data->colortable.size();
@ -604,7 +604,7 @@ static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt:
for (int i = 0; i < src->height; ++i) {
const QRgb *end = src_data + src->width;
while (src_data < end) {
*dest_data = INV_PREMUL(*src_data);
*dest_data = qUnpremultiply(*src_data);
++src_data;
++dest_data;
}
@ -628,7 +628,7 @@ static void convert_ARGB_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::
for (int i = 0; i < src->height; ++i) {
const QRgb *end = src_data + src->width;
while (src_data < end) {
*dest_data = 0xff000000 | INV_PREMUL(*src_data);
*dest_data = 0xff000000 | qUnpremultiply(*src_data);
++src_data;
++dest_data;
}
@ -652,7 +652,7 @@ static void convert_ARGB_PM_to_RGBx(QImageData *dest, const QImageData *src, Qt:
for (int i = 0; i < src->height; ++i) {
const QRgb *end = src_data + src->width;
while (src_data < end) {
*dest_data = ARGB2RGBA(0xff000000 | INV_PREMUL(*src_data));
*dest_data = ARGB2RGBA(0xff000000 | qUnpremultiply(*src_data));
++src_data;
++dest_data;
}
@ -676,7 +676,7 @@ static void convert_ARGB_PM_to_RGBA(QImageData *dest, const QImageData *src, Qt:
for (int i = 0; i < src->height; ++i) {
const QRgb *end = src_data + src->width;
while (src_data < end) {
*dest_data = ARGB2RGBA(INV_PREMUL(*src_data));
*dest_data = ARGB2RGBA(qUnpremultiply(*src_data));
++src_data;
++dest_data;
}
@ -748,7 +748,7 @@ static void convert_RGBA_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt:
for (int i = 0; i < src->height; ++i) {
const QRgb *end = src_data + src->width;
while (src_data < end) {
*dest_data = INV_PREMUL(RGBA2ARGB(*src_data));
*dest_data = qUnpremultiply(RGBA2ARGB(*src_data));
++src_data;
++dest_data;
}
@ -772,7 +772,7 @@ static void convert_RGBA_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::
for (int i = 0; i < src->height; ++i) {
const QRgb *end = src_data + src->width;
while (src_data < end) {
*dest_data = 0xff000000 | INV_PREMUL(RGBA2ARGB(*src_data));
*dest_data = 0xff000000 | qUnpremultiply(RGBA2ARGB(*src_data));
++src_data;
++dest_data;
}
@ -862,7 +862,7 @@ static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format f
} else if (format == QImage::Format_ARGB32_Premultiplied) {
// check if the color table has alpha
for (int i = 0; i < colorTable.size(); ++i)
colorTable[i] = PREMUL(colorTable.at(i));
colorTable[i] = qPremultiply(colorTable.at(i));
}
return colorTable;
}

View File

@ -94,7 +94,7 @@ bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionF
if (*p < 0x00ffffff)
*p = 0;
else if (*p < 0xff000000)
*p = PREMUL(*p);
*p = qPremultiply(*p);
}
d = reinterpret_cast<__m128i*>(p+pad);

View File

@ -148,7 +148,7 @@ void QBlittablePlatformPixmap::fill(const QColor &color)
m_alpha = true;
}
uint pixel = PREMUL(color.rgba());
uint pixel = qPremultiply(color.rgba());
const QPixelLayout *layout = &qPixelLayouts[blittable()->lock()->format()];
Q_ASSERT(layout->convertFromARGB32PM);
layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0);

View File

@ -208,7 +208,7 @@ void QRasterPlatformPixmap::fill(const QColor &color)
}
}
}
pixel = PREMUL(color.rgba());
pixel = qPremultiply(color.rgba());
const QPixelLayout *layout = &qPixelLayouts[image.format()];
layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0);
} else {

View File

@ -168,7 +168,7 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient
uint current_color = ARGB_COMBINE_ALPHA(colors[0], alpha);
qreal incr = 1.0 / qreal(size);
qreal fpos = 1.5 * incr;
colorTable[pos++] = ARGB2RGBA(PREMUL(current_color));
colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color));
while (fpos <= s.first().first) {
colorTable[pos] = colorTable[pos - 1];
@ -177,13 +177,13 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient
}
if (colorInterpolation)
current_color = PREMUL(current_color);
current_color = qPremultiply(current_color);
for (int i = 0; i < s.size() - 1; ++i) {
qreal delta = 1/(s[i+1].first - s[i].first);
uint next_color = ARGB_COMBINE_ALPHA(colors[i+1], alpha);
if (colorInterpolation)
next_color = PREMUL(next_color);
next_color = qPremultiply(next_color);
while (fpos < s[i+1].first && pos < size) {
int dist = int(256 * ((fpos - s[i].first) * delta));
@ -191,7 +191,7 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient
if (colorInterpolation)
colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
else
colorTable[pos] = ARGB2RGBA(PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
++pos;
fpos += incr;
}
@ -200,7 +200,7 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient
Q_ASSERT(s.size() > 0);
uint last_color = ARGB2RGBA(PREMUL(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha)));
uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha)));
for (;pos < size; ++pos)
colorTable[pos] = last_color;

View File

@ -2499,6 +2499,41 @@ QDataStream &operator>>(QDataStream &stream, QColor &color)
}
#endif // QT_NO_DATASTREAM
// A table of precalculated results of 0x00ff00ff/alpha use by qUnpremultiply:
const uint qt_inv_premul_factor[256] = {
0, 16711935, 8355967, 5570645, 4177983, 3342387, 2785322, 2387419,
2088991, 1856881, 1671193, 1519266, 1392661, 1285533, 1193709, 1114129,
1044495, 983055, 928440, 879575, 835596, 795806, 759633, 726605,
696330, 668477, 642766, 618960, 596854, 576273, 557064, 539094,
522247, 506422, 491527, 477483, 464220, 451673, 439787, 428511,
417798, 407608, 397903, 388649, 379816, 371376, 363302, 355573,
348165, 341059, 334238, 327685, 321383, 315319, 309480, 303853,
298427, 293191, 288136, 283253, 278532, 273966, 269547, 265268,
261123, 257106, 253211, 249431, 245763, 242201, 238741, 235379,
232110, 228930, 225836, 222825, 219893, 217038, 214255, 211543,
208899, 206320, 203804, 201348, 198951, 196611, 194324, 192091,
189908, 187774, 185688, 183647, 181651, 179698, 177786, 175915,
174082, 172287, 170529, 168807, 167119, 165464, 163842, 162251,
160691, 159161, 157659, 156186, 154740, 153320, 151926, 150557,
149213, 147893, 146595, 145321, 144068, 142837, 141626, 140436,
139266, 138115, 136983, 135869, 134773, 133695, 132634, 131590,
130561, 129549, 128553, 127572, 126605, 125653, 124715, 123792,
122881, 121984, 121100, 120229, 119370, 118524, 117689, 116866,
116055, 115254, 114465, 113686, 112918, 112160, 111412, 110675,
109946, 109228, 108519, 107818, 107127, 106445, 105771, 105106,
104449, 103800, 103160, 102527, 101902, 101284, 100674, 100071,
99475, 98887, 98305, 97730, 97162, 96600, 96045, 95496,
94954, 94417, 93887, 93362, 92844, 92331, 91823, 91322,
90825, 90334, 89849, 89368, 88893, 88422, 87957, 87497,
87041, 86590, 86143, 85702, 85264, 84832, 84403, 83979,
83559, 83143, 82732, 82324, 81921, 81521, 81125, 80733,
80345, 79961, 79580, 79203, 78829, 78459, 78093, 77729,
77370, 77013, 76660, 76310, 75963, 75619, 75278, 74941,
74606, 74275, 73946, 73620, 73297, 72977, 72660, 72346,
72034, 71725, 71418, 71114, 70813, 70514, 70218, 69924,
69633, 69344, 69057, 68773, 68491, 68211, 67934, 67659,
67386, 67116, 66847, 66581, 66317, 66055, 65795, 65537
};
/*****************************************************************************
QColor global functions (documentation only)
@ -2580,6 +2615,26 @@ QDataStream &operator>>(QDataStream &stream, QColor &color)
the alpha-channel is ignored.
*/
/*!
\fn QRgb qPremultiply(QRgb rgb)
\since 5.3
\relates QColor
Converts an unpremultiplied ARGB quadruplet \a rgb into a premultiplied ARGB quadruplet.
\sa qUnpremultiply()
*/
/*!
\fn QRgb qUnpremultiply(QRgb rgb)
\since 5.3
\relates QColor
Converts a premultiplied ARGB quadruplet \a rgb into an unpremultiplied ARGB quadruplet.
\sa qPremultiply()
*/
/*!
\fn QColor QColor::convertTo(Spec colorSpec) const

View File

@ -255,7 +255,7 @@ static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint *
Q_CONSTEXPR uchar blueRightShift = 8 - blueWidth<Format>();
for (int i = 0; i < count; ++i) {
const uint color = INV_PREMUL(src[i]);
const uint color = qUnpremultiply(src[i]);
const uint red = ((color >> redRightShift) & redMask) << redShift<Format>();
const uint green = ((color >> greenRightShift) & greenMask) << greenShift<Format>();
const uint blue = ((color >> blueRightShift) & blueMask) << blueShift<Format>();
@ -387,7 +387,7 @@ static const uint *QT_FASTCALL convertToARGB32PM(uint *buffer, const uint *src,
red = (red << redLeftShift) | (red >> redRightShift);
green = (green << greenLeftShift) | (green >> greenRightShift);
blue = (blue << blueLeftShift) | (blue >> blueRightShift);
buffer[i] = PREMUL((alpha << 24) | (red << 16) | (green << 8) | blue);
buffer[i] = qPremultiply((alpha << 24) | (red << 16) | (green << 8) | blue);
}
}
return buffer;
@ -446,7 +446,7 @@ static const uint *QT_FASTCALL convertFromARGB32PM(uint *buffer, const uint *src
if (!layout->premultiplied) {
for (int i = 0; i < count; ++i)
buffer[i] = INV_PREMUL(src[i]);
buffer[i] = qUnpremultiply(src[i]);
src = buffer;
}
for (int i = 0; i < count; ++i) {
@ -505,7 +505,7 @@ static const uint *QT_FASTCALL convertRGB16FromARGB32PM(uint *buffer, const uint
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
buffer[i] = qConvertRgb32To16(INV_PREMUL(src[i]));
buffer[i] = qConvertRgb32To16(qUnpremultiply(src[i]));
return buffer;
}
#endif
@ -515,7 +515,7 @@ static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint
const QPixelLayout *, const QRgb *clut)
{
for (int i = 0; i < count; ++i)
buffer[i] = PREMUL(clut[src[i]]);
buffer[i] = qPremultiply(clut[src[i]]);
return buffer;
}
@ -529,7 +529,7 @@ static const uint *QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, const uint
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
buffer[i] = PREMUL(src[i]);
buffer[i] = qPremultiply(src[i]);
return buffer;
}
@ -545,7 +545,7 @@ static const uint *QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, const uin
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
buffer[i] = PREMUL(RGBA2ARGB(src[i]));
buffer[i] = qPremultiply(RGBA2ARGB(src[i]));
return buffer;
}
@ -553,7 +553,7 @@ static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uin
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
buffer[i] = INV_PREMUL(src[i]);
buffer[i] = qUnpremultiply(src[i]);
return buffer;
}
@ -569,7 +569,7 @@ static const uint *QT_FASTCALL convertRGBA8888FromARGB32PM(uint *buffer, const u
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
buffer[i] = ARGB2RGBA(INV_PREMUL(src[i]));
buffer[i] = ARGB2RGBA(qUnpremultiply(src[i]));
return buffer;
}
@ -585,7 +585,7 @@ static const uint *QT_FASTCALL convertRGBXFromARGB32PM(uint *buffer, const uint
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
buffer[i] = ARGB2RGBA(0xff000000 | INV_PREMUL(src[i]));
buffer[i] = ARGB2RGBA(0xff000000 | qUnpremultiply(src[i]));
return buffer;
}
@ -853,9 +853,9 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] =
*/
static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
{
QRgb color_0 = PREMUL(rbuf->destColor0);
QRgb color_1 = PREMUL(rbuf->destColor1);
color = PREMUL(color);
QRgb color_0 = qPremultiply(rbuf->destColor0);
QRgb color_1 = qPremultiply(rbuf->destColor1);
color = qPremultiply(color);
int r = qRed(color);
int g = qGreen(color);
@ -6250,7 +6250,7 @@ static void qt_rectfill_nonpremul_argb32(QRasterBuffer *rasterBuffer,
quint32 color)
{
qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine());
qUnpremultiply(color), x, y, width, height, rasterBuffer->bytesPerLine());
}
static void qt_rectfill_rgba(QRasterBuffer *rasterBuffer,
@ -6266,7 +6266,7 @@ static void qt_rectfill_nonpremul_rgba(QRasterBuffer *rasterBuffer,
quint32 color)
{
qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
ARGB2RGBA(INV_PREMUL(color)), x, y, width, height, rasterBuffer->bytesPerLine());
ARGB2RGBA(qUnpremultiply(color)), x, y, width, height, rasterBuffer->bytesPerLine());
}

View File

@ -599,14 +599,6 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) {
return (uint(t)) | (uint(t >> 24));
}
static Q_ALWAYS_INLINE uint PREMUL(uint x) {
uint a = x >> 24;
quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a;
t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080) >> 8;
t &= 0x000000ff00ff00ff;
return (uint(t)) | (uint(t >> 24)) | (a << 24);
}
#else // 32-bit versions
static Q_ALWAYS_INLINE uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) {
@ -639,20 +631,9 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) {
# pragma pop
#endif
static Q_ALWAYS_INLINE uint PREMUL(uint x) {
uint a = x >> 24;
uint t = (x & 0xff00ff) * a;
t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
t &= 0xff00ff;
x = ((x >> 8) & 0xff) * a;
x = (x + ((x >> 8) & 0xff) + 0x80);
x &= 0xff00;
x |= t | (a << 24);
return x;
}
#endif
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) {
quint32 rgb = x >> 8;
@ -691,17 +672,9 @@ static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16_32(uint x, uint a) {
return t;
}
static Q_ALWAYS_INLINE uint INV_PREMUL(uint p) {
const uint alpha = qAlpha(p);
if (alpha == 255)
return p;
if (alpha == 0)
return 0;
// (p*(0x00ff00ff/alpha)) >> 16 == (p*255)/alpha for all p and alpha <= 256.
const uint invAlpha = 0x00ff00ffU / alpha;
// We add 0x8000 to get even rounding. The rounding also ensures that PREMUL(INV_PREMUL(p)) == p for all p.
return qRgba((qRed(p)*invAlpha + 0x8000)>>16, (qGreen(p)*invAlpha + 0x8000)>>16, (qBlue(p)*invAlpha + 0x8000)>>16, alpha);
}
// FIXME: Remove when all Qt modules have stopped using PREMUL and INV_PREMUL
#define PREMUL(x) qPremultiply(x)
#define INV_PREMUL(p) qUnpremultiply(p)
struct quint24 {
quint24(uint value);

View File

@ -1823,7 +1823,7 @@ void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
d->solid_color_filler.solid.color = qPremultiply(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
if ((d->solid_color_filler.solid.color & 0xff000000) == 0
&& s->composition_mode == QPainter::CompositionMode_SourceOver) {
return;
@ -2272,7 +2272,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
| ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
break;
default:
d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
d->solid_color_filler.solid.color = qPremultiply(ARGB_COMBINE_ALPHA(color, s->intOpacity));
break;
}
@ -3662,7 +3662,7 @@ QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
QRgb fg = PREMUL(color.rgba());
QRgb fg = qPremultiply(color.rgba());
QRgb bg = 0;
int height = sourceImage.height();
@ -3702,8 +3702,8 @@ QImage::Format QRasterBuffer::prepare(QImage *image)
drawHelper = qDrawHelper + format;
if (image->depth() == 1 && image->colorTable().size() == 2) {
monoDestinationWithClut = true;
destColor0 = PREMUL(image->colorTable()[0]);
destColor1 = PREMUL(image->colorTable()[1]);
destColor0 = qPremultiply(image->colorTable()[0]);
destColor1 = qPremultiply(image->colorTable()[1]);
}
return format;
@ -4260,8 +4260,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
}
if (colorInterpolation) {
first_color = PREMUL(first_color);
second_color = PREMUL(second_color);
first_color = qPremultiply(first_color);
second_color = qPremultiply(second_color);
}
int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
@ -4282,7 +4282,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
if (colorInterpolation)
colorTable[i] = first_color;
else
colorTable[i] = PREMUL(first_color);
colorTable[i] = qPremultiply(first_color);
}
if (i < second_index) {
@ -4311,7 +4311,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
if (colorInterpolation)
colorTable[i] = color;
else
colorTable[i] = PREMUL(color);
colorTable[i] = qPremultiply(color);
}
}
@ -4319,7 +4319,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
if (colorInterpolation)
colorTable[i] = second_color;
else
colorTable[i] = PREMUL(second_color);
colorTable[i] = qPremultiply(second_color);
}
return;
@ -4327,7 +4327,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
if (stopCount == 1) {
current_color = PREMUL(current_color);
current_color = qPremultiply(current_color);
for (int i = 0; i < size; ++i)
colorTable[i] = current_color;
return;
@ -4344,7 +4344,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
// Up to first point
colorTable[pos++] = PREMUL(current_color);
colorTable[pos++] = qPremultiply(current_color);
while (dpos <= begin_pos) {
colorTable[pos] = colorTable[pos - 1];
++pos;
@ -4366,8 +4366,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
if (colorInterpolation) {
current_color = PREMUL(current_color);
next_color = PREMUL(next_color);
current_color = qPremultiply(current_color);
next_color = qPremultiply(next_color);
}
qreal diff = stops[current_stop+1].first - stops[current_stop].first;
@ -4384,7 +4384,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
if (colorInterpolation)
colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
else
colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
colorTable[pos] = qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
++pos;
dpos += incr;
@ -4408,8 +4408,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
if (colorInterpolation) {
if (skip != 1)
current_color = PREMUL(current_color);
next_color = PREMUL(next_color);
current_color = qPremultiply(current_color);
next_color = qPremultiply(next_color);
}
qreal diff = stops[current_stop+1].first - stops[current_stop].first;
@ -4421,7 +4421,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
}
// After last point
current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
current_color = qPremultiply(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
while (pos < size - 1) {
colorTable[pos] = current_color;
++pos;
@ -4455,7 +4455,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
type = Solid;
QColor c = qbrush_color(brush);
QRgb rgba = c.rgba();
solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
solid.color = qPremultiply(ARGB_COMBINE_ALPHA(rgba, alpha));
if ((solid.color & 0xff000000) == 0
&& compositionMode == QPainter::CompositionMode_SourceOver) {
type = None;

View File

@ -43,6 +43,7 @@
#define QRGB_H
#include <QtCore/qglobal.h>
#include <QtCore/qprocessordetection.h>
QT_BEGIN_NAMESPACE
@ -79,6 +80,48 @@ inline Q_DECL_CONSTEXPR int qGray(QRgb rgb) // convert RGB to gra
inline Q_DECL_CONSTEXPR bool qIsGray(QRgb rgb)
{ return qRed(rgb) == qGreen(rgb) && qRed(rgb) == qBlue(rgb); }
#if Q_PROCESSOR_WORDSIZE == 8 // 64-bit version
inline QRgb qPremultiply(QRgb x)
{
const uint a = qAlpha(x);
quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a;
t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080) >> 8;
t &= 0x000000ff00ff00ff;
return (uint(t)) | (uint(t >> 24)) | (a << 24);
}
#else // 32-bit version
inline QRgb qPremultiply(QRgb x)
{
const uint a = qAlpha(x);
uint t = (x & 0xff00ff) * a;
t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
t &= 0xff00ff;
x = ((x >> 8) & 0xff) * a;
x = (x + ((x >> 8) & 0xff) + 0x80);
x &= 0xff00;
x |= t | (a << 24);
return x;
}
#endif
Q_GUI_EXPORT extern const uint qt_inv_premul_factor[];
inline QRgb qUnpremultiply(QRgb p)
{
const uint alpha = qAlpha(p);
// Alpha 255 and 0 are the two most common values, which makes them beneficial to short-cut.
if (alpha == 255)
return p;
if (alpha == 0)
return 0;
// (p*(0x00ff00ff/alpha)) >> 16 == (p*255)/alpha for all p and alpha <= 256.
const uint invAlpha = qt_inv_premul_factor[alpha];
// We add 0x8000 to get even rounding. The rounding also ensures that qPremultiply(qUnpremultiply(p)) == p for all p.
return qRgba((qRed(p)*invAlpha + 0x8000)>>16, (qGreen(p)*invAlpha + 0x8000)>>16, (qBlue(p)*invAlpha + 0x8000)>>16, alpha);
}
QT_END_NAMESPACE
#endif // QRGB_H

View File

@ -184,7 +184,7 @@ void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, ui
uint current_color = ARGB_COMBINE_ALPHA(colors[0], alpha);
qreal incr = 1.0 / qreal(size);
qreal fpos = 1.5 * incr;
colorTable[pos++] = qtToGlColor(PREMUL(current_color));
colorTable[pos++] = qtToGlColor(qPremultiply(current_color));
while (fpos <= s.first().first) {
colorTable[pos] = colorTable[pos - 1];
@ -193,13 +193,13 @@ void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, ui
}
if (colorInterpolation)
current_color = PREMUL(current_color);
current_color = qPremultiply(current_color);
for (int i = 0; i < s.size() - 1; ++i) {
qreal delta = 1/(s[i+1].first - s[i].first);
uint next_color = ARGB_COMBINE_ALPHA(colors[i+1], alpha);
if (colorInterpolation)
next_color = PREMUL(next_color);
next_color = qPremultiply(next_color);
while (fpos < s[i+1].first && pos < size) {
int dist = int(256 * ((fpos - s[i].first) * delta));
@ -207,7 +207,7 @@ void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, ui
if (colorInterpolation)
colorTable[pos] = qtToGlColor(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
else
colorTable[pos] = qtToGlColor(PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
colorTable[pos] = qtToGlColor(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
++pos;
fpos += incr;
}
@ -216,7 +216,7 @@ void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, ui
Q_ASSERT(s.size() > 0);
uint last_color = qtToGlColor(PREMUL(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha)));
uint last_color = qtToGlColor(qPremultiply(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha)));
for (;pos < size; ++pos)
colorTable[pos] = last_color;