summaryrefslogtreecommitdiffstats
path: root/src/gui/painting
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-12-04 15:05:04 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-09-22 17:15:26 +0200
commitd0d18b06458edd3b6b0712ea71c787404bbaa7e1 (patch)
tree3918a8c40b49c69bef47fcd01598e854bfd77dfc /src/gui/painting
parentbc35941dbbf6cbd09805a2217ecb062c565855ad (diff)
Handle transparent pen color in fast text path
Switches the text blending to be SourceOver as that is much more common than Source, and means we can now handle semi-transparent text colors there. Task-number: QTBUG-72165 Change-Id: I7b3aedb22412e6fb6f60197596b37f26c6008784 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'src/gui/painting')
-rw-r--r--src/gui/painting/qdrawhelper.cpp187
-rw-r--r--src/gui/painting/qdrawhelper_p.h2
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp4
-rw-r--r--src/gui/painting/qrgba64_p.h2
4 files changed, 101 insertions, 94 deletions
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index edb363ac69..3d06a27d8e 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -5658,44 +5658,60 @@ static inline void alphamapblend_argb32(quint32 *dst, int coverage, QRgba64 srcL
{
if (coverage == 0) {
// nothing
- } else if (coverage == 255) {
- *dst = src;
- } else if (!colorProfile) {
- *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage);
+ } else if (coverage == 255 || !colorProfile) {
+ blend_pixel(*dst, src, coverage);
+ } else if (*dst < 0xff000000) {
+ // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
+ blend_pixel(*dst, src, coverage);
+ } else if (src >= 0xff000000) {
+ grayBlendPixel(dst, coverage, srcLinear, colorProfile);
} else {
- if (*dst >= 0xff000000) {
- grayBlendPixel(dst, coverage, srcLinear, colorProfile);
- } else {
- // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
- *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage);
- }
+ // First do naive blend with text-color
+ QRgb s = *dst;
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ grayBlendPixel(dst, coverage, colorProfile->toLinear64(s), colorProfile);
}
}
#if QT_CONFIG(raster_64bit)
+
+static inline void grayBlendPixel(QRgba64 &dst, int coverage, QRgba64 srcLinear, const QColorTrcLut *colorProfile)
+{
+ // Do a gammacorrected gray alphablend...
+ QRgba64 dstColor = dst;
+ if (colorProfile) {
+ if (dstColor.isOpaque())
+ dstColor = colorProfile->toLinear(dstColor);
+ else if (!dstColor.isTransparent())
+ dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied();
+ }
+
+ blend_pixel(dstColor, srcLinear, coverage);
+
+ if (colorProfile) {
+ if (dstColor.isOpaque())
+ dstColor = colorProfile->fromLinear(dstColor);
+ else if (!dstColor.isTransparent())
+ dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied();
+ }
+ dst = dstColor;
+}
+
static inline void alphamapblend_generic(int coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
{
if (coverage == 0) {
// nothing
} else if (coverage == 255) {
- dest[x] = src;
+ blend_pixel(dest[x], src);
+ } else if (src.isOpaque()) {
+ grayBlendPixel(dest[x], coverage, srcLinear, colorProfile);
} else {
- QRgba64 dstColor = dest[x];
- if (colorProfile) {
- if (dstColor.isOpaque())
- dstColor = colorProfile->toLinear(dstColor);
- else if (!dstColor.isTransparent())
- dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied();
- }
-
- dstColor = interpolate255(srcLinear, coverage, dstColor, 255 - coverage);
- if (colorProfile) {
- if (dstColor.isOpaque())
- dstColor = colorProfile->fromLinear(dstColor);
- else if (!dstColor.isTransparent())
- dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied();
- }
- dest[x] = dstColor;
+ // First do naive blend with text-color
+ QRgba64 s = dest[x];
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ grayBlendPixel(dest[x], coverage, colorProfile->toLinear(s), colorProfile);
}
}
@@ -5714,12 +5730,8 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
alignas(8) QRgba64 buffer[BufferSize];
const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
@@ -5792,12 +5804,8 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
quint32 buffer[BufferSize];
const DestFetchProc destFetch = destFetchProc[rasterBuffer->format];
@@ -5872,7 +5880,7 @@ void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
int mapWidth, int mapHeight, int mapStride,
const QClipData *clip, bool useGammaCorrection)
{
- if (useGammaCorrection) {
+ if (useGammaCorrection || !color.isOpaque()) {
qt_alphamapblit_generic(rasterBuffer, x, y, color, map, mapWidth, mapHeight, mapStride, clip, useGammaCorrection);
return;
}
@@ -5931,12 +5939,8 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
if (!clip) {
quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
@@ -6031,48 +6035,59 @@ static inline QRgb rgbBlend(QRgb d, QRgb s, uint rgbAlpha)
#endif
}
-#if QT_CONFIG(raster_64bit)
-static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
+static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile)
{
if (coverage == 0xff000000) {
// nothing
- } else if (coverage == 0xffffffff) {
- dest[x] = src;
+ } else if (coverage == 0xffffffff && qAlpha(src) == 255) {
+ blend_pixel(*dst, src);
+ } else if (!colorProfile) {
+ *dst = rgbBlend(*dst, src, coverage);
+ } else if (*dst < 0xff000000) {
+ // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
+ blend_pixel(*dst, src, qRgbAvg(coverage));
+ } else if (srcLinear.isOpaque()) {
+ rgbBlendPixel(dst, coverage, srcLinear, colorProfile);
} else {
- QRgba64 dstColor = dest[x];
- if (dstColor.isOpaque()) {
- if (colorProfile)
- dstColor = colorProfile->toLinear(dstColor);
- dstColor = rgbBlend(dstColor, srcLinear, coverage);
- if (colorProfile)
- dstColor = colorProfile->fromLinear(dstColor);
- dest[x] = dstColor;
- } else {
- // Do a gray alphablend.
- alphamapblend_generic(qRgbAvg(coverage), dest, x, srcLinear, src, colorProfile);
- }
+ // First do naive blend with text-color
+ QRgb s = *dst;
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ rgbBlendPixel(dst, coverage, colorProfile->toLinear64(s), colorProfile);
}
}
-#endif
-static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile)
+#if QT_CONFIG(raster_64bit)
+static inline void rgbBlendPixel(QRgba64 &dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile)
+{
+ // Do a gammacorrected RGB alphablend...
+ const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(dst) : dst;
+
+ QRgba64 blend = rgbBlend(dlinear, slinear, coverage);
+
+ dst = colorProfile ? colorProfile->fromLinear(blend) : blend;
+}
+
+static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
{
if (coverage == 0xff000000) {
// nothing
} else if (coverage == 0xffffffff) {
- *dst = src;
- } else if (*dst < 0xff000000) {
- // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
- const int a = qRgbAvg(coverage);
- *dst = INTERPOLATE_PIXEL_255(src, a, *dst, 255 - a);
- } else if (!colorProfile) {
- *dst = rgbBlend(*dst, src, coverage);
- } else {
- rgbBlendPixel(dst, coverage, srcLinear, colorProfile);
+ blend_pixel(dest[x], src);
+ } else if (!dest[x].isOpaque()) {
+ // Do a gray alphablend.
+ alphamapblend_generic(qRgbAvg(coverage), dest, x, srcLinear, src, colorProfile);
+ } else if (src.isOpaque()) {
+ rgbBlendPixel(dest[x], coverage, srcLinear, colorProfile);
+ } else {
+ // First do naive blend with text-color
+ QRgba64 s = dest[x];
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ rgbBlendPixel(dest[x], coverage, colorProfile->toLinear(s), colorProfile);
}
}
-#if QT_CONFIG(raster_64bit)
static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
int x, int y, const QRgba64 &color,
const uint *src, int mapWidth, int mapHeight, int srcStride,
@@ -6087,12 +6102,8 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
alignas(8) QRgba64 buffer[BufferSize];
const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
@@ -6164,12 +6175,8 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
quint32 buffer[BufferSize];
const DestFetchProc destFetch = destFetchProc[rasterBuffer->format];
@@ -6242,12 +6249,8 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
if (!clip) {
quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index 9c5d525722..dd42b96d79 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -671,6 +671,8 @@ static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src)
static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src, const int const_alpha)
{
+ if (const_alpha == 255)
+ return blend_pixel(dst, src);
if (src != 0) {
const quint32 s = BYTE_MUL(src, const_alpha);
dst = s + BYTE_MUL(dst, qAlpha(~s));
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 9894da8fe1..447ecb358a 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -842,8 +842,8 @@ void QRasterPaintEngine::updateRasterState()
const QPainter::CompositionMode mode = s->composition_mode;
s->flags.fast_text = (s->penData.type == QSpanData::Solid)
&& s->intOpacity == 256
- && (mode == QPainter::CompositionMode_Source
- || (mode == QPainter::CompositionMode_SourceOver
+ && (mode == QPainter::CompositionMode_SourceOver
+ || (mode == QPainter::CompositionMode_Source
&& s->penData.solidColor.isOpaque()));
}
diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h
index ca879de27c..d145dbfbea 100644
--- a/src/gui/painting/qrgba64_p.h
+++ b/src/gui/painting/qrgba64_p.h
@@ -284,6 +284,8 @@ static Q_ALWAYS_INLINE void blend_pixel(QRgba64 &dst, QRgba64 src)
static Q_ALWAYS_INLINE void blend_pixel(QRgba64 &dst, QRgba64 src, const int const_alpha)
{
+ if (const_alpha == 255)
+ return blend_pixel(dst, src);
if (!src.isTransparent()) {
src = multiplyAlpha255(src, const_alpha);
dst = src + multiplyAlpha65535(dst, 65535 - src.alpha());