summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp46
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h14
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;