src/gui/graphicsview/qgraphicsitem.cpp
changeset 18 2f34d5167611
parent 3 41300fa6a67c
child 19 fcece45ef507
--- a/src/gui/graphicsview/qgraphicsitem.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/src/gui/graphicsview/qgraphicsitem.cpp	Fri Apr 16 15:50:13 2010 +0300
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
@@ -268,6 +268,17 @@
 */
 
 /*!
+    \variable QGraphicsItem::Type
+
+    The type value returned by the virtual type() function in standard
+    graphics item classes in Qt. All such standard graphics item
+    classes in Qt are associated with a unique value for Type,
+    e.g. the value returned by QGraphicsPathItem::type() is 2.
+
+    \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 18
+*/
+
+/*!
     \variable QGraphicsItem::UserType
 
     The lowest permitted type value for custom items (subclasses
@@ -276,6 +287,8 @@
     and declaring a Type enum value. Example:
 
     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 1
+
+    \note UserType = 65536
 */
 
 /*!
@@ -306,7 +319,7 @@
     QGraphicsItem::keyPressEvent() and QGraphicsItem::keyReleaseEvent().
 
     \value ItemClipsToShape The item clips to its own shape. The item cannot
-    draw or receive mouse, tablet, drag and drop or hover events outside ts
+    draw or receive mouse, tablet, drag and drop or hover events outside its
     shape. It is disabled by default. This behavior is enforced by
     QGraphicsView::drawItems() or QGraphicsScene::drawItems(). This flag was
     introduced in Qt 4.3.
@@ -344,19 +357,22 @@
     default, child items are stacked on top of the parent item. But setting
     this flag, the child will be stacked behind it. This flag is useful for
     drop shadow effects and for decoration objects that follow the parent
-    item's geometry without drawing on top of it.
+    item's geometry without drawing on top of it. This flag was introduced
+    in Qt 4.5.
 
     \value ItemUsesExtendedStyleOption The item makes use of either
-    \l{QStyleOptionGraphicsItem::}{exposedRect} or
-    \l{QStyleOptionGraphicsItem::}{matrix} in QStyleOptionGraphicsItem. By default,
-    the \l{QStyleOptionGraphicsItem::}{exposedRect} is initialized to the item's
-    boundingRect() and the \l{QStyleOptionGraphicsItem::}{matrix} is untransformed.
-    You can enable this flag for the style options to be set up with more
-    fine-grained values.
-    Note that QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag
+    \l{QStyleOptionGraphicsItem::} {exposedRect} or
+    \l{QStyleOptionGraphicsItem::} {matrix} in
+    QStyleOptionGraphicsItem. By default, the
+    \l{QStyleOptionGraphicsItem::} {exposedRect} is initialized to the
+    item's boundingRect() and the
+    \l{QStyleOptionGraphicsItem::}{matrix} is untransformed.  You can
+    enable this flag for the style options to be set up with more
+    fine-grained values.  Note that
+    QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag
     and always initialized to 1. Use
-    QStyleOptionGraphicsItem::levelOfDetailFromTransform() if you need a higher
-    value.
+    QStyleOptionGraphicsItem::levelOfDetailFromTransform() if you need
+    a higher value. This flag was introduced in Qt 4.6.
 
     \value ItemHasNoContents The item does not paint anything (i.e., calling
     paint() on the item has no effect). You should set this flag on items that
@@ -374,9 +390,10 @@
     used for Asian languages.
     This flag was introduced in Qt 4.6.
 
-    \value ItemNegativeZStacksBehindParent The item automatically stacks behind
-    it's parent if it's z-value is negative. This flag enables setZValue() to
-    toggle ItemStacksBehindParent.
+    \value ItemNegativeZStacksBehindParent The item automatically
+    stacks behind it's parent if it's z-value is negative. This flag
+    enables setZValue() to toggle ItemStacksBehindParent. This flag
+    was introduced in Qt 4.6.
 
     \value ItemIsPanel The item is a panel. A panel provides activation and
     contained focus handling. Only one panel can be active at a time (see
@@ -798,8 +815,36 @@
             return;
     }
 
-    foreach (QGraphicsItem *child, children)
-        child->d_ptr->updateAncestorFlag(childFlag, flag, enabled, false);
+    for (int i = 0; i < children.size(); ++i)
+        children.at(i)->d_ptr->updateAncestorFlag(childFlag, flag, enabled, false);
+}
+
+void QGraphicsItemPrivate::updateAncestorFlags()
+{
+    int flags = 0;
+    if (parent) {
+        // Inherit the parent's ancestor flags.
+        QGraphicsItemPrivate *pd = parent->d_ptr.data();
+        flags = pd->ancestorFlags;
+
+        // Add in flags from the parent.
+        if (pd->filtersDescendantEvents)
+            flags |= AncestorFiltersChildEvents;
+        if (pd->handlesChildEvents)
+            flags |= AncestorHandlesChildEvents;
+        if (pd->flags & QGraphicsItem::ItemClipsChildrenToShape)
+            flags |= AncestorClipsChildren;
+        if (pd->flags & QGraphicsItem::ItemIgnoresTransformations)
+            flags |= AncestorIgnoresTransformations;
+    }
+
+    if (ancestorFlags == flags)
+        return; // No change; stop propagation.
+    ancestorFlags = flags;
+
+    // Propagate to children recursively.
+    for (int i = 0; i < children.size(); ++i)
+        children.at(i)->d_ptr->updateAncestorFlags();
 }
 
 /*!
@@ -984,25 +1029,17 @@
     prepareGeometryChange) if the item is in its destructor, i.e.
     inDestructor is 1.
 */
