summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2010-04-26 07:40:19 (GMT)
committerBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2010-05-03 12:33:33 (GMT)
commit666cacd03d57da6a9caab5936f14c68d1c486e7e (patch)
tree4665bafee6942c454b00e9e0ea93d30fca2d129e /tests
parent28659c21d12a267b10e5b441bf4c776e04d69bdc (diff)
downloadQt-666cacd03d57da6a9caab5936f14c68d1c486e7e.zip
Qt-666cacd03d57da6a9caab5936f14c68d1c486e7e.tar.gz
Qt-666cacd03d57da6a9caab5936f14c68d1c486e7e.tar.bz2
QGraphicsView drawing artifacts due to rounding errors.
Found during investigation of QTBUG-8820, and clearly visible in examples/graphicsview/diagramscene when slowly moving an item out of the viewport (left and top edge). Caused by two problems: 1) Using QRectF::toRect() instead of QRectF::toAlignedRect(). 2) Didn't adjust the item's bounding rect properly in drawSubtree(). QRectF::toRect() is completely useless since all the coordinates are rounded to the nearest integer. E.g. QRectF(-0.4, -0.4, 10.4, 10.4).toRect() -> QRect(0, 0, 10, 10), whereas toAlignedRect() returns QRect(-1, -1, 11, 11). Then when we have a proper aligned rect, we have to adjust it by 2 pixels in all directions (or 1 pixel in case of QGraphicsView::DontAdjustForAntialiasing). At first glance this adjustment seems too much, since one would assume adjusing the QRectF by 0.5 before using toAlignedRect() would be sufficient. That's sufficient in an untransformed world with pens using BevelJoin. However, the story is completely different as soon as the world is transformed or the pens use a different join. It's basically complicated (in some cases impossible) to calculate a pixel perfect aligned QRect, so instead we adjust by the amount of pixels required in the worst case. This commit also includes some optimizations for QRegion updates (since I anyways had to change the code). There's no point in using QRegion granularity if the viewport update mode is either FullViewportUpdate or BoundingRectViewportUpdate. Auto tests adjusted and new ones included. Task-number: QTBUG-10338
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp14
-rw-r--r--tests/auto/qgraphicsview/tst_qgraphicsview.cpp123
2 files changed, 118 insertions, 19 deletions
diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
index 055ae80..81097be 100644
--- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
+++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
@@ -7293,7 +7293,7 @@ void tst_QGraphicsItem::update()
QCOMPARE(item->repaints, 1);
QCOMPARE(view.repaints, 1);
QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
- .mapRect(item->boundingRect()).toRect();
+ .mapRect(item->boundingRect()).toAlignedRect();
QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
// The entire item's bounding rect (adjusted for antialiasing) should have been painted.
QCOMPARE(view.paintedRegion, expectedRegion);
@@ -7372,7 +7372,7 @@ void tst_QGraphicsItem::update()
scene.addItem(parent);
QTest::qWait(50);
itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
- .mapRect(item->boundingRect()).toRect();
+ .mapRect(item->boundingRect()).toAlignedRect();
expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2);
view.reset();
item->repaints = 0;
@@ -7648,7 +7648,7 @@ void tst_QGraphicsItem::moveItem()
// Item's boundingRect: (-10, -10, 20, 20).
QRect parentDeviceBoundingRect = parent->deviceTransform(view.viewportTransform())
- .mapRect(parent->boundingRect()).toRect()
+ .mapRect(parent->boundingRect()).toAlignedRect()
.adjusted(-2, -2, 2, 2); // Adjusted for antialiasing.
parent->setPos(20, 20);
@@ -7711,8 +7711,14 @@ void tst_QGraphicsItem::moveLineItem()
QTest::qWait(200);
view.reset();
+ QRectF brect = item->boundingRect();
+ // Do same adjustments as in qgraphicsscene.cpp
+ if (!brect.width())
+ brect.adjust(qreal(-0.00001), 0, qreal(0.00001), 0);
+ if (!brect.height())
+ brect.adjust(0, qreal(-0.00001), 0, qreal(0.00001));
const QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform())
- .mapRect(item->boundingRect()).toRect();
+ .mapRect(brect).toAlignedRect();
QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); // antialiasing
// Make sure the calculated region is correct.
diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp
index d0752af..1df9a37 100644
--- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp
+++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp
@@ -216,6 +216,8 @@ private slots:
void exposeRegion();
void update_data();
void update();
+ void update2_data();
+ void update2();
void inputMethodSensitivity();
void inputContextReset();
void indirectPainting();
@@ -1383,28 +1385,48 @@ void tst_QGraphicsView::itemsInRect_cosmeticAdjust_data()
{
QTest::addColumn<QRect>("updateRect");
QTest::addColumn<int>("numPaints");
+ QTest::addColumn<bool>("adjustForAntialiasing");
- QTest::newRow("nil") << QRect() << 1;
- QTest::newRow("0, 0, 300, 100") << QRect(0, 0, 300, 100) << 1;
- QTest::newRow("0, 0, 100, 300") << QRect(0, 0, 100, 300) << 1;
- QTest::newRow("200, 0, 100, 300") << QRect(200, 0, 100, 300) << 1;
- QTest::newRow("0, 200, 300, 100") << QRect(0, 200, 300, 100) << 1;
- QTest::newRow("0, 0, 300, 99") << QRect(0, 0, 300, 99) << 0;
- QTest::newRow("0, 0, 99, 300") << QRect(0, 0, 99, 300) << 0;
- QTest::newRow("201, 0, 99, 300") << QRect(201, 0, 99, 300) << 0;
- QTest::newRow("0, 201, 300, 99") << QRect(0, 201, 300, 99) << 0;
+ // Aliased.
+ QTest::newRow("nil") << QRect() << 1 << false;
+ QTest::newRow("0, 0, 300, 100") << QRect(0, 0, 300, 100) << 1 << false;
+ QTest::newRow("0, 0, 100, 300") << QRect(0, 0, 100, 300) << 1 << false;
+ QTest::newRow("200, 0, 100, 300") << QRect(200, 0, 100, 300) << 1 << false;
+ QTest::newRow("0, 200, 300, 100") << QRect(0, 200, 300, 100) << 1 << false;
+ QTest::newRow("0, 0, 300, 99") << QRect(0, 0, 300, 99) << 0 << false;
+ QTest::newRow("0, 0, 99, 300") << QRect(0, 0, 99, 300) << 0 << false;
+ QTest::newRow("201, 0, 99, 300") << QRect(201, 0, 99, 300) << 0 << false;
+ QTest::newRow("0, 201, 300, 99") << QRect(0, 201, 300, 99) << 0 << false;
+
+ // Anti-aliased.
+ QTest::newRow("nil") << QRect() << 1 << true;
+ QTest::newRow("0, 0, 300, 100") << QRect(0, 0, 300, 100) << 1 << true;
+ QTest::newRow("0, 0, 100, 300") << QRect(0, 0, 100, 300) << 1 << true;
+ QTest::newRow("200, 0, 100, 300") << QRect(200, 0, 100, 300) << 1 << true;
+ QTest::newRow("0, 200, 300, 100") << QRect(0, 200, 300, 100) << 1 << true;
+ QTest::newRow("0, 0, 300, 99") << QRect(0, 0, 300, 99) << 1 << true;
+ QTest::newRow("0, 0, 99, 300") << QRect(0, 0, 99, 300) << 1 << true;
+ QTest::newRow("201, 0, 99, 300") << QRect(201, 0, 99, 300) << 1 << true;
+ QTest::newRow("0, 201, 300, 99") << QRect(0, 201, 300, 99) << 1 << true;
+ QTest::newRow("0, 0, 300, 98") << QRect(0, 0, 300, 98) << 0 << false;
+ QTest::newRow("0, 0, 98, 300") << QRect(0, 0, 98, 300) << 0 << false;
+ QTest::newRow("202, 0, 98, 300") << QRect(202, 0, 98, 300) << 0 << false;
+ QTest::newRow("0, 202, 300, 98") << QRect(0, 202, 300, 98) << 0 << false;
}
void tst_QGraphicsView::itemsInRect_cosmeticAdjust()
{
QFETCH(QRect, updateRect);
QFETCH(int, numPaints);
+ QFETCH(bool, adjustForAntialiasing);
QGraphicsScene scene(-100, -100, 200, 200);
CountPaintItem *rect = new CountPaintItem(QRectF(-50, -50, 100, 100));
scene.addItem(rect);
QGraphicsView view(&scene);
+ view.setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, !adjustForAntialiasing);
+ view.setRenderHint(QPainter::Antialiasing, adjustForAntialiasing);
view.setFrameStyle(0);
view.resize(300, 300);
view.show();
@@ -2219,8 +2241,8 @@ void tst_QGraphicsView::viewportUpdateMode()
QTRY_VERIFY(!view.lastUpdateRegions.isEmpty());
#ifndef QT_MAC_USE_COCOA //cocoa doesn't support drawing regions
QCOMPARE(view.lastUpdateRegions.last().rects().size(), 2);
- QCOMPARE(view.lastUpdateRegions.last().rects().at(0).size(), QSize(15, 15));
- QCOMPARE(view.lastUpdateRegions.last().rects().at(1).size(), QSize(15, 15));
+ QCOMPARE(view.lastUpdateRegions.last().rects().at(0).size(), QSize(14, 14));
+ QCOMPARE(view.lastUpdateRegions.last().rects().at(1).size(), QSize(14, 14));
#endif
// Set full update mode.
@@ -2254,7 +2276,7 @@ void tst_QGraphicsView::viewportUpdateMode()
// The view gets one bounding rect update.
QCOMPARE(view.lastUpdateRegions.last().rects().size(), 1);
- QCOMPARE(view.lastUpdateRegions.last().rects().at(0).size(), QSize(33, 33));
+ QCOMPARE(view.lastUpdateRegions.last().rects().at(0).size(), QSize(32, 32));
// Set no update mode
view.setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
@@ -3647,7 +3669,6 @@ void tst_QGraphicsView::update()
const bool intersects = updateRect.intersects(viewportRect);
QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(&view));
QTRY_COMPARE(viewPrivate->updateRect(updateRect), intersects);
- QCOMPARE(viewPrivate->updateRegion(updateRect), intersects);
view.lastUpdateRegions.clear();
viewPrivate->processPendingUpdates();
@@ -3658,13 +3679,85 @@ void tst_QGraphicsView::update()
QTRY_VERIFY(view.lastUpdateRegions.isEmpty());
} else {
QTRY_COMPARE(view.lastUpdateRegions.size(), 1);
- // Note that we adjust by 2 for antialiasing.
- QTRY_COMPARE(view.lastUpdateRegions.at(0), QRegion(updateRect.adjusted(-2, -2, 2, 2) & viewportRect));
+ QTRY_COMPARE(view.lastUpdateRegions.at(0), QRegion(updateRect) & viewportRect);
}
QTRY_VERIFY(!viewPrivate->fullUpdatePending);
#endif
}
+void tst_QGraphicsView::update2_data()
+{
+ QTest::addColumn<qreal>("penWidth");
+ QTest::addColumn<bool>("antialiasing");
+
+ // Anti-aliased.
+ QTest::newRow("pen width: 0.0, antialiasing: true") << 0.0 << true;
+ QTest::newRow("pen width: 1.5, antialiasing: true") << 1.5 << true;
+ QTest::newRow("pen width: 2.0, antialiasing: true") << 2.0 << true;
+ QTest::newRow("pen width: 3.0, antialiasing: true") << 3.0 << true;
+
+ // Aliased.
+ QTest::newRow("pen width: 0.0, antialiasing: false") << 0.0 << false;
+ QTest::newRow("pen width: 1.5, antialiasing: false") << 1.5 << false;
+ QTest::newRow("pen width: 2.0, antialiasing: false") << 2.0 << false;
+ QTest::newRow("pen width: 3.0, antialiasing: false") << 3.0 << false;
+}
+
+void tst_QGraphicsView::update2()
+{
+ QFETCH(qreal, penWidth);
+ QFETCH(bool, antialiasing);
+
+ // Create a rect item.
+ const QRectF rawItemRect(-50.4, -50.3, 100.2, 100.1);
+ CountPaintItem *rect = new CountPaintItem(rawItemRect);
+ QPen pen;
+ pen.setWidthF(penWidth);
+ rect->setPen(pen);
+
+ // Add item to a scene.
+ QGraphicsScene scene(-100, -100, 200, 200);
+ scene.addItem(rect);
+
+ // Create a view on the scene.
+ CustomView view(&scene);
+ view.setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, !antialiasing);
+ view.setRenderHint(QPainter::Antialiasing, antialiasing);
+ view.setFrameStyle(0);
+ view.resize(200, 200);
+ view.show();
+ QTest::qWaitForWindowShown(&view) ;
+ QTRY_VERIFY(rect->numPaints > 0);
+
+ // Calculate expected update region for the rect.
+ QRectF expectedItemBoundingRect = rawItemRect;
+ const qreal halfPenWidth = penWidth / qreal(2.0);
+ expectedItemBoundingRect.adjust(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth);
+ QCOMPARE(rect->boundingRect(), expectedItemBoundingRect);
+
+ QRect expectedItemDeviceBoundingRect = rect->deviceTransform(view.viewportTransform())
+ .mapRect(expectedItemBoundingRect).toAlignedRect();
+ if (antialiasing)
+ expectedItemDeviceBoundingRect.adjust(-2, -2, 2, 2);
+ else
+ expectedItemDeviceBoundingRect.adjust(-1, -1, 1, 1);
+ const QRegion expectedUpdateRegion(expectedItemDeviceBoundingRect);
+
+ // Reset.
+ rect->numPaints = 0;
+ view.lastUpdateRegions.clear();
+ view.painted = false;
+
+ rect->update();
+ QTRY_VERIFY(view.painted);
+
+#ifndef QT_MAC_USE_COCOA //cocoa doesn't support drawing regions
+ QTRY_VERIFY(view.painted);
+ QCOMPARE(view.lastUpdateRegions.size(), 1);
+ QCOMPARE(view.lastUpdateRegions.at(0), expectedUpdateRegion);
+#endif
+}
+
class FocusItem : public QGraphicsRectItem
{
public: