Draw extended RGB solid colors

Pass extended RGB colors through the paint engine.

Change-Id: I2e212cd4c76aaa65439746352c0da2b9db4a506d
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
bb10
Allan Sandfeld Jensen 2021-02-10 15:49:11 +01:00
parent 996061a1c0
commit 96269ecc77
7 changed files with 112 additions and 25 deletions

View File

@ -1909,6 +1909,31 @@ void QImage::fill(const QColor &color)
qt_rectfill<quint64>(reinterpret_cast<quint64 *>(d->data), color.rgba64().premultiplied(),
0, 0, d->width, d->height, d->bytes_per_line);
break;
case QImage::Format_RGBX16FPx4:
case QImage::Format_RGBA16FPx4:
case QImage::Format_RGBA16FPx4_Premultiplied:
case QImage::Format_RGBX32FPx4:
case QImage::Format_RGBA32FPx4:
case QImage::Format_RGBA32FPx4_Premultiplied:{
float r, g, b, a;
color.getRgbF(&r, &g, &b, &a);
if (!hasAlphaChannel())
a = 1.0f;
if (depth() == 64) {
QRgbaFloat16 c16{r, g, b, a};
if (d->format == Format_RGBA16FPx4_Premultiplied)
c16 = c16.premultiplied();
qt_rectfill<QRgbaFloat16>(reinterpret_cast<QRgbaFloat16 *>(d->data), c16,
0, 0, d->width, d->height, d->bytes_per_line);
} else {
QRgbaFloat32 c32{r, g, b, a};
if (d->format == Format_RGBA32FPx4_Premultiplied)
c32 = c32.premultiplied();
qt_rectfill<QRgbaFloat32>(reinterpret_cast<QRgbaFloat32 *>(d->data), c32,
0, 0, d->width, d->height, d->bytes_per_line);
}
break;
}
default: {
QPainter p(this);
p.setCompositionMode(QPainter::CompositionMode_Source);

View File

@ -862,7 +862,7 @@ Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush)
bool QBrush::isOpaque() const
{
bool opaqueColor = d->color.alpha() == 255;
bool opaqueColor = d->color.alphaF() >= 1.0f;
// Test awfully simple case first
if (d->style == Qt::SolidPattern)
@ -876,7 +876,7 @@ bool QBrush::isOpaque() const
|| d->style == Qt::ConicalGradientPattern) {
QGradientStops stops = gradient()->stops();
for (int i=0; i<stops.size(); ++i)
if (stops.at(i).second.alpha() != 255)
if (stops.at(i).second.alphaF() < 1.0f)
return false;
return true;
} else if (d->style == Qt::TexturePattern) {

View File

@ -299,7 +299,7 @@ void QCosmeticStroker::setup()
drawCaps = state->lastPen.capStyle() != Qt::FlatCap;
if (strokeSelection & FastDraw) {
color = multiplyAlpha256(state->penData.solidColor, opacity).toArgb32();
color = multiplyAlpha256(state->penData.solidColor.rgba64(), opacity).toArgb32();
QRasterBuffer *buffer = state->penData.rasterBuffer;
pixels = reinterpret_cast<uint *>(buffer->buffer());
ppl = buffer->stride<quint32>();

View File

@ -3591,7 +3591,7 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
switch(data->type) {
case QSpanData::Solid:
solidSource = data->solidColor.isOpaque();
solidSource = data->solidColor.alphaF() >= 1.0f;
op.srcFetch = nullptr;
op.srcFetch64 = nullptr;
op.srcFetchFP = nullptr;
@ -3763,7 +3763,7 @@ static void blend_color_generic(int count, const QSpan *spans, void *userData)
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
uint buffer[BufferSize];
Operator op = getOperator(data, nullptr, 0);
const uint color = data->solidColor.toArgb32();
const uint color = data->solidColor.rgba();
const bool solidFill = op.mode == QPainter::CompositionMode_Source;
const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
@ -3795,7 +3795,7 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData)
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
const Operator op = getOperator(data, nullptr, 0);
const uint color = data->solidColor.toArgb32();
const uint color = data->solidColor.rgba();
if (op.mode == QPainter::CompositionMode_Source) {
// inline for performance
@ -3836,7 +3836,7 @@ static void blend_color_generic_rgb64(int count, const QSpan *spans, void *userD
}
alignas(8) QRgba64 buffer[BufferSize];
const QRgba64 color = data->solidColor;
const QRgba64 color = data->solidColor.rgba64();
const bool solidFill = op.mode == QPainter::CompositionMode_Source;
const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
@ -3877,7 +3877,9 @@ static void blend_color_generic_fp(int count, const QSpan *spans, void *userData
}
QRgbaFloat32 buffer[BufferSize];
const QRgbaFloat32 color = qConvertRgb64ToRgbaF32(data->solidColor);
float r, g, b, a;
data->solidColor.getRgbF(&r, &g, &b, &a);
const QRgbaFloat32 color{r, g, b, a};
const bool solidFill = op.mode == QPainter::CompositionMode_Source;
QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
@ -4929,7 +4931,7 @@ static void blend_vertical_gradient(int count, const QSpan *spans, void *userDat
#if QT_CONFIG(raster_64bit)
data->solidColor = qt_gradient_pixel64_fixed(&data->gradient, yinc * y + off);
#else
data->solidColor = QRgba64::fromArgb32(qt_gradient_pixel_fixed(&data->gradient, yinc * y + off));
data->solidColor = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
#endif
blend_color(1, spans, userData);
++spans;

View File

@ -368,7 +368,7 @@ struct QSpanData
uint fast_matrix : 1;
bool bilinear;
QImage *tempImage;
QRgba64 solidColor;
QColor solidColor;
union {
QGradientData gradient;
QTextureData texture;

View File

@ -783,7 +783,8 @@ void QRasterPaintEngine::updateRasterState()
&& s->intOpacity == 256
&& (mode == QPainter::CompositionMode_SourceOver
|| (mode == QPainter::CompositionMode_Source
&& s->penData.solidColor.isOpaque()));
&& (s->penData.solidColor.spec() != QColor::ExtendedRgb &&
s->penData.solidColor.alphaF() >= 1.0f)));
}
s->dirty = 0;
@ -1449,9 +1450,10 @@ static void fillRect_normalized(const QRect &r, QSpanData *data,
if (data->fillRect && (mode == QPainter::CompositionMode_Source
|| (mode == QPainter::CompositionMode_SourceOver
&& data->solidColor.isOpaque())))
&& (data->solidColor.spec() != QColor::ExtendedRgb &&
data->solidColor.alphaF() >= 1.0f))))
{
data->fillRect(data->rasterBuffer, x1, y1, width, height, data->solidColor);
data->fillRect(data->rasterBuffer, x1, y1, width, height, data->solidColor.rgba64());
return;
}
}
@ -1800,6 +1802,19 @@ void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
fillRect(r, &s->brushData);
}
static QColor qPremultiplyWithExtraAlpha(const QColor &c, int alpha)
{
if (alpha == 0)
return Qt::transparent;
if (c.spec() == QColor::ExtendedRgb) {
float r, g, b, a;
c.getRgbF(&r, &g, &b, &a);
a = a * alpha * (1.f / 256.f);
return QColor::fromRgbF(r * a, g * a, b * a, a);
}
return qPremultiply(combineAlpha256(c.rgba64(), alpha));
}
/*!
\reimp
*/
@ -1811,9 +1826,9 @@ void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
d->solid_color_filler.solidColor = qPremultiply(combineAlpha256(color.rgba64(), s->intOpacity));
d->solid_color_filler.solidColor = qPremultiplyWithExtraAlpha(color, s->intOpacity);
if (d->solid_color_filler.solidColor.isTransparent()
if (d->solid_color_filler.solidColor.alphaF() <= 0.0f
&& s->composition_mode == QPainter::CompositionMode_SourceOver) {
return;
}
@ -2274,7 +2289,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
break;
}
if (d->solid_color_filler.solidColor.isTransparent() && s->composition_mode == QPainter::CompositionMode_SourceOver)
if (d->solid_color_filler.solidColor.alphaF() <= 0.0f && s->composition_mode == QPainter::CompositionMode_SourceOver)
return;
d->solid_color_filler.clip = d->clip();
@ -2618,20 +2633,20 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
if (unclipped) {
if (depth == 1) {
if (s->penData.bitmapBlit) {
s->penData.bitmapBlit(rb, rx, ry, s->penData.solidColor,
s->penData.bitmapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
scanline, w, h, bpl);
return;
}
} else if (depth == 8) {
if (s->penData.alphamapBlit) {
s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor,
s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
scanline, w, h, bpl, nullptr, useGammaCorrection);
return;
}
} else if (depth == 32) {
// (A)RGB Alpha mask where the alpha component is not used.
if (s->penData.alphaRGBBlit) {
s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor,
s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
(const uint *) scanline, w, h, bpl / 4, nullptr, useGammaCorrection);
return;
}
@ -2660,10 +2675,10 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
ry = ny;
}
if (depth == 8)
s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor,
s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
scanline, w, h, bpl, clip, useGammaCorrection);
else if (depth == 32)
s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor,
s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
(const uint *) scanline, w, h, bpl / 4, clip, useGammaCorrection);
return;
}
@ -2856,9 +2871,9 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
QFontEngine::GlyphFormat glyphFormat = fontEngine->glyphFormat != QFontEngine::Format_None ? fontEngine->glyphFormat : d->glyphCacheFormat;
QImageTextureGlyphCache *cache =
static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(nullptr, glyphFormat, s->matrix, QColor(s->penData.solidColor)));
static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(nullptr, glyphFormat, s->matrix, s->penData.solidColor));
if (!cache) {
cache = new QImageTextureGlyphCache(glyphFormat, s->matrix, QColor(s->penData.solidColor));
cache = new QImageTextureGlyphCache(glyphFormat, s->matrix, s->penData.solidColor);
fontEngine->setGlyphCache(nullptr, cache);
}
@ -4523,8 +4538,8 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
case Qt::SolidPattern: {
type = Solid;
QColor c = qbrush_color(brush);
solidColor = qPremultiply(combineAlpha256(c.rgba64(), alpha));
if (solidColor.isTransparent() && compositionMode == QPainter::CompositionMode_SourceOver)
solidColor = qPremultiplyWithExtraAlpha(c, alpha);
if (solidColor.alphaF() <= 0.0f && compositionMode == QPainter::CompositionMode_SourceOver)
type = None;
break;
}

