Bug 814435 - Annotate layers for scrollbars as such. r=tn, r=BenWa, a=1.3+
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 09 Dec 2013 22:14:53 -0500
changeset 175204 cd7afa66a5b4532893af85c6c4613df4c3c9b8b7
parent 175203 14ee95c5c5239baeb3fab6e5ecbbc4c9d257f57a
child 175205 434453c80f438cc438f6723e5be122a95c2f2be1
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn, BenWa, 1
bugs814435
milestone28.0a2
Bug 814435 - Annotate layers for scrollbars as such. r=tn, r=BenWa, a=1.3+
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/ShadowLayers.cpp
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/generic/nsGfxScrollFrame.cpp
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -179,16 +179,17 @@ Layer::Layer(LayerManager* aManager, voi
   mMixBlendMode(gfxContext::OPERATOR_OVER),
   mForceIsolatedGroup(false),
   mContentFlags(0),
   mUseClipRect(false),
   mUseTileSourceRect(false),
   mIsFixedPosition(false),
   mMargins(0, 0, 0, 0),
   mStickyPositionData(nullptr),
+  mIsScrollbar(false),
   mDebugColorIndex(0),
   mAnimationGeneration(0)
 {}
 
 Layer::~Layer()
 {}
 
 Animation*
@@ -1273,16 +1274,23 @@ Layer::PrintInfo(nsACString& aTo, const 
     aTo.AppendPrintf(" [opacity=%g]", mOpacity);
   }
   if (GetContentFlags() & CONTENT_OPAQUE) {
     aTo += " [opaqueContent]";
   }
   if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) {
     aTo += " [componentAlpha]";
   }
+  if (GetIsScrollbar()) {
+    if (GetScrollbarDirection() == VERTICAL) {
+      aTo.AppendPrintf(" [vscrollbar=%lld]", GetScrollbarTargetContainerId());
+    } else {
+      aTo.AppendPrintf(" [hscrollbar=%lld]", GetScrollbarTargetContainerId());
+    }
+  }
   if (GetIsFixedPosition()) {
     aTo.AppendPrintf(" [isFixedPosition anchor=%f,%f]", mAnchor.x, mAnchor.y);
   }
   if (GetIsStickyPosition()) {
     aTo.AppendPrintf(" [isStickyPosition scrollId=%d outer=%f,%f %fx%f "
                      "inner=%f,%f %fx%f]", mStickyPositionData->mScrollId,
                      mStickyPositionData->mOuter.x, mStickyPositionData->mOuter.y,
                      mStickyPositionData->mOuter.width, mStickyPositionData->mOuter.height,
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -967,16 +967,39 @@ public:
       }
       mStickyPositionData->mScrollId = aScrollId;
       mStickyPositionData->mOuter = aOuter;
       mStickyPositionData->mInner = aInner;
       Mutated();
     }
   }
 
+  enum ScrollDirection {
+    VERTICAL,
+    HORIZONTAL
+  };
+
+  /**
+   * CONSTRUCTION PHASE ONLY
+   * If a layer is a scrollbar layer, |aScrollId| holds the scroll identifier
+   * of the scrollable content that the scrollbar is for.
+   */
+  void SetScrollbarData(FrameMetrics::ViewID aScrollId, ScrollDirection aDir)
+  {
+    if (mIsScrollbar ||
+        mScrollbarTargetId != aScrollId ||
+        mScrollbarDirection != aDir) {
+      MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ScrollbarData", this));
+      mIsScrollbar = true;
+      mScrollbarTargetId = aScrollId;
+      mScrollbarDirection = aDir;
+      Mutated();
+    }
+  }
+
   // These getters can be used anytime.
   float GetOpacity() { return mOpacity; }
   gfxContext::GraphicsOperator GetMixBlendMode() const { return mMixBlendMode; }
   const nsIntRect* GetClipRect() { return mUseClipRect ? &mClipRect : nullptr; }
   uint32_t GetContentFlags() { return mContentFlags; }
   const nsIntRegion& GetVisibleRegion() { return mVisibleRegion; }
   ContainerLayer* GetParent() { return mParent; }
   Layer* GetNextSibling() { return mNextSibling; }
