Bug 1219296 - Factor out scroll snap information into a form that's usable by the compositor. r=kats

MozReview-Commit-ID: DTvu7UsKsBg

--HG--
extra : rebase_source : 71831d884d128bc9e50aac55c7a8302f7ffe74f8
This commit is contained in:
Botond Ballo 2016-03-18 20:07:27 -04:00
parent a74ec8c79b
commit 4690842281
3 changed files with 116 additions and 30 deletions

View File

@ -16,6 +16,7 @@
#include "mozilla/gfx/Logging.h" // for Log
#include "mozilla/TimeStamp.h" // for TimeStamp
#include "nsString.h"
#include "nsStyleCoord.h" // for nsStyleCoord
namespace IPC {
template <typename T> struct ParamTraits;
@ -751,6 +752,29 @@ private:
}
};
struct ScrollSnapInfo {
ScrollSnapInfo()
: mScrollSnapTypeX(NS_STYLE_SCROLL_SNAP_TYPE_NONE)
, mScrollSnapTypeY(NS_STYLE_SCROLL_SNAP_TYPE_NONE)
{}
// The scroll frame's scroll-snap-type.
// One of NS_STYLE_SCROLL_SNAP_{NONE, MANDATORY, PROXIMITY}.
uint8_t mScrollSnapTypeX;
uint8_t mScrollSnapTypeY;
// The intervals derived from the scroll frame's scroll-snap-points.
Maybe<nscoord> mScrollSnapIntervalX;
Maybe<nscoord> mScrollSnapIntervalY;
// The scroll frame's scroll-snap-destination, in cooked form (to avoid
// shipping the raw nsStyleCoord::CalcValue over IPC).
nsPoint mScrollSnapDestination;
// The scroll-snap-coordinates of any descendant frames of the scroll frame,
// relative to the origin of the scrolled frame.
nsTArray<nsPoint> mScrollSnapCoordinates;
};
/**
* Metadata about a scroll frame that's stored in the layer tree for use by

View File

@ -6010,9 +6010,26 @@ CalcSnapPoints::AddEdgeInterval(nscoord aInterval, nscoord aMinPos,
}
static void
ScrollSnapHelper(SnappingEdgeCallback& aCallback, nsIFrame* aFrame,
nsIFrame* aScrolledFrame,
const nsPoint &aScrollSnapDestination) {
ProcessScrollSnapCoordinates(SnappingEdgeCallback& aCallback,
const nsTArray<nsPoint>& aScrollSnapCoordinates,
const nsPoint& aScrollSnapDestination) {
for (nsPoint snapCoords : aScrollSnapCoordinates) {
// Make them relative to the scroll snap destination.
snapCoords -= aScrollSnapDestination;
aCallback.AddVerticalEdge(snapCoords.x);
aCallback.AddHorizontalEdge(snapCoords.y);
}
}
/**
* Collect the scroll-snap-coordinates of frames in the subtree rooted at
* |aFrame|, relative to |aScrolledFrame|, into |aOutCoords|.
*/
void
CollectScrollSnapCoordinates(nsIFrame* aFrame, nsIFrame* aScrolledFrame,
nsTArray<nsPoint>& aOutCoords)
{
nsIFrame::ChildListIterator childLists(aFrame);
for (; !childLists.IsDone(); childLists.Next()) {
nsFrameList::Enumerator childFrames(childLists.CurrentList());
@ -6029,7 +6046,7 @@ ScrollSnapHelper(SnappingEdgeCallback& aCallback, nsIFrame* aFrame,
for (size_t coordNum = 0; coordNum < coordCount; coordNum++) {
const nsStyleImageLayers::Position &coordPosition =
f->StyleDisplay()->mScrollSnapCoordinate[coordNum];
nsPoint coordPoint = edgesRect.TopLeft() - aScrollSnapDestination;
nsPoint coordPoint = edgesRect.TopLeft();
coordPoint += nsPoint(coordPosition.mXPosition.mLength,
coordPosition.mYPosition.mLength);
if (coordPosition.mXPosition.mHasPercent) {
@ -6041,68 +6058,110 @@ ScrollSnapHelper(SnappingEdgeCallback& aCallback, nsIFrame* aFrame,
frameRect.height);
}
aCallback.AddVerticalEdge(coordPoint.x);
aCallback.AddHorizontalEdge(coordPoint.y);
aOutCoords.AppendElement(coordPoint);
}
}
ScrollSnapHelper(aCallback, f, aScrolledFrame, aScrollSnapDestination);
CollectScrollSnapCoordinates(f, aScrolledFrame, aOutCoords);
}
}
}
layers::ScrollSnapInfo
ComputeScrollSnapInfo(const ScrollFrameHelper& aScrollFrame)
{
ScrollSnapInfo result;
ScrollbarStyles styles = aScrollFrame.GetScrollbarStylesFromFrame();
if (styles.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_NONE &&
styles.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_NONE) {
// We won't be snapping, short-circuit the computation.
return result;
}
result.mScrollSnapTypeX = styles.mScrollSnapTypeX;
result.mScrollSnapTypeY = styles.mScrollSnapTypeY;
nsSize scrollPortSize = aScrollFrame.GetScrollPortRect().Size();
result.mScrollSnapDestination = nsPoint(styles.mScrollSnapDestinationX.mLength,
styles.mScrollSnapDestinationY.mLength);
if (styles.mScrollSnapDestinationX.mHasPercent) {
result.mScrollSnapDestination.x +=
NSToCoordFloorClamped(styles.mScrollSnapDestinationX.mPercent *
scrollPortSize.width);
}
if (styles.mScrollSnapDestinationY.mHasPercent) {
result.mScrollSnapDestination.y +=
NSToCoordFloorClamped(styles.mScrollSnapDestinationY.mPercent *
scrollPortSize.height);
}
if (styles.mScrollSnapPointsX.GetUnit() != eStyleUnit_None) {
result.mScrollSnapIntervalX = Some(nsRuleNode::ComputeCoordPercentCalc(
styles.mScrollSnapPointsX, scrollPortSize.width));
}
if (styles.mScrollSnapPointsY.GetUnit() != eStyleUnit_None) {
result.mScrollSnapIntervalY = Some(nsRuleNode::ComputeCoordPercentCalc(
styles.mScrollSnapPointsY, scrollPortSize.height));
}
CollectScrollSnapCoordinates(aScrollFrame.GetScrolledFrame(),
aScrollFrame.GetScrolledFrame(),
result.mScrollSnapCoordinates);
return result;
}
layers::ScrollSnapInfo
ScrollFrameHelper::GetScrollSnapInfo() const
{
// TODO(botond): Should we cache it?
return ComputeScrollSnapInfo(*this);
}
bool
ScrollFrameHelper::GetSnapPointForDestination(nsIScrollableFrame::ScrollUnit aUnit,
nsPoint aStartPos,
nsPoint &aDestination)
{
ScrollbarStyles styles = GetScrollbarStylesFromFrame();
if (styles.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_NONE &&
styles.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_NONE) {
ScrollSnapInfo snapInfo = GetScrollSnapInfo();
if (snapInfo.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_NONE &&
snapInfo.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_NONE) {
return false;
}
nsSize scrollPortSize = mScrollPort.Size();
nsRect scrollRange = GetScrollRangeForClamping();
nsPoint destPos = nsPoint(styles.mScrollSnapDestinationX.mLength,
styles.mScrollSnapDestinationY.mLength);
if (styles.mScrollSnapDestinationX.mHasPercent) {
destPos.x += NSToCoordFloorClamped(styles.mScrollSnapDestinationX.mPercent
* scrollPortSize.width);
}
if (styles.mScrollSnapDestinationY.mHasPercent) {
destPos.y += NSToCoordFloorClamped(styles.mScrollSnapDestinationY.mPercent
* scrollPortSize.height);
}
nsPoint destPos = snapInfo.mScrollSnapDestination;
CalcSnapPoints calcSnapPoints(aUnit, aDestination, aStartPos);
if (styles.mScrollSnapPointsX.GetUnit() != eStyleUnit_None) {
nscoord interval = nsRuleNode::ComputeCoordPercentCalc(styles.mScrollSnapPointsX,
scrollPortSize.width);
if (snapInfo.mScrollSnapIntervalX.isSome()) {
nscoord interval = snapInfo.mScrollSnapIntervalX.value();
calcSnapPoints.AddVerticalEdgeInterval(scrollRange, interval, destPos.x);
}
if (styles.mScrollSnapPointsY.GetUnit() != eStyleUnit_None) {
nscoord interval = nsRuleNode::ComputeCoordPercentCalc(styles.mScrollSnapPointsY,
scrollPortSize.height);
if (snapInfo.mScrollSnapIntervalY.isSome()) {
nscoord interval = snapInfo.mScrollSnapIntervalY.value();
calcSnapPoints.AddHorizontalEdgeInterval(scrollRange, interval, destPos.y);
}
ScrollSnapHelper(calcSnapPoints, mScrolledFrame, mScrolledFrame, destPos);
ProcessScrollSnapCoordinates(calcSnapPoints, snapInfo.mScrollSnapCoordinates, destPos);
bool snapped = false;
nsPoint finalPos = calcSnapPoints.GetBestEdge();
nscoord proximityThreshold =
Preferences::GetInt("layout.css.scroll-snap.proximity-threshold", 0);
proximityThreshold = nsPresContext::CSSPixelsToAppUnits(proximityThreshold);
if (styles.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY &&
if (snapInfo.mScrollSnapTypeY == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY &&
std::abs(aDestination.y - finalPos.y) > proximityThreshold) {
finalPos.y = aDestination.y;
} else {
snapped = true;
}
if (styles.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY &&
if (snapInfo.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY &&
std::abs(aDestination.x - finalPos.x) > proximityThreshold) {
finalPos.x = aDestination.x;
} else {

View File

@ -49,6 +49,7 @@ public:
typedef mozilla::CSSIntPoint CSSIntPoint;
typedef mozilla::layout::ScrollbarActivity ScrollbarActivity;
typedef mozilla::layers::FrameMetrics FrameMetrics;
typedef mozilla::layers::ScrollSnapInfo ScrollSnapInfo;
typedef mozilla::layers::Layer Layer;
class AsyncScroll;
@ -390,6 +391,8 @@ public:
bool UsesContainerScrolling() const;
ScrollSnapInfo GetScrollSnapInfo() const;
bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
nsRect* aDirtyRect,
bool aAllowCreateDisplayPort);