Bug 1465616 - Temporarily apply async test attributes when compositing. r?botond
Includes a new RAII class: AutoApplyAsyncTestAttributes, which, for the
duration of its lifetime, applies mTestAsyncScrollOffset and mTestAsyncZoom to
the APZC's FrameMetrics. We need this to ensure that the
AsyncPanZoomController::GetCurrentAsync* methods consider test scroll and zoom
attributes when doing their respective computations.
MozReview-Commit-ID: 9owJcdIegNH
--- a/gfx/layers/apz/public/APZSampler.h
+++ b/gfx/layers/apz/public/APZSampler.h
@@ -6,16 +6,17 @@
#ifndef mozilla_layers_APZSampler_h
#define mozilla_layers_APZSampler_h
#include <unordered_map>
#include "base/platform_thread.h" // for PlatformThreadId
#include "mozilla/layers/AsyncCompositionManager.h" // for AsyncTransform
+#include "mozilla/layers/APZUtils.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/StaticPtr.h"
#include "nsTArray.h"
#include "Units.h"
namespace mozilla {
class TimeStamp;
@@ -86,16 +87,23 @@ public:
AsyncTransform GetCurrentAsyncTransform(const LayerMetricsWrapper& aLayer);
AsyncTransformComponentMatrix GetOverscrollTransform(const LayerMetricsWrapper& aLayer);
AsyncTransformComponentMatrix GetCurrentAsyncTransformWithOverscroll(const LayerMetricsWrapper& aLayer);
void MarkAsyncTransformAppliedToContent(const LayerMetricsWrapper& aLayer);
bool HasUnusedAsyncTransform(const LayerMetricsWrapper& aLayer);
/**
+ * Return a new AutoApplyAsyncTestAttributes instance. This should be called
+ * whenever we need to apply async attributes for test purposes (namely
+ * reftest-async-scroll-{x,y} and reftest-async-zoom).
+ */
+ UniquePtr<AutoApplyAsyncTestAttributes> ApplyAsyncTestAttributes(const LayerMetricsWrapper& aLayer);
+
+ /**
* This can be used to assert that the current thread is the
* sampler thread (which samples the async transform).
* This does nothing if thread assertions are disabled.
*/
void AssertOnSamplerThread() const;
/**
* Returns true if currently on the APZSampler's "sampler thread".
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -596,16 +596,21 @@ APZCTreeManager::SampleForWebRender(wr::
const TimeStamp& aSampleTime)
{
AssertOnSamplerThread();
MutexAutoLock lock(mMapLock);
bool activeAnimations = false;
for (const auto& mapping : mApzcMap) {
AsyncPanZoomController* apzc = mapping.second;
+
+ // Apply any additional async scrolling for testing purposes (used for
+ // reftest-async-scroll and reftest-async-zoom).
+ auto _ = MakeUnique<AutoApplyAsyncTestAttributes>(apzc);
+
ParentLayerPoint layerTranslation = apzc->GetCurrentAsyncTransform(
AsyncPanZoomController::eForCompositing).mTranslation;
// The positive translation means the painted content is supposed to
// move down (or to the right), and that corresponds to a reduction in
// the scroll offset. Since we are effectively giving WR the async
// scroll delta here, we want to negate the translation.
ParentLayerPoint asyncScrollDelta = -layerTranslation;
@@ -3041,16 +3046,19 @@ APZCTreeManager::CommonAncestor(AsyncPan
return ancestor.forget();
}
LayerToParentLayerMatrix4x4
APZCTreeManager::ComputeTransformForNode(const HitTestingTreeNode* aNode) const
{
mTreeLock.AssertCurrentThreadIn();
if (AsyncPanZoomController* apzc = aNode->GetApzc()) {
+ // Apply any additional async scrolling for testing purposes (used for
+ // reftest-async-scroll and reftest-async-zoom).
+ auto _ = MakeUnique<AutoApplyAsyncTestAttributes>(apzc);
// If the node represents scrollable content, apply the async transform
// from its APZC.
return aNode->GetTransform() *
CompleteAsyncTransform(
apzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::eForHitTesting));
} else if (aNode->IsScrollThumbNode()) {
// If the node represents a scrollbar thumb, compute and apply the
// transformation that will be applied to the thumb in
@@ -3130,16 +3138,20 @@ APZCTreeManager::ComputeTransformForScro
// layer has been built for a scroll frame, as this would result in a
// disparity between scrollbars and visible content.
if (aMetrics.IsScrollInfoLayer()) {
return LayerToParentLayerMatrix4x4{};
}
MOZ_RELEASE_ASSERT(aApzc);
+ // Apply any additional async scrolling for testing purposes (used for
+ // reftest-async-scroll and reftest-async-zoom).
+ auto _ = MakeUnique<AutoApplyAsyncTestAttributes>(aApzc);
+
AsyncTransformComponentMatrix asyncTransform =
aApzc->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing);
// |asyncTransform| represents the amount by which we have scrolled and
// zoomed since the last paint. Because the scrollbar was sized and positioned based
// on the painted content, we need to adjust it based on asyncTransform so that
// it reflects what the user is actually seeing now.
AsyncTransformComponentMatrix scrollbarTransform;
--- a/gfx/layers/apz/src/APZSampler.cpp
+++ b/gfx/layers/apz/src/APZSampler.cpp
@@ -5,16 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/layers/APZSampler.h"
#include "APZCTreeManager.h"
#include "AsyncPanZoomController.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/layers/APZThreadUtils.h"
+#include "mozilla/layers/APZUtils.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/LayerMetricsWrapper.h"
#include "mozilla/layers/SynchronousTask.h"
#include "TreeTraversal.h"
#include "mozilla/webrender/WebRenderAPI.h"
namespace mozilla {
namespace layers {
@@ -217,16 +218,26 @@ APZSampler::HasUnusedAsyncTransform(cons
AssertOnSamplerThread();
AsyncPanZoomController* apzc = aLayer.GetApzc();
return apzc
&& !apzc->GetAsyncTransformAppliedToContent()
&& !AsyncTransformComponentMatrix(apzc->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing)).IsIdentity();
}
+UniquePtr<AutoApplyAsyncTestAttributes>
+APZSampler::ApplyAsyncTestAttributes(const LayerMetricsWrapper& aLayer)
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ AssertOnSamplerThread();
+
+ MOZ_ASSERT(aLayer.GetApzc());
+ return MakeUnique<AutoApplyAsyncTestAttributes>(aLayer.GetApzc());
+}
+
void
APZSampler::AssertOnSamplerThread() const
{
if (APZThreadUtils::GetThreadAssertionsEnabled()) {
MOZ_ASSERT(IsSamplerThread());
}
}
--- a/gfx/layers/apz/src/APZUtils.cpp
+++ b/gfx/layers/apz/src/APZUtils.cpp
@@ -5,16 +5,29 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/layers/APZUtils.h"
#include "AsyncPanZoomController.h"
namespace mozilla {
namespace layers {
+
+AutoApplyAsyncTestAttributes::AutoApplyAsyncTestAttributes(AsyncPanZoomController* aApzc)
+ : mApzc(aApzc)
+ , mPrevFrameMetrics(aApzc->Metrics())
+{
+ mApzc->ApplyAsyncTestAttributes();
+}
+
+AutoApplyAsyncTestAttributes::~AutoApplyAsyncTestAttributes()
+{
+ mApzc->UnapplyAsyncTestAttributes(mPrevFrameMetrics);
+}
+
namespace apz {
/*static*/ void
InitializeGlobalState()
{
MOZ_ASSERT(NS_IsMainThread());
AsyncPanZoomController::InitializeGlobalState();
}
--- a/gfx/layers/apz/src/APZUtils.h
+++ b/gfx/layers/apz/src/APZUtils.h
@@ -15,16 +15,18 @@
#include "mozilla/gfx/Point.h"
#include "mozilla/DefineEnum.h"
#include "mozilla/EnumSet.h"
#include "mozilla/FloatingPoint.h"
namespace mozilla {
namespace layers {
+class AsyncPanZoomController;
+
enum CancelAnimationFlags : uint32_t {
Default = 0x0, /* Cancel all animations */
ExcludeOverscroll = 0x1, /* Don't clear overscroll */
ScrollSnap = 0x2, /* Snap to snap points */
ExcludeWheel = 0x4, /* Don't stop wheel smooth-scroll animations */
TriggeredExternally = 0x8, /* Cancellation was not triggered by APZ in
response to an input event */
};
@@ -93,16 +95,29 @@ struct TargetConfirmationFlags {
!(aHitTestInfo & gfx::CompositorHitTestInfo::eDispatchToContent))
, mRequiresTargetConfirmation(aHitTestInfo & gfx::CompositorHitTestInfo::eRequiresTargetConfirmation)
{}
bool mTargetConfirmed : 1;
bool mRequiresTargetConfirmation : 1;
};
+/**
+ * An RAII class to temporarily apply async test attributes to the provided
+ * AsyncPanZoomController.
+ */
+class AutoApplyAsyncTestAttributes {
+public:
+ explicit AutoApplyAsyncTestAttributes(AsyncPanZoomController*);
+ ~AutoApplyAsyncTestAttributes();
+private:
+ AsyncPanZoomController* mApzc;
+ FrameMetrics mPrevFrameMetrics;
+};
+
namespace apz {
/**
* Initializes the global state used in AsyncPanZoomController.
* This is normally called when it is first needed in the constructor
* of APZCTreeManager, but can be called manually to force it to be
* initialized earlier.
*/
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3794,47 +3794,45 @@ ParentLayerPoint
AsyncPanZoomController::GetCurrentAsyncScrollOffset(AsyncTransformConsumer aMode) const
{
RecursiveMutexAutoLock lock(mRecursiveMutex);
if (aMode == eForCompositing && mScrollMetadata.IsApzForceDisabled()) {
return mLastContentPaintMetrics.GetScrollOffset() * mLastContentPaintMetrics.GetZoom();
}
- return (GetEffectiveScrollOffset(aMode) + mTestAsyncScrollOffset)
- * GetEffectiveZoom(aMode) * mTestAsyncZoom.scale;
+ return GetEffectiveScrollOffset(aMode) * GetEffectiveZoom(aMode);
}
CSSPoint
AsyncPanZoomController::GetCurrentAsyncScrollOffsetInCssPixels(AsyncTransformConsumer aMode) const {
RecursiveMutexAutoLock lock(mRecursiveMutex);
if (aMode == eForCompositing && mScrollMetadata.IsApzForceDisabled()) {
return mLastContentPaintMetrics.GetScrollOffset();
}
- return GetEffectiveScrollOffset(aMode) + mTestAsyncScrollOffset;
+ return GetEffectiveScrollOffset(aMode);
}
AsyncTransform
AsyncPanZoomController::GetCurrentAsyncTransform(AsyncTransformConsumer aMode) const
{
RecursiveMutexAutoLock lock(mRecursiveMutex);
if (aMode == eForCompositing && mScrollMetadata.IsApzForceDisabled()) {
return AsyncTransform();
}
CSSPoint lastPaintScrollOffset;
if (mLastContentPaintMetrics.IsScrollable()) {
lastPaintScrollOffset = mLastContentPaintMetrics.GetScrollOffset();
}
- CSSPoint currentScrollOffset = GetEffectiveScrollOffset(aMode) +
- mTestAsyncScrollOffset;
+ CSSPoint currentScrollOffset = GetEffectiveScrollOffset(aMode);
// If checkerboarding has been disallowed, clamp the scroll position to stay
// within rendered content.
if (!gfxPrefs::APZAllowCheckerboarding() &&
!mLastContentPaintMetrics.GetDisplayPort().IsEmpty()) {
CSSSize compositedSize = mLastContentPaintMetrics.CalculateCompositedSizeInCssPixels();
CSSPoint maxScrollOffset = lastPaintScrollOffset +
CSSPoint(mLastContentPaintMetrics.GetDisplayPort().XMost() - compositedSize.width,
@@ -3845,25 +3843,29 @@ AsyncPanZoomController::GetCurrentAsyncT
currentScrollOffset.x = clamped(currentScrollOffset.x, minScrollOffset.x, maxScrollOffset.x);
}
if (minScrollOffset.y < maxScrollOffset.y) {
currentScrollOffset.y = clamped(currentScrollOffset.y, minScrollOffset.y, maxScrollOffset.y);
}
}
CSSToParentLayerScale2D effectiveZoom = GetEffectiveZoom(aMode);
-
- ParentLayerPoint translation = (currentScrollOffset - lastPaintScrollOffset)
- * effectiveZoom * mTestAsyncZoom.scale;
-
+ ParentLayerPoint translation =
+ (currentScrollOffset - lastPaintScrollOffset) * effectiveZoom;
LayerToParentLayerScale compositedAsyncZoom =
- (effectiveZoom / Metrics().LayersPixelsPerCSSPixel()).ToScaleFactor();
- return AsyncTransform(
- LayerToParentLayerScale(compositedAsyncZoom.scale * mTestAsyncZoom.scale),
- -translation);
+ (effectiveZoom / Metrics().LayersPixelsPerCSSPixel()).ToScaleFactor();
+
+ return AsyncTransform(compositedAsyncZoom, -translation);
+}
+
+AsyncTransformComponentMatrix
+AsyncPanZoomController::GetCurrentAsyncTransformWithOverscroll(AsyncTransformConsumer aMode) const
+{
+ return AsyncTransformComponentMatrix(GetCurrentAsyncTransform(aMode))
+ * GetOverscrollTransform(aMode);
}
CSSRect
AsyncPanZoomController::GetEffectiveLayoutViewport(AsyncTransformConsumer aMode) const
{
if (gfxPrefs::APZFrameDelayEnabled() && aMode == eForCompositing) {
return mCompositedLayoutViewport;
}
@@ -3897,21 +3899,39 @@ AsyncPanZoomController::SampleComposited
mCompositedLayoutViewport = Metrics().GetViewport();
mCompositedScrollOffset = Metrics().GetScrollOffset();
mCompositedZoom = Metrics().GetZoom();
return true;
}
return false;
}
-AsyncTransformComponentMatrix
-AsyncPanZoomController::GetCurrentAsyncTransformWithOverscroll(AsyncTransformConsumer aMode) const
-{
- return AsyncTransformComponentMatrix(GetCurrentAsyncTransform(aMode))
- * GetOverscrollTransform(aMode);
+bool
+AsyncPanZoomController::ApplyAsyncTestAttributes() {
+ RecursiveMutexAutoLock lock(mRecursiveMutex);
+ if (mTestAsyncScrollOffset == CSSPoint() &&
+ mTestAsyncZoom == LayerToParentLayerScale()) {
+ return false;
+ }
+ Metrics().ZoomBy(mTestAsyncZoom.scale);
+ ScrollBy(mTestAsyncScrollOffset);
+ SampleCompositedAsyncTransform();
+ return true;
+}
+
+bool
+AsyncPanZoomController::UnapplyAsyncTestAttributes(const FrameMetrics& aPrevFrameMetrics) {
+ RecursiveMutexAutoLock lock(mRecursiveMutex);
+ if (mTestAsyncScrollOffset == CSSPoint() &&
+ mTestAsyncZoom == LayerToParentLayerScale()) {
+ return false;
+ }
+ Metrics() = aPrevFrameMetrics;
+ SampleCompositedAsyncTransform();
+ return true;
}
Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() const {
RecursiveMutexAutoLock lock(mRecursiveMutex);
LayerPoint scrollChange =
(mLastContentPaintMetrics.GetScrollOffset() - mExpectedGeckoMetrics.GetScrollOffset())
* mLastContentPaintMetrics.GetDevPixelsPerCSSPixel()
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -1081,16 +1081,38 @@ private:
* zoom either directly from |Metrics()|, or from cached variables that
* store the required value from the last time it was sampled by calling
* SampleCompositedAsyncTransform(), depending on who is asking.
*/
CSSRect GetEffectiveLayoutViewport(AsyncTransformConsumer aMode) const;
CSSPoint GetEffectiveScrollOffset(AsyncTransformConsumer aMode) const;
CSSToParentLayerScale2D GetEffectiveZoom(AsyncTransformConsumer aMode) const;
+private:
+ friend class AutoApplyAsyncTestAttributes;
+
+ /**
+ * Applies |mTestAsyncScrollOffset| and |mTestAsyncZoom| to this
+ * AsyncPanZoomController. Calls |SampleCompositedAsyncTransform| to ensure
+ * that the GetCurrentAsync* functions consider the test offset and zoom in
+ * their computations.
+ *
+ * Returns false if neither test value is set, and true otherwise.
+ */
+ bool ApplyAsyncTestAttributes();
+
+ /**
+ * Sets this AsyncPanZoomController's FrameMetrics to |aPrevFrameMetrics| and
+ * calls |SampleCompositedAsyncTransform| to unapply any test values applied
+ * by |ApplyAsyncTestAttributes|.
+ *
+ * Returns false if neither test value is set, and true otherwise.
+ */
+ bool UnapplyAsyncTestAttributes(const FrameMetrics& aPrevFrameMetrics);
+
/* ===================================================================
* The functions and members in this section are used to manage
* the state that tracks what this APZC is doing with the input events.
*/
protected:
enum PanZoomState {
NOTHING, /* no touch-start events received */
FLING, /* all touches removed, but we're still scrolling page */
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -972,16 +972,21 @@ AsyncCompositionManager::ApplyAsyncConte
}
if (RefPtr<APZSampler> sampler = mCompositorBridge->GetAPZSampler()) {
for (uint32_t i = 0; i < layer->GetScrollMetadataCount(); i++) {
LayerMetricsWrapper wrapper(layer, i);
if (!wrapper.GetApzc()) {
continue;
}
+
+ // Apply any additional async scrolling for testing purposes (used
+ // for reftest-async-scroll and reftest-async-zoom).
+ auto _ = sampler->ApplyAsyncTestAttributes(wrapper);
+
const FrameMetrics& metrics = wrapper.Metrics();
MOZ_ASSERT(metrics.IsScrollable());
hasAsyncTransform = true;
AsyncTransform asyncTransformWithoutOverscroll =
sampler->GetCurrentAsyncTransform(wrapper);
AsyncTransformComponentMatrix overscrollTransform =