Bug 1434250 - Use a Box, rather than a Rect, representation for position:sticky inner/outer rects in the Layers API. r=kats draft
authorBotond Ballo <botond@mozilla.com>
Fri, 09 Feb 2018 15:40:13 -0500
changeset 753218 4f163eca06a7f99eb3d01c80daf8c4674126d4e0
parent 753217 6b5f6cf27eb89a0e4a9764246229d5f84485fb5b
child 753219 d8475017ccc4af936654c1fba18f1b9e2b247b8d
push id98523
push userbballo@mozilla.com
push dateFri, 09 Feb 2018 20:49:23 +0000
reviewerskats
bugs1434250
milestone60.0a1
Bug 1434250 - Use a Box, rather than a Rect, representation for position:sticky inner/outer rects in the Layers API. r=kats MozReview-Commit-ID: 4LDQ3XmWynx
gfx/layers/LayerAttributes.h
gfx/layers/Layers.h
gfx/layers/composite/AsyncCompositionManager.cpp
layout/generic/StickyScrollContainer.cpp
layout/generic/StickyScrollContainer.h
layout/painting/nsDisplayList.cpp
--- a/gfx/layers/LayerAttributes.h
+++ b/gfx/layers/LayerAttributes.h
@@ -187,18 +187,18 @@ public:
     if (!mFixedPositionData) {
       mFixedPositionData.emplace();
     }
     mFixedPositionData->mScrollId = aScrollId;
     mFixedPositionData->mAnchor = aAnchor;
     mFixedPositionData->mSides = aSides;
     return true;
   }