-void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent)
+void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, const QVariant *newParentVariant,
+                                               const QVariant *thisPointerVariant)
 {
     Q_Q(QGraphicsItem);
-    if (newParent == q) {
-        qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this);
-        return;
-    }
-    if (newParent == parent)
-        return;
-
-    const QVariant newParentVariant(q->itemChange(QGraphicsItem::ItemParentChange,
-                                                  qVariantFromValue<QGraphicsItem *>(newParent)));
-    newParent = qVariantValue<QGraphicsItem *>(newParentVariant);
     if (newParent == parent)
         return;
 
     if (scene) {
         // Deliver the change to the index
-        scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParentVariant);
+        if (scene->d_func()->indexMethod != QGraphicsScene::NoIndex)
+            scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParent);
 
         // Disable scene pos notifications for old ancestors
         if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
@@ -1020,11 +1057,11 @@
     if (!inDestructor)
         q_ptr->prepareGeometryChange();
 
-    const QVariant thisPointerVariant(qVariantFromValue<QGraphicsItem *>(q));
     if (parent) {
         // Remove from current parent
         parent->d_ptr->removeChild(q);
-        parent->itemChange(QGraphicsItem::ItemChildRemovedChange, thisPointerVariant);
+        if (thisPointerVariant)
+            parent->itemChange(QGraphicsItem::ItemChildRemovedChange, *thisPointerVariant);
     }
 
     // Update toplevelitem list. If this item is being deleted, its parent
