Bug 1418387 - Propagate scrollbar direction for scrollbar containers to APZ. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 24 Nov 2017 16:23:05 -0500
changeset 703338 f554a355862b8b587126b4490a28384097d78cb8
parent 703337 724c6c9cbc85166da0f2c9d6f86ae45b169caf5c
child 703339 e4248e57686c8077e49a23b88e65a5084ef74da8
push id90784
push userkgupta@mozilla.com
push dateFri, 24 Nov 2017 21:25:10 +0000
reviewersbotond
bugs1418387
milestone59.0a1
Bug 1418387 - Propagate scrollbar direction for scrollbar containers to APZ. r?botond Most of this patch is just mechanical changes, but note that this patch now makes the mFlags in scrollbar-container nsDisplayOwnLayer instances have one of the direction bits set. As a result, this requires changing the implementation of nsDisplayOwnLayer::IsScrollThumbLayer(). MozReview-Commit-ID: 2BLdbpz5Sa8
gfx/layers/LayerAttributes.h
gfx/layers/LayerMetricsWrapper.h
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/HitTestingTreeNode.cpp
gfx/layers/apz/src/HitTestingTreeNode.h
gfx/layers/wr/WebRenderScrollData.cpp
gfx/layers/wr/WebRenderScrollData.h
gfx/layers/wr/WebRenderScrollDataWrapper.h
layout/generic/nsGfxScrollFrame.cpp
layout/painting/nsDisplayList.cpp
--- a/gfx/layers/LayerAttributes.h
+++ b/gfx/layers/LayerAttributes.h
@@ -74,17 +74,16 @@ public:
   SimpleLayerAttributes()
    : mTransformIsPerspective(false),
      mPostXScale(1.0f),
      mPostYScale(1.0f),
      mContentFlags(0),
      mOpacity(1.0f),
      mIsFixedPosition(false),
      mScrollbarTargetContainerId(FrameMetrics::NULL_SCROLL_ID),
-     mIsScrollbarContainer(false),
      mMixBlendMode(gfx::CompositionOp::OP_OVER),
      mForceIsolatedGroup(false)
   {
   }
 
   //
   // Setters.
   // All set methods return true if values changed, false otherwise.
@@ -124,21 +123,24 @@ public:
         mThumbData == aThumbData)
     {
       return false;
     }
     mScrollbarTargetContainerId = aScrollId;
     mThumbData = aThumbData;
     return true;
   }
