diff options
Diffstat (limited to 'src/gui/painting/qpaintengine_raster.cpp')
-rw-r--r-- | src/gui/painting/qpaintengine_raster.cpp | 385 |
1 files changed, 183 insertions, 202 deletions
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 26f8de5b8b..f62373d4ef 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include <QtCore/qglobal.h> #include <QtCore/qmutex.h> @@ -49,7 +13,7 @@ #include <qpainterpath.h> #include <qdebug.h> #include <qbitmap.h> -#include <qmath.h> +#include "qmath_p.h" #include <qrandom.h> // #include <private/qdatabuffer_p.h> @@ -134,7 +98,6 @@ public: Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp -#define qreal_to_fixed_26_6(f) (int(f * 64)) #define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; } #define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; } @@ -180,9 +143,9 @@ bool QRasterPaintEngine::clearTypeFontsEnabled() /******************************************************************************** * Span functions */ -static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData); -static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData); -static void qt_span_clip(int count, const QSpan *spans, void *userData); +static void qt_span_fill_clipRect(int count, const QT_FT_Span *spans, void *userData); +static void qt_span_fill_clipped(int count, const QT_FT_Span *spans, void *userData); +static void qt_span_clip(int count, const QT_FT_Span *spans, void *userData); struct ClipData { @@ -277,8 +240,7 @@ QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() : /*! \class QRasterPaintEngine - \preliminary - \ingroup qws + \internal \inmodule QtGui \since 4.2 @@ -313,15 +275,6 @@ QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() : */ /*! - \typedef QSpan - \relates QRasterPaintEngine - - A struct equivalent to QT_FT_Span, containing a position (x, - y), the span's length in pixels and its color/coverage (a value - ranging from 0 to 255). -*/ - -/*! \since 4.5 Creates a raster based paint engine for operating on the given @@ -452,22 +405,16 @@ bool QRasterPaintEngine::begin(QPaintDevice *device) QRasterPaintEngineState *s = state(); ensureOutlineMapper(); - d->outlineMapper->m_clip_rect = d->deviceRect; - - if (d->outlineMapper->m_clip_rect.width() > QT_RASTER_COORD_LIMIT) - d->outlineMapper->m_clip_rect.setWidth(QT_RASTER_COORD_LIMIT); - if (d->outlineMapper->m_clip_rect.height() > QT_RASTER_COORD_LIMIT) - d->outlineMapper->m_clip_rect.setHeight(QT_RASTER_COORD_LIMIT); - + d->outlineMapper->setClipRect(d->deviceRect); d->rasterizer->setClipRect(d->deviceRect); s->penData.init(d->rasterBuffer.data(), this); - s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode); + s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode, s->flags.cosmetic_brush); s->stroker = &d->basicStroker; d->basicStroker.setClipRect(d->deviceRect); s->brushData.init(d->rasterBuffer.data(), this); - s->brushData.setup(s->brush, s->intOpacity, s->composition_mode); + s->brushData.setup(s->brush, s->intOpacity, s->composition_mode, s->flags.cosmetic_brush); d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver; @@ -526,31 +473,6 @@ void QRasterPaintEngine::updateMatrix(const QTransform &matrix) QRasterPaintEngineState *s = state(); // FALCON: get rid of this line, see drawImage call below. s->matrix = matrix; - QTransform::TransformationType txop = s->matrix.type(); - - switch (txop) { - - case QTransform::TxNone: - s->flags.int_xform = true; - break; - - case QTransform::TxTranslate: - s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx() - && qreal(int(s->matrix.dy())) == s->matrix.dy(); - break; - - case QTransform::TxScale: - s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx() - && qreal(int(s->matrix.dy())) == s->matrix.dy() - && qreal(int(s->matrix.m11())) == s->matrix.m11() - && qreal(int(s->matrix.m22())) == s->matrix.m22(); - break; - - default: // shear / perspective... - s->flags.int_xform = false; - break; - } - s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale); ensureOutlineMapper(); @@ -577,14 +499,15 @@ QRasterPaintEngineState::QRasterPaintEngineState() txscale = 1.; + flag_bits = 0; flags.fast_pen = true; flags.non_complex_pen = false; flags.antialiased = false; flags.bilinear = false; flags.fast_text = true; - flags.int_xform = true; flags.tx_noshear = true; flags.fast_images = true; + flags.cosmetic_brush = true; clip = nullptr; flags.has_clip_ownership = false; @@ -683,7 +606,8 @@ void QRasterPaintEngine::updatePen(const QPen &pen) s->strokeFlags = 0; s->penData.clip = d->clip(); - s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode); + s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, + s->composition_mode, s->flags.cosmetic_brush); if (s->strokeFlags & QRasterPaintEngine::DirtyTransform || pen.brush().transform().type() >= QTransform::TxNone) { @@ -782,7 +706,7 @@ void QRasterPaintEngine::updateBrush(const QBrush &brush) QRasterPaintEngineState *s = state(); // must set clip prior to setup, as setup uses it... s->brushData.clip = d->clip(); - s->brushData.setup(brush, s->intOpacity, s->composition_mode); + s->brushData.setup(brush, s->intOpacity, s->composition_mode, s->flags.cosmetic_brush); if (s->fillFlags & DirtyTransform || brush.transform().type() >= QTransform::TxNone) d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix()); @@ -809,7 +733,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; @@ -868,20 +793,25 @@ void QRasterPaintEngine::renderHintsChanged() bool was_aa = s->flags.antialiased; bool was_bilinear = s->flags.bilinear; + bool was_cosmetic_brush = s->flags.cosmetic_brush; s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing); s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform); + s->flags.cosmetic_brush = !bool(s->renderHints & QPainter::NonCosmeticBrushPatterns); if (was_aa != s->flags.antialiased) s->strokeFlags |= DirtyHints; - if (was_bilinear != s->flags.bilinear) { + if (was_bilinear != s->flags.bilinear || was_cosmetic_brush != s->flags.cosmetic_brush) { s->strokeFlags |= DirtyPen; s->fillFlags |= DirtyBrush; } Q_D(QRasterPaintEngine); d->recalculateFastImages(); + + if (was_aa != s->flags.antialiased) + d->updateClipping(); } /*! @@ -969,7 +899,7 @@ void QRasterPaintEnginePrivate::drawImage(const QPointF &pt, if (iw <= 0) return; - // adapt the y paremeters... + // adapt the y parameters... int cy1 = clip.y(); int cy2 = clip.y() + clip.height(); int y = qRound(pt.y()); @@ -1039,7 +969,7 @@ void QRasterPaintEnginePrivate::blitImage(const QPointF &pt, if (iw <= 0) return; - // adapt the y paremeters... + // adapt the y parameters... int cy1 = clip.y(); int cy2 = clip.y() + clip.height(); int y = qRound(pt.y()); @@ -1217,7 +1147,7 @@ void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) #endif const qreal *points = path.points(); QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]); - if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toAlignedRect(), op)) + if (setClipRectInDeviceCoords(qt_mapFillRect(r, s->matrix), op)) return; } } @@ -1276,7 +1206,7 @@ void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) QPaintEngineEx::clip(rect, op); return; - } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(QRectF(rect)).toRect(), op)) { + } else if (!setClipRectInDeviceCoords(qt_mapFillRect(rect, s->matrix), op)) { QPaintEngineEx::clip(rect, op); return; } @@ -1469,16 +1399,17 @@ 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; } } ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend; - const int nspans = 256; + const int nspans = 512; QT_FT_Span spans[nspans]; Q_ASSERT(data->blend); @@ -1633,8 +1564,9 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) patternLength += pattern.at(i); if (patternLength > 0) { - int n = qFloor(dashOffset / patternLength); - dashOffset -= n * patternLength; + dashOffset = std::fmod(dashOffset, patternLength); + if (dashOffset < 0) + dashOffset += patternLength; while (dashOffset >= pattern.at(dashIndex)) { dashOffset -= pattern.at(dashIndex); if (++dashIndex >= pattern.size()) @@ -1649,17 +1581,18 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) const QLineF *lines = reinterpret_cast<const QLineF *>(path.points()); for (int i = 0; i < lineCount; ++i) { - if (lines[i].p1() == lines[i].p2()) { + const QLineF line = s->matrix.map(lines[i]); + if (line.p1() == line.p2()) { if (s->lastPen.capStyle() != Qt::FlatCap) { QPointF p = lines[i].p1(); - QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()), + QLineF mappedline = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()), QPointF(p.x() + width*0.5, p.y()))); - d->rasterizer->rasterizeLine(line.p1(), line.p2(), width / line.length()); + d->rasterizer->rasterizeLine(mappedline.p1(), mappedline.p2(), + width / mappedline.length()); } continue; } - const QLineF line = s->matrix.map(lines[i]); if (qpen_style(s->lastPen) == Qt::SolidLine) { d->rasterizer->rasterizeLine(line.p1(), line.p2(), width / line.length(), @@ -1741,7 +1674,7 @@ void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush) QRectF cpRect = path.controlPointRect(); const QRectF pathDeviceRect = s->matrix.mapRect(cpRect); // Skip paths that by conservative estimates are completely outside the paint device. - if (!pathDeviceRect.intersects(QRectF(d->deviceRect))) + if (!pathDeviceRect.intersects(QRectF(d->deviceRect)) || !pathDeviceRect.isValid()) return; ProcessSpans blend = d->getBrushFunc(pathDeviceRect, &s->brushData); @@ -1818,6 +1751,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 */ @@ -1829,9 +1775,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; } @@ -2292,7 +2238,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(); @@ -2315,6 +2261,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)) { RotationType rotationType = qRotationType(s->matrix); + Q_ASSERT(d->rasterBuffer->format < QImage::NImageFormats); const QPixelLayout::BPP plBpp = qPixelLayouts[d->rasterBuffer->format].bpp; if (rotationType != NoRotation && qMemRotateFunctions[plBpp][rotationType] && img.rect().contains(sr.toAlignedRect())) { @@ -2357,15 +2304,20 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe QRectF targetBounds = s->matrix.mapRect(r); bool exceedsPrecision = r.width() > 0x7fff || r.height() > 0x7fff + || targetBounds.left() < -0x7fff + || targetBounds.top() < -0x7fff + || targetBounds.right() > 0x7fff + || targetBounds.bottom() > 0x7fff || targetBounds.width() > 0x7fff || targetBounds.height() > 0x7fff || s->matrix.m11() >= 512 || s->matrix.m22() >= 512; - if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) { if (s->matrix.type() > QTransform::TxScale) { SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()]; - if (func && (!clip || clip->hasRectClip)) { + // The fast transform methods doesn't really work on small targets, see QTBUG-93475 + // And it can't antialias the edges + if (func && (!clip || clip->hasRectClip) && !s->flags.antialiased && targetBounds.width() >= 16 && targetBounds.height() >= 16) { func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(), img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect, s->matrix, s->intOpacity); @@ -2390,9 +2342,16 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe } SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()]; if (func && (!clip || clip->hasRectClip)) { + QRectF tr = qt_mapRect_non_normalizing(r, s->matrix); + if (!s->flags.antialiased) { + tr.setX(qRound(tr.x())); + tr.setY(qRound(tr.y())); + tr.setWidth(qRound(tr.width())); + tr.setHeight(qRound(tr.height())); + } func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(), img.bytesPerLine(), img.height(), - qt_mapRect_non_normalizing(r, s->matrix), sr, + tr, sr, !clip ? d->deviceRect : clip->clipRect, s->intOpacity); return; @@ -2590,6 +2549,8 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx return; QRasterBuffer *rb = d->rasterBuffer.data(); + if (rb->colorSpace.transferFunction() == QColorSpace::TransferFunction::Linear) + useGammaCorrection = false; const QRect rect(rx, ry, w, h); const QClipData *clip = d->clip(); @@ -2629,20 +2590,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; } @@ -2671,10 +2632,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; } @@ -2699,8 +2660,8 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx if (w <= 0 || h <= 0) return; - const int NSPANS = 256; - QSpan spans[NSPANS]; + const int NSPANS = 512; + QT_FT_Span spans[NSPANS]; int current = 0; const int x1 = x0 + w; @@ -2867,9 +2828,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); } @@ -3004,7 +2965,7 @@ inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect, int penWidth) const { const QRectF norm = rect.normalized(); - if (norm.left() < INT_MIN || norm.top() < INT_MIN + if (norm.left() <= INT_MIN || norm.top() <= INT_MIN || norm.right() > INT_MAX || norm.bottom() > INT_MAX || norm.width() > INT_MAX || norm.height() > INT_MAX) return false; @@ -3038,13 +2999,19 @@ QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect, return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend; } -static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine, - glyph_t *glyphs, QFixedPoint *positions, int numGlyphs) +struct VisibleGlyphRange { - QFixed clipLeft = QFixed::fromReal(clip.left()); - QFixed clipRight = QFixed::fromReal(clip.right()); - QFixed clipTop = QFixed::fromReal(clip.top()); - QFixed clipBottom = QFixed::fromReal(clip.bottom()); + int begin; + int end; +}; + +static VisibleGlyphRange visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine, + glyph_t *glyphs, QFixedPoint *positions, int numGlyphs) +{ + QFixed clipLeft = QFixed::fromReal(clip.left() - 1); + QFixed clipRight = QFixed::fromReal(clip.right() + 1); + QFixed clipTop = QFixed::fromReal(clip.top() - 1); + QFixed clipBottom = QFixed::fromReal(clip.bottom() + 1); int first = 0; while (first < numGlyphs) { @@ -3068,7 +3035,7 @@ static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEn break; --last; } - return QPair<int, int>(first, last + 1); + return {first, last + 1}; } /*! @@ -3094,13 +3061,13 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) if (!invertible) return; - QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()), - textItem->fontEngine(), textItem->glyphs, - textItem->glyphPositions, textItem->numGlyphs); + const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()), + textItem->fontEngine(), textItem->glyphs, + textItem->glyphPositions, textItem->numGlyphs); QStaticTextItem copy = *textItem; - copy.glyphs += range.first; - copy.glyphPositions += range.first; - copy.numGlyphs = range.second - range.first; + copy.glyphs += range.begin; + copy.glyphPositions += range.begin; + copy.numGlyphs = range.end - range.begin; QPaintEngineEx::drawStaticTextItem(©); } else { QPaintEngineEx::drawStaticTextItem(textItem); @@ -3149,20 +3116,20 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()), ti.flags, glyphs, positions); - QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()), - ti.fontEngine, glyphs.data(), positions.data(), - glyphs.size()); + const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()), + ti.fontEngine, glyphs.data(), positions.data(), + glyphs.size()); - if (range.first >= range.second) + if (range.begin >= range.end) return; QStaticTextItem staticTextItem; staticTextItem.color = s->pen.color(); staticTextItem.font = s->font; staticTextItem.setFontEngine(ti.fontEngine); - staticTextItem.numGlyphs = range.second - range.first; - staticTextItem.glyphs = glyphs.data() + range.first; - staticTextItem.glyphPositions = positions.data() + range.first; + staticTextItem.numGlyphs = range.end - range.begin; + staticTextItem.glyphs = glyphs.data() + range.begin; + staticTextItem.glyphPositions = positions.data() + range.begin; QPaintEngineEx::drawStaticTextItem(&staticTextItem); } else { QPaintEngineEx::drawTextItem(p, ti); @@ -3257,6 +3224,11 @@ void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line, qreal length = line.length(); Q_ASSERT(length > 0); + if (length / (patternLength * width) > QDashStroker::repetitionLimit()) { + rasterizer->rasterizeLine(line.p1(), line.p2(), width / length, squareCap); + return; + } + while (length > 0) { const bool rasterize = *inDash; qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width; @@ -3418,23 +3390,25 @@ void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSp Q_ASSERT(image.depth() == 1); - const int spanCount = 256; + const int spanCount = 512; QT_FT_Span spans[spanCount]; int n = 0; // Boundaries int w = image.width(); int h = image.height(); - int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height()); - int ymin = qMax(qRound(pos.y()), 0); - int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width()); - int xmin = qMax(qRound(pos.x()), 0); + int px = qRound(pos.x()); + int py = qRound(pos.y()); + int ymax = qMin(py + h, d->rasterBuffer->height()); + int ymin = qMax(py, 0); + int xmax = qMin(px + w, d->rasterBuffer->width()); + int xmin = qMax(px, 0); - int x_offset = xmin - qRound(pos.x()); + int x_offset = xmin - px; QImage::Format format = image.format(); for (int y = ymin; y < ymax; ++y) { - const uchar *src = image.scanLine(y - qRound(pos.y())); + const uchar *src = image.scanLine(y - py); if (format == QImage::Format_MonoLSB) { for (int x = 0; x < xmax - xmin; ++x) { int src_x = x + x_offset; @@ -3522,7 +3496,7 @@ QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const \internal Returns the bounding rect of the currently set clip. */ -QRect QRasterPaintEngine::clipBoundingRect() const +QRectF QRasterPaintEngine::clipBoundingRect() const { Q_D(const QRasterPaintEngine); @@ -3534,7 +3508,7 @@ QRect QRasterPaintEngine::clipBoundingRect() const if (clip->hasRectClip) return clip->clipRect; - return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin); + return QRectF(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin); } void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data) @@ -3687,6 +3661,18 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline, free(rasterPoolOnHeap); } +void QRasterPaintEnginePrivate::updateClipping() +{ + Q_Q(QRasterPaintEngine); + QRasterPaintEngineState *s = q->state(); + + if (!s->clipEnabled) + return; + + qrasterpaintengine_state_setNoClip(s); + replayClipOperations(); +} + void QRasterPaintEnginePrivate::recalculateFastImages() { Q_Q(QRasterPaintEngine); @@ -3727,15 +3713,9 @@ bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mo QImage::Format dFormat = rasterBuffer->format; QImage::Format sFormat = image.format(); - // Formats must match or source format must be a subset of destination format - if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha) { - if ((sFormat == QImage::Format_RGB32 && dFormat == QImage::Format_ARGB32) - || (sFormat == QImage::Format_RGBX8888 && dFormat == QImage::Format_RGBA8888) - || (sFormat == QImage::Format_RGBX64 && dFormat == QImage::Format_RGBA64)) - sFormat = dFormat; - else - sFormat = qt_maybeAlphaVersionWithSameDepth(sFormat); // this returns premul formats - } + // Formats must match or source format must be an opaque version of destination format + if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha) + dFormat = qt_maybeDataCompatibleOpaqueVersion(dFormat); return (dFormat == sFormat); } @@ -3745,6 +3725,8 @@ QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color) const QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB); QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied); + if (sourceImage.isNull() || dest.isNull()) + return image; // we must have run out of memory QRgb fg = qPremultiply(color.rgba()); QRgb bg = 0; @@ -3754,8 +3736,6 @@ QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color) for (int y=0; y<height; ++y) { const uchar *source = sourceImage.constScanLine(y); QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y)); - if (!source || !target) - QT_THROW(std::bad_alloc()); // we must have run out of memory for (int x=0; x < width; ++x) target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg; } @@ -3783,6 +3763,7 @@ QImage::Format QRasterBuffer::prepare(QImage *image) bytes_per_line = image->bytesPerLine(); format = image->format(); + colorSpace = image->colorSpace(); if (image->depth() == 1 && image->colorTable().size() == 2) { monoDestinationWithClut = true; const QList<QRgb> colorTable = image->colorTable(); @@ -3821,23 +3802,23 @@ void QClipData::initialize() return; if (!m_clipLines) - m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight); + m_clipLines = (ClipLine *)calloc(clipSpanHeight, sizeof(ClipLine)); Q_CHECK_PTR(m_clipLines); QT_TRY { allocated = clipSpanHeight; + count = 0; QT_TRY { if (hasRegionClip) { const auto rects = clipRegion.begin(); const int numRects = clipRegion.rectCount(); const int maxSpans = (ymax - ymin) * numRects; allocated = qMax(allocated, maxSpans); - m_spans = (QSpan *)malloc(allocated * sizeof(QSpan)); + m_spans = (QT_FT_Span *)malloc(allocated * sizeof(QT_FT_Span)); Q_CHECK_PTR(m_spans); int y = 0; int firstInBand = 0; - count = 0; while (firstInBand < numRects) { const int currMinY = rects[firstInBand].y(); const int currMaxY = currMinY + rects[firstInBand].height(); @@ -3859,7 +3840,7 @@ void QClipData::initialize() for (int r = firstInBand; r <= lastInBand; ++r) { const QRect &currRect = rects[r]; - QSpan *span = m_spans + count; + QT_FT_Span *span = m_spans + count; span->x = currRect.x(); span->len = currRect.width(); span->y = y; @@ -3883,7 +3864,7 @@ void QClipData::initialize() return; } - m_spans = (QSpan *)malloc(allocated * sizeof(QSpan)); + m_spans = (QT_FT_Span *)malloc(allocated * sizeof(QT_FT_Span)); Q_CHECK_PTR(m_spans); if (hasRectClip) { @@ -3895,9 +3876,8 @@ void QClipData::initialize() } const int len = clipRect.width(); - count = 0; while (y < ymax) { - QSpan *span = m_spans + count; + QT_FT_Span *span = m_spans + count; span->x = xmin; span->len = len; span->y = y; @@ -4036,16 +4016,16 @@ void QClipData::setClipRegion(const QRegion ®ion) \internal spans must be sorted on y */ -static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip, - const QSpan *spans, const QSpan *end, - QSpan **outSpans, int available) +static const QT_FT_Span *qt_intersect_spans(const QClipData *clip, int *currentClip, + const QT_FT_Span *spans, const QT_FT_Span *end, + QT_FT_Span **outSpans, int available) { const_cast<QClipData *>(clip)->initialize(); - QSpan *out = *outSpans; + QT_FT_Span *out = *outSpans; - const QSpan *clipSpans = clip->m_spans + *currentClip; - const QSpan *clipEnd = clip->m_spans + clip->count; + const QT_FT_Span *clipSpans = clip->m_spans + *currentClip; + const QT_FT_Span *clipEnd = clip->m_spans + clip->count; while (available && spans < end ) { if (clipSpans >= clipEnd) { @@ -4099,19 +4079,19 @@ static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip, return spans; } -static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData) +static void qt_span_fill_clipped(int spanCount, const QT_FT_Span *spans, void *userData) { // qDebug() << "qt_span_fill_clipped" << spanCount; QSpanData *fillData = reinterpret_cast<QSpanData *>(userData); Q_ASSERT(fillData->blend && fillData->unclipped_blend); - const int NSPANS = 256; - QSpan cspans[NSPANS]; + const int NSPANS = 512; + QT_FT_Span cspans[NSPANS]; int currentClip = 0; - const QSpan *end = spans + spanCount; + const QT_FT_Span *end = spans + spanCount; while (spans < end) { - QSpan *clipped = cspans; + QT_FT_Span *clipped = cspans; spans = qt_intersect_spans(fillData->clip, ¤tClip, spans, end, &clipped, NSPANS); // qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans // << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage; @@ -4163,7 +4143,7 @@ static int qt_intersect_spans(QT_FT_Span *&spans, int numSpans, } -static void qt_span_fill_clipRect(int count, const QSpan *spans, +static void qt_span_fill_clipRect(int count, const QT_FT_Span *spans, void *userData) { QSpanData *fillData = reinterpret_cast<QSpanData *>(userData); @@ -4172,7 +4152,7 @@ static void qt_span_fill_clipRect(int count, const QSpan *spans, Q_ASSERT(fillData->clip); Q_ASSERT(!fillData->clip->clipRect.isEmpty()); - QSpan *s = const_cast<QSpan *>(spans); + QT_FT_Span *s = const_cast<QT_FT_Span *>(spans); // hw: check if this const_cast<> is safe!!! count = qt_intersect_spans(s, count, fillData->clip->clipRect); @@ -4180,7 +4160,7 @@ static void qt_span_fill_clipRect(int count, const QSpan *spans, fillData->unclipped_blend(count, s, fillData); } -static void qt_span_clip(int count, const QSpan *spans, void *userData) +static void qt_span_clip(int count, const QT_FT_Span *spans, void *userData) { ClipData *clipData = reinterpret_cast<ClipData *>(userData); @@ -4197,14 +4177,14 @@ static void qt_span_clip(int count, const QSpan *spans, void *userData) newClip->initialize(); int currentClip = 0; - const QSpan *end = spans + count; + const QT_FT_Span *end = spans + count; while (spans < end) { - QSpan *newspans = newClip->m_spans + newClip->count; + QT_FT_Span *newspans = newClip->m_spans + newClip->count; spans = qt_intersect_spans(clipData->oldClip, ¤tClip, spans, end, &newspans, newClip->allocated - newClip->count); newClip->count = newspans - newClip->m_spans; if (spans < end) { - newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan))); + newClip->m_spans = q_check_ptr((QT_FT_Span *)realloc(newClip->m_spans, newClip->allocated * 2 * sizeof(QT_FT_Span))); newClip->allocated *= 2; } } @@ -4222,7 +4202,7 @@ static void qt_span_clip(int count, const QSpan *spans, void *userData) class QGradientCache { public: - struct CacheInfo : QSpanData::Pinnable + struct CacheInfo { inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) : stops(std::move(s)), opacity(op), interpolationMode(mode) {} @@ -4233,9 +4213,9 @@ public: QGradient::InterpolationMode interpolationMode; }; - typedef QMultiHash<quint64, QSharedPointer<const CacheInfo>> QGradientColorTableHash; + using QGradientColorTableHash = QMultiHash<quint64, std::shared_ptr<const CacheInfo>>; - inline QSharedPointer<const CacheInfo> getBuffer(const QGradient &gradient, int opacity) { + std::shared_ptr<const CacheInfo> getBuffer(const QGradient &gradient, int opacity) { quint64 hash_val = 0; const QGradientStops stops = gradient.stops(); @@ -4265,16 +4245,16 @@ protected: inline void generateGradientColorTable(const QGradient& g, QRgba64 *colorTable, int size, int opacity) const; - QSharedPointer<const CacheInfo> addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) { + std::shared_ptr<const CacheInfo> addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) { if (cache.size() == maxCacheSize()) { // may remove more than 1, but OK cache.erase(std::next(cache.begin(), QRandomGenerator::global()->bounded(maxCacheSize()))); } - auto cache_entry = QSharedPointer<CacheInfo>::create(gradient.stops(), opacity, gradient.interpolationMode()); + auto cache_entry = std::make_shared<CacheInfo>(gradient.stops(), opacity, gradient.interpolationMode()); generateGradientColorTable(gradient, cache_entry->buffer64, paletteSize(), opacity); for (int i = 0; i < GRADIENT_STOPTABLE_SIZE; ++i) cache_entry->buffer32[i] = cache_entry->buffer64[i].toArgb32(); - return cache.insert(hash_val, cache_entry).value(); + return cache.insert(hash_val, std::move(cache_entry)).value(); } QGradientColorTableHash cache; @@ -4284,7 +4264,7 @@ protected: void QGradientCache::generateGradientColorTable(const QGradient& gradient, QRgba64 *colorTable, int size, int opacity) const { const QGradientStops stops = gradient.stops(); - int stopCount = stops.count(); + int stopCount = stops.size(); Q_ASSERT(stopCount > 0); bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); @@ -4490,7 +4470,8 @@ void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe) Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert); -void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode) +void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode, + bool isCosmetic) { Qt::BrushStyle brushStyle = qbrush_style(brush); cachedGradient.reset(); @@ -4498,8 +4479,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; } @@ -4512,7 +4493,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha); gradient.colorTable32 = cacheInfo->buffer32; -#if QT_CONFIG(raster_64bit) +#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp) gradient.colorTable64 = cacheInfo->buffer64; #endif cachedGradient = std::move(cacheInfo); @@ -4536,7 +4517,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha); gradient.colorTable32 = cacheInfo->buffer32; -#if QT_CONFIG(raster_64bit) +#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp) gradient.colorTable64 = cacheInfo->buffer64; #endif cachedGradient = std::move(cacheInfo); @@ -4564,7 +4545,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha); gradient.colorTable32 = cacheInfo->buffer32; -#if QT_CONFIG(raster_64bit) +#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp) gradient.colorTable64 = cacheInfo->buffer64; #endif cachedGradient = std::move(cacheInfo); @@ -4597,7 +4578,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode if (!tempImage) tempImage = new QImage(); *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color()); - initTexture(tempImage, alpha, QTextureData::Pattern); + initTexture(tempImage, alpha, isCosmetic ? QTextureData::Pattern : QTextureData::Tiled); break; case Qt::TexturePattern: type = Texture; @@ -4884,7 +4865,7 @@ void dumpClip(int width, int height, const QClipData *clip) ((QClipData *) clip)->spans(); // Force allocation of the spans structure... for (int i = 0; i < clip->count; ++i) { - const QSpan *span = ((QClipData *) clip)->spans() + i; + const QT_FT_Span *span = ((QClipData *) clip)->spans() + i; for (int j = 0; j < span->len; ++j) clipImg.setPixel(span->x + j, span->y, 0xffffff00); x0 = qMin(x0, int(span->x)); |