@@ -1042,7 +1079,7 @@
     QGraphicsItem *p = parent;
     QGraphicsItem *parentFocusScopeItem = 0;
     while (p) {
-        if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+        if (p->d_ptr->flags & QGraphicsItem::ItemIsFocusScope) {
             // If this item's focus scope's focus scope item points
             // to this item or a descendent, then clear it.
             QGraphicsItem *fsi = p->d_ptr->focusScopeItem;
@@ -1055,6 +1092,10 @@
         p = p->d_ptr->parent;
     }
 
+    // Update graphics effect optimization flag
+    if (newParent && (graphicsEffect || mayHaveChildWithGraphicsEffect))
+        newParent->d_ptr->updateChildWithGraphicsEffectFlagRecursively();
+
     // Update focus scope item ptr in new scope.
     QGraphicsItem *newFocusScopeItem = subFocusItem ? subFocusItem : parentFocusScopeItem;
     if (newFocusScopeItem && newParent) {
@@ -1063,11 +1104,11 @@
             QGraphicsItem *ancestorScope = 0;
             QGraphicsItem *p = subFocusItem->d_ptr->parent;
             while (p) {
-                if (p->flags() & QGraphicsItem::ItemIsFocusScope)
+                if (p->d_ptr->flags & QGraphicsItem::ItemIsFocusScope)
                     ancestorScope = p;
-                if (p->isPanel())
+                if (p->d_ptr->flags & QGraphicsItem::ItemIsPanel)
                     break;
-                p = p->parentItem();
+                p = p->d_ptr->parent;
             }
             if (ancestorScope)
                 newFocusScopeItem = ancestorScope;
@@ -1075,7 +1116,7 @@
 
         QGraphicsItem *p = newParent;
         while (p) {
-            if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+            if (p->d_ptr->flags & QGraphicsItem::ItemIsFocusScope) {
                 p->d_ptr->focusScopeItem = newFocusScopeItem;
                 // Ensure the new item is no longer the subFocusItem. The
                 // only way to set focus on a child of a focus scope is
@@ -1089,52 +1130,45 @@
     }
 
     if ((parent = newParent)) {
-        bool implicitUpdate = false;
         if (parent->d_func()->scene && parent->d_func()->scene != scene) {
             // Move this item to its new parent's scene
             parent->d_func()->scene->addItem(q);
-            implicitUpdate = true;
         } else if (!parent->d_func()->scene && scene) {
             // Remove this item from its former scene
             scene->removeItem(q);
         }
 
         parent->d_ptr->addChild(q);
-        parent->itemChange(QGraphicsItem::ItemChildAddedChange, thisPointerVariant);
+        if (thisPointerVariant)
+            parent->itemChange(QGraphicsItem::ItemChildAddedChange, *thisPointerVariant);
         if (scene) {
-            if (!implicitUpdate)
-                scene->d_func()->markDirty(q_ptr);
-
             // Re-enable scene pos notifications for new ancestors
             if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
                 scene->d_func()->setScenePosItemEnabled(q, true);
         }
 
+        // Propagate dirty flags to the new parent
+        markParentDirty(/*updateBoundingRect=*/true);
+
         // Inherit ancestor flags from the new parent.
-        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
-        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
-        updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape);
-        updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations);
+        updateAncestorFlags();
 
         // Update item visible / enabled.
-        if (parent->isVisible() != visible) {
-            if (!parent->isVisible() || !explicitlyHidden)
-                setVisibleHelper(parent->isVisible(), /* explicit = */ false, /* update = */ !implicitUpdate);
+        if (parent->d_ptr->visible != visible) {
+            if (!parent->d_ptr->visible || !explicitlyHidden)
+                setVisibleHelper(parent->d_ptr->visible, /* explicit = */ false, /* update = */ false);
         }
         if (parent->isEnabled() != enabled) {
-            if (!parent->isEnabled() || !explicitlyDisabled)
-                setEnabledHelper(parent->isEnabled(), /* explicit = */ false, /* update = */ !implicitUpdate);
+            if (!parent->d_ptr->enabled || !explicitlyDisabled)
+                setEnabledHelper(parent->d_ptr->enabled, /* explicit = */ false, /* update = */ false);
         }
 
         // Auto-activate if visible and the parent is active.
-        if (q->isVisible() && parent->isActive())
+        if (visible && parent->isActive())
             q->setActive(true);
     } else {
         // Inherit ancestor flags from the new parent.
-        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
-        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
-        updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape);
-        updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations);
+        updateAncestorFlags();
 
         if (!inDestructor) {
             // Update item visible / enabled.
@@ -1142,10 +1176,6 @@
                 setVisibleHelper(true, /* explicit = */ false);
             if (!enabled && !explicitlyDisabled)
                 setEnabledHelper(true, /* explicit = */ false);
-
-            // If the item is being deleted, the whole scene will be updated.
-            if (scene)
-                scene->d_func()->markDirty(q_ptr);
         }
     }
 
