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
--- 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)