summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview/qgraphicsitem.cpp
diff options
context:
space:
mode:
authorBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2009-06-02 16:53:42 (GMT)
committerAndreas Aardal Hanssen <andreas.aardal.hanssen@nokia.com>2009-06-09 07:32:06 (GMT)
commit95949e7ef88eb14b7b22b06d235603f8581f6aa0 (patch)
tree7290a91ce86144cced01d268af39c5b89c3f62c2 /src/gui/graphicsview/qgraphicsitem.cpp
parent6887a89b0e0ee7a0eaff2adc34ae71ab01e2ba2f (diff)
downloadQt-95949e7ef88eb14b7b22b06d235603f8581f6aa0.zip
Qt-95949e7ef88eb14b7b22b06d235603f8581f6aa0.tar.gz
Qt-95949e7ef88eb14b7b22b06d235603f8581f6aa0.tar.bz2
Cache QGrahicsItem's scene transform.
Invalidating the scene transform is just a matter of setting a bit on the item. Then, when we ask for the item's scene transform, we traverse its ancestors recursively and find the top-most dirty item. The algorithm then backtracks to that item and start calculating the scene transform for the item itself and all its children in the call stack. If the item itself and all its ancestors are "clean", nothing is calculated, only traversed. We use this approach when processing dirty items / drawing items as well. That way we ensure the scene transform is only calculated once when absolutely needed. G'night :)
Diffstat (limited to 'src/gui/graphicsview/qgraphicsitem.cpp')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp50
1 files changed, 44 insertions, 6 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index b913d89..57ca2ef 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -952,6 +952,7 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de
// Resolve depth.
resolveDepth(parent ? parent->d_ptr->depth : -1);
+ dirtySceneTransform = 1;
// Deliver post-change notification
q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant);
@@ -2540,6 +2541,7 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos)
if (scene)
q->prepareGeometryChange();
this->pos = newPos;
+ dirtySceneTransform = 1;
// Send post-notification.
#ifndef QGRAPHICSITEM_NO_ITEMCHANGE
@@ -2682,12 +2684,17 @@ QMatrix QGraphicsItem::sceneMatrix() const
*/
QTransform QGraphicsItem::sceneTransform() const
{
- QTransform m;
- const QGraphicsItem *p = this;
- do {
- p->d_ptr->combineTransformToParent(&m);
- } while ((p = p->d_ptr->parent));
- return m;
+ if (d_ptr->dirtySceneTransform) {
+ // This item and all its descendants have dirty scene transforms.
+ // We're about to validate this item's scene transform, so we have to
+ // invalidate all the children; otherwise there's no way for the descendants
+ // to detect that the ancestor has changed.
+ d_ptr->invalidateChildrenSceneTransform();
+ }
+
+ QGraphicsItem *that = const_cast<QGraphicsItem *>(this);
+ d_ptr->ensureSceneTransformRecursive(&that);
+ return d_ptr->sceneTransform;
}
/*!
@@ -2899,6 +2906,7 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
// Update and set the new transformation.
prepareGeometryChange();
*d_ptr->transform = newTransform;
+ d_ptr->dirtySceneTransform = 1;
// Send post-notification.
#ifndef QGRAPHICSITEM_NO_ITEMCHANGE
@@ -2945,6 +2953,7 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine)
// Update and set the new transformation.
prepareGeometryChange();
*d_ptr->transform = newTransform;
+ d_ptr->dirtySceneTransform = 1;
// Send post-notification.
itemChange(ItemTransformHasChanged, newTransformVariant);
@@ -3966,6 +3975,35 @@ void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &n
}
}
+// Traverses all the ancestors up to the top-level and updates the pointer to
+// always point to the top-most item that has a dirty scene transform.
+// It then backtracks to the top-most dirty item and start calculating the
+// scene transform by combining the item's transform (+pos) with the parent's
+// cached scene transform (which we at this point know for sure is valid).
+void QGraphicsItemPrivate::ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem)
+{
+ Q_ASSERT(topMostDirtyItem);
+
+ if (dirtySceneTransform)
+ *topMostDirtyItem = q_ptr;
+
+ if (parent)
+ parent->d_ptr->ensureSceneTransformRecursive(topMostDirtyItem);
+
+ if (*topMostDirtyItem == q_ptr) {
+ if (!dirtySceneTransform)
+ return; // OK, neither my ancestors nor I have dirty scene transforms.
+ *topMostDirtyItem = 0;
+ } else if (*topMostDirtyItem) {
+ return; // Continue backtrack.
+ }
+
+ // COMBINE my transform with the parent's scene transform.
+ sceneTransform = parent ? parent->d_ptr->sceneTransform : QTransform();
+ combineTransformFromParent(&sceneTransform);
+ dirtySceneTransform = 0;
+}
+
/*!
\internal