-  bool SetStickyPositionData(FrameMetrics::ViewID aScrollId, LayerRect aOuter,
-                             LayerRect aInner)
+  bool SetStickyPositionData(FrameMetrics::ViewID aScrollId, LayerBox aOuter,
+                             LayerBox aInner)
   {
     if (mStickyPositionData &&
         mStickyPositionData->mOuter.IsEqualEdges(aOuter) &&
         mStickyPositionData->mInner.IsEqualEdges(aInner)) {
       return false;
     }
     if (!mStickyPositionData) {
       mStickyPositionData.emplace();
@@ -285,20 +285,20 @@ public:
     return mFixedPositionData ? mFixedPositionData->mSides : eSideBitsNone;
   }
   bool IsStickyPosition() const {
     return !!mStickyPositionData;
   }
   FrameMetrics::ViewID StickyScrollContainerId() const {
     return mStickyPositionData->mScrollId;
   }
-  const LayerRect& StickyScrollRangeOuter() const {
+  const LayerBox& StickyScrollRangeOuter() const {
     return mStickyPositionData->mOuter;
   }
-  const LayerRect& StickyScrollRangeInner() const {
+  const LayerBox& StickyScrollRangeInner() const {
     return mStickyPositionData->mInner;
   }
 
   bool operator ==(const SimpleLayerAttributes& aOther) const {
     return mTransform == aOther.mTransform &&
            mTransformIsPerspective == aOther.mTransformIsPerspective &&
            mScrolledClip == aOther.mScrolledClip &&
            mPostXScale == aOther.mPostXScale &&
@@ -332,18 +332,18 @@ private:
     FrameMetrics::ViewID mScrollId;
     LayerPoint mAnchor;
     int32_t mSides;
   };
   Maybe<FixedPositionData> mFixedPositionData;
 
   struct StickyPositionData {
     FrameMetrics::ViewID mScrollId;
-    LayerRect mOuter;
-    LayerRect mInner;
+    LayerBox mOuter;
+    LayerBox mInner;
   };
   Maybe<StickyPositionData> mStickyPositionData;
 
   // This class may only contain plain-old-data members that can be safely
   // copied over IPC. Make sure to add new members to operator ==.
 };
 
 } // namespace layers
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1274,18 +1274,18 @@ public:
    * CONSTRUCTION PHASE ONLY
    * If a layer is "sticky position", |aScrollId| holds the scroll identifier
    * of the scrollable content that contains it. The difference between the two
    * rectangles |aOuter| and |aInner| is treated as two intervals in each
    * dimension, with the current scroll position at the origin. For each
    * dimension, while that component of the scroll position lies within either
    * interval, the layer should not move relative to its scrolling container.
    */
-  void SetStickyPositionData(FrameMetrics::ViewID aScrollId, LayerRect aOuter,
-                             LayerRect aInner)
+  void SetStickyPositionData(FrameMetrics::ViewID aScrollId, LayerBox aOuter,
+                             LayerBox aInner)
   {
     if (mSimpleAttrs.SetStickyPositionData(aScrollId, aOuter, aInner)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) StickyPositionData", this));
       MutatedSimple();
     }
   }
 
   /**
@@ -1363,18 +1363,18 @@ public:
   virtual float GetPostYScale() const { return mSimpleAttrs.PostYScale(); }
   bool GetIsFixedPosition() { return mSimpleAttrs.IsFixedPosition(); }
   bool GetTransformIsPerspective() const { return mSimpleAttrs.TransformIsPerspective(); }
   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(); }
+  const LayerBox& GetStickyScrollRangeOuter() { return mSimpleAttrs.StickyScrollRangeOuter(); }
+  const LayerBox& GetStickyScrollRangeInner() { return mSimpleAttrs.StickyScrollRangeInner(); }
   FrameMetrics::ViewID GetScrollbarTargetContainerId() { return mSimpleAttrs.ScrollbarTargetContainerId(); }
   const ScrollThumbData& GetScrollThumbData() const { return mSimpleAttrs.ThumbData(); }
   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(); }
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -526,18 +526,18 @@ AsyncCompositionManager::AlignFixedAndSt
   LayerPoint unconsumedTranslation;
 
   if (layer->GetIsStickyPosition()) {
     // For sticky positioned layers, the difference between the two rectangles
     // defines a pair of translation intervals in each dimension through which
     // the layer should not move relative to the scroll container. To
     // accomplish this, we limit each dimension of the |translation| to that
     // part of it which overlaps those intervals.
-    const LayerRect& stickyOuter = layer->GetStickyScrollRangeOuter();
-    const LayerRect& stickyInner = layer->GetStickyScrollRangeInner();
+    const LayerBox& stickyOuter = layer->GetStickyScrollRangeOuter();
+    const LayerBox& stickyInner = layer->GetStickyScrollRangeInner();
 
     LayerPoint originalTranslation = translation;
     translation.y = IntervalOverlap(translation.y, stickyOuter.Y(), stickyOuter.YMost()) -
                     IntervalOverlap(translation.y, stickyInner.Y(), stickyInner.YMost());
     translation.x = IntervalOverlap(translation.x, stickyOuter.X(), stickyOuter.XMost()) -
                     IntervalOverlap(translation.x, stickyInner.X(), stickyInner.XMost());
     unconsumedTranslation = translation - originalTranslation;
   }
--- a/layout/generic/StickyScrollContainer.cpp
+++ b/layout/generic/StickyScrollContainer.cpp
@@ -145,25 +145,29 @@ StickyScrollContainer::ComputeStickyOffs
   if (offsets) {
     *offsets = computedOffsets;
   } else {
     aFrame->SetProperty(nsIFrame::ComputedOffsetProperty(),
                         new nsMargin(computedOffsets));
   }
 }
 
+static nscoord gUnboundedNegative = nscoord_MIN / 2;
+static nscoord gUnboundedExtent = nscoord_MAX;
+static nscoord gUnboundedPositive = gUnboundedNegative + gUnboundedExtent;
+
 void
 StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame, nsRect* aStick,
                                            nsRect* aContain) const
 {
   NS_ASSERTION(nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aFrame),
                "Can't sticky position individual continuations");
 
-  aStick->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
-  aContain->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
+  aStick->SetRect(gUnboundedNegative, gUnboundedNegative, gUnboundedExtent, gUnboundedExtent);
+  aContain->SetRect(gUnboundedNegative, gUnboundedNegative, gUnboundedExtent, gUnboundedExtent);
 
   const nsMargin* computedOffsets =
     aFrame->GetProperty(nsIFrame::ComputedOffsetProperty());
   if (!computedOffsets) {
     // We haven't reflowed the scroll frame yet, so offsets haven't been
     // computed. Bail.
     return;
   }
@@ -270,54 +274,57 @@ StickyScrollContainer::ComputePosition(n
   position.y = std::min(position.y, std::max(stick.YMost(), contain.y));
   position.x = std::max(position.x, std::min(stick.x, contain.XMost()));
   position.x = std::min(position.x, std::max(stick.XMost(), contain.x));
 
   return position;
 }
 
 void
-StickyScrollContainer::GetScrollRanges(nsIFrame* aFrame, nsRect* aOuter,
-                                       nsRect* aInner) const
+StickyScrollContainer::GetScrollRanges(nsIFrame* aFrame, nsCoordBox* aOuter,
+                                       nsCoordBox* aInner) const
 {
   // We need to use the first in flow; continuation frames should not move
   // relative to each other and should get identical scroll ranges.
   // Also, ComputeStickyLimits requires this.
   nsIFrame *firstCont =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
 
-  nsRect stick;
-  nsRect contain;
-  ComputeStickyLimits(firstCont, &stick, &contain);
+  nsRect stickRect;
+  nsRect containRect;
+  ComputeStickyLimits(firstCont, &stickRect, &containRect);
 
-  aOuter->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
-  aInner->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
+  nsCoordBox stick = nsCoordBox::FromRect(stickRect);
+  nsCoordBox contain = nsCoordBox::FromRect(containRect);
+
+  aOuter->SetBox(gUnboundedNegative, gUnboundedNegative, gUnboundedPositive, gUnboundedPositive);
+  aInner->SetBox(gUnboundedNegative, gUnboundedNegative, gUnboundedPositive, gUnboundedPositive);
 
   const nsPoint normalPosition = firstCont->GetNormalPosition();
 
   // Bottom and top
-  if (stick.YMost() != (nscoord_MAX + (nscoord_MIN/2))) {
-    aOuter->SetTopEdge(contain.y - stick.YMost());
+  if (stick.YMost() != gUnboundedPositive) {
+    aOuter->SetTopEdge(contain.Y() - stick.YMost());
     aInner->SetTopEdge(normalPosition.y - stick.YMost());
   }
 
-  if (stick.y != nscoord_MIN/2) {
-    aInner->SetBottomEdge(normalPosition.y - stick.y);
-    aOuter->SetBottomEdge(contain.YMost() - stick.y);
+  if (stick.Y() != gUnboundedNegative) {
+    aInner->SetBottomEdge(normalPosition.y - stick.Y());
+    aOuter->SetBottomEdge(contain.YMost() - stick.Y());
   }
 
   // Right and left
-  if (stick.XMost() != (nscoord_MAX + (nscoord_MIN/2))) {
-    aOuter->SetLeftEdge(contain.x - stick.XMost());
+  if (stick.XMost() != gUnboundedPositive) {
+    aOuter->SetLeftEdge(contain.X() - stick.XMost());
     aInner->SetLeftEdge(normalPosition.x - stick.XMost());
   }
 
-  if (stick.x != nscoord_MIN/2) {
-    aInner->SetRightEdge(normalPosition.x - stick.x);
-    aOuter->SetRightEdge(contain.XMost() - stick.x);
+  if (stick.X() != gUnboundedNegative) {
+    aInner->SetRightEdge(normalPosition.x - stick.X());
+    aOuter->SetRightEdge(contain.XMost() - stick.X());
   }
 
   // Make sure |inner| does not extend outside of |outer|. (The consumers of
   // the Layers API, to which this information is propagated, expect this
   // invariant to hold.) The calculated value of |inner| can sometimes extend
   // outside of |outer|, for example due to margin collapsing, since
   // GetNormalPosition() returns the actual position after margin collapsing,
   // while |contain| is calculated based on the frame's GetUsedMargin() which
--- a/layout/generic/StickyScrollContainer.h
+++ b/layout/generic/StickyScrollContainer.h
@@ -7,16 +7,17 @@
 /**
  * compute sticky positioning, both during reflow and when the scrolling
  * container scrolls
  */
 
 #ifndef StickyScrollContainer_h
 #define StickyScrollContainer_h
 