@@ -1161,7 +1191,8 @@
     }
 
     // Deliver post-change notification
-    q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant);
+    if (newParentVariant)
+        q->itemChange(QGraphicsItem::ItemParentHasChanged, *newParentVariant);
 
     if (isObject)
         emit static_cast<QGraphicsObject *>(q)->parentChanged();
@@ -1350,7 +1381,7 @@
         d_ptr->scene->d_func()->removeItemHelper(this);
     } else {
         d_ptr->resetFocusProxy();
-        d_ptr->setParentItemHelper(0);
+        setParentItem(0);
     }
 
 #ifndef QT_NO_GRAPHICSEFFECT
@@ -1365,7 +1396,8 @@
     }
     delete d_ptr->transformData;
 
-    qt_dataStore()->data.remove(this);
+    if (QGraphicsItemCustomDataStore *dataStore = qt_dataStore())
+        dataStore->data.remove(this);
 }
 
 /*!
@@ -1543,21 +1575,36 @@
 }
 
 /*!
-    Sets this item's parent item to \a parent. If this item already has a
-    parent, it is first removed from the previous parent. If \a parent is 0,
-    this item will become a top-level item.
-
-    Note that this implicitly adds this graphics item to the scene of
-    the parent. You should not \l{QGraphicsScene::addItem()}{add} the
-    item to the scene yourself.
-
-    Calling this function on an item that is an ancestor of \a parent have undefined behaviour.
-
-    \sa parentItem(), childItems()
-*/
-void QGraphicsItem::setParentItem(QGraphicsItem *parent)
-{
-    d_ptr->setParentItemHelper(parent);
+  Sets this item's parent item to \a newParent. If this item already
+  has a parent, it is first removed from the previous parent. If \a
+  newParent is 0, this item will become a top-level item.
+
+  Note that this implicitly adds this graphics item to the scene of
+  the parent. You should not \l{QGraphicsScene::addItem()}{add} the
+  item to the scene yourself.
+
+  Calling this function on an item that is an ancestor of \a newParent
+  have undefined behaviour.
+
+  \sa parentItem(), childItems()
+*/
+void QGraphicsItem::setParentItem(QGraphicsItem *newParent)
+{
+    if (newParent == this) {
+        qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this);
+        return;
+    }
+    if (newParent == d_ptr->parent)
+        return;
+
+    const QVariant newParentVariant(itemChange(QGraphicsItem::ItemParentChange,
+                                               qVariantFromValue<QGraphicsItem *>(newParent)));
+    newParent = qVariantValue<QGraphicsItem *>(newParentVariant);
+    if (newParent == d_ptr->parent)
+        return;
+
+    const QVariant thisPointerVariant(qVariantFromValue<QGraphicsItem *>(this));
+    d_ptr->setParentItemHelper(newParent, &newParentVariant, &thisPointerVariant);
 }
 
 /*!
@@ -1607,7 +1654,7 @@
 */
 bool QGraphicsItem::isWindow() const
 {
-    return isWidget() && (static_cast<const QGraphicsWidget *>(this)->windowType() & Qt::Window);
+    return d_ptr->isWidget && (static_cast<const QGraphicsWidget *>(this)->windowType() & Qt::Window);
 }
 
 /*!
@@ -1644,9 +1691,9 @@
 void QGraphicsItem::setFlag(GraphicsItemFlag flag, bool enabled)
 {
     if (enabled)
-        setFlags(flags() | flag);
+        setFlags(GraphicsItemFlags(d_ptr->flags) | flag);
     else
-        setFlags(flags() & ~flag);
+        setFlags(GraphicsItemFlags(d_ptr->flags) & ~flag);
 }
 
 /*!
@@ -1693,8 +1740,8 @@
     flags = GraphicsItemFlags(itemChange(ItemFlagsChange, quint32(flags)).toUInt());
     if (quint32(d_ptr->flags) == quint32(flags))
         return;
-    if (d_ptr->scene)
-        d_ptr->scene->d_func()->index->itemChange(this, ItemFlagsChange, quint32(flags));
+    if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex)
+        d_ptr->scene->d_func()->index->itemChange(this, ItemFlagsChange, &flags);
 
     // Flags that alter the geometry of the item (or its children).
     const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations | ItemIsSelectable);
@@ -1703,7 +1750,7 @@
         d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
 
     // Keep the old flags to compare the diff.
-    GraphicsItemFlags oldFlags = this->flags();
+    GraphicsItemFlags oldFlags = GraphicsItemFlags(d_ptr->flags);
 
     // Update flags.
     d_ptr->flags = flags;
@@ -1732,7 +1779,23 @@
         d_ptr->updateAncestorFlag(ItemIgnoresTransformations);
     }
 
+    if ((flags & ItemNegativeZStacksBehindParent) != (oldFlags & ItemNegativeZStacksBehindParent)) {
+        // NB! We change the flags directly here, so we must also update d_ptr->flags.
+        // Note that this has do be done before the ItemStacksBehindParent check
+        // below; otherwise we will loose the change.
+
+        // Update stack-behind.
+        if (d_ptr->z < qreal(0.0))
+            flags |= ItemStacksBehindParent;
+        else
+            flags &= ~ItemStacksBehindParent;
+        d_ptr->flags = flags;
+    }
+
     if ((flags & ItemStacksBehindParent) != (oldFlags & ItemStacksBehindParent)) {
+        // NB! This check has to come after the ItemNegativeZStacksBehindParent
+        // check above. Be careful.
+
         // Ensure child item sorting is up to date when toggling this flag.
         if (d_ptr->parent)
             d_ptr->parent->d_ptr->needSortChildren = 1;
@@ -1746,10 +1809,6 @@
             d_ptr->scene->d_func()->updateInputMethodSensitivityInViews();
     }
 
-    if ((flags & ItemNegativeZStacksBehindParent) != (oldFlags & ItemNegativeZStacksBehindParent)) {
-        // Update stack-behind.
-        setFlag(ItemStacksBehindParent, d_ptr->z < qreal(0.0));
-    }
 
     if ((d_ptr->panelModality != NonModal)
         && d_ptr->scene
@@ -2515,6 +2574,7 @@
     if (newOpacity == d_ptr->opacity)
         return;
 
+    bool wasFullyTransparent = d_ptr->isOpacityNull();
     d_ptr->opacity = newOpacity;
 
     // Notify change.
@@ -2523,12 +2583,16 @@
     // Update.
     if (d_ptr->scene) {
 #ifndef QT_NO_GRAPHICSEFFECT
-        d_ptr->invalidateGraphicsEffectsRecursively();
+        d_ptr->invalidateParentGraphicsEffectsRecursively();
+        if (!(d_ptr->flags & ItemDoesntPropagateOpacityToChildren))
+            d_ptr->invalidateChildGraphicsEffectsRecursively(QGraphicsItemPrivate::OpacityChanged);
 #endif //QT_NO_GRAPHICSEFFECT
         d_ptr->scene->d_func()->markDirty(this, QRectF(),
                                           /*invalidateChildren=*/true,
                                           /*force=*/false,
