Bug 1349750 - Group scroll thumb-related information in Layer into a ScrollThumbData structure. r=kats draft
authorBotond Ballo <botond@mozilla.com>
Wed, 10 May 2017 14:02:15 -0400
changeset 577053 7b2bfccf1351c82bb16296635e69d5488c87a50f
parent 576982 1e2fe13035e13b7b4001ade3b48f226957cef5fc
child 577054 6cc6d2f2e3ecc4dedce2b83f6b0faf819f4be0f8
push id58590
push userbballo@mozilla.com
push dateFri, 12 May 2017 19:24:13 +0000
reviewerskats
bugs1349750
milestone55.0a1
Bug 1349750 - Group scroll thumb-related information in Layer into a ScrollThumbData structure. r=kats The patch also renames Layer::SetScrollbarData() to Layer::SetScrollThumbData() for clarity. MozReview-Commit-ID: DVwJ3DMl3Zs
gfx/layers/LayerAttributes.h
gfx/layers/LayerMetricsWrapper.h
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/composite/AsyncCompositionManager.cpp
gfx/layers/wr/WebRenderScrollData.cpp
layout/generic/nsFrame.cpp
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
layout/xul/nsSliderFrame.cpp
--- a/gfx/layers/LayerAttributes.h
+++ b/gfx/layers/LayerAttributes.h
@@ -12,32 +12,52 @@
 
 namespace IPC {
 template <typename T> struct ParamTraits;
 } // namespace IPC
 
 namespace mozilla {
 namespace layers {
 
+// Data stored for scroll thumb container layers.
+struct ScrollThumbData {
+  ScrollThumbData()
+    : mDirection(ScrollDirection::NONE), mThumbRatio(0.0f) {}
+  ScrollThumbData(ScrollDirection aDirection, float aThumbRatio)
+    : mDirection(aDirection), mThumbRatio(aThumbRatio) {}
+
+  ScrollDirection mDirection;
+  // The scrollbar thumb ratio is the ratio of the thumb position (in the CSS
+  // pixels of the scrollframe's parent's space) to the scroll position (in the
+  // CSS pixels of the scrollframe's space).
+  float mThumbRatio;
+
+  bool operator==(const ScrollThumbData& aOther) const {
+    return mDirection == aOther.mDirection &&
+           mThumbRatio == aOther.mThumbRatio;
+  }
+  bool operator!=(const ScrollThumbData& aOther) const {
+    return !(*this == aOther);
+  }
+};
+
 // Infrequently changing layer attributes that require no special
 // serialization work.
 class SimpleLayerAttributes final
 {
   friend struct IPC::ParamTraits<mozilla::layers::SimpleLayerAttributes>;
 public:
   SimpleLayerAttributes()
    : mTransformIsPerspective(false),
      mPostXScale(1.0f),
      mPostYScale(1.0f),
      mContentFlags(0),
      mOpacity(1.0f),
      mIsFixedPosition(false),
      mScrollbarTargetContainerId(FrameMetrics::NULL_SCROLL_ID),
-     mScrollbarDirection(ScrollDirection::NONE),
-     mScrollbarThumbRatio(0.0f),
      mIsScrollbarContainer(false),
      mMixBlendMode(gfx::CompositionOp::OP_OVER),
      mForceIsolatedGroup(false)
   {
   }
 
   //
   // Setters.
@@ -68,26 +88,24 @@ public:
   }
   bool SetIsFixedPosition(bool aFixedPosition) {
     if (mIsFixedPosition == aFixedPosition) {
       return false;
     }
     mIsFixedPosition = aFixedPosition;
     return true;
   }
-  bool SetScrollbarData(FrameMetrics::ViewID aScrollId, ScrollDirection aDir, float aThumbRatio) {
+  bool SetScrollThumbData(FrameMetrics::ViewID aScrollId, const ScrollThumbData& aThumbData) {
     if (mScrollbarTargetContainerId == aScrollId &&
-        mScrollbarDirection == aDir &&
-        mScrollbarThumbRatio == aThumbRatio)
+        mThumbData == aThumbData)
     {
       return false;
     }
     mScrollbarTargetContainerId = aScrollId;
-    mScrollbarDirection = aDir;
-    mScrollbarThumbRatio = aThumbRatio;
+    mThumbData = aThumbData;
     return true;
   }
   bool SetIsScrollbarContainer(FrameMetrics::ViewID aScrollId) {
     if (mIsScrollbarContainer && mScrollbarTargetContainerId == aScrollId) {
       return false;
     }
     mIsScrollbarContainer = true;
     mScrollbarTargetContainerId = aScrollId;
@@ -167,17 +185,17 @@ public:
   // APZ hit testing.
   bool HitTestingInfoIsEqual(const SimpleLayerAttributes& aOther) const {
     if (mIsScrollbarContainer != aOther.mIsScrollbarContainer) {
       return false;
     }
     if (mScrollbarTargetContainerId != aOther.mScrollbarTargetContainerId) {
       return false;
     }
-    if (mScrollbarDirection != aOther.mScrollbarDirection) {
+    if (mThumbData != aOther.mThumbData) {
       return false;
     }
     if (FixedPositionScrollContainerId() != aOther.FixedPositionScrollContainerId()) {
       return false;
     }
     if (mTransform != aOther.mTransform) {
       return false;
     }
@@ -201,21 +219,18 @@ public:
     return mOpacity;
   }
   bool IsFixedPosition() const {
     return mIsFixedPosition;
   }
   FrameMetrics::ViewID ScrollbarTargetContainerId() const {
     return mScrollbarTargetContainerId;
   }
-  ScrollDirection ScrollbarDirection() const {
-    return mScrollbarDirection;
-  }
-  float ScrollbarThumbRatio() const {
-    return mScrollbarThumbRatio;
+  const ScrollThumbData& ThumbData() const {
+    return mThumbData;
   }
   float IsScrollbarContainer() const {
     return mIsScrollbarContainer;
   }
   gfx::CompositionOp MixBlendMode() const {
     return mMixBlendMode;
   }
   bool ForceIsolatedGroup() const {
@@ -259,38 +274,33 @@ public:
            mTransformIsPerspective == aOther.mTransformIsPerspective &&
            mScrolledClip == aOther.mScrolledClip &&
            mPostXScale == aOther.mPostXScale &&
            mPostYScale == aOther.mPostYScale &&
            mContentFlags == aOther.mContentFlags &&
            mOpacity == aOther.mOpacity &&
            mIsFixedPosition == aOther.mIsFixedPosition &&
            mScrollbarTargetContainerId == aOther.mScrollbarTargetContainerId &&
-           mScrollbarDirection == aOther.mScrollbarDirection &&
-           mScrollbarThumbRatio == aOther.mScrollbarThumbRatio &&
+           mThumbData == aOther.mThumbData &&
            mIsScrollbarContainer == aOther.mIsScrollbarContainer &&
            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;
-  ScrollDirection mScrollbarDirection;
-  // The scrollbar thumb ratio is the ratio of the thumb position (in the CSS
-  // pixels of the scrollframe's parent's space) to the scroll position (in the
-  // CSS pixels of the scrollframe's space).
-  float mScrollbarThumbRatio;
+  ScrollThumbData mThumbData;
   bool mIsScrollbarContainer;
   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
@@ -408,17 +408,17 @@ public:
     }
     return EventRegionsOverride::NoOverride;
   }
 
   ScrollDirection GetScrollbarDirection() const
   {
     MOZ_ASSERT(IsValid());
 
-    return mLayer->GetScrollbarDirection();
+    return mLayer->GetScrollThumbData().mDirection;
   }
 
   FrameMetrics::ViewID GetScrollbarTargetContainerId() const
   {
     MOZ_ASSERT(IsValid());
 
     return mLayer->GetScrollbarTargetContainerId();
   }
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -1884,20 +1884,21 @@ Layer::PrintInfo(std::stringstream& aStr
     aStream << " [combines3DTransformWithAncestors]";
   }
   if (Is3DContextLeaf()) {
     aStream << " [is3DContextLeaf]";
   }
   if (IsScrollbarContainer()) {
     aStream << " [scrollbar]";
   }
-  if (GetScrollbarDirection() == ScrollDirection::VERTICAL) {
+  ScrollDirection thumbDirection = GetScrollThumbData().mDirection;
+  if (thumbDirection == ScrollDirection::VERTICAL) {
     aStream << nsPrintfCString(" [vscrollbar=%" PRIu64 "]", GetScrollbarTargetContainerId()).get();
   }
-  if (GetScrollbarDirection() == ScrollDirection::HORIZONTAL) {
+  if (thumbDirection == ScrollDirection::HORIZONTAL) {
     aStream << nsPrintfCString(" [hscrollbar=%" PRIu64 "]", GetScrollbarTargetContainerId()).get();
   }
   if (GetIsFixedPosition()) {
     LayerPoint anchor = GetFixedPositionAnchor();
     aStream << nsPrintfCString(" [isFixedPosition scrollId=%" PRIu64 " sides=0x%x anchor=%s]",
                      GetFixedPositionScrollContainerId(),
                      GetFixedPositionSides(),
                      ToString(anchor).c_str()).get();
@@ -2033,18 +2034,19 @@ Layer::DumpPacket(layerscope::LayersPack
   }
   // Opacity
   layer->set_opacity(GetOpacity());
   // Content opaque
   layer->set_copaque(static_cast<bool>(GetContentFlags() & CONTENT_OPAQUE));
   // Component alpha
   layer->set_calpha(static_cast<bool>(GetContentFlags() & CONTENT_COMPONENT_ALPHA));
   // Vertical or horizontal bar
-  if (GetScrollbarDirection() != ScrollDirection::NONE) {
-    layer->set_direct(GetScrollbarDirection() == ScrollDirection::VERTICAL ?
+  ScrollDirection thumbDirection = GetScrollThumbData().mDirection;
+  if (thumbDirection != ScrollDirection::NONE) {
+    layer->set_direct(thumbDirection == ScrollDirection::VERTICAL ?
                       LayersPacket::Layer::VERTICAL :
                       LayersPacket::Layer::HORIZONTAL);
     layer->set_barid(GetScrollbarTargetContainerId());
   }
 
   // Mask layer
   if (mMaskLayer) {
     layer->set_mask(reinterpret_cast<uint64_t>(mMaskLayer.get()));
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1283,22 +1283,23 @@ public:
     if (mSimpleAttrs.SetStickyPositionData(aScrollId, aOuter, aInner)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) StickyPositionData", this));
       MutatedSimple();
     }
   }
 
   /**
    * CONSTRUCTION PHASE ONLY
-   * If a layer is a scrollbar layer, |aScrollId| holds the scroll identifier
-   * of the scrollable content that the scrollbar is for.
+   * If a layer is a scroll thumb container layer, set the scroll identifier
+   * of the scroll frame scrolled by the thumb, and other data related to the
+   * thumb.
    */
-  void SetScrollbarData(FrameMetrics::ViewID aScrollId, ScrollDirection aDir, float aThumbRatio)
+  void SetScrollThumbData(FrameMetrics::ViewID aScrollId, const ScrollThumbData& aThumbData)
   {
-    if (mSimpleAttrs.SetScrollbarData(aScrollId, aDir, aThumbRatio)) {
+    if (mSimpleAttrs.SetScrollThumbData(aScrollId, aThumbData)) {
       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.
@@ -1362,18 +1363,17 @@ public:
   bool GetIsStickyPosition() { return mSimpleAttrs.IsStickyPosition(); }
   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(); }
-  ScrollDirection GetScrollbarDirection() { return mSimpleAttrs.ScrollbarDirection(); }
-  float GetScrollbarThumbRatio() { return mSimpleAttrs.ScrollbarThumbRatio(); }
+  const ScrollThumbData& GetScrollThumbData() const { return mSimpleAttrs.ThumbData(); }
   bool IsScrollbarContainer() { return mSimpleAttrs.IsScrollbarContainer(); }
   Layer* GetMaskLayer() const { return mMaskLayer; }
   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 {
     return mAncestorMaskLayers.Length();
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -799,17 +799,17 @@ MoveScrollbarForLayerMargin(Layer* aRoot
                             const ScreenMargin& aFixedLayerMargins)
 {
   // See bug 1223928 comment 9 - once we can detect the RCD with just the
   // isRootContent flag on the metrics, we can probably move this code into
   // ApplyAsyncTransformToScrollbar rather than having it as a separate
   // adjustment on the layer tree.
   Layer* scrollbar = BreadthFirstSearch<ReverseIterator>(aRoot,
     [aRootScrollId](Layer* aNode) {
-      return (aNode->GetScrollbarDirection() == ScrollDirection::HORIZONTAL &&
+      return (aNode->GetScrollThumbData().mDirection == ScrollDirection::HORIZONTAL &&
               aNode->GetScrollbarTargetContainerId() == aRootScrollId);
     });
   if (scrollbar) {
     // Shift the horizontal scrollbar down into the new space exposed by the
     // dynamic toolbar hiding. Technically we should also scale the vertical
     // scrollbar a bit to expand into the new space but it's not as noticeable
     // and it would add a lot more complexity, so we're going with the "it's not
     // worth it" justification.
@@ -1075,17 +1075,17 @@ AsyncCompositionManager::ApplyAsyncConte
                 maskLayer->GetLocalTransformTyped() * combinedAsyncTransform);
           }
 
           appliedTransform = true;
         }
 
         ExpandRootClipRect(layer, fixedLayerMargins);
 
-        if (layer->GetScrollbarDirection() != ScrollDirection::NONE) {
+        if (layer->GetScrollThumbData().mDirection != ScrollDirection::NONE) {
           ApplyAsyncTransformToScrollbar(layer);
         }
       });
 
   return appliedTransform;
 }
 
 static bool
@@ -1123,32 +1123,33 @@ ApplyAsyncTransformToScrollbarForContent
   AsyncTransformComponentMatrix asyncTransform =
     apzc->GetCurrentAsyncTransform(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
 
   // |asyncTransform| represents the amount by which we have scrolled and
   // zoomed since the last paint. Because the scrollbar was sized and positioned based
   // on the painted content, we need to adjust it based on asyncTransform so that
   // it reflects what the user is actually seeing now.
   AsyncTransformComponentMatrix scrollbarTransform;
-  if (aScrollbar->GetScrollbarDirection() == ScrollDirection::VERTICAL) {
+  const ScrollThumbData& thumbData = aScrollbar->GetScrollThumbData();
+  if (thumbData.mDirection == ScrollDirection::VERTICAL) {
     const ParentLayerCoord asyncScrollY = asyncTransform._42;
     const float asyncZoomY = asyncTransform._22;
 
     // The scroll thumb needs to be scaled in the direction of scrolling by the
     // inverse of the async zoom. This is because zooming in decreases the
     // fraction of the whole srollable rect that is in view.
     const float yScale = 1.f / asyncZoomY;
 
     // Note: |metrics.GetZoom()| doesn't yet include the async zoom.
     const CSSToParentLayerScale effectiveZoom(metrics.GetZoom().yScale * asyncZoomY);
 
     // Here we convert the scrollbar thumb ratio into a true unitless ratio by
     // dividing out the conversion factor from the scrollframe's parent's space
     // to the scrollframe's space.
-    const float ratio = aScrollbar->GetScrollbarThumbRatio() /
+    const float ratio = thumbData.mThumbRatio /
         (metrics.GetPresShellResolution() * asyncZoomY);
     // The scroll thumb needs to be translated in opposite direction of the
     // async scroll. This is because scrolling down, which translates the layer
     // content up, should result in moving the scroll thumb down.
     ParentLayerCoord yTranslation = -asyncScrollY * ratio;
 
     // The scroll thumb additionally needs to be translated to compensate for
     // the scale applied above. The origin with respect to which the scale is
@@ -1175,27 +1176,27 @@ ApplyAsyncTransformToScrollbarForContent
       // resolution-cancelling transform which ensures the scroll thumb isn't
       // actually rendered at a larger scale.
       yTranslation *= metrics.GetPresShellResolution();
     }
 
     scrollbarTransform.PostScale(1.f, yScale, 1.f);
     scrollbarTransform.PostTranslate(0, yTranslation, 0);
   }
-  if (aScrollbar->GetScrollbarDirection() == ScrollDirection::HORIZONTAL) {
+  if (thumbData.mDirection == ScrollDirection::HORIZONTAL) {
     // See detailed comments under the VERTICAL case.
 
     const ParentLayerCoord asyncScrollX = asyncTransform._41;
     const float asyncZoomX = asyncTransform._11;
 
     const float xScale = 1.f / asyncZoomX;
 
     const CSSToParentLayerScale effectiveZoom(metrics.GetZoom().xScale * asyncZoomX);
 
-    const float ratio = aScrollbar->GetScrollbarThumbRatio() /
+    const float ratio = thumbData.mThumbRatio /
         (metrics.GetPresShellResolution() * asyncZoomX);
     ParentLayerCoord xTranslation = -asyncScrollX * ratio;
 
     const CSSCoord thumbOrigin = (metrics.GetScrollOffset().x * ratio);
     const CSSCoord thumbOriginScaled = thumbOrigin * xScale;
     const CSSCoord thumbOriginDelta = thumbOriginScaled - thumbOrigin;
     const ParentLayerCoord thumbOriginDeltaPL = thumbOriginDelta * effectiveZoom;
     xTranslation -= thumbOriginDeltaPL;
--- a/gfx/layers/wr/WebRenderScrollData.cpp
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -38,17 +38,17 @@ WebRenderLayerScrollData::Initialize(Web
   mTransformIsPerspective = aLayer->GetTransformIsPerspective();
   mEventRegions = aLayer->GetEventRegions();
   mReferentId = aLayer->AsRefLayer()
       ? Some(aLayer->AsRefLayer()->GetReferentId())
       : Nothing();
   mEventRegionsOverride = aLayer->AsContainerLayer()
       ? aLayer->AsContainerLayer()->GetEventRegionsOverride()
       : EventRegionsOverride::NoOverride;
-  mScrollbarDirection = aLayer->GetScrollbarDirection();
+  mScrollbarDirection = aLayer->GetScrollThumbData().mDirection;
   mScrollbarTargetContainerId = aLayer->GetScrollbarTargetContainerId();
   mScrollThumbLength = mScrollbarDirection == ScrollDirection::VERTICAL
       ? aLayer->GetVisibleRegion().GetBounds().height
       : aLayer->GetVisibleRegion().GetBounds().width;
   mIsScrollbarContainer = aLayer->IsScrollbarContainer();
   mFixedPosScrollContainerId = aLayer->GetFixedPositionScrollContainerId();
 }
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2787,17 +2787,17 @@ nsIFrame::BuildDisplayListForStackingCon
   }
 
   if (clipCapturedBy == ContainerItemType::eOwnLayerForTransformWithRoundedClip) {
     clipState.Restore();
     resultList.AppendNewToTop(
       new (aBuilder) nsDisplayOwnLayer(aBuilder, this, &resultList,
                                        aBuilder->CurrentActiveScrolledRoot(), 0,
                                        mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
-                                       0.0f, /* aForceActive = */ false));
+                                       ScrollThumbData{}, /* aForceActive = */ false));
   }
 
   /* If we have sticky positioning, wrap it in a sticky position item.
    */
   if (useFixedPosition) {
     if (clipCapturedBy == ContainerItemType::eFixedPosition) {
       clipState.Restore();
     }
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -6146,22 +6146,22 @@ bool nsDisplayBlendContainer::TryMerge(n
   MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendContainer*>(aItem));
   return true;
 }
 
 nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayList* aList,
                                      const ActiveScrolledRoot* aActiveScrolledRoot,
                                      uint32_t aFlags, ViewID aScrollTarget,
-                                     float aScrollbarThumbRatio,
+                                     const ScrollThumbData& aThumbData,
                                      bool aForceActive)
     : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot)
     , mFlags(aFlags)
     , mScrollTarget(aScrollTarget)
-    , mScrollbarThumbRatio(aScrollbarThumbRatio)
+    , mThumbData(aThumbData)
     , mForceActive(aForceActive)
 {
   MOZ_COUNT_CTOR(nsDisplayOwnLayer);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayOwnLayer::~nsDisplayOwnLayer() {
   MOZ_COUNT_DTOR(nsDisplayOwnLayer);
@@ -6185,21 +6185,18 @@ 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 (mFlags & VERTICAL_SCROLLBAR) {
-    layer->SetScrollbarData(mScrollTarget, ScrollDirection::VERTICAL, mScrollbarThumbRatio);
-  }
-  if (mFlags & HORIZONTAL_SCROLLBAR) {
-    layer->SetScrollbarData(mScrollTarget, ScrollDirection::HORIZONTAL, mScrollbarThumbRatio);
+  if (mThumbData.mDirection != ScrollDirection::NONE) {
+    layer->SetScrollThumbData(mScrollTarget, mThumbData);
   }
   if (mFlags & SCROLLBAR_CONTAINER) {
     layer->SetIsScrollbarContainer(mScrollTarget);
   }
 
   if (mFlags & GENERATE_SUBDOC_INVALIDATIONS) {
     mFrame->PresContext()->SetNotifySubDocInvalidationData(layer);
   }
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -30,16 +30,17 @@
 #include "DisplayListClipState.h"
 #include "LayerState.h"
 #include "FrameMetrics.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/gfx/UserData.h"
+#include "mozilla/layers/LayerAttributes.h"
 #include "nsCSSRenderingBorders.h"
 
 #include <stdint.h>
 #include "nsTHashtable.h"
 
 #include <stdlib.h>
 #include <algorithm>
 
@@ -4036,16 +4037,17 @@ private:
 };
 
 /**
  * A display item that has no purpose but to ensure its contents get
  * their own layer.
  */
 class nsDisplayOwnLayer : public nsDisplayWrapList {
 public:
+  typedef mozilla::layers::ScrollThumbData ScrollThumbData;
 
   /**
    * nsDisplayOwnLayer constructor flags
    */
   enum {
     GENERATE_SUBDOC_INVALIDATIONS = 0x01,
     VERTICAL_SCROLLBAR = 0x02,
     HORIZONTAL_SCROLLBAR = 0x04,
@@ -4064,17 +4066,17 @@ public:
    * 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,
                     const ActiveScrolledRoot* aActiveScrolledRoot,
                     uint32_t aFlags = 0,
                     ViewID aScrollTarget = mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
-                    float aScrollbarThumbRatio = 0.0f,
+                    const ScrollThumbData& aThumbData = ScrollThumbData{},
                     bool aForceActive = true);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayOwnLayer();
 #endif
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
@@ -4089,17 +4091,21 @@ public:
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
     return false;
   }
   uint32_t GetFlags() { return mFlags; }
   NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
 protected:
   uint32_t mFlags;
   ViewID mScrollTarget;
-  float mScrollbarThumbRatio;
+  // If this nsDisplayOwnLayer represents a scroll thumb layer, mThumbData
+  // stores information about the scroll thumb. Otherwise, mThumbData will be
+  // default-constructed (in particular with mDirection == ScrollDirection::NONE)
+  // and can be ignored.
+  ScrollThumbData mThumbData;
   bool mForceActive;
 };
 
 /**
  * A display item for subdocuments. This is more or less the same as nsDisplayOwnLayer,
  * except that it always populates the FrameMetrics instance on the ContainerLayer it
  * builds.
  */
--- a/layout/xul/nsSliderFrame.cpp
+++ b/layout/xul/nsSliderFrame.cpp
@@ -49,17 +49,19 @@
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layers/ScrollInputMethods.h"
 #include <algorithm>
 
 using namespace mozilla;
 using mozilla::layers::APZCCallbackHelper;
 using mozilla::layers::AsyncDragMetrics;
 using mozilla::layers::InputAPZContext;
+using mozilla::layers::ScrollDirection;
 using mozilla::layers::ScrollInputMethod;
+using mozilla::layers::ScrollThumbData;
 
 bool nsSliderFrame::gMiddlePref = false;
 int32_t nsSliderFrame::gSnapMultiplier;
 
 // Turn this on if you want to debug slider frames.
 #undef DEBUG_SLIDER
 
 static already_AddRefed<nsIContent>
@@ -359,16 +361,22 @@ nsSliderFrame::BuildDisplayListForChildr
 
     uint32_t flags = aBuilder->GetCurrentScrollbarFlags();
     mozilla::layers::FrameMetrics::ViewID scrollTargetId =
       aBuilder->GetCurrentScrollbarTarget();
     bool thumbGetsLayer = (scrollTargetId != layers::FrameMetrics::NULL_SCROLL_ID);
     nsLayoutUtils::SetScrollbarThumbLayerization(thumb, thumbGetsLayer);
 
     if (thumbGetsLayer) {
+      MOZ_ASSERT((flags & nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR) ||
+                 (flags & nsDisplayOwnLayer::VERTICAL_SCROLLBAR));
+      ScrollDirection scrollDirection =
+            (flags & nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR)
+          ? ScrollDirection::HORIZONTAL
+          : ScrollDirection::VERTICAL;
       nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
       nsDisplayListCollection tempLists;
       nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, tempLists);
 
       // This is a bit of a hack. Collect up all descendant display items
       // and merge them into a single Content() list.
       nsDisplayList masterList;
       masterList.AppendToTop(tempLists.BorderBackground());
@@ -380,17 +388,17 @@ nsSliderFrame::BuildDisplayListForChildr
 
       // Wrap the list to make it its own layer.
       const ActiveScrolledRoot* ownLayerASR = contASRTracker.GetContainerASR();
       DisplayListClipState::AutoSaveRestore ownLayerClipState(aBuilder);
       ownLayerClipState.ClearUpToASR(ownLayerASR);
       aLists.Content()->AppendNewToTop(new (aBuilder)
         nsDisplayOwnLayer(aBuilder, this, &masterList, ownLayerASR,
                           flags, scrollTargetId,
-                          GetThumbRatio()));
+                          ScrollThumbData{scrollDirection, GetThumbRatio()}));
 
       return;
     }
   }
   
   nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists);
 }