From e5ff8517e34963efbf2561feeb69cdba365a7aae Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 16 Jul 2010 09:08:06 +1200 Subject: [PATCH] Bug 564991. Part 25: Introduce a 'has active layers' flag on frames, which times out, and use it for 'opacity'. r=mats,sr=dbaron --- layout/base/nsCSSFrameConstructor.cpp | 2 + layout/base/nsDisplayList.cpp | 3 +- layout/build/nsLayoutStatics.cpp | 1 + layout/generic/nsFrame.cpp | 83 +++++++++++++++++++++++++++ layout/generic/nsFrame.h | 2 + layout/generic/nsIFrame.h | 13 +++++ 6 files changed, 103 insertions(+), 1 deletion(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index c77ec8af102e..0b338dbae3f1 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -120,6 +120,7 @@ #include "nsTArray.h" #include "nsGenericDOMDataNode.h" #include "mozilla/dom/Element.h" +#include "FrameLayerBuilder.h" #ifdef MOZ_XUL #include "nsIRootBox.h" @@ -7671,6 +7672,7 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame, } } if (aChange & nsChangeHint_UpdateOpacityLayer) { + aFrame->MarkLayersActive(); aFrame->InvalidateLayer(aFrame->GetOverflowRectRelativeToSelf(), nsDisplayItem::TYPE_OPACITY); } diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 2cecc8f67df6..4e4e80ab4623 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -1137,7 +1137,8 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder, nsDisplayItem::LayerState nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder, LayerManager* aManager) { - // XXX fix this to detect animated opacity + if (mFrame->AreLayersMarkedActive()) + return LAYER_ACTIVE; nsIFrame* activeScrolledRoot = nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull, nsnull); return !ChildrenCanBeInactive(aBuilder, aManager, mList, activeScrolledRoot) diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index 30d1ccd9ebcb..b75d42f9ad4b 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -316,6 +316,7 @@ nsLayoutStatics::Shutdown() nsFrame::DisplayReflowShutdown(); #endif nsCellMap::Shutdown(); + nsFrame::ShutdownLayerActivityTimer(); #ifdef MOZ_SVG nsSVGUtils::Shutdown(); diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index d0fc8196dc02..01c44c83dc7b 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -121,6 +121,7 @@ #include "nsBlockFrame.h" #include "nsDisplayList.h" #include "nsIObjectLoadingContent.h" +#include "nsExpirationTracker.h" #ifdef MOZ_SVG #include "nsSVGIntegrationUtils.h" #include "nsSVGEffects.h" @@ -3692,6 +3693,88 @@ nsIFrame::InvalidateLayer(const nsRect& aDamageRect, PRUint32 aDisplayItemKey) InvalidateWithFlags(aDamageRect, INVALIDATE_NO_THEBES_LAYERS); } +class LayerActivity { +public: + LayerActivity(nsIFrame* aFrame) : mFrame(aFrame) {} + ~LayerActivity(); + nsExpirationState* GetExpirationState() { return &mState; } + + nsIFrame* mFrame; + nsExpirationState mState; +}; + +class LayerActivityTracker : public nsExpirationTracker { +public: + // 75-100ms is a good timeout period. We use 4 generations of 25ms each. + enum { GENERATION_MS = 100 }; + LayerActivityTracker() + : nsExpirationTracker(GENERATION_MS) {} + ~LayerActivityTracker() { + AgeAllGenerations(); + } + + virtual void NotifyExpired(LayerActivity* aObject); +}; + +static LayerActivityTracker* gLayerActivityTracker = nsnull; + +LayerActivity::~LayerActivity() +{ + if (mFrame) { + NS_ASSERTION(gLayerActivityTracker, "Should still have a tracker"); + gLayerActivityTracker->RemoveObject(this); + } +} + +static void DestroyLayerActivity(void* aPropertyValue) +{ + delete static_cast(aPropertyValue); +} + +NS_DECLARE_FRAME_PROPERTY(LayerActivityProperty, DestroyLayerActivity) + +void +LayerActivityTracker::NotifyExpired(LayerActivity* aObject) +{ + RemoveObject(aObject); + + nsIFrame* f = aObject->mFrame; + aObject->mFrame = nsnull; + f->Properties().Delete(LayerActivityProperty()); + f->InvalidateOverflowRect(); +} + +void +nsIFrame::MarkLayersActive() +{ + FrameProperties properties = Properties(); + LayerActivity* layerActivity = + static_cast(properties.Get(LayerActivityProperty())); + if (layerActivity) { + gLayerActivityTracker->MarkUsed(layerActivity); + } else { + if (!gLayerActivityTracker) { + gLayerActivityTracker = new LayerActivityTracker(); + } + layerActivity = new LayerActivity(this); + gLayerActivityTracker->AddObject(layerActivity); + properties.Set(LayerActivityProperty(), layerActivity); + } +} + +PRBool +nsIFrame::AreLayersMarkedActive() +{ + return Properties().Get(LayerActivityProperty()) != nsnull; +} + +/* static */ void +nsFrame::ShutdownLayerActivityTimer() +{ + delete gLayerActivityTracker; + gLayerActivityTracker = nsnull; +} + void nsIFrame::InvalidateWithFlags(const nsRect& aDamageRect, PRUint32 aFlags) { diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index 51358da88fc4..bc8216dee122 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -488,6 +488,8 @@ public: static void DisplayReflowShutdown(); #endif + static void ShutdownLayerActivityTimer(); + /** * Adds display item for standard CSS background if necessary. * Does not check IsVisibleForPainting. diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 8d0a25891fdc..27138a5e2c19 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -1817,6 +1817,19 @@ public: */ void EndDeferringInvalidatesForDisplayRoot(); + /** + * Mark this frame as using active layers. This marking will time out + * after a short period. This call does no immediate invalidation, + * but when the mark times out, we'll invalidate the frame's overflow + * area. + */ + void MarkLayersActive(); + + /** + * Return true if this frame is marked as needing active layers. + */ + PRBool AreLayersMarkedActive(); + /** * @param aFlags see InvalidateInternal below */