From 2f5ba54a6b6afa997c1b4b4ddf720e946398e341 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 10 Feb 2011 21:58:11 +1300 Subject: [PATCH] Bug 618722. background-attachment:fixed display items rendered via temporary layer managers can't have their scrolling taken care of via the layer system, so make sure we invalidate them when we scroll in their document. r=tnikkel,a=blocker --- layout/base/FrameLayerBuilder.cpp | 29 +++++++++++++++++++++++++++++ layout/base/FrameLayerBuilder.h | 20 ++++++++++++++++++++ layout/generic/nsGfxScrollFrame.cpp | 7 ++++--- 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 2d0f151a886..55dad0e45e2 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 1e863f05ab2..e051c85c4c3 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 a1f94004866..90e4a988a64 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()); } }