Bug 1375949 - Delay application of async scroll offset by one composite, to give content a chance to remain in sync. r=kats

With this in place, scroll-linked effects will remain in sync with async
scrolling if they can be processed and painted within the frame budget.

This change is currently behind a pref that's off by default.

MozReview-Commit-ID: 6GEJTKZh6ON

--HG--
extra : rebase_source : 534bf15ef1c5ca26e1dc0d7eb298063b80aa9dd3
This commit is contained in:
Botond Ballo 2017-07-05 19:17:14 -04:00
Родитель 8e4f219cfd
Коммит a01f110229
4 изменённых файлов: 84 добавлений и 7 удалений

Просмотреть файл

@ -273,6 +273,13 @@ typedef GenericFlingAnimation FlingAnimation;
* NOTE: Should not be set to anything
* other than 0.0 for Android except for tests to disable flings.
*
* \li\b apz.frame_delay.enabled
* If this is set to true, changes to the async scroll offset and async zoom
* will not be immediately reflected in GetCurrentAsyncTransform() when called
* with |AsyncTransformConsumer::eForCompositing|. Rather, the transform will
* reflect the value of the async scroll offset and async zoom at the last time
* SampleCompositedAsyncTransform() was called.
*
* \li\b apz.max_velocity_inches_per_ms
* Maximum velocity. Velocity will be capped at this value if a faster fling
* occurs. Negative values indicate unlimited velocity.\n
@ -3218,6 +3225,12 @@ bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
if (mLastSampleTime == aSampleTime) {
return false;
}
// Sample the composited async transform once per composite. Note that we
// call this after the |mLastSampleTime == aSampleTime| check, to ensure
// it's only called once per APZC on each composite.
SampleCompositedAsyncTransform();
TimeDuration sampleTimeDelta = aSampleTime - mLastSampleTime;
mLastSampleTime = aSampleTime;
@ -3319,8 +3332,8 @@ AsyncPanZoomController::GetCurrentAsyncScrollOffset(AsyncTransformConsumer aMode
return mLastContentPaintMetrics.GetScrollOffset() * mLastContentPaintMetrics.GetZoom();
}
return (mFrameMetrics.GetScrollOffset() + mTestAsyncScrollOffset)
* mFrameMetrics.GetZoom() * mTestAsyncZoom.scale;
return (GetEffectiveScrollOffset(aMode) + mTestAsyncScrollOffset)
* GetEffectiveZoom(aMode) * mTestAsyncZoom.scale;
}
CSSPoint
@ -3331,7 +3344,7 @@ AsyncPanZoomController::GetCurrentAsyncScrollOffsetInCssPixels(AsyncTransformCon
return mLastContentPaintMetrics.GetScrollOffset();
}
return mFrameMetrics.GetScrollOffset() + mTestAsyncScrollOffset;
return GetEffectiveScrollOffset(aMode) + mTestAsyncScrollOffset;
}
AsyncTransform
@ -3348,7 +3361,7 @@ AsyncPanZoomController::GetCurrentAsyncTransform(AsyncTransformConsumer aMode) c
lastPaintScrollOffset = mLastContentPaintMetrics.GetScrollOffset();
}
CSSPoint currentScrollOffset = mFrameMetrics.GetScrollOffset() +
CSSPoint currentScrollOffset = GetEffectiveScrollOffset(aMode) +
mTestAsyncScrollOffset;
// If checkerboarding has been disallowed, clamp the scroll position to stay
@ -3369,14 +3382,44 @@ AsyncPanZoomController::GetCurrentAsyncTransform(AsyncTransformConsumer aMode) c
}
}
ParentLayerPoint translation = (currentScrollOffset - lastPaintScrollOffset)
* mFrameMetrics.GetZoom() * mTestAsyncZoom.scale;
CSSToParentLayerScale2D effectiveZoom = GetEffectiveZoom(aMode);
ParentLayerPoint translation = (currentScrollOffset - lastPaintScrollOffset)
* effectiveZoom * mTestAsyncZoom.scale;
LayerToParentLayerScale compositedAsyncZoom =
(effectiveZoom / mFrameMetrics.LayersPixelsPerCSSPixel()).ToScaleFactor();
return AsyncTransform(
LayerToParentLayerScale(mFrameMetrics.GetAsyncZoom().scale * mTestAsyncZoom.scale),
LayerToParentLayerScale(compositedAsyncZoom.scale * mTestAsyncZoom.scale),
-translation);
}
CSSPoint
AsyncPanZoomController::GetEffectiveScrollOffset(AsyncTransformConsumer aMode) const
{
if (gfxPrefs::APZFrameDelayEnabled() && aMode == eForCompositing) {
return mCompositedScrollOffset;
}
return mFrameMetrics.GetScrollOffset();
}
CSSToParentLayerScale2D
AsyncPanZoomController::GetEffectiveZoom(AsyncTransformConsumer aMode) const
{
if (gfxPrefs::APZFrameDelayEnabled() && aMode == eForCompositing) {
return mCompositedZoom;
}
return mFrameMetrics.GetZoom();
}
void
AsyncPanZoomController::SampleCompositedAsyncTransform()
{
ReentrantMonitorAutoEnter lock(mMonitor);
mCompositedScrollOffset = mFrameMetrics.GetScrollOffset();
mCompositedZoom = mFrameMetrics.GetZoom();
}
AsyncTransformComponentMatrix
AsyncPanZoomController::GetCurrentAsyncTransformWithOverscroll(AsyncTransformConsumer aMode) const
{
@ -3628,6 +3671,9 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
mExpectedGeckoMetrics = aLayerMetrics;
ShareCompositorFrameMetrics();
mCompositedScrollOffset = mFrameMetrics.GetScrollOffset();
mCompositedZoom = mFrameMetrics.GetZoom();
if (mFrameMetrics.GetDisplayPortMargins() != ScreenMargin()) {
// A non-zero display port margin here indicates a displayport has
// been set by a previous APZC for the content at this guid. The
@ -3659,11 +3705,14 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
needContentRepaint = true;
}
mFrameMetrics.ZoomBy(totalResolutionChange / presShellResolutionChange);
mCompositedZoom.xScale *= (totalResolutionChange / presShellResolutionChange).width;
mCompositedZoom.yScale *= (totalResolutionChange / presShellResolutionChange).height;
} else {
// Take the new zoom as either device scale or composition width or
// viewport size got changed (e.g. due to orientation change, or content
// changing the meta-viewport tag).
mFrameMetrics.SetZoom(aLayerMetrics.GetZoom());
mCompositedZoom = aLayerMetrics.GetZoom();
mFrameMetrics.SetDevPixelsPerCSSPixel(aLayerMetrics.GetDevPixelsPerCSSPixel());
}
bool scrollableRectChanged = false;
@ -3702,6 +3751,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
// correct this we need to update mExpectedGeckoMetrics to be the
// last thing we know was painted by Gecko.
mFrameMetrics.CopyScrollInfoFrom(aLayerMetrics);
mCompositedScrollOffset = mFrameMetrics.GetScrollOffset();
mExpectedGeckoMetrics = aLayerMetrics;
// Cancel the animation (which might also trigger a repaint request)