-  bool SetIsScrollbarContainer(FrameMetrics::ViewID aScrollId) {
-    if (mIsScrollbarContainer && mScrollbarTargetContainerId == aScrollId) {
+  bool SetScrollbarContainer(FrameMetrics::ViewID aScrollId,
+                             ScrollDirection aDirection) {
+    if (mScrollbarContainerDirection &&
+        *mScrollbarContainerDirection == aDirection &&
+        mScrollbarTargetContainerId == aScrollId) {
       return false;
     }
-    mIsScrollbarContainer = true;
+    mScrollbarContainerDirection = Some(aDirection);
     mScrollbarTargetContainerId = aScrollId;
     return true;
   }
   bool SetMixBlendMode(gfx::CompositionOp aMixBlendMode) {
     if (mMixBlendMode == aMixBlendMode) {
       return false;
     }
     mMixBlendMode = aMixBlendMode;
@@ -205,17 +207,17 @@ public:
     mStickyPositionData->mOuter = aOuter;
     mStickyPositionData->mInner = aInner;
     return true;
   }
 
   // This returns true if scrolling info is equivalent for the purposes of
   // APZ hit testing.
   bool HitTestingInfoIsEqual(const SimpleLayerAttributes& aOther) const {
-    if (mIsScrollbarContainer != aOther.mIsScrollbarContainer) {
+    if (mScrollbarContainerDirection != aOther.mScrollbarContainerDirection) {
       return false;
     }
     if (mScrollbarTargetContainerId != aOther.mScrollbarTargetContainerId) {
       return false;
     }
     if (mThumbData != aOther.mThumbData) {
       return false;
     }
@@ -248,18 +250,18 @@ public:
     return mIsFixedPosition;
   }
   FrameMetrics::ViewID ScrollbarTargetContainerId() const {
     return mScrollbarTargetContainerId;
   }
   const ScrollThumbData& ThumbData() const {
     return mThumbData;
   }
-  bool IsScrollbarContainer() const {
-    return mIsScrollbarContainer;
+  Maybe<ScrollDirection> GetScrollbarContainerDirection() const {
+    return mScrollbarContainerDirection;
   }
   gfx::CompositionOp MixBlendMode() const {
     return mMixBlendMode;
   }
   bool ForceIsolatedGroup() const {
     return mForceIsolatedGroup;
   }
   const gfx::Matrix4x4& Transform() const {
@@ -301,33 +303,33 @@ public:
            mScrolledClip == aOther.mScrolledClip &&
            mPostXScale == aOther.mPostXScale &&
            mPostYScale == aOther.mPostYScale &&
            mContentFlags == aOther.mContentFlags &&
            mOpacity == aOther.mOpacity &&
            mIsFixedPosition == aOther.mIsFixedPosition &&
            mScrollbarTargetContainerId == aOther.mScrollbarTargetContainerId &&
            mThumbData == aOther.mThumbData &&
-           mIsScrollbarContainer == aOther.mIsScrollbarContainer &&
+           mScrollbarContainerDirection == aOther.mScrollbarContainerDirection &&
            mMixBlendMode == aOther.mMixBlendMode &&
            mForceIsolatedGroup == aOther.mForceIsolatedGroup;
   }
 
 private:
   gfx::Matrix4x4 mTransform;
   bool mTransformIsPerspective;
   Maybe<LayerClip> mScrolledClip;
   float mPostXScale;
   float mPostYScale;
   uint32_t mContentFlags;
   float mOpacity;
   bool mIsFixedPosition;
   uint64_t mScrollbarTargetContainerId;
   ScrollThumbData mThumbData;
-  bool mIsScrollbarContainer;
+  Maybe<ScrollDirection> mScrollbarContainerDirection;
   gfx::CompositionOp mMixBlendMode;
   bool mForceIsolatedGroup;
 
   struct FixedPositionData {
     FrameMetrics::ViewID mScrollId;
     LayerPoint mAnchor;
     int32_t mSides;
   };
--- a/gfx/layers/LayerMetricsWrapper.h
+++ b/gfx/layers/LayerMetricsWrapper.h
@@ -428,20 +428,20 @@ public:
 
   FrameMetrics::ViewID GetScrollbarTargetContainerId() const
   {
     MOZ_ASSERT(IsValid());
 
     return mLayer->GetScrollbarTargetContainerId();
   }
 
-  bool IsScrollbarContainer() const
+  Maybe<ScrollDirection> GetScrollbarContainerDirection() const
   {
     MOZ_ASSERT(IsValid());
-    return mLayer->IsScrollbarContainer();
+    return mLayer->GetScrollbarContainerDirection();
   }
 
   FrameMetrics::ViewID GetFixedPositionScrollContainerId() const
   {
     MOZ_ASSERT(IsValid());
 
     return mLayer->GetFixedPositionScrollContainerId();
   }
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -1807,17 +1807,17 @@ Layer::PrintInfo(std::stringstream& aStr
     aStream << " [extend3DContext]";
   }
   if (Combines3DTransformWithAncestors()) {
     aStream << " [combines3DTransformWithAncestors]";
   }
   if (Is3DContextLeaf()) {
     aStream << " [is3DContextLeaf]";
   }
-  if (IsScrollbarContainer()) {
+  if (GetScrollbarContainerDirection().isSome()) {
     aStream << " [scrollbar]";
   }
   if (Maybe<ScrollDirection> thumbDirection = GetScrollThumbData().mDirection) {
     if (*thumbDirection == ScrollDirection::eVertical) {
       aStream << nsPrintfCString(" [vscrollbar=%" PRIu64 "]", GetScrollbarTargetContainerId()).get();
     }
     if (*thumbDirection == ScrollDirection::eHorizontal) {
       aStream << nsPrintfCString(" [hscrollbar=%" PRIu64 "]", GetScrollbarTargetContainerId()).get();
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1307,19 +1307,20 @@ public:
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ScrollbarData", this));
       MutatedSimple();
     }
   }
 
   // Set during construction for the container layer of scrollbar components.
   // |aScrollId| holds the scroll identifier of the scrollable content that
   // the scrollbar is for.
-  void SetIsScrollbarContainer(FrameMetrics::ViewID aScrollId)
+  void SetScrollbarContainer(FrameMetrics::ViewID aScrollId,
+                             ScrollDirection aDirection)
   {
-    if (mSimpleAttrs.SetIsScrollbarContainer(aScrollId)) {
+    if (mSimpleAttrs.SetScrollbarContainer(aScrollId, aDirection)) {
       MutatedSimple();
     }
   }
 
   // Used when forwarding transactions. Do not use at any other time.
   void SetSimpleAttributes(const SimpleLayerAttributes& aAttrs) {
     mSimpleAttrs = aAttrs;
   }
@@ -1373,17 +1374,18 @@ public:
   FrameMetrics::ViewID GetFixedPositionScrollContainerId() { return mSimpleAttrs.FixedPositionScrollContainerId(); }
   LayerPoint GetFixedPositionAnchor() { return mSimpleAttrs.FixedPositionAnchor(); }
   int32_t GetFixedPositionSides() { return mSimpleAttrs.FixedPositionSides(); }
   FrameMetrics::ViewID GetStickyScrollContainerId() { return mSimpleAttrs.StickyScrollContainerId(); }
   const LayerRect& GetStickyScrollRangeOuter() { return mSimpleAttrs.StickyScrollRangeOuter(); }
   const LayerRect& GetStickyScrollRangeInner() { return mSimpleAttrs.StickyScrollRangeInner(); }
   FrameMetrics::ViewID GetScrollbarTargetContainerId() { return mSimpleAttrs.ScrollbarTargetContainerId(); }
   const ScrollThumbData& GetScrollThumbData() const { return mSimpleAttrs.ThumbData(); }
-  bool IsScrollbarContainer() { return mSimpleAttrs.IsScrollbarContainer(); }
+  bool IsScrollbarContainer() { return mSimpleAttrs.GetScrollbarContainerDirection().isSome(); }
+  Maybe<ScrollDirection> GetScrollbarContainerDirection() { return mSimpleAttrs.GetScrollbarContainerDirection(); }
   Layer* GetMaskLayer() const { return mMaskLayer; }
   bool HasPendingTransform() const { return mPendingTransform; }
 
   void CheckCanary() const { mCanary.Check(); }
 
   // Ancestor mask layers are associated with FrameMetrics, but for simplicity
   // in maintaining the layer tree structure we attach them to the layer.
   size_t GetAncestorMaskLayerCount() const {
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -753,17 +753,17 @@ APZCTreeManager::PrepareNodeForLayer(con
         GetEventRegions(aLayer),
         aLayer.GetVisibleRegion(),
         aLayer.GetTransformTyped(),
         aLayer.GetClipRect() ? Some(ParentLayerIntRegion(*aLayer.GetClipRect())) : Nothing(),
         GetEventRegionsOverride(aParent, aLayer));
     node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(),
                            aLayer.GetScrollbarAnimationId(),
                            aLayer.GetScrollThumbData(),
-                           aLayer.IsScrollbarContainer());
+                           aLayer.GetScrollbarContainerDirection());
     node->SetFixedPosData(aLayer.GetFixedPositionScrollContainerId());
     return node;
   }
 
   AsyncPanZoomController* apzc = nullptr;
   // If we get here, aLayer is a scrollable layer and somebody
   // has registered a GeckoContentController for it, so we need to ensure
   // it has an APZC instance to manage its scrolling.
@@ -947,17 +947,17 @@ APZCTreeManager::PrepareNodeForLayer(con
   }
 
   // Note: if layer properties must be propagated to nodes, RecvUpdate in
   // LayerTransactionParent.cpp must ensure that APZ will be notified
   // when those properties change.
   node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(),
                          aLayer.GetScrollbarAnimationId(),
                          aLayer.GetScrollThumbData(),
-                         aLayer.IsScrollbarContainer());
+                         aLayer.GetScrollbarContainerDirection());
   node->SetFixedPosData(aLayer.GetFixedPositionScrollContainerId());
   return node;
 }
 
 template<typename PanGestureOrScrollWheelInput>
 static bool
 WillHandleInput(const PanGestureOrScrollWheelInput& aPanInput)
 {
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp
+++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp
@@ -23,17 +23,16 @@ namespace layers {
 HitTestingTreeNode::HitTestingTreeNode(AsyncPanZoomController* aApzc,
                                        bool aIsPrimaryHolder,
                                        uint64_t aLayersId)
   : mApzc(aApzc)
   , mIsPrimaryApzcHolder(aIsPrimaryHolder)
   , mLayersId(aLayersId)
   , mScrollViewId(FrameMetrics::NULL_SCROLL_ID)
   , mScrollbarAnimationId(0)
-  , mIsScrollbarContainer(false)
   , mFixedPosTarget(FrameMetrics::NULL_SCROLL_ID)
   , mOverride(EventRegionsOverride::NoOverride)
 {
 if (mIsPrimaryApzcHolder) {
     MOZ_ASSERT(mApzc);
   }
   MOZ_ASSERT(!mApzc || mApzc->GetLayersId() == mLayersId);
 }
@@ -92,22 +91,22 @@ HitTestingTreeNode::SetLastChild(HitTest
     }
   }
 }
 
 void
 HitTestingTreeNode::SetScrollbarData(FrameMetrics::ViewID aScrollViewId,
                                      const uint64_t& aScrollbarAnimationId,
                                      const ScrollThumbData& aThumbData,
-                                     bool aIsScrollContainer)
+                                     const Maybe<ScrollDirection>& aScrollContainerDirection)
 {
   mScrollViewId = aScrollViewId;
   mScrollbarAnimationId = aScrollbarAnimationId;
   mScrollThumbData = aThumbData;
-  mIsScrollbarContainer = aIsScrollContainer;
+  mScrollbarContainerDirection = aScrollContainerDirection;
 }
 
 bool
 HitTestingTreeNode::MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const
 {
   return IsScrollThumbNode() &&
          mScrollThumbData.mDirection == aDragMetrics.mDirection &&
          mScrollViewId == aDragMetrics.mViewId;
@@ -117,17 +116,17 @@ bool
 HitTestingTreeNode::IsScrollThumbNode() const
 {
   return mScrollThumbData.mDirection.isSome();
 }
 
 bool
 HitTestingTreeNode::IsScrollbarNode() const
 {
-  return mIsScrollbarContainer || IsScrollThumbNode();
+  return mScrollbarContainerDirection.isSome() || IsScrollThumbNode();
 }
 
 FrameMetrics::ViewID
 HitTestingTreeNode::GetScrollTargetId() const
 {
   return mScrollViewId;
 }
 
@@ -341,17 +340,17 @@ HitTestingTreeNode::Dump(const char* aPr
   printf_stderr("%sHitTestingTreeNode (%p) APZC (%p) g=(%s) %s%s%sr=(%s) t=(%s) c=(%s)%s%s\n",
     aPrefix, this, mApzc.get(),
     mApzc ? Stringify(mApzc->GetGuid()).c_str() : nsPrintfCString("l=0x%" PRIx64, mLayersId).get(),
     (mOverride & EventRegionsOverride::ForceDispatchToContent) ? "fdtc " : "",
     (mOverride & EventRegionsOverride::ForceEmptyHitRegion) ? "fehr " : "",
     (mFixedPosTarget != FrameMetrics::NULL_SCROLL_ID) ? nsPrintfCString("fixed=%" PRIu64 " ", mFixedPosTarget).get() : "",
     Stringify(mEventRegions).c_str(), Stringify(mTransform).c_str(),
     mClipRegion ? Stringify(mClipRegion.ref()).c_str() : "none",
-    mIsScrollbarContainer ? " scrollbar" : "",
+    mScrollbarContainerDirection.isSome() ? " scrollbar" : "",
     IsScrollThumbNode() ? " scrollthumb" : "");
   if (mLastChild) {
     mLastChild->Dump(nsPrintfCString("%s  ", aPrefix).get());
   }
 }
 
 void
 HitTestingTreeNode::SetApzcParent(AsyncPanZoomController* aParent)
--- a/gfx/layers/apz/src/HitTestingTreeNode.h
+++ b/gfx/layers/apz/src/HitTestingTreeNode.h
@@ -92,17 +92,17 @@ public:
                       const EventRegionsOverride& aOverride);
   bool IsOutsideClip(const ParentLayerPoint& aPoint) const;
 
   /* Scrollbar info */
 
   void SetScrollbarData(FrameMetrics::ViewID aScrollViewId,
                         const uint64_t& aScrollbarAnimationId,
                         const ScrollThumbData& aThumbData,
-                        bool aIsScrollContainer);
+                        const Maybe<ScrollDirection>& aScrollContainerDirection);
   bool MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const;
   bool IsScrollbarNode() const;  // Scroll thumb or scrollbar container layer.
   bool IsScrollThumbNode() const;  // Scroll thumb container layer.
   FrameMetrics::ViewID GetScrollTargetId() const;
   const ScrollThumbData& GetScrollThumbData() const;
   const uint64_t& GetScrollbarAnimationId() const;
 
   /* Fixed pos info */
