Bug 1465616 - Temporarily apply async test attributes when compositing. r?botond draft
authorKashav Madan <kshvmdn@gmail.com>
Fri, 20 Jul 2018 17:37:36 -0400
changeset 830108 96b62222a107300fb80e435e813b8c72f8c0ad07
parent 829034 2a2ec4983e2ec7f69a3c18389661e00e47ac5277
child 830109 84137acdf43c38ad91ccbac36ae2c034cd6dfb61
push id118813
push userbmo:kshvmdn@gmail.com
push dateSun, 19 Aug 2018 00:42:00 +0000
reviewersbotond
bugs1465616
milestone63.0a1
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
gfx/layers/apz/public/APZSampler.h
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/APZSampler.cpp
gfx/layers/apz/src/APZUtils.cpp
gfx/layers/apz/src/APZUtils.h
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/AsyncPanZoomController.h
gfx/layers/composite/AsyncCompositionManager.cpp
--- 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 =