Просмотреть файл

@ -731,6 +731,11 @@ private:
// This allows us to transform events into Gecko's coordinate space.
FrameMetrics mExpectedGeckoMetrics;
// These variables cache the scroll offset and zoom stored in |mFrameMetrics|
// the last time SampleCompositedAsyncTransform() was called.
CSSPoint mCompositedScrollOffset;
CSSToParentLayerScale2D mCompositedZoom;
AxisX mX;
AxisY mY;
@ -839,6 +844,26 @@ public:
*/
AsyncTransformComponentMatrix GetCurrentAsyncTransformWithOverscroll(AsyncTransformConsumer aMode) const;
private:
/**
* Samples the composited async transform, making the result of
* |GetCurrentAsyncTransform(eForCompositing)| and similar functions reflect
* the async scroll offset and zoom stored in |mFrameMetrics|.
*
* (This is only relevant when |gfxPrefs::APZFrameDelayEnabled() == true|.
* Otherwise, GetCurrentAsyncTransform() always reflects what's stored in
* |mFrameMetrics| immediately, without any delay.)
*/
void SampleCompositedAsyncTransform();
/*
* Helper functions to query the async scroll offset and zoom either
* directly from |mFrameMetrics|, or from cached variables that store
* the scroll offset and zoom from the last time it was sampled by
* calling SampleCompositedAsyncTransform(), depending on who is asking.
*/
CSSPoint GetEffectiveScrollOffset(AsyncTransformConsumer aMode) const;
CSSToParentLayerScale2D GetEffectiveZoom(AsyncTransformConsumer aMode) const;
/* ===================================================================
* The functions and members in this section are used to manage

Просмотреть файл

@ -311,6 +311,7 @@ private:
DECL_GFX_PREF(Live, "apz.fling_min_velocity_threshold", APZFlingMinVelocityThreshold, float, 0.5f);
DECL_GFX_PREF(Live, "apz.fling_stop_on_tap_threshold", APZFlingStopOnTapThreshold, float, 0.05f);
DECL_GFX_PREF(Live, "apz.fling_stopped_threshold", APZFlingStoppedThreshold, float, 0.01f);
DECL_GFX_PREF(Live, "apz.frame_delay.enabled", APZFrameDelayEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.highlight_checkerboarded_areas", APZHighlightCheckerboardedAreas, bool, false);
DECL_GFX_PREF(Once, "apz.keyboard.enabled", APZKeyboardEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.max_velocity_inches_per_ms", APZMaxVelocity, float, -1.0f);

Просмотреть файл

@ -695,6 +695,7 @@ pref("apz.fling_friction", "0.002");
pref("apz.fling_min_velocity_threshold", "0.5");
pref("apz.fling_stop_on_tap_threshold", "0.05");
pref("apz.fling_stopped_threshold", "0.01");
pref("apz.frame_delay.enabled", false);
pref("apz.highlight_checkerboarded_areas", false);
pref("apz.keyboard.enabled", false);
pref("apz.max_velocity_inches_per_ms", "-1.0");