@@ -991,16 +1014,19 @@ public:
   float GetPostYScale() const { return mPostYScale; }
   bool GetIsFixedPosition() { return mIsFixedPosition; }
   bool GetIsStickyPosition() { return mStickyPositionData; }
   LayerPoint GetFixedPositionAnchor() { return mAnchor; }
   const LayerMargin& GetFixedPositionMargins() { return mMargins; }
   FrameMetrics::ViewID GetStickyScrollContainerId() { return mStickyPositionData->mScrollId; }
   const LayerRect& GetStickyScrollRangeOuter() { return mStickyPositionData->mOuter; }
   const LayerRect& GetStickyScrollRangeInner() { return mStickyPositionData->mInner; }
+  bool GetIsScrollbar() { return mIsScrollbar; }
+  FrameMetrics::ViewID GetScrollbarTargetContainerId() { return mScrollbarTargetId; }
+  ScrollDirection GetScrollbarDirection() { return mScrollbarDirection; }
   Layer* GetMaskLayer() const { return mMaskLayer; }
 
   // Note that all lengths in animation data are either in CSS pixels or app
   // units and must be converted to device pixels by the compositor.
   AnimationArray& GetAnimations() { return mAnimations; }
   InfallibleTArray<AnimData>& GetAnimationData() { return mAnimationData; }
 
   uint64_t GetAnimationGeneration() { return mAnimationGeneration; }
@@ -1362,16 +1388,19 @@ protected:
   LayerPoint mAnchor;
   LayerMargin mMargins;
   struct StickyPositionData {
     FrameMetrics::ViewID mScrollId;
     LayerRect mOuter;
     LayerRect mInner;
   };
   nsAutoPtr<StickyPositionData> mStickyPositionData;
