diff options
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 46 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 14 |
2 files changed, 53 insertions, 7 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 443cc8c..5b997f4 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -631,6 +631,7 @@ void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag ch case QGraphicsItem::ItemClipsChildrenToShape: flag = AncestorClipsChildren; enabled = flags & QGraphicsItem::ItemClipsChildrenToShape; + invalidateCachedClipPathRecursively(/*childrenOnly=*/true); break; case QGraphicsItem::ItemIgnoresTransformations: flag = AncestorIgnoresTransformations; @@ -1270,6 +1271,9 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) d_ptr->updateAncestorFlag(ItemClipsChildrenToShape); } + if ((flags & ItemClipsToShape) != (oldFlags & ItemClipsToShape)) + d_ptr->invalidateCachedClipPath(); + if ((flags & ItemIgnoresTransformations) != (oldFlags & ItemIgnoresTransformations)) { // Item children clipping changes. Propagate the ancestor flag to // all children. @@ -3136,10 +3140,15 @@ bool QGraphicsItem::isClipped() const QPainterPath QGraphicsItem::clipPath() const { Q_D(const QGraphicsItem); - QPainterPath clip; - if (!isClipped()) - return clip; + if (!d->dirtyClipPath) + return d->cachedClipPath; + + if (!isClipped()) { + d_ptr->setCachedClipPath(QPainterPath()); + return d->cachedClipPath; + } + QPainterPath clip; // Start with the item's bounding rect. clip.addRect(boundingRect()); @@ -3150,15 +3159,27 @@ QPainterPath QGraphicsItem::clipPath() const // Intersect any in-between clips starting at the top and moving downwards. while ((parent = parent->d_ptr->parent)) { if (parent->d_ptr->flags & ItemClipsChildrenToShape) { - // Map clip to the current parent and intersect with its shape. - clip = (lastParent->itemTransform(parent).map(clip)).intersected(parent->shape()); - if (clip.isEmpty()) + // Map clip to the current parent and intersect with its shape/clipPath + clip = lastParent->itemTransform(parent).map(clip); + if (!parent->d_ptr->dirtyClipPath) { + clip = clip.intersected(parent->d_ptr->cachedClipPath); + if (!(parent->d_ptr->flags & ItemClipsToShape)) + clip = clip.intersected(parent->shape()); + } else { + clip = clip.intersected(parent->shape()); + } + + if (clip.isEmpty()) { + d_ptr->setCachedClipPath(clip); return clip; + } lastParent = parent; } - if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) + if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) + || !parent->d_ptr->dirtyClipPath) { break; + } } if (lastParent != this) { @@ -3171,6 +3192,7 @@ QPainterPath QGraphicsItem::clipPath() const if (d->flags & ItemClipsToShape) clip = clip.intersected(shape()); + d_ptr->setCachedClipPath(clip); return clip; } @@ -3726,6 +3748,15 @@ void QGraphicsItemPrivate::removeExtraItemCache() unsetExtra(ExtraCacheData); } +void QGraphicsItemPrivate::invalidateCachedClipPathRecursively(bool childrenOnly) +{ + if (!childrenOnly) + invalidateCachedClipPath(); + // ### Return if this item doesn't clip its children? + for (int i = 0; i < children.size(); ++i) + children.at(i)->d_ptr->invalidateCachedClipPathRecursively(false); +} + /*! \internal @@ -5505,6 +5536,7 @@ void QGraphicsItem::prepareGeometryChange() QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func(); scenePrivate->removeFromIndex(this); + d_ptr->invalidateCachedClipPathRecursively(); } } diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 7deae52..1e2c09b 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -138,6 +138,7 @@ public: dirty(0), dirtyChildren(0), localCollisionHack(0), + dirtyClipPath(1), globalStackingOrder(-1), sceneTransformIndex(-1), q_ptr(0) @@ -234,6 +235,18 @@ public: QGraphicsItemCache *extraItemCache() const; void removeExtraItemCache(); + inline void setCachedClipPath(const QPainterPath &path) + { + cachedClipPath = path; + dirtyClipPath = 0; + } + + inline void invalidateCachedClipPath() + { dirtyClipPath = 1; } + + void invalidateCachedClipPathRecursively(bool childrenOnly = false); + + QPainterPath cachedClipPath; QPointF pos; qreal z; QGraphicsScene *scene; @@ -268,6 +281,7 @@ public: quint32 dirty : 1; quint32 dirtyChildren : 1; quint32 localCollisionHack : 1; + quint32 dirtyClipPath : 1; // Optional stacking order int globalStackingOrder; |