-                                          /*ignoreOpacity=*/true);
+                                          /*ignoreOpacity=*/d_ptr->isOpacityNull());
+        if (wasFullyTransparent)
+            d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
     }
 
     if (d_ptr->isObject)
@@ -2568,6 +2632,8 @@
     if (d_ptr->graphicsEffect) {
         delete d_ptr->graphicsEffect;
         d_ptr->graphicsEffect = 0;
+    } else if (d_ptr->parent) {
+        d_ptr->parent->d_ptr->updateChildWithGraphicsEffectFlagRecursively();
     }
 
     if (effect) {
@@ -2581,6 +2647,19 @@
 }
 #endif //QT_NO_GRAPHICSEFFECT
 
+void QGraphicsItemPrivate::updateChildWithGraphicsEffectFlagRecursively()
+{
+#ifndef QT_NO_GRAPHICSEFFECT
+    QGraphicsItemPrivate *itemPrivate = this;
+    do {
+        // parent chain already notified?
+        if (itemPrivate->mayHaveChildWithGraphicsEffect)
+            return;
+        itemPrivate->mayHaveChildWithGraphicsEffect = 1;
+    } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : 0));
+#endif
+}
+
 /*!
     \internal
     \since 4.6
@@ -2997,9 +3076,16 @@
 */
 bool QGraphicsItem::hasFocus() const
 {
+    if (!d_ptr->scene || !d_ptr->scene->isActive())
+        return false;
+
     if (d_ptr->focusProxy)
         return d_ptr->focusProxy->hasFocus();
-    return isActive() && (d_ptr->scene && d_ptr->scene->focusItem() == this);
+
+    if (d_ptr->scene->d_func()->focusItem != this)
+        return false;
+
+    return panel() == d_ptr->scene->d_func()->activePanel;
 }
 
 /*!
@@ -4257,9 +4343,9 @@
     if (newZ == d_ptr->z)
         return;
 
-    if (d_ptr->scene) {
+    if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex) {
         // Z Value has changed, we have to notify the index.
-        d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, newZVariant);
+        d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, &newZ);
     }
 
     d_ptr->z = newZ;
@@ -5026,7 +5112,7 @@
     \internal
 */
 #ifndef QT_NO_GRAPHICSEFFECT
