diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 2d0f151a8867..55dad0e45e21 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -621,6 +621,27 @@ FrameLayerBuilder::StoreNewDisplayItemData(DisplayItemDataEntry* aEntry, return PL_DHASH_REMOVE; } +PRBool +FrameLayerBuilder::HasRetainedLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey) +{ + void* propValue = aFrame->Properties().Get(DisplayItemDataProperty()); + if (!propValue) + return PR_FALSE; + + nsTArray* array = + (reinterpret_cast*>(&propValue)); + for (PRUint32 i = 0; i < array->Length(); ++i) { + if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) { + Layer* layer = array->ElementAt(i).mLayer; + if (layer->Manager()->GetUserData(&gLayerManagerUserData)) { + // All layer managers with our user data are retained layer managers + return PR_TRUE; + } + } + } + return PR_FALSE; +} + Layer* FrameLayerBuilder::GetOldLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey) { @@ -1358,6 +1379,14 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer) } } +PRBool +FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder* aBuilder, + nsDisplayItem* aItem) +{ + return !aItem->IsFixedAndCoveringViewport(aBuilder) || + !HasRetainedLayerFor(aItem->GetUnderlyingFrame(), aItem->GetPerFrameKey()); +} + void FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer, nsDisplayItem* aItem, diff --git a/layout/base/FrameLayerBuilder.h b/layout/base/FrameLayerBuilder.h index 1e863f05ab22..e051c85c4c38 100644 --- a/layout/base/FrameLayerBuilder.h +++ b/layout/base/FrameLayerBuilder.h @@ -278,6 +278,26 @@ public: aFrame->Properties().Delete(DisplayItemDataProperty()); } + LayerManager* GetRetainingLayerManager() { return mRetainingManager; } + + /** + * Returns true if the given item (which we assume here is + * background-attachment:fixed) needs to be repainted as we scroll in its + * document. + * Returns false if it doesn't need to be repainted because the layer system + * is ensuring its fixed-ness for us. + */ + static PRBool NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder* aBuilder, + nsDisplayItem* aItem); + + /** + * Returns true if the given display item was rendered directly + * into a retained layer. + * Returns false if it was rendered into a temporary layer manager and then + * into a retained layer. + */ + static PRBool HasRetainedLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey); + /** * Clip represents the intersection of an optional rectangle with a * list of rounded rectangles. diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index a1f940048663..90e4a988a640 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -81,7 +81,9 @@ #include "nsIPrefService.h" #include "nsILookAndFeel.h" #include "mozilla/dom/Element.h" +#include "FrameLayerBuilder.h" +using namespace mozilla; using namespace mozilla::dom; //---------------------------------------------------------------------- @@ -1598,9 +1600,8 @@ InvalidateFixedBackgroundFramesFromList(nsDisplayListBuilder* aBuilder, nsIFrame* f = item->GetUnderlyingFrame(); if (f && item->IsVaryingRelativeToMovingFrame(aBuilder, aMovingFrame)) { - if (item->IsFixedAndCoveringViewport(aBuilder)) { - // FrameLayerBuilder takes care of scrolling these - } else { + if (FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(aBuilder, item)) { + // FrameLayerBuilder does not take care of scrolling this one f->Invalidate(item->GetVisibleRect() - item->ToReferenceFrame()); } }