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
authorRobert O'Callahan <robert@ocallahan.org>
Thu, 10 Feb 2011 21:58:11 +1300
changeset 62289 84cebd5b0f9317a305a7ab732ae834a5ab1367a9
parent 62288 199cb628255440c7016a41284b14226160fa38db
child 62290 1431568b3e1b2b4b5f122c2c5d4815278b0b4ae5
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewerstnikkel, blocker
bugs618722
milestone2.0b12pre
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
layout/base/FrameLayerBuilder.h
layout/generic/nsGfxScrollFrame.cpp
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -616,16 +616,37 @@ FrameLayerBuilder::StoreNewDisplayItemDa
   props.Set(DisplayItemDataProperty(), propValue);
 
   if (f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) {
     props.Set(ThebesLayerInvalidRegionProperty(), new nsRegion());
   }
   return PL_DHASH_REMOVE;
 }
 
+PRBool
+FrameLayerBuilder::HasRetainedLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
+{
+  void* propValue = aFrame->Properties().Get(DisplayItemDataProperty());
+  if (!propValue)
+    return PR_FALSE;
+
+  nsTArray<DisplayItemData>* array =
+    (reinterpret_cast<nsTArray<DisplayItemData>*>(&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)
 {
   // If we need to build a new layer tree, then just refuse to recycle
   // anything.
   if (!mRetainingManager || mInvalidateAllLayers)
     return nsnull;
 
@@ -1353,16 +1374,24 @@ ContainerState::InvalidateForLayerChange
                  "app units per dev pixel should be constant in a container");
     mContainerFrame->InvalidateWithFlags(
         bounds - mBuilder->ToReferenceFrame(mContainerFrame),
         nsIFrame::INVALIDATE_NO_THEBES_LAYERS |
         nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT);
   }
 }
 
+PRBool
+FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder* aBuilder,
+                                                    nsDisplayItem* aItem)
+{
+  return !aItem->IsFixedAndCoveringViewport(aBuilder) ||
+      !HasRetainedLayerFor(aItem->GetUnderlyingFrame(), aItem->GetPerFrameKey());
+}
+
 void
 FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
                                         nsDisplayItem* aItem,
                                         const Clip& aClip,
                                         nsIFrame* aContainerLayerFrame,
                                         LayerState aLayerState,
                                         LayerManager* aTempManager)
 {
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -273,16 +273,36 @@ public:
   /**
    * Destroy any stored DisplayItemDataProperty for aFrame.
    */
   static void DestroyDisplayItemDataFor(nsIFrame* aFrame)
   {
     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.
    */
   struct Clip {
     struct RoundedRect {
       nsRect mRect;
       // Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -76,17 +76,19 @@
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 #include "nsBidiUtils.h"
 #include "nsFrameManager.h"
 #include "nsIPrefService.h"
 #include "nsILookAndFeel.h"
 #include "mozilla/dom/Element.h"
-
+#include "FrameLayerBuilder.h"
+
+using namespace mozilla;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 
 //----------nsHTMLScrollFrame-------------------------------------------
 
 nsIFrame*
 NS_NewHTMLScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRBool aIsRoot)
@@ -1593,19 +1595,18 @@ InvalidateFixedBackgroundFramesFromList(
     nsDisplayList* sublist = item->GetList();
     if (sublist) {
       InvalidateFixedBackgroundFramesFromList(aBuilder, aMovingFrame, *sublist);
       continue;
     }
     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());
       }
     }
   }
 }
 
 static void
 InvalidateFixedBackgroundFrames(nsIFrame* aRootFrame,