View File

@ -301,6 +301,9 @@ private slots:
void drawImageAtPointF();
void scaledDashes();
#if QT_CONFIG(raster_fp)
void hdrColors();
#endif
private:
void fillData();
@ -5393,6 +5396,48 @@ void tst_QPainter::scaledDashes()
QVERIFY(backFound);
}
#if QT_CONFIG(raster_fp)
void tst_QPainter::hdrColors()
{
QImage img(10, 10, QImage::Format_RGBA32FPx4_Premultiplied);
img.fill(Qt::transparent);
QColor color = QColor::fromRgbF(2.0f, -0.25f, 1.5f);
img.setPixelColor(2, 2, color);
QCOMPARE(img.pixelColor(2, 2), color);
{
QPainterPath path;
path.addEllipse(4, 4, 2, 2);
QPainter p(&img);
p.fillPath(path, color);
p.end();
}
QCOMPARE(img.pixelColor(4, 4), color);
img.fill(color);
QCOMPARE(img.pixelColor(8, 8), color);
QColor color2 = QColor::fromRgbF(0.0f, 1.25f, 2.5f);
{
QPainter p(&img);
p.fillRect(0, 0, 3, 3, color2);
p.end();
}
QCOMPARE(img.pixelColor(1, 1), color2);
QCOMPARE(img.pixelColor(4, 4), color);
QImage img2(10, 10, QImage::Format_RGBX32FPx4);
{
QPainter p(&img2);
p.drawImage(0, 0, img);
p.end();
}
QCOMPARE(img2.pixelColor(2, 2), color2);
QCOMPARE(img2.pixelColor(5, 5), color);
}
#endif
QTEST_MAIN(tst_QPainter)
#include "tst_qpainter.moc"