зеркало из https://github.com/mozilla/gecko-dev.git
Bug 945584: Part 6 - Implementation of scroll snapping (v10 Patch), r=roc, r=kats
- Implemented CSS scroll snapping (http://dev.w3.org/csswg/css-snappoints/) --HG-- extra : rebase_source : e100b6a2cbc00321d6d1083d12a99213e34d5f9d
This commit is contained in:
Родитель
467260920d
Коммит
8d1fcc4892
|
@ -2417,13 +2417,16 @@ EventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
|
|||
actualDevPixelScrollAmount.y = 0;
|
||||
}
|
||||
|
||||
nsIScrollableFrame::ScrollSnapMode snapMode = nsIScrollableFrame::DISABLE_SNAP;
|
||||
nsIAtom* origin = nullptr;
|
||||
switch (aEvent->deltaMode) {
|
||||
case nsIDOMWheelEvent::DOM_DELTA_LINE:
|
||||
origin = nsGkAtoms::mouseWheel;
|
||||
snapMode = nsIScrollableFrame::ENABLE_SNAP;
|
||||
break;
|
||||
case nsIDOMWheelEvent::DOM_DELTA_PAGE:
|
||||
origin = nsGkAtoms::pages;
|
||||
snapMode = nsIScrollableFrame::ENABLE_SNAP;
|
||||
break;
|
||||
case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
|
||||
origin = nsGkAtoms::pixels;
|
||||
|
@ -2483,7 +2486,7 @@ EventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
|
|||
nsIntPoint overflow;
|
||||
aScrollableFrame->ScrollBy(actualDevPixelScrollAmount,
|
||||
nsIScrollableFrame::DEVICE_PIXELS,
|
||||
mode, &overflow, origin, momentum);
|
||||
mode, &overflow, origin, momentum, snapMode);
|
||||
|
||||
if (!scrollFrameWeak.IsAlive()) {
|
||||
// If the scroll causes changing the layout, we can think that the event
|
||||
|
@ -2984,6 +2987,13 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
|||
{
|
||||
MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
|
||||
ScrollbarsForWheel::MayInactivate();
|
||||
WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
|
||||
nsIScrollableFrame* scrollTarget =
|
||||
ComputeScrollTarget(aTargetFrame, wheelEvent,
|
||||
COMPUTE_DEFAULT_ACTION_TARGET);
|
||||
if (scrollTarget) {
|
||||
scrollTarget->ScrollSnap();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_WHEEL_WHEEL:
|
||||
|
|
|
@ -513,6 +513,7 @@ child:
|
|||
// The following methods correspond to functions on the GeckoContentController
|
||||
// interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation
|
||||
// in that file for these functions.
|
||||
RequestFlingSnap(ViewID aScrollID, CSSPoint aDestination);
|
||||
AcknowledgeScrollUpdate(ViewID aScrollId, uint32_t aScrollGeneration);
|
||||
HandleDoubleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
|
||||
HandleSingleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
|
||||
|
|
|
@ -2036,6 +2036,14 @@ TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
|
|||
return TabChildBase::UpdateFrameHandler(aFrameMetrics);
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvRequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
APZCCallbackHelper::RequestFlingSnap(aScrollId, aDestination);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration)
|
||||
|
|
|
@ -319,6 +319,8 @@ public:
|
|||
const ScreenOrientation& orientation,
|
||||
const nsIntPoint& chromeDisp) MOZ_OVERRIDE;
|
||||
virtual bool RecvUpdateFrame(const layers::FrameMetrics& aFrameMetrics) MOZ_OVERRIDE;
|
||||
virtual bool RecvRequestFlingSnap(const ViewID& aScrollId,
|
||||
const CSSPoint& aDestination) MOZ_OVERRIDE;
|
||||
virtual bool RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) MOZ_OVERRIDE;
|
||||
virtual bool RecvHandleDoubleTap(const CSSPoint& aPoint,
|
||||
|
|
|
@ -922,6 +922,15 @@ TabParent::UIResolutionChanged()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
if (!mIsDestroyed) {
|
||||
unused << SendRequestFlingSnap(aScrollId, aDestination);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::AcknowledgeScrollUpdate(const ViewID& aScrollId, const uint32_t& aScrollGeneration)
|
||||
{
|
||||
|
|
|
@ -245,6 +245,8 @@ public:
|
|||
const nsIntPoint& chromeDisp);
|
||||
void UpdateFrame(const layers::FrameMetrics& aFrameMetrics);
|
||||
void UIResolutionChanged();
|
||||
void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination);
|
||||
void AcknowledgeScrollUpdate(const ViewID& aScrollId, const uint32_t& aScrollGeneration);
|
||||
void HandleDoubleTap(const CSSPoint& aPoint,
|
||||
Modifiers aModifiers,
|
||||
|
|
|
@ -30,6 +30,14 @@ public:
|
|||
*/
|
||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
|
||||
|
||||
/**
|
||||
* Requests handling of a scroll snapping at the end of a fling gesture for
|
||||
* the scrollable frame with the given scroll id. aDestination specifies the
|
||||
* expected landing position of the fling if no snapping were to be performed.
|
||||
*/
|
||||
virtual void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination) = 0;
|
||||
|
||||
/**
|
||||
* Acknowledges the recipt of a scroll offset update for the scrollable
|
||||
* frame with the given scroll id. This is used to maintain consistency
|
||||
|
|
|
@ -1980,9 +1980,37 @@ void AsyncPanZoomController::AcceptFling(const ParentLayerPoint& aVelocity,
|
|||
mX.SetVelocity(mX.GetVelocity() + aVelocity.x);
|
||||
mY.SetVelocity(mY.GetVelocity() + aVelocity.y);
|
||||
SetState(FLING);
|
||||
StartAnimation(new FlingAnimation(*this,
|
||||
FlingAnimation *fling = new FlingAnimation(*this,
|
||||
aOverscrollHandoffChain,
|
||||
!aHandoff)); // only apply acceleration if this is an initial fling
|
||||
!aHandoff); // only apply acceleration if this is an initial fling
|
||||
|
||||
float friction = gfxPrefs::APZFlingFriction();
|
||||
ParentLayerPoint velocity(mX.GetVelocity(), mY.GetVelocity());
|
||||
ParentLayerPoint predictedDelta;
|
||||
// "-velocity / log(1.0 - friction)" is the integral of the deceleration
|
||||
// curve modeled for flings in the "Axis" class.
|
||||
if (velocity.x != 0.0f) {
|
||||
predictedDelta.x = -velocity.x / log(1.0 - friction);
|
||||
}
|
||||
if (velocity.y != 0.0f) {
|
||||
predictedDelta.y = -velocity.y / log(1.0 - friction);
|
||||
}
|
||||
CSSPoint predictedDestination = mFrameMetrics.GetScrollOffset() + predictedDelta / mFrameMetrics.GetZoom();
|
||||
|
||||
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
APZC_LOG("%p fling snapping. friction: %f velocity: %f, %f "
|
||||
"predictedDelta: %f, %f position: %f, %f "
|
||||
"predictedDestination: %f, %f\n",
|
||||
this, friction, velocity.x, velocity.y, (float)predictedDelta.x,
|
||||
(float)predictedDelta.y, (float)mFrameMetrics.GetScrollOffset().x,
|
||||
(float)mFrameMetrics.GetScrollOffset().y,
|
||||
(float)predictedDestination.x, (float)predictedDestination.y);
|
||||
controller->RequestFlingSnap(mFrameMetrics.GetScrollId(),
|
||||
predictedDestination);
|
||||
}
|
||||
|
||||
StartAnimation(fling);
|
||||
}
|
||||
|
||||
bool AsyncPanZoomController::AttemptFling(ParentLayerPoint aVelocity,
|
||||
|
|
|
@ -264,6 +264,46 @@ APZCCallbackHelper::GetOrCreateScrollIdentifiers(nsIContent* aContent,
|
|||
return utils && (utils->GetPresShellId(aPresShellIdOut) == NS_OK);
|
||||
}
|
||||
|
||||
class FlingSnapEvent : public nsRunnable
|
||||
{
|
||||
typedef mozilla::layers::FrameMetrics::ViewID ViewID;
|
||||
|
||||
public:
|
||||
FlingSnapEvent(const ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
: mScrollId(aScrollId)
|
||||
, mDestination(aDestination)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(mScrollId);
|
||||
if (sf) {
|
||||
sf->FlingSnap(mDestination);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
ViewID mScrollId;
|
||||
mozilla::CSSPoint mDestination;
|
||||
};
|
||||
|
||||
void
|
||||
APZCCallbackHelper::RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r1 = new FlingSnapEvent(aScrollId, aDestination);
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(r1);
|
||||
} else {
|
||||
r1->Run();
|
||||
}
|
||||
}
|
||||
|
||||
class AcknowledgeScrollUpdateEvent : public nsRunnable
|
||||
{
|
||||
typedef mozilla::layers::FrameMetrics::ViewID ViewID;
|
||||
|
|
|
@ -81,6 +81,14 @@ public:
|
|||
uint32_t* aPresShellIdOut,
|
||||
FrameMetrics::ViewID* aViewIdOut);
|
||||
|
||||
/* Tell layout to perform scroll snapping for the scrollable frame with the
|
||||
* given scroll id. aDestination specifies the expected landing position of
|
||||
* a current fling or scrolling animation that should be used to select
|
||||
* the scroll snap point.
|
||||
*/
|
||||
static void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination);
|
||||
|
||||
/* Tell layout that we received the scroll offset update for the given view ID, so
|
||||
that it accepts future scroll offset updates from APZ. */
|
||||
static void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
|
|
|
@ -80,6 +80,13 @@ ChromeProcessController::PostDelayedTask(Task* aTask, int aDelayMs)
|
|||
MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
|
||||
}
|
||||
|
||||
void
|
||||
ChromeProcessController::RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
APZCCallbackHelper::RequestFlingSnap(aScrollId, aDestination);
|
||||
}
|
||||
|
||||
void
|
||||
ChromeProcessController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration)
|
||||
|
|
|
@ -37,6 +37,8 @@ public:
|
|||
// GeckoContentController interface
|
||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) MOZ_OVERRIDE;
|
||||
virtual void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE;
|
||||
virtual void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination) MOZ_OVERRIDE;
|
||||
virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ private:
|
|||
class MockContentController : public GeckoContentController {
|
||||
public:
|
||||
MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
|
||||
MOCK_METHOD2(RequestFlingSnap, void(const FrameMetrics::ViewID& aScrollId, const mozilla::CSSPoint& aDestination));
|
||||
MOCK_METHOD2(AcknowledgeScrollUpdate, void(const FrameMetrics::ViewID&, const uint32_t& aScrollGeneration));
|
||||
MOCK_METHOD3(HandleDoubleTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&));
|
||||
MOCK_METHOD3(HandleSingleTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&));
|
||||
|
|
|
@ -2392,7 +2392,8 @@ PresShell::ScrollPage(bool aForward)
|
|||
nsIScrollableFrame::PAGES,
|
||||
nsIScrollableFrame::SMOOTH,
|
||||
nullptr, nullptr,
|
||||
nsIScrollableFrame::NOT_MOMENTUM);
|
||||
nsIScrollableFrame::NOT_MOMENTUM,
|
||||
nsIScrollableFrame::ENABLE_SNAP);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2409,7 +2410,8 @@ PresShell::ScrollLine(bool aForward)
|
|||
nsIScrollableFrame::LINES,
|
||||
nsIScrollableFrame::SMOOTH,
|
||||
nullptr, nullptr,
|
||||
nsIScrollableFrame::NOT_MOMENTUM);
|
||||
nsIScrollableFrame::NOT_MOMENTUM,
|
||||
nsIScrollableFrame::ENABLE_SNAP);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2426,7 +2428,8 @@ PresShell::ScrollCharacter(bool aRight)
|
|||
nsIScrollableFrame::LINES,
|
||||
nsIScrollableFrame::SMOOTH,
|
||||
nullptr, nullptr,
|
||||
nsIScrollableFrame::NOT_MOMENTUM);
|
||||
nsIScrollableFrame::NOT_MOMENTUM,
|
||||
nsIScrollableFrame::ENABLE_SNAP);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2441,7 +2444,8 @@ PresShell::CompleteScroll(bool aForward)
|
|||
nsIScrollableFrame::WHOLE,
|
||||
nsIScrollableFrame::SMOOTH,
|
||||
nullptr, nullptr,
|
||||
nsIScrollableFrame::NOT_MOMENTUM);
|
||||
nsIScrollableFrame::NOT_MOMENTUM,
|
||||
nsIScrollableFrame::ENABLE_SNAP);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -1899,6 +1899,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter,
|
|||
, mIgnoreMomentumScroll(false)
|
||||
, mScaleToResolution(false)
|
||||
, mTransformingByAPZ(false)
|
||||
, mVelocityQueue(aOuter->PresContext())
|
||||
{
|
||||
if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
|
||||
mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter));
|
||||
|
@ -2069,8 +2070,16 @@ void
|
|||
ScrollFrameHelper::ScrollToWithOrigin(nsPoint aScrollPosition,
|
||||
nsIScrollableFrame::ScrollMode aMode,
|
||||
nsIAtom *aOrigin,
|
||||
const nsRect* aRange)
|
||||
const nsRect* aRange,
|
||||
nsIScrollableFrame::ScrollSnapMode aSnap)
|
||||
{
|
||||
|
||||
if (aSnap == nsIScrollableFrame::ENABLE_SNAP) {
|
||||
GetSnapPointForDestination(nsIScrollableFrame::DEVICE_PIXELS,
|
||||
mDestination,
|
||||
aScrollPosition);
|
||||
}
|
||||
|
||||
nsRect scrollRange = GetScrollRangeForClamping();
|
||||
mDestination = scrollRange.ClampPoint(aScrollPosition);
|
||||
|
||||
|
@ -2094,6 +2103,9 @@ ScrollFrameHelper::ScrollToWithOrigin(nsPoint aScrollPosition,
|
|||
if (aMode == nsIScrollableFrame::SMOOTH_MSD) {
|
||||
mIgnoreMomentumScroll = true;
|
||||
if (!mAsyncSmoothMSDScroll) {
|
||||
nsPoint sv = mVelocityQueue.GetVelocity();
|
||||
currentVelocity.width = sv.x;
|
||||
currentVelocity.height = sv.y;
|
||||
if (mAsyncScroll) {
|
||||
if (mAsyncScroll->mIsSmoothScroll) {
|
||||
currentVelocity = mAsyncScroll->VelocityAt(now);
|
||||
|
@ -3327,7 +3339,8 @@ ScrollFrameHelper::ScrollBy(nsIntPoint aDelta,
|
|||
nsIScrollableFrame::ScrollMode aMode,
|
||||
nsIntPoint* aOverflow,
|
||||
nsIAtom *aOrigin,
|
||||
nsIScrollableFrame::ScrollMomentum aMomentum)
|
||||
nsIScrollableFrame::ScrollMomentum aMomentum,
|
||||
nsIScrollableFrame::ScrollSnapMode aSnap)
|
||||
{
|
||||
// When a smooth scroll is being processed on a frame, mouse wheel and trackpad
|
||||
// momentum scroll event updates must notcancel the SMOOTH or SMOOTH_MSD
|
||||
|
@ -3390,6 +3403,9 @@ ScrollFrameHelper::ScrollBy(nsIntPoint aDelta,
|
|||
nsPoint pos = GetScrollPosition();
|
||||
AdjustForWholeDelta(aDelta.x, &pos.x);
|
||||
AdjustForWholeDelta(aDelta.y, &pos.y);
|
||||
if (aSnap == nsIScrollableFrame::ENABLE_SNAP) {
|
||||
GetSnapPointForDestination(aUnit, mDestination, pos);
|
||||
}
|
||||
ScrollTo(pos, aMode);
|
||||
// 'this' might be destroyed here
|
||||
if (aOverflow) {
|
||||
|
@ -3402,8 +3418,27 @@ ScrollFrameHelper::ScrollBy(nsIntPoint aDelta,
|
|||
return;
|
||||
}
|
||||
|
||||
nsPoint newPos = mDestination +
|
||||
nsPoint(aDelta.x*deltaMultiplier.width, aDelta.y*deltaMultiplier.height);
|
||||
nsPoint newPos = mDestination + nsPoint(aDelta.x*deltaMultiplier.width, aDelta.y*deltaMultiplier.height);
|
||||
|
||||
if (aSnap == nsIScrollableFrame::ENABLE_SNAP) {
|
||||
ScrollbarStyles styles = GetScrollbarStylesFromFrame();
|
||||
if (styles.mScrollSnapTypeY != NS_STYLE_SCROLL_SNAP_TYPE_NONE ||
|
||||
styles.mScrollSnapTypeX != NS_STYLE_SCROLL_SNAP_TYPE_NONE) {
|
||||
nscoord appUnitsPerDevPixel = mOuter->PresContext()->AppUnitsPerDevPixel();
|
||||
deltaMultiplier = nsSize(appUnitsPerDevPixel, appUnitsPerDevPixel);
|
||||
negativeTolerance = 0.1f;
|
||||
positiveTolerance = 0;
|
||||
nsIScrollableFrame::ScrollUnit snapUnit = aUnit;
|
||||
if (aOrigin == nsGkAtoms::mouseWheel) {
|
||||
// When using a clicky scroll wheel, snap point selection works the same
|
||||
// as keyboard up/down/left/right navigation, but with varying amounts
|
||||
// of scroll delta.
|
||||
snapUnit = nsIScrollableFrame::LINES;
|
||||
}
|
||||
GetSnapPointForDestination(snapUnit, mDestination, newPos);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate desired range values.
|
||||
nscoord rangeLowerX, rangeUpperX, rangeLowerY, rangeUpperY;
|
||||
CalcRangeForScrollBy(aDelta.x, newPos.x, negativeTolerance, positiveTolerance,
|
||||
|
@ -3427,6 +3462,49 @@ ScrollFrameHelper::ScrollBy(nsIntPoint aDelta,
|
|||
NSAppUnitsToIntPixels(clampAmount.x, appUnitsPerDevPixel),
|
||||
NSAppUnitsToIntPixels(clampAmount.y, appUnitsPerDevPixel));
|
||||
}
|
||||
|
||||
if (aUnit == nsIScrollableFrame::DEVICE_PIXELS &&
|
||||
!gfxPrefs::AsyncPanZoomEnabled()) {
|
||||
// When APZ is disabled, we must track the velocity
|
||||
// on the main thread; otherwise, the APZC will manage this.
|
||||
mVelocityQueue.Sample(GetScrollPosition());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ScrollFrameHelper::ScrollSnap()
|
||||
{
|
||||
float flingSensitivity = gfxPrefs::ScrollSnapPredictionSensitivity();
|
||||
int maxVelocity = gfxPrefs::ScrollSnapPredictionMaxVelocity();
|
||||
maxVelocity = nsPresContext::CSSPixelsToAppUnits(maxVelocity);
|
||||
int maxOffset = maxVelocity * flingSensitivity;
|
||||
nsPoint velocity = mVelocityQueue.GetVelocity();
|
||||
// Multiply each component individually to avoid integer multiply
|
||||
nsPoint predictedOffset = nsPoint(velocity.x * flingSensitivity,
|
||||
velocity.y * flingSensitivity);
|
||||
predictedOffset.Clamp(maxOffset);
|
||||
nsPoint pos = GetScrollPosition();
|
||||
nsPoint destinationPos = pos + predictedOffset;
|
||||
ScrollSnap(destinationPos);
|
||||
}
|
||||
|
||||
void
|
||||
ScrollFrameHelper::FlingSnap(const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
ScrollSnap(CSSPoint::ToAppUnits(aDestination));
|
||||
}
|
||||
|
||||
void
|
||||
ScrollFrameHelper::ScrollSnap(const nsPoint &aDestination)
|
||||
{
|
||||
nsRect scrollRange = GetScrollRangeForClamping();
|
||||
nsPoint pos = GetScrollPosition();
|
||||
nsPoint snapDestination = scrollRange.ClampPoint(aDestination);
|
||||
if (GetSnapPointForDestination(nsIScrollableFrame::DEVICE_PIXELS,
|
||||
pos,
|
||||
snapDestination)) {
|
||||
ScrollTo(snapDestination, nsIScrollableFrame::SMOOTH_MSD);
|
||||
}
|
||||
}
|
||||
|
||||
nsSize
|
||||
|
@ -5196,3 +5274,343 @@ nsIScrollableFrame::GetPerceivedScrollingDirections() const
|
|||
}
|
||||
return directions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores candidate snapping edges.
|
||||
*/
|
||||
class SnappingEdgeCallback {
|
||||
public:
|
||||
virtual void AddHorizontalEdge(nscoord aEdge) = 0;
|
||||
virtual void AddVerticalEdge(nscoord aEdge) = 0;
|
||||
virtual void AddHorizontalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval,
|
||||
nscoord aOffset) = 0;
|
||||
virtual void AddVerticalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval,
|
||||
nscoord aOffset) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Keeps track of the current best edge to snap to. The criteria for
|
||||
* adding an edge depends on the scrolling unit.
|
||||
*/
|
||||
class CalcSnapPoints : public SnappingEdgeCallback {
|
||||
public:
|
||||
CalcSnapPoints(nsIScrollableFrame::ScrollUnit aUnit,
|
||||
const nsPoint& aDestination,
|
||||
const nsPoint& aStartPos);
|
||||
virtual void AddHorizontalEdge(nscoord aEdge) MOZ_OVERRIDE;
|
||||
virtual void AddVerticalEdge(nscoord aEdge) MOZ_OVERRIDE;
|
||||
virtual void AddHorizontalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
MOZ_OVERRIDE;
|
||||
virtual void AddVerticalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
MOZ_OVERRIDE;
|
||||
void AddEdge(nscoord aEdge,
|
||||
nscoord aDestination,
|
||||
nscoord aStartPos,
|
||||
nscoord aScrollingDirection,
|
||||
nscoord* aBestEdge,
|
||||
bool* aEdgeFound);
|
||||
void AddEdgeInterval(nscoord aInterval,
|
||||
nscoord aMinPos,
|
||||
nscoord aMaxPos,
|
||||
nscoord aOffset,
|
||||
nscoord aDestination,
|
||||
nscoord aStartPos,
|
||||
nscoord aScrollingDirection,
|
||||
nscoord* aBestEdge,
|
||||
bool* aEdgeFound);
|
||||
nsPoint GetBestEdge() const;
|
||||
protected:
|
||||
nsIScrollableFrame::ScrollUnit mUnit;
|
||||
nsPoint mDestination; // gives the position after scrolling but before snapping
|
||||
nsPoint mStartPos; // gives the position before scrolling
|
||||
nsIntPoint mScrollingDirection; // always -1, 0, or 1
|
||||
nsPoint mBestEdge; // keeps track of the position of the current best edge
|
||||
bool mHorizontalEdgeFound; // true if mBestEdge.x is storing a valid horizontal edge
|
||||
bool mVerticalEdgeFound; // true if mBestEdge.y is storing a valid vertical edge
|
||||
};
|
||||
|
||||
CalcSnapPoints::CalcSnapPoints(nsIScrollableFrame::ScrollUnit aUnit,
|
||||
const nsPoint& aDestination,
|
||||
const nsPoint& aStartPos)
|
||||
{
|
||||
mUnit = aUnit;
|
||||
mDestination = aDestination;
|
||||
mStartPos = aStartPos;
|
||||
|
||||
nsPoint direction = aDestination - aStartPos;
|
||||
mScrollingDirection = nsIntPoint(0,0);
|
||||
if (direction.x < 0) {
|
||||
mScrollingDirection.x = -1;
|
||||
}
|
||||
if (direction.x > 0) {
|
||||
mScrollingDirection.x = 1;
|
||||
}
|
||||
if (direction.y < 0) {
|
||||
mScrollingDirection.y = -1;
|
||||
}
|
||||
if (direction.y > 0) {
|
||||
mScrollingDirection.y = 1;
|
||||
}
|
||||
mBestEdge = aDestination;
|
||||
mHorizontalEdgeFound = false;
|
||||
mVerticalEdgeFound = false;
|
||||
}
|
||||
|
||||
nsPoint
|
||||
CalcSnapPoints::GetBestEdge() const
|
||||
{
|
||||
return nsPoint(mVerticalEdgeFound ? mBestEdge.x : mStartPos.x,
|
||||
mHorizontalEdgeFound ? mBestEdge.y : mStartPos.y);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddHorizontalEdge(nscoord aEdge)
|
||||
{
|
||||
AddEdge(aEdge, mDestination.y, mStartPos.y, mScrollingDirection.y, &mBestEdge.y,
|
||||
&mHorizontalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddVerticalEdge(nscoord aEdge)
|
||||
{
|
||||
AddEdge(aEdge, mDestination.x, mStartPos.x, mScrollingDirection.x, &mBestEdge.x,
|
||||
&mVerticalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddHorizontalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
{
|
||||
AddEdgeInterval(aInterval, aScrollRange.y, aScrollRange.YMost(), aOffset,
|
||||
mDestination.y, mStartPos.y, mScrollingDirection.y,
|
||||
&mBestEdge.y, &mHorizontalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddVerticalEdgeInterval(const nsRect &aScrollRange,
|
||||
nscoord aInterval, nscoord aOffset)
|
||||
{
|
||||
AddEdgeInterval(aInterval, aScrollRange.x, aScrollRange.XMost(), aOffset,
|
||||
mDestination.x, mStartPos.x, mScrollingDirection.x,
|
||||
&mBestEdge.x, &mVerticalEdgeFound);
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination, nscoord aStartPos,
|
||||
nscoord aScrollingDirection, nscoord* aBestEdge,
|
||||
bool *aEdgeFound)
|
||||
{
|
||||
// nsIScrollableFrame::DEVICE_PIXELS indicates that we are releasing a drag
|
||||
// gesture or any other user input event that sets an absolute scroll
|
||||
// position. In this case, scroll snapping is expected to travel in any
|
||||
// direction. Otherwise, we will restrict the direction of the scroll
|
||||
// snapping movement based on aScrollingDirection.
|
||||
if (mUnit != nsIScrollableFrame::DEVICE_PIXELS) {
|
||||
// Unless DEVICE_PIXELS, we only want to snap to points ahead of the
|
||||
// direction we are scrolling
|
||||
if (aScrollingDirection == 0) {
|
||||
// The scroll direction is neutral - will not hit a snap point.
|
||||
return;
|
||||
}
|
||||
// nsIScrollableFrame::WHOLE indicates that we are navigating to "home" or
|
||||
// "end". In this case, we will always select the first or last snap point
|
||||
// regardless of the direction of the scroll. Otherwise, we will select
|
||||
// scroll snapping points only in the direction specified by
|
||||
// aScrollingDirection.
|
||||
if (mUnit != nsIScrollableFrame::WHOLE) {
|
||||
// Direction of the edge from the current position (before scrolling) in
|
||||
// the direction of scrolling
|
||||
nscoord direction = (aEdge - aStartPos) * aScrollingDirection;
|
||||
if (direction <= 0) {
|
||||
// The edge is not in the direction we are scrolling, skip it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!*aEdgeFound) {
|
||||
*aBestEdge = aEdge;
|
||||
*aEdgeFound = true;
|
||||
return;
|
||||
}
|
||||
if (mUnit == nsIScrollableFrame::DEVICE_PIXELS ||
|
||||
mUnit == nsIScrollableFrame::LINES) {
|
||||
if (std::abs(aEdge - aDestination) < std::abs(*aBestEdge - aDestination)) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
} else if (mUnit == nsIScrollableFrame::PAGES) {
|
||||
// distance to the edge from the scrolling destination in the direction of scrolling
|
||||
nscoord overshoot = (aEdge - aDestination) * aScrollingDirection;
|
||||
// distance to the current best edge from the scrolling destination in the direction of scrolling
|
||||
nscoord curOvershoot = (*aBestEdge - aDestination) * aScrollingDirection;
|
||||
|
||||
// edges between the current position and the scrolling destination are favoured
|
||||
// to preserve context
|
||||
if (overshoot < 0 && (overshoot > curOvershoot || curOvershoot >= 0)) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
// if there are no edges between the current position and the scrolling destination
|
||||
// the closest edge beyond the destination is used
|
||||
if (overshoot > 0 && overshoot < curOvershoot) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
} else if (mUnit == nsIScrollableFrame::WHOLE) {
|
||||
// the edge closest to the top/bottom/left/right is used, depending on scrolling direction
|
||||
if (aScrollingDirection > 0 && aEdge > *aBestEdge) {
|
||||
*aBestEdge = aEdge;
|
||||
} else if (aScrollingDirection < 0 && aEdge < *aBestEdge) {
|
||||
*aBestEdge = aEdge;
|
||||
}
|
||||
} else {
|
||||
NS_ERROR("Invalid scroll mode");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CalcSnapPoints::AddEdgeInterval(nscoord aInterval, nscoord aMinPos,
|
||||
nscoord aMaxPos, nscoord aOffset,
|
||||
nscoord aDestination, nscoord aStartPos,
|
||||
nscoord aScrollingDirection,
|
||||
nscoord* aBestEdge, bool *aEdgeFound)
|
||||
{
|
||||
if (aInterval == 0) {
|
||||
// When interval is 0, there are no scroll snap points.
|
||||
// Avoid division by zero and bail.
|
||||
return;
|
||||
}
|
||||
|
||||
// The only possible candidate interval snap points are the edges immediately
|
||||
// surrounding aDestination.
|
||||
|
||||
// aDestination must be clamped to the scroll
|
||||
// range in order to handle cases where the best matching snap point would
|
||||
// result in scrolling out of bounds. This clamping must be prior to
|
||||
// selecting the two interval edges.
|
||||
nscoord clamped = std::max(std::min(aDestination, aMaxPos), aMinPos);
|
||||
|
||||
// Add each edge in the interval immediately before aTarget and after aTarget
|
||||
// Do not add edges that are out of range.
|
||||
nscoord r = (clamped + aOffset) % aInterval;
|
||||
if (r < aMinPos) {
|
||||
r += aInterval;
|
||||
}
|
||||
nscoord edge = clamped - r;
|
||||
if (edge >= aMinPos && edge <= aMaxPos) {
|
||||
AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge,
|
||||
aEdgeFound);
|
||||
}
|
||||
edge += aInterval;
|
||||
if (edge >= aMinPos && edge <= aMaxPos) {
|
||||
AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge,
|
||||
aEdgeFound);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ScrollSnapHelper(SnappingEdgeCallback& aCallback, nsIFrame* aFrame,
|
||||
nsIFrame* aScrolledFrame,
|
||||
const nsPoint &aScrollSnapDestination) {
|
||||
nsIFrame::ChildListIterator childLists(aFrame);
|
||||
for (; !childLists.IsDone(); childLists.Next()) {
|
||||
nsFrameList::Enumerator childFrames(childLists.CurrentList());
|
||||
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
||||
nsIFrame* f = childFrames.get();
|
||||
|
||||
const nsStyleDisplay* styleDisplay = f->StyleDisplay();
|
||||
size_t coordCount = styleDisplay->mScrollSnapCoordinate.Length();
|
||||
|
||||
if (coordCount) {
|
||||
nsRect frameRect = f->GetRect();
|
||||
nsPoint offset = f->GetOffsetTo(aScrolledFrame);
|
||||
nsRect edgesRect = nsRect(offset, frameRect.Size());
|
||||
for (size_t coordNum = 0; coordNum < coordCount; coordNum++) {
|
||||
const nsStyleBackground::Position &coordPosition =
|
||||
f->StyleDisplay()->mScrollSnapCoordinate[coordNum];
|
||||
nsPoint coordPoint = edgesRect.TopLeft() - aScrollSnapDestination;
|
||||
coordPoint += nsPoint(coordPosition.mXPosition.mLength,
|
||||
coordPosition.mYPosition.mLength);
|
||||
if (coordPosition.mXPosition.mHasPercent) {
|
||||
coordPoint.x += NSToCoordRound(coordPosition.mXPosition.mPercent *
|
||||
frameRect.width);
|
||||
}
|
||||
if (coordPosition.mYPosition.mHasPercent) {
|
||||
coordPoint.y += NSToCoordRound(coordPosition.mYPosition.mPercent *
|
||||
frameRect.height);
|
||||
}
|
||||
|
||||
aCallback.AddVerticalEdge(coordPoint.x);
|
||||
aCallback.AddHorizontalEdge(coordPoint.y);
|
||||
}
|
||||
}
|
||||
|
||||
ScrollSnapHelper(aCallback, f, aScrolledFrame, aScrollSnapDestination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
CalcSnapPoints calcSnapPoints(aUnit, aDestination, aStartPos);
|
||||
|
||||
if (styles.mScrollSnapPointsX.GetUnit() != eStyleUnit_None) {
|
||||
nscoord interval = nsRuleNode::ComputeCoordPercentCalc(styles.mScrollSnapPointsX,
|
||||
scrollPortSize.width);
|
||||
calcSnapPoints.AddVerticalEdgeInterval(scrollRange, interval, destPos.x);
|
||||
}
|
||||
if (styles.mScrollSnapPointsY.GetUnit() != eStyleUnit_None) {
|
||||
nscoord interval = nsRuleNode::ComputeCoordPercentCalc(styles.mScrollSnapPointsY,
|
||||
scrollPortSize.width);
|
||||
calcSnapPoints.AddHorizontalEdgeInterval(scrollRange, interval, destPos.y);
|
||||
}
|
||||
|
||||
ScrollSnapHelper(calcSnapPoints, mScrolledFrame, mScrolledFrame, 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 &&
|
||||
std::abs(aDestination.y - finalPos.y) > proximityThreshold) {
|
||||
finalPos.y = aDestination.y;
|
||||
} else {
|
||||
snapped = true;
|
||||
}
|
||||
if (styles.mScrollSnapTypeX == NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY &&
|
||||
std::abs(aDestination.x - finalPos.x) > proximityThreshold) {
|
||||
finalPos.x = aDestination.x;
|
||||
} else {
|
||||
snapped = true;
|
||||
}
|
||||
if (snapped) {
|
||||
aDestination = finalPos;
|
||||
}
|
||||
return snapped;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "nsQueryFrame.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "TextOverflow.h"
|
||||
#include "ScrollVelocityQueue.h"
|
||||
|
||||
class nsPresContext;
|
||||
class nsIPresShell;
|
||||
|
@ -179,6 +180,9 @@ public:
|
|||
gfxSize GetResolution() const;
|
||||
void SetResolution(const gfxSize& aResolution);
|
||||
void SetResolutionAndScaleTo(const gfxSize& aResolution);
|
||||
void FlingSnap(const mozilla::CSSPoint& aDestination);
|
||||
void ScrollSnap();
|
||||
void ScrollSnap(const nsPoint &aDestination);
|
||||
|
||||
protected:
|
||||
nsRect GetScrollRangeForClamping() const;
|
||||
|
@ -195,8 +199,10 @@ public:
|
|||
* This is a closed-ended range --- aRange.XMost()/aRange.YMost() are allowed.
|
||||
*/
|
||||
void ScrollTo(nsPoint aScrollPosition, nsIScrollableFrame::ScrollMode aMode,
|
||||
const nsRect* aRange = nullptr) {
|
||||
ScrollToWithOrigin(aScrollPosition, aMode, nsGkAtoms::other, aRange);
|
||||
const nsRect* aRange = nullptr,
|
||||
nsIScrollableFrame::ScrollSnapMode aSnap = nsIScrollableFrame::DISABLE_SNAP) {
|
||||
ScrollToWithOrigin(aScrollPosition, aMode, nsGkAtoms::other, aRange,
|
||||
aSnap);
|
||||
}
|
||||
/**
|
||||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
|
@ -222,11 +228,23 @@ public:
|
|||
void ScrollBy(nsIntPoint aDelta, nsIScrollableFrame::ScrollUnit aUnit,
|
||||
nsIScrollableFrame::ScrollMode aMode, nsIntPoint* aOverflow,
|
||||
nsIAtom* aOrigin = nullptr,
|
||||
nsIScrollableFrame::ScrollMomentum aMomentum = nsIScrollableFrame::NOT_MOMENTUM);
|
||||
nsIScrollableFrame::ScrollMomentum aMomentum = nsIScrollableFrame::NOT_MOMENTUM,
|
||||
nsIScrollableFrame::ScrollSnapMode aSnap = nsIScrollableFrame::DISABLE_SNAP);
|
||||
/**
|
||||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
*/
|
||||
void ScrollToRestoredPosition();
|
||||
/**
|
||||
* GetSnapPointForDestination determines which point to snap to after
|
||||
* scrolling. aStartPos gives the position before scrolling and aDestination
|
||||
* gives the position after scrolling, with no snapping. Behaviour is
|
||||
* dependent on the value of aUnit.
|
||||
* Returns true if a suitable snap point could be found and aDestination has
|
||||
* been updated to a valid snapping position.
|
||||
*/
|
||||
bool GetSnapPointForDestination(nsIScrollableFrame::ScrollUnit aUnit,
|
||||
nsPoint aStartPos,
|
||||
nsPoint &aDestination);
|
||||
|
||||
nsSize GetLineScrollAmount() const;
|
||||
nsSize GetPageScrollAmount() const;
|
||||
|
@ -492,6 +510,8 @@ public:
|
|||
// (as best as we can tell on the main thread, anyway).
|
||||
bool mTransformingByAPZ:1;
|
||||
|
||||
mozilla::layout::ScrollVelocityQueue mVelocityQueue;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
|
@ -499,7 +519,8 @@ protected:
|
|||
void ScrollToWithOrigin(nsPoint aScrollPosition,
|
||||
nsIScrollableFrame::ScrollMode aMode,
|
||||
nsIAtom *aOrigin, // nullptr indicates "other" origin
|
||||
const nsRect* aRange);
|
||||
const nsRect* aRange,
|
||||
nsIScrollableFrame::ScrollSnapMode aSnap = nsIScrollableFrame::DISABLE_SNAP);
|
||||
|
||||
void CompleteAsyncScroll(const nsRect &aRange, nsIAtom* aOrigin = nullptr);
|
||||
|
||||
|
@ -687,8 +708,10 @@ public:
|
|||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
*/
|
||||
virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode,
|
||||
const nsRect* aRange = nullptr) MOZ_OVERRIDE {
|
||||
mHelper.ScrollTo(aScrollPosition, aMode, aRange);
|
||||
const nsRect* aRange = nullptr,
|
||||
nsIScrollableFrame::ScrollSnapMode aSnap = nsIScrollableFrame::DISABLE_SNAP)
|
||||
MOZ_OVERRIDE {
|
||||
mHelper.ScrollTo(aScrollPosition, aMode, aRange, aSnap);
|
||||
}
|
||||
/**
|
||||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
|
@ -713,9 +736,16 @@ public:
|
|||
*/
|
||||
virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
|
||||
nsIntPoint* aOverflow, nsIAtom* aOrigin = nullptr,
|
||||
nsIScrollableFrame::ScrollMomentum aMomentum = nsIScrollableFrame::NOT_MOMENTUM)
|
||||
nsIScrollableFrame::ScrollMomentum aMomentum = nsIScrollableFrame::NOT_MOMENTUM,
|
||||
nsIScrollableFrame::ScrollSnapMode aSnap = nsIScrollableFrame::DISABLE_SNAP)
|
||||
MOZ_OVERRIDE {
|
||||
mHelper.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin, aMomentum);
|
||||
mHelper.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin, aMomentum, aSnap);
|
||||
}
|
||||
virtual void FlingSnap(const mozilla::CSSPoint& aDestination) MOZ_OVERRIDE {
|
||||
mHelper.FlingSnap(aDestination);
|
||||
}
|
||||
virtual void ScrollSnap() MOZ_OVERRIDE {
|
||||
mHelper.ScrollSnap();
|
||||
}
|
||||
/**
|
||||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
|
@ -1059,8 +1089,9 @@ public:
|
|||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
*/
|
||||
virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode,
|
||||
const nsRect* aRange = nullptr) MOZ_OVERRIDE {
|
||||
mHelper.ScrollTo(aScrollPosition, aMode, aRange);
|
||||
const nsRect* aRange = nullptr,
|
||||
ScrollSnapMode aSnap = nsIScrollableFrame::DISABLE_SNAP) MOZ_OVERRIDE {
|
||||
mHelper.ScrollTo(aScrollPosition, aMode, aRange, aSnap);
|
||||
}
|
||||
/**
|
||||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
|
@ -1082,9 +1113,16 @@ public:
|
|||
*/
|
||||
virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
|
||||
nsIntPoint* aOverflow, nsIAtom* aOrigin = nullptr,
|
||||
nsIScrollableFrame::ScrollMomentum aMomentum = nsIScrollableFrame::NOT_MOMENTUM)
|
||||
nsIScrollableFrame::ScrollMomentum aMomentum = nsIScrollableFrame::NOT_MOMENTUM,
|
||||
nsIScrollableFrame::ScrollSnapMode aSnap = nsIScrollableFrame::DISABLE_SNAP)
|
||||
MOZ_OVERRIDE {
|
||||
mHelper.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin, aMomentum);
|
||||
mHelper.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin, aMomentum, aSnap);
|
||||
}
|
||||
virtual void FlingSnap(const mozilla::CSSPoint& aDestination) MOZ_OVERRIDE {
|
||||
mHelper.FlingSnap(aDestination);
|
||||
}
|
||||
virtual void ScrollSnap() MOZ_OVERRIDE {
|
||||
mHelper.ScrollSnap();
|
||||
}
|
||||
/**
|
||||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
|
|
|
@ -207,6 +207,13 @@ public:
|
|||
* been started since the last actual user input.
|
||||
*/
|
||||
enum ScrollMomentum { NOT_MOMENTUM, SYNTHESIZED_MOMENTUM_EVENT };
|
||||
/**
|
||||
* When set to ENABLE_SNAP, additional scrolling will be performed after the
|
||||
* scroll operation to maintain the constraints set by CSS Scroll snapping.
|
||||
* The additional scrolling may include asynchronous smooth scrolls that
|
||||
* continue to animate after the initial scroll position has been set.
|
||||
*/
|
||||
enum ScrollSnapMode { DISABLE_SNAP, ENABLE_SNAP };
|
||||
/**
|
||||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
* Clamps aScrollPosition to GetScrollRange and sets the scroll position
|
||||
|
@ -217,7 +224,8 @@ public:
|
|||
* The choosen point will be as close as possible to aScrollPosition.
|
||||
*/
|
||||
virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode,
|
||||
const nsRect* aRange = nullptr) = 0;
|
||||
const nsRect* aRange = nullptr,
|
||||
ScrollSnapMode aSnap = DISABLE_SNAP) = 0;
|
||||
/**
|
||||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
* Scrolls to a particular position in integer CSS pixels.
|
||||
|
@ -271,7 +279,27 @@ public:
|
|||
virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
|
||||
nsIntPoint* aOverflow = nullptr,
|
||||
nsIAtom* aOrigin = nullptr,
|
||||
ScrollMomentum aMomentum = NOT_MOMENTUM) = 0;
|
||||
ScrollMomentum aMomentum = NOT_MOMENTUM,
|
||||
ScrollSnapMode aSnap = DISABLE_SNAP) = 0;
|
||||
|
||||
/**
|
||||
* Perform scroll snapping, possibly resulting in a smooth scroll to
|
||||
* maintain the scroll snap position constraints. A predicted landing
|
||||
* position determined by the APZC is used to select the best matching
|
||||
* snap point, allowing touchscreen fling gestures to navigate between
|
||||
* snap points.
|
||||
* @param aDestination The desired landing position of the fling, which
|
||||
* is used to select the best matching snap point.
|
||||
*/
|
||||
virtual void FlingSnap(const mozilla::CSSPoint& aDestination) = 0;
|
||||
/**
|
||||
* Perform scroll snapping, possibly resulting in a smooth scroll to
|
||||
* maintain the scroll snap position constraints. Velocity sampled from
|
||||
* main thread scrolling is used to determine best matching snap point
|
||||
* when called after a fling gesture on a trackpad or mouse wheel.
|
||||
*/
|
||||
virtual void ScrollSnap() = 0;
|
||||
|
||||
/**
|
||||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
* This tells the scroll frame to try scrolling to the scroll
|
||||
|
|
|
@ -101,6 +101,24 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination) MOZ_OVERRIDE
|
||||
{
|
||||
if (MessageLoop::current() != mUILoop) {
|
||||
// We have to send this message from the "UI thread" (main
|
||||
// thread).
|
||||
mUILoop->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &RemoteContentController::RequestFlingSnap,
|
||||
aScrollId, aDestination));
|
||||
return;
|
||||
}
|
||||
if (mRenderFrame) {
|
||||
TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
|
||||
browser->RequestFlingSnap(aScrollId, aDestination);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) MOZ_OVERRIDE
|
||||
{
|
||||
|
|
|
@ -102,6 +102,13 @@ APZCCallbackHandler::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
APZCCallbackHandler::RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
APZCCallbackHelper::RequestFlingSnap(aScrollId, aDestination);
|
||||
}
|
||||
|
||||
void
|
||||
APZCCallbackHandler::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration)
|
||||
|
|
|
@ -44,6 +44,8 @@ public:
|
|||
|
||||
public: // GeckoContentController methods
|
||||
void RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics) MOZ_OVERRIDE;
|
||||
void RequestFlingSnap(const mozilla::layers::FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination) MOZ_OVERRIDE;
|
||||
void AcknowledgeScrollUpdate(const mozilla::layers::FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) MOZ_OVERRIDE;
|
||||
void HandleDoubleTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
|
||||
|
|
|
@ -187,6 +187,17 @@ APZController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
APZController::RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination)
|
||||
{
|
||||
#ifdef DEBUG_CONTROLLER
|
||||
WinUtils::Log("APZController::RequestFlingSnap scrollid=%I64d destination: %lu %lu",
|
||||
aScrollId, aDestination.x, aDestination.y);
|
||||
#endif
|
||||
mozilla::layers::APZCCallbackHelper::RequestFlingSnap(aScrollId, aDestination);
|
||||
}
|
||||
|
||||
void
|
||||
APZController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration)
|
||||
|
|
|
@ -37,6 +37,8 @@ public:
|
|||
|
||||
// GeckoContentController interface
|
||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics);
|
||||
virtual void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
const mozilla::CSSPoint& aDestination);
|
||||
virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, const uint32_t& aScrollGeneration);
|
||||
virtual void HandleDoubleTap(const mozilla::CSSPoint& aPoint,
|
||||
Modifiers aModifiers,
|
||||
|
|
Загрузка…
Ссылка в новой задаче