diff options
author | Bjoern Erik Nilsen <bjorn.nilsen@nokia.com> | 2009-03-24 14:50:26 (GMT) |
---|---|---|
committer | Andreas Aardal Hanssen <andreas.aardal.hanssen@nokia.com> | 2009-04-06 11:49:47 (GMT) |
commit | 0d959a6c402ea3a3a55d7076d453d4bdbf8dce8e (patch) | |
tree | e62dfa5843fea4841e2ad781ed15dad94ddc9e8b /src/gui/graphicsview | |
parent | deccc867b244fbc52ca58e21623febbc27310b05 (diff) | |
download | Qt-0d959a6c402ea3a3a55d7076d453d4bdbf8dce8e.zip Qt-0d959a6c402ea3a3a55d7076d453d4bdbf8dce8e.tar.gz Qt-0d959a6c402ea3a3a55d7076d453d4bdbf8dce8e.tar.bz2 |
Fixes: Discard update requests if possible.
AutoTest: Still pass.
Details: Update requests can be discarded if the item itself is
clipped away and the item clips all its children to shape.
This cut-off is extremely effective (and aggressive:))
Diffstat (limited to 'src/gui/graphicsview')
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 54 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 9 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview.cpp | 2 |
3 files changed, 44 insertions, 21 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 75b6cf1..a5d6021 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1063,7 +1063,7 @@ void QGraphicsItem::setParentItem(QGraphicsItem *parent) qVariantSetValue<QGraphicsItem *>(variant, this); d_ptr->parent->itemChange(ItemChildAddedChange, variant); if (!implicitUpdate) - d_ptr->updateHelper(); + d_ptr->updateHelper(QRectF(), false, true); // Inherit ancestor flags from the new parent. d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1)); @@ -1092,7 +1092,7 @@ void QGraphicsItem::setParentItem(QGraphicsItem *parent) if (!d_ptr->enabled && !d_ptr->explicitlyDisabled) d_ptr->setEnabledHelper(true, /* explicit = */ false); - d_ptr->updateHelper(); + d_ptr->updateHelper(QRectF(), false, true); } if (d_ptr->scene) { @@ -1236,7 +1236,7 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) int geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations); bool fullUpdate = (flags & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask); if (fullUpdate) - d_ptr->fullUpdateHelper(); + d_ptr->fullUpdateHelper(false, true); // Keep the old flags to compare the diff. GraphicsItemFlags oldFlags = this->flags(); @@ -1281,7 +1281,7 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) } // ### Why updateHelper? - d_ptr->updateHelper(); + d_ptr->updateHelper(QRectF(), false, true); // Notify change. itemChange(ItemFlagsHaveChanged, quint32(flags)); @@ -2369,13 +2369,13 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos) // Update and repositition. inSetPosHelper = 1; + updateCachedClipPathFromSetPosHelper(newPos); if (scene) { fullUpdateHelper(true); q->prepareGeometryChange(); } this->pos = newPos; invalidateSceneTransformCache(); - updateCachedClipPathFromSetPosHelper(); // Send post-notification. q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPos); @@ -2771,7 +2771,7 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) return; // Update and set the new transformation. - d_ptr->fullUpdateHelper(true); + d_ptr->fullUpdateHelper(true, true); prepareGeometryChange(); d_ptr->hasTransform = !newTransform.isIdentity(); d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); @@ -2817,7 +2817,7 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) return; // Update and set the new transformation. - d_ptr->fullUpdateHelper(true); + d_ptr->fullUpdateHelper(true, true); prepareGeometryChange(); d_ptr->hasTransform = !newTransform.isIdentity(); d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform); @@ -3626,7 +3626,7 @@ void QGraphicsItem::setBoundingRegionGranularity(qreal granularity) only case where the item's background should be marked as dirty even when the item isn't visible. */ -void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force) +void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force, bool maybeDirtyClipPath) { // No scene, or if the scene is updating everything, means we have nothing // to do. The only exception is if the scene tracks the growing scene rect. @@ -3634,6 +3634,8 @@ void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force) return; if (!scene || (scene && scene->d_func()->updateAll && scene->d_func()->hasSceneRect)) return; + if (!force && !maybeDirtyClipPath && discardUpdateRequest()) + return; if (scene && (visible || force)) { if (rect.isNull()) dirty = 1; @@ -3646,17 +3648,19 @@ void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force) Propagates updates to \a item and all its children. */ -void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly) +void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly, bool maybeDirtyClipPath) { + if (!maybeDirtyClipPath && discardUpdateRequest()) + return; // No scene, or if the scene is updating everything, means we have nothing // to do. The only exception is if the scene tracks the growing scene rect. if (!scene || (scene && scene->d_func()->updateAll && scene->d_func()->hasSceneRect)) return; if (!childrenOnly && !dirty) - updateHelper(); + updateHelper(QRectF(), false, maybeDirtyClipPath); if (children.isEmpty() || dirtyChildren) return; - if (flags & QGraphicsItem::ItemClipsChildrenToShape) { + if (flags & QGraphicsItem::ItemClipsChildrenToShape || children.isEmpty()) { // ### mark all children dirty? // Unnecessary to update children as well. return; @@ -3683,7 +3687,7 @@ void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly) } } foreach (QGraphicsItem *child, children) - child->d_ptr->fullUpdateHelper(); + child->d_ptr->fullUpdateHelper(false, maybeDirtyClipPath); dirtyChildren = 1; } @@ -3813,23 +3817,35 @@ void QGraphicsItemPrivate::invalidateCachedClipPathRecursively(bool childrenOnly } } -void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper() +void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &newPos) { Q_ASSERT(inSetPosHelper); if (!(ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) return; // Not clipped by any ancestor. - // Find closest clip ancestor. + // Find closest clip ancestor and transform. + Q_Q(QGraphicsItem); + QTransform thisToParentTransform = hasTransform + ? q->transform() * QTransform::fromTranslate(newPos.x(), newPos.y()) + : QTransform::fromTranslate(newPos.x(), newPos.y()); QGraphicsItem *clipParent = parent; - while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) + while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) { + if (clipParent->d_ptr->hasTransform) + thisToParentTransform *= clipParent->transform(); + if (!clipParent->d_ptr->pos.isNull()) { + thisToParentTransform *= QTransform::fromTranslate(clipParent->d_ptr->pos.x(), + clipParent->d_ptr->pos.y()); + } clipParent = clipParent->d_ptr->parent; + } + // thisToParentTransform is now the same as q->itemTransform(clipParent), except + // that the new position (which is not yet set on the item) is taken into account. Q_ASSERT(clipParent); - Q_Q(QGraphicsItem); + Q_ASSERT(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); // From here everything is calculated in clip parent's coordinates. - const QTransform thisToParentTransform(q->itemTransform(clipParent)); const QRectF parentBoundingRect(clipParent->boundingRect()); const QRectF thisBoundingRect(thisToParentTransform.mapRect(q->boundingRect())); @@ -3894,6 +3910,8 @@ void QGraphicsItem::update(const QRectF &rect) { if (d_ptr->dirty || (rect.isEmpty() && !rect.isNull())) return; + if (d_ptr->discardUpdateRequest()) + return; if (d_ptr->scene && isVisible()) { if (CacheMode(d_ptr->cacheMode) != NoCache) { QGraphicsItemCache *cache = d_ptr->extraItemCache(); @@ -5639,7 +5657,7 @@ void QGraphicsItem::prepareGeometryChange() if (!d_ptr->scene) return; - d_ptr->updateHelper(); + d_ptr->updateHelper(QRectF(), false, /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper); QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); scenePrivate->removeFromIndex(this); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 3e4c269..dabbe53 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -164,8 +164,8 @@ public: void setPosHelper(const QPointF &pos); void setVisibleHelper(bool newVisible, bool explicitly, bool update = true); void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true); - void updateHelper(const QRectF &rect = QRectF(), bool force = false); - void fullUpdateHelper(bool childrenOnly = false); + void updateHelper(const QRectF &rect = QRectF(), bool force = false, bool maybeDirtyClipPath = false); + void fullUpdateHelper(bool childrenOnly = false, bool maybeDirtyClipPath = false); void resolveEffectiveOpacity(qreal effectiveParentOpacity); void resolveDepth(int parentDepth); void invalidateSceneTransformCache(); @@ -256,7 +256,7 @@ public: { /*static int count = 0 ;qWarning("%i", ++count);*/ dirtyClipPath = 1; emptyClipPath = 0; } void invalidateCachedClipPathRecursively(bool childrenOnly = false, const QRectF &emptyIfOutsideThisRect = QRectF()); - void updateCachedClipPathFromSetPosHelper(); + void updateCachedClipPathFromSetPosHelper(const QPointF &newPos); inline bool isInvisible() const { @@ -267,6 +267,9 @@ public: inline bool isClippedAway() const { return !dirtyClipPath && q_func()->isClipped() && (emptyClipPath || cachedClipPath.isEmpty()); } + inline bool discardUpdateRequest() const + { return ((flags & QGraphicsItem::ItemClipsChildrenToShape) || children.isEmpty()) && isClippedAway(); } + QPainterPath cachedClipPath; QPointF pos; qreal z; diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 9191fc5..43263da 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -855,6 +855,8 @@ void QGraphicsViewPrivate::_q_updateLaterSlot() const QList<QGraphicsItem *> &dirtyItems = scene->d_func()->dirtyItems; for (int i = 0; i < dirtyItems.size(); ++i) { const QGraphicsItem *item = dirtyItems.at(i); + if (item->d_ptr->discardUpdateRequest()) + continue; QTransform x = item->sceneTransform() * viewTransform; updateRect(x.mapRect(item->boundingRect()).toAlignedRect() & vr); } |