summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/graphicsview')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp20
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h1
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp14
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp59
-rw-r--r--src/gui/graphicsview/qgraphicsview_p.h6
5 files changed, 95 insertions, 5 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index b8c240a..65edb2a 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -1812,7 +1812,7 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags)
const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations | ItemIsSelectable);
bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask);
if (fullUpdate)
- d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
+ d_ptr->updatePaintedViewBoundingRects(/*children=*/true);
// Keep the old flags to compare the diff.
GraphicsItemFlags oldFlags = GraphicsItemFlags(d_ptr->flags);
@@ -5432,6 +5432,24 @@ void QGraphicsItemPrivate::removeExtraItemCache()
unsetExtra(ExtraCacheData);
}
+void QGraphicsItemPrivate::updatePaintedViewBoundingRects(bool updateChildren)
+{
+ if (!scene)
+ return;
+
+ for (int i = 0; i < scene->d_func()->views.size(); ++i) {
+ QGraphicsViewPrivate *viewPrivate = scene->d_func()->views.at(i)->d_func();
+ QRect rect = paintedViewBoundingRects.value(viewPrivate->viewport);
+ rect.translate(viewPrivate->dirtyScrollOffset);
+ viewPrivate->updateRect(rect);
+ }
+
+ if (updateChildren) {
+ for (int i = 0; i < children.size(); ++i)
+ children.at(i)->d_ptr->updatePaintedViewBoundingRects(true);
+ }
+}
+
// 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
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 569a329..e812f29 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -377,6 +377,7 @@ public:
QGraphicsItemCache *extraItemCache() const;
void removeExtraItemCache();
+ void updatePaintedViewBoundingRects(bool updateChildren);
void ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem);
inline void ensureSceneTransform()
{
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 36fd5c8..dfba7c9 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -5116,9 +5116,15 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool
// Process children.
if (itemHasChildren && item->d_ptr->dirtyChildren) {
+ const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape;
+ if (itemClipsChildrenToShape) {
+ // Make sure child updates are clipped to the item's bounding rect.
+ for (int i = 0; i < views.size(); ++i)
+ views.at(i)->d_func()->setUpdateClip(item);
+ }
if (!dirtyAncestorContainsChildren) {
dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending
- && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
+ && itemClipsChildrenToShape;
}
const bool allChildrenDirty = item->d_ptr->allChildrenDirty;
const bool parentIgnoresVisible = item->d_ptr->ignoreVisible;
@@ -5141,6 +5147,12 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool
}
processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity);
}
+
+ if (itemClipsChildrenToShape) {
+ // Reset updateClip.
+ for (int i = 0; i < views.size(); ++i)
+ views.at(i)->d_func()->setUpdateClip(0);
+ }
} else if (wasDirtyParentSceneTransform) {
item->d_ptr->invalidateChildrenSceneTransform();
}
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index 96d5ba1..0f951ef 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -337,6 +337,7 @@ QGraphicsViewPrivate::QGraphicsViewPrivate()
mustAllocateStyleOptions(false),
mustResizeBackgroundPixmap(true),
fullUpdatePending(true),
+ hasUpdateClip(false),
mousePressButton(Qt::NoButton),
leftIndent(0), topIndent(0),
lastMouseEvent(QEvent::None, QPoint(), Qt::NoButton, 0, 0),
@@ -880,6 +881,52 @@ static inline void QRect_unite(QRect *rect, const QRect &other)
}
}
+/*
+ Calling this function results in update rects being clipped to the item's
+ bounding rect. Note that updates prior to this function call is not clipped.
+ The clip is removed by passing 0.
+*/
+void QGraphicsViewPrivate::setUpdateClip(QGraphicsItem *item)
+{
+ Q_Q(QGraphicsView);
+ // We simply ignore the request if the update mode is either FullViewportUpdate
+ // or NoViewportUpdate; in that case there's no point in clipping anything.
+ if (!item || viewportUpdateMode == QGraphicsView::NoViewportUpdate
+ || viewportUpdateMode == QGraphicsView::FullViewportUpdate) {
+ hasUpdateClip = false;
+ return;
+ }
+
+ // Calculate the clip (item's bounding rect in view coordinates).
+ // Optimized version of:
+ // QRect clip = item->deviceTransform(q->viewportTransform())
+ // .mapRect(item->boundingRect()).toAlignedRect();
+ QRect clip;
+ if (item->d_ptr->itemIsUntransformable()) {
+ QTransform xform = item->deviceTransform(q->viewportTransform());
+ clip = xform.mapRect(item->boundingRect()).toAlignedRect();
+ } else if (item->d_ptr->sceneTransformTranslateOnly && identityMatrix) {
+ QRectF r(item->boundingRect());
+ r.translate(item->d_ptr->sceneTransform.dx() - horizontalScroll(),
+ item->d_ptr->sceneTransform.dy() - verticalScroll());
+ clip = r.toAlignedRect();
+ } else if (!q->isTransformed()) {
+ clip = item->d_ptr->sceneTransform.mapRect(item->boundingRect()).toAlignedRect();
+ } else {
+ QTransform xform = item->d_ptr->sceneTransform;
+ xform *= q->viewportTransform();
+ clip = xform.mapRect(item->boundingRect()).toAlignedRect();
+ }
+
+ if (hasUpdateClip) {
+ // Intersect with old clip.
+ updateClip &= clip;
+ } else {
+ updateClip = clip;
+ hasUpdateClip = true;
+ }
+}
+
bool QGraphicsViewPrivate::updateRegion(const QRectF &rect, const QTransform &xform)
{
if (rect.isEmpty())
@@ -910,6 +957,8 @@ bool QGraphicsViewPrivate::updateRegion(const QRectF &rect, const QTransform &xf
viewRect.adjust(-1, -1, 1, 1);
else
viewRect.adjust(-2, -2, 2, 2);
+ if (hasUpdateClip)
+ viewRect &= updateClip;
dirtyRegion += viewRect;
}
@@ -931,7 +980,10 @@ bool QGraphicsViewPrivate::updateRect(const QRect &r)
viewport->update();
break;
case QGraphicsView::BoundingRectViewportUpdate:
- QRect_unite(&dirtyBoundingRect, r);
+ if (hasUpdateClip)
+ QRect_unite(&dirtyBoundingRect, r & updateClip);
+ else
+ QRect_unite(&dirtyBoundingRect, r);
if (containsViewport(dirtyBoundingRect, viewport->width(), viewport->height())) {
fullUpdatePending = true;
viewport->update();
@@ -939,7 +991,10 @@ bool QGraphicsViewPrivate::updateRect(const QRect &r)
break;
case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE
case QGraphicsView::MinimalViewportUpdate:
- dirtyRegion += r;
+ if (hasUpdateClip)
+ dirtyRegion += r & updateClip;
+ else
+ dirtyRegion += r;
break;
default:
break;
diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h
index 1239ca4..7bd9ecb 100644
--- a/src/gui/graphicsview/qgraphicsview_p.h
+++ b/src/gui/graphicsview/qgraphicsview_p.h
@@ -91,7 +91,8 @@ public:
quint32 mustAllocateStyleOptions : 1;
quint32 mustResizeBackgroundPixmap : 1;
quint32 fullUpdatePending : 1;
- quint32 padding : 19;
+ quint32 hasUpdateClip : 1;
+ quint32 padding : 18;
QRectF sceneRect;
void updateLastCenterPoint();
@@ -102,6 +103,7 @@ public:
QRectF mapRectToScene(const QRect &rect) const;
QRectF mapRectFromScene(const QRectF &rect) const;
+ QRect updateClip;
QPointF mousePressItemPoint;
QPointF mousePressScenePoint;
QPoint mousePressViewPoint;
@@ -195,6 +197,8 @@ public:
#endif
}
+ void setUpdateClip(QGraphicsItem *);
+
inline bool updateRectF(const QRectF &rect)
{
if (rect.isEmpty())