Fixed dashes being rendered differently depending on system clip.

We need to clip lines to the unclipped device rect in the case of
dashing, since otherwise the dashes will be shifted and rendered
differently when partial repaints are done.

Task-number: QTBUG-24762
Change-Id: I3599b54baa552acc20bf8cc2e12f846b45f6019e
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
This commit is contained in:
Samuel Rødal 2013-03-05 15:43:50 +01:00 committed by The Qt Project
parent 7128bcbbd5
commit a12f6ba302
5 changed files with 62 additions and 18 deletions

View File

@ -290,11 +290,14 @@ void QCosmeticStroker::setup()
ppl = buffer->bytesPerLine()>>2;
}
// dashes are sensitive to clips, so we need to clip consistently when painting to the same device
QRect clipRect = strokeSelection & Dashed ? deviceRect : clip;
// setup FP clip bounds
xmin = clip.left() - 1;
xmax = clip.right() + 2;
ymin = clip.top() - 1;
ymax = clip.bottom() + 2;
xmin = clipRect.left() - 1;
xmax = clipRect.right() + 2;
ymin = clipRect.top() - 1;
ymax = clipRect.bottom() + 2;
lastPixel.x = -1;
}

View File

@ -85,8 +85,9 @@ public:
HorizontalMask = 0xc
};
QCosmeticStroker(QRasterPaintEngineState *s, const QRect &dr)
QCosmeticStroker(QRasterPaintEngineState *s, const QRect &dr, const QRect &dr_unclipped)
: state(s),
deviceRect(dr_unclipped),
clip(dr),
pattern(0),
reversePattern(0),
@ -110,6 +111,7 @@ public:
QRasterPaintEngineState *state;
QRect deviceRect;
QRect clip;
// clip bounds in real
qreal xmin, xmax;

View File

@ -1054,20 +1054,20 @@ void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
void QRasterPaintEnginePrivate::systemStateChanged()
{
QRect clipRect(0, 0,
deviceRectUnclipped = QRect(0, 0,
qMin(QT_RASTER_COORD_LIMIT, device->width()),
qMin(QT_RASTER_COORD_LIMIT, device->height()));
if (!systemClip.isEmpty()) {
QRegion clippedDeviceRgn = systemClip & clipRect;
QRegion clippedDeviceRgn = systemClip & deviceRectUnclipped;
deviceRect = clippedDeviceRgn.boundingRect();
baseClip->setClipRegion(clippedDeviceRgn);
} else {
deviceRect = clipRect;
deviceRect = deviceRectUnclipped;
baseClip->setClipRect(deviceRect);
}
#ifdef QT_DEBUG_DRAW
qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << clipRect << systemClip;
qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << deviceRectUnclipped << systemClip;
#endif
exDeviceRect = deviceRect;
@ -1529,7 +1529,7 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
if (s->penData.blend) {
QRectVectorPath path;
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i = 0; i < rectCount; ++i) {
path.set(rects[i]);
@ -1576,7 +1576,7 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
if (s->penData.blend) {
QRectVectorPath path;
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i = 0; i < rectCount; ++i) {
path.set(rects[i]);
@ -1610,7 +1610,7 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
return;
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPath(path);
} else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
@ -1953,7 +1953,7 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly
if (s->penData.blend) {
QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPath(vp);
} else {
@ -2018,7 +2018,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg
QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPath(vp);
} else {
@ -3112,7 +3112,7 @@ void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
return;
}
QCosmeticStroker stroker(s, d->deviceRect);
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPoints(points, pointCount);
}
@ -3132,7 +3132,7 @@ void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
return;
}
QCosmeticStroker stroker(s, d->deviceRect);
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPoints(points, pointCount);
}
@ -3153,7 +3153,7 @@ void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
return;
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i=0; i<lineCount; ++i) {
const QLine &l = lines[i];
@ -3225,7 +3225,7 @@ void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
if (!s->penData.blend)
return;
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i=0; i<lineCount; ++i) {
QLineF line = lines[i];

View File

@ -323,6 +323,7 @@ public:
#endif
QRect deviceRect;
QRect deviceRectUnclipped;
QStroker basicStroker;
QScopedPointer<QDashStroker> dashStroker;

View File

@ -280,6 +280,7 @@ private slots:
void drawTextWithComplexBrush();
void QTBUG26013_squareCapStroke();
void QTBUG25153_drawLine();
void dashing_systemClip();
private:
void fillData();
@ -4461,6 +4462,43 @@ void tst_QPainter::QTBUG25153_drawLine()
}
}
static void dashing_systemClip_paint(QPainter *p)
{
p->setPen(QPen(Qt::black, 1, Qt::DashLine, Qt::RoundCap, Qt::MiterJoin));
p->drawLine(8, 8, 42, 8);
p->drawLine(42, 8, 42, 42);
p->drawLine(42, 42, 8, 42);
p->drawLine(8, 42, 8, 8);
}
void tst_QPainter::dashing_systemClip()
{
QImage image(50, 50, QImage::Format_RGB32);
image.fill(Qt::white);
QPainter p(&image);
dashing_systemClip_paint(&p);
p.end();
QImage old = image.copy();
image.paintEngine()->setSystemClip(QRect(10, 0, image.width() - 10, image.height()));
p.begin(&image);
dashing_systemClip_paint(&p);
// doing same paint operation again with different system clip should not change the image
QCOMPARE(old, image);
old = image;
p.setClipRect(QRect(20, 20, 30, 30));
dashing_systemClip_paint(&p);
// ditto for regular clips
QCOMPARE(old, image);
}
QTEST_MAIN(tst_QPainter)
#include "tst_qpainter.moc"