summaryrefslogtreecommitdiffstats
path: root/src/gui/painting/qpaintengine_raster.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting/qpaintengine_raster.cpp')
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp351
1 files changed, 162 insertions, 189 deletions
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 5ac1f748e5..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())
@@ -1742,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);
@@ -1819,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
*/
@@ -1830,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;
}
@@ -2293,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();
@@ -2316,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())) {
@@ -2396,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;
@@ -2637,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;
}
@@ -2679,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;
}
@@ -2707,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;
@@ -2875,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);
}
@@ -3012,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;
@@ -3046,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
+{
+ 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());
- QFixed clipRight = QFixed::fromReal(clip.right());
- QFixed clipTop = QFixed::fromReal(clip.top());
- QFixed clipBottom = QFixed::fromReal(clip.bottom());
+ 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) {
@@ -3076,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};
}
/*!
@@ -3102,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(&copy);
} else {
QPaintEngineEx::drawStaticTextItem(textItem);
@@ -3157,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);
@@ -3265,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;
@@ -3426,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;
@@ -3530,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);
@@ -3542,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)
@@ -3695,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);
@@ -3735,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);
}
@@ -3830,7 +3802,7 @@ 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 {
@@ -3842,7 +3814,7 @@ void QClipData::initialize()
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;
@@ -3868,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;
@@ -3892,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) {
@@ -3905,7 +3877,7 @@ void QClipData::initialize()
const int len = clipRect.width();
while (y < ymax) {
- QSpan *span = m_spans + count;
+ QT_FT_Span *span = m_spans + count;
span->x = xmin;
span->len = len;
span->y = y;
@@ -4044,16 +4016,16 @@ void QClipData::setClipRegion(const QRegion &region)
\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) {
@@ -4107,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, &currentClip, spans, end, &clipped, NSPANS);
// qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
// << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
@@ -4171,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);
@@ -4180,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);
@@ -4188,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);
@@ -4205,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, &currentClip, 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;
}
}
@@ -4230,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) {}
@@ -4241,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();
@@ -4273,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;
@@ -4292,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);
@@ -4498,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();
@@ -4506,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;
}
@@ -4605,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;
@@ -4892,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));