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>
This commit is contained in:
parent
bc35941dbb
commit
d0d18b0645
@ -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
|
||||
}
|
||||
|
||||
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 && 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 {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
#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) {
|
||||
dest[x] = src;
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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) {
|
||||
*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);
|
||||
// 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;
|
||||
|
@ -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));
|
||||
|
@ -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()));
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user