+  bool mIsScrollbar;
+  FrameMetrics::ViewID mScrollbarTargetId;
+  ScrollDirection mScrollbarDirection;
   DebugOnly<uint32_t> mDebugColorIndex;
   // If this layer is used for OMTA, then this counter is used to ensure we
   // stay in sync with the animation manager
   uint64_t mAnimationGeneration;
 };
 
 /**
  * A Layer which we can draw into using Thebes. It is a conceptually
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -274,16 +274,20 @@ LayerTransactionParent::RecvUpdate(const
       layer->SetIsFixedPosition(common.isFixedPosition());
       layer->SetFixedPositionAnchor(common.fixedPositionAnchor());
       layer->SetFixedPositionMargins(common.fixedPositionMargin());
       if (common.isStickyPosition()) {
         layer->SetStickyPositionData(common.stickyScrollContainerId(),
                                      common.stickyScrollRangeOuter(),
                                      common.stickyScrollRangeInner());
       }
+      if (common.isScrollbar()) {
+        layer->SetScrollbarData(common.scrollbarTargetContainerId(),
+          static_cast<Layer::ScrollDirection>(common.scrollbarDirection()));
+      }
       if (PLayerParent* maskLayer = common.maskLayerParent()) {
         layer->SetMaskLayer(cast(maskLayer)->AsLayer());
       } else {
         layer->SetMaskLayer(nullptr);
       }
       layer->SetAnimations(common.animations());
       layer->SetInvalidRegion(common.invalidRegion());
 
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -192,16 +192,19 @@ struct CommonLayerAttributes {
   nsIntRect clipRect;
   bool isFixedPosition;
   LayerPoint fixedPositionAnchor;
   LayerMargin fixedPositionMargin;
   bool isStickyPosition;
   uint64_t stickyScrollContainerId;
   LayerRect stickyScrollRangeOuter;
   LayerRect stickyScrollRangeInner;
+  bool isScrollbar;
+  uint64_t scrollbarTargetContainerId;
+  uint32_t scrollbarDirection;
   nullable PLayer maskLayer;
   // Animated colors will only honored for ColorLayers.
   Animation[] animations;
   nsIntRegion invalidRegion;
 };
 
 struct ThebesLayerAttributes {
   nsIntRegion validRegion;
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -523,16 +523,21 @@ ShadowLayerForwarder::EndTransaction(Inf
     common.fixedPositionAnchor() = mutant->GetFixedPositionAnchor();
     common.fixedPositionMargin() = mutant->GetFixedPositionMargins();
     common.isStickyPosition() = mutant->GetIsStickyPosition();
     if (mutant->GetIsStickyPosition()) {
       common.stickyScrollContainerId() = mutant->GetStickyScrollContainerId();
       common.stickyScrollRangeOuter() = mutant->GetStickyScrollRangeOuter();
       common.stickyScrollRangeInner() = mutant->GetStickyScrollRangeInner();
     }
+    common.isScrollbar() = mutant->GetIsScrollbar();
+    if (mutant->GetIsScrollbar()) {
+      common.scrollbarTargetContainerId() = mutant->GetScrollbarTargetContainerId();
+      common.scrollbarDirection() = mutant->GetScrollbarDirection();
+    }
     if (Layer* maskLayer = mutant->GetMaskLayer()) {
       common.maskLayerChild() = Shadow(maskLayer->AsShadowableLayer());
     } else {
       common.maskLayerChild() = nullptr;
     }
     common.maskLayerParent() = nullptr;
     common.animations() = mutant->GetAnimations();
     common.invalidRegion() = mutant->GetInvalidRegion();
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -3248,19 +3248,20 @@ bool nsDisplayBlendContainer::TryMerge(n
   if (aItem->GetClip() != GetClip())
     return false;
   MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendContainer*>(aItem));
   return true;
 }
 
 nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayList* aList,
-                                     uint32_t aFlags)
+                                     uint32_t aFlags, ViewID aScrollTarget)
     : nsDisplayWrapList(aBuilder, aFrame, aList)
-    , mFlags(aFlags) {
+    , mFlags(aFlags)
+    , mScrollTarget(aScrollTarget) {
   MOZ_COUNT_CTOR(nsDisplayOwnLayer);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayOwnLayer::~nsDisplayOwnLayer() {
   MOZ_COUNT_DTOR(nsDisplayOwnLayer);
 }
 #endif
@@ -3268,16 +3269,22 @@ nsDisplayOwnLayer::~nsDisplayOwnLayer() 
 // nsDisplayOpacity uses layers for rendering
 already_AddRefed<Layer>
 nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
                               LayerManager* aManager,
                               const ContainerLayerParameters& aContainerParameters) {
   nsRefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                            aContainerParameters, nullptr);
+  if (mFlags & VERTICAL_SCROLLBAR) {
+    layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::VERTICAL);
+  }
+  if (mFlags & HORIZONTAL_SCROLLBAR) {
+    layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::HORIZONTAL);
+  }
 
   if (mFlags & GENERATE_SUBDOC_INVALIDATIONS) {
     mFrame->PresContext()->SetNotifySubDocInvalidationData(layer);
   }
   return layer.forget();
 }
 
 nsDisplayResolution::nsDisplayResolution(nsDisplayListBuilder* aBuilder,
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2570,26 +2570,32 @@ public:
  */
 class nsDisplayOwnLayer : public nsDisplayWrapList {
 public:
 
   /**
    * nsDisplayOwnLayer constructor flags
    */
   enum {
-    GENERATE_SUBDOC_INVALIDATIONS = 0x01
+    GENERATE_SUBDOC_INVALIDATIONS = 0x01,
+    VERTICAL_SCROLLBAR = 0x02,
+    HORIZONTAL_SCROLLBAR = 0x04
   };
 
   /**
    * @param aFlags GENERATE_SUBDOC_INVALIDATIONS :
    * Add UserData to the created ContainerLayer, so that invalidations
    * for this layer are send to our nsPresContext.
+   * @param aScrollTarget when VERTICAL_SCROLLBAR or HORIZONTAL_SCROLLBAR
+   * is set in the flags, this parameter should be the ViewID of the
+   * scrollable content this scrollbar is for.
    */
   nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-                    nsDisplayList* aList, uint32_t aFlags = 0);
