diff options
author | Dimitar Asenov <dimitar.asenov@gmail.com> | 2014-03-12 14:11:45 -0700 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-03-31 22:54:14 +0200 |
commit | 3270b4490bc420359483cb00ae48e91e261b30e8 (patch) | |
tree | d6e18a39fd0d21d36d10abe6edbfdb68084780ca /src | |
parent | d13d03f012b9c0516fa027f4e1ea18c12f1491ca (diff) |
Add a new optimization flag to QGraphicsItem.
The new flag ItemContainsChildrenInShape is similar to the existing
flag ItemClipsChildrenToShape. Setting the new flag makes QGraphicsScene
assume that children are drawn within the shape of the current item
but this is not enforced by clipping. When an application manually
ensures this clipping boundary, setting the new flag removes the
overhead of enforcing the clip with ItemClipsChildrenToShape, while
still allowing other routines to behave more optimially by assuming
children are within the shape of the current item.
[ChangeLog][QtWidgets][QGraphicsItem] Added the
ItemContainsChildrenInShape flag that enables using optimizations
of ItemClipsChildrenToShape without the overhead of enforcing the clip.
Change-Id: I5496fe1ca331b77fd51e0df8a3ace2b8e939eaf2
Reviewed-by: Andreas Aardal Hanssen <andreas@hanssen.name>
Diffstat (limited to 'src')
-rw-r--r-- | src/widgets/graphicsview/qgraphicsitem.cpp | 43 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsitem.h | 3 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsitem_p.h | 15 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsscene.cpp | 6 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicsscenebsptreeindex.cpp | 24 | ||||
-rw-r--r-- | src/widgets/graphicsview/qgraphicssceneindex.cpp | 3 |
6 files changed, 71 insertions, 23 deletions
diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index d4edc63403..605e96802b 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -332,6 +332,8 @@ this flag is disabled; children can draw anywhere. This behavior is enforced by QGraphicsView::drawItems() or QGraphicsScene::drawItems(). This flag was introduced in Qt 4.3. + \note This flag is similar to ItemContainsChildrenInShape but in addition + enforces the containment by clipping the children. \value ItemIgnoresTransformations The item ignores inherited transformations (i.e., its position is still anchored to its parent, but @@ -423,6 +425,19 @@ ItemStopsClickFocusPropagation, but also suppresses focus-out. This flag allows you to completely take over focus handling. This flag was introduced in Qt 4.7. \endomit + + \value ItemContainsChildrenInShape This flag indicates that all of the + item's direct or indirect children only draw within the item's shape. + Unlike ItemClipsChildrenToShape, this restriction is not enforced. Set + ItemContainsChildrenInShape when you manually assure that drawing + is bound to the item's shape and want to avoid the cost associated with + enforcing the clip. Setting this flag enables more efficient drawing and + collision detection. The flag is disabled by default. + \note If both this flag and ItemClipsChildrenToShape are set, the clip + will be enforced. This is equivalent to just setting + ItemClipsChildrenToShape. + . + This flag was introduced in Qt 5.4. */ /*! @@ -836,6 +851,10 @@ void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag ch flag = AncestorIgnoresTransformations; enabled = flags & QGraphicsItem::ItemIgnoresTransformations; break; + case QGraphicsItem::ItemContainsChildrenInShape: + flag = AncestorContainsChildren; + enabled = flags & QGraphicsItem::ItemContainsChildrenInShape; + break; default: return; } @@ -895,6 +914,8 @@ void QGraphicsItemPrivate::updateAncestorFlags() flags |= AncestorClipsChildren; if (pd->flags & QGraphicsItem::ItemIgnoresTransformations) flags |= AncestorIgnoresTransformations; + if (pd->flags & QGraphicsItem::ItemContainsChildrenInShape) + flags |= AncestorContainsChildren; } if (ancestorFlags == flags) @@ -1831,6 +1852,11 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) d_ptr->markParentDirty(true); } + if ((flags & ItemContainsChildrenInShape) != (oldFlags & ItemContainsChildrenInShape)) { + // Item children containtment changes. Propagate the ancestor flag to all children. + d_ptr->updateAncestorFlag(ItemContainsChildrenInShape); + } + if ((flags & ItemIgnoresTransformations) != (oldFlags & ItemIgnoresTransformations)) { // Item children clipping changes. Propagate the ancestor flag to // all children. @@ -2322,7 +2348,8 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, } // Update children with explicitly = false. - const bool updateChildren = update && !((flags & QGraphicsItem::ItemClipsChildrenToShape) + const bool updateChildren = update && !((flags & QGraphicsItem::ItemClipsChildrenToShape + || flags & QGraphicsItem::ItemContainsChildrenInShape) && !(flags & QGraphicsItem::ItemHasNoContents)); foreach (QGraphicsItem *child, children) { if (!newVisible || !child->d_ptr->explicitlyHidden) @@ -2835,7 +2862,9 @@ QRectF QGraphicsItemPrivate::effectiveBoundingRect(QGraphicsItem *topMostEffectI #ifndef QT_NO_GRAPHICSEFFECT Q_Q(const QGraphicsItem); QRectF brect = effectiveBoundingRect(q_ptr->boundingRect()); - if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren || topMostEffectItem == q) + if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren + || ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren + || topMostEffectItem == q) return brect; const QGraphicsItem *effectParent = parent; @@ -2847,6 +2876,7 @@ QRectF QGraphicsItemPrivate::effectiveBoundingRect(QGraphicsItem *topMostEffectI brect = effectParent->mapRectToItem(q, effectRectInParentSpace); } if (effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren + || effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren || topMostEffectItem == effectParent) { return brect; } @@ -7442,7 +7472,8 @@ QVariant QGraphicsItem::extension(const QVariant &variant) const */ void QGraphicsItem::addToIndex() { - if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) { + if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren + || d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren) { // ### add to child index only if applicable return; } @@ -7459,7 +7490,8 @@ void QGraphicsItem::addToIndex() */ void QGraphicsItem::removeFromIndex() { - if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) { + if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren + || d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren) { // ### remove from child index only if applicable return; } @@ -11451,6 +11483,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag) case QGraphicsItem::ItemStopsFocusHandling: str = "ItemStopsFocusHandling"; break; + case QGraphicsItem::ItemContainsChildrenInShape: + str = "ItemContainsChildrenInShape"; + break; } debug << str; return debug; diff --git a/src/widgets/graphicsview/qgraphicsitem.h b/src/widgets/graphicsview/qgraphicsitem.h index 4283deb5b8..dfc06fdaea 100644 --- a/src/widgets/graphicsview/qgraphicsitem.h +++ b/src/widgets/graphicsview/qgraphicsitem.h @@ -105,7 +105,8 @@ public: ItemIsFocusScope = 0x8000, // internal ItemSendsScenePositionChanges = 0x10000, ItemStopsClickFocusPropagation = 0x20000, - ItemStopsFocusHandling = 0x40000 + ItemStopsFocusHandling = 0x40000, + ItemContainsChildrenInShape = 0x80000 // NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag. }; Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag) diff --git a/src/widgets/graphicsview/qgraphicsitem_p.h b/src/widgets/graphicsview/qgraphicsitem_p.h index 3968d89a13..4d1835f178 100644 --- a/src/widgets/graphicsview/qgraphicsitem_p.h +++ b/src/widgets/graphicsview/qgraphicsitem_p.h @@ -172,7 +172,8 @@ public: AncestorHandlesChildEvents = 0x1, AncestorClipsChildren = 0x2, AncestorIgnoresTransformations = 0x4, - AncestorFiltersChildEvents = 0x8 + AncestorFiltersChildEvents = 0x8, + AncestorContainsChildren = 0x10 }; inline QGraphicsItemPrivate() @@ -213,7 +214,6 @@ public: needSortChildren(0), allChildrenDirty(0), fullUpdatePending(0), - dirtyChildrenBoundingRect(1), flags(0), paintedViewBoundingRectsNeedRepaint(0), dirtySceneTransform(1), @@ -239,6 +239,7 @@ public: mayHaveChildWithGraphicsEffect(0), isDeclarativeItem(0), sendParentChangeNotification(0), + dirtyChildrenBoundingRect(1), globalStackingOrder(-1), q_ptr(0) { @@ -544,7 +545,7 @@ public: quint32 handlesChildEvents : 1; quint32 itemDiscovered : 1; quint32 hasCursor : 1; - quint32 ancestorFlags : 4; + quint32 ancestorFlags : 5; quint32 cacheMode : 2; quint32 hasBoundingRegionGranularity : 1; quint32 isWidget : 1; @@ -555,10 +556,9 @@ public: quint32 needSortChildren : 1; quint32 allChildrenDirty : 1; quint32 fullUpdatePending : 1; - quint32 dirtyChildrenBoundingRect : 1; // Packed 32 bits - quint32 flags : 19; + quint32 flags : 20; quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; quint32 geometryChanged : 1; @@ -571,9 +571,9 @@ public: quint32 filtersDescendantEvents : 1; quint32 sceneTransformTranslateOnly : 1; quint32 notifyBoundingRectChanged : 1; - quint32 notifyInvalidated : 1; // New 32 bits + quint32 notifyInvalidated : 1; quint32 mouseSetsFocus : 1; quint32 explicitActivate : 1; quint32 wantsActive : 1; @@ -585,7 +585,8 @@ public: quint32 mayHaveChildWithGraphicsEffect : 1; quint32 isDeclarativeItem : 1; quint32 sendParentChangeNotification : 1; - quint32 padding : 21; + quint32 dirtyChildrenBoundingRect : 1; + quint32 padding : 19; // Optional stacking order int globalStackingOrder; diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp index a7584ef198..1cd162e6bb 100644 --- a/src/widgets/graphicsview/qgraphicsscene.cpp +++ b/src/widgets/graphicsview/qgraphicsscene.cpp @@ -4717,7 +4717,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * wasDirtyParentSceneTransform = true; } - const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); + const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape + || item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape); bool drawItem = itemHasContents && !itemIsFullyTransparent; if (drawItem || minimumRenderSize > 0.0) { const QRectF brect = adjustedItemEffectiveBoundingRect(item); @@ -5221,7 +5222,8 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool // Process children. if (itemHasChildren && item->d_ptr->dirtyChildren) { - const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape; + const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape + || item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape; // Items with no content are threated as 'dummy' items which means they are never drawn and // 'processed', so the painted view bounding rect is never up-to-date. This means that whenever // such an item changes geometry, its children have to take care of the update regardless diff --git a/src/widgets/graphicsview/qgraphicsscenebsptreeindex.cpp b/src/widgets/graphicsview/qgraphicsscenebsptreeindex.cpp index 7598163f2d..50f17ab73f 100644 --- a/src/widgets/graphicsview/qgraphicsscenebsptreeindex.cpp +++ b/src/widgets/graphicsview/qgraphicsscenebsptreeindex.cpp @@ -169,7 +169,8 @@ void QGraphicsSceneBspTreeIndexPrivate::_q_updateIndex() untransformableItems << item; continue; } - if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) + if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren + || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren) continue; bsp.insertItem(item, item->d_ptr->sceneEffectiveBoundingRect()); @@ -351,7 +352,8 @@ void QGraphicsSceneBspTreeIndexPrivate::removeItem(QGraphicsItem *item, bool rec // Avoid virtual function calls from the destructor. purgePending = true; removedItems << item; - } else if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) { + } else if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren + || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)) { bsp.removeItem(item, item->d_ptr->sceneEffectiveBoundingRect()); } } else { @@ -510,7 +512,8 @@ void QGraphicsSceneBspTreeIndex::prepareBoundingRectChange(const QGraphicsItem * return; if (item->d_ptr->index == -1 || item->d_ptr->itemIsUntransformable() - || (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) { + || (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren + || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)) { return; // Item is not in BSP tree; nothing to do. } @@ -641,8 +644,10 @@ void QGraphicsSceneBspTreeIndex::itemChange(const QGraphicsItem *item, QGraphics QGraphicsItem::GraphicsItemFlags newFlags = *static_cast<const QGraphicsItem::GraphicsItemFlags *>(value); bool ignoredTransform = item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations; bool willIgnoreTransform = newFlags & QGraphicsItem::ItemIgnoresTransformations; - bool clipsChildren = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape; - bool willClipChildren = newFlags & QGraphicsItem::ItemClipsChildrenToShape; + bool clipsChildren = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape + || item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape; + bool willClipChildren = newFlags & QGraphicsItem::ItemClipsChildrenToShape + || newFlags & QGraphicsItem::ItemContainsChildrenInShape; if ((ignoredTransform != willIgnoreTransform) || (clipsChildren != willClipChildren)) { QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item); // Remove item and its descendants from the index and append @@ -663,10 +668,13 @@ void QGraphicsSceneBspTreeIndex::itemChange(const QGraphicsItem *item, QGraphics bool ignoredTransform = item->d_ptr->itemIsUntransformable(); bool willIgnoreTransform = (item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations) || (newParent && newParent->d_ptr->itemIsUntransformable()); - bool ancestorClippedChildren = item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren; + bool ancestorClippedChildren = item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren + || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren; bool ancestorWillClipChildren = newParent - && ((newParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) - || (newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)); + && ((newParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape + || newParent->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape) + || (newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren + || newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)); if ((ignoredTransform != willIgnoreTransform) || (ancestorClippedChildren != ancestorWillClipChildren)) { QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item); // Remove item and its descendants from the index and append diff --git a/src/widgets/graphicsview/qgraphicssceneindex.cpp b/src/widgets/graphicsview/qgraphicssceneindex.cpp index 40f63937f4..d06c5523ca 100644 --- a/src/widgets/graphicsview/qgraphicssceneindex.cpp +++ b/src/widgets/graphicsview/qgraphicssceneindex.cpp @@ -278,7 +278,8 @@ void QGraphicsSceneIndexPrivate::recursive_items_helper(QGraphicsItem *item, QRe Q_ASSERT(!item->d_ptr->dirtySceneTransform); } - const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); + const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape + || item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape); bool processItem = !itemIsFullyTransparent; if (processItem) { processItem = intersect(item, exposeRect, mode, viewTransform, intersectData); |