summaryrefslogtreecommitdiffstats
path: root/src/gui/painting
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting')
-rw-r--r--src/gui/painting/qcolor.cpp55
-rw-r--r--src/gui/painting/qdrawhelper.cpp30
-rw-r--r--src/gui/painting/qdrawhelper_p.h35
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp38
-rw-r--r--src/gui/painting/qrgb.h43
5 files changed, 136 insertions, 65 deletions
diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp
index 706273c151..b9d3ca888e 100644
--- a/src/gui/painting/qcolor.cpp
+++ b/src/gui/painting/qcolor.cpp
@@ -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)
@@ -2581,6 +2616,26 @@ QDataStream &operator>>(QDataStream &stream, QColor &color)
*/
/*!
+ \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
Creates a copy of \e this color in the format specified by \a colorSpec.
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 1851734bbc..52a6b5d211 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -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());
}
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index 0f98b07229..bbeb73f0af 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -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);
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index bdd0d9cd4c..9a2e49618c 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -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;
diff --git a/src/gui/painting/qrgb.h b/src/gui/painting/qrgb.h
index 3c2bc5b97a..d8e19302d1 100644
--- a/src/gui/painting/qrgb.h
+++ b/src/gui/painting/qrgb.h
@@ -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