-void QGraphicsItemPrivate::invalidateGraphicsEffectsRecursively()
+void QGraphicsItemPrivate::invalidateParentGraphicsEffectsRecursively()
 {
     QGraphicsItemPrivate *itemPrivate = this;
     do {
@@ -5038,6 +5124,24 @@
         }
     } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : 0));
 }
+
+void QGraphicsItemPrivate::invalidateChildGraphicsEffectsRecursively(QGraphicsItemPrivate::InvalidateReason reason)
+{
+    if (!mayHaveChildWithGraphicsEffect)
+        return;
+
+    for (int i = 0; i < children.size(); ++i) {
+        QGraphicsItemPrivate *childPrivate = children.at(i)->d_ptr.data();
+        if (reason == OpacityChanged && (childPrivate->flags & QGraphicsItem::ItemIgnoresParentOpacity))
+            continue;
+        if (childPrivate->graphicsEffect) {
+            childPrivate->notifyInvalidated = 1;
+            static_cast<QGraphicsItemEffectSourcePrivate *>(childPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache();
+        }
+
+        childPrivate->invalidateChildGraphicsEffectsRecursively(reason);
+    }
+}
 #endif //QT_NO_GRAPHICSEFFECT
 
 /*!
@@ -5282,7 +5386,7 @@
 
     // Make sure we notify effects about invalidated source.
 #ifndef QT_NO_GRAPHICSEFFECT
-    d_ptr->invalidateGraphicsEffectsRecursively();
+    d_ptr->invalidateParentGraphicsEffectsRecursively();
 #endif //QT_NO_GRAPHICSEFFECT
 
     if (CacheMode(d_ptr->cacheMode) != NoCache) {
@@ -7158,7 +7262,9 @@
 
         QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func();
         scenePrivate->index->prepareBoundingRectChange(this);
-        scenePrivate->markDirty(this, QRectF(), /*invalidateChildren=*/true);
+        scenePrivate->markDirty(this, QRectF(), /*invalidateChildren=*/true, /*force=*/false,
+                                /*ignoreOpacity=*/ false, /*removingItemFromScene=*/ false,
+                                /*updateBoundingRect=*/true);
 
         // For compatibility reasons, we have to update the item's old geometry
         // if someone is connected to the changed signal or the scene has no views.