@@ -146,17 +146,17 @@ private:
   // where IsScrollThumbNode() returns true. It holds the animation id that we
   // use to move the thumb node to reflect async scrolling.
   uint64_t mScrollbarAnimationId;
 
   // This is set for scroll thumb Container layers only.
   ScrollThumbData mScrollThumbData;
 
   // This is set for scroll track Container layers only.
-  bool mIsScrollbarContainer;
+  Maybe<ScrollDirection> mScrollbarContainerDirection;
 
   FrameMetrics::ViewID mFixedPosTarget;
 
   /* Let {L,M} be the {layer, scrollable metrics} pair that this node
    * corresponds to in the layer tree. mEventRegions contains the event regions
    * from L, in the case where event-regions are enabled. If event-regions are
    * disabled, it will contain the visible region of L, which we use as an
    * approximation to the hit region for the purposes of obscuring other layers.
--- a/gfx/layers/wr/WebRenderScrollData.cpp
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -18,17 +18,16 @@ namespace mozilla {
 namespace layers {
 
 WebRenderLayerScrollData::WebRenderLayerScrollData()
   : mDescendantCount(-1)
   , mTransformIsPerspective(false)
   , mEventRegionsOverride(EventRegionsOverride::NoOverride)
   , mScrollbarAnimationId(0)
   , mScrollbarTargetContainerId(FrameMetrics::NULL_SCROLL_ID)
-  , mIsScrollbarContainer(false)
   , mFixedPosScrollContainerId(FrameMetrics::NULL_SCROLL_ID)
 {
 }
 
 WebRenderLayerScrollData::~WebRenderLayerScrollData()
 {
 }
 
@@ -113,17 +112,17 @@ WebRenderLayerScrollData::Dump(const Web
     Stringify(mTransform).c_str(), mTransformIsPerspective,
     Stringify(mVisibleRegion).c_str());
   printf_stderr("  event regions: %s override: 0x%x\n",
     Stringify(mEventRegions).c_str(), mEventRegionsOverride);
   printf_stderr("  ref layers id: 0x%" PRIx64 "\n", mReferentId.valueOr(0));
   //printf_stderr("  scroll thumb: %s animation: %" PRIu64 "\n",
   //  Stringify(mScrollThumbData).c_str(), mScrollbarAnimationId);
   printf_stderr("  scroll container: %d target: %" PRIu64 "\n",
-    mIsScrollbarContainer, mScrollbarTargetContainerId);
+    mScrollbarContainerDirection.isSome(), mScrollbarTargetContainerId);
   printf_stderr("  fixed pos container: %" PRIu64 "\n",
     mFixedPosScrollContainerId);
 }
 
 WebRenderScrollData::WebRenderScrollData()
   : mManager(nullptr)
   , mIsFirstPaint(false)
   , mPaintSequenceNumber(0)
--- a/gfx/layers/wr/WebRenderScrollData.h
+++ b/gfx/layers/wr/WebRenderScrollData.h
@@ -76,18 +76,18 @@ public:
   Maybe<uint64_t> GetReferentId() const { return mReferentId; }
 
   void SetScrollThumbData(const ScrollThumbData& aData) { mScrollThumbData = aData; }
   const ScrollThumbData& GetScrollThumbData() const { return mScrollThumbData; }
   void SetScrollbarAnimationId(const uint64_t& aId) { mScrollbarAnimationId = aId; }
   const uint64_t& GetScrollbarAnimationId() const { return mScrollbarAnimationId; }
   void SetScrollbarTargetContainerId(FrameMetrics::ViewID aId) { mScrollbarTargetContainerId = aId; }
   FrameMetrics::ViewID GetScrollbarTargetContainerId() const { return mScrollbarTargetContainerId; }
-  void SetIsScrollbarContainer() { mIsScrollbarContainer = true; }
-  bool IsScrollbarContainer() const { return mIsScrollbarContainer; }
+  void SetScrollbarContainerDirection(ScrollDirection aDirection) { mScrollbarContainerDirection = Some(aDirection); }
+  Maybe<ScrollDirection> GetScrollbarContainerDirection() const { return mScrollbarContainerDirection; }
 
   void SetFixedPositionScrollContainerId(FrameMetrics::ViewID aId) { mFixedPosScrollContainerId = aId; }
   FrameMetrics::ViewID GetFixedPositionScrollContainerId() const { return mFixedPosScrollContainerId; }
 
   void Dump(const WebRenderScrollData& aOwner) const;
 
   friend struct IPC::ParamTraits<WebRenderLayerScrollData>;
 
@@ -111,17 +111,17 @@ private:
   bool mTransformIsPerspective;
   EventRegions mEventRegions;
   LayerIntRegion mVisibleRegion;
   Maybe<uint64_t> mReferentId;
   EventRegionsOverride mEventRegionsOverride;
   ScrollThumbData mScrollThumbData;
   uint64_t mScrollbarAnimationId;
   FrameMetrics::ViewID mScrollbarTargetContainerId;
-  bool mIsScrollbarContainer;
+  Maybe<ScrollDirection> mScrollbarContainerDirection;
   FrameMetrics::ViewID mFixedPosScrollContainerId;
 };
 
 // Data needed by APZ, for the whole layer tree. One instance of this class
 // is created for each transaction sent over PWebRenderBridge. It is populated
 // with information from the WebRender layer tree on the client side and the
 // information is used by APZ on the parent side.
 class WebRenderScrollData
@@ -228,17 +228,17 @@ struct ParamTraits<mozilla::layers::WebR
     WriteParam(aMsg, aParam.mTransformIsPerspective);
     WriteParam(aMsg, aParam.mEventRegions);
     WriteParam(aMsg, aParam.mVisibleRegion);
     WriteParam(aMsg, aParam.mReferentId);
     WriteParam(aMsg, aParam.mEventRegionsOverride);
     WriteParam(aMsg, aParam.mScrollThumbData);
     WriteParam(aMsg, aParam.mScrollbarAnimationId);
     WriteParam(aMsg, aParam.mScrollbarTargetContainerId);
-    WriteParam(aMsg, aParam.mIsScrollbarContainer);
+    WriteParam(aMsg, aParam.mScrollbarContainerDirection);
     WriteParam(aMsg, aParam.mFixedPosScrollContainerId);
   }
 
   static bool
   Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mDescendantCount)
         && ReadParam(aMsg, aIter, &aResult->mScrollIds)
@@ -246,17 +246,17 @@ struct ParamTraits<mozilla::layers::WebR
         && ReadParam(aMsg, aIter, &aResult->mTransformIsPerspective)
         && ReadParam(aMsg, aIter, &aResult->mEventRegions)
         && ReadParam(aMsg, aIter, &aResult->mVisibleRegion)
         && ReadParam(aMsg, aIter, &aResult->mReferentId)
         && ReadParam(aMsg, aIter, &aResult->mEventRegionsOverride)
         && ReadParam(aMsg, aIter, &aResult->mScrollThumbData)
         && ReadParam(aMsg, aIter, &aResult->mScrollbarAnimationId)
         && ReadParam(aMsg, aIter, &aResult->mScrollbarTargetContainerId)
-        && ReadParam(aMsg, aIter, &aResult->mIsScrollbarContainer)
+        && ReadParam(aMsg, aIter, &aResult->mScrollbarContainerDirection)
         && ReadParam(aMsg, aIter, &aResult->mFixedPosScrollContainerId);
   }
 };
 
 template<>
 struct ParamTraits<mozilla::layers::WebRenderScrollData>
 {
   typedef mozilla::layers::WebRenderScrollData paramType;
--- a/gfx/layers/wr/WebRenderScrollDataWrapper.h
+++ b/gfx/layers/wr/WebRenderScrollDataWrapper.h
@@ -298,20 +298,20 @@ public:
   }
 
   FrameMetrics::ViewID GetScrollbarTargetContainerId() const
   {
     MOZ_ASSERT(IsValid());
     return mLayer->GetScrollbarTargetContainerId();
   }
 
-  bool IsScrollbarContainer() const
+  Maybe<ScrollDirection> GetScrollbarContainerDirection() const
   {
     MOZ_ASSERT(IsValid());
-    return mLayer->IsScrollbarContainer();
+    return mLayer->GetScrollbarContainerDirection();
   }
 
   FrameMetrics::ViewID GetFixedPositionScrollContainerId() const
   {
     MOZ_ASSERT(IsValid());
     return mLayer->GetFixedPositionScrollContainerId();
   }
 
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3023,22 +3023,30 @@ AppendToTop(nsDisplayListBuilder* aBuild
             nsDisplayList* aSource, nsIFrame* aSourceFrame, uint32_t aFlags)
 {
   if (aSource->IsEmpty())
     return;
 
   nsDisplayWrapList* newItem;
   const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
   if (aFlags & APPEND_OWN_LAYER) {
-    nsDisplayOwnLayerFlags flags = (aFlags & APPEND_SCROLLBAR_CONTAINER)
-        ? nsDisplayOwnLayerFlags::eScrollbarContainer
-        : nsDisplayOwnLayerFlags::eNone;
-    FrameMetrics::ViewID scrollTarget = (aFlags & APPEND_SCROLLBAR_CONTAINER)
-        ? aBuilder->GetCurrentScrollbarTarget()
-        : FrameMetrics::NULL_SCROLL_ID;
+    FrameMetrics::ViewID scrollTarget = FrameMetrics::NULL_SCROLL_ID;
+    nsDisplayOwnLayerFlags flags = aBuilder->GetCurrentScrollbarFlags();
+    // The flags here should be at most one scrollbar direction and nothing else
+    MOZ_ASSERT(flags == nsDisplayOwnLayerFlags::eNone ||
+               flags == nsDisplayOwnLayerFlags::eVerticalScrollbar ||
+               flags == nsDisplayOwnLayerFlags::eHorizontalScrollbar);
+
+    if (aFlags & APPEND_SCROLLBAR_CONTAINER) {
+      scrollTarget = aBuilder->GetCurrentScrollbarTarget();
+      // The flags here should be exactly one scrollbar direction
+      MOZ_ASSERT(flags != nsDisplayOwnLayerFlags::eNone);
+      flags |= nsDisplayOwnLayerFlags::eScrollbarContainer;
+    }
+
     newItem = new (aBuilder) nsDisplayOwnLayer(aBuilder, aSourceFrame, aSource, asr, flags, scrollTarget);
   } else {
     newItem = new (aBuilder) nsDisplayWrapList(aBuilder, aSourceFrame, aSource, asr);
   }
 
   if (aFlags & APPEND_POSITIONED) {
     // We want overlay scrollbars to always be on top of the scrolled content,
     // but we don't want them to unnecessarily cover overlapping elements from
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -6833,18 +6833,17 @@ nsDisplayOwnLayer::GetLayerState(nsDispl
   }
 
   return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, mAnimatedGeometryRoot);
 }
 
 bool
 nsDisplayOwnLayer::IsScrollThumbLayer() const
 {
-  return (mFlags & nsDisplayOwnLayerFlags::eVerticalScrollbar) ||
-         (mFlags & nsDisplayOwnLayerFlags::eHorizontalScrollbar);
+  return mThumbData.mDirection.isSome();
 }
 
 bool
 nsDisplayOwnLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) const
 {
   // Render scroll thumb layers even if they are invisible, because async
   // scrolling might bring them into view.
   return IsScrollThumbLayer();
@@ -6855,37 +6854,40 @@ already_AddRefed<Layer>
 nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
                               LayerManager* aManager,
                               const ContainerLayerParameters& aContainerParameters)
 {
   RefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
                            aContainerParameters, nullptr,
                            FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR);
-  if (mThumbData.mDirection.isSome()) {
+  if (IsScrollThumbLayer()) {
     layer->SetScrollThumbData(mScrollTarget, mThumbData);
   }
   if (mFlags & nsDisplayOwnLayerFlags::eScrollbarContainer) {
-    layer->SetIsScrollbarContainer(mScrollTarget);
+    ScrollDirection dir = (mFlags & nsDisplayOwnLayerFlags::eVerticalScrollbar)
+                        ? ScrollDirection::eVertical
+                        : ScrollDirection::eHorizontal;
+    layer->SetScrollbarContainer(mScrollTarget, dir);
   }
 
   if (mFlags & nsDisplayOwnLayerFlags::eGenerateSubdocInvalidations) {
     mFrame->PresContext()->SetNotifySubDocInvalidationData(layer);
   }
   return layer.forget();
 }
 
 bool
 nsDisplayOwnLayer::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                            mozilla::wr::IpcResourceUpdateQueue& aResources,
                                            const StackingContextHelper& aSc,
                                            WebRenderLayerManager* aManager,
                                            nsDisplayListBuilder* aDisplayListBuilder)
 {
-  if (!aManager->AsyncPanZoomEnabled() || mThumbData.mDirection.isNothing()) {
+  if (!aManager->AsyncPanZoomEnabled() || !IsScrollThumbLayer()) {
     return nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, aSc,
                                                       aManager, aDisplayListBuilder);
   }
 
   // APZ is enabled and this is a scroll thumb, so we need to create and
   // set an animation id. That way APZ can move this scrollthumb around as
   // needed.
   RefPtr<WebRenderAnimationData> animationData = aManager->CommandBuilder().CreateOrRecycleWebRenderUserData<WebRenderAnimationData>(this);
@@ -6917,17 +6919,20 @@ nsDisplayOwnLayer::UpdateScrollData(mozi
       aLayerData->SetScrollThumbData(mThumbData);
       aLayerData->SetScrollbarAnimationId(mWrAnimationId);
       aLayerData->SetScrollbarTargetContainerId(mScrollTarget);
     }
   }
   if (mFlags & nsDisplayOwnLayerFlags::eScrollbarContainer) {
     ret = true;
     if (aLayerData) {
-      aLayerData->SetIsScrollbarContainer();
+      ScrollDirection dir = (mFlags & nsDisplayOwnLayerFlags::eVerticalScrollbar)
+                          ? ScrollDirection::eVertical
+                          : ScrollDirection::eHorizontal;
+      aLayerData->SetScrollbarContainerDirection(dir);
       aLayerData->SetScrollbarTargetContainerId(mScrollTarget);
     }
   }
   return ret;
 }
 
 nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder* aBuilder,
                                            nsIFrame* aFrame,