diff options
author | Bjørn Erik Nilsen <bjorn.nilsen@nokia.com> | 2010-04-26 07:40:19 (GMT) |
---|---|---|
committer | Bjørn Erik Nilsen <bjorn.nilsen@nokia.com> | 2010-05-03 12:33:33 (GMT) |
commit | 666cacd03d57da6a9caab5936f14c68d1c486e7e (patch) | |
tree | 4665bafee6942c454b00e9e0ea93d30fca2d129e /src/gui/graphicsview/qgraphicsscene.cpp | |
parent | 28659c21d12a267b10e5b441bf4c776e04d69bdc (diff) | |
download | Qt-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 'src/gui/graphicsview/qgraphicsscene.cpp')
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 44 |
1 files changed, 25 insertions, 19 deletions
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 8cee021..0d4e48a 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -297,6 +297,7 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() scenePosDescendantsUpdatePending(false), stickyFocus(false), hasFocus(false), + rectAdjust(2), focusItem(0), lastFocusItem(0), tabFocusFirst(0), @@ -3217,7 +3218,10 @@ void QGraphicsScene::update(const QRectF &rect) // Update all views. for (int i = 0; i < d->views.size(); ++i) { QGraphicsView *view = d->views.at(i); - view->d_func()->updateRegion(QRegion(view->mapFromScene(rect).boundingRect())); + if (view->isTransformed()) + view->d_func()->updateRectF(view->viewportTransform().mapRect(rect)); + else + view->d_func()->updateRectF(rect); } } else { d->updatedRects << rect; @@ -4701,11 +4705,11 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (drawItem) { const QRectF brect = adjustedItemEffectiveBoundingRect(item); ENSURE_TRANSFORM_PTR - QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect() - : transformPtr->mapRect(brect).toRect(); + QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toAlignedRect() + : transformPtr->mapRect(brect).toAlignedRect(); + viewBoundingRect.adjust(-rectAdjust, -rectAdjust, rectAdjust, rectAdjust); if (widget) item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); - viewBoundingRect.adjust(-1, -1, 1, 1); drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.normalized().isEmpty(); if (!drawItem) { @@ -4954,34 +4958,29 @@ static inline bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate if (itemIsUntransformable) { const QTransform xform = itemq->deviceTransform(viewq->viewportTransform()); if (!item->hasBoundingRegionGranularity) - return view->updateRect(xform.mapRect(rect).toRect()); - return view->updateRegion(xform.map(QRegion(rect.toRect()))); + return view->updateRectF(xform.mapRect(rect)); + return view->updateRegion(rect, xform); } if (item->sceneTransformTranslateOnly && view->identityMatrix) { const qreal dx = item->sceneTransform.dx(); const qreal dy = item->sceneTransform.dy(); - if (!item->hasBoundingRegionGranularity) { - QRectF r(rect); - r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll()); - return view->updateRect(r.toRect()); - } - QRegion r(rect.toRect()); - r.translate(qRound(dx) - view->horizontalScroll(), qRound(dy) - view->verticalScroll()); - return view->updateRegion(r); + QRectF r(rect); + r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll()); + return view->updateRectF(r); } if (!viewq->isTransformed()) { if (!item->hasBoundingRegionGranularity) - return view->updateRect(item->sceneTransform.mapRect(rect).toRect()); - return view->updateRegion(item->sceneTransform.map(QRegion(rect.toRect()))); + return view->updateRectF(item->sceneTransform.mapRect(rect)); + return view->updateRegion(rect, item->sceneTransform); } QTransform xform = item->sceneTransform; xform *= viewq->viewportTransform(); if (!item->hasBoundingRegionGranularity) - return view->updateRect(xform.mapRect(rect).toRect()); - return view->updateRegion(xform.map(QRegion(rect.toRect()))); + return view->updateRectF(xform.mapRect(rect)); + return view->updateRegion(rect, xform); } void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren, @@ -5197,8 +5196,14 @@ void QGraphicsScene::drawItems(QPainter *painter, // Determine view, expose and flags. QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0; QRegion *expose = 0; - if (view) + const quint32 oldRectAdjust = d->rectAdjust; + if (view) { expose = &view->d_func()->exposedRegion; + if (view->d_func()->optimizationFlags & QGraphicsView::DontAdjustForAntialiasing) + d->rectAdjust = 1; + else + d->rectAdjust = 2; + } // Find all toplevels, they are already sorted. QList<QGraphicsItem *> topLevelItems; @@ -5211,6 +5216,7 @@ void QGraphicsScene::drawItems(QPainter *painter, } } + d->rectAdjust = oldRectAdjust; // Reset discovery bits. for (int i = 0; i < topLevelItems.size(); ++i) topLevelItems.at(i)->d_ptr->itemDiscovered = 0; |