diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 92b0008dac2d..811a630d3fe3 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4642,7 +4642,18 @@ LayerActivityTracker::NotifyExpired(LayerActivity* aObject) nsIFrame* f = aObject->mFrame; aObject->mFrame = nullptr; f->Properties().Delete(LayerActivityProperty()); - f->InvalidateFrameSubtree(); + + // if there are hints other than transform/opacity, invalidate, since we don't know what else to do. + if (aObject->mChangeHint & ~(nsChangeHint_UpdateOpacityLayer|nsChangeHint_UpdateTransformLayer)) { + f->InvalidateFrameSubtree(); + } else { + if (aObject->mChangeHint & nsChangeHint_UpdateOpacityLayer) { + f->InvalidateFrameSubtree(nsDisplayItem::TYPE_OPACITY); + } + if (aObject->mChangeHint & nsChangeHint_UpdateTransformLayer) { + f->InvalidateFrameSubtree(nsDisplayItem::TYPE_TRANSFORM); + } + } } void @@ -4752,12 +4763,40 @@ nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor, 0.0f); } -void -nsIFrame::InvalidateFrameSubtree() +static void InvalidateFrameInternal(nsIFrame *aFrame, bool aHasDisplayItem = true) { - InvalidateFrame(); + if (aHasDisplayItem) { + aFrame->AddStateBits(NS_FRAME_NEEDS_PAINT); + } + nsSVGEffects::InvalidateDirectRenderingObservers(aFrame); + nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame); + while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) { + if (aHasDisplayItem) { + parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT); + } + nsSVGEffects::InvalidateDirectRenderingObservers(parent); + parent = nsLayoutUtils::GetCrossDocParentFrame(parent); + } + if (!aHasDisplayItem) { + return; + } + if (!parent) { + aFrame->SchedulePaint(); + } + if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) { + aFrame->Properties().Delete(nsIFrame::InvalidationRect()); + aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT); + } +} - if (HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) { +void +nsIFrame::InvalidateFrameSubtree(uint32_t aDisplayItemKey) +{ + bool hasDisplayItem = + !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey); + InvalidateFrameInternal(this, hasDisplayItem); + + if (HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT) || !hasDisplayItem) { return; } @@ -4796,41 +4835,30 @@ nsIFrame::ClearInvalidationStateBits() NS_FRAME_ALL_DESCENDANTS_NEED_PAINT); } -static void InvalidateFrameInternal(nsIFrame *aFrame) +void +nsIFrame::InvalidateFrame(uint32_t aDisplayItemKey) { - aFrame->AddStateBits(NS_FRAME_NEEDS_PAINT); - nsSVGEffects::InvalidateDirectRenderingObservers(aFrame); - nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame); - while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) { - parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT); - nsSVGEffects::InvalidateDirectRenderingObservers(parent); - parent = nsLayoutUtils::GetCrossDocParentFrame(parent); - } - if (!parent) { - aFrame->SchedulePaint(); - } - if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) { - aFrame->Properties().Delete(nsIFrame::InvalidationRect()); - aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT); - } + bool hasDisplayItem = + !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey); + InvalidateFrameInternal(this, hasDisplayItem); } void -nsIFrame::InvalidateFrame() -{ - InvalidateFrameInternal(this); -} - -void -nsIFrame::InvalidateFrameWithRect(const nsRect& aRect) +nsIFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) { + bool hasDisplayItem = + !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey); bool alreadyInvalid = false; if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) { - InvalidateFrameInternal(this); + InvalidateFrameInternal(this, hasDisplayItem); } else { alreadyInvalid = true; } + if (!hasDisplayItem) { + return; + } + nsRect *rect = static_cast(Properties().Get(InvalidationRect())); if (!rect) { if (alreadyInvalid) { @@ -4894,7 +4922,14 @@ nsIFrame::InvalidateLayer(uint32_t aDisplayItemKey, const nsIntRect* aDamageRect } if (!layer) { - InvalidateFrame(); + // Plugins can transition from not rendering anything to rendering, + // and still only call this. So always invalidate, with specifying + // the display item type just in case. + if (aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN) { + InvalidateFrame(); + } else { + InvalidateFrame(aDisplayItemKey); + } return nullptr; } diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 8bf4bce61b57..583a7fca662a 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -2183,8 +2183,12 @@ public: * * This includes all display items created by this frame, including * container types. + * + * @param aDisplayItemKey If specified, only issues an invalidate + * if this frame painted a display item of that type during the + * previous paint. SVG rendering observers are always notified. */ - virtual void InvalidateFrame(); + virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0); /** * Same as InvalidateFrame(), but only mark a fixed rect as needing @@ -2192,8 +2196,11 @@ public: * * @param aRect The rect to invalidate, relative to the TopLeft of the * frame's border box. + * @param aDisplayItemKey If specified, only issues an invalidate + * if this frame painted a display item of that type during the + * previous paint. SVG rendering observers are always notified. */ - virtual void InvalidateFrameWithRect(const nsRect& aRect); + virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0); /** * Calls InvalidateFrame() on all frames descendant frames (including @@ -2201,12 +2208,17 @@ public: * * This function doesn't walk through placeholder frames to invalidate * the out-of-flow frames. + * + * @param aDisplayItemKey If specified, only issues an invalidate + * if this frame painted a display item of that type during the + * previous paint. SVG rendering observers are always notified. */ - void InvalidateFrameSubtree(); + void InvalidateFrameSubtree(uint32_t aDisplayItemKey = 0); /** * Called when a frame is about to be removed and needs to be invalidated. * Normally does nothing since DLBI handles removed frames. + * */ virtual void InvalidateFrameForRemoval() {} diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 2f17f12b7c2b..14b5639e40b3 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -592,10 +592,14 @@ nsImageFrame::OnDataAvailable(imgIRequest *aRequest, printf("Source rect (%d,%d,%d,%d)\n", aRect->x, aRect->y, aRect->width, aRect->height); #endif + if (aRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) { - InvalidateFrame(); + InvalidateFrame(nsDisplayItem::TYPE_IMAGE); + InvalidateFrame(nsDisplayItem::TYPE_ALT_FEEDBACK); } else { - InvalidateFrameWithRect(SourceRectToDest(*aRect)); + nsRect invalid = SourceRectToDest(*aRect); + InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_IMAGE); + InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_ALT_FEEDBACK); } return NS_OK;