+#include "nsCoordBox.h"
 #include "nsPoint.h"
 #include "nsTArray.h"
 #include "nsIScrollPositionListener.h"
 
 struct nsRect;
 class nsIFrame;
 class nsIScrollableFrame;
 
@@ -62,17 +63,17 @@ public:
    * stored in its properties along with our scroll frame and scroll position.
    */
   nsPoint ComputePosition(nsIFrame* aFrame) const;
 
   /**
    * Compute where a frame should not scroll with the page, represented by the
    * difference of two rectangles.
    */
-  void GetScrollRanges(nsIFrame* aFrame, nsRect* aOuter, nsRect* aInner) const;
+  void GetScrollRanges(nsIFrame* aFrame, nsCoordBox* aOuter, nsCoordBox* aInner) const;
 
   /**
    * Compute and set the position of a frame and its following continuations.
    */
   void PositionContinuations(nsIFrame* aFrame);
 
   /**
    * Compute and set the position of all sticky frames, given the current
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -7479,34 +7479,34 @@ nsDisplayStickyPosition::BuildLayer(nsDi
   nsLayoutUtils::SetFixedPositionLayerData(layer, scrollFrame,
     nsRect(scrollFrame->GetOffsetToCrossDoc(ReferenceFrame()), scrollFrameSize),
     mFrame, presContext, aContainerParameters);
 
   ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(
     stickyScrollContainer->ScrollFrame()->GetScrolledFrame()->GetContent());
 
   float factor = presContext->AppUnitsPerDevPixel();
-  nsRect outer;
-  nsRect inner;
+  nsCoordBox outer;
+  nsCoordBox inner;
   stickyScrollContainer->GetScrollRanges(mFrame, &outer, &inner);
-  LayerRect stickyOuter(NSAppUnitsToFloatPixels(outer.x, factor) *
+  LayerBox stickyOuter(NSAppUnitsToFloatPixels(outer.X(), factor) *
                           aContainerParameters.mXScale,
-                        NSAppUnitsToFloatPixels(outer.y, factor) *
+                        NSAppUnitsToFloatPixels(outer.Y(), factor) *
                           aContainerParameters.mYScale,
-                        NSAppUnitsToFloatPixels(outer.width, factor) *
+                        NSAppUnitsToFloatPixels(outer.XMost(), factor) *
                           aContainerParameters.mXScale,
-                        NSAppUnitsToFloatPixels(outer.height, factor) *
+                        NSAppUnitsToFloatPixels(outer.YMost(), factor) *
                           aContainerParameters.mYScale);
-  LayerRect stickyInner(NSAppUnitsToFloatPixels(inner.x, factor) *
+  LayerBox stickyInner(NSAppUnitsToFloatPixels(inner.X(), factor) *
                           aContainerParameters.mXScale,
-                        NSAppUnitsToFloatPixels(inner.y, factor) *
+                        NSAppUnitsToFloatPixels(inner.Y(), factor) *
                           aContainerParameters.mYScale,
-                        NSAppUnitsToFloatPixels(inner.width, factor) *
+                        NSAppUnitsToFloatPixels(inner.XMost(), factor) *
                           aContainerParameters.mXScale,
-                        NSAppUnitsToFloatPixels(inner.height, factor) *
+                        NSAppUnitsToFloatPixels(inner.YMost(), factor) *
                           aContainerParameters.mYScale);
   layer->SetStickyPositionData(scrollId, stickyOuter, stickyInner);
 
   return layer.forget();
 }
 
 // Returns the smallest distance from "0" to the range [min, max] where
 // min <= max.
@@ -7556,18 +7556,18 @@ nsDisplayStickyPosition::CreateWebRender
     Maybe<float> topMargin;
     Maybe<float> rightMargin;
     Maybe<float> bottomMargin;
     Maybe<float> leftMargin;
     wr::StickyOffsetBounds vBounds = { 0.0, 0.0 };
     wr::StickyOffsetBounds hBounds = { 0.0, 0.0 };
     nsPoint appliedOffset;
 
-    nsRect outer;
-    nsRect inner;
+    nsCoordBox outer;
+    nsCoordBox inner;
     stickyScrollContainer->GetScrollRanges(mFrame, &outer, &inner);
 
     nsIFrame* scrollFrame = do_QueryFrame(stickyScrollContainer->ScrollFrame());
     nsPoint offset = scrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
 
     // Adjust the scrollPort coordinates to be relative to the reference frame,
     // so that it is in the same space as everything else.
     nsRect scrollPort = stickyScrollContainer->ScrollFrame()->GetScrollPortRect();
@@ -7609,48 +7609,48 @@ nsDisplayStickyPosition::CreateWebRender
       // then layout has already applied some offset to the position of the
       // item. The amount of the adjustment is |0 - inner.YMost()| in case (a)
       // and |outer.YMost() - inner.YMost()| in case (b).
       if (inner.YMost() < 0) {
         appliedOffset.y = std::min(0, outer.YMost()) - inner.YMost();
         MOZ_ASSERT(appliedOffset.y > 0);
       }
     }
-    if (outer.y != inner.y) {
+    if (outer.Y() != inner.Y()) {
       // Similar logic as in the previous section, but this time we care about
       // the distance from itemBounds.YMost() to scrollPort.YMost().
-      nscoord distance = DistanceToRange(outer.y, inner.y);
+      nscoord distance = DistanceToRange(outer.Y(), inner.Y());
       bottomMargin = Some(NSAppUnitsToFloatPixels(scrollPort.YMost() - itemBounds.YMost() + distance, auPerDevPixel));
       // And here WR will be moving the item upwards rather than downwards so
       // again things are inverted from the previous block.
-      vBounds.min = NSAppUnitsToFloatPixels(outer.y - inner.y, auPerDevPixel);
+      vBounds.min = NSAppUnitsToFloatPixels(outer.Y() - inner.Y(), auPerDevPixel);
       // We can't have appliedOffset be both positive and negative, and the top
       // adjustment takes priority. So here we only update appliedOffset.y if
       // it wasn't set by the top-sticky case above.
-      if (appliedOffset.y == 0 && inner.y > 0) {
-        appliedOffset.y = std::max(0, outer.y) - inner.y;
+      if (appliedOffset.y == 0 && inner.Y() > 0) {
+        appliedOffset.y = std::max(0, outer.Y()) - inner.Y();
         MOZ_ASSERT(appliedOffset.y < 0);
       }
     }
     // Same as above, but for the x-axis
     if (outer.XMost() != inner.XMost()) {
       nscoord distance = DistanceToRange(inner.XMost(), outer.XMost());
       leftMargin = Some(NSAppUnitsToFloatPixels(itemBounds.x - scrollPort.x - distance, auPerDevPixel));
       hBounds.max = NSAppUnitsToFloatPixels(outer.XMost() - inner.XMost(), auPerDevPixel);
       if (inner.XMost() < 0) {
         appliedOffset.x = std::min(0, outer.XMost()) - inner.XMost();
         MOZ_ASSERT(appliedOffset.x > 0);
       }
     }
-    if (outer.x != inner.x) {
-      nscoord distance = DistanceToRange(outer.x, inner.x);
+    if (outer.X() != inner.X()) {
+      nscoord distance = DistanceToRange(outer.X(), inner.X());
       rightMargin = Some(NSAppUnitsToFloatPixels(scrollPort.XMost() - itemBounds.XMost() + distance, auPerDevPixel));
-      hBounds.min = NSAppUnitsToFloatPixels(outer.x - inner.x, auPerDevPixel);
-      if (appliedOffset.x == 0 && inner.x > 0) {
-        appliedOffset.x = std::max(0, outer.x) - inner.x;
+      hBounds.min = NSAppUnitsToFloatPixels(outer.X() - inner.X(), auPerDevPixel);
+      if (appliedOffset.x == 0 && inner.X() > 0) {
+        appliedOffset.x = std::max(0, outer.X()) - inner.X();
         MOZ_ASSERT(appliedOffset.x < 0);
       }
     }
 
     LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(itemBounds, auPerDevPixel);
     wr::LayoutVector2D applied = {
       NSAppUnitsToFloatPixels(appliedOffset.x, auPerDevPixel),
       NSAppUnitsToFloatPixels(appliedOffset.y, auPerDevPixel)