Bug 1402498 - Add ScrollAnimationMSDPhysics, can be enabled using general.smoothScroll.msdPhysics.enabled. r?rhunt
MozReview-Commit-ID: fr8Q9iod5k
--- a/gfx/layers/apz/src/GenericScrollAnimation.cpp
+++ b/gfx/layers/apz/src/GenericScrollAnimation.cpp
@@ -6,28 +6,33 @@
#include "GenericScrollAnimation.h"
#include "AsyncPanZoomController.h"
#include "gfxPrefs.h"
#include "nsPoint.h"
#include "ScrollAnimationPhysics.h"
#include "ScrollAnimationBezierPhysics.h"
+#include "ScrollAnimationMSDPhysics.h"
namespace mozilla {
namespace layers {
GenericScrollAnimation::GenericScrollAnimation(AsyncPanZoomController& aApzc,
const nsPoint& aInitialPosition,
const ScrollAnimationBezierPhysicsSettings& aSettings)
: mApzc(aApzc)
- , mAnimationPhysics(MakeUnique<ScrollAnimationBezierPhysics>(aInitialPosition, aSettings))
, mFinalDestination(aInitialPosition)
, mForceVerticalOverscroll(false)
{
+ if (gfxPrefs::SmoothScrollMSDPhysicsEnabled()) {
+ mAnimationPhysics = MakeUnique<ScrollAnimationMSDPhysics>(aInitialPosition);
+ } else {
+ mAnimationPhysics = MakeUnique<ScrollAnimationBezierPhysics>(aInitialPosition, aSettings);
+ }
}
void
GenericScrollAnimation::UpdateDelta(TimeStamp aTime, nsPoint aDelta, const nsSize& aCurrentVelocity)
{
mFinalDestination += aDelta;
Update(aTime, aCurrentVelocity);
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -399,16 +399,31 @@ private:
DECL_GFX_PREF(Live, "general.smoothScroll.pixels", PixelSmoothScrollEnabled, bool, true);
DECL_GFX_PREF(Live, "general.smoothScroll.pixels.durationMaxMS",
PixelSmoothScrollMaxDurationMs, int32_t, 150);
DECL_GFX_PREF(Live, "general.smoothScroll.pixels.durationMinMS",
PixelSmoothScrollMinDurationMs, int32_t, 150);
DECL_GFX_PREF(Live, "general.smoothScroll.stopDecelerationWeighting",
SmoothScrollStopDecelerationWeighting, float, 0.4f);
+ DECL_GFX_PREF(Live, "general.smoothScroll.msdPhysics.enabled",
+ SmoothScrollMSDPhysicsEnabled, bool, false);
+ DECL_GFX_PREF(Live, "general.smoothScroll.msdPhysics.continuousMotionMaxDeltaMS",
+ SmoothScrollMSDPhysicsContinuousMotionMaxDeltaMS, int32_t, 120);
+ DECL_GFX_PREF(Live, "general.smoothScroll.msdPhysics.motionBeginSpringConstant",
+ SmoothScrollMSDPhysicsMotionBeginSpringConstant, int32_t, 1250);
+ DECL_GFX_PREF(Live, "general.smoothScroll.msdPhysics.slowdownMinDeltaMS",
+ SmoothScrollMSDPhysicsSlowdownMinDeltaMS, int32_t, 12);
+ DECL_GFX_PREF(Live, "general.smoothScroll.msdPhysics.slowdownMinDeltaRatio",
+ SmoothScrollMSDPhysicsSlowdownMinDeltaRatio, float, 1.3f);
+ DECL_GFX_PREF(Live, "general.smoothScroll.msdPhysics.slowdownSpringConstant",
+ SmoothScrollMSDPhysicsSlowdownSpringConstant, int32_t, 2000);
+ DECL_GFX_PREF(Live, "general.smoothScroll.msdPhysics.regularSpringConstant",
+ SmoothScrollMSDPhysicsRegularSpringConstant, int32_t, 1000);
+
DECL_GFX_PREF(Once, "gfx.android.rgb16.force", AndroidRGB16Force, bool, false);
#if defined(ANDROID)
DECL_GFX_PREF(Once, "gfx.apitrace.enabled", UseApitrace, bool, false);
#endif
#if defined(RELEASE_OR_BETA)
// "Skip" means this is locked to the default value in beta and release.
DECL_GFX_PREF(Skip, "gfx.blocklist.all", BlocklistAll, int32_t, 0);
#else
new file mode 100644
--- /dev/null
+++ b/layout/generic/ScrollAnimationMSDPhysics.cpp
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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 "ScrollAnimationMSDPhysics.h"
+#include "gfxPrefs.h"
+
+using namespace mozilla;
+
+ScrollAnimationMSDPhysics::ScrollAnimationMSDPhysics(const nsPoint& aStartPos)
+ : mStartPos(aStartPos)
+ , mModelX(0, 0, 0, gfxPrefs::SmoothScrollMSDPhysicsRegularSpringConstant(), 1)
+ , mModelY(0, 0, 0, gfxPrefs::SmoothScrollMSDPhysicsRegularSpringConstant(), 1)
+ , mIsFirstIteration(true)
+{
+}
+
+void
+ScrollAnimationMSDPhysics::Update(const TimeStamp& aTime,
+ const nsPoint& aDestination,
+ const nsSize& aCurrentVelocity)
+{
+ double springConstant = ComputeSpringConstant(aTime);
+
+ // mLastSimulatedTime is the most recent time that this animation has been
+ // "observed" at. We don't want to update back to a state in the past, so we
+ // set mStartTime to the more recent of mLastSimulatedTime and aTime.
+ // aTime can be in the past if we're processing an input event whose internal
+ // timestamp is in the past.
+ if (mLastSimulatedTime && aTime < mLastSimulatedTime) {
+ mStartTime = mLastSimulatedTime;
+ } else {
+ mStartTime = aTime;
+ }
+
+ if (!mIsFirstIteration) {
+ mStartPos = PositionAt(mStartTime);
+ }
+
+ mLastSimulatedTime = mStartTime;
+ mDestination = aDestination;
+ mModelX = AxisPhysicsMSDModel(mStartPos.x, aDestination.x,
+ aCurrentVelocity.width, springConstant, 1);
+ mModelY = AxisPhysicsMSDModel(mStartPos.y, aDestination.y,
+ aCurrentVelocity.height, springConstant, 1);
+ mIsFirstIteration = false;
+}
+
+double
+ScrollAnimationMSDPhysics::ComputeSpringConstant(const TimeStamp& aTime)
+{
+ if (!mPreviousEventTime) {
+ mPreviousEventTime = aTime;
+ mPreviousDelta = TimeDuration();
+ return gfxPrefs::SmoothScrollMSDPhysicsMotionBeginSpringConstant();
+ }
+
+ TimeDuration delta = aTime - mPreviousEventTime;
+ TimeDuration previousDelta = mPreviousDelta;
+
+ mPreviousEventTime = aTime;
+ mPreviousDelta = delta;
+
+ double deltaMS = delta.ToMilliseconds();
+ if (deltaMS >= gfxPrefs::SmoothScrollMSDPhysicsContinuousMotionMaxDeltaMS()) {
+ return gfxPrefs::SmoothScrollMSDPhysicsMotionBeginSpringConstant();
+ }
+
+ if (previousDelta &&
+ deltaMS >= gfxPrefs::SmoothScrollMSDPhysicsSlowdownMinDeltaMS() &&
+ deltaMS >= previousDelta.ToMilliseconds() * gfxPrefs::SmoothScrollMSDPhysicsSlowdownMinDeltaRatio()) {
+ // The rate of events has slowed (the time delta between events has
+ // increased) enough that we think that the current scroll motion is coming
+ // to a stop. Use a stiffer spring in order to reach the destination more
+ // quickly.
+ return gfxPrefs::SmoothScrollMSDPhysicsSlowdownSpringConstant();
+ }
+
+ return gfxPrefs::SmoothScrollMSDPhysicsRegularSpringConstant();
+}
+
+void
+ScrollAnimationMSDPhysics::SimulateUntil(const TimeStamp& aTime)
+{
+ if (!mLastSimulatedTime || aTime < mLastSimulatedTime) {
+ return;
+ }
+ TimeDuration delta = aTime - mLastSimulatedTime;
+ mModelX.Simulate(delta);
+ mModelY.Simulate(delta);
+ mLastSimulatedTime = aTime;
+}
+
+nsPoint
+ScrollAnimationMSDPhysics::PositionAt(const TimeStamp& aTime)
+{
+ SimulateUntil(aTime);
+ return nsPoint(NSToCoordRound(mModelX.GetPosition()),
+ NSToCoordRound(mModelY.GetPosition()));
+}
+
+nsSize
+ScrollAnimationMSDPhysics::VelocityAt(const TimeStamp& aTime)
+{
+ SimulateUntil(aTime);
+ return nsSize(NSToCoordRound(mModelX.GetVelocity()),
+ NSToCoordRound(mModelY.GetVelocity()));
+}
new file mode 100644
--- /dev/null
+++ b/layout/generic/ScrollAnimationMSDPhysics.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+#ifndef mozilla_layout_ScrollAnimationMSDPhysics_h_
+#define mozilla_layout_ScrollAnimationMSDPhysics_h_
+
+#include "ScrollAnimationPhysics.h"
+#include "mozilla/layers/AxisPhysicsMSDModel.h"
+
+namespace mozilla {
+
+// This class implements a cubic MSD timing function and automatically
+// adapts the animation duration based on the scrolling rate.
+class ScrollAnimationMSDPhysics : public ScrollAnimationPhysics
+{
+public:
+ typedef mozilla::layers::AxisPhysicsMSDModel AxisPhysicsMSDModel;
+
+ explicit ScrollAnimationMSDPhysics(const nsPoint& aStartPos);
+
+ void Update(const TimeStamp& aTime,
+ const nsPoint& aDestination,
+ const nsSize& aCurrentVelocity) override;
+
+ // Get the velocity at a point in time in nscoords/sec.
+ nsSize VelocityAt(const TimeStamp& aTime) override;
+
+ // Returns the expected scroll position at a given point in time, in app
+ // units, relative to the scroll frame.
+ nsPoint PositionAt(const TimeStamp& aTime) override;
+
+ bool IsFinished(const TimeStamp& aTime) override {
+ SimulateUntil(aTime);
+ return mModelX.IsFinished(1) && mModelY.IsFinished(1);
+ }
+
+protected:
+ double ComputeSpringConstant(const TimeStamp& aTime);
+ void SimulateUntil(const TimeStamp& aTime);
+
+ TimeStamp mPreviousEventTime;
+ TimeDuration mPreviousDelta;
+
+ TimeStamp mStartTime;
+
+ nsPoint mStartPos;
+ nsPoint mDestination;
+ TimeStamp mLastSimulatedTime;
+ AxisPhysicsMSDModel mModelX;
+ AxisPhysicsMSDModel mModelY;
+ bool mIsFirstIteration;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_layout_ScrollAnimationMSDPhysics_h_
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -96,16 +96,17 @@ EXPORTS += [
'nsRubyTextContainerFrame.h',
'nsRubyTextFrame.h',
'nsSplittableFrame.h',
'nsSubDocumentFrame.h',
'nsTextFrameUtils.h',
'nsTextRunTransformations.h',
'RubyUtils.h',
'ScrollAnimationBezierPhysics.h',
+ 'ScrollAnimationMSDPhysics.h',
'ScrollAnimationPhysics.h',
'ScrollbarActivity.h',
'ScrollSnap.h',
'TextDrawTarget.h',
'Visibility.h',
]
EXPORTS.mozilla += [
@@ -173,16 +174,17 @@ UNIFIED_SOURCES += [
'nsTextFrame.cpp',
'nsTextFrameUtils.cpp',
'nsTextRunTransformations.cpp',
'nsVideoFrame.cpp',
'ReflowInput.cpp',
'ReflowOutput.cpp',
'RubyUtils.cpp',
'ScrollAnimationBezierPhysics.cpp',
+ 'ScrollAnimationMSDPhysics.cpp',
'ScrollbarActivity.cpp',
'ScrollSnap.cpp',
'ScrollVelocityQueue.cpp',
'StickyScrollContainer.cpp',
'TextOverflow.cpp',
'ViewportFrame.cpp',
]
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -54,16 +54,17 @@
#include "nsSVGIntegrationUtils.h"
#include "nsIScrollPositionListener.h"
#include "StickyScrollContainer.h"
#include "nsIFrameInlines.h"
#include "gfxPlatform.h"
#include "gfxPrefs.h"
#include "ScrollAnimationPhysics.h"
#include "ScrollAnimationBezierPhysics.h"
+#include "ScrollAnimationMSDPhysics.h"
#include "ScrollSnap.h"
#include "UnitTransforms.h"
#include "nsPluginFrame.h"
#include "nsSliderFrame.h"
#include "mozilla/layers/APZCCallbackHelper.h"
#include <mozilla/layers/AxisPhysicsModel.h>
#include <mozilla/layers/AxisPhysicsMSDModel.h>
#include "mozilla/layers/LayerTransactionChild.h"
@@ -1907,17 +1908,17 @@ private:
}
};
/*
* Calculate duration, possibly dynamically according to events rate and event origin.
* (also maintain previous timestamps - which are only used here).
*/
static ScrollAnimationBezierPhysicsSettings
-ComputeAnimationSettingsForOrigin(nsIAtom *aOrigin)
+ComputeBezierAnimationSettingsForOrigin(nsIAtom *aOrigin)
{
int32_t minMS = 0;
int32_t maxMS = 0;
bool isOriginSmoothnessEnabled = false;
double intervalRatio = 1;
// Default values for all preferences are defined in all.js
static const int32_t kDefaultMinMS = 150, kDefaultMaxMS = 150;
@@ -1967,19 +1968,24 @@ ScrollFrameHelper::AsyncScroll::InitSmoo
}
// 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;
- ScrollAnimationBezierPhysicsSettings settings = ComputeAnimationSettingsForOrigin(mOrigin);
- mAnimationPhysics =
- MakeUnique<ScrollAnimationBezierPhysics>(aInitialPosition, settings);
+ if (gfxPrefs::SmoothScrollMSDPhysicsEnabled()) {
+ mAnimationPhysics = MakeUnique<ScrollAnimationMSDPhysics>(aInitialPosition);
+ } else {
+ ScrollAnimationBezierPhysicsSettings settings =
+ ComputeBezierAnimationSettingsForOrigin(mOrigin);
+ mAnimationPhysics =
+ MakeUnique<ScrollAnimationBezierPhysics>(aInitialPosition, settings);
+ }
}
mRange = aRange;
mAnimationPhysics->Update(aTime, aDestination, aCurrentVelocity);
}
bool
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2805,16 +2805,24 @@ pref("general.smoothScroll.other", true)
// should be longer than scroll events intervals (or else the scroll will stop
// before the next event arrives - we're guessing next interval by averaging recent
// intervals).
// This defines how longer is the duration compared to events interval (percentage)
pref("general.smoothScroll.durationToIntervalRatio", 200);
// These two prefs determine the timing function.
pref("general.smoothScroll.currentVelocityWeighting", "0.25");
pref("general.smoothScroll.stopDecelerationWeighting", "0.4");
+// Alternative smooth scroll physics ("MSD" = Mass-Spring-Damper)
+pref("general.smoothScroll.msdPhysics.enabled", false);
+pref("general.smoothScroll.msdPhysics.continuousMotionMaxDeltaMS", 120);
+pref("general.smoothScroll.msdPhysics.motionBeginSpringConstant", 1250);
+pref("general.smoothScroll.msdPhysics.slowdownMinDeltaMS", 12);
+pref("general.smoothScroll.msdPhysics.slowdownMinDeltaRatio", "1.3");
+pref("general.smoothScroll.msdPhysics.slowdownSpringConstant", 2000);
+pref("general.smoothScroll.msdPhysics.regularSpringConstant", 1000);
pref("profile.confirm_automigration",true);
// profile.migration_behavior determines how the profiles root is set
// 0 - use NS_APP_USER_PROFILES_ROOT_DIR
// 1 - create one based on the NS4.x profile root
// 2 - use, if not empty, profile.migration_directory otherwise same as 0
pref("profile.migration_behavior",0);
pref("profile.migration_directory", "");