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
parent
996061a1c0
commit
96269ecc77
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ struct QSpanData
|
|||
uint fast_matrix : 1;
|
||||
bool bilinear;
|
||||
QImage *tempImage;
|
||||
QRgba64 solidColor;
|
||||
QColor solidColor;
|
||||
union {
|
||||
QGradientData gradient;
|
||||
QTextureData texture;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue