Bug 1022825 - Implement Asynchronous Smooth Scrolling on Compositor Thread. r=kats

- Extended nsIScrollableFrame and nsGfxScrollFrame to return destination
  of smooth scrolls which are to be animated on the compositor thread.
- Added apz.smooth_scroll_repaint_interval preference.
- Implemented AsyncPanZoomController::PanZoomState::SMOOTH_MSD_SCROLL state
  and AsyncPanZoomController::SmoothScrollAnimation class to animate smooth
  scroll animations on the compositor thread.
- Extended FrameMetrics to report requests for smooth scrolls to be animated
  on the compositor thread and their corresponding destination positions.
- AsyncPanZoomController now checks FrameMetrics for requests to perform
  smooth scrolling on the compositor thread.  It will ensure that they
  are cancelled as needed by mousewheel, touchpanel, keyboard, and
  CSSOM-View instant scrolling DOM methods.
- The layout/generic/test/test_scroll_behavior.html mochitest has been
  commented as depending on Bug 1062609 before being enabled for APZ.
This commit is contained in:
Kearwood (Kip) Gilbert 2014-07-10 11:52:40 -07:00
parent b7556664b4
commit 5f59b02c90
14 changed files with 336 additions and 28 deletions

View File

@ -51,6 +51,7 @@ pref("layers.componentalpha.enabled", false);
pref("apz.touch_start_tolerance", "0.1"); // dpi * tolerance = pixel threshold
pref("apz.pan_repaint_interval", 50); // prefer 20 fps
pref("apz.fling_repaint_interval", 50); // prefer 20 fps
pref("apz.smooth_scroll_repaint_interval", 50); // prefer 20 fps
pref("apz.fling_stopped_threshold", "0.2");
pref("apz.x_skate_size_multiplier", "2.5");
pref("apz.y_skate_size_multiplier", "2.5");

View File

@ -754,6 +754,8 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
WriteParam(aMsg, aParam.mScrollGeneration);
WriteParam(aMsg, aParam.mTransformScale);
WriteParam(aMsg, aParam.mBackgroundColor);
WriteParam(aMsg, aParam.mDoSmoothScroll);
WriteParam(aMsg, aParam.mSmoothScrollOffset);
WriteParam(aMsg, aParam.GetContentDescription());
}
@ -793,6 +795,8 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
ReadParam(aMsg, aIter, &aResult->mScrollGeneration) &&
ReadParam(aMsg, aIter, &aResult->mTransformScale) &&
ReadParam(aMsg, aIter, &aResult->mBackgroundColor) &&
ReadParam(aMsg, aIter, &aResult->mDoSmoothScroll) &&
ReadParam(aMsg, aIter, &aResult->mSmoothScrollOffset) &&
ReadContentDescription(aMsg, aIter, aResult));
}
};

View File

