Bug 810470. Part 4: Make only background-attachment:fixed backgrounds that have propagated to the viewport use a dedicated layer, and refactor how we do that. r=mattwoodrow
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 09 Nov 2012 18:14:14 -0500
changeset 113430 12182f4817cf2c65f35d5820b759c83b15d9ee47
parent 113429 85793c93543aabf86d2003139a6fb1b19eb1d8a4
child 113431 deda72e9eb11ab79a444a7daa1039bb1a1e5b353
push id18151
push userrocallahan@mozilla.com
push dateFri, 16 Nov 2012 00:03:18 +0000
treeherdermozilla-inbound@e8c599817e97 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs810470
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 810470. Part 4: Make only background-attachment:fixed backgrounds that have propagated to the viewport use a dedicated layer, and refactor how we do that. r=mattwoodrow
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/generic/nsCanvasFrame.h
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1464,23 +1464,21 @@ RegisterThemeGeometry(nsDisplayListBuild
   aBuilder->RegisterThemeGeometry(aFrame->GetStyleDisplay()->mAppearance,
       borderBox.ToNearestPixels(aFrame->PresContext()->AppUnitsPerDevPixel()));
 }
 
 nsDisplayBackground::nsDisplayBackground(nsDisplayListBuilder* aBuilder,
                                          nsIFrame* aFrame,
                                          uint32_t aLayer,
                                          bool aIsThemed,
-                                         const nsStyleBackground* aBackgroundStyle,
-                                         bool aSkipFixedItemBoundsCheck)
+                                         const nsStyleBackground* aBackgroundStyle)
   : nsDisplayItem(aBuilder, aFrame)
   , mBackgroundStyle(aBackgroundStyle)
   , mLayer(aLayer)
   , mIsThemed(aIsThemed)
-  , mIsFixed(false)
   , mIsBottommostLayer(true)
 {
   MOZ_COUNT_CTOR(nsDisplayBackground);
 
   if (mIsThemed) {
     const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
     mFrame->IsThemed(disp, &mThemeTransparency);
     // Perform necessary RegisterThemeGeometry
@@ -1496,46 +1494,16 @@ nsDisplayBackground::nsDisplayBackground
     if (mLayer != mBackgroundStyle->mImageCount - 1) {
       mIsBottommostLayer = false;
     }
 
     // Check if this background layer is attachment-fixed
     if (!mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty() &&
         mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED) {
       aBuilder->SetHasFixedItems();
-
-      // Check whether we should fix to viewport scrolling
-      if (mBackgroundStyle->mLayers[mLayer].mClip == NS_STYLE_BG_CLIP_BORDER &&
-          !nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius)) {
-        if (aSkipFixedItemBoundsCheck) {
-          mIsFixed = true;
-        } else {
-          nsPresContext* presContext = mFrame->PresContext();
-          nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
-          if (rootScrollFrame) {
-            bool snap;
-            nsRect bounds = GetBounds(aBuilder, &snap);
-
-            // This bounds check prevents an item fixing to the viewport unless it
-            // it encompasses the scroll-port. If a fixed background doesn't
-            // encompass the scroll-port, it usually means that scrolling will
-            // expose a new area of the fixed background and cause a lot of
-            // invalidation. This performs badly, and looks especially bad when
-            // async scrolling is being used.
-            // XXX A better check would be to see if the underlying frame is fixed to
-            //     the viewport/is the viewport.
-            nsIScrollableFrame* scrollable = do_QueryFrame(rootScrollFrame);
-            nsRect scrollport(scrollable->GetScrollPortRect().TopLeft() +
-                              aBuilder->ToReferenceFrame(rootScrollFrame),
-                              scrollable->GetScrollPositionClampingScrollPortSize());
-
-            mIsFixed = bounds.Contains(scrollport);
-          }
-        }
-      }
     }
   }
 }
 
 nsDisplayBackground::~nsDisplayBackground()
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   MOZ_COUNT_DTOR(nsDisplayBackground);
@@ -2067,22 +2035,16 @@ nsDisplayBackground::RenderingMightDepen
 
   const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
   if (layer.RenderingMightDependOnPositioningAreaSizeChange()) {
     return true;
   }
   return false;
 }
 
-bool
-nsDisplayBackground::ShouldFixToViewport(nsDisplayListBuilder* aBuilder)
-{
-  return mIsFixed;
-}
-
 static void CheckForBorderItem(nsDisplayItem *aItem, uint32_t& aFlags)
 {
   nsDisplayItem* nextItem = aItem->GetAbove();
   while (nextItem && nextItem->GetType() == nsDisplayItem::TYPE_BACKGROUND) {
     nextItem = nextItem->GetAbove();
   }
   if (nextItem && 
       nextItem->GetUnderlyingFrame() == aItem->GetUnderlyingFrame() &&
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1781,27 +1781,25 @@ private:
   nscolor mColor;
 };
 
 /**
  * The standard display item to paint the CSS background of a frame.
  */
 class nsDisplayBackground : public nsDisplayItem {
 public:
-  // aLayer signifies which background layer this item represents. Normally
-  // a background layer will only be marked as fixed if it covers the scroll-
-  // port of the root scroll-frame. This check can be skipped using
-  // aSkipFixedItemBoundsCheck.
-  // aIsThemed should be the value of aFrame->IsThemed.
-  // aBackgroundStyle should be the result of
-  // nsCSSRendering::FindBackground, or null if FindBackground returned false.
+  /**
+   * aLayer signifies which background layer this item represents.
+   * aIsThemed should be the value of aFrame->IsThemed.
+   * aBackgroundStyle should be the result of
+   * nsCSSRendering::FindBackground, or null if FindBackground returned false.
+   */
   nsDisplayBackground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                       uint32_t aLayer, bool aIsThemed,
-                      const nsStyleBackground* aBackgroundStyle,
-                      bool aSkipFixedItemBoundsCheck = false);
+                      const nsStyleBackground* aBackgroundStyle);
   virtual ~nsDisplayBackground();
 
   // This will create and append new items for all the layers of the
   // background. If given, aBackground will be set with the address of the
   // bottom-most background item.
   static nsresult AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
                                              nsIFrame* aFrame,
                                              nsDisplayList* aList,
@@ -1820,17 +1818,16 @@ public:
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) MOZ_OVERRIDE;
   virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
                                                 nsIFrame* aFrame) MOZ_OVERRIDE;
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE;
-  virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   /**
    * GetBounds() returns the background painting area.
    */
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   virtual uint32_t GetPerFrameKey() MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("Background", TYPE_BACKGROUND)
   // Returns the value of GetUnderlyingFrame()->IsThemed(), but cached
@@ -1878,19 +1875,16 @@ protected:
   /* If this background can be a simple image layer, we store the format here. */
   nsRefPtr<ImageContainer> mImageContainer;
   gfxRect mDestRect;
   uint32_t mLayer;
 
   nsITheme::Transparency mThemeTransparency;
   /* Used to cache mFrame->IsThemed() since it isn't a cheap call */
   bool mIsThemed;
-  /* true if this item represents a background-attachment:fixed layer and
-   * should fix to the viewport. */
-  bool mIsFixed;
   /* true if this item represents the bottom-most background layer */
   bool mIsBottommostLayer;
 };
 
 class nsDisplayBackgroundColor : public nsDisplayItem
 {
 public:
   nsDisplayBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -122,20 +122,19 @@ protected:
  * We can also paint an "extra background color" behind the normal
  * background.
  */
 class nsDisplayCanvasBackground : public nsDisplayBackground {
 public:
   nsDisplayCanvasBackground(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
                             uint32_t aLayer, bool aIsThemed,
                             const nsStyleBackground* aBackgroundStyle)
-    : nsDisplayBackground(aBuilder, aFrame, aLayer,
-                          aIsThemed, aBackgroundStyle, true)
+    : nsDisplayBackground(aBuilder, aFrame, aLayer, aIsThemed, aBackgroundStyle),
+      mExtraBackgroundColor(NS_RGBA(0,0,0,0))
   {
-    mExtraBackgroundColor = NS_RGBA(0,0,0,0);
   }
 
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                  nsRegion* aVisibleRegion,
                                  const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE
   {
     return NS_GET_A(mExtraBackgroundColor) > 0 ||
       nsDisplayBackground::ComputeVisibility(aBuilder, aVisibleRegion,
@@ -167,25 +166,34 @@ public:
     return frame->CanvasArea() + ToReferenceFrame();
   }
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE
   {
     // We need to override so we don't consider border-radius.
     aOutFrames->AppendElement(mFrame);
   }
-  
+  virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
+  {
+    // Put background-attachment:fixed canvas background images in their own
+    // compositing layer. Since we know their background painting area can't
+    // change (unless the viewport size itself changes), async scrolling
+    // will work well.
+    return mBackgroundStyle &&
+      mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
+      !mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty();
+  }
+
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
 
   void SetExtraBackgroundColor(nscolor aColor)
   {
     mExtraBackgroundColor = aColor;
   }
 
   NS_DISPLAY_DECL_NAME("CanvasBackground", TYPE_CANVAS_BACKGROUND)
 
 private:
   nscolor mExtraBackgroundColor;
 };
 
-
 #endif /* nsCanvasFrame_h___ */