diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 1ed94f70e2..2468b52d84 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -1909,6 +1909,31 @@ void QImage::fill(const QColor &color) qt_rectfill(reinterpret_cast(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(reinterpret_cast(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(reinterpret_cast(d->data), c32, + 0, 0, d->width, d->height, d->bytes_per_line); + } + break; + } default: { QPainter p(this); p.setCompositionMode(QPainter::CompositionMode_Source); diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index 1f3cacba72..0b374d62f8 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -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; istyle == Qt::TexturePattern) { diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp index a584ed5d0c..215efcbc00 100644 --- a/src/gui/painting/qcosmeticstroker.cpp +++ b/src/gui/painting/qcosmeticstroker.cpp @@ -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(buffer->buffer()); ppl = buffer->stride(); diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 2029b2d7b9..18911e3ee9 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -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(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(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; diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 2881d8a4f4..d2836f636b 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -368,7 +368,7 @@ struct QSpanData uint fast_matrix : 1; bool bilinear; QImage *tempImage; - QRgba64 solidColor; + QColor solidColor; union { QGradientData gradient; QTextureData texture; diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index ac321ccdb0..2afd9b9715 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -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(fontEngine->glyphCache(nullptr, glyphFormat, s->matrix, QColor(s->penData.solidColor))); + static_cast(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; } diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp index 45490ef815..cfcaf5b67e 100644 --- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp +++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp @@ -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"