@ -90,6 +90,8 @@ public:
, mZoom(1)
, mUpdateScrollOffset(false)
, mScrollGeneration(0)
, mDoSmoothScroll(false)
, mSmoothScrollOffset(0, 0)
, mRootCompositionSize(0, 0)
, mDisplayPortMargins(0, 0, 0, 0)
, mUseDisplayPortMargins(false)
@ -121,9 +123,11 @@ public:
mScrollId == aOther.mScrollId &&
mScrollParentId == aOther.mScrollParentId &&
mScrollOffset == aOther.mScrollOffset &&
mSmoothScrollOffset == aOther.mSmoothScrollOffset &&
mHasScrollgrab == aOther.mHasScrollgrab &&
mUpdateScrollOffset == aOther.mUpdateScrollOffset &&
mBackgroundColor == aOther.mBackgroundColor;
mBackgroundColor == aOther.mBackgroundColor &&
mDoSmoothScroll == aOther.mDoSmoothScroll;
}
bool operator!=(const FrameMetrics& aOther) const
{
@ -241,6 +245,13 @@ public:
mScrollGeneration = aOther.mScrollGeneration;
}
void CopySmoothScrollInfoFrom(const FrameMetrics& aOther)
{
mSmoothScrollOffset = aOther.mSmoothScrollOffset;
mScrollGeneration = aOther.mScrollGeneration;
mDoSmoothScroll = aOther.mDoSmoothScroll;
}
// Make a copy of this FrameMetrics object which does not have any pointers
// to heap-allocated memory (i.e. is Plain Old Data, or 'POD'), and is
// therefore safe to be placed into shared memory.
@ -382,6 +393,16 @@ public:
return mScrollOffset;
}
void SetSmoothScrollOffset(const CSSPoint& aSmoothScrollDestination)
{
mSmoothScrollOffset = aSmoothScrollDestination;
}
const CSSPoint& GetSmoothScrollOffset() const
{
return mSmoothScrollOffset;
}
void SetZoom(const CSSToScreenScale& aZoom)
{
mZoom = aZoom;
@ -398,11 +419,22 @@ public:
mScrollGeneration = aScrollGeneration;
}
void SetSmoothScrollOffsetUpdated(int32_t aScrollGeneration)
{
mDoSmoothScroll = true;
mScrollGeneration = aScrollGeneration;
}
bool GetScrollOffsetUpdated() const
{
return mUpdateScrollOffset;
}
bool GetDoSmoothScroll() const
{
return mDoSmoothScroll;
}
uint32_t GetScrollGeneration() const
{
return mScrollGeneration;
@ -543,6 +575,11 @@ private:
// The scroll generation counter used to acknowledge the scroll offset update.
uint32_t mScrollGeneration;
// When mDoSmoothScroll, the scroll offset should be animated to
// smoothly transition to mScrollOffset rather than be updated instantly.
bool mDoSmoothScroll;
CSSPoint mSmoothScrollOffset;
// The size of the root scrollable's composition bounds, but in local CSS pixels.
CSSSize mRootCompositionSize;

View File

@ -121,6 +121,9 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m,
AppendToString(aStream, m.mCompositionBounds, "{ cb=");
AppendToString(aStream, m.mScrollableRect, " sr=");
AppendToString(aStream, m.GetScrollOffset(), " s=");
if (m.GetDoSmoothScroll()) {
AppendToString(aStream, m.GetSmoothScrollOffset(), " ss=");
}
AppendToString(aStream, m.mDisplayPort, " dp=");
AppendToString(aStream, m.mCriticalDisplayPort, " cdp=");
AppendToString(aStream, m.GetBackgroundColor(), " color=");
@ -139,8 +142,9 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m,
m.mDevPixelsPerCSSPixel.scale, m.mResolution.scale,
m.mCumulativeResolution.scale, m.GetZoom().scale,
m.mTransformScale.scale).get();
aStream << nsPrintfCString(" u=(%d %lu)",
m.GetScrollOffsetUpdated(), m.GetScrollGeneration()).get();
aStream << nsPrintfCString(" u=(%d %d %lu)",
m.GetScrollOffsetUpdated(), m.GetDoSmoothScroll(),
m.GetScrollGeneration()).get();
AppendToString(aStream, m.GetScrollParentId(), " p=");
aStream << nsPrintfCString(" i=(%ld %lld) }",
m.GetPresShellId(), m.GetScrollId()).get();

View File

