Fix floating point clip rectangle rounding in raster and opengl paint engine

Fixes: QTBUG-83229
Pick-to: 5.15
Change-Id: If94028f27c9085e391acb9c423cde1b7c12bca36
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
Jani Hautakangas 2013-12-12 21:48:35 +02:00 committed by Dominik Holland
parent 7e2fded55e
commit d9cc149995
4 changed files with 108 additions and 2 deletions

View File

@ -1251,7 +1251,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).toRect(), op))
if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toAlignedRect(), op))
return;
}
}

View File

@ -2496,7 +2496,7 @@ void QOpenGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
&& qFuzzyIsNull(state()->matrix.m11())
&& qFuzzyIsNull(state()->matrix.m22())))
{
state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect());
state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toAlignedRect());
d->updateClipScissorTest();
return;
}

View File

@ -138,6 +138,7 @@ private slots:
void disableEnableClipping();
void setClipRect();
void clipRect();
void setEqualClipRegionAndPath_data();
void setEqualClipRegionAndPath();
@ -1750,6 +1751,42 @@ void tst_QPainter::setClipRect()
}
}
/*
Verify that the clipping works correctly.
The red outline should be covered by the blue rect on top and left,
while it should be clipped on the right and bottom and thus the red outline be visible
See: QTBUG-83229
*/
void tst_QPainter::clipRect()
{
int width = 654;
int height = 480;
QRect rect(0, 0, width, height);
QImage image(width, height, QImage::Format_ARGB32);
QPainter p(&image);
qreal halfWidth = width / 2.0;
qreal halfHeight = height / 2.0;
QRectF clipRect = QRectF(halfWidth - halfWidth / 2.0, halfHeight - halfHeight / 2.0,
halfWidth / 2.0, halfHeight / 2.0);
p.fillRect(rect, Qt::white);
p.setPen(Qt::red);
p.drawRect(clipRect);
p.setClipRect(clipRect, Qt::ReplaceClip);
p.fillRect(rect, Qt::blue);
p.end();
QCOMPARE(image.pixelColor(clipRect.left() + 1, clipRect.top()), QColor(Qt::blue));
QCOMPARE(image.pixelColor(clipRect.left(), clipRect.top() + 1), QColor(Qt::blue));
QCOMPARE(image.pixelColor(clipRect.left() + 1, clipRect.bottom()), QColor(Qt::red));
QCOMPARE(image.pixelColor(clipRect.right(), clipRect.top() + 1), QColor(Qt::red));
}
/*
This tests the two different clipping approaches in QRasterPaintEngine,
one when using a QRegion and one when using a QPainterPath. They should

View File

@ -93,6 +93,7 @@ private slots:
void defaultSurfaceFormat();
void imageFormatPainting();
void nullTextureInitializtion();
void clipRect();
#ifdef USE_GLX
void glxContextWrap();
@ -1686,6 +1687,74 @@ void tst_QOpenGL::nullTextureInitializtion()
QVERIFY(!t.isCreated());
}
/*
Verify that the clipping works correctly.
The red outline should be covered by the blue rect on top and left,
while it should be clipped on the right and bottom and thus the red outline be visible
See: QTBUG-83229
*/
void tst_QOpenGL::clipRect()
{
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(__x86_64__)
QSKIP("QTBUG-22617");
#endif
QScopedPointer<QSurface> surface(createSurface(int(QSurface::Window)));
QOpenGLContext ctx;
QVERIFY(ctx.create());
QVERIFY(ctx.makeCurrent(surface.data()));
if (!QOpenGLFramebufferObject::hasOpenGLFramebufferObjects())
QSKIP("QOpenGLFramebufferObject not supported on this platform");
// No multisample with combined depth/stencil attachment:
QOpenGLFramebufferObjectFormat fboFormat;
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
// Uncomplicate things by using POT:
const QSize size(654, 480);
const QRect rect(QPoint(0, 0), size);
QOpenGLFramebufferObject fbo(size, fboFormat);
if (fbo.attachment() != QOpenGLFramebufferObject::CombinedDepthStencil)
QSKIP("FBOs missing combined depth~stencil support");
QVERIFY(fbo.bind());
QPainter fboPainter;
QOpenGLPaintDevice device(fbo.width(), fbo.height());
bool painterBegun = fboPainter.begin(&device);
QVERIFY(painterBegun);
qreal halfWidth = size.width() / 2.0;
qreal halfHeight = size.height() / 2.0;
QRectF clipRect = QRectF(halfWidth - halfWidth / 2.0, halfHeight - halfHeight / 2.0,
halfWidth / 2.0, halfHeight / 2.0);
fboPainter.fillRect(rect, Qt::white);
fboPainter.setPen(Qt::red);
fboPainter.drawRect(clipRect);
fboPainter.setClipRect(clipRect, Qt::ReplaceClip);
fboPainter.fillRect(rect, Qt::blue);
fboPainter.end();
const QImage fb = fbo.toImage().convertToFormat(QImage::Format_RGB32);
QCOMPARE(fb.size(), size);
QCOMPARE(fb.pixelColor(clipRect.left() + 1, clipRect.top()), QColor(Qt::blue));
QCOMPARE(fb.pixelColor(clipRect.left(), clipRect.top() + 1), QColor(Qt::blue));
QCOMPARE(fb.pixelColor(clipRect.left() + 1, clipRect.bottom()), QColor(Qt::red));
// Enable this once QTBUG-85286 is fixed
//QCOMPARE(fb.pixelColor(clipRect.right(), clipRect.top() + 1), QColor(Qt::red));
}
QTEST_MAIN(tst_QOpenGL)
#include "tst_qopengl.moc"