--- a/gfx/layers/apz/src/GenericScrollAnimation.cpp
+++ b/gfx/layers/apz/src/GenericScrollAnimation.cpp
@@ -9,19 +9,20 @@
#include "AsyncPanZoomController.h"
#include "gfxPrefs.h"
#include "nsPoint.h"
namespace mozilla {
namespace layers {
GenericScrollAnimation::GenericScrollAnimation(AsyncPanZoomController& aApzc,
- const nsPoint& aInitialPosition)
+ const nsPoint& aInitialPosition,
+ const ScrollAnimationPhysicsSettings& aSettings)
: mApzc(aApzc)
- , mAnimationPhysics(aInitialPosition)
+ , mAnimationPhysics(MakeUnique<ScrollAnimationPhysics>(aInitialPosition, aSettings))
, mFinalDestination(aInitialPosition)
, mForceVerticalOverscroll(false)
{
}
void
GenericScrollAnimation::UpdateDelta(TimeStamp aTime, nsPoint aDelta, const nsSize& aCurrentVelocity)
{
@@ -36,51 +37,45 @@ GenericScrollAnimation::UpdateDestinatio
mFinalDestination = aDestination;
Update(aTime, aCurrentVelocity);
}
void
GenericScrollAnimation::Update(TimeStamp aTime, const nsSize& aCurrentVelocity)
{
- if (mAnimationPhysics.mIsFirstIteration) {
- mAnimationPhysics.InitializeHistory(aTime);
- }
-
// Clamp the final destination to the scrollable area.
CSSPoint clamped = CSSPoint::FromAppUnits(mFinalDestination);
clamped.x = mApzc.mX.ClampOriginToScrollableRect(clamped.x);
clamped.y = mApzc.mY.ClampOriginToScrollableRect(clamped.y);
mFinalDestination = CSSPoint::ToAppUnits(clamped);
- mAnimationPhysics.Update(aTime, mFinalDestination, aCurrentVelocity);
+ mAnimationPhysics->Update(aTime, mFinalDestination, aCurrentVelocity);
}
bool
GenericScrollAnimation::DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta)
{
TimeStamp now = mApzc.GetFrameTime();
CSSToParentLayerScale2D zoom = aFrameMetrics.GetZoom();
// If the animation is finished, make sure the final position is correct by
// using one last displacement. Otherwise, compute the delta via the timing
// function as normal.
- bool finished = mAnimationPhysics.IsFinished(now);
- nsPoint sampledDest = finished
- ? mAnimationPhysics.mDestination
- : mAnimationPhysics.PositionAt(now);
+ bool finished = mAnimationPhysics->IsFinished(now);
+ nsPoint sampledDest = mAnimationPhysics->PositionAt(now);
ParentLayerPoint displacement =
(CSSPoint::FromAppUnits(sampledDest) - aFrameMetrics.GetScrollOffset()) * zoom;
if (finished) {
mApzc.mX.SetVelocity(0);
mApzc.mY.SetVelocity(0);
} else if (!IsZero(displacement)) {
// Convert velocity from AppUnits/Seconds to ParentLayerCoords/Milliseconds
- nsSize velocity = mAnimationPhysics.VelocityAt(now);
+ nsSize velocity = mAnimationPhysics->VelocityAt(now);
ParentLayerPoint velocityPL =
CSSPoint::FromAppUnits(nsPoint(velocity.width, velocity.height)) * zoom;
mApzc.mX.SetVelocity(velocityPL.x / 1000.0);
mApzc.mY.SetVelocity(velocityPL.y / 1000.0);
}
// Note: we ignore overscroll for generic animations.
ParentLayerPoint adjustedOffset, overscroll;
--- a/gfx/layers/apz/src/GenericScrollAnimation.h
+++ b/gfx/layers/apz/src/GenericScrollAnimation.h
@@ -15,33 +15,34 @@ namespace layers {
class AsyncPanZoomController;
class GenericScrollAnimation
: public AsyncPanZoomAnimation
{
public:
GenericScrollAnimation(AsyncPanZoomController& aApzc,
- const nsPoint& aInitialPosition);
+ const nsPoint& aInitialPosition,
+ const ScrollAnimationPhysicsSettings& aSettings);
bool DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta) override;
void UpdateDelta(TimeStamp aTime, nsPoint aDelta, const nsSize& aCurrentVelocity);
void UpdateDestination(TimeStamp aTime, nsPoint aDestination, const nsSize& aCurrentVelocity);
CSSPoint GetDestination() const {
return CSSPoint::FromAppUnits(mFinalDestination);
}
private:
void Update(TimeStamp aTime, const nsSize& aCurrentVelocity);
-
+
protected:
AsyncPanZoomController& mApzc;
- ScrollAnimationPhysics mAnimationPhysics;
+ UniquePtr<ScrollAnimationPhysics> mAnimationPhysics;
nsPoint mFinalDestination;
bool mForceVerticalOverscroll;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_GenericScrollAnimation_h_
--- a/gfx/layers/apz/src/KeyboardScrollAnimation.cpp
+++ b/gfx/layers/apz/src/KeyboardScrollAnimation.cpp
@@ -6,39 +6,48 @@
#include "KeyboardScrollAnimation.h"
#include "gfxPrefs.h"
namespace mozilla {
namespace layers {
-KeyboardScrollAnimation::KeyboardScrollAnimation(AsyncPanZoomController& aApzc,
- const nsPoint& aInitialPosition,
- KeyboardScrollAction::KeyboardScrollActionType aType)
- : GenericScrollAnimation(aApzc, aInitialPosition)
+static ScrollAnimationPhysicsSettings
+SettingsForType(KeyboardScrollAction::KeyboardScrollActionType aType)
{
+ int32_t minMS = 0;
+ int32_t maxMS = 0;
+
switch (aType) {
case KeyboardScrollAction::eScrollCharacter:
case KeyboardScrollAction::eScrollLine: {
- mAnimationPhysics.mOriginMaxMS = clamped(gfxPrefs::LineSmoothScrollMaxDurationMs(), 0, 10000);
- mAnimationPhysics.mOriginMinMS = clamped(gfxPrefs::LineSmoothScrollMinDurationMs(), 0, mAnimationPhysics.mOriginMaxMS);
+ maxMS = clamped(gfxPrefs::LineSmoothScrollMaxDurationMs(), 0, 10000);
+ minMS = clamped(gfxPrefs::LineSmoothScrollMinDurationMs(), 0, maxMS);
break;
}
case KeyboardScrollAction::eScrollPage: {
- mAnimationPhysics.mOriginMaxMS = clamped(gfxPrefs::PageSmoothScrollMaxDurationMs(), 0, 10000);
- mAnimationPhysics.mOriginMinMS = clamped(gfxPrefs::PageSmoothScrollMinDurationMs(), 0, mAnimationPhysics.mOriginMaxMS);
+ maxMS = clamped(gfxPrefs::PageSmoothScrollMaxDurationMs(), 0, 10000);
+ minMS = clamped(gfxPrefs::PageSmoothScrollMinDurationMs(), 0, maxMS);
break;
}
case KeyboardScrollAction::eScrollComplete: {
- mAnimationPhysics.mOriginMaxMS = clamped(gfxPrefs::OtherSmoothScrollMaxDurationMs(), 0, 10000);
- mAnimationPhysics.mOriginMinMS = clamped(gfxPrefs::OtherSmoothScrollMinDurationMs(), 0, mAnimationPhysics.mOriginMaxMS);
+ maxMS = clamped(gfxPrefs::OtherSmoothScrollMaxDurationMs(), 0, 10000);
+ minMS = clamped(gfxPrefs::OtherSmoothScrollMinDurationMs(), 0, maxMS);
break;
}
}
// The pref is 100-based int percentage, while mIntervalRatio is 1-based ratio
- mAnimationPhysics.mIntervalRatio = ((double)gfxPrefs::SmoothScrollDurationToIntervalRatio()) / 100.0;
- mAnimationPhysics.mIntervalRatio = std::max(1.0, mAnimationPhysics.mIntervalRatio);
+ double intervalRatio = ((double)gfxPrefs::SmoothScrollDurationToIntervalRatio()) / 100.0;
+ intervalRatio = std::max(1.0, intervalRatio);
+ return ScrollAnimationPhysicsSettings { minMS, maxMS, intervalRatio };
+}
+
+KeyboardScrollAnimation::KeyboardScrollAnimation(AsyncPanZoomController& aApzc,
+ const nsPoint& aInitialPosition,
+ KeyboardScrollAction::KeyboardScrollActionType aType)
+ : GenericScrollAnimation(aApzc, aInitialPosition, SettingsForType(aType))
+{
}
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/apz/src/WheelScrollAnimation.cpp
+++ b/gfx/layers/apz/src/WheelScrollAnimation.cpp
@@ -8,37 +8,45 @@
#include "AsyncPanZoomController.h"
#include "gfxPrefs.h"
#include "nsPoint.h"
namespace mozilla {
namespace layers {
+static ScrollAnimationPhysicsSettings
+SettingsForDeltaType(ScrollWheelInput::ScrollDeltaType aDeltaType)
+{
+ int32_t minMS = 0;
+ int32_t maxMS = 0;
+
+ switch (aDeltaType) {
+ case ScrollWheelInput::SCROLLDELTA_PAGE:
+ maxMS = clamped(gfxPrefs::PageSmoothScrollMaxDurationMs(), 0, 10000);
+ minMS = clamped(gfxPrefs::PageSmoothScrollMinDurationMs(), 0, maxMS);
+ break;
+ case ScrollWheelInput::SCROLLDELTA_PIXEL:
+ maxMS = clamped(gfxPrefs::PixelSmoothScrollMaxDurationMs(), 0, 10000);
+ minMS = clamped(gfxPrefs::PixelSmoothScrollMinDurationMs(), 0, maxMS);
+ break;
+ case ScrollWheelInput::SCROLLDELTA_LINE:
+ maxMS = clamped(gfxPrefs::WheelSmoothScrollMaxDurationMs(), 0, 10000);
+ minMS = clamped(gfxPrefs::WheelSmoothScrollMinDurationMs(), 0, maxMS);
+ break;
+ }
+
+ // The pref is 100-based int percentage, while mIntervalRatio is 1-based ratio
+ double intervalRatio = ((double)gfxPrefs::SmoothScrollDurationToIntervalRatio()) / 100.0;
+ intervalRatio = std::max(1.0, intervalRatio);
+ return ScrollAnimationPhysicsSettings { minMS, maxMS, intervalRatio };
+}
+
WheelScrollAnimation::WheelScrollAnimation(AsyncPanZoomController& aApzc,
const nsPoint& aInitialPosition,
ScrollWheelInput::ScrollDeltaType aDeltaType)
- : GenericScrollAnimation(aApzc, aInitialPosition)
+ : GenericScrollAnimation(aApzc, aInitialPosition, SettingsForDeltaType(aDeltaType))
{
mForceVerticalOverscroll = !mApzc.mScrollMetadata.AllowVerticalScrollWithWheel();
-
- switch (aDeltaType) {
- case ScrollWheelInput::SCROLLDELTA_PAGE:
- mAnimationPhysics.mOriginMaxMS = clamped(gfxPrefs::PageSmoothScrollMaxDurationMs(), 0, 10000);
- mAnimationPhysics.mOriginMinMS = clamped(gfxPrefs::PageSmoothScrollMinDurationMs(), 0, mAnimationPhysics.mOriginMaxMS);
- break;
- case ScrollWheelInput::SCROLLDELTA_PIXEL:
- mAnimationPhysics.mOriginMaxMS = clamped(gfxPrefs::PixelSmoothScrollMaxDurationMs(), 0, 10000);
- mAnimationPhysics.mOriginMinMS = clamped(gfxPrefs::PixelSmoothScrollMinDurationMs(), 0, mAnimationPhysics.mOriginMaxMS);
- break;
- case ScrollWheelInput::SCROLLDELTA_LINE:
- mAnimationPhysics.mOriginMaxMS = clamped(gfxPrefs::WheelSmoothScrollMaxDurationMs(), 0, 10000);
- mAnimationPhysics.mOriginMinMS = clamped(gfxPrefs::WheelSmoothScrollMinDurationMs(), 0, mAnimationPhysics.mOriginMaxMS);
- break;
- }
-
- // The pref is 100-based int percentage, while mIntervalRatio is 1-based ratio
- mAnimationPhysics.mIntervalRatio = ((double)gfxPrefs::SmoothScrollDurationToIntervalRatio()) / 100.0;
- mAnimationPhysics.mIntervalRatio = std::max(1.0, mAnimationPhysics.mIntervalRatio);
}
} // namespace layers
} // namespace mozilla
--- a/layout/generic/ScrollAnimationPhysics.cpp
+++ b/layout/generic/ScrollAnimationPhysics.cpp
@@ -3,27 +3,33 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ScrollAnimationPhysics.h"
#include "gfxPrefs.h"
using namespace mozilla;
-ScrollAnimationPhysics::ScrollAnimationPhysics(nsPoint aStartPos)
- : mIsFirstIteration(true)
+ScrollAnimationPhysics::ScrollAnimationPhysics(nsPoint aStartPos,
+ const ScrollAnimationPhysicsSettings& aSettings)
+ : mSettings(aSettings)
, mStartPos(aStartPos)
+ , mIsFirstIteration(true)
{
}
void
ScrollAnimationPhysics::Update(TimeStamp aTime,
nsPoint aDestination,
const nsSize& aCurrentVelocity)
{
+ if (mIsFirstIteration) {
+ InitializeHistory(aTime);
+ }
+
TimeDuration duration = ComputeDuration(aTime);
nsSize currentVelocity = aCurrentVelocity;
if (!mIsFirstIteration) {
// If an additional event has not changed the destination, then do not let
// another minimum duration reset slow things down. If it would then
// instead continue with the existing timing function.
if (aDestination == mDestination &&
@@ -55,29 +61,32 @@ ScrollAnimationPhysics::ComputeDuration(
mPrevEventTime[1] = mPrevEventTime[0];
mPrevEventTime[0] = aTime;
// Modulate duration according to events rate (quicker events -> shorter durations).
// The desired effect is to use longer duration when scrolling slowly, such that
// it's easier to follow, but reduce the duration to make it feel more snappy when
// scrolling quickly. To reduce fluctuations of the duration, we average event
// intervals using the recent 4 timestamps (now + three prev -> 3 intervals).
- int32_t durationMS = clamped<int32_t>(eventsDeltaMs * mIntervalRatio, mOriginMinMS, mOriginMaxMS);
+ int32_t durationMS =
+ clamped<int32_t>(eventsDeltaMs * mSettings.mIntervalRatio,
+ mSettings.mMinMS, mSettings.mMaxMS);
return TimeDuration::FromMilliseconds(durationMS);
}
void
ScrollAnimationPhysics::InitializeHistory(TimeStamp aTime)
{
// Starting a new scroll (i.e. not when extending an existing scroll animation),
// create imaginary prev timestamps with maximum relevant intervals between them.
// Longest relevant interval (which results in maximum duration)
- TimeDuration maxDelta = TimeDuration::FromMilliseconds(mOriginMaxMS / mIntervalRatio);
+ TimeDuration maxDelta =
+ TimeDuration::FromMilliseconds(mSettings.mMaxMS / mSettings.mIntervalRatio);
mPrevEventTime[0] = aTime - maxDelta;
mPrevEventTime[1] = mPrevEventTime[0] - maxDelta;
mPrevEventTime[2] = mPrevEventTime[1] - maxDelta;
}
void
ScrollAnimationPhysics::InitTimingFunction(nsSMILKeySpline& aTimingFunction,
nscoord aCurrentPos,
@@ -93,27 +102,35 @@ ScrollAnimationPhysics::InitTimingFuncti
double slope = aCurrentVelocity * (mDuration / oneSecond) / (aDestination - aCurrentPos);
double normalization = sqrt(1.0 + slope * slope);
double dt = 1.0 / normalization * gfxPrefs::SmoothScrollCurrentVelocityWeighting();
double dxy = slope / normalization * gfxPrefs::SmoothScrollCurrentVelocityWeighting();
aTimingFunction.Init(dt, dxy, 1 - gfxPrefs::SmoothScrollStopDecelerationWeighting(), 1);
}
nsPoint
-ScrollAnimationPhysics::PositionAt(TimeStamp aTime) const
+ScrollAnimationPhysics::PositionAt(TimeStamp aTime)
{
+ if (IsFinished(aTime)) {
+ return mDestination;
+ }
+
double progressX = mTimingFunctionX.GetSplineValue(ProgressAt(aTime));
double progressY = mTimingFunctionY.GetSplineValue(ProgressAt(aTime));
return nsPoint(NSToCoordRound((1 - progressX) * mStartPos.x + progressX * mDestination.x),
NSToCoordRound((1 - progressY) * mStartPos.y + progressY * mDestination.y));
}
nsSize
-ScrollAnimationPhysics::VelocityAt(TimeStamp aTime) const
+ScrollAnimationPhysics::VelocityAt(TimeStamp aTime)
{
+ if (IsFinished(aTime)) {
+ return nsSize(0, 0);
+ }
+
double timeProgress = ProgressAt(aTime);
return nsSize(VelocityComponent(timeProgress, mTimingFunctionX,
mStartPos.x, mDestination.x),
VelocityComponent(timeProgress, mTimingFunctionY,
mStartPos.y, mDestination.y));
}
nscoord
--- a/layout/generic/ScrollAnimationPhysics.h
+++ b/layout/generic/ScrollAnimationPhysics.h
@@ -7,56 +7,53 @@
#define mozilla_layout_ScrollAnimationPhysics_h_
#include "mozilla/TimeStamp.h"
#include "nsPoint.h"
#include "nsSMILKeySpline.h"
namespace mozilla {
+struct ScrollAnimationPhysicsSettings
+{
+ // These values are minimum and maximum animation duration per event,
+ // and a global ratio which defines how longer is the animation's duration
+ // compared to the average recent events intervals (such that for a relatively
+ // consistent events rate, the next event arrives before current animation ends)
+ int32_t mMinMS;
+ int32_t mMaxMS;
+ double mIntervalRatio;
+};
+
// This is the base class for driving scroll wheel animation on both the
// compositor and main thread.
class ScrollAnimationPhysics
{
public:
typedef mozilla::TimeStamp TimeStamp;
typedef mozilla::TimeDuration TimeDuration;
- explicit ScrollAnimationPhysics(nsPoint aStartPos);
+ explicit ScrollAnimationPhysics(nsPoint aStartPos,
+ const ScrollAnimationPhysicsSettings& aSettings);
void Update(TimeStamp aTime,
nsPoint aDestination,
const nsSize& aCurrentVelocity);
// Get the velocity at a point in time in nscoords/sec.
- nsSize VelocityAt(TimeStamp aTime) const;
+ nsSize VelocityAt(TimeStamp aTime);
// Returns the expected scroll position at a given point in time, in app
// units, relative to the scroll frame.
- nsPoint PositionAt(TimeStamp aTime) const;
+ nsPoint PositionAt(TimeStamp aTime);
bool IsFinished(TimeStamp aTime) {
return aTime > mStartTime + mDuration;
}
- // Initialize event history.
- void InitializeHistory(TimeStamp aTime);
-
- // Cached Preferences value.
- //
- // These values are minimum and maximum animation duration per event origin,
- // and a global ratio which defines how longer is the animation's duration
- // compared to the average recent events intervals (such that for a relatively
- // consistent events rate, the next event arrives before current animation ends)
- int32_t mOriginMinMS;
- int32_t mOriginMaxMS;
- double mIntervalRatio;
- nsPoint mDestination;
- bool mIsFirstIteration;
-
protected:
double ProgressAt(TimeStamp aTime) const {
return clamped((aTime - mStartTime) / mDuration, 0.0, 1.0);
}
nscoord VelocityComponent(double aTimeProgress,
const nsSMILKeySpline& aTimingFunction,
nscoord aStart, nscoord aDestination) const;
@@ -67,29 +64,37 @@ protected:
TimeDuration ComputeDuration(TimeStamp aTime);
// Initializes the timing function in such a way that the current velocity is
// preserved.
void InitTimingFunction(nsSMILKeySpline& aTimingFunction,
nscoord aCurrentPos, nscoord aCurrentVelocity,
nscoord aDestination);
+ // Initialize event history.
+ void InitializeHistory(TimeStamp aTime);
+
+ // Cached Preferences values.
+ ScrollAnimationPhysicsSettings mSettings;
+
// mPrevEventTime holds previous 3 timestamps for intervals averaging (to
// reduce duration fluctuations). When AsyncScroll is constructed and no
// previous timestamps are available (indicated with mIsFirstIteration),
// initialize mPrevEventTime using imaginary previous timestamps with maximum
// relevant intervals between them.
TimeStamp mPrevEventTime[3];
TimeStamp mStartTime;
nsPoint mStartPos;
+ nsPoint mDestination;
TimeDuration mDuration;
nsSMILKeySpline mTimingFunctionX;
nsSMILKeySpline mTimingFunctionY;
+ bool mIsFirstIteration;
};
// Helper for accelerated wheel deltas. This can be called from the main thread
// or the APZ Controller thread.
static inline double
ComputeAcceleratedWheelDelta(double aDelta, int32_t aCounter, int32_t aFactor)
{
if (!aDelta) {
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1800,52 +1800,69 @@ private:
// AsyncScroll has ref counting.
class ScrollFrameHelper::AsyncScroll final
: public nsARefreshObserver
{
public:
typedef mozilla::TimeStamp TimeStamp;
typedef mozilla::TimeDuration TimeDuration;
- explicit AsyncScroll(nsPoint aStartPos)
- : mAnimationPhysics(aStartPos)
- , mCallee(nullptr)
+ explicit AsyncScroll()
+ : mCallee(nullptr)
{
Telemetry::SetHistogramRecordingEnabled(
Telemetry::FX_REFRESH_DRIVER_SYNC_SCROLL_FRAME_DELAY_MS, true);
}
private:
// Private destructor, to discourage deletion outside of Release():
~AsyncScroll() {
RemoveObserver();
Telemetry::SetHistogramRecordingEnabled(
Telemetry::FX_REFRESH_DRIVER_SYNC_SCROLL_FRAME_DELAY_MS, false);
}
public:
- void InitSmoothScroll(TimeStamp aTime, nsPoint aDestination,
+ void InitSmoothScroll(TimeStamp aTime,
+ nsPoint aInitialPosition, nsPoint aDestination,
nsIAtom *aOrigin, const nsRect& aRange,
const nsSize& aCurrentVelocity);
void Init(const nsRect& aRange) {
+ mAnimationPhysics = nullptr;
mRange = aRange;
}
- ScrollAnimationPhysics mAnimationPhysics;
+ bool IsSmoothScroll() { return mAnimationPhysics != nullptr; }
+
+ bool IsFinished(const TimeStamp& aTime) const {
+ MOZ_RELEASE_ASSERT(mAnimationPhysics);
+ return mAnimationPhysics->IsFinished(aTime);
+ }
+
+ nsPoint PositionAt(const TimeStamp& aTime) const {
+ MOZ_RELEASE_ASSERT(mAnimationPhysics);
+ return mAnimationPhysics->PositionAt(aTime);
+ }
+
+ nsSize VelocityAt(const TimeStamp& aTime) const {
+ MOZ_RELEASE_ASSERT(mAnimationPhysics);
+ return mAnimationPhysics->VelocityAt(aTime);
+ }
// Most recent scroll origin.
RefPtr<nsIAtom> mOrigin;
// Allowed destination positions around mDestination
nsRect mRange;
- bool mIsSmoothScroll;
private:
void InitPreferences(TimeStamp aTime, nsIAtom *aOrigin);
+ UniquePtr<ScrollAnimationPhysics> mAnimationPhysics;
+
// The next section is observer/callback management
// Bodies of WillRefresh and RefreshDriver contain ScrollFrameHelper specific code.
public:
NS_INLINE_DECL_REFCOUNTING(AsyncScroll, override)
/*
* Set a refresh observer for smooth scroll iterations (and start observing).
* Should be used at most once during the lifetime of this object.
@@ -1888,84 +1905,84 @@ private:
}
}
};
/*
* Calculate duration, possibly dynamically according to events rate and event origin.
* (also maintain previous timestamps - which are only used here).
*/
-void
-ScrollFrameHelper::AsyncScroll::InitPreferences(TimeStamp aTime, nsIAtom *aOrigin)
-{
- if (!aOrigin || aOrigin == nsGkAtoms::restore) {
- // We don't have special prefs for "restore", just treat it as "other".
- // "restore" scrolls are (for now) always instant anyway so unless something
- // changes we should never have aOrigin == nsGkAtoms::restore here.
- aOrigin = nsGkAtoms::other;
- }
- // Likewise we should never get APZ-triggered scrolls here, and if that changes
- // something is likely broken somewhere.
- MOZ_ASSERT(aOrigin != nsGkAtoms::apz);
-
- // Read preferences only on first iteration or for a different event origin.
- if (!mAnimationPhysics.mIsFirstIteration && aOrigin == mOrigin) {
- return;
- }
-
- mOrigin = aOrigin;
- mAnimationPhysics.mOriginMinMS = mAnimationPhysics.mOriginMaxMS = 0;
+static ScrollAnimationPhysicsSettings
+ComputeAnimationSettingsForOrigin(nsIAtom *aOrigin)
+{
+ int32_t minMS = 0;
+ int32_t maxMS = 0;
bool isOriginSmoothnessEnabled = false;
- mAnimationPhysics.mIntervalRatio = 1;
+ double intervalRatio = 1;
// Default values for all preferences are defined in all.js
static const int32_t kDefaultMinMS = 150, kDefaultMaxMS = 150;
static const bool kDefaultIsSmoothEnabled = true;
nsAutoCString originName;
aOrigin->ToUTF8String(originName);
nsAutoCString prefBase = NS_LITERAL_CSTRING("general.smoothScroll.") + originName;
isOriginSmoothnessEnabled = Preferences::GetBool(prefBase.get(), kDefaultIsSmoothEnabled);
if (isOriginSmoothnessEnabled) {
nsAutoCString prefMin = prefBase + NS_LITERAL_CSTRING(".durationMinMS");
nsAutoCString prefMax = prefBase + NS_LITERAL_CSTRING(".durationMaxMS");
- mAnimationPhysics.mOriginMinMS = Preferences::GetInt(prefMin.get(), kDefaultMinMS);
- mAnimationPhysics.mOriginMaxMS = Preferences::GetInt(prefMax.get(), kDefaultMaxMS);
+ minMS = Preferences::GetInt(prefMin.get(), kDefaultMinMS);
+ maxMS = Preferences::GetInt(prefMax.get(), kDefaultMaxMS);
static const int32_t kSmoothScrollMaxAllowedAnimationDurationMS = 10000;
- mAnimationPhysics.mOriginMaxMS = clamped(mAnimationPhysics.mOriginMaxMS, 0, kSmoothScrollMaxAllowedAnimationDurationMS);
- mAnimationPhysics.mOriginMinMS = clamped(mAnimationPhysics.mOriginMinMS, 0, mAnimationPhysics.mOriginMaxMS);
+ maxMS = clamped(maxMS, 0, kSmoothScrollMaxAllowedAnimationDurationMS);
+ minMS = clamped(minMS, 0, maxMS);
}
// Keep the animation duration longer than the average event intervals
// (to "connect" consecutive scroll animations before the scroll comes to a stop).
static const double kDefaultDurationToIntervalRatio = 2; // Duplicated at all.js
- mAnimationPhysics.mIntervalRatio = Preferences::GetInt("general.smoothScroll.durationToIntervalRatio",
+ intervalRatio = Preferences::GetInt("general.smoothScroll.durationToIntervalRatio",
kDefaultDurationToIntervalRatio * 100) / 100.0;
// Duration should be at least as long as the intervals -> ratio is at least 1
- mAnimationPhysics.mIntervalRatio = std::max(1.0, mAnimationPhysics.mIntervalRatio);
-
- if (mAnimationPhysics.mIsFirstIteration) {
- mAnimationPhysics.InitializeHistory(aTime);
- }
+ intervalRatio = std::max(1.0, intervalRatio);
+
+ return ScrollAnimationPhysicsSettings { minMS, maxMS, intervalRatio };
}
void
ScrollFrameHelper::AsyncScroll::InitSmoothScroll(TimeStamp aTime,
+ nsPoint aInitialPosition,
nsPoint aDestination,
nsIAtom *aOrigin,
const nsRect& aRange,
const nsSize& aCurrentVelocity)
{
- InitPreferences(aTime, aOrigin);
+ if (!aOrigin || aOrigin == nsGkAtoms::restore) {
+ // We don't have special prefs for "restore", just treat it as "other".
+ // "restore" scrolls are (for now) always instant anyway so unless something
+ // changes we should never have aOrigin == nsGkAtoms::restore here.
+ aOrigin = nsGkAtoms::other;
+ }
+ // Likewise we should never get APZ-triggered scrolls here, and if that changes
+ // something is likely broken somewhere.
+ MOZ_ASSERT(aOrigin != nsGkAtoms::apz);
+
+ // Read preferences only on first iteration or for a different event origin.
+ if (!mAnimationPhysics || aOrigin != mOrigin) {
+ mOrigin = aOrigin;
+ ScrollAnimationPhysicsSettings settings = ComputeAnimationSettingsForOrigin(mOrigin);
+ mAnimationPhysics = MakeUnique<ScrollAnimationPhysics>(aInitialPosition, settings);
+ }
+
mRange = aRange;
- mAnimationPhysics.Update(aTime, aDestination, aCurrentVelocity);
+ mAnimationPhysics->Update(aTime, aDestination, aCurrentVelocity);
}
bool
ScrollFrameHelper::IsSmoothScrollingEnabled()
{
return Preferences::GetBool(SMOOTH_SCROLL_PREF_NAME, false);
}
@@ -2123,19 +2140,19 @@ ScrollFrameHelper::AsyncScrollCallback(S
MOZ_ASSERT(aInstance->mAsyncScroll,
"Did not expect AsyncScrollCallback without an active async scroll.");
if (!aInstance || !aInstance->mAsyncScroll) {
return; // XXX wallpaper bug 1107353 for now.
}
nsRect range = aInstance->mAsyncScroll->mRange;
- if (aInstance->mAsyncScroll->mIsSmoothScroll) {
- if (!aInstance->mAsyncScroll->mAnimationPhysics.IsFinished(aTime)) {
- nsPoint destination = aInstance->mAsyncScroll->mAnimationPhysics.PositionAt(aTime);
+ if (aInstance->mAsyncScroll->IsSmoothScroll()) {
+ if (!aInstance->mAsyncScroll->IsFinished(aTime)) {
+ nsPoint destination = aInstance->mAsyncScroll->PositionAt(aTime);
// Allow this scroll operation to land on any pixel boundary between the
// current position and the final allowed range. (We don't want
// intermediate steps to be more constrained than the final step!)
nsRect intermediateRange =
nsRect(aInstance->GetScrollPosition(), nsSize()).UnionEdges(range);
aInstance->ScrollToImpl(destination, intermediateRange);
// 'aInstance' might be destroyed here
return;
@@ -2287,18 +2304,18 @@ ScrollFrameHelper::ScrollToWithOrigin(ns
if (gfxPrefs::ScrollBehaviorEnabled()) {
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->mAnimationPhysics.VelocityAt(now);
+ if (mAsyncScroll->IsSmoothScroll()) {
+ currentVelocity = mAsyncScroll->VelocityAt(now);
}
mAsyncScroll = nullptr;
}
if (nsLayoutUtils::AsyncPanZoomEnabled(mOuter) && WantAsyncScroll()) {
if (mApzSmoothScrollDestination == Some(mDestination) &&
mScrollGeneration == sScrollGenerationCounter) {
// If we already sent APZ a smooth-scroll request to this
@@ -2368,28 +2385,27 @@ ScrollFrameHelper::ScrollToWithOrigin(ns
if (mAsyncSmoothMSDScroll) {
currentVelocity = mAsyncSmoothMSDScroll->GetVelocity();
mAsyncSmoothMSDScroll = nullptr;
}
}
}
if (!mAsyncScroll) {
- mAsyncScroll = new AsyncScroll(GetScrollPosition());
+ mAsyncScroll = new AsyncScroll();
if (!mAsyncScroll->SetRefreshObserver(this)) {
// Observer setup failed. Scroll the normal way.
CompleteAsyncScroll(range, aOrigin);
return;
}
}
- mAsyncScroll->mIsSmoothScroll = isSmoothScroll;
-
if (isSmoothScroll) {
- mAsyncScroll->InitSmoothScroll(now, mDestination, aOrigin, range, currentVelocity);
+ mAsyncScroll->InitSmoothScroll(now, GetScrollPosition(), mDestination,
+ aOrigin, range, currentVelocity);
} else {
mAsyncScroll->Init(range);
}
}
// We can't use nsContainerFrame::PositionChildViews here because
// we don't want to invalidate views that have moved.
static void AdjustViews(nsIFrame* aFrame)