@ -42,6 +42,8 @@
#include "mozilla/layers/APZCTreeManager.h" // for ScrollableLayerGuid
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
#include "mozilla/layers/Axis.h" // for AxisX, AxisY, Axis, etc
#include "mozilla/layers/AxisPhysicsModel.h" // for AxisPhysicsModel
#include "mozilla/layers/AxisPhysicsMSDModel.h" // for AxisPhysicsMSDModel
#include "mozilla/layers/LayerTransactionParent.h" // for LayerTransactionParent
#include "mozilla/layers/PCompositorParent.h" // for PCompositorParent
#include "mozilla/layers/TaskThrottler.h" // for TaskThrottler
@ -270,6 +272,11 @@ typedef mozilla::gfx::Matrix4x4 Matrix4x4;
* Maximum amount of time while panning before sending a viewport change. This
* will asynchronously repaint the page. It is also forced when panning stops.
*
* "apz.smooth_scroll_repaint_interval"
* Maximum amount of time doing a smooth scroll before sending a viewport
* change. This will asynchronously repaint the page.
* Units: milliseconds
*
* "apz.test.logging_enabled"
* Enable logging of APZ test data (see bug 961289).
*
@ -555,6 +562,8 @@ public:
&AsyncPanZoomController::HandleFlingOverscroll,
velocity,
mOverscrollHandoffChain));
return false;
}
}
@ -663,6 +672,119 @@ private:
AsyncPanZoomController& mApzc;
};
class SmoothScrollAnimation : public AsyncPanZoomAnimation {
public:
SmoothScrollAnimation(AsyncPanZoomController& aApzc,
const nsPoint &aInitialPosition,
const nsPoint &aInitialVelocity,
const nsPoint& aDestination, double aSpringConstant,
double aDampingRatio)
: AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(
gfxPrefs::APZSmoothScrollRepaintInterval()))
, mApzc(aApzc)
, mXAxisModel(aInitialPosition.x, aDestination.x, aInitialVelocity.x,
aSpringConstant, aDampingRatio)
, mYAxisModel(aInitialPosition.y, aDestination.y, aInitialVelocity.y,
aSpringConstant, aDampingRatio)
{
}
/**
* Advances a smooth scroll simulation based on the time passed in |aDelta|.
* This should be called whenever sampling the content transform for this
* frame. Returns true if the smooth scroll should be advanced by one frame,
* or false if the smooth scroll has ended.
*/
bool Sample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta) {
if (aDelta.ToMilliseconds() <= 0) {
return true;
}
if (mXAxisModel.IsFinished() && mYAxisModel.IsFinished()) {
return false;
}
mXAxisModel.Simulate(aDelta);
mYAxisModel.Simulate(aDelta);
CSSPoint position = CSSPoint::FromAppUnits(nsPoint(mXAxisModel.GetPosition(),
mYAxisModel.GetPosition()));
CSSPoint css_velocity = CSSPoint::FromAppUnits(nsPoint(mXAxisModel.GetVelocity(),
mYAxisModel.GetVelocity()));
// Convert from points/second to points/ms
ScreenPoint velocity = ScreenPoint(css_velocity.x, css_velocity.y) / 1000.0f;
// Keep the velocity updated for the Axis class so that any animations
// chained off of the smooth scroll will inherit it.
if (mXAxisModel.IsFinished()) {
mApzc.mX.SetVelocity(0);
} else {
mApzc.mX.SetVelocity(velocity.x);
}
if (mYAxisModel.IsFinished()) {
mApzc.mY.SetVelocity(0);
} else {
mApzc.mY.SetVelocity(velocity.y);
}
// If we overscroll, hand off to a fling animation that will complete the
// spring back.
float displacement_x = position.x - mApzc.mX.GetOrigin();
float displacement_y = position.y - mApzc.mY.GetOrigin();
CSSPoint overscroll;
CSSPoint adjustedOffset;
mApzc.mX.AdjustDisplacement(displacement_x, adjustedOffset.x, overscroll.x);
mApzc.mY.AdjustDisplacement(displacement_y, adjustedOffset.y, overscroll.y);
aFrameMetrics.ScrollBy(adjustedOffset);
// The smooth scroll may have caused us to reach the end of our scroll range.
// This can happen if either the layout.css.scroll-behavior.damping-ratio
// preference is set to less than 1 (underdamped) or if a smooth scroll
// inherits velocity from a fling gesture.
if (!IsZero(overscroll)) {
// Hand off a fling with the remaining momentum to the next APZC in the
// overscroll handoff chain.
// We may have reached the end of the scroll range along one axis but
// not the other. In such a case we only want to hand off the relevant
// component of the fling.
if (FuzzyEqualsAdditive(overscroll.x, 0.0f, COORDINATE_EPSILON)) {
velocity.x = 0;
} else if (FuzzyEqualsAdditive(overscroll.y, 0.0f, COORDINATE_EPSILON)) {
velocity.y = 0;
}
// To hand off the fling, we attempt to find a target APZC and start a new
// fling with the same velocity on that APZC. For simplicity, the actual
// overscroll of the current sample is discarded rather than being handed
// off. The compositor should sample animations sufficiently frequently
// that this is not noticeable. The target APZC is chosen by seeing if
// there is an APZC further in the handoff chain which is pannable; if
// there isn't, we take the new fling ourselves, entering an overscrolled
// state.
// Note: APZC is holding mMonitor, so directly calling
// HandleSmoothScrollOverscroll() (which acquires the tree lock) would violate
// the lock ordering. Instead we schedule HandleSmoothScrollOverscroll() to be
// called after mMonitor is released.
mDeferredTasks.append(NewRunnableMethod(&mApzc,
&AsyncPanZoomController::HandleSmoothScrollOverscroll,
velocity));
return false;
}
return true;
}
private:
AsyncPanZoomController& mApzc;
AxisPhysicsMSDModel mXAxisModel, mYAxisModel;
};
void
AsyncPanZoomController::SetFrameTime(const TimeStamp& aTime) {
sFrameTime = aTime;
@ -1019,6 +1141,7 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
switch (mState) {
case FLING:
case ANIMATING_ZOOM:
case SMOOTH_SCROLL:
CurrentTouchBlock()->GetOverscrollHandoffChain()->CancelAnimations();
// Fall through.
case NOTHING: {
@ -1053,6 +1176,7 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
APZC_LOG("%p got a touch-move in state %d\n", this, mState);
switch (mState) {
case FLING:
case SMOOTH_SCROLL:
case NOTHING:
case ANIMATING_ZOOM:
// May happen if the user double-taps and drags without lifting after the
@ -1127,6 +1251,7 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
NS_WARNING("Received impossible touch end in OnTouchEnd.");
// Fall through.
case ANIMATING_ZOOM:
case SMOOTH_SCROLL:
case NOTHING:
// May happen if the user double-taps and drags without lifting after the
// second tap. Ignore if this happens.
@ -1375,6 +1500,11 @@ nsEventStatus AsyncPanZoomController::OnPanCancelled(const PanGestureInput& aEve
nsEventStatus AsyncPanZoomController::OnPanBegin(const PanGestureInput& aEvent) {
APZC_LOG("%p got a pan-begin in state %d\n", this, mState);
if (mState == SMOOTH_SCROLL) {
// SMOOTH_SCROLL scrolls are cancelled by pan gestures.
CancelAnimation();
}
mPanGestureState = MakeUnique<InputBlockState>(BuildOverscrollHandoffChain());
mX.StartTouch(aEvent.mPanStartPoint.x, aEvent.mTime);
@ -1397,6 +1527,20 @@ nsEventStatus AsyncPanZoomController::OnPanBegin(const PanGestureInput& aEvent)
nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent, bool aFingersOnTouchpad) {
APZC_LOG("%p got a pan-pan in state %d\n", this, mState);
if (mState == SMOOTH_SCROLL) {
if (aEvent.mType == PanGestureInput::PANGESTURE_MOMENTUMPAN) {
// When a SMOOTH_SCROLL scroll is being processed on a frame, mouse
// wheel and trackpad momentum scroll position updates will not cancel the
// SMOOTH_SCROLL scroll animations, enabling scripts that depend on
// them to be responsive without forcing the user to wait for the momentum
// scrolling to completely stop.
return nsEventStatus_eConsumeNoDefault;
} else {
// SMOOTH_SCROLL scrolls are cancelled by pan gestures.
CancelAnimation();
}
}
// We need to update the axis velocity in order to get a useful display port
// size and position. We need to do so even if this is a momentum pan (i.e.
// aFingersOnTouchpad == false); in that case the "with touch" part is not
@ -1430,6 +1574,11 @@ nsEventStatus AsyncPanZoomController::OnPanEnd(const PanGestureInput& aEvent) {
nsEventStatus AsyncPanZoomController::OnPanMomentumStart(const PanGestureInput& aEvent) {
APZC_LOG("%p got a pan-momentumstart in state %d\n", this, mState);
if (mState == SMOOTH_SCROLL) {
// SMOOTH_SCROLL scrolls are cancelled by pan gestures.
CancelAnimation();
}
mPanGestureState = MakeUnique<InputBlockState>(BuildOverscrollHandoffChain());
return nsEventStatus_eConsumeNoDefault;
@ -1846,6 +1995,28 @@ void AsyncPanZoomController::HandleFlingOverscroll(const ScreenPoint& aVelocity,
}
}
void AsyncPanZoomController::HandleSmoothScrollOverscroll(const ScreenPoint& aVelocity) {
// We must call BuildOverscrollHandoffChain from this deferred callback
// function in order to avoid a deadlock when acquiring the tree lock.
HandleFlingOverscroll(aVelocity, BuildOverscrollHandoffChain());
}
void AsyncPanZoomController::StartSmoothScroll() {
SetState(SMOOTH_SCROLL);
nsPoint initialPosition = CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset());
// Cast velocity from ScreenPoints/ms to CSSPoints/ms then convert to
// appunits/second
nsPoint initialVelocity = CSSPoint::ToAppUnits(CSSPoint(mX.GetVelocity(),
mY.GetVelocity())) * 1000.0f;
nsPoint destination = CSSPoint::ToAppUnits(mFrameMetrics.GetSmoothScrollOffset());
StartAnimation(new SmoothScrollAnimation(*this,
initialPosition, initialVelocity,
destination,
gfxPrefs::ScrollBehaviorSpringConstant(),
gfxPrefs::ScrollBehaviorDampingRatio()));
}
void AsyncPanZoomController::StartSnapBack() {
SetState(SNAP_BACK);
StartAnimation(new OverscrollSnapBackAnimation(*this));
@ -2434,6 +2605,9 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
needContentRepaint = true;
}
} else {
bool smoothScrollRequested = aLayerMetrics.GetDoSmoothScroll()
&& (aLayerMetrics.GetScrollGeneration() != mFrameMetrics.GetScrollGeneration());
// If we're not taking the aLayerMetrics wholesale we still need to pull
// in some things into our local mFrameMetrics because these things are
// determined by Gecko and our copy in mFrameMetrics may be stale.
@ -2478,6 +2652,23 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
// last thing we know was painted by Gecko.
mLastDispatchedPaintMetrics = aLayerMetrics;
}
if (smoothScrollRequested) {
// A smooth scroll has been requested for animation on the compositor
// thread. This flag will be reset by the main thread when it receives
// the scroll update acknowledgement.
APZC_LOG("%p smooth scrolling from %s to %s\n", this,
Stringify(mFrameMetrics.GetScrollOffset()).c_str(),
Stringify(aLayerMetrics.GetSmoothScrollOffset()).c_str());
mFrameMetrics.CopySmoothScrollInfoFrom(aLayerMetrics);
CancelAnimation();
mLastDispatchedPaintMetrics = aLayerMetrics;
StartSmoothScroll();
scrollOffsetUpdated = true; // Ensure that AcknowledgeScrollUpdate is called
}
}
if (scrollOffsetUpdated) {

View File

@ -344,6 +344,8 @@ protected:
PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */
ANIMATING_ZOOM, /* animated zoom to a new rect */
SNAP_BACK, /* snap-back animation to relieve overscroll */
SMOOTH_SCROLL, /* Smooth scrolling to destination. Used by
CSSOM-View smooth scroll-behavior */
};
// Protected destructor, to discourage deletion outside of Release():
@ -799,7 +801,8 @@ private:
/* ===================================================================
* The functions and members in this section are used to manage
* fling animations and handling overscroll during a fling.
* fling animations, smooth scroll animations, and overscroll
* during a fling or smooth scroll.
*/
public:
/**
@ -818,6 +821,7 @@ public:
private:
friend class FlingAnimation;
friend class OverscrollSnapBackAnimation;
friend class SmoothScrollAnimation;
// The initial velocity of the most recent fling.
ScreenPoint mLastFlingVelocity;
// The time at which the most recent fling started.
@ -831,6 +835,8 @@ private:
void HandleFlingOverscroll(const ScreenPoint& aVelocity,
const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain);
void HandleSmoothScrollOverscroll(const ScreenPoint& aVelocity);
// Helper function used by TakeOverFling() and HandleFlingOverscroll().
void AcceptFling(const ScreenPoint& aVelocity,
const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
@ -840,6 +846,7 @@ private:
// Start a snap-back animation to relieve overscroll.
void StartSnapBack();
void StartSmoothScroll();
/* ===================================================================
* The functions and members in this section are used to build a tree

View File

@ -86,8 +86,10 @@ ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint, bool& aSuccess
// Also if the scrollable frame got a scroll request from something other than us
// since the last layers update, then we don't want to push our scroll request
// because we'll clobber that one, which is bad.
if (!aFrame->IsProcessingAsyncScroll() &&
(!aFrame->OriginOfLastScroll() || aFrame->OriginOfLastScroll() == nsGkAtoms::apz)) {
bool scrollInProgress = aFrame->IsProcessingAsyncScroll()
|| (aFrame->LastScrollOrigin() && aFrame->LastScrollOrigin() != nsGkAtoms::apz)
|| aFrame->LastSmoothScrollOrigin();
if (!scrollInProgress) {
aFrame->ScrollToCSSPixelsApproximate(targetScrollPosition, nsGkAtoms::apz);
geckoScrollPosition = CSSPoint::FromAppUnits(aFrame->GetScrollPosition());
aSuccessOut = true;
@ -287,7 +289,7 @@ public:
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(mScrollId);
if (sf) {
sf->ResetOriginIfScrollAtGeneration(mScrollGeneration);
sf->ResetScrollInfoIfGeneration(mScrollGeneration);
}
return NS_OK;

View File

@ -158,6 +158,7 @@ private:
DECL_GFX_PREF(Live, "apz.overscroll.snap_back.mass", APZOverscrollSnapBackMass, float, 1000.0f);
DECL_GFX_PREF(Live, "apz.pan_repaint_interval", APZPanRepaintInterval, int32_t, 250);
DECL_GFX_PREF(Live, "apz.printtree", APZPrintTree, bool, false);
DECL_GFX_PREF(Live, "apz.smooth_scroll_repaint_interval", APZSmoothScrollRepaintInterval, int32_t, 75);
DECL_GFX_PREF(Live, "apz.subframe.enabled", APZSubframeEnabled, bool, false);
DECL_GFX_PREF(Once, "apz.test.logging_enabled", APZTestLoggingEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.touch_start_tolerance", APZTouchStartTolerance, float, 1.0f/4.5f);

View File

@ -699,13 +699,20 @@ nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame* aForFrame,
nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
metrics.SetScrollOffset(CSSPoint::FromAppUnits(scrollPosition));
nsPoint smoothScrollPosition = scrollableFrame->LastScrollDestination();
metrics.SetSmoothScrollOffset(CSSPoint::FromAppUnits(smoothScrollPosition));
// If the frame was scrolled since the last layers update, and by
// something other than the APZ code, we want to tell the APZ to update
// its scroll offset.
nsIAtom* originOfLastScroll = scrollableFrame->OriginOfLastScroll();
if (originOfLastScroll && originOfLastScroll != nsGkAtoms::apz) {
nsIAtom* lastScrollOrigin = scrollableFrame->LastScrollOrigin();
if (lastScrollOrigin && lastScrollOrigin != nsGkAtoms::apz) {
metrics.SetScrollOffsetUpdated(scrollableFrame->CurrentScrollGeneration());
}
nsIAtom* lastSmoothScrollOrigin = scrollableFrame->LastSmoothScrollOrigin();
if (lastSmoothScrollOrigin) {
metrics.SetSmoothScrollOffsetUpdated(scrollableFrame->CurrentScrollGeneration());
}
}
metrics.SetScrollId(scrollId);

View File

@ -1824,7 +1824,8 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter,
, mOuter(aOuter)
, mAsyncScroll(nullptr)
, mAsyncSmoothMSDScroll(nullptr)
, mOriginOfLastScroll(nsGkAtoms::other)
, mLastScrollOrigin(nsGkAtoms::other)
, mLastSmoothScrollOrigin(nullptr)
, mScrollGeneration(++sScrollGenerationCounter)
, mDestination(0, 0)
, mScrollPosAtLastPaint(0, 0)
@ -2053,6 +2054,19 @@ ScrollFrameHelper::ScrollToWithOrigin(nsPoint aScrollPosition,
mAsyncScroll = nullptr;
}
if (gfxPrefs::AsyncPanZoomEnabled()) {
// The animation will be handled in the compositor, pass the
// information needed to start the animation and skip the main-thread
// animation for this scroll.
mLastSmoothScrollOrigin = aOrigin;
mScrollGeneration = ++sScrollGenerationCounter;
// Schedule a paint to ensure that the frame metrics get updated on
// the compositor thread.
mOuter->SchedulePaint();
return;
}
mAsyncSmoothMSDScroll =
new AsyncSmoothMSDScroll(GetScrollPosition(), mDestination,
currentVelocity, GetScrollRangeForClamping(),
@ -2404,7 +2418,8 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOri
nsPoint oldScrollFramePos = mScrolledFrame->GetPosition();
// Update frame position for scrolling
mScrolledFrame->SetPosition(mScrollPort.TopLeft() - pt);
mOriginOfLastScroll = aOrigin;
mLastScrollOrigin = aOrigin;
mLastSmoothScrollOrigin = nullptr;
mScrollGeneration = ++sScrollGenerationCounter;
// We pass in the amount to move visually

View File

@ -322,11 +322,14 @@ public:
void HandleScrollbarStyleSwitching();
nsIAtom* OriginOfLastScroll() const { return mOriginOfLastScroll; }
nsIAtom* LastScrollOrigin() const { return mLastScrollOrigin; }
nsIAtom* LastSmoothScrollOrigin() const { return mLastSmoothScrollOrigin; }
uint32_t CurrentScrollGeneration() const { return mScrollGeneration; }
void ResetOriginIfScrollAtGeneration(uint32_t aGeneration) {
nsPoint LastScrollDestination() const { return mDestination; }
void ResetScrollInfoIfGeneration(uint32_t aGeneration) {
if (aGeneration == mScrollGeneration) {
mOriginOfLastScroll = nullptr;
mLastScrollOrigin = nullptr;
mLastSmoothScrollOrigin = nullptr;
}
}
bool WantAsyncScroll() const;
@ -367,7 +370,8 @@ public:
nsRefPtr<AsyncSmoothMSDScroll> mAsyncSmoothMSDScroll;
nsRefPtr<ScrollbarActivity> mScrollbarActivity;
nsTArray<nsIScrollPositionListener*> mListeners;
nsIAtom* mOriginOfLastScroll;
nsIAtom* mLastScrollOrigin;
nsIAtom* mLastSmoothScrollOrigin;
uint32_t mScrollGeneration;
nsRect mScrollPort;
// Where we're currently scrolling to, if we're scrolling asynchronously.
@ -707,14 +711,20 @@ public:
virtual nsRect ExpandRectToNearlyVisible(const nsRect& aRect) const MOZ_OVERRIDE {
return mHelper.ExpandRectToNearlyVisible(aRect);
}
virtual nsIAtom* OriginOfLastScroll() MOZ_OVERRIDE {
return mHelper.OriginOfLastScroll();
virtual nsIAtom* LastScrollOrigin() MOZ_OVERRIDE {
return mHelper.LastScrollOrigin();
}
virtual nsIAtom* LastSmoothScrollOrigin() MOZ_OVERRIDE {
return mHelper.LastSmoothScrollOrigin();
}
virtual uint32_t CurrentScrollGeneration() MOZ_OVERRIDE {
return mHelper.CurrentScrollGeneration();
}
virtual void ResetOriginIfScrollAtGeneration(uint32_t aGeneration) MOZ_OVERRIDE {
mHelper.ResetOriginIfScrollAtGeneration(aGeneration);
virtual nsPoint LastScrollDestination() MOZ_OVERRIDE {
return mHelper.LastScrollDestination();
}
virtual void ResetScrollInfoIfGeneration(uint32_t aGeneration) MOZ_OVERRIDE {
mHelper.ResetScrollInfoIfGeneration(aGeneration);
}
virtual bool WantAsyncScroll() const MOZ_OVERRIDE {
return mHelper.WantAsyncScroll();
@ -1053,14 +1063,20 @@ public:
virtual nsRect ExpandRectToNearlyVisible(const nsRect& aRect) const MOZ_OVERRIDE {
return mHelper.ExpandRectToNearlyVisible(aRect);
}
virtual nsIAtom* OriginOfLastScroll() MOZ_OVERRIDE {
return mHelper.OriginOfLastScroll();
virtual nsIAtom* LastScrollOrigin() MOZ_OVERRIDE {
return mHelper.LastScrollOrigin();
}
virtual nsIAtom* LastSmoothScrollOrigin() MOZ_OVERRIDE {
return mHelper.LastSmoothScrollOrigin();
}
virtual uint32_t CurrentScrollGeneration() MOZ_OVERRIDE {
return mHelper.CurrentScrollGeneration();
}
virtual void ResetOriginIfScrollAtGeneration(uint32_t aGeneration) MOZ_OVERRIDE {
mHelper.ResetOriginIfScrollAtGeneration(aGeneration);
virtual nsPoint LastScrollDestination() MOZ_OVERRIDE {
return mHelper.LastScrollDestination();
}
virtual void ResetScrollInfoIfGeneration(uint32_t aGeneration) MOZ_OVERRIDE {
mHelper.ResetScrollInfoIfGeneration(aGeneration);
}
virtual bool WantAsyncScroll() const MOZ_OVERRIDE {
return mHelper.WantAsyncScroll();

View File

@ -330,21 +330,42 @@ public:
*/
virtual nsRect ExpandRectToNearlyVisible(const nsRect& aRect) const = 0;
/**
* Returns the origin passed in to the last ScrollToImpl call that took
* effect.
* Returns the origin that triggered the last instant scroll. Will equal
* nsGkAtoms::apz when the compositor's replica frame metrics includes the
* latest instant scroll.
*/
virtual nsIAtom* OriginOfLastScroll() = 0;
virtual nsIAtom* LastScrollOrigin() = 0;
/**
* Returns the origin that triggered the last smooth scroll.
* Will equal nsGkAtoms::apz when the compositor's replica frame
* metrics includes the latest smooth scroll. The compositor will always
* perform an instant scroll prior to instantiating any smooth scrolls
* if LastScrollOrigin and LastSmoothScrollOrigin indicate that
* an instant scroll and a smooth scroll have occurred since the last
* replication of the frame metrics.
*
* This is set to nullptr to when the compositor thread acknowledges that
* the smooth scroll has been started. If the smooth scroll has been stomped
* by an instant scroll before the smooth scroll could be started by the
* compositor, this is set to nullptr to clear the smooth scroll.
*/
virtual nsIAtom* LastSmoothScrollOrigin() = 0;
/**
* Returns the current generation counter for the scroll. This counter
* increments every time the scroll position is set.
*/
virtual uint32_t CurrentScrollGeneration() = 0;
/**
* LastScrollDestination returns the destination of the most recently
* requested smooth scroll animation.
*/
virtual nsPoint LastScrollDestination() = 0;
/**
* Clears the "origin of last scroll" property stored in this frame, if
* the generation counter passed in matches the current scroll generation
* counter.
*/
virtual void ResetOriginIfScrollAtGeneration(uint32_t aGeneration) = 0;
virtual void ResetScrollInfoIfGeneration(uint32_t aGeneration) = 0;
/**
* Determine whether it is desirable to be able to asynchronously scroll this
* scroll frame.

View File

@ -123,7 +123,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1
[test_plugin_position.xhtml]
skip-if = e10s
[test_scroll_behavior.html]
skip-if = e10s || buildapp == 'b2g' #Bug 1022825 will enable this for APZ and e10s
skip-if = e10s || buildapp == 'b2g' # Bug 1062609
[test_selection_expanding.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' # b2g(mouse selection not working) b2g-debug(mouse selection not working) b2g-desktop(mouse selection not working)
support-files = selection_expanding_xbl.xml

View File

@ -480,12 +480,14 @@ pref("apz.zoom_animation_duration_ms", 250);
// Layerize scrollable subframes to allow async panning
pref("apz.subframe.enabled", true);
pref("apz.fling_repaint_interval", 16);
pref("apz.smooth_scroll_repaint_interval", 16);
pref("apz.pan_repaint_interval", 16);
pref("apz.x_skate_size_multiplier", "2.5");
pref("apz.y_skate_size_multiplier", "3.5");
#else
pref("apz.subframe.enabled", false);
pref("apz.fling_repaint_interval", 75);
pref("apz.smooth_scroll_repaint_interval", 75);
pref("apz.pan_repaint_interval", 250);
pref("apz.x_skate_size_multiplier", "1.5");
pref("apz.y_skate_size_multiplier", "2.5");