summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp156
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h22
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp212
-rw-r--r--src/gui/graphicsview/qgraphicsscene.h4
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h30
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp194
-rw-r--r--src/gui/graphicsview/qgraphicsview.h1
-rw-r--r--src/gui/graphicsview/qgraphicsview_p.h9
8 files changed, 250 insertions, 378 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index e09d3f0..ec6b35b 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -863,8 +863,11 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de
parent->d_ptr->addChild(q);
parent->itemChange(QGraphicsItem::ItemChildAddedChange, thisPointerVariant);
- if (!implicitUpdate)
- updateHelper(QRectF(), false, true);
+ if (!implicitUpdate && scene) {
+ scene->d_func()->markDirty(q_ptr, QRect(),
+ /*invalidateChildren=*/false,
+ /*maybeDirtyClipPath=*/true);
+ }
// Inherit ancestor flags from the new parent.
updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
@@ -895,7 +898,11 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, bool de
setEnabledHelper(true, /* explicit = */ false);
// If the item is being deleted, the whole scene will be updated.
- updateHelper(QRectF(), false, true);
+ if (scene) {
+ scene->d_func()->markDirty(q_ptr, QRect(),
+ /*invalidateChildren=*/false,
+ /*maybeDirtyClipPath=*/true);
+ }
}
}
@@ -1358,7 +1365,7 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags)
const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations);
bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask);
if (fullUpdate)
- d_ptr->fullUpdateHelper(false, true);
+ d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
// Keep the old flags to compare the diff.
GraphicsItemFlags oldFlags = this->flags();
@@ -1398,8 +1405,11 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags)
d_ptr->updateAncestorFlag(ItemIgnoresTransformations);
}
- // ### Why updateHelper?
- d_ptr->updateHelper(QRectF(), false, true);
+ if (d_ptr->scene) {
+ d_ptr->scene->d_func()->markDirty(this, QRectF(),
+ /*invalidateChildren=*/true,
+ /*maybeDirtyClipPath*/true);
+ }
// Notify change.
itemChange(ItemFlagsHaveChanged, quint32(flags));
@@ -1665,7 +1675,12 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo
QGraphicsItemCache *c = (QGraphicsItemCache *)qVariantValue<void *>(extra(ExtraCacheData));
if (c)
c->purge();
- updateHelper(QRectF(), /* force = */ true);
+ if (scene) {
+ scene->d_func()->markDirty(q_ptr, QRectF(),
+ /*invalidateChildren=*/false,
+ /*maybeDirtyClipPath=*/false,
+ /*force=*/true);
+ }
}
// Certain properties are dropped as an item becomes invisible.
@@ -1828,8 +1843,8 @@ void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bo
enabled = newEnabledVariant.toBool();
// Schedule redraw.
- if (update)
- updateHelper();
+ if (update && scene)
+ scene->d_func()->markDirty(q_ptr);
foreach (QGraphicsItem *child, children) {
if (!newEnabled || !child->d_ptr->explicitlyDisabled)
@@ -1930,9 +1945,8 @@ void QGraphicsItem::setSelected(bool selected)
return;
d_ptr->selected = newSelected;
- d_ptr->updateHelper();
-
if (d_ptr->scene) {
+ d_ptr->scene->d_func()->markDirty(this);
QGraphicsScenePrivate *sceneD = d_ptr->scene->d_func();
if (selected) {
sceneD->selectedItems << this;
@@ -2051,7 +2065,12 @@ void QGraphicsItem::setOpacity(qreal opacity)
itemChange(ItemOpacityHasChanged, newOpacity);
// Update.
- d_ptr->fullUpdateHelper(/*childrenOnly=*/false, /*maybeDirtyClipPath=*/false, /*ignoreOpacity=*/true);
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->markDirty(this, QRectF(),
+ /*invalidateChildren=*/true,
+ /*maybeDirtyClipPath=*/false,
+ /*force=*/false,
+ /*ignoreOpacity=*/true);
}
/*!
@@ -2501,10 +2520,8 @@ void QGraphicsItemPrivate::setPosHelper(const QPointF &pos)
// Update and repositition.
inSetPosHelper = 1;
updateCachedClipPathFromSetPosHelper(newPos);
- if (scene) {
- fullUpdateHelper(true);
+ if (scene)
q->prepareGeometryChange();
- }
this->pos = newPos;
invalidateSceneTransformCache();
@@ -3305,7 +3322,6 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
return;
// Update and set the new transformation.
- d_ptr->fullUpdateHelper(true, true);
prepareGeometryChange();
d_ptr->hasTransform = !newTransform.isIdentity();
d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform);
@@ -3358,7 +3374,6 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine)
return;
// Update and set the new transformation.
- d_ptr->fullUpdateHelper(true, true);
prepareGeometryChange();
d_ptr->hasTransform = !newTransform.isIdentity();
d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform);
@@ -3545,9 +3560,9 @@ void QGraphicsItem::setZValue(qreal z)
if (newZ == d_ptr->z)
return;
d_ptr->z = newZ;
- d_ptr->fullUpdateHelper();
if (d_ptr->scene) {
+ d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
// Invalidate any sort caching; arrival of a new item means we need to
// resort.
d_ptr->scene->d_func()->invalidateSortCache();
@@ -4208,84 +4223,13 @@ bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, bool ignore
// 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.
return (!visible && !ignoreVisibleBit)
- || (dirty && !ignoreDirtyBit)
+ || (!ignoreDirtyBit && (dirty || hasDirtyAncestor()))
|| !scene
|| (scene->d_func()->updateAll && scene->d_func()->hasSceneRect)
|| (!ignoreClipping && (childrenClippedToShape() && isClippedAway()))
|| (!ignoreOpacity && childrenCombineOpacity() && isFullyTransparent());
}
-/*!
- \internal
-
- Asks the scene to mark this item's scene rect as dirty, requesting a
- redraw. This does not invalidate any cache.
-
- The \a force argument is for the update call in setVisible(), which is the
- 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, 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.
- if (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/force))
- return;
-
- if (rect.isNull())
- dirty = 1;
- scene->itemUpdated(q_ptr, rect);
-}
-
-/*!
- \internal
-
- Propagates updates to \a item and all its children.
-*/
-void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly, bool maybeDirtyClipPath, bool ignoreOpacity)
-{
- if (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/false,
- /*ignoreDirtyBit=*/true, ignoreOpacity)) {
- return;
- }
-
- if (!childrenOnly && !dirty) {
- // Effectively the same as updateHelper(QRectF(), false, maybeDirtyClipPath).
- dirty = 1;
- scene->itemUpdated(q_ptr, QRectF());
- }
-
- if (dirtyChildren || childrenClippedToShape()) {
- // Unnecessary to update children as well.
- return;
- }
-
- if (ancestorFlags & AncestorClipsChildren) {
- Q_Q(QGraphicsItem);
- // Check if we can avoid updating all children.
- QGraphicsItem *p = parent;
- QRectF br = q->boundingRect();
- while (p) {
- if (p->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) {
- bool ok;
- QTransform x = q->itemTransform(p, &ok);
- if (!ok)
- break;
- if (x.mapRect(br).contains(p->boundingRect()))
- return;
- }
- p = p->d_ptr->parent;
- if (!p || !(p->d_ptr->ancestorFlags & AncestorClipsChildren))
- break;
- // ### check one level only
- break;
- }
- }
- foreach (QGraphicsItem *child, children)
- child->d_ptr->fullUpdateHelper(false, maybeDirtyClipPath);
- dirtyChildren = 1;
-}
-
static inline bool allChildrenCombineOpacityHelper(QGraphicsItem *parent)
{
Q_ASSERT(parent);
@@ -4590,14 +4534,10 @@ void QGraphicsItem::update(const QRectF &rect)
// Only invalidate cache; item is already dirty.
if (d_ptr->dirty)
return;
- } else if (d_ptr->discardUpdateRequest()) {
- return;
}
- // Effectively the same as updateHelper(rect);
- if (rect.isNull())
- d_ptr->dirty = 1;
- d_ptr->scene->itemUpdated(this, rect);
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->markDirty(this);
}
/*!
@@ -4695,7 +4635,7 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect)
exposed -= r.translated(dx, dy);
foreach (QRect rect, exposed.rects())
update(rect);
- d_ptr->updateHelper();
+ d->scene->d_func()->markDirty(this);
} else {
update(rect);
}
@@ -5911,7 +5851,8 @@ void QGraphicsItem::focusOutEvent(QFocusEvent *event)
void QGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
- d_ptr->updateHelper();
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->markDirty(this);
}
/*!
@@ -5939,7 +5880,8 @@ void QGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
void QGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
- d_ptr->updateHelper();
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->markDirty(this);
}
/*!
@@ -6367,9 +6309,10 @@ void QGraphicsItem::addToIndex()
// ### add to child index only if applicable
return;
}
- if (d_ptr->scene)
+ if (d_ptr->scene) {
d_ptr->scene->d_func()->addToIndex(this);
- d_ptr->updateHelper();
+ d_ptr->scene->d_func()->markDirty(this);
+ }
}
/*!
@@ -6385,9 +6328,10 @@ void QGraphicsItem::removeFromIndex()
// ### remove from child index only if applicable
return;
}
- d_ptr->updateHelper();
- if (d_ptr->scene)
+ if (d_ptr->scene) {
+ d_ptr->scene->d_func()->markDirty(this);
d_ptr->scene->d_func()->removeFromIndex(this);
+ }
}
/*!
@@ -6406,7 +6350,10 @@ void QGraphicsItem::removeFromIndex()
void QGraphicsItem::prepareGeometryChange()
{
if (d_ptr->scene) {
- d_ptr->updateHelper(QRectF(), false, /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper);
+ d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
+ d_ptr->scene->d_func()->markDirty(this, QRectF(),
+ /*invalidateChildren=*/true,
+ /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper);
QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func();
scenePrivate->removeFromIndex(this);
}
@@ -8075,7 +8022,6 @@ void QGraphicsPixmapItem::setTransformationMode(Qt::TransformationMode mode)
{
Q_D(QGraphicsPixmapItem);
if (mode != d->transformationMode) {
- d_ptr->updateHelper();
d->transformationMode = mode;
update();
}
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 200d177..1d4b37a 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -161,6 +161,8 @@ public:
dirtyTransform(0),
dirtyTransformComponents(0),
dirtyChildrenBoundingRect(1),
+ inDirtyList(0),
+ paintedViewBoundingRectsNeedRepaint(0),
globalStackingOrder(-1),
sceneTransformIndex(-1),
q_ptr(0)
@@ -186,8 +188,6 @@ public:
void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true);
bool discardUpdateRequest(bool ignoreClipping = false, bool ignoreVisibleBit = false,
bool ignoreDirtyBit = false, bool ignoreOpacity = false) const;
- void updateHelper(const QRectF &rect = QRectF(), bool force = false, bool maybeDirtyClipPath = false);
- void fullUpdateHelper(bool childrenOnly = false, bool maybeDirtyClipPath = false, bool ignoreOpacity = false);
void updateEffectiveOpacity();
void resolveEffectiveOpacity(qreal effectiveParentOpacity);
void resolveDepth(int parentDepth);
@@ -308,8 +308,22 @@ public:
|| (childrenCombineOpacity() && isFullyTransparent());
}
+ inline bool hasDirtyAncestor() const
+ {
+ QGraphicsItem *p = parent;
+ while (p) {
+ if (p->d_ptr->dirtyChildren || (p->d_ptr->dirty && p->d_ptr->childrenClippedToShape()))
+ return true;
+ p = p->d_ptr->parent;
+ }
+ return false;
+ }
+
+
QPainterPath cachedClipPath;
QRectF childrenBoundingRect;
+ QRectF needsRepaint;
+ QMap<QWidget *, QRect> paintedViewBoundingRects;
QPointF pos;
qreal z;
QGraphicsScene *scene;
@@ -353,7 +367,9 @@ public:
quint32 dirtyTransform : 1;
quint32 dirtyTransformComponents : 1;
quint32 dirtyChildrenBoundingRect : 1;
- quint32 padding : 17; // feel free to use
+ quint32 inDirtyList : 1;
+ quint32 paintedViewBoundingRectsNeedRepaint : 1;
+ quint32 padding : 15; // feel free to use
// Optional stacking order
int globalStackingOrder;
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 7eb49e9..d004ed2 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -334,7 +334,6 @@ QGraphicsScenePrivate::QGraphicsScenePrivate()
updateAll(false),
calledEmitUpdated(false),
selectionChanging(0),
- dirtyItemResetPending(false),
regenerateIndex(true),
purgePending(false),
indexTimerId(0),
@@ -678,31 +677,81 @@ void QGraphicsScenePrivate::_q_polishItems()
unpolishedItems.clear();
}
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::_q_resetDirtyItems()
+void QGraphicsScenePrivate::_q_processDirtyItems()
{
+ Q_Q(QGraphicsScene);
+ if (dirtyItems.isEmpty())
+ return;
+
+ if (updateAll) {
+ for (int i = 0; i < dirtyItems.size(); ++i)
+ resetDirtyItem(dirtyItems.at(i));
+ dirtyItems.clear();
+ return;
+ }
+
+ const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask);
for (int i = 0; i < dirtyItems.size(); ++i) {
QGraphicsItem *item = dirtyItems.at(i);
- item->d_ptr->dirty = 0;
- item->d_ptr->dirtyChildren = 0;
+ if (useCompatUpdate && !item->d_ptr->itemIsUntransformable()
+ && qFuzzyIsNull(item->boundingRegionGranularity())) {
+ // This block of code is kept for compatibility. Since 4.5, by default
+ // QGraphicsView does not connect the signal and we use the below
+ // method of delivering updates.
+ q->update(item->sceneBoundingRect());
+ resetDirtyItem(item);
+ continue;
+ }
+
+ QRectF dirtyRect;
+ bool uninitializedDirtyRect = true;
+
+ for (int j = 0; j < views.size(); ++j) {
+ QGraphicsView *view = views.at(j);
+ QGraphicsViewPrivate *viewPrivate = view->d_func();
+ if (viewPrivate->fullUpdatePending)
+ continue;
+ switch (viewPrivate->viewportUpdateMode) {
+ case QGraphicsView::NoViewportUpdate:
+ continue;
+ case QGraphicsView::FullViewportUpdate:
+ view->viewport()->update();
+ viewPrivate->fullUpdatePending = 1;
+ continue;
+ default:
+ break;
+ }
+
+ if (uninitializedDirtyRect) {
+ dirtyRect = adjustedItemBoundingRect(item);
+ if (!item->d_ptr->dirty) {
+ _q_adjustRect(&item->d_ptr->needsRepaint);
+ dirtyRect &= item->d_ptr->needsRepaint;
+ }
+
+ if (item->d_ptr->dirtyChildren && !item->d_ptr->children.isEmpty()
+ && !item->d_ptr->childrenClippedToShape()) {
+ QRectF childrenBounds = item->childrenBoundingRect();
+ _q_adjustRect(&childrenBounds);
+ dirtyRect |= childrenBounds;
+ }
+ uninitializedDirtyRect = false;
+ }
+
+ if (item->d_ptr->paintedViewBoundingRectsNeedRepaint)
+ viewPrivate->updateRect(item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport));
+
+ if (!item->d_ptr->hasBoundingRegionGranularity)
+ viewPrivate->updateRect(viewPrivate->mapToViewRect(item, dirtyRect));
+ else
+ viewPrivate->updateRegion(viewPrivate->mapToViewRegion(item, dirtyRect));
+ }
+ resetDirtyItem(item);
}
- dirtyItems.clear();
- dirtyItemResetPending = false;
-}
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::resetDirtyItemsLater()
-{
- Q_Q(QGraphicsScene);
- if (dirtyItemResetPending)
- return;
- // dirtyItems.reserve(indexedItems.size() + unindexedItems.size());
- dirtyItemResetPending = true;
- QMetaObject::invokeMethod(q, "_q_resetDirtyItems", Qt::QueuedConnection);
+ dirtyItems.clear();
+ for (int i = 0; i < views.size(); ++i)
+ views.at(i)->d_func()->processPendingUpdates();
}
/*!
@@ -761,10 +810,9 @@ void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item)
// Update selected & hovered item bookkeeping
selectedItems.remove(item);
hoverItems.removeAll(item);
- pendingUpdateItems.removeAll(item);
cachedItemsUnderMouse.removeAll(item);
unpolishedItems.removeAll(item);
- dirtyItems.removeAll(item);
+ removeFromDirtyItems(item);
//We remove all references of item from the sceneEventFilter arrays
QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin();
@@ -3319,7 +3367,7 @@ void QGraphicsScene::removeItem(QGraphicsItem *item)
d->pendingUpdateItems.removeAll(item);
d->cachedItemsUnderMouse.removeAll(item);
d->unpolishedItems.removeAll(item);
- d->dirtyItems.removeAll(item);
+ d->removeFromDirtyItems(item);
//We remove all references of item from the sceneEventFilter arrays
QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = d->sceneEventFilters.begin();
@@ -3330,11 +3378,6 @@ void QGraphicsScene::removeItem(QGraphicsItem *item)
++iterator;
}
-
- //Ensure dirty flag have the correct default value so the next time it will be added it will receive updates
- item->d_func()->dirty = 0;
- item->d_func()->dirtyChildren = 0;
-
// Remove all children recursively
foreach (QGraphicsItem *child, item->children())
removeItem(child);
@@ -5050,7 +5093,9 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
}
QRectF brect = item->boundingRect();
_q_adjustRect(&brect);
- viewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1) & exposedRegion.boundingRect();
+ const QRect paintedViewBoundingRect = transform.mapRect(brect).toRect().adjusted(-1, -1, 1, 1);
+ item->d_ptr->paintedViewBoundingRects.insert(widget, paintedViewBoundingRect);
+ viewBoundingRect = paintedViewBoundingRect & exposedRegion.boundingRect();
} else {
transform = parentTransform;
}
@@ -5117,6 +5162,44 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
painter->restore();
}
+void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren,
+ bool maybeDirtyClipPath, bool force, bool ignoreOpacity)
+{
+ Q_ASSERT(item);
+ if (updateAll)
+ return;
+
+ if (item->d_ptr->discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath,
+ /*ignoreVisibleBit=*/force,
+ /*ignoreDirtyBit=*/false, ignoreOpacity)) {
+ return;
+ }
+
+ const bool fullItemUpdate = rect.isNull();
+ if (!fullItemUpdate && rect.isEmpty())
+ return;
+
+ if (dirtyItems.isEmpty())
+ QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection);
+
+ if (item->d_ptr->inDirtyList) {
+ if (fullItemUpdate)
+ item->d_ptr->dirty = 1;
+ else if (!item->d_ptr->dirty)
+ item->d_ptr->needsRepaint |= rect;
+ } else {
+ dirtyItems.append(item);
+ item->d_ptr->inDirtyList = 1;
+ if (fullItemUpdate)
+ item->d_ptr->dirty = 1;
+ else if (!item->d_ptr->dirty)
+ item->d_ptr->needsRepaint = rect;
+ }
+
+ if (invalidateChildren)
+ item->d_ptr->dirtyChildren = 1;
+}
+
/*!
Paints the given \a items using the provided \a painter, after the
background has been drawn, and before the foreground has been
@@ -5238,6 +5321,8 @@ void QGraphicsScene::drawItems(QPainter *painter,
// Draw the item
d->drawItemHelper(item, painter, &options[i], widget, d->painterStateProtection);
+ const QRect paintedViewBoundingRect = painter->worldTransform().mapRect(options[i].rect).adjusted(-1, -1, 1, 1);
+ item->d_ptr->paintedViewBoundingRects.insert(widget, paintedViewBoundingRect);
if (saveState)
painter->restore();
@@ -5364,73 +5449,6 @@ bool QGraphicsScene::focusNextPrevChild(bool next)
*/
/*!
- \internal
-
- This private function is called by QGraphicsItem, which is a friend of
- QGraphicsScene. It is used by QGraphicsScene to record the rectangles that
- need updating. It also launches a single-shot timer to ensure that
- updated() will be emitted later.
-
- The \a item parameter is the item that changed, and \a rect is the
- area of the item that changed given in item coordinates.
-*/
-void QGraphicsScene::itemUpdated(QGraphicsItem *item, const QRectF &rect)
-{
- Q_D(QGraphicsScene);
- // Deliver the actual update.
- if (!d->updateAll) {
- if (d->views.isEmpty() || ((d->connectedSignals & d->changedSignalMask) && !item->d_ptr->itemIsUntransformable()
- && qFuzzyIsNull(item->boundingRegionGranularity()))) {
- // This block of code is kept for compatibility. Since 4.5, by default
- // QGraphicsView does not connect the signal and we use the below
- // method of delivering updates.
- update(item->sceneBoundingRect());
- } else {
- // ### Remove _q_adjustedRects().
- QRectF boundingRect(adjustedItemBoundingRect(item));
- if (!rect.isNull()) {
- QRectF adjustedRect(rect);
- _q_adjustRect(&adjustedRect);
- boundingRect &= adjustedRect;
- }
-
- // Update each view directly.
- for (int i = 0; i < d->views.size(); ++i)
- d->views.at(i)->d_func()->itemUpdated(item, boundingRect);
- }
- }
- if (item->d_ptr->dirty) {
- d->dirtyItems << item;
- d->resetDirtyItemsLater();
- }
-
- if (!item->isVisible())
- return; // Hiding an item won't effect the largestUntransformableItem/sceneRect.
-
- // Update d->largestUntransformableItem by mapping this item's bounding
- // rect back to the topmost untransformable item's untransformed
- // coordinate system (which sort of equals the 1:1 coordinate system of an
- // untransformed view).
- if (item->d_ptr->itemIsUntransformable()) {
- QGraphicsItem *parent = item;
- while (parent && (parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations))
- parent = parent->parentItem();
- d->largestUntransformableItem |= item->mapToItem(parent, item->boundingRect()).boundingRect();
- }
-
- // Only track the automatically growing scene rect if the scene has no
- // defined scene rect.
- if (!d->hasSceneRect) {
- QRectF oldGrowingItemsBoundingRect = d->growingItemsBoundingRect;
- QRectF adjustedItemSceneBoundingRect(item->sceneBoundingRect());
- _q_adjustRect(&adjustedItemSceneBoundingRect);
- d->growingItemsBoundingRect |= adjustedItemSceneBoundingRect;
- if (d->growingItemsBoundingRect != oldGrowingItemsBoundingRect)
- emit sceneRectChanged(d->growingItemsBoundingRect);
- }
-}
-
-/*!
\since 4.4
Returns the scene's style, or the same as QApplication::style() if the
diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h
index 9802f87..4c0f2ec 100644
--- a/src/gui/graphicsview/qgraphicsscene.h
+++ b/src/gui/graphicsview/qgraphicsscene.h
@@ -271,8 +271,6 @@ Q_SIGNALS:
void selectionChanged();
private:
- void itemUpdated(QGraphicsItem *item, const QRectF &rect);
-
Q_DECLARE_PRIVATE(QGraphicsScene)
Q_DISABLE_COPY(QGraphicsScene)
Q_PRIVATE_SLOT(d_func(), void _q_updateIndex())
@@ -281,7 +279,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_updateLater())
Q_PRIVATE_SLOT(d_func(), void _q_polishItems())
Q_PRIVATE_SLOT(d_func(), void _q_updateSortCache())
- Q_PRIVATE_SLOT(d_func(), void _q_resetDirtyItems())
+ Q_PRIVATE_SLOT(d_func(), void _q_processDirtyItems())
friend class QGraphicsItem;
friend class QGraphicsItemPrivate;
friend class QGraphicsView;
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index bb99908..f2226bf 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -111,7 +111,7 @@ public:
QSet<QGraphicsItem *> selectedItems;
QList<QGraphicsItem *> unindexedItems;
QList<QGraphicsItem *> indexedItems;
- QList<QGraphicsItem *> dirtyItems;
+ QVector<QGraphicsItem *> dirtyItems;
QList<QGraphicsItem *> pendingUpdateItems;
QList<QGraphicsItem *> unpolishedItems;
QList<QGraphicsItem *> topLevelItems;
@@ -121,9 +121,7 @@ public:
void _q_updateLater();
void _q_polishItems();
- void _q_resetDirtyItems();
- void resetDirtyItemsLater();
- bool dirtyItemResetPending;
+ void _q_processDirtyItems();
QList<int> freeItemIndexes;
bool regenerateIndex;
@@ -257,6 +255,30 @@ public:
void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform &parentTransform,
const QTransform &viewTransform,
const QRegion &exposedRegion, QWidget *widget, QGraphicsView::OptimizationFlags optimizationFlags);
+ void markDirty(QGraphicsItem *item, const QRectF &rect = QRectF(), bool invalidateChildren = false,
+ bool maybeDirtyClipPath = false, bool force = false, bool ignoreOpacity = false);
+
+ inline void resetDirtyItem(QGraphicsItem *item)
+ {
+ Q_ASSERT(item);
+ item->d_ptr->dirty = 0;
+ item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0;
+ item->d_ptr->dirtyChildren = 0;
+ item->d_ptr->inDirtyList = 0;
+ item->d_ptr->needsRepaint = QRectF();
+ }
+
+ inline void removeFromDirtyItems(QGraphicsItem *item)
+ {
+ int i = 0;
+ while (i < dirtyItems.size()) {
+ if (dirtyItems.at(i) == item)
+ dirtyItems.remove(i);
+ else
+ ++i;
+ }
+ resetDirtyItem(item);
+ }
QStyle *style;
QFont font;
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index 1994675..acf26e1 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -329,8 +329,6 @@ QGraphicsViewPrivate::QGraphicsViewPrivate()
#endif
lastDragDropEvent(0),
fullUpdatePending(true),
- dirtyRectCount(0),
- updatingLater(false),
updateSceneSlotReimplementedChecked(false)
{
styleOptions.reserve(QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS);
@@ -804,125 +802,28 @@ static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item)
return boundingRect;
}
-/*!
- \internal
-*/
-void QGraphicsViewPrivate::itemUpdated(QGraphicsItem *item, const QRectF &rect)
+void QGraphicsViewPrivate::processPendingUpdates()
{
- if (fullUpdatePending || viewportUpdateMode == QGraphicsView::NoViewportUpdate)
- return;
- if (item->d_ptr->dirty)
- updateLater();
-
- QRectF updateRect = rect;
- if ((item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) || item->d_ptr->children.isEmpty()) {
- updateRect &= adjustedItemBoundingRect(item);
- if (updateRect.isEmpty())
- return;
- }
-
- QGraphicsItem *clipItem = item;
- if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) {
- // Minimize unnecessary redraw.
- QGraphicsItem *parent = item;
- while ((parent = parent->d_ptr->parent)) {
- if (parent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) {
- // Map update rect to the current parent and itersect with its bounding rect.
- updateRect = clipItem->itemTransform(parent).mapRect(updateRect)
- & adjustedItemBoundingRect(parent);
- if (updateRect.isEmpty())
- return;
- clipItem = parent;
- }
-
- if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren))
- break;
- }
- }
-
- // Map update rect from clipItem coordinates to view coordinates.
- Q_ASSERT(clipItem);
- if (!item->d_ptr->hasBoundingRegionGranularity)
- this->updateRect(mapToViewRect(clipItem, updateRect) & viewport->rect());
- else
- updateRegion(mapToViewRegion(clipItem, updateRect) & viewport->rect());
-}
-
-void QGraphicsViewPrivate::updateLater()
-{
- Q_Q(QGraphicsView);
- if (updatingLater)
- return;
- updatingLater = true;
- QMetaObject::invokeMethod(q, "_q_updateLaterSlot", Qt::QueuedConnection);
-}
-
-void QGraphicsViewPrivate::_q_updateLaterSlot()
-{
- Q_Q(QGraphicsView);
if (!scene)
return;
- QRect vr = viewport->rect();
- QTransform viewTransform = q->viewportTransform();
- 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(/*ignoreClipping=*/false,
- /*ignoreVisibleBit=*/false,
- /*ignoreDirtyBit=*/true)) {
- continue;
- }
- QTransform x = item->sceneTransform() * viewTransform;
- updateRect(x.mapRect(item->boundingRect()).toAlignedRect() & vr);
+ if (fullUpdatePending) { // We have already called viewport->update()
+ dirtyBoundingRect = QRect();
+ dirtyRegion = QRegion();
+ return;
}
- dirtyRectCount += dirtyRects.size();
-
- bool noUpdate = !fullUpdatePending && viewportUpdateMode == QGraphicsView::FullViewportUpdate;
- if ((dirtyRectCount > 0 || !dirtyBoundingRect.isEmpty()) && !fullUpdatePending && !noUpdate) {
- if (viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate
- || (viewportUpdateMode == QGraphicsView::SmartViewportUpdate
- && dirtyRectCount >= QGRAPHICSVIEW_REGION_RECT_THRESHOLD)) {
- if (!(optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)) {
- viewport->update(dirtyBoundingRect.adjusted(-2, -2, 2, 2));
- } else {
- viewport->update(dirtyBoundingRect);
- }
- } else {
- // ### Improve this block, which is very slow for complex regions. We
- // need to strike the balance between having an accurate update
- // region, and running fast. The below approach is the simplest way to
- // create a region from a bunch of rects, but we might want to use
- // other approaches; e.g., a grid of a fixed size representing
- // quadrants of the viewport, which we mark as dirty depending on the
- // rectangles in the list. Perhaps this should go into a
- // QRegion::fromRects(rects, how) function.
- QRegion region;
- if (!(optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)) {
- for (int i = 0; i < dirtyRegions.size(); ++i) {
- QVector<QRect> rects = dirtyRegions.at(i).rects();
- for (int j = 0; j < rects.size(); ++j)
- region += rects.at(j).adjusted(-2, -2, 2, 2);
- }
- for (int i = 0; i < dirtyRects.size(); ++i)
- region += dirtyRects.at(i).adjusted(-2, -2, 2, 2);
- } else {
- for (int i = 0; i < dirtyRegions.size(); ++i)
- region += dirtyRegions.at(i);
- for (int i = 0; i < dirtyRects.size(); ++i)
- region += dirtyRects.at(i);
- }
-
- viewport->update(region);
- }
+ if (viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate) {
+ if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
+ viewport->update(dirtyBoundingRect);
+ else
+ viewport->update(dirtyBoundingRect.adjusted(-2, -2, 2, 2));
+ } else {
+ viewport->update(dirtyRegion); // Already adjusted in updateRect/Region.
}
- dirtyRegions.clear();
- dirtyRects.clear();
- dirtyRectCount = 0;
dirtyBoundingRect = QRect();
- updatingLater = false;
+ dirtyRegion = QRegion();
}
void QGraphicsViewPrivate::updateAll()
@@ -930,14 +831,13 @@ void QGraphicsViewPrivate::updateAll()
Q_Q(QGraphicsView);
q->viewport()->update();
fullUpdatePending = true;
- dirtyRectCount = 0;
dirtyBoundingRect = QRect();
- updatingLater = false;
+ dirtyRegion = QRegion();
}
void QGraphicsViewPrivate::updateRegion(const QRegion &r)
{
- if (r.isEmpty())
+ if (r.isEmpty() || fullUpdatePending)
return;
Q_Q(QGraphicsView);
@@ -950,45 +850,30 @@ void QGraphicsViewPrivate::updateRegion(const QRegion &r)
break;
case QGraphicsView::BoundingRectViewportUpdate:
dirtyBoundingRect |= r.boundingRect();
- if (dirtyBoundingRect == q->viewport()->rect()) {
+ if (dirtyBoundingRect.contains(q->viewport()->rect())) {
fullUpdatePending = true;
q->viewport()->update();
- } else {
- updateLater();
}
break;
- case QGraphicsView::SmartViewportUpdate:
- dirtyBoundingRect |= r.boundingRect();
- if ((dirtyRectCount + r.numRects()) < QGRAPHICSVIEW_REGION_RECT_THRESHOLD)
- dirtyRegions << r;
- dirtyRectCount += r.numRects();
- updateLater();
- break;
+ case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE
case QGraphicsView::MinimalViewportUpdate:
- dirtyRegions << r;
- dirtyRectCount += r.numRects();
- updateLater();
+ if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing) {
+ dirtyRegion += r;
+ } else {
+ const QVector<QRect> &rects = r.rects();
+ for (int i = 0; i < rects.size(); ++i)
+ dirtyRegion += rects.at(i).adjusted(-2, -2, 2, 2);
+ }
break;
case QGraphicsView::NoViewportUpdate:
// Unreachable
break;
}
-
- // Compress the regions...
- if (dirtyRectCount > QGRAPHICSVIEW_REGION_RECT_THRESHOLD && dirtyRegions.size() > 1) {
- QRegion masterRegion;
- for (int i=0; i<dirtyRegions.size(); ++i) {
- masterRegion |= dirtyRegions.at(i);
- }
- dirtyRectCount = masterRegion.numRects();
- dirtyRegions.clear();
- dirtyRegions << masterRegion;
- }
}
void QGraphicsViewPrivate::updateRect(const QRect &r)
{
- if (r.isEmpty())
+ if (r.isEmpty() || fullUpdatePending)
return;
Q_Q(QGraphicsView);
@@ -1001,22 +886,17 @@ void QGraphicsViewPrivate::updateRect(const QRect &r)
break;
case QGraphicsView::BoundingRectViewportUpdate:
dirtyBoundingRect |= r;
- if (dirtyBoundingRect == q->viewport()->rect()) {
+ if (dirtyBoundingRect.contains(q->viewport()->rect())) {
fullUpdatePending = true;
q->viewport()->update();
- } else {
- updateLater();
}
break;
- case QGraphicsView::SmartViewportUpdate:
- dirtyBoundingRect |= r;
- if ((dirtyRectCount + dirtyRects.size()) < QGRAPHICSVIEW_REGION_RECT_THRESHOLD)
- dirtyRects << r;
- updateLater();
- break;
+ case QGraphicsView::SmartViewportUpdate: // ### DEPRECATE
case QGraphicsView::MinimalViewportUpdate:
- dirtyRects << r;
- updateLater();
+ if (optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
+ dirtyRegion += r;
+ else
+ dirtyRegion += r.adjusted(-2, -2, 2, 2);
break;
case QGraphicsView::NoViewportUpdate:
// Unreachable
@@ -2613,9 +2493,10 @@ void QGraphicsView::updateScene(const QList<QRectF> &rects)
// Extract and reset dirty scene rect info.
QVector<QRect> dirtyViewportRects;
- for (int i = 0; i < d->dirtyRegions.size(); ++i)
- dirtyViewportRects += d->dirtyRegions.at(i).rects();
- d->dirtyRegions.clear();
+ const QVector<QRect> &dirtyRects = d->dirtyRegion.rects();
+ for (int i = 0; i < dirtyRects.size(); ++i)
+ dirtyViewportRects += dirtyRects.at(i);
+ d->dirtyRegion = QRegion();
bool fullUpdate = !d->accelerateScrolling || d->viewportUpdateMode == QGraphicsView::FullViewportUpdate;
bool boundingRectUpdate = (d->viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate)
@@ -3544,10 +3425,7 @@ void QGraphicsView::scrollContentsBy(int dx, int dy)
if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate) {
if (d->viewportUpdateMode != QGraphicsView::FullViewportUpdate) {
- for (int i = 0; i < d->dirtyRects.size(); ++i)
- d->dirtyRects[i].translate(dx, dy);
- for (int i = 0; i < d->dirtyRegions.size(); ++i)
- d->dirtyRegions[i].translate(dx, dy);
+ d->dirtyRegion.translate(dx, dy);
if (d->accelerateScrolling) {
#ifndef QT_NO_RUBBERBAND
// Update new and old rubberband regions
diff --git a/src/gui/graphicsview/qgraphicsview.h b/src/gui/graphicsview/qgraphicsview.h
index 7692e16..deed1d0 100644
--- a/src/gui/graphicsview/qgraphicsview.h
+++ b/src/gui/graphicsview/qgraphicsview.h
@@ -274,7 +274,6 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_setViewportCursor(const QCursor &))
Q_PRIVATE_SLOT(d_func(), void _q_unsetViewportCursor())
#endif
- Q_PRIVATE_SLOT(d_func(), void _q_updateLaterSlot())
friend class QGraphicsSceneWidget;
friend class QGraphicsScene;
friend class QGraphicsScenePrivate;
diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h
index c18f85d..637687b 100644
--- a/src/gui/graphicsview/qgraphicsview_p.h
+++ b/src/gui/graphicsview/qgraphicsview_p.h
@@ -159,15 +159,10 @@ public:
QRect mapToViewRect(const QGraphicsItem *item, const QRectF &rect) const;
QRegion mapToViewRegion(const QGraphicsItem *item, const QRectF &rect) const;
- void itemUpdated(QGraphicsItem *item, const QRectF &rect);
bool fullUpdatePending;
- QList<QRect> dirtyRects;
- QList<QRegion> dirtyRegions;
- int dirtyRectCount;
+ QRegion dirtyRegion;
QRect dirtyBoundingRect;
- void updateLater();
- bool updatingLater;
- void _q_updateLaterSlot();
+ void processPendingUpdates();
void updateAll();
void updateRect(const QRect &rect);
void updateRegion(const QRegion &region);