+                    nsDisplayList* aList, uint32_t aFlags = 0,
+                    ViewID aScrollTarget = mozilla::layers::FrameMetrics::NULL_SCROLL_ID);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayOwnLayer();
 #endif
   
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE;
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
@@ -2601,16 +2607,17 @@ public:
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE
   {
     // Don't allow merging, each sublist must have its own layer
     return false;
   }
   NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
 private:
   uint32_t mFlags;
+  ViewID mScrollTarget;
 };
 
 /**
  * A display item for subdocuments to capture the resolution from the presShell
  * and ensure that it gets applied to all the right elements. This item creates
  * a container layer.
  */
 class nsDisplayResolution : public nsDisplayOwnLayer {
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2053,23 +2053,25 @@ ScrollFrameHelper::ScrollToImpl(nsPoint 
   // notify the listeners.
   for (uint32_t i = 0; i < mListeners.Length(); i++) {
     mListeners[i]->ScrollPositionDidChange(pt.x, pt.y);
   }
 }
 
 static void
 AppendToTop(nsDisplayListBuilder* aBuilder, nsDisplayList* aDest,
-            nsDisplayList* aSource, nsIFrame* aSourceFrame, bool aOwnLayer)
+            nsDisplayList* aSource, nsIFrame* aSourceFrame, bool aOwnLayer,
+            uint32_t aFlags, mozilla::layers::FrameMetrics::ViewID aScrollTargetId)
 {
   if (aSource->IsEmpty())
     return;
   if (aOwnLayer) {
     aDest->AppendNewToTop(
-        new (aBuilder) nsDisplayOwnLayer(aBuilder, aSourceFrame, aSource));
+        new (aBuilder) nsDisplayOwnLayer(aBuilder, aSourceFrame, aSource,
+                                         aFlags, aScrollTargetId));
   } else {
     aDest->AppendToTop(aSource);
   }
 }
 
 struct HoveredStateComparator
 {
   bool Equals(nsIFrame* A, nsIFrame* B) const {
@@ -2108,37 +2110,49 @@ ScrollFrameHelper::AppendScrollPartsTo(n
   for (nsIFrame* kid = mOuter->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
     if (kid == mScrolledFrame ||
         (kid->IsPositioned() || overlayScrollbars) != aPositioned)
       continue;
 
     scrollParts.AppendElement(kid);
   }
 
+  mozilla::layers::FrameMetrics::ViewID scrollTargetId = aCreateLayer
+    ? nsLayoutUtils::FindOrCreateIDFor(mScrolledFrame->GetContent())
+    : mozilla::layers::FrameMetrics::NULL_SCROLL_ID;
+
   scrollParts.Sort(HoveredStateComparator());
 
   for (uint32_t i = 0; i < scrollParts.Length(); ++i) {
     nsDisplayListCollection partList;
     mOuter->BuildDisplayListForChild(
       aBuilder, scrollParts[i], aDirtyRect, partList,
       nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
 
     // Don't append textarea resizers to the positioned descendants because
     // we don't want them to float on top of overlapping elements.
     bool appendToPositioned = aPositioned &&
                               !(scrollParts[i] == mResizerBox && !mIsRoot);
 
     nsDisplayList* dest = appendToPositioned ?
       aLists.PositionedDescendants() : aLists.BorderBackground();
 
+    uint32_t flags = 0;
+    if (scrollParts[i] == mVScrollbarBox) {
+      flags |= nsDisplayOwnLayer::VERTICAL_SCROLLBAR;
+    }
+    if (scrollParts[i] == mHScrollbarBox) {
+      flags |= nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR;
+    }
+
     // DISPLAY_CHILD_FORCE_STACKING_CONTEXT put everything into
     // partList.PositionedDescendants().
     ::AppendToTop(aBuilder, dest,
                   partList.PositionedDescendants(), scrollParts[i],
-                  aCreateLayer);
+                  aCreateLayer, flags, scrollTargetId);
   }
 }
 
 class ScrollLayerWrapper : public nsDisplayWrapper
 {
 public:
   ScrollLayerWrapper(nsIFrame* aScrollFrame, nsIFrame* aScrolledFrame)
     : mCount(0)