@@ -7175,19 +7281,7 @@
         }
     }
 
-    QGraphicsItem *parent = this;
-    while ((parent = parent->d_ptr->parent)) {
-        QGraphicsItemPrivate *parentp = parent->d_ptr.data();
-        parentp->dirtyChildrenBoundingRect = 1;
-        // ### Only do this if the parent's effect applies to the entire subtree.
-        parentp->notifyBoundingRectChanged = 1;
-#ifndef QT_NO_GRAPHICSEFFECT
-        if (parentp->scene && parentp->graphicsEffect) {
-            parentp->notifyInvalidated = 1;
-            static_cast<QGraphicsItemEffectSourcePrivate *>(parentp->graphicsEffect->d_func()->source->d_func())->invalidateCache();
-        }
-#endif
-    }
+    d_ptr->markParentDirty(/*updateBoundingRect=*/true);
 }
 
 /*!
@@ -10715,6 +10809,36 @@
     }
 }
 
+QRect QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded) const
+{
+    QRectF effectRectF;
+
+    if (unpadded)
+        *unpadded = false;
+
+    if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) {
+        if (info) {
+            effectRectF = item->graphicsEffect()->boundingRectFor(boundingRect(Qt::DeviceCoordinates));
+            if (unpadded)
+                *unpadded = (effectRectF.size() == sourceRect.size());
+            if (info && system == Qt::LogicalCoordinates)
+                effectRectF = info->painter->worldTransform().inverted().mapRect(effectRectF);
+        } else {
+            // no choice but to send a logical coordinate bounding rect to boundingRectFor
+            effectRectF = item->graphicsEffect()->boundingRectFor(sourceRect);
+        }
+    } else if (mode == QGraphicsEffect::PadToTransparentBorder) {
+        // adjust by 1.5 to account for cosmetic pens
+        effectRectF = sourceRect.adjusted(-1.5, -1.5, 1.5, 1.5);
+    } else {
+        effectRectF = sourceRect;
+        if (unpadded)
+            *unpadded = true;
+    }
+
+    return effectRectF.toAlignedRect();
+}
+
 QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset,
                                                  QGraphicsEffect::PixmapPadMode mode) const
 {
@@ -10728,29 +10852,9 @@
         return QPixmap();
     QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
 
+    bool unpadded;
     const QRectF sourceRect = boundingRect(system);
-    QRectF effectRectF;
-
-    bool unpadded = false;
-    if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) {
-        if (info) {
-            effectRectF = item->graphicsEffect()->boundingRectFor(boundingRect(Qt::DeviceCoordinates));
-            unpadded = (effectRectF.size() == sourceRect.size());
-            if (info && system == Qt::LogicalCoordinates)
-                effectRectF = info->painter->worldTransform().inverted().mapRect(effectRectF);
-        } else {
-            // no choice but to send a logical coordinate bounding rect to boundingRectFor
-            effectRectF = item->graphicsEffect()->boundingRectFor(sourceRect);
-        }
-    } else if (mode == QGraphicsEffect::PadToTransparentBorder) {
-        // adjust by 1.5 to account for cosmetic pens
-        effectRectF = sourceRect.adjusted(-1.5, -1.5, 1.5, 1.5);
-    } else {
-        effectRectF = sourceRect;
-        unpadded = true;
-    }
-
-    QRect effectRect = effectRectF.toAlignedRect();
+    QRect effectRect = paddedEffectRect(system, mode, sourceRect, &unpadded);
 
     if (offset)
         *offset = effectRect.topLeft();