LCOV - code coverage report
Current view: top level - gfx/layers/apz/src - APZCTreeManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 12 1311 0.9 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include <stack>
       8             : #include <unordered_set>
       9             : #include "APZCTreeManager.h"
      10             : #include "AsyncPanZoomController.h"
      11             : #include "Compositor.h"                 // for Compositor
      12             : #include "DragTracker.h"                // for DragTracker
      13             : #include "gfxPrefs.h"                   // for gfxPrefs
      14             : #include "HitTestingTreeNode.h"         // for HitTestingTreeNode
      15             : #include "InputBlockState.h"            // for InputBlockState
      16             : #include "InputData.h"                  // for InputData, etc
      17             : #include "Layers.h"                     // for Layer, etc
      18             : #include "mozilla/dom/MouseEventBinding.h" // for MouseEvent constants
      19             : #include "mozilla/dom/Touch.h"          // for Touch
      20             : #include "mozilla/gfx/gfxVars.h"        // for gfxVars
      21             : #include "mozilla/gfx/GPUParent.h"      // for GPUParent
      22             : #include "mozilla/gfx/Logging.h"        // for gfx::TreeLog
      23             : #include "mozilla/gfx/Point.h"          // for Point
      24             : #include "mozilla/layers/APZSampler.h"  // for APZSampler
      25             : #include "mozilla/layers/APZThreadUtils.h"  // for AssertOnControllerThread, etc
      26             : #include "mozilla/layers/APZUpdater.h"  // for APZUpdater
      27             : #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
      28             : #include "mozilla/layers/AsyncDragMetrics.h" // for AsyncDragMetrics
      29             : #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent, etc
      30             : #include "mozilla/layers/LayerMetricsWrapper.h"
      31             : #include "mozilla/layers/WebRenderScrollDataWrapper.h"
      32             : #include "mozilla/MouseEvents.h"
      33             : #include "mozilla/mozalloc.h"           // for operator new
      34             : #include "mozilla/TouchEvents.h"
      35             : #include "mozilla/Preferences.h"        // for Preferences
      36             : #include "mozilla/EventStateManager.h"  // for WheelPrefs
      37             : #include "mozilla/webrender/WebRenderAPI.h"
      38             : #include "nsDebug.h"                    // for NS_WARNING
      39             : #include "nsPoint.h"                    // for nsIntPoint
      40             : #include "nsThreadUtils.h"              // for NS_IsMainThread
      41             : #include "OverscrollHandoffState.h"     // for OverscrollHandoffState
      42             : #include "TreeTraversal.h"              // for ForEachNode, BreadthFirstSearch, etc
      43             : #include "LayersLogging.h"              // for Stringify
      44             : #include "Units.h"                      // for ParentlayerPixel
      45             : #include "GestureEventListener.h"       // for GestureEventListener::setLongTapEnabled
      46             : #include "UnitTransforms.h"             // for ViewAs
      47             : 
      48             : #define ENABLE_APZCTM_LOGGING 0
      49             : // #define ENABLE_APZCTM_LOGGING 1
      50             : 
      51             : #if ENABLE_APZCTM_LOGGING
      52             : #  define APZCTM_LOG(...) printf_stderr("APZCTM: " __VA_ARGS__)
      53             : #else
      54             : #  define APZCTM_LOG(...)
      55             : #endif
      56             : 
      57             : // #define APZ_KEY_LOG(...) printf_stderr("APZKEY: " __VA_ARGS__)
      58             : #define APZ_KEY_LOG(...)
      59             : 
      60             : namespace mozilla {
      61             : namespace layers {
      62             : 
      63             : using mozilla::gfx::CompositorHitTestInfo;
      64             : 
      65             : typedef mozilla::gfx::Point Point;
      66             : typedef mozilla::gfx::Point4D Point4D;
      67             : typedef mozilla::gfx::Matrix4x4 Matrix4x4;
      68             : 
      69             : typedef CompositorBridgeParent::LayerTreeState LayerTreeState;
      70             : 
      71           0 : struct APZCTreeManager::TreeBuildingState {
      72           0 :   TreeBuildingState(LayersId aRootLayersId,
      73             :                     bool aIsFirstPaint, LayersId aOriginatingLayersId,
      74             :                     APZTestData* aTestData, uint32_t aPaintSequence)
      75           0 :     : mIsFirstPaint(aIsFirstPaint)
      76             :     , mOriginatingLayersId(aOriginatingLayersId)
      77           0 :     , mPaintLogger(aTestData, aPaintSequence)
      78             :   {
      79           0 :     CompositorBridgeParent::CallWithIndirectShadowTree(aRootLayersId,
      80           0 :         [this](LayerTreeState& aState) -> void {
      81           0 :           mCompositorController = aState.GetCompositorController();
      82           0 :           mInProcessSharingController = aState.InProcessSharingController();
      83           0 :         });
      84           0 :   }
      85             : 
      86             :   typedef std::unordered_map<AsyncPanZoomController*, gfx::Matrix4x4> DeferredTransformMap;
      87             : 
      88             :   // State that doesn't change as we recurse in the tree building
      89             :   RefPtr<CompositorController> mCompositorController;
      90             :   RefPtr<MetricsSharingController> mInProcessSharingController;
      91             :   const bool mIsFirstPaint;
      92             :   const LayersId mOriginatingLayersId;
      93             :   const APZPaintLogHelper mPaintLogger;
      94             : 
      95             :   // State that is updated as we perform the tree build
      96             : 
      97             :   // A list of nodes that need to be destroyed at the end of the tree building.
      98             :   // This is initialized with all nodes in the old tree, and nodes are removed
      99             :   // from it as we reuse them in the new tree.
     100             :   nsTArray<RefPtr<HitTestingTreeNode>> mNodesToDestroy;
     101             : 
     102             :   // This map is populated as we place APZCs into the new tree. Its purpose is
     103             :   // to facilitate re-using the same APZC for different layers that scroll
     104             :   // together (and thus have the same ScrollableLayerGuid). The presShellId
     105             :   // doesn't matter for this purpose, and we move the map to the APZCTreeManager
     106             :   // after we're done building, so it's useful to have the presshell-ignoring
     107             :   // map for that.
     108             :   std::unordered_map<ScrollableLayerGuid,
     109             :                      RefPtr<AsyncPanZoomController>,
     110             :                      ScrollableLayerGuid::HashIgnoringPresShellFn,
     111             :                      ScrollableLayerGuid::EqualIgnoringPresShellFn> mApzcMap;
     112             : 
     113             :   // This is populated with all the HitTestingTreeNodes that are scroll thumbs
     114             :   // and have a scrollthumb animation id (which indicates that they need to be
     115             :   // sampled for WebRender on the sampler thread).
     116             :   std::vector<HitTestingTreeNode*> mScrollThumbs;
     117             :   // This is populated with all the scroll target nodes. We use in conjunction
     118             :   // with mScrollThumbs to build APZCTreeManager::mScrollThumbInfo.
     119             :   std::unordered_map<ScrollableLayerGuid,
     120             :                      HitTestingTreeNode*,
     121             :                      ScrollableLayerGuid::HashIgnoringPresShellFn,
     122             :                      ScrollableLayerGuid::EqualIgnoringPresShellFn> mScrollTargets;
     123             : 
     124             :   // As the tree is traversed, the top element of this stack tracks whether
     125             :   // the parent scroll node has a perspective transform.
     126             :   std::stack<bool> mParentHasPerspective;
     127             : 
     128             :   // During the tree building process, the perspective transform component
     129             :   // of the ancestor transforms of some APZCs can be "deferred" to their
     130             :   // children, meaning they are added to the children's ancestor transforms
     131             :   // instead. Those deferred transforms are tracked here.
     132             :   DeferredTransformMap mPerspectiveTransformsDeferredToChildren;
     133             : };
     134             : 
     135             : class APZCTreeManager::CheckerboardFlushObserver : public nsIObserver {
     136             : public:
     137             :   NS_DECL_ISUPPORTS
     138             :   NS_DECL_NSIOBSERVER
     139             : 
     140           0 :   explicit CheckerboardFlushObserver(APZCTreeManager* aTreeManager)
     141           0 :     : mTreeManager(aTreeManager)
     142             :   {
     143           0 :     MOZ_ASSERT(NS_IsMainThread());
     144           0 :     nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
     145           0 :     MOZ_ASSERT(obsSvc);
     146           0 :     if (obsSvc) {
     147           0 :       obsSvc->AddObserver(this, "APZ:FlushActiveCheckerboard", false);
     148             :     }
     149           0 :   }
     150             : 
     151           0 :   void Unregister()
     152             :   {
     153           0 :     MOZ_ASSERT(NS_IsMainThread());
     154           0 :     nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
     155           0 :     if (obsSvc) {
     156           0 :       obsSvc->RemoveObserver(this, "APZ:FlushActiveCheckerboard");
     157             :     }
     158           0 :     mTreeManager = nullptr;
     159           0 :   }
     160             : 
     161             : protected:
     162           0 :   virtual ~CheckerboardFlushObserver() = default;
     163             : 
     164             : private:
     165             :   RefPtr<APZCTreeManager> mTreeManager;
     166             : };
     167             : 
     168           0 : NS_IMPL_ISUPPORTS(APZCTreeManager::CheckerboardFlushObserver, nsIObserver)
     169             : 
     170             : NS_IMETHODIMP
     171           0 : APZCTreeManager::CheckerboardFlushObserver::Observe(nsISupports* aSubject,
     172             :                                                     const char* aTopic,
     173             :                                                     const char16_t*)
     174             : {
     175           0 :   MOZ_ASSERT(NS_IsMainThread());
     176           0 :   MOZ_ASSERT(mTreeManager.get());
     177             : 
     178           0 :   RecursiveMutexAutoLock lock(mTreeManager->mTreeLock);
     179           0 :   if (mTreeManager->mRootNode) {
     180           0 :     ForEachNode<ReverseIterator>(mTreeManager->mRootNode.get(),
     181           0 :         [](HitTestingTreeNode* aNode)
     182             :         {
     183           0 :           if (aNode->IsPrimaryHolder()) {
     184           0 :             MOZ_ASSERT(aNode->GetApzc());
     185           0 :             aNode->GetApzc()->FlushActiveCheckerboardReport();
     186             :           }
     187           0 :         });
     188             :   }
     189           0 :   if (XRE_IsGPUProcess()) {
     190           0 :     if (gfx::GPUParent* gpu = gfx::GPUParent::GetSingleton()) {
     191           0 :       nsCString topic("APZ:FlushActiveCheckerboard:Done");
     192           0 :       Unused << gpu->SendNotifyUiObservers(topic);
     193             :     }
     194             :   } else {
     195           0 :     MOZ_ASSERT(XRE_IsParentProcess());
     196           0 :     nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
     197           0 :     if (obsSvc) {
     198           0 :       obsSvc->NotifyObservers(nullptr, "APZ:FlushActiveCheckerboard:Done", nullptr);
     199             :     }
     200             :   }
     201           0 :   return NS_OK;
     202             : }
     203             : 
     204             : /**
     205             :  * A RAII class used for setting the focus sequence number on input events
     206             :  * as they are being processed. Any input event is assumed to be potentially
     207             :  * focus changing unless explicitly marked otherwise.
     208             :  */
     209             : class MOZ_RAII AutoFocusSequenceNumberSetter
     210             : {
     211             : public:
     212             :   AutoFocusSequenceNumberSetter(FocusState& aFocusState, InputData& aEvent)
     213           0 :     : mFocusState(aFocusState)
     214             :     , mEvent(aEvent)
     215           0 :     , mMayChangeFocus(true)
     216             :   { }
     217             : 
     218           0 :   void MarkAsNonFocusChanging() { mMayChangeFocus = false; }
     219             : 
     220           0 :   ~AutoFocusSequenceNumberSetter()
     221           0 :   {
     222           0 :     if (mMayChangeFocus) {
     223           0 :       mFocusState.ReceiveFocusChangingEvent();
     224             : 
     225             :       APZ_KEY_LOG("Marking input with type=%d as focus changing with seq=%" PRIu64 "\n",
     226             :                   static_cast<int>(mEvent.mInputType),
     227             :                   mFocusState.LastAPZProcessedEvent());
     228             :     } else {
     229             :       APZ_KEY_LOG("Marking input with type=%d as non focus changing with seq=%" PRIu64 "\n",
     230             :                   static_cast<int>(mEvent.mInputType),
     231             :                   mFocusState.LastAPZProcessedEvent());
     232             :     }
     233             : 
     234           0 :     mEvent.mFocusSequenceNumber = mFocusState.LastAPZProcessedEvent();
     235           0 :   }
     236             : 
     237             : private:
     238             :   FocusState& mFocusState;
     239             :   InputData& mEvent;
     240             :   bool mMayChangeFocus;
     241             : };
     242             : 
     243           0 : APZCTreeManager::APZCTreeManager(LayersId aRootLayersId)
     244           0 :     : mInputQueue(new InputQueue()),
     245             :       mRootLayersId(aRootLayersId),
     246             :       mSampler(nullptr),
     247             :       mUpdater(nullptr),
     248             :       mTreeLock("APZCTreeLock"),
     249             :       mMapLock("APZCMapLock"),
     250             :       mHitResultForInputBlock(CompositorHitTestInfo::eInvisibleToHitTest),
     251             :       mRetainedTouchIdentifier(-1),
     252             :       mInScrollbarTouchDrag(false),
     253             :       mApzcTreeLog("apzctree"),
     254             :       mTestDataLock("APZTestDataLock"),
     255           0 :       mDPI(160.0)
     256             : {
     257           0 :   RefPtr<APZCTreeManager> self(this);
     258           0 :   NS_DispatchToMainThread(
     259           0 :     NS_NewRunnableFunction("layers::APZCTreeManager::APZCTreeManager", [self] {
     260           0 :       self->mFlushObserver = new CheckerboardFlushObserver(self);
     261           0 :     }));
     262           0 :   AsyncPanZoomController::InitializeGlobalState();
     263           0 :   mApzcTreeLog.ConditionOnPrefFunction(gfxPrefs::APZPrintTree);
     264             : #if defined(MOZ_WIDGET_ANDROID)
     265             :   mToolbarAnimator = new AndroidDynamicToolbarAnimator(this);
     266             : #endif // (MOZ_WIDGET_ANDROID)
     267           0 : }
     268             : 
     269             : APZCTreeManager::~APZCTreeManager() = default;
     270             : 
     271             : void
     272           0 : APZCTreeManager::SetSampler(APZSampler* aSampler)
     273             : {
     274             :   // We're either setting the sampler or clearing it
     275           0 :   MOZ_ASSERT((mSampler == nullptr) != (aSampler == nullptr));
     276           0 :   mSampler = aSampler;
     277           0 : }
     278             : 
     279             : void
     280           0 : APZCTreeManager::SetUpdater(APZUpdater* aUpdater)
     281             : {
     282             :   // We're either setting the updater or clearing it
     283           0 :   MOZ_ASSERT((mUpdater == nullptr) != (aUpdater == nullptr));
     284           0 :   mUpdater = aUpdater;
     285           0 : }
     286             : 
     287             : void
     288           0 : APZCTreeManager::NotifyLayerTreeAdopted(LayersId aLayersId,
     289             :                                         const RefPtr<APZCTreeManager>& aOldApzcTreeManager)
     290             : {
     291           0 :   AssertOnUpdaterThread();
     292             : 
     293           0 :   if (aOldApzcTreeManager) {
     294           0 :     aOldApzcTreeManager->mFocusState.RemoveFocusTarget(aLayersId);
     295             :     // While we could move the focus target information from the old APZC tree
     296             :     // manager into this one, it's safer to not do that, as we'll probably have
     297             :     // that information repopulated soon anyway (on the next layers update).
     298             :   }
     299             : 
     300           0 :   UniquePtr<APZTestData> adoptedData;
     301           0 :   if (aOldApzcTreeManager) {
     302           0 :     MutexAutoLock lock(aOldApzcTreeManager->mTestDataLock);
     303           0 :     auto it = aOldApzcTreeManager->mTestData.find(aLayersId);
     304           0 :     if (it != aOldApzcTreeManager->mTestData.end()) {
     305           0 :       adoptedData = std::move(it->second);
     306           0 :       aOldApzcTreeManager->mTestData.erase(it);
     307             :     }
     308             :   }
     309           0 :   if (adoptedData) {
     310           0 :     MutexAutoLock lock(mTestDataLock);
     311           0 :     mTestData[aLayersId] = std::move(adoptedData);
     312             :   }
     313           0 : }
     314             : 
     315             : void
     316           0 : APZCTreeManager::NotifyLayerTreeRemoved(LayersId aLayersId)
     317             : {
     318           0 :   AssertOnUpdaterThread();
     319             : 
     320           0 :   mFocusState.RemoveFocusTarget(aLayersId);
     321             : 
     322             :   { // scope lock
     323           0 :     MutexAutoLock lock(mTestDataLock);
     324           0 :     mTestData.erase(aLayersId);
     325             :   }
     326           0 : }
     327             : 
     328             : AsyncPanZoomController*
     329           0 : APZCTreeManager::NewAPZCInstance(LayersId aLayersId,
     330             :                                  GeckoContentController* aController)
     331             : {
     332             :   return new AsyncPanZoomController(aLayersId, this, mInputQueue,
     333           0 :     aController, AsyncPanZoomController::USE_GESTURE_DETECTOR);
     334             : }
     335             : 
     336             : TimeStamp
     337           0 : APZCTreeManager::GetFrameTime()
     338             : {
     339           0 :   return TimeStamp::Now();
     340             : }
     341             : 
     342             : void
     343           0 : APZCTreeManager::SetAllowedTouchBehavior(uint64_t aInputBlockId,
     344             :                                          const nsTArray<TouchBehaviorFlags> &aValues)
     345             : {
     346           0 :   APZThreadUtils::AssertOnControllerThread();
     347             : 
     348           0 :   mInputQueue->SetAllowedTouchBehavior(aInputBlockId, aValues);
     349           0 : }
     350             : 
     351             : template<class ScrollNode> void // ScrollNode is a LayerMetricsWrapper or a WebRenderScrollDataWrapper
     352           0 : APZCTreeManager::UpdateHitTestingTreeImpl(LayersId aRootLayerTreeId,
     353             :                                           const ScrollNode& aRoot,
     354             :                                           bool aIsFirstPaint,
     355             :                                           LayersId aOriginatingLayersId,
     356             :                                           uint32_t aPaintSequenceNumber)
     357             : {
     358           0 :   RecursiveMutexAutoLock lock(mTreeLock);
     359             : 
     360             :   // For testing purposes, we log some data to the APZTestData associated with
     361             :   // the layers id that originated this update.
     362           0 :   APZTestData* testData = nullptr;
     363           0 :   if (gfxPrefs::APZTestLoggingEnabled()) {
     364           0 :     MutexAutoLock lock(mTestDataLock);
     365           0 :     UniquePtr<APZTestData> ptr = MakeUnique<APZTestData>();
     366           0 :     auto result = mTestData.insert(std::make_pair(aOriginatingLayersId, std::move(ptr)));
     367           0 :     testData = result.first->second.get();
     368           0 :     testData->StartNewPaint(aPaintSequenceNumber);
     369             :   }
     370             : 
     371             :   TreeBuildingState state(aRootLayerTreeId, aIsFirstPaint, aOriginatingLayersId,
     372           0 :                           testData, aPaintSequenceNumber);
     373             : 
     374             :   // We do this business with collecting the entire tree into an array because otherwise
     375             :   // it's very hard to determine which APZC instances need to be destroyed. In the worst
     376             :   // case, there are two scenarios: (a) a layer with an APZC is removed from the layer
     377             :   // tree and (b) a layer with an APZC is moved in the layer tree from one place to a
     378             :   // completely different place. In scenario (a) we would want to destroy the APZC while
     379             :   // walking the layer tree and noticing that the layer/APZC is no longer there. But if
     380             :   // we do that then we run into a problem in scenario (b) because we might encounter that
     381             :   // layer later during the walk. To handle both of these we have to 'remember' that the
     382             :   // layer was not found, and then do the destroy only at the end of the tree walk after
     383             :   // we are sure that the layer was removed and not just transplanted elsewhere. Doing that
     384             :   // as part of a recursive tree walk is hard and so maintaining a list and removing
     385             :   // APZCs that are still alive is much simpler.
     386           0 :   ForEachNode<ReverseIterator>(mRootNode.get(),
     387           0 :       [&state] (HitTestingTreeNode* aNode)
     388           0 :       {
     389           0 :         state.mNodesToDestroy.AppendElement(aNode);
     390           0 :       });
     391           0 :   mRootNode = nullptr;
     392             : 
     393           0 :   if (aRoot) {
     394           0 :     std::stack<gfx::TreeAutoIndent> indents;
     395           0 :     std::stack<AncestorTransform> ancestorTransforms;
     396           0 :     HitTestingTreeNode* parent = nullptr;
     397           0 :     HitTestingTreeNode* next = nullptr;
     398           0 :     LayersId layersId = aRootLayerTreeId;
     399           0 :     ancestorTransforms.push(AncestorTransform());
     400           0 :     state.mParentHasPerspective.push(false);
     401             : 
     402           0 :     mApzcTreeLog << "[start]\n";
     403           0 :     mTreeLock.AssertCurrentThreadIn();
     404             : 
     405           0 :     ForEachNode<ReverseIterator>(aRoot,
     406           0 :         [&](ScrollNode aLayerMetrics)
     407             :         {
     408           0 :           mApzcTreeLog << aLayerMetrics.Name() << '\t';
     409             : 
     410           0 :           HitTestingTreeNode* node = PrepareNodeForLayer(lock, aLayerMetrics,
     411           0 :                 aLayerMetrics.Metrics(), layersId, ancestorTransforms.top(),
     412           0 :                 parent, next, state);
     413           0 :           MOZ_ASSERT(node);
     414           0 :           AsyncPanZoomController* apzc = node->GetApzc();
     415           0 :           aLayerMetrics.SetApzc(apzc);
     416             : 
     417             :           // GetScrollbarAnimationId is only non-zero when webrender is enabled,
     418             :           // which limits the extra thumb mapping work to the webrender-enabled
     419             :           // case where it is needed.
     420             :           // Note also that when webrender is enabled, a "valid" animation id
     421             :           // is always nonzero, so we don't need to worry about handling the
     422             :           // case where WR is enabled and the animation id is zero.
     423           0 :           if (node->IsScrollThumbNode() && node->GetScrollbarAnimationId()) {
     424           0 :             state.mScrollThumbs.push_back(node);
     425             :           }
     426           0 :           if (apzc && node->IsPrimaryHolder()) {
     427           0 :             state.mScrollTargets[apzc->GetGuid()] = node;
     428             :           }
     429             : 
     430           0 :           mApzcTreeLog << '\n';
     431             : 
     432             :           // Accumulate the CSS transform between layers that have an APZC.
     433             :           // In the terminology of the big comment above APZCTreeManager::GetScreenToApzcTransform, if
     434             :           // we are at layer M, then aAncestorTransform is NC * OC * PC, and we left-multiply MC and
     435             :           // compute ancestorTransform to be MC * NC * OC * PC. This gets passed down as the ancestor
     436             :           // transform to layer L when we recurse into the children below. If we are at a layer
     437             :           // with an APZC, such as P, then we reset the ancestorTransform to just PC, to start
     438             :           // the new accumulation as we go down.
     439             :           AncestorTransform currentTransform{aLayerMetrics.GetTransform(),
     440           0 :                                              aLayerMetrics.TransformIsPerspective()};
     441           0 :           if (!apzc) {
     442           0 :             currentTransform = currentTransform * ancestorTransforms.top();
     443             :           }
     444           0 :           ancestorTransforms.push(currentTransform);
     445             : 
     446             :           // Note that |node| at this point will not have any children, otherwise we
     447             :           // we would have to set next to node->GetFirstChild().
     448           0 :           MOZ_ASSERT(!node->GetFirstChild());
     449           0 :           parent = node;
     450           0 :           next = nullptr;
     451             : 
     452             :           // Update the layersId if we have a new one
     453           0 :           if (Maybe<LayersId> newLayersId = aLayerMetrics.GetReferentId()) {
     454           0 :             layersId = *newLayersId;
     455             :           }
     456             : 
     457           0 :           indents.push(gfx::TreeAutoIndent(mApzcTreeLog));
     458           0 :           state.mParentHasPerspective.push(aLayerMetrics.TransformIsPerspective());
     459           0 :         },
     460           0 :         [&](ScrollNode aLayerMetrics)
     461             :         {
     462           0 :           next = parent;
     463           0 :           parent = parent->GetParent();
     464           0 :           layersId = next->GetLayersId();
     465           0 :           ancestorTransforms.pop();
     466           0 :           indents.pop();
     467           0 :           state.mParentHasPerspective.pop();
     468           0 :         });
     469             : 
     470           0 :     mApzcTreeLog << "[end]\n";
     471             : 
     472             :     // If we have perspective transforms deferred to children, do another
     473             :     // walk of the tree and actually apply them to the children.
     474             :     // We can't do this "as we go" in the previous traversal, because by the
     475             :     // time we realize we need to defer a perspective transform for an APZC,
     476             :     // we may already have processed a previous layer (including children
     477             :     // found in its subtree) that shares that APZC.
     478           0 :     if (!state.mPerspectiveTransformsDeferredToChildren.empty()) {
     479           0 :       ForEachNode<ReverseIterator>(mRootNode.get(),
     480           0 :           [&state](HitTestingTreeNode* aNode) {
     481           0 :             AsyncPanZoomController* apzc = aNode->GetApzc();
     482           0 :             if (!apzc) {
     483           0 :               return;
     484             :             }
     485           0 :             if (!aNode->IsPrimaryHolder()) {
     486             :               return;
     487             :             }
     488             : 
     489           0 :             AsyncPanZoomController* parent = apzc->GetParent();
     490           0 :             if (!parent) {
     491             :               return;
     492             :             }
     493             : 
     494           0 :             auto it = state.mPerspectiveTransformsDeferredToChildren.find(parent);
     495           0 :             if (it != state.mPerspectiveTransformsDeferredToChildren.end()) {
     496           0 :               apzc->SetAncestorTransform(AncestorTransform{
     497           0 :                 it->second * apzc->GetAncestorTransform(), false
     498             :               });
     499             :             }
     500             :           });
     501             :     }
     502             :   }
     503             : 
     504             :   // We do not support tree structures where the root node has siblings.
     505           0 :   MOZ_ASSERT(!(mRootNode && mRootNode->GetPrevSibling()));
     506             : 
     507             :   { // scope lock and update our mApzcMap before we destroy all the unused
     508             :     // APZC instances
     509           0 :     MutexAutoLock lock(mMapLock);
     510           0 :     mApzcMap = std::move(state.mApzcMap);
     511           0 :     mScrollThumbInfo.clear();
     512             :     // For non-webrender, state.mScrollThumbs will be empty so this will be a
     513             :     // no-op.
     514           0 :     for (HitTestingTreeNode* thumb : state.mScrollThumbs) {
     515           0 :       MOZ_ASSERT(thumb->IsScrollThumbNode());
     516           0 :       ScrollableLayerGuid targetGuid(thumb->GetLayersId(), 0, thumb->GetScrollTargetId());
     517           0 :       auto it = state.mScrollTargets.find(targetGuid);
     518           0 :       if (it == state.mScrollTargets.end()) {
     519             :         // It could be that |thumb| is a scrollthumb for content which didn't
     520             :         // have an APZC, for example if the content isn't layerized. Regardless,
     521             :         // we can't async-scroll it so we don't need to worry about putting it
     522             :         // in mScrollThumbInfo.
     523           0 :         continue;
     524             :       }
     525           0 :       HitTestingTreeNode* target = it->second;
     526           0 :       mScrollThumbInfo.emplace_back(
     527           0 :           thumb->GetScrollbarAnimationId(),
     528           0 :           thumb->GetTransform(),
     529             :           thumb->GetScrollbarData(),
     530             :           targetGuid,
     531           0 :           target->GetTransform(),
     532           0 :           target->IsAncestorOf(thumb));
     533             :     }
     534             :   }
     535             : 
     536           0 :   for (size_t i = 0; i < state.mNodesToDestroy.Length(); i++) {
     537             :     APZCTM_LOG("Destroying node at %p with APZC %p\n",
     538             :         state.mNodesToDestroy[i].get(),
     539             :         state.mNodesToDestroy[i]->GetApzc());
     540           0 :     state.mNodesToDestroy[i]->Destroy();
     541             :   }
     542             : 
     543             : #if ENABLE_APZCTM_LOGGING
     544             :   // Make the hit-test tree line up with the layer dump
     545             :   printf_stderr("APZCTreeManager (%p)\n", this);
     546             :   mRootNode->Dump("  ");
     547             : #endif
     548           0 : }
     549             : 
     550             : void
     551           0 : APZCTreeManager::UpdateFocusState(LayersId aRootLayerTreeId,
     552             :                                   LayersId aOriginatingLayersId,
     553             :                                   const FocusTarget& aFocusTarget)
     554             : {
     555           0 :   AssertOnUpdaterThread();
     556             : 
     557           0 :   if (!gfxPrefs::APZKeyboardEnabled()) {
     558             :     return;
     559             :   }
     560             : 
     561           0 :   mFocusState.Update(aRootLayerTreeId,
     562             :                      aOriginatingLayersId,
     563           0 :                      aFocusTarget);
     564             : }
     565             : 
     566             : void
     567           0 : APZCTreeManager::UpdateHitTestingTree(LayersId aRootLayerTreeId,
     568             :                                       Layer* aRoot,
     569             :                                       bool aIsFirstPaint,
     570             :                                       LayersId aOriginatingLayersId,
     571             :                                       uint32_t aPaintSequenceNumber)
     572             : {
     573           0 :   AssertOnUpdaterThread();
     574             : 
     575           0 :   LayerMetricsWrapper root(aRoot);
     576           0 :   UpdateHitTestingTreeImpl(aRootLayerTreeId, root, aIsFirstPaint,
     577           0 :                            aOriginatingLayersId, aPaintSequenceNumber);
     578           0 : }
     579             : 
     580             : void
     581           0 : APZCTreeManager::UpdateHitTestingTree(LayersId aRootLayerTreeId,
     582             :                                       const WebRenderScrollDataWrapper& aScrollWrapper,
     583             :                                       bool aIsFirstPaint,
     584             :                                       LayersId aOriginatingLayersId,
     585             :                                       uint32_t aPaintSequenceNumber)
     586             : {
     587           0 :   AssertOnUpdaterThread();
     588             : 
     589           0 :   UpdateHitTestingTreeImpl(aRootLayerTreeId, aScrollWrapper, aIsFirstPaint,
     590           0 :                            aOriginatingLayersId, aPaintSequenceNumber);
     591           0 : }
     592             : 
     593             : void
     594           0 : APZCTreeManager::SampleForWebRender(wr::TransactionWrapper& aTxn,
     595             :                                     const TimeStamp& aSampleTime)
     596             : {
     597           0 :   AssertOnSamplerThread();
     598           0 :   MutexAutoLock lock(mMapLock);
     599             : 
     600           0 :   bool activeAnimations = false;
     601           0 :   for (const auto& mapping : mApzcMap) {
     602           0 :     AsyncPanZoomController* apzc = mapping.second;
     603           0 :     ParentLayerPoint layerTranslation = apzc->GetCurrentAsyncTransform(
     604           0 :         AsyncPanZoomController::eForCompositing).mTranslation;
     605             : 
     606             :     // The positive translation means the painted content is supposed to
     607             :     // move down (or to the right), and that corresponds to a reduction in
     608             :     // the scroll offset. Since we are effectively giving WR the async
     609             :     // scroll delta here, we want to negate the translation.
     610           0 :     ParentLayerPoint asyncScrollDelta = -layerTranslation;
     611             :     // XXX figure out what zoom-related conversions need to happen here.
     612             :     aTxn.UpdateScrollPosition(
     613           0 :         wr::AsPipelineId(apzc->GetGuid().mLayersId),
     614           0 :         apzc->GetGuid().mScrollId,
     615           0 :         wr::ToLayoutPoint(LayoutDevicePoint::FromUnknownPoint(asyncScrollDelta.ToUnknownPoint())));
     616             : 
     617           0 :     apzc->ReportCheckerboard(aSampleTime);
     618           0 :     activeAnimations |= apzc->AdvanceAnimations(aSampleTime);
     619             :   }
     620             : 
     621             :   // Now collect all the async transforms needed for the scrollthumbs.
     622           0 :   nsTArray<wr::WrTransformProperty> scrollbarTransforms;
     623           0 :   for (const ScrollThumbInfo& info : mScrollThumbInfo) {
     624           0 :     auto it = mApzcMap.find(info.mTargetGuid);
     625           0 :     if (it == mApzcMap.end()) {
     626             :       // It could be that |info| is a scrollthumb for content which didn't
     627             :       // have an APZC, for example if the content isn't layerized. Regardless,
     628             :       // we can't async-scroll it so we don't need to worry about putting it
     629             :       // in mScrollThumbInfo.
     630           0 :       continue;
     631             :     }
     632           0 :     AsyncPanZoomController* scrollTargetApzc = it->second;
     633           0 :     MOZ_ASSERT(scrollTargetApzc);
     634             :     LayerToParentLayerMatrix4x4 transform = scrollTargetApzc->CallWithLastContentPaintMetrics(
     635           0 :         [&](const FrameMetrics& aMetrics) {
     636             :             return ComputeTransformForScrollThumb(
     637           0 :                 info.mThumbTransform * AsyncTransformMatrix(),
     638           0 :                 info.mTargetTransform.ToUnknownMatrix(),
     639           0 :                 scrollTargetApzc,
     640             :                 aMetrics,
     641             :                 info.mThumbData,
     642           0 :                 info.mTargetIsAncestor,
     643             :                 nullptr);
     644           0 :         });
     645           0 :     scrollbarTransforms.AppendElement(wr::ToWrTransformProperty(
     646           0 :         info.mThumbAnimationId,
     647           0 :         transform));
     648             :   }
     649           0 :   aTxn.AppendTransformProperties(scrollbarTransforms);
     650             : 
     651           0 :   if (activeAnimations) {
     652           0 :     RefPtr<CompositorController> controller;
     653           0 :     CompositorBridgeParent::CallWithIndirectShadowTree(mRootLayersId,
     654           0 :       [&](LayerTreeState& aState) -> void {
     655           0 :         controller = aState.GetCompositorController();
     656           0 :       });
     657           0 :     if (controller) {
     658           0 :       controller->ScheduleRenderOnCompositorThread();
     659             :     }
     660             :   }
     661           0 : }
     662             : 
     663             : // Compute the clip region to be used for a layer with an APZC. This function
     664             : // is only called for layers which actually have scrollable metrics and an APZC.
     665             : template<class ScrollNode> static ParentLayerIntRegion
     666           0 : ComputeClipRegion(const ScrollNode& aLayer)
     667             : {
     668           0 :   ParentLayerIntRegion clipRegion;
     669           0 :   if (aLayer.GetClipRect()) {
     670           0 :     clipRegion = *aLayer.GetClipRect();
     671             :   } else {
     672             :     // if there is no clip on this layer (which should only happen for the
     673             :     // root scrollable layer in a process, or for some of the LayerMetrics
     674             :     // expansions of a multi-metrics layer), fall back to using the comp
     675             :     // bounds which should be equivalent.
     676           0 :     clipRegion = RoundedToInt(aLayer.Metrics().GetCompositionBounds());
     677             :   }
     678             : 
     679           0 :   return clipRegion;
     680             : }
     681             : 
     682             : template<class ScrollNode> void
     683           0 : APZCTreeManager::PrintAPZCInfo(const ScrollNode& aLayer,
     684             :                                const AsyncPanZoomController* apzc)
     685             : {
     686           0 :   const FrameMetrics& metrics = aLayer.Metrics();
     687           0 :   mApzcTreeLog << "APZC " << apzc->GetGuid()
     688           0 :                << "\tcb=" << metrics.GetCompositionBounds()
     689           0 :                << "\tsr=" << metrics.GetScrollableRect()
     690           0 :                << (metrics.IsScrollInfoLayer() ? "\tscrollinfo" : "")
     691           0 :                << (apzc->HasScrollgrab() ? "\tscrollgrab" : "") << "\t"
     692           0 :                << aLayer.Metadata().GetContentDescription().get();
     693           0 : }
     694             : 
     695             : void
     696           0 : APZCTreeManager::AttachNodeToTree(HitTestingTreeNode* aNode,
     697             :                                   HitTestingTreeNode* aParent,
     698             :                                   HitTestingTreeNode* aNextSibling)
     699             : {
     700           0 :   if (aNextSibling) {
     701           0 :     aNextSibling->SetPrevSibling(aNode);
     702           0 :   } else if (aParent) {
     703           0 :     aParent->SetLastChild(aNode);
     704             :   } else {
     705           0 :     MOZ_ASSERT(!mRootNode);
     706           0 :     mRootNode = aNode;
     707           0 :     aNode->MakeRoot();
     708             :   }
     709           0 : }
     710             : 
     711             : template<class ScrollNode> static EventRegions
     712           0 : GetEventRegions(const ScrollNode& aLayer)
     713             : {
     714           0 :   if (aLayer.Metrics().IsScrollInfoLayer()) {
     715           0 :     ParentLayerIntRect compositionBounds(RoundedToInt(aLayer.Metrics().GetCompositionBounds()));
     716           0 :     nsIntRegion hitRegion(compositionBounds.ToUnknownRect());
     717           0 :     EventRegions eventRegions(hitRegion);
     718           0 :     eventRegions.mDispatchToContentHitRegion = eventRegions.mHitRegion;
     719           0 :     return eventRegions;
     720             :   }
     721           0 :   return aLayer.GetEventRegions();
     722             : }
     723             : 
     724             : 
     725             : 
     726             : already_AddRefed<HitTestingTreeNode>
     727           0 : APZCTreeManager::RecycleOrCreateNode(const RecursiveMutexAutoLock& aProofOfTreeLock,
     728             :                                      TreeBuildingState& aState,
     729             :                                      AsyncPanZoomController* aApzc,
     730             :                                      LayersId aLayersId)
     731             : {
     732             :   // Find a node without an APZC and return it. Note that unless the layer tree
     733             :   // actually changes, this loop should generally do an early-return on the
     734             :   // first iteration, so it should be cheap in the common case.
     735           0 :   for (int32_t i = aState.mNodesToDestroy.Length() - 1; i >= 0; i--) {
     736           0 :     RefPtr<HitTestingTreeNode> node = aState.mNodesToDestroy[i];
     737           0 :     if (node->IsRecyclable(aProofOfTreeLock)) {
     738           0 :       aState.mNodesToDestroy.RemoveElementAt(i);
     739           0 :       node->RecycleWith(aProofOfTreeLock, aApzc, aLayersId);
     740           0 :       return node.forget();
     741             :     }
     742             :   }
     743           0 :   RefPtr<HitTestingTreeNode> node = new HitTestingTreeNode(aApzc, false, aLayersId);
     744           0 :   return node.forget();
     745             : }
     746             : 
     747             : template<class ScrollNode> static EventRegionsOverride
     748           0 : GetEventRegionsOverride(HitTestingTreeNode* aParent,
     749             :                        const ScrollNode& aLayer)
     750             : {
     751             :   // Make it so that if the flag is set on the layer tree, it automatically
     752             :   // propagates to all the nodes in the corresponding subtree rooted at that
     753             :   // layer in the hit-test tree. This saves having to walk up the tree every
     754             :   // we want to see if a hit-test node is affected by this flag.
     755           0 :   EventRegionsOverride result = aLayer.GetEventRegionsOverride();
     756           0 :   if (result != EventRegionsOverride::NoOverride) {
     757             :     // Overrides should only ever get set for ref layers.
     758           0 :     MOZ_ASSERT(aLayer.GetReferentId());
     759             :   }
     760           0 :   if (aParent) {
     761           0 :     result |= aParent->GetEventRegionsOverride();
     762             :   }
     763           0 :   return result;
     764             : }
     765             : 
     766             : void
     767           0 : APZCTreeManager::StartScrollbarDrag(const ScrollableLayerGuid& aGuid,
     768             :                                     const AsyncDragMetrics& aDragMetrics)
     769             : {
     770           0 :   APZThreadUtils::AssertOnControllerThread();
     771             : 
     772           0 :   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
     773           0 :   if (!apzc) {
     774           0 :     NotifyScrollbarDragRejected(aGuid);
     775           0 :     return;
     776             :   }
     777             : 
     778           0 :   uint64_t inputBlockId = aDragMetrics.mDragStartSequenceNumber;
     779           0 :   mInputQueue->ConfirmDragBlock(inputBlockId, apzc, aDragMetrics);
     780             : }
     781             : 
     782             : bool
     783           0 : APZCTreeManager::StartAutoscroll(const ScrollableLayerGuid& aGuid,
     784             :                                  const ScreenPoint& aAnchorLocation)
     785             : {
     786           0 :   APZThreadUtils::AssertOnControllerThread();
     787             : 
     788           0 :   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
     789           0 :   if (!apzc) {
     790           0 :     if (XRE_IsGPUProcess()) {
     791             :       // If we're in the compositor process, the "return false" will be
     792             :       // ignored because the query comes over the PAPZCTreeManager protocol
     793             :       // via an async message. In this case, send an explicit rejection
     794             :       // message to content.
     795           0 :       NotifyAutoscrollRejected(aGuid);
     796             :     }
     797             :     return false;
     798             :   }
     799             : 
     800           0 :   apzc->StartAutoscroll(aAnchorLocation);
     801           0 :   return true;
     802             : }
     803             : 
     804             : void
     805           0 : APZCTreeManager::StopAutoscroll(const ScrollableLayerGuid& aGuid)
     806             : {
     807           0 :   APZThreadUtils::AssertOnControllerThread();
     808             : 
     809           0 :   if (RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid)) {
     810           0 :     apzc->StopAutoscroll();
     811             :   }
     812           0 : }
     813             : 
     814             : void
     815           0 : APZCTreeManager::NotifyScrollbarDragRejected(const ScrollableLayerGuid& aGuid) const
     816             : {
     817             :   RefPtr<GeckoContentController> controller =
     818           0 :     GetContentController(aGuid.mLayersId);
     819           0 :   MOZ_ASSERT(controller);
     820           0 :   controller->NotifyAsyncScrollbarDragRejected(aGuid.mScrollId);
     821           0 : }
     822             : 
     823             : void
     824           0 : APZCTreeManager::NotifyAutoscrollRejected(const ScrollableLayerGuid& aGuid) const
     825             : {
     826             :   RefPtr<GeckoContentController> controller =
     827           0 :     GetContentController(aGuid.mLayersId);
     828           0 :   MOZ_ASSERT(controller);
     829           0 :   controller->NotifyAsyncAutoscrollRejected(aGuid.mScrollId);
     830           0 : }
     831             : 
     832             : template<class ScrollNode> HitTestingTreeNode*
     833           0 : APZCTreeManager::PrepareNodeForLayer(const RecursiveMutexAutoLock& aProofOfTreeLock,
     834             :                                      const ScrollNode& aLayer,
     835             :                                      const FrameMetrics& aMetrics,
     836             :                                      LayersId aLayersId,
     837             :                                      const AncestorTransform& aAncestorTransform,
     838             :                                      HitTestingTreeNode* aParent,
     839             :                                      HitTestingTreeNode* aNextSibling,
     840             :                                      TreeBuildingState& aState)
     841             : {
     842           0 :   bool needsApzc = true;
     843           0 :   if (!aMetrics.IsScrollable()) {
     844           0 :     needsApzc = false;
     845             :   }
     846             : 
     847             :   // XXX: As a future optimization we can probably stick these things on the
     848             :   // TreeBuildingState, and update them as we change layers id during the
     849             :   // traversal
     850           0 :   RefPtr<GeckoContentController> geckoContentController;
     851           0 :   RefPtr<MetricsSharingController> crossProcessSharingController;
     852           0 :   CompositorBridgeParent::CallWithIndirectShadowTree(aLayersId,
     853           0 :       [&](LayerTreeState& lts) -> void {
     854           0 :         geckoContentController = lts.mController;
     855           0 :         crossProcessSharingController = lts.CrossProcessSharingController();
     856           0 :       });
     857             : 
     858           0 :   if (!geckoContentController) {
     859           0 :     needsApzc = false;
     860             :   }
     861             : 
     862           0 :   bool parentHasPerspective = aState.mParentHasPerspective.top();
     863             : 
     864           0 :   RefPtr<HitTestingTreeNode> node = nullptr;
     865           0 :   if (!needsApzc) {
     866             :     // Note: if layer properties must be propagated to nodes, RecvUpdate in
     867             :     // LayerTransactionParent.cpp must ensure that APZ will be notified
     868             :     // when those properties change.
     869           0 :     node = RecycleOrCreateNode(aProofOfTreeLock, aState, nullptr, aLayersId);
     870           0 :     AttachNodeToTree(node, aParent, aNextSibling);
     871           0 :     node->SetHitTestData(
     872             :         GetEventRegions(aLayer),
     873             :         aLayer.GetVisibleRegion(),
     874             :         aLayer.GetTransformTyped(),
     875           0 :         (!parentHasPerspective && aLayer.GetClipRect())
     876           0 :           ? Some(ParentLayerIntRegion(*aLayer.GetClipRect()))
     877             :           : Nothing(),
     878           0 :         GetEventRegionsOverride(aParent, aLayer),
     879             :         aLayer.IsBackfaceHidden());
     880           0 :     node->SetScrollbarData(aLayer.GetScrollbarAnimationId(),
     881             :                            aLayer.GetScrollbarData());
     882           0 :     node->SetFixedPosData(aLayer.GetFixedPositionScrollContainerId());
     883           0 :     return node;
     884             :   }
     885             : 
     886           0 :   AsyncPanZoomController* apzc = nullptr;
     887             :   // If we get here, aLayer is a scrollable layer and somebody
     888             :   // has registered a GeckoContentController for it, so we need to ensure
     889             :   // it has an APZC instance to manage its scrolling.
     890             : 
     891             :   // aState.mApzcMap allows reusing the exact same APZC instance for different layers
     892             :   // with the same FrameMetrics data. This is needed because in some cases content
     893             :   // that is supposed to scroll together is split into multiple layers because of
     894             :   // e.g. non-scrolling content interleaved in z-index order.
     895           0 :   ScrollableLayerGuid guid(aLayersId, aMetrics);
     896           0 :   auto insertResult = aState.mApzcMap.insert(std::make_pair(guid, static_cast<AsyncPanZoomController*>(nullptr)));
     897           0 :   if (!insertResult.second) {
     898           0 :     apzc = insertResult.first->second;
     899           0 :     PrintAPZCInfo(aLayer, apzc);
     900             :   }
     901             :   APZCTM_LOG("Found APZC %p for layer %p with identifiers %" PRIx64 " %" PRId64 "\n",
     902             :       apzc, aLayer.GetLayer(), uint64_t(guid.mLayersId), guid.mScrollId);
     903             : 
     904             :   // If we haven't encountered a layer already with the same metrics, then we need to
     905             :   // do the full reuse-or-make-an-APZC algorithm, which is contained inside the block
     906             :   // below.
     907           0 :   if (apzc == nullptr) {
     908           0 :     apzc = aLayer.GetApzc();
     909             : 
     910             :     // If the content represented by the scrollable layer has changed (which may
     911             :     // be possible because of DLBI heuristics) then we don't want to keep using
     912             :     // the same old APZC for the new content. Also, when reparenting a tab into a
     913             :     // new window a layer might get moved to a different layer tree with a
     914             :     // different APZCTreeManager. In these cases we don't want to reuse the same
     915             :     // APZC, so null it out so we run through the code to find another one or
     916             :     // create one.
     917           0 :     if (apzc && (!apzc->Matches(guid) || !apzc->HasTreeManager(this))) {
     918           0 :       apzc = nullptr;
     919             :     }
     920             : 
     921             :     // See if we can find an APZC from the previous tree that matches the
     922             :     // ScrollableLayerGuid from this layer. If there is one, then we know that
     923             :     // the layout of the page changed causing the layer tree to be rebuilt, but
     924             :     // the underlying content for the APZC is still there somewhere. Therefore,
     925             :     // we want to find the APZC instance and continue using it here.
     926             :     //
     927             :     // We particularly want to find the primary-holder node from the previous
     928             :     // tree that matches, because we don't want that node to get destroyed. If
     929             :     // it does get destroyed, then the APZC will get destroyed along with it by
     930             :     // definition, but we want to keep that APZC around in the new tree.
     931             :     // We leave non-primary-holder nodes in the destroy list because we don't
     932             :     // care about those nodes getting destroyed.
     933           0 :     for (size_t i = 0; i < aState.mNodesToDestroy.Length(); i++) {
     934           0 :       RefPtr<HitTestingTreeNode> n = aState.mNodesToDestroy[i];
     935           0 :       if (n->IsPrimaryHolder() && n->GetApzc() && n->GetApzc()->Matches(guid)) {
     936           0 :         node = n;
     937           0 :         if (apzc != nullptr) {
     938             :           // If there is an APZC already then it should match the one from the
     939             :           // old primary-holder node
     940           0 :           MOZ_ASSERT(apzc == node->GetApzc());
     941             :         }
     942           0 :         apzc = node->GetApzc();
     943           0 :         break;
     944             :       }
     945             :     }
     946             : 
     947             :     // The APZC we get off the layer may have been destroyed previously if the
     948             :     // layer was inactive or omitted from the layer tree for whatever reason
     949             :     // from a layers update. If it later comes back it will have a reference to
     950             :     // a destroyed APZC and so we need to throw that out and make a new one.
     951           0 :     bool newApzc = (apzc == nullptr || apzc->IsDestroyed());
     952           0 :     if (newApzc) {
     953           0 :       apzc = NewAPZCInstance(aLayersId, geckoContentController);
     954           0 :       apzc->SetCompositorController(aState.mCompositorController.get());
     955           0 :       if (crossProcessSharingController) {
     956           0 :         apzc->SetMetricsSharingController(crossProcessSharingController);
     957             :       } else {
     958           0 :         apzc->SetMetricsSharingController(aState.mInProcessSharingController.get());
     959             :       }
     960           0 :       MOZ_ASSERT(node == nullptr);
     961           0 :       node = new HitTestingTreeNode(apzc, true, aLayersId);
     962             :     } else {
     963             :       // If we are re-using a node for this layer clear the tree pointers
     964             :       // so that it doesn't continue pointing to nodes that might no longer
     965             :       // be in the tree. These pointers will get reset properly as we continue
     966             :       // building the tree. Also remove it from the set of nodes that are going
     967             :       // to be destroyed, because it's going to remain active.
     968           0 :       aState.mNodesToDestroy.RemoveElement(node);
     969           0 :       node->SetPrevSibling(nullptr);
     970           0 :       node->SetLastChild(nullptr);
     971             :     }
     972             : 
     973             :     APZCTM_LOG("Using APZC %p for layer %p with identifiers %" PRIx64 " %" PRId64 "\n",
     974             :         apzc, aLayer.GetLayer(), uint64_t(aLayersId), aMetrics.GetScrollId());
     975             : 
     976           0 :     apzc->NotifyLayersUpdated(aLayer.Metadata(), aState.mIsFirstPaint,
     977           0 :         aLayersId == aState.mOriginatingLayersId);
     978             : 
     979             :     // Since this is the first time we are encountering an APZC with this guid,
     980             :     // the node holding it must be the primary holder. It may be newly-created
     981             :     // or not, depending on whether it went through the newApzc branch above.
     982           0 :     MOZ_ASSERT(node->IsPrimaryHolder() && node->GetApzc() && node->GetApzc()->Matches(guid));
     983             : 
     984             :     Maybe<ParentLayerIntRegion> clipRegion = parentHasPerspective
     985             :       ? Nothing()
     986           0 :       : Some(ComputeClipRegion(aLayer));
     987           0 :     node->SetHitTestData(
     988             :         GetEventRegions(aLayer),
     989             :         aLayer.GetVisibleRegion(),
     990             :         aLayer.GetTransformTyped(),
     991             :         clipRegion,
     992           0 :         GetEventRegionsOverride(aParent, aLayer),
     993             :         aLayer.IsBackfaceHidden());
     994           0 :     apzc->SetAncestorTransform(aAncestorTransform);
     995             : 
     996           0 :     PrintAPZCInfo(aLayer, apzc);
     997             : 
     998             :     // Bind the APZC instance into the tree of APZCs
     999           0 :     AttachNodeToTree(node, aParent, aNextSibling);
    1000             : 
    1001             :     // For testing, log the parent scroll id of every APZC that has a
    1002             :     // parent. This allows test code to reconstruct the APZC tree.
    1003             :     // Note that we currently only do this for APZCs in the layer tree
    1004             :     // that originated the update, because the only identifying information
    1005             :     // we are logging about APZCs is the scroll id, and otherwise we could
    1006             :     // confuse APZCs from different layer trees with the same scroll id.
    1007           0 :     if (aLayersId == aState.mOriginatingLayersId) {
    1008           0 :       if (apzc->HasNoParentWithSameLayersId()) {
    1009           0 :         aState.mPaintLogger.LogTestData(aMetrics.GetScrollId(),
    1010             :             "hasNoParentWithSameLayersId", true);
    1011             :       } else {
    1012           0 :         MOZ_ASSERT(apzc->GetParent());
    1013           0 :         aState.mPaintLogger.LogTestData(aMetrics.GetScrollId(),
    1014           0 :             "parentScrollId", apzc->GetParent()->GetGuid().mScrollId);
    1015             :       }
    1016           0 :       if (aMetrics.IsRootContent()) {
    1017           0 :         aState.mPaintLogger.LogTestData(aMetrics.GetScrollId(),
    1018             :             "isRootContent", true);
    1019             :       }
    1020             :       // Note that the async scroll offset is in ParentLayer pixels
    1021           0 :       aState.mPaintLogger.LogTestData(aMetrics.GetScrollId(), "asyncScrollOffset",
    1022           0 :           apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting));
    1023           0 :       aState.mPaintLogger.LogTestData(aMetrics.GetScrollId(), "hasAsyncKeyScrolled",
    1024           0 :           apzc->TestHasAsyncKeyScrolled());
    1025             :     }
    1026             : 
    1027           0 :     if (newApzc) {
    1028           0 :       auto it = mZoomConstraints.find(guid);
    1029           0 :       if (it != mZoomConstraints.end()) {
    1030             :         // We have a zoomconstraints for this guid, apply it.
    1031           0 :         apzc->UpdateZoomConstraints(it->second);
    1032           0 :       } else if (!apzc->HasNoParentWithSameLayersId()) {
    1033             :         // This is a sub-APZC, so inherit the zoom constraints from its parent.
    1034             :         // This ensures that if e.g. user-scalable=no was specified, none of the
    1035             :         // APZCs for that subtree allow double-tap to zoom.
    1036           0 :         apzc->UpdateZoomConstraints(apzc->GetParent()->GetZoomConstraints());
    1037             :       }
    1038             :       // Otherwise, this is the root of a layers id, but we didn't have a saved
    1039             :       // zoom constraints. Leave it empty for now.
    1040             :     }
    1041             : 
    1042             :     // Add a guid -> APZC mapping for the newly created APZC.
    1043           0 :     insertResult.first->second = apzc;
    1044             :   } else {
    1045             :     // We already built an APZC earlier in this tree walk, but we have another layer
    1046             :     // now that will also be using that APZC. The hit-test region on the APZC needs
    1047             :     // to be updated to deal with the new layer's hit region.
    1048             : 
    1049           0 :     node = RecycleOrCreateNode(aProofOfTreeLock, aState, apzc, aLayersId);
    1050           0 :     AttachNodeToTree(node, aParent, aNextSibling);
    1051             : 
    1052             :     // Even though different layers associated with a given APZC may be at
    1053             :     // different levels in the layer tree (e.g. one being an uncle of another),
    1054             :     // we require from Layout that the CSS transforms up to their common
    1055             :     // ancestor be roughly the same. There are cases in which the transforms
    1056             :     // are not exactly the same, for example if the parent is container layer
    1057             :     // for an opacity, and this container layer has a resolution-induced scale
    1058             :     // as its base transform and a prescale that is supposed to undo that scale.
    1059             :     // Due to floating point inaccuracies those transforms can end up not quite
    1060             :     // canceling each other. That's why we're using a fuzzy comparison here
    1061             :     // instead of an exact one.
    1062             :     // In addition, two ancestor transforms are allowed to differ if one of
    1063             :     // them contains a perspective transform component and the other does not.
    1064             :     // This represents situations where some content in a scrollable frame
    1065             :     // is subject to a perspective transform and other content does not.
    1066             :     // In such cases, go with the one that does not include the perspective
    1067             :     // component; the perspective transform is remembered and applied to the
    1068             :     // children instead.
    1069           0 :     if (!aAncestorTransform.CombinedTransform().FuzzyEqualsMultiplicative(apzc->GetAncestorTransform())) {
    1070             :       typedef TreeBuildingState::DeferredTransformMap::value_type PairType;
    1071           0 :       if (!aAncestorTransform.ContainsPerspectiveTransform() &&
    1072           0 :           !apzc->AncestorTransformContainsPerspective()) {
    1073           0 :         MOZ_ASSERT(false, "Two layers that scroll together have different ancestor transforms");
    1074           0 :       } else if (!aAncestorTransform.ContainsPerspectiveTransform()) {
    1075           0 :         aState.mPerspectiveTransformsDeferredToChildren.insert(
    1076             :             PairType{apzc, apzc->GetAncestorTransformPerspective()});
    1077           0 :         apzc->SetAncestorTransform(aAncestorTransform);
    1078             :       } else {
    1079           0 :         aState.mPerspectiveTransformsDeferredToChildren.insert(
    1080             :             PairType{apzc, aAncestorTransform.GetPerspectiveTransform()});
    1081             :       }
    1082             :     }
    1083             : 
    1084             :     Maybe<ParentLayerIntRegion> clipRegion = parentHasPerspective
    1085             :       ? Nothing()
    1086           0 :       : Some(ComputeClipRegion(aLayer));
    1087           0 :     node->SetHitTestData(
    1088             :         GetEventRegions(aLayer),
    1089             :         aLayer.GetVisibleRegion(),
    1090             :         aLayer.GetTransformTyped(),
    1091             :         clipRegion,
    1092           0 :         GetEventRegionsOverride(aParent, aLayer),
    1093             :         aLayer.IsBackfaceHidden());
    1094             :   }
    1095             : 
    1096             :   // Note: if layer properties must be propagated to nodes, RecvUpdate in
    1097             :   // LayerTransactionParent.cpp must ensure that APZ will be notified
    1098             :   // when those properties change.
    1099           0 :   node->SetScrollbarData(aLayer.GetScrollbarAnimationId(),
    1100             :                          aLayer.GetScrollbarData());
    1101           0 :   node->SetFixedPosData(aLayer.GetFixedPositionScrollContainerId());
    1102           0 :   return node;
    1103             : }
    1104             : 
    1105             : template<typename PanGestureOrScrollWheelInput>
    1106             : static bool
    1107           0 : WillHandleInput(const PanGestureOrScrollWheelInput& aPanInput)
    1108             : {
    1109           0 :   if (!XRE_IsParentProcess() || !NS_IsMainThread()) {
    1110             :     return true;
    1111             :   }
    1112             : 
    1113           0 :   WidgetWheelEvent wheelEvent = aPanInput.ToWidgetWheelEvent(nullptr);
    1114           0 :   return APZInputBridge::ActionForWheelEvent(&wheelEvent).isSome();
    1115             : }
    1116             : 
    1117             : void
    1118           0 : APZCTreeManager::FlushApzRepaints(LayersId aLayersId)
    1119             : {
    1120             :   // Previously, paints were throttled and therefore this method was used to
    1121             :   // ensure any pending paints were flushed. Now, paints are flushed
    1122             :   // immediately, so it is safe to simply send a notification now.
    1123             :   APZCTM_LOG("Flushing repaints for layers id 0x%" PRIx64 "\n", uint64_t(aLayersId));
    1124           0 :   RefPtr<GeckoContentController> controller = GetContentController(aLayersId);
    1125           0 :   MOZ_ASSERT(controller);
    1126           0 :   controller->DispatchToRepaintThread(
    1127           0 :     NewRunnableMethod("layers::GeckoContentController::NotifyFlushComplete",
    1128             :                       controller,
    1129           0 :                       &GeckoContentController::NotifyFlushComplete));
    1130           0 : }
    1131             : 
    1132             : nsEventStatus
    1133           0 : APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
    1134             :                                    ScrollableLayerGuid* aOutTargetGuid,
    1135             :                                    uint64_t* aOutInputBlockId)
    1136             : {
    1137           0 :   APZThreadUtils::AssertOnControllerThread();
    1138             : 
    1139             :   // Use a RAII class for updating the focus sequence number of this event
    1140           0 :   AutoFocusSequenceNumberSetter focusSetter(mFocusState, aEvent);
    1141             : 
    1142             : #if defined(MOZ_WIDGET_ANDROID)
    1143             :   MOZ_ASSERT(mToolbarAnimator);
    1144             :   ScreenPoint scrollOffset;
    1145             :   {
    1146             :     RecursiveMutexAutoLock lock(mTreeLock);
    1147             :     RefPtr<AsyncPanZoomController> apzc = FindRootContentOrRootApzc();
    1148             :     if (apzc) {
    1149             :       scrollOffset = ViewAs<ScreenPixel>(apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting),
    1150             :                                          PixelCastJustification::ScreenIsParentLayerForRoot);
    1151             :     }
    1152             :   }
    1153             :   RefPtr<APZCTreeManager> self = this;
    1154             :   nsEventStatus isConsumed = mToolbarAnimator->ReceiveInputEvent(self, aEvent, scrollOffset);
    1155             :   // Check if the mToolbarAnimator consumed the event.
    1156             :   if (isConsumed == nsEventStatus_eConsumeNoDefault) {
    1157             :     APZCTM_LOG("Dynamic toolbar consumed event");
    1158             :     return isConsumed;
    1159             :   }
    1160             : #endif // (MOZ_WIDGET_ANDROID)
    1161             : 
    1162             :   // Initialize aOutInputBlockId to a sane value, and then later we overwrite
    1163             :   // it if the input event goes into a block.
    1164           0 :   if (aOutInputBlockId) {
    1165           0 :     *aOutInputBlockId = InputBlockState::NO_BLOCK_ID;
    1166             :   }
    1167           0 :   nsEventStatus result = nsEventStatus_eIgnore;
    1168           0 :   CompositorHitTestInfo hitResult = CompositorHitTestInfo::eInvisibleToHitTest;
    1169           0 :   switch (aEvent.mInputType) {
    1170             :     case MULTITOUCH_INPUT: {
    1171           0 :       MultiTouchInput& touchInput = aEvent.AsMultiTouchInput();
    1172           0 :       result = ProcessTouchInput(touchInput, aOutTargetGuid, aOutInputBlockId);
    1173           0 :       break;
    1174             :     } case MOUSE_INPUT: {
    1175           0 :       MouseInput& mouseInput = aEvent.AsMouseInput();
    1176           0 :       mouseInput.mHandledByAPZ = true;
    1177             : 
    1178           0 :       mCurrentMousePosition = mouseInput.mOrigin;
    1179             : 
    1180           0 :       bool startsDrag = DragTracker::StartsDrag(mouseInput);
    1181           0 :       if (startsDrag) {
    1182             :         // If this is the start of a drag we need to unambiguously know if it's
    1183             :         // going to land on a scrollbar or not. We can't apply an untransform
    1184             :         // here without knowing that, so we need to ensure the untransform is
    1185             :         // a no-op.
    1186           0 :         FlushRepaintsToClearScreenToGeckoTransform();
    1187             :       }
    1188             : 
    1189           0 :       HitTestingTreeNodeAutoLock hitScrollbarNode;
    1190           0 :       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(mouseInput.mOrigin,
    1191           0 :             &hitResult, &hitScrollbarNode);
    1192           0 :       bool hitScrollbar = (bool)hitScrollbarNode;
    1193             : 
    1194             :       // When the mouse is outside the window we still want to handle dragging
    1195             :       // but we won't find an APZC. Fallback to root APZC then.
    1196             :       { // scope lock
    1197           0 :         RecursiveMutexAutoLock lock(mTreeLock);
    1198           0 :         if (!apzc && mRootNode) {
    1199           0 :           apzc = mRootNode->GetApzc();
    1200             :         }
    1201             :       }
    1202             : 
    1203           0 :       if (apzc) {
    1204           0 :         if (gfxPrefs::APZTestLoggingEnabled() && mouseInput.mType == MouseInput::MOUSE_HITTEST) {
    1205           0 :           ScrollableLayerGuid guid = apzc->GetGuid();
    1206             : 
    1207           0 :           MutexAutoLock lock(mTestDataLock);
    1208           0 :           auto it = mTestData.find(guid.mLayersId);
    1209           0 :           MOZ_ASSERT(it != mTestData.end());
    1210           0 :           it->second->RecordHitResult(mouseInput.mOrigin, hitResult, guid.mScrollId);
    1211             :         }
    1212             : 
    1213           0 :         TargetConfirmationFlags confFlags{hitResult};
    1214           0 :         bool apzDragEnabled = gfxPrefs::APZDragEnabled();
    1215           0 :         if (apzDragEnabled && hitScrollbar) {
    1216             :           // If scrollbar dragging is enabled and we hit a scrollbar, wait
    1217             :           // for the main-thread confirmation because it contains drag metrics
    1218             :           // that we need.
    1219           0 :           confFlags.mTargetConfirmed = false;
    1220             :         }
    1221           0 :         result = mInputQueue->ReceiveInputEvent(
    1222           0 :           apzc, confFlags, mouseInput, aOutInputBlockId);
    1223             : 
    1224             :         // If we're starting an async scrollbar drag
    1225           0 :         if (apzDragEnabled && startsDrag && hitScrollbarNode &&
    1226           0 :             hitScrollbarNode->IsScrollThumbNode() &&
    1227           0 :             hitScrollbarNode->GetScrollbarData().mThumbIsAsyncDraggable) {
    1228           0 :           SetupScrollbarDrag(mouseInput, hitScrollbarNode, apzc.get());
    1229             :         }
    1230             : 
    1231           0 :         if (result == nsEventStatus_eConsumeDoDefault) {
    1232             :           // This input event is part of a drag block, so whether or not it is
    1233             :           // directed at a scrollbar depends on whether the drag block started
    1234             :           // on a scrollbar.
    1235           0 :           hitScrollbar = mInputQueue->IsDragOnScrollbar(hitScrollbar);
    1236             :         }
    1237             : 
    1238             :         // Update the out-parameters so they are what the caller expects.
    1239           0 :         apzc->GetGuid(aOutTargetGuid);
    1240             : 
    1241           0 :         if (!hitScrollbar) {
    1242             :           // The input was not targeted at a scrollbar, so we untransform it
    1243             :           // like we do for other content. Scrollbars are "special" because they
    1244             :           // have special handling in AsyncCompositionManager when resolution is
    1245             :           // applied. TODO: we should find a better way to deal with this.
    1246           0 :           ScreenToParentLayerMatrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
    1247           0 :           ParentLayerToScreenMatrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
    1248           0 :           ScreenToScreenMatrix4x4 outTransform = transformToApzc * transformToGecko;
    1249             :           Maybe<ScreenPoint> untransformedRefPoint = UntransformBy(
    1250           0 :             outTransform, mouseInput.mOrigin);
    1251           0 :           if (untransformedRefPoint) {
    1252           0 :             mouseInput.mOrigin = *untransformedRefPoint;
    1253             :           }
    1254             :         } else {
    1255             :           // Likewise, if the input was targeted at a scrollbar, we don't want to
    1256             :           // apply the callback transform in the main thread, so we remove the
    1257             :           // scrollid from the guid. We need to keep the layersId intact so
    1258             :           // that the response from the child process doesn't get discarded.
    1259           0 :           aOutTargetGuid->mScrollId = FrameMetrics::NULL_SCROLL_ID;
    1260             :         }
    1261             :       }
    1262             :       break;
    1263             :     } case SCROLLWHEEL_INPUT: {
    1264           0 :       FlushRepaintsToClearScreenToGeckoTransform();
    1265             : 
    1266           0 :       ScrollWheelInput& wheelInput = aEvent.AsScrollWheelInput();
    1267           0 :       wheelInput.mHandledByAPZ = WillHandleInput(wheelInput);
    1268           0 :       if (!wheelInput.mHandledByAPZ) {
    1269           0 :         return result;
    1270             :       }
    1271             : 
    1272           0 :       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(wheelInput.mOrigin,
    1273           0 :                                                             &hitResult);
    1274           0 :       if (apzc) {
    1275           0 :         MOZ_ASSERT(hitResult != CompositorHitTestInfo::eInvisibleToHitTest);
    1276             : 
    1277           0 :         if (wheelInput.mAPZAction == APZWheelAction::PinchZoom) {
    1278             :           // The mousewheel may have hit a subframe, but we want to send the
    1279             :           // pinch-zoom events to the root-content APZC.
    1280             :           {
    1281           0 :             RecursiveMutexAutoLock lock(mTreeLock);
    1282           0 :             apzc = FindRootContentApzcForLayersId(apzc->GetLayersId());
    1283             :           }
    1284           0 :           if (apzc) {
    1285           0 :             SynthesizePinchGestureFromMouseWheel(wheelInput, apzc);
    1286             :           }
    1287           0 :           return nsEventStatus_eConsumeNoDefault;
    1288             :         }
    1289             : 
    1290           0 :         MOZ_ASSERT(wheelInput.mAPZAction == APZWheelAction::Scroll);
    1291             : 
    1292             :         // For wheel events, the call to ReceiveInputEvent below may result in
    1293             :         // scrolling, which changes the async transform. However, the event we
    1294             :         // want to pass to gecko should be the pre-scroll event coordinates,
    1295             :         // transformed into the gecko space. (pre-scroll because the mouse
    1296             :         // cursor is stationary during wheel scrolling, unlike touchmove
    1297             :         // events). Since we just flushed the pending repaints the transform to
    1298             :         // gecko space should only consist of overscroll-cancelling transforms.
    1299           0 :         ScreenToScreenMatrix4x4 transformToGecko = GetScreenToApzcTransform(apzc)
    1300           0 :                                                  * GetApzcToGeckoTransform(apzc);
    1301             :         Maybe<ScreenPoint> untransformedOrigin = UntransformBy(
    1302           0 :           transformToGecko, wheelInput.mOrigin);
    1303             : 
    1304           0 :         if (!untransformedOrigin) {
    1305           0 :           return result;
    1306             :         }
    1307             : 
    1308           0 :         result = mInputQueue->ReceiveInputEvent(
    1309             :           apzc,
    1310             :           TargetConfirmationFlags{hitResult},
    1311           0 :           wheelInput, aOutInputBlockId);
    1312             : 
    1313             :         // Update the out-parameters so they are what the caller expects.
    1314           0 :         apzc->GetGuid(aOutTargetGuid);
    1315           0 :         wheelInput.mOrigin = *untransformedOrigin;
    1316             :       }
    1317           0 :       break;
    1318             :     } case PANGESTURE_INPUT: {
    1319           0 :       FlushRepaintsToClearScreenToGeckoTransform();
    1320             : 
    1321           0 :       PanGestureInput& panInput = aEvent.AsPanGestureInput();
    1322           0 :       panInput.mHandledByAPZ = WillHandleInput(panInput);
    1323           0 :       if (!panInput.mHandledByAPZ) {
    1324           0 :         return result;
    1325             :       }
    1326             : 
    1327             :       // If/when we enable support for pan inputs off-main-thread, we'll need
    1328             :       // to duplicate this EventStateManager code or something. See the call to
    1329             :       // GetUserPrefsForWheelEvent in IAPZCTreeManager.cpp for why these fields
    1330             :       // are stored separately.
    1331           0 :       MOZ_ASSERT(NS_IsMainThread());
    1332           0 :       WidgetWheelEvent wheelEvent = panInput.ToWidgetWheelEvent(nullptr);
    1333           0 :       EventStateManager::GetUserPrefsForWheelEvent(&wheelEvent,
    1334             :         &panInput.mUserDeltaMultiplierX,
    1335           0 :         &panInput.mUserDeltaMultiplierY);
    1336             : 
    1337           0 :       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(panInput.mPanStartPoint,
    1338           0 :                                                             &hitResult);
    1339           0 :       if (apzc) {
    1340           0 :         MOZ_ASSERT(hitResult != CompositorHitTestInfo::eInvisibleToHitTest);
    1341             : 
    1342             :         // For pan gesture events, the call to ReceiveInputEvent below may result in
    1343             :         // scrolling, which changes the async transform. However, the event we
    1344             :         // want to pass to gecko should be the pre-scroll event coordinates,
    1345             :         // transformed into the gecko space. (pre-scroll because the mouse
    1346             :         // cursor is stationary during pan gesture scrolling, unlike touchmove
    1347             :         // events). Since we just flushed the pending repaints the transform to
    1348             :         // gecko space should only consist of overscroll-cancelling transforms.
    1349           0 :         ScreenToScreenMatrix4x4 transformToGecko = GetScreenToApzcTransform(apzc)
    1350           0 :                                                  * GetApzcToGeckoTransform(apzc);
    1351             :         Maybe<ScreenPoint> untransformedStartPoint = UntransformBy(
    1352           0 :           transformToGecko, panInput.mPanStartPoint);
    1353             :         Maybe<ScreenPoint> untransformedDisplacement = UntransformVector(
    1354           0 :             transformToGecko, panInput.mPanDisplacement, panInput.mPanStartPoint);
    1355             : 
    1356           0 :         if (!untransformedStartPoint || !untransformedDisplacement) {
    1357           0 :           return result;
    1358             :         }
    1359             : 
    1360           0 :         result = mInputQueue->ReceiveInputEvent(
    1361             :             apzc,
    1362             :             TargetConfirmationFlags{hitResult},
    1363           0 :             panInput, aOutInputBlockId);
    1364             : 
    1365             :         // Update the out-parameters so they are what the caller expects.
    1366           0 :         apzc->GetGuid(aOutTargetGuid);
    1367           0 :         panInput.mPanStartPoint = *untransformedStartPoint;
    1368           0 :         panInput.mPanDisplacement = *untransformedDisplacement;
    1369             : 
    1370           0 :         panInput.mOverscrollBehaviorAllowsSwipe =
    1371           0 :             apzc->OverscrollBehaviorAllowsSwipe();
    1372             :       }
    1373           0 :       break;
    1374             :     } case PINCHGESTURE_INPUT: {  // note: no one currently sends these
    1375           0 :       PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput();
    1376           0 :       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(pinchInput.mFocusPoint,
    1377           0 :                                                             &hitResult);
    1378           0 :       if (apzc) {
    1379           0 :         MOZ_ASSERT(hitResult != CompositorHitTestInfo::eInvisibleToHitTest);
    1380             : 
    1381           0 :         ScreenToScreenMatrix4x4 outTransform = GetScreenToApzcTransform(apzc)
    1382           0 :                                              * GetApzcToGeckoTransform(apzc);
    1383             :         Maybe<ScreenPoint> untransformedFocusPoint = UntransformBy(
    1384           0 :           outTransform, pinchInput.mFocusPoint);
    1385             : 
    1386           0 :         if (!untransformedFocusPoint) {
    1387           0 :           return result;
    1388             :         }
    1389             : 
    1390           0 :         result = mInputQueue->ReceiveInputEvent(
    1391             :             apzc,
    1392             :             TargetConfirmationFlags{hitResult},
    1393           0 :             pinchInput, aOutInputBlockId);
    1394             : 
    1395             :         // Update the out-parameters so they are what the caller expects.
    1396           0 :         apzc->GetGuid(aOutTargetGuid);
    1397           0 :         pinchInput.mFocusPoint = *untransformedFocusPoint;
    1398             :       }
    1399           0 :       break;
    1400             :     } case TAPGESTURE_INPUT: {  // note: no one currently sends these
    1401           0 :       TapGestureInput& tapInput = aEvent.AsTapGestureInput();
    1402           0 :       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(tapInput.mPoint,
    1403           0 :                                                             &hitResult);
    1404           0 :       if (apzc) {
    1405           0 :         MOZ_ASSERT(hitResult != CompositorHitTestInfo::eInvisibleToHitTest);
    1406             : 
    1407           0 :         ScreenToScreenMatrix4x4 outTransform = GetScreenToApzcTransform(apzc)
    1408           0 :                                              * GetApzcToGeckoTransform(apzc);
    1409             :         Maybe<ScreenIntPoint> untransformedPoint =
    1410           0 :           UntransformBy(outTransform, tapInput.mPoint);
    1411             : 
    1412           0 :         if (!untransformedPoint) {
    1413           0 :           return result;
    1414             :         }
    1415             : 
    1416           0 :         result = mInputQueue->ReceiveInputEvent(
    1417             :             apzc,
    1418             :             TargetConfirmationFlags{hitResult},
    1419           0 :             tapInput, aOutInputBlockId);
    1420             : 
    1421             :         // Update the out-parameters so they are what the caller expects.
    1422           0 :         apzc->GetGuid(aOutTargetGuid);
    1423           0 :         tapInput.mPoint = *untransformedPoint;
    1424             :       }
    1425           0 :       break;
    1426             :     } case KEYBOARD_INPUT: {
    1427             :       // Disable async keyboard scrolling when accessibility.browsewithcaret is enabled
    1428           0 :       if (!gfxPrefs::APZKeyboardEnabled() ||
    1429           0 :           gfxPrefs::AccessibilityBrowseWithCaret()) {
    1430             :         APZ_KEY_LOG("Skipping key input from invalid prefs\n");
    1431           0 :         return result;
    1432             :       }
    1433             : 
    1434           0 :       KeyboardInput& keyInput = aEvent.AsKeyboardInput();
    1435             : 
    1436             :       // Try and find a matching shortcut for this keyboard input
    1437           0 :       Maybe<KeyboardShortcut> shortcut = mKeyboardMap.FindMatch(keyInput);
    1438             : 
    1439           0 :       if (!shortcut) {
    1440             :         APZ_KEY_LOG("Skipping key input with no shortcut\n");
    1441             : 
    1442             :         // If we don't have a shortcut for this key event, then we can keep our focus
    1443             :         // only if we know there are no key event listeners for this target
    1444           0 :         if (mFocusState.CanIgnoreKeyboardShortcutMisses()) {
    1445           0 :           focusSetter.MarkAsNonFocusChanging();
    1446             :         }
    1447             :         return result;
    1448             :       }
    1449             : 
    1450             :       // Check if this shortcut needs to be dispatched to content. Anything matching
    1451             :       // this is assumed to be able to change focus.
    1452           0 :       if (shortcut->mDispatchToContent) {
    1453             :         APZ_KEY_LOG("Skipping key input with dispatch-to-content shortcut\n");
    1454             :         return result;
    1455             :       }
    1456             : 
    1457             :       // We know we have an action to execute on whatever is the current focus target
    1458           0 :       const KeyboardScrollAction& action = shortcut->mAction;
    1459             : 
    1460             :       // The current focus target depends on which direction the scroll is to happen
    1461           0 :       Maybe<ScrollableLayerGuid> targetGuid;
    1462           0 :       switch (action.mType)
    1463             :       {
    1464             :         case KeyboardScrollAction::eScrollCharacter: {
    1465           0 :           targetGuid = mFocusState.GetHorizontalTarget();
    1466           0 :           break;
    1467             :         }
    1468             :         case KeyboardScrollAction::eScrollLine:
    1469             :         case KeyboardScrollAction::eScrollPage:
    1470             :         case KeyboardScrollAction::eScrollComplete: {
    1471           0 :           targetGuid = mFocusState.GetVerticalTarget();
    1472           0 :           break;
    1473             :         }
    1474             :       }
    1475             : 
    1476             :       // If we don't have a scroll target then either we have a stale focus target,
    1477             :       // the focused element has event listeners, or the focused element doesn't have a
    1478             :       // layerized scroll frame. In any case we need to dispatch to content.
    1479           0 :       if (!targetGuid) {
    1480             :         APZ_KEY_LOG("Skipping key input with no current focus target\n");
    1481             :         return result;
    1482             :       }
    1483             : 
    1484           0 :       RefPtr<AsyncPanZoomController> targetApzc = GetTargetAPZC(targetGuid->mLayersId,
    1485           0 :                                                                 targetGuid->mScrollId);
    1486             : 
    1487           0 :       if (!targetApzc) {
    1488             :         APZ_KEY_LOG("Skipping key input with focus target but no APZC\n");
    1489           0 :         return result;
    1490             :       }
    1491             : 
    1492             :       // Attach the keyboard scroll action to the input event for processing
    1493             :       // by the input queue.
    1494           0 :       keyInput.mAction = action;
    1495             : 
    1496             :       APZ_KEY_LOG("Dispatching key input with apzc=%p\n",
    1497             :                   targetApzc.get());
    1498             : 
    1499             :       // Dispatch the event to the input queue.
    1500           0 :       result = mInputQueue->ReceiveInputEvent(
    1501             :           targetApzc,
    1502             :           TargetConfirmationFlags{true},
    1503           0 :           keyInput, aOutInputBlockId);
    1504             : 
    1505             :       // Any keyboard event that is dispatched to the input queue at this point
    1506             :       // should have been consumed
    1507           0 :       MOZ_ASSERT(result == nsEventStatus_eConsumeDoDefault ||
    1508             :                  result == nsEventStatus_eConsumeNoDefault);
    1509             : 
    1510           0 :       keyInput.mHandledByAPZ = true;
    1511           0 :       focusSetter.MarkAsNonFocusChanging();
    1512             : 
    1513           0 :       break;
    1514             :     }
    1515             :   }
    1516             :   return result;
    1517             : }
    1518             : 
    1519             : static TouchBehaviorFlags
    1520           0 : ConvertToTouchBehavior(CompositorHitTestInfo info)
    1521             : {
    1522           0 :   TouchBehaviorFlags result = AllowedTouchBehavior::UNKNOWN;
    1523           0 :   if (info == CompositorHitTestInfo::eInvisibleToHitTest) {
    1524             :     result = AllowedTouchBehavior::NONE;
    1525           0 :   } else if (info & CompositorHitTestInfo::eDispatchToContent) {
    1526             :     result = AllowedTouchBehavior::UNKNOWN;
    1527             :   } else {
    1528           0 :     result = AllowedTouchBehavior::VERTICAL_PAN
    1529             :            | AllowedTouchBehavior::HORIZONTAL_PAN
    1530             :            | AllowedTouchBehavior::PINCH_ZOOM
    1531             :            | AllowedTouchBehavior::DOUBLE_TAP_ZOOM;
    1532           0 :     if (info & CompositorHitTestInfo::eTouchActionPanXDisabled) {
    1533           0 :       result &= ~AllowedTouchBehavior::HORIZONTAL_PAN;
    1534             :     }
    1535           0 :     if (info & CompositorHitTestInfo::eTouchActionPanYDisabled) {
    1536           0 :       result &= ~AllowedTouchBehavior::VERTICAL_PAN;
    1537             :     }
    1538           0 :     if (info & CompositorHitTestInfo::eTouchActionPinchZoomDisabled) {
    1539           0 :       result &= ~AllowedTouchBehavior::PINCH_ZOOM;
    1540             :     }
    1541           0 :     if (info & CompositorHitTestInfo::eTouchActionDoubleTapZoomDisabled) {
    1542           0 :       result &= ~AllowedTouchBehavior::DOUBLE_TAP_ZOOM;
    1543             :     }
    1544             :   }
    1545           0 :   return result;
    1546             : }
    1547             : 
    1548             : already_AddRefed<AsyncPanZoomController>
    1549           0 : APZCTreeManager::GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
    1550             :                                         nsTArray<TouchBehaviorFlags>* aOutTouchBehaviors,
    1551             :                                         CompositorHitTestInfo* aOutHitResult,
    1552             :                                         HitTestingTreeNodeAutoLock* aOutHitScrollbarNode)
    1553             : {
    1554           0 :   RefPtr<AsyncPanZoomController> apzc;
    1555           0 :   if (aEvent.mTouches.Length() == 0) {
    1556             :     return apzc.forget();
    1557             :   }
    1558             : 
    1559           0 :   FlushRepaintsToClearScreenToGeckoTransform();
    1560             : 
    1561             :   CompositorHitTestInfo hitResult;
    1562           0 :   apzc = GetTargetAPZC(aEvent.mTouches[0].mScreenPoint, &hitResult,
    1563           0 :       aOutHitScrollbarNode);
    1564           0 :   if (aOutTouchBehaviors) {
    1565           0 :     aOutTouchBehaviors->AppendElement(ConvertToTouchBehavior(hitResult));
    1566             :   }
    1567           0 :   for (size_t i = 1; i < aEvent.mTouches.Length(); i++) {
    1568           0 :     RefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(aEvent.mTouches[i].mScreenPoint, &hitResult);
    1569           0 :     if (aOutTouchBehaviors) {
    1570           0 :       aOutTouchBehaviors->AppendElement(ConvertToTouchBehavior(hitResult));
    1571             :     }
    1572           0 :     apzc = GetMultitouchTarget(apzc, apzc2);
    1573             :     APZCTM_LOG("Using APZC %p as the root APZC for multi-touch\n", apzc.get());
    1574             :     // A multi-touch gesture will not be a scrollbar drag, even if the
    1575             :     // first touch point happened to hit a scrollbar.
    1576           0 :     aOutHitScrollbarNode->Clear();
    1577             :   }
    1578             : 
    1579           0 :   if (aOutHitResult) {
    1580             :     // XXX we should probably be combining the hit results from the different
    1581             :     // touch points somehow, instead of just using the last one.
    1582           0 :     *aOutHitResult = hitResult;
    1583             :   }
    1584             :   return apzc.forget();
    1585             : }
    1586             : 
    1587             : nsEventStatus
    1588           0 : APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
    1589             :                                    ScrollableLayerGuid* aOutTargetGuid,
    1590             :                                    uint64_t* aOutInputBlockId)
    1591             : {
    1592           0 :   aInput.mHandledByAPZ = true;
    1593           0 :   nsTArray<TouchBehaviorFlags> touchBehaviors;
    1594           0 :   HitTestingTreeNodeAutoLock hitScrollbarNode;
    1595           0 :   if (aInput.mType == MultiTouchInput::MULTITOUCH_START) {
    1596             :     // If we are panned into overscroll and a second finger goes down,
    1597             :     // ignore that second touch point completely. The touch-start for it is
    1598             :     // dropped completely; subsequent touch events until the touch-end for it
    1599             :     // will have this touch point filtered out.
    1600             :     // (By contrast, if we're in overscroll but not panning, such as after
    1601             :     // putting two fingers down during an overscroll animation, we process the
    1602             :     // second touch and proceed to pinch.)
    1603           0 :     if (mApzcForInputBlock &&
    1604           0 :         mApzcForInputBlock->IsInPanningState() &&
    1605           0 :         BuildOverscrollHandoffChain(mApzcForInputBlock)->HasOverscrolledApzc()) {
    1606           0 :       if (mRetainedTouchIdentifier == -1) {
    1607           0 :         mRetainedTouchIdentifier = mApzcForInputBlock->GetLastTouchIdentifier();
    1608             :       }
    1609             :       return nsEventStatus_eConsumeNoDefault;
    1610             :     }
    1611             : 
    1612           0 :     mHitResultForInputBlock = CompositorHitTestInfo::eInvisibleToHitTest;
    1613           0 :     mApzcForInputBlock = GetTouchInputBlockAPZC(aInput, &touchBehaviors,
    1614           0 :         &mHitResultForInputBlock, &hitScrollbarNode);
    1615             : 
    1616             :     // Check if this event starts a scrollbar touch-drag. The conditions
    1617             :     // checked are similar to the ones we check for MOUSE_INPUT starting
    1618             :     // a scrollbar mouse-drag.
    1619           0 :     mInScrollbarTouchDrag = gfxPrefs::APZDragEnabled() &&
    1620           0 :                             gfxPrefs::APZTouchDragEnabled() && hitScrollbarNode &&
    1621           0 :                             hitScrollbarNode->IsScrollThumbNode() &&
    1622           0 :                             hitScrollbarNode->GetScrollbarData().mThumbIsAsyncDraggable;
    1623             : 
    1624           0 :     MOZ_ASSERT(touchBehaviors.Length() == aInput.mTouches.Length());
    1625           0 :     for (size_t i = 0; i < touchBehaviors.Length(); i++) {
    1626             :       APZCTM_LOG("Touch point has allowed behaviours 0x%02x\n", touchBehaviors[i]);
    1627           0 :       if (touchBehaviors[i] == AllowedTouchBehavior::UNKNOWN) {
    1628             :         // If there's any unknown items in the list, throw it out and we'll
    1629             :         // wait for the main thread to send us a notification.
    1630           0 :         touchBehaviors.Clear();
    1631           0 :         break;
    1632             :       }
    1633             :     }
    1634             :   } else if (mApzcForInputBlock) {
    1635             :     APZCTM_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get());
    1636             :   }
    1637             : 
    1638           0 :   nsEventStatus result = nsEventStatus_eIgnore;
    1639             : 
    1640           0 :   if (mInScrollbarTouchDrag) {
    1641             :     result = ProcessTouchInputForScrollbarDrag(aInput, hitScrollbarNode,
    1642           0 :         aOutTargetGuid, aOutInputBlockId);
    1643             :   } else {
    1644             :     // If we receive a touch-cancel, it means all touches are finished, so we
    1645             :     // can stop ignoring any that we were ignoring.
    1646           0 :     if (aInput.mType == MultiTouchInput::MULTITOUCH_CANCEL) {
    1647           0 :       mRetainedTouchIdentifier = -1;
    1648             :     }
    1649             : 
    1650             :     // If we are currently ignoring any touch points, filter them out from the
    1651             :     // set of touch points included in this event. Note that we modify aInput
    1652             :     // itself, so that the touch points are also filtered out when the caller
    1653             :     // passes the event on to content.
    1654           0 :     if (mRetainedTouchIdentifier != -1) {
    1655           0 :       for (size_t j = 0; j < aInput.mTouches.Length(); ++j) {
    1656           0 :         if (aInput.mTouches[j].mIdentifier != mRetainedTouchIdentifier) {
    1657           0 :           aInput.mTouches.RemoveElementAt(j);
    1658           0 :           if (!touchBehaviors.IsEmpty()) {
    1659           0 :             MOZ_ASSERT(touchBehaviors.Length() > j);
    1660           0 :             touchBehaviors.RemoveElementAt(j);
    1661             :           }
    1662           0 :           --j;
    1663             :         }
    1664             :       }
    1665           0 :       if (aInput.mTouches.IsEmpty()) {
    1666             :         return nsEventStatus_eConsumeNoDefault;
    1667             :       }
    1668             :     }
    1669             : 
    1670           0 :     if (mApzcForInputBlock) {
    1671           0 :       MOZ_ASSERT(mHitResultForInputBlock != CompositorHitTestInfo::eInvisibleToHitTest);
    1672             : 
    1673           0 :       mApzcForInputBlock->GetGuid(aOutTargetGuid);
    1674           0 :       uint64_t inputBlockId = 0;
    1675           0 :       result = mInputQueue->ReceiveInputEvent(mApzcForInputBlock,
    1676             :           TargetConfirmationFlags{mHitResultForInputBlock},
    1677           0 :           aInput, &inputBlockId);
    1678           0 :       if (aOutInputBlockId) {
    1679           0 :         *aOutInputBlockId = inputBlockId;
    1680             :       }
    1681           0 :       if (!touchBehaviors.IsEmpty()) {
    1682           0 :         mInputQueue->SetAllowedTouchBehavior(inputBlockId, touchBehaviors);
    1683             :       }
    1684             : 
    1685             :       // For computing the event to pass back to Gecko, use up-to-date transforms
    1686             :       // (i.e. not anything cached in an input block).
    1687             :       // This ensures that transformToApzc and transformToGecko are in sync.
    1688           0 :       ScreenToParentLayerMatrix4x4 transformToApzc = GetScreenToApzcTransform(mApzcForInputBlock);
    1689           0 :       ParentLayerToScreenMatrix4x4 transformToGecko = GetApzcToGeckoTransform(mApzcForInputBlock);
    1690           0 :       ScreenToScreenMatrix4x4 outTransform = transformToApzc * transformToGecko;
    1691             : 
    1692           0 :       for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
    1693           0 :         SingleTouchData& touchData = aInput.mTouches[i];
    1694             :         Maybe<ScreenIntPoint> untransformedScreenPoint = UntransformBy(
    1695           0 :             outTransform, touchData.mScreenPoint);
    1696           0 :         if (!untransformedScreenPoint) {
    1697           0 :           return nsEventStatus_eIgnore;
    1698             :         }
    1699           0 :         touchData.mScreenPoint = *untransformedScreenPoint;
    1700             :       }
    1701             :     }
    1702             :   }
    1703             : 
    1704           0 :   mTouchCounter.Update(aInput);
    1705             : 
    1706             :   // If it's the end of the touch sequence then clear out variables so we
    1707             :   // don't keep dangling references and leak things.
    1708           0 :   if (mTouchCounter.GetActiveTouchCount() == 0) {
    1709           0 :     mApzcForInputBlock = nullptr;
    1710           0 :     mHitResultForInputBlock = CompositorHitTestInfo::eInvisibleToHitTest;
    1711           0 :     mRetainedTouchIdentifier = -1;
    1712           0 :     mInScrollbarTouchDrag = false;
    1713             :   }
    1714             : 
    1715             :   return result;
    1716             : }
    1717             : 
    1718             : MouseInput::MouseType
    1719           0 : MultiTouchTypeToMouseType(MultiTouchInput::MultiTouchType aType)
    1720             : {
    1721           0 :   switch (aType)
    1722             :   {
    1723             :   case MultiTouchInput::MULTITOUCH_START:
    1724             :     return MouseInput::MOUSE_DOWN;
    1725             :   case MultiTouchInput::MULTITOUCH_MOVE:
    1726           0 :     return MouseInput::MOUSE_MOVE;
    1727             :   case MultiTouchInput::MULTITOUCH_END:
    1728             :   case MultiTouchInput::MULTITOUCH_CANCEL:
    1729           0 :     return MouseInput::MOUSE_UP;
    1730             :   }
    1731           0 :   MOZ_ASSERT_UNREACHABLE("Invalid multi-touch type");
    1732             :   return MouseInput::MOUSE_NONE;
    1733             : }
    1734             : 
    1735             : nsEventStatus
    1736           0 : APZCTreeManager::ProcessTouchInputForScrollbarDrag(MultiTouchInput& aTouchInput,
    1737             :                                                    const HitTestingTreeNodeAutoLock& aScrollThumbNode,
    1738             :                                                    ScrollableLayerGuid* aOutTargetGuid,
    1739             :                                                    uint64_t* aOutInputBlockId)
    1740             : {
    1741           0 :   MOZ_ASSERT(mRetainedTouchIdentifier == -1);
    1742           0 :   MOZ_ASSERT(mApzcForInputBlock);
    1743           0 :   MOZ_ASSERT(aTouchInput.mTouches.Length() == 1);
    1744             : 
    1745             :   // Synthesize a mouse event based on the touch event, so that we can
    1746             :   // reuse code in InputQueue and APZC for handling scrollbar mouse-drags.
    1747             :   MouseInput mouseInput{MultiTouchTypeToMouseType(aTouchInput.mType),
    1748             :                         MouseInput::LEFT_BUTTON,
    1749             :                         dom::MouseEventBinding::MOZ_SOURCE_TOUCH,
    1750             :                         WidgetMouseEvent::eLeftButtonFlag,
    1751           0 :                         aTouchInput.mTouches[0].mScreenPoint,
    1752             :                         aTouchInput.mTime,
    1753             :                         aTouchInput.mTimeStamp,
    1754           0 :                         aTouchInput.modifiers};
    1755           0 :   mouseInput.mHandledByAPZ = true;
    1756             : 
    1757             :   // The value of |targetConfirmed| passed to InputQueue::ReceiveInputEvent()
    1758             :   // only matters for the first event, which creates the drag block. For
    1759             :   // that event, the correct value is false, since the drag block will, at the
    1760             :   // earliest, be confirmed in the subsequent SetupScrollbarDrag() call.
    1761           0 :   TargetConfirmationFlags targetConfirmed{false};
    1762             : 
    1763           0 :   nsEventStatus result = mInputQueue->ReceiveInputEvent(mApzcForInputBlock,
    1764           0 :       targetConfirmed, mouseInput, aOutInputBlockId);
    1765             : 
    1766             :   // |aScrollThumbNode| is non-null iff. this is the event that starts the drag.
    1767             :   // If so, set up the drag.
    1768           0 :   if (aScrollThumbNode) {
    1769           0 :     SetupScrollbarDrag(mouseInput, aScrollThumbNode, mApzcForInputBlock.get());
    1770             :   }
    1771             : 
    1772           0 :   mApzcForInputBlock->GetGuid(aOutTargetGuid);
    1773             : 
    1774             :   // Since the input was targeted at a scrollbar:
    1775             :   //    - The original touch event (which will be sent on to content) will
    1776             :   //      not be untransformed.
    1777             :   //    - We don't want to apply the callback transform in the main thread,
    1778             :   //      so we remove the scrollid from the guid.
    1779             :   // Both of these match the behaviour of mouse events that target a scrollbar;
    1780             :   // see the code for handling mouse events in ReceiveInputEvent() for
    1781             :   // additional explanation.
    1782           0 :   aOutTargetGuid->mScrollId = FrameMetrics::NULL_SCROLL_ID;
    1783             : 
    1784           0 :   return result;
    1785             : }
    1786             : 
    1787             : void
    1788           0 : APZCTreeManager::SetupScrollbarDrag(MouseInput& aMouseInput,
    1789             :                                     const HitTestingTreeNodeAutoLock& aScrollThumbNode,
    1790             :                                     AsyncPanZoomController* aApzc)
    1791             : {
    1792           0 :   DragBlockState* dragBlock = mInputQueue->GetCurrentDragBlock();
    1793           0 :   if (!dragBlock) {
    1794             :     return;
    1795             :   }
    1796             : 
    1797           0 :   const ScrollbarData& thumbData = aScrollThumbNode->GetScrollbarData();
    1798           0 :   MOZ_ASSERT(thumbData.mDirection.isSome());
    1799             : 
    1800             :   // Record the thumb's position at the start of the drag.
    1801             :   // We snap back to this position if, during the drag, the mouse
    1802             :   // gets sufficiently far away from the scrollbar.
    1803           0 :   dragBlock->SetInitialThumbPos(thumbData.mThumbStart);
    1804             : 
    1805             :   // Under some conditions, we can confirm the drag block right away.
    1806             :   // Otherwise, we have to wait for a main-thread confirmation.
    1807           0 :   if (gfxPrefs::APZDragInitiationEnabled() &&
    1808             :       // check that the scrollbar's target scroll frame is layerized
    1809           0 :       aScrollThumbNode->GetScrollTargetId() == aApzc->GetGuid().mScrollId &&
    1810           0 :       !aApzc->IsScrollInfoLayer()) {
    1811           0 :     uint64_t dragBlockId = dragBlock->GetBlockId();
    1812             :     // AsyncPanZoomController::HandleInputEvent() will call
    1813             :     // TransformToLocal() on the event, but we need its mLocalOrigin now
    1814             :     // to compute a drag start offset for the AsyncDragMetrics.
    1815           0 :     aMouseInput.TransformToLocal(aApzc->GetTransformToThis());
    1816             :     CSSCoord dragStart = aApzc->ConvertScrollbarPoint(
    1817           0 :         aMouseInput.mLocalOrigin, thumbData);
    1818             :     // ConvertScrollbarPoint() got the drag start offset relative to
    1819             :     // the scroll track. Now get it relative to the thumb.
    1820             :     // ScrollThumbData::mThumbStart stores the offset of the thumb
    1821             :     // relative to the scroll track at the time of the last paint.
    1822             :     // Since that paint, the thumb may have acquired an async transform
    1823             :     // due to async scrolling, so look that up and apply it.
    1824           0 :     LayerToParentLayerMatrix4x4 thumbTransform;
    1825             :     {
    1826           0 :       RecursiveMutexAutoLock lock(mTreeLock);
    1827           0 :       thumbTransform = ComputeTransformForNode(aScrollThumbNode.Get(lock));
    1828             :     }
    1829             :     // Only consider the translation, since we do not support both
    1830             :     // zooming and scrollbar dragging on any platform.
    1831             :     CSSCoord thumbStart = thumbData.mThumbStart
    1832           0 :                         + ((*thumbData.mDirection == ScrollDirection::eHorizontal)
    1833           0 :                            ? thumbTransform._41 : thumbTransform._42);
    1834           0 :     dragStart -= thumbStart;
    1835             : 
    1836             :     // Content can't prevent scrollbar dragging with preventDefault(),
    1837             :     // so we don't need to wait for a content response. It's important
    1838             :     // to do this before calling ConfirmDragBlock() since that can
    1839             :     // potentially process and consume the block.
    1840           0 :     dragBlock->SetContentResponse(false);
    1841             : 
    1842           0 :     mInputQueue->ConfirmDragBlock(
    1843             :         dragBlockId, aApzc,
    1844           0 :         AsyncDragMetrics(aApzc->GetGuid().mScrollId,
    1845           0 :                          aApzc->GetGuid().mPresShellId,
    1846             :                          dragBlockId,
    1847             :                          dragStart,
    1848           0 :                          *thumbData.mDirection));
    1849             :   }
    1850             : }
    1851             : 
    1852             : void
    1853           0 : APZCTreeManager::SynthesizePinchGestureFromMouseWheel(
    1854             :     const ScrollWheelInput& aWheelInput,
    1855             :     const RefPtr<AsyncPanZoomController>& aTarget)
    1856             : {
    1857           0 :   MOZ_ASSERT(aTarget);
    1858             : 
    1859           0 :   ScreenPoint focusPoint = aWheelInput.mOrigin;
    1860             : 
    1861             :   // Compute span values based on the wheel delta.
    1862             :   // See the PinchGestureInput constructor called below for why
    1863             :   // it's OK to use ParentLayer coordinates for the span values.
    1864           0 :   ParentLayerCoord oldSpan = 100;
    1865           0 :   ParentLayerCoord newSpan = oldSpan + aWheelInput.mDeltaY;
    1866             : 
    1867             :   // There's no ambiguity as to the target for pinch gesture events.
    1868           0 :   TargetConfirmationFlags confFlags{true};
    1869             : 
    1870             :   PinchGestureInput pinchStart{
    1871             :       PinchGestureInput::PINCHGESTURE_START,
    1872           0 :       aWheelInput.mTime,
    1873             :       aWheelInput.mTimeStamp,
    1874             :       focusPoint,
    1875             :       oldSpan,
    1876             :       oldSpan,
    1877           0 :       aWheelInput.modifiers};
    1878             :   PinchGestureInput pinchScale1{
    1879             :       PinchGestureInput::PINCHGESTURE_SCALE,
    1880           0 :       aWheelInput.mTime,
    1881             :       aWheelInput.mTimeStamp,
    1882             :       focusPoint,
    1883             :       oldSpan,
    1884             :       oldSpan,
    1885           0 :       aWheelInput.modifiers};
    1886             :   PinchGestureInput pinchScale2{
    1887             :       PinchGestureInput::PINCHGESTURE_SCALE,
    1888           0 :       aWheelInput.mTime,
    1889             :       aWheelInput.mTimeStamp,
    1890             :       focusPoint,
    1891             :       oldSpan,
    1892             :       newSpan,
    1893           0 :       aWheelInput.modifiers};
    1894             :   PinchGestureInput pinchEnd{
    1895             :       PinchGestureInput::PINCHGESTURE_END,
    1896           0 :       aWheelInput.mTime,
    1897             :       aWheelInput.mTimeStamp,
    1898           0 :       PinchGestureInput::BothFingersLifted<ScreenPixel>(),
    1899             :       newSpan,
    1900             :       newSpan,
    1901           0 :       aWheelInput.modifiers};
    1902             : 
    1903           0 :   mInputQueue->ReceiveInputEvent(aTarget, confFlags, pinchStart, nullptr);
    1904           0 :   mInputQueue->ReceiveInputEvent(aTarget, confFlags, pinchScale1, nullptr);
    1905           0 :   mInputQueue->ReceiveInputEvent(aTarget, confFlags, pinchScale2, nullptr);
    1906           0 :   mInputQueue->ReceiveInputEvent(aTarget, confFlags, pinchEnd, nullptr);
    1907           0 : }
    1908             : 
    1909             : void
    1910           0 : APZCTreeManager::UpdateWheelTransaction(LayoutDeviceIntPoint aRefPoint,
    1911             :                                         EventMessage aEventMessage)
    1912             : {
    1913           0 :   APZThreadUtils::AssertOnControllerThread();
    1914             : 
    1915           0 :   WheelBlockState* txn = mInputQueue->GetActiveWheelTransaction();
    1916           0 :   if (!txn) {
    1917             :     return;
    1918             :   }
    1919             : 
    1920             :   // If the transaction has simply timed out, we don't need to do anything
    1921             :   // else.
    1922           0 :   if (txn->MaybeTimeout(TimeStamp::Now())) {
    1923             :     return;
    1924             :   }
    1925             : 
    1926           0 :   switch (aEventMessage) {
    1927             :    case eMouseMove:
    1928             :    case eDragOver: {
    1929             : 
    1930             :     ScreenIntPoint point =
    1931             :      ViewAs<ScreenPixel>(aRefPoint,
    1932           0 :        PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
    1933             : 
    1934           0 :     txn->OnMouseMove(point);
    1935             : 
    1936             :     return;
    1937             :    }
    1938             :    case eKeyPress:
    1939             :    case eKeyUp:
    1940             :    case eKeyDown:
    1941             :    case eMouseUp:
    1942             :    case eMouseDown:
    1943             :    case eMouseDoubleClick:
    1944             :    case eMouseAuxClick:
    1945             :    case eMouseClick:
    1946             :    case eContextMenu:
    1947             :    case eDrop:
    1948           0 :      txn->EndTransaction();
    1949           0 :      return;
    1950             :    default:
    1951             :      break;
    1952             :   }
    1953             : }
    1954             : 
    1955             : void
    1956           0 : APZCTreeManager::ProcessUnhandledEvent(LayoutDeviceIntPoint* aRefPoint,
    1957             :                                         ScrollableLayerGuid*  aOutTargetGuid,
    1958             :                                         uint64_t*             aOutFocusSequenceNumber)
    1959             : {
    1960           0 :   APZThreadUtils::AssertOnControllerThread();
    1961             : 
    1962             :   // Transform the aRefPoint.
    1963             :   // If the event hits an overscrolled APZC, instruct the caller to ignore it.
    1964           0 :   CompositorHitTestInfo hitResult = CompositorHitTestInfo::eInvisibleToHitTest;
    1965           0 :   PixelCastJustification LDIsScreen = PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent;
    1966             :   ScreenIntPoint refPointAsScreen =
    1967           0 :     ViewAs<ScreenPixel>(*aRefPoint, LDIsScreen);
    1968           0 :   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(refPointAsScreen, &hitResult);
    1969           0 :   if (apzc) {
    1970           0 :     MOZ_ASSERT(hitResult != CompositorHitTestInfo::eInvisibleToHitTest);
    1971           0 :     apzc->GetGuid(aOutTargetGuid);
    1972           0 :     ScreenToParentLayerMatrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
    1973           0 :     ParentLayerToScreenMatrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
    1974           0 :     ScreenToScreenMatrix4x4 outTransform = transformToApzc * transformToGecko;
    1975             :     Maybe<ScreenIntPoint> untransformedRefPoint =
    1976           0 :       UntransformBy(outTransform, refPointAsScreen);
    1977           0 :     if (untransformedRefPoint) {
    1978             :       *aRefPoint =
    1979           0 :         ViewAs<LayoutDevicePixel>(*untransformedRefPoint, LDIsScreen);
    1980             :     }
    1981             :   }
    1982             : 
    1983             :   // Update the focus sequence number and attach it to the event
    1984           0 :   mFocusState.ReceiveFocusChangingEvent();
    1985           0 :   *aOutFocusSequenceNumber = mFocusState.LastAPZProcessedEvent();
    1986           0 : }
    1987             : 
    1988             : void
    1989           0 : APZCTreeManager::ProcessTouchVelocity(uint32_t aTimestampMs, float aSpeedY)
    1990             : {
    1991           0 :   if (mApzcForInputBlock) {
    1992           0 :     mApzcForInputBlock->HandleTouchVelocity(aTimestampMs, aSpeedY);
    1993             :   }
    1994           0 : }
    1995             : 
    1996             : void
    1997           0 : APZCTreeManager::SetKeyboardMap(const KeyboardMap& aKeyboardMap)
    1998             : {
    1999           0 :   APZThreadUtils::AssertOnControllerThread();
    2000             : 
    2001           0 :   mKeyboardMap = aKeyboardMap;
    2002           0 : }
    2003             : 
    2004             : void
    2005           0 : APZCTreeManager::ZoomToRect(const ScrollableLayerGuid& aGuid,
    2006             :                             const CSSRect& aRect,
    2007             :                             const uint32_t aFlags)
    2008             : {
    2009             :   // We could probably move this to run on the updater thread if needed, but
    2010             :   // either way we should restrict it to a single thread. For now let's use the
    2011             :   // controller thread.
    2012           0 :   APZThreadUtils::AssertOnControllerThread();
    2013             : 
    2014           0 :   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
    2015           0 :   if (apzc) {
    2016           0 :     apzc->ZoomToRect(aRect, aFlags);
    2017             :   }
    2018           0 : }
    2019             : 
    2020             : void
    2021           0 : APZCTreeManager::ContentReceivedInputBlock(uint64_t aInputBlockId, bool aPreventDefault)
    2022             : {
    2023           0 :   APZThreadUtils::AssertOnControllerThread();
    2024             : 
    2025           0 :   mInputQueue->ContentReceivedInputBlock(aInputBlockId, aPreventDefault);
    2026           0 : }
    2027             : 
    2028             : void
    2029           0 : APZCTreeManager::SetTargetAPZC(uint64_t aInputBlockId,
    2030             :                                const nsTArray<ScrollableLayerGuid>& aTargets)
    2031             : {
    2032           0 :   APZThreadUtils::AssertOnControllerThread();
    2033             : 
    2034           0 :   RefPtr<AsyncPanZoomController> target = nullptr;
    2035           0 :   if (aTargets.Length() > 0) {
    2036           0 :     target = GetTargetAPZC(aTargets[0]);
    2037             :   }
    2038           0 :   for (size_t i = 1; i < aTargets.Length(); i++) {
    2039           0 :     RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aTargets[i]);
    2040           0 :     target = GetMultitouchTarget(target, apzc);
    2041             :   }
    2042           0 :   mInputQueue->SetConfirmedTargetApzc(aInputBlockId, target);
    2043           0 : }
    2044             : 
    2045             : void
    2046           0 : APZCTreeManager::SetTargetAPZC(uint64_t aInputBlockId, const ScrollableLayerGuid& aTarget)
    2047             : {
    2048           0 :   APZThreadUtils::AssertOnControllerThread();
    2049             : 
    2050           0 :   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aTarget);
    2051           0 :   mInputQueue->SetConfirmedTargetApzc(aInputBlockId, apzc);
    2052           0 : }
    2053             : 
    2054             : void
    2055           0 : APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
    2056             :                                        const Maybe<ZoomConstraints>& aConstraints)
    2057             : {
    2058           0 :   if (!GetUpdater()->IsUpdaterThread()) {
    2059             :     // This can happen if we're in the UI process and got a call directly from
    2060             :     // nsBaseWidget or from a content process over PAPZCTreeManager. In that case
    2061             :     // we get this call on the compositor thread, which may be different from
    2062             :     // the updater thread. It can also happen in the GPU process if that is
    2063             :     // enabled, since the call will go over PAPZCTreeManager and arrive on the
    2064             :     // compositor thread in the GPU process.
    2065           0 :     GetUpdater()->RunOnUpdaterThread(
    2066             :         aGuid.mLayersId,
    2067           0 :         NewRunnableMethod<ScrollableLayerGuid, Maybe<ZoomConstraints>>(
    2068             :             "APZCTreeManager::UpdateZoomConstraints",
    2069             :             this,
    2070             :             &APZCTreeManager::UpdateZoomConstraints,
    2071             :             aGuid,
    2072           0 :             aConstraints));
    2073           0 :     return;
    2074             :   }
    2075             : 
    2076           0 :   AssertOnUpdaterThread();
    2077             : 
    2078           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2079           0 :   RefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, nullptr);
    2080           0 :   MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
    2081             : 
    2082             :   // Propagate the zoom constraints down to the subtree, stopping at APZCs
    2083             :   // which have their own zoom constraints or are in a different layers id.
    2084           0 :   if (aConstraints) {
    2085             :     APZCTM_LOG("Recording constraints %s for guid %s\n",
    2086             :       Stringify(aConstraints.value()).c_str(), Stringify(aGuid).c_str());
    2087           0 :     mZoomConstraints[aGuid] = aConstraints.ref();
    2088             :   } else {
    2089             :     APZCTM_LOG("Removing constraints for guid %s\n", Stringify(aGuid).c_str());
    2090           0 :     mZoomConstraints.erase(aGuid);
    2091             :   }
    2092           0 :   if (node && aConstraints) {
    2093           0 :     ForEachNode<ReverseIterator>(node.get(),
    2094           0 :         [&aConstraints, &node, this](HitTestingTreeNode* aNode)
    2095           0 :         {
    2096           0 :           if (aNode != node) {
    2097           0 :             if (AsyncPanZoomController* childApzc = aNode->GetApzc()) {
    2098             :               // We can have subtrees with their own zoom constraints or separate layers
    2099             :               // id - leave these alone.
    2100           0 :               if (childApzc->HasNoParentWithSameLayersId() ||
    2101           0 :                   this->mZoomConstraints.find(childApzc->GetGuid()) != this->mZoomConstraints.end()) {
    2102             :                 return TraversalFlag::Skip;
    2103             :               }
    2104             :             }
    2105             :           }
    2106           0 :           if (aNode->IsPrimaryHolder()) {
    2107           0 :             MOZ_ASSERT(aNode->GetApzc());
    2108           0 :             aNode->GetApzc()->UpdateZoomConstraints(aConstraints.ref());
    2109             :           }
    2110             :           return TraversalFlag::Continue;
    2111           0 :         });
    2112             :   }
    2113             : }
    2114             : 
    2115             : void
    2116           0 : APZCTreeManager::FlushRepaintsToClearScreenToGeckoTransform()
    2117             : {
    2118             :   // As the name implies, we flush repaint requests for the entire APZ tree in
    2119             :   // order to clear the screen-to-gecko transform (aka the "untransform" applied
    2120             :   // to incoming input events before they can be passed on to Gecko).
    2121             :   //
    2122             :   // The primary reason we do this is to avoid the problem where input events,
    2123             :   // after being untransformed, end up hit-testing differently in Gecko. This
    2124             :   // might happen in cases where the input event lands on content that is async-
    2125             :   // scrolled into view, but Gecko still thinks it is out of view given the
    2126             :   // visible area of a scrollframe.
    2127             :   //
    2128             :   // Another reason we want to clear the untransform is that if our APZ hit-test
    2129             :   // hits a dispatch-to-content region then that's an ambiguous result and we
    2130             :   // need to ask Gecko what actually got hit. In order to do this we need to
    2131             :   // untransform the input event into Gecko space - but to do that we need to
    2132             :   // know which APZC got hit! This leads to a circular dependency; the only way
    2133             :   // to get out of it is to make sure that the untransform for all the possible
    2134             :   // matched APZCs is the same. It is simplest to ensure that by flushing the
    2135             :   // pending repaint requests, which makes all of the untransforms empty (and
    2136             :   // therefore equal).
    2137           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2138             : 
    2139           0 :   ForEachNode<ReverseIterator>(mRootNode.get(),
    2140           0 :       [](HitTestingTreeNode* aNode)
    2141             :       {
    2142           0 :         if (aNode->IsPrimaryHolder()) {
    2143           0 :           MOZ_ASSERT(aNode->GetApzc());
    2144           0 :           aNode->GetApzc()->FlushRepaintForNewInputBlock();
    2145             :         }
    2146           0 :       });
    2147           0 : }
    2148             : 
    2149             : void
    2150           0 : APZCTreeManager::CancelAnimation(const ScrollableLayerGuid &aGuid)
    2151             : {
    2152           0 :   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
    2153           0 :   if (apzc) {
    2154           0 :     apzc->CancelAnimation();
    2155             :   }
    2156           0 : }
    2157             : 
    2158             : void
    2159           0 : APZCTreeManager::AdjustScrollForSurfaceShift(const ScreenPoint& aShift)
    2160             : {
    2161           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2162           0 :   RefPtr<AsyncPanZoomController> apzc = FindRootContentOrRootApzc();
    2163           0 :   if (apzc) {
    2164           0 :     apzc->AdjustScrollForSurfaceShift(aShift);
    2165             :   }
    2166           0 : }
    2167             : 
    2168             : void
    2169           0 : APZCTreeManager::ClearTree()
    2170             : {
    2171           0 :   AssertOnUpdaterThread();
    2172             : 
    2173             : #if defined(MOZ_WIDGET_ANDROID)
    2174             :   mToolbarAnimator->ClearTreeManager();
    2175             : #endif
    2176             : 
    2177             :   // Ensure that no references to APZCs are alive in any lingering input
    2178             :   // blocks. This breaks cycles from InputBlockState::mTargetApzc back to
    2179             :   // the InputQueue.
    2180           0 :   APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
    2181           0 :     "layers::InputQueue::Clear", mInputQueue, &InputQueue::Clear));
    2182             : 
    2183           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2184             : 
    2185             :   // Collect the nodes into a list, and then destroy each one.
    2186             :   // We can't destroy them as we collect them, because ForEachNode()
    2187             :   // does a pre-order traversal of the tree, and Destroy() nulls out
    2188             :   // the fields needed to reach the children of the node.
    2189           0 :   nsTArray<RefPtr<HitTestingTreeNode>> nodesToDestroy;
    2190           0 :   ForEachNode<ReverseIterator>(mRootNode.get(),
    2191           0 :       [&nodesToDestroy](HitTestingTreeNode* aNode)
    2192           0 :       {
    2193           0 :         nodesToDestroy.AppendElement(aNode);
    2194           0 :       });
    2195             : 
    2196           0 :   for (size_t i = 0; i < nodesToDestroy.Length(); i++) {
    2197           0 :     nodesToDestroy[i]->Destroy();
    2198             :   }
    2199           0 :   mRootNode = nullptr;
    2200             : 
    2201           0 :   RefPtr<APZCTreeManager> self(this);
    2202           0 :   NS_DispatchToMainThread(
    2203           0 :     NS_NewRunnableFunction("layers::APZCTreeManager::ClearTree", [self] {
    2204           0 :       self->mFlushObserver->Unregister();
    2205           0 :       self->mFlushObserver = nullptr;
    2206           0 :     }));
    2207           0 : }
    2208             : 
    2209             : RefPtr<HitTestingTreeNode>
    2210           0 : APZCTreeManager::GetRootNode() const
    2211             : {
    2212           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2213           0 :   return mRootNode;
    2214             : }
    2215             : 
    2216             : /**
    2217             :  * Transform a displacement from the ParentLayer coordinates of a source APZC
    2218             :  * to the ParentLayer coordinates of a target APZC.
    2219             :  * @param aTreeManager the tree manager for the APZC tree containing |aSource|
    2220             :  *                     and |aTarget|
    2221             :  * @param aSource the source APZC
    2222             :  * @param aTarget the target APZC
    2223             :  * @param aStartPoint the start point of the displacement
    2224             :  * @param aEndPoint the end point of the displacement
    2225             :  * @return true on success, false if aStartPoint or aEndPoint cannot be transformed into target's coordinate space
    2226             :  */
    2227             : static bool
    2228           0 : TransformDisplacement(APZCTreeManager* aTreeManager,
    2229             :                       AsyncPanZoomController* aSource,
    2230             :                       AsyncPanZoomController* aTarget,
    2231             :                       ParentLayerPoint& aStartPoint,
    2232             :                       ParentLayerPoint& aEndPoint) {
    2233           0 :   if (aSource == aTarget) {
    2234             :     return true;
    2235             :   }
    2236             : 
    2237             :   // Convert start and end points to Screen coordinates.
    2238           0 :   ParentLayerToScreenMatrix4x4 untransformToApzc = aTreeManager->GetScreenToApzcTransform(aSource).Inverse();
    2239           0 :   ScreenPoint screenStart = TransformBy(untransformToApzc, aStartPoint);
    2240           0 :   ScreenPoint screenEnd = TransformBy(untransformToApzc, aEndPoint);
    2241             : 
    2242             :   // Convert start and end points to aTarget's ParentLayer coordinates.
    2243           0 :   ScreenToParentLayerMatrix4x4 transformToApzc = aTreeManager->GetScreenToApzcTransform(aTarget);
    2244           0 :   Maybe<ParentLayerPoint> startPoint = UntransformBy(transformToApzc, screenStart);
    2245           0 :   Maybe<ParentLayerPoint> endPoint = UntransformBy(transformToApzc, screenEnd);
    2246           0 :   if (!startPoint || !endPoint) {
    2247             :     return false;
    2248             :   }
    2249           0 :   aEndPoint = *endPoint;
    2250           0 :   aStartPoint = *startPoint;
    2251             : 
    2252           0 :   return true;
    2253             : }
    2254             : 
    2255             : void
    2256           0 : APZCTreeManager::DispatchScroll(AsyncPanZoomController* aPrev,
    2257             :                                 ParentLayerPoint& aStartPoint,
    2258             :                                 ParentLayerPoint& aEndPoint,
    2259             :                                 OverscrollHandoffState& aOverscrollHandoffState)
    2260             : {
    2261           0 :   const OverscrollHandoffChain& overscrollHandoffChain = aOverscrollHandoffState.mChain;
    2262           0 :   uint32_t overscrollHandoffChainIndex = aOverscrollHandoffState.mChainIndex;
    2263           0 :   RefPtr<AsyncPanZoomController> next;
    2264             :   // If we have reached the end of the overscroll handoff chain, there is
    2265             :   // nothing more to scroll, so we ignore the rest of the pan gesture.
    2266           0 :   if (overscrollHandoffChainIndex >= overscrollHandoffChain.Length()) {
    2267             :     // Nothing more to scroll - ignore the rest of the pan gesture.
    2268           0 :     return;
    2269             :   }
    2270             : 
    2271           0 :   next = overscrollHandoffChain.GetApzcAtIndex(overscrollHandoffChainIndex);
    2272             : 
    2273           0 :   if (next == nullptr || next->IsDestroyed()) {
    2274             :     return;
    2275             :   }
    2276             : 
    2277             :   // Convert the start and end points from |aPrev|'s coordinate space to
    2278             :   // |next|'s coordinate space.
    2279           0 :   if (!TransformDisplacement(this, aPrev, next, aStartPoint, aEndPoint)) {
    2280             :     return;
    2281             :   }
    2282             : 
    2283             :   // Scroll |next|. If this causes overscroll, it will call DispatchScroll()
    2284             :   // again with an incremented index.
    2285           0 :   if (!next->AttemptScroll(aStartPoint, aEndPoint, aOverscrollHandoffState)) {
    2286             :     // Transform |aStartPoint| and |aEndPoint| (which now represent the
    2287             :     // portion of the displacement that wasn't consumed by APZCs later
    2288             :     // in the handoff chain) back into |aPrev|'s coordinate space. This
    2289             :     // allows the caller (which is |aPrev|) to interpret the unconsumed
    2290             :     // displacement in its own coordinate space, and make use of it
    2291             :     // (e.g. by going into overscroll).
    2292           0 :     if (!TransformDisplacement(this, next, aPrev, aStartPoint, aEndPoint)) {
    2293           0 :       NS_WARNING("Failed to untransform scroll points during dispatch");
    2294             :     }
    2295             :   }
    2296             : }
    2297             : 
    2298             : ParentLayerPoint
    2299           0 : APZCTreeManager::DispatchFling(AsyncPanZoomController* aPrev,
    2300             :                                const FlingHandoffState& aHandoffState)
    2301             : {
    2302             :   // If immediate handoff is disallowed, do not allow handoff beyond the
    2303             :   // single APZC that's scrolled by the input block that triggered this fling.
    2304           0 :   if (aHandoffState.mIsHandoff &&
    2305           0 :       !gfxPrefs::APZAllowImmediateHandoff() &&
    2306           0 :       aHandoffState.mScrolledApzc == aPrev) {
    2307           0 :     return aHandoffState.mVelocity;
    2308             :   }
    2309             : 
    2310           0 :   const OverscrollHandoffChain* chain = aHandoffState.mChain;
    2311           0 :   RefPtr<AsyncPanZoomController> current;
    2312           0 :   uint32_t overscrollHandoffChainLength = chain->Length();
    2313             :   uint32_t startIndex;
    2314             : 
    2315             :   // The fling's velocity needs to be transformed from the screen coordinates
    2316             :   // of |aPrev| to the screen coordinates of |next|. To transform a velocity
    2317             :   // correctly, we need to convert it to a displacement. For now, we do this
    2318             :   // by anchoring it to a start point of (0, 0).
    2319             :   // TODO: For this to be correct in the presence of 3D transforms, we should
    2320             :   // use the end point of the touch that started the fling as the start point
    2321             :   // rather than (0, 0).
    2322           0 :   ParentLayerPoint startPoint;  // (0, 0)
    2323           0 :   ParentLayerPoint endPoint;
    2324             : 
    2325           0 :   if (aHandoffState.mIsHandoff) {
    2326           0 :     startIndex = chain->IndexOf(aPrev) + 1;
    2327             : 
    2328             :     // IndexOf will return aOverscrollHandoffChain->Length() if
    2329             :     // |aPrev| is not found.
    2330           0 :     if (startIndex >= overscrollHandoffChainLength) {
    2331           0 :       return aHandoffState.mVelocity;
    2332             :     }
    2333             :   } else {
    2334             :     startIndex = 0;
    2335             :   }
    2336             : 
    2337             :   // This will store any velocity left over after the entire handoff.
    2338           0 :   ParentLayerPoint finalResidualVelocity = aHandoffState.mVelocity;
    2339             : 
    2340           0 :   ParentLayerPoint currentVelocity = aHandoffState.mVelocity;
    2341           0 :   for (; startIndex < overscrollHandoffChainLength; startIndex++) {
    2342           0 :     current = chain->GetApzcAtIndex(startIndex);
    2343             : 
    2344             :     // Make sure the apzc about to be handled can be handled
    2345           0 :     if (current == nullptr || current->IsDestroyed()) {
    2346             :       break;
    2347             :     }
    2348             : 
    2349           0 :     endPoint = startPoint + currentVelocity;
    2350             : 
    2351             :     RefPtr<AsyncPanZoomController> prevApzc = (startIndex > 0)
    2352             :                                             ? chain->GetApzcAtIndex(startIndex - 1)
    2353           0 :                                             : nullptr;
    2354             : 
    2355             :     // Only transform when current apzc can be transformed with previous
    2356           0 :     if (prevApzc) {
    2357           0 :       if (!TransformDisplacement(this,
    2358             :                                  prevApzc,
    2359             :                                  current,
    2360             :                                  startPoint,
    2361             :                                  endPoint)) {
    2362             :         break;
    2363             :       }
    2364             :     }
    2365             : 
    2366           0 :     ParentLayerPoint availableVelocity = (endPoint - startPoint);
    2367           0 :     ParentLayerPoint residualVelocity;
    2368             : 
    2369           0 :     FlingHandoffState transformedHandoffState = aHandoffState;
    2370           0 :     transformedHandoffState.mVelocity = availableVelocity;
    2371             : 
    2372             :     // Obey overscroll-behavior.
    2373           0 :     if (prevApzc) {
    2374           0 :       residualVelocity += prevApzc->AdjustHandoffVelocityForOverscrollBehavior(transformedHandoffState.mVelocity);
    2375             :     }
    2376             : 
    2377           0 :     residualVelocity += current->AttemptFling(transformedHandoffState);
    2378             : 
    2379             :     // If there's no residual velocity, there's nothing more to hand off.
    2380           0 :     if (IsZero(residualVelocity)) {
    2381           0 :       return ParentLayerPoint();
    2382             :     }
    2383             : 
    2384             :     // If any of the velocity available to be handed off was consumed,
    2385             :     // subtract the proportion of consumed velocity from finalResidualVelocity.
    2386             :     // Note: it's important to compare |residualVelocity| to |availableVelocity|
    2387             :     // here and not to |transformedHandoffState.mVelocity|, since the latter
    2388             :     // may have been modified by AdjustHandoffVelocityForOverscrollBehavior().
    2389           0 :     if (!FuzzyEqualsAdditive(availableVelocity.x,
    2390             :                              residualVelocity.x, COORDINATE_EPSILON)) {
    2391           0 :       finalResidualVelocity.x *= (residualVelocity.x / availableVelocity.x);
    2392             :     }
    2393           0 :     if (!FuzzyEqualsAdditive(availableVelocity.y,
    2394             :                              residualVelocity.y, COORDINATE_EPSILON)) {
    2395           0 :       finalResidualVelocity.y *= (residualVelocity.y / availableVelocity.y);
    2396             :     }
    2397             : 
    2398           0 :     currentVelocity = residualVelocity;
    2399             :   }
    2400             : 
    2401             :   // Return any residual velocity left over after the entire handoff process.
    2402           0 :   return finalResidualVelocity;
    2403             : }
    2404             : 
    2405             : bool
    2406           0 : APZCTreeManager::HitTestAPZC(const ScreenIntPoint& aPoint)
    2407             : {
    2408           0 :   RefPtr<AsyncPanZoomController> target = GetTargetAPZC(aPoint, nullptr);
    2409           0 :   return target != nullptr;
    2410             : }
    2411             : 
    2412             : already_AddRefed<AsyncPanZoomController>
    2413           0 : APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
    2414             : {
    2415           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2416           0 :   RefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, nullptr);
    2417           0 :   MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
    2418           0 :   RefPtr<AsyncPanZoomController> apzc = node ? node->GetApzc() : nullptr;
    2419           0 :   return apzc.forget();
    2420             : }
    2421             : 
    2422             : static bool
    2423           0 : GuidComparatorIgnoringPresShell(const ScrollableLayerGuid& aOne, const ScrollableLayerGuid& aTwo)
    2424             : {
    2425           0 :   return aOne.mLayersId == aTwo.mLayersId
    2426           0 :       && aOne.mScrollId == aTwo.mScrollId;
    2427             : }
    2428             : 
    2429             : already_AddRefed<AsyncPanZoomController>
    2430           0 : APZCTreeManager::GetTargetAPZC(const LayersId& aLayersId,
    2431             :                                const FrameMetrics::ViewID& aScrollId)
    2432             : {
    2433           0 :   MutexAutoLock lock(mMapLock);
    2434           0 :   ScrollableLayerGuid guid(aLayersId, 0, aScrollId);
    2435           0 :   auto it = mApzcMap.find(guid);
    2436           0 :   RefPtr<AsyncPanZoomController> apzc = (it != mApzcMap.end() ? it->second : nullptr);
    2437           0 :   return apzc.forget();
    2438             : }
    2439             : 
    2440             : already_AddRefed<HitTestingTreeNode>
    2441           0 : APZCTreeManager::GetTargetNode(const ScrollableLayerGuid& aGuid,
    2442             :                                GuidComparator aComparator) const
    2443             : {
    2444           0 :   mTreeLock.AssertCurrentThreadIn();
    2445             :   RefPtr<HitTestingTreeNode> target = DepthFirstSearchPostOrder<ReverseIterator>(mRootNode.get(),
    2446           0 :       [&aGuid, &aComparator](HitTestingTreeNode* node)
    2447           0 :       {
    2448           0 :         bool matches = false;
    2449           0 :         if (node->GetApzc()) {
    2450           0 :           if (aComparator) {
    2451           0 :             matches = aComparator(aGuid, node->GetApzc()->GetGuid());
    2452             :           } else {
    2453           0 :             matches = node->GetApzc()->Matches(aGuid);
    2454             :           }
    2455             :         }
    2456           0 :         return matches;
    2457             :       }
    2458           0 :   );
    2459           0 :   return target.forget();
    2460             : }
    2461             : 
    2462             : already_AddRefed<AsyncPanZoomController>
    2463           0 : APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint,
    2464             :                                CompositorHitTestInfo* aOutHitResult,
    2465             :                                HitTestingTreeNodeAutoLock* aOutScrollbarNode)
    2466             : {
    2467           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2468             : 
    2469           0 :   CompositorHitTestInfo hitResult = CompositorHitTestInfo::eInvisibleToHitTest;
    2470           0 :   HitTestingTreeNode* scrollbarNode = nullptr;
    2471           0 :   RefPtr<AsyncPanZoomController> target;
    2472           0 :   if (gfx::gfxVars::UseWebRender()) {
    2473           0 :     target = GetAPZCAtPointWR(aPoint, &hitResult, &scrollbarNode);
    2474             :   } else {
    2475           0 :     target = GetAPZCAtPoint(mRootNode, aPoint, &hitResult, &scrollbarNode);
    2476             :   }
    2477             : 
    2478           0 :   if (aOutHitResult) {
    2479           0 :     *aOutHitResult = hitResult;
    2480             :   }
    2481           0 :   if (aOutScrollbarNode && scrollbarNode) {
    2482           0 :     RefPtr<HitTestingTreeNode> scrollbarRef = scrollbarNode;
    2483           0 :     aOutScrollbarNode->Initialize(lock, scrollbarRef.forget(), mTreeLock);
    2484             :   }
    2485           0 :   return target.forget();
    2486             : }
    2487             : 
    2488             : already_AddRefed<AsyncPanZoomController>
    2489           0 : APZCTreeManager::GetAPZCAtPointWR(const ScreenPoint& aHitTestPoint,
    2490             :                                   CompositorHitTestInfo* aOutHitResult,
    2491             :                                   HitTestingTreeNode** aOutScrollbarNode)
    2492             : {
    2493           0 :   MOZ_ASSERT(aOutHitResult);
    2494           0 :   MOZ_ASSERT(aOutScrollbarNode);
    2495             : 
    2496           0 :   RefPtr<AsyncPanZoomController> result;
    2497           0 :   RefPtr<wr::WebRenderAPI> wr = GetWebRenderAPI();
    2498           0 :   if (!wr) {
    2499             :     // If WebRender isn't running, fall back to the root APZC.
    2500             :     // This is mostly for the benefit of GTests which do not
    2501             :     // run a WebRender instance, but gracefully falling back
    2502             :     // here allows those tests which are not specifically
    2503             :     // testing the hit-test algorithm to still work.
    2504           0 :     result = FindRootApzcForLayersId(mRootLayersId);
    2505           0 :     *aOutHitResult = CompositorHitTestInfo::eVisibleToHitTest;
    2506             :     return result.forget();
    2507             :   }
    2508             : 
    2509             :   wr::WrPipelineId pipelineId;
    2510             :   FrameMetrics::ViewID scrollId;
    2511             :   gfx::CompositorHitTestInfo hitInfo;
    2512           0 :   bool hitSomething = wr->HitTest(wr::ToWorldPoint(aHitTestPoint),
    2513           0 :       pipelineId, scrollId, hitInfo);
    2514           0 :   if (!hitSomething) {
    2515             :     return result.forget();
    2516             :   }
    2517             : 
    2518           0 :   LayersId layersId = wr::AsLayersId(pipelineId);
    2519           0 :   result = GetTargetAPZC(layersId, scrollId);
    2520           0 :   if (!result) {
    2521             :     // It falls back to the root
    2522           0 :     MOZ_ASSERT(scrollId == FrameMetrics::NULL_SCROLL_ID);
    2523           0 :     result = FindRootApzcForLayersId(layersId);
    2524           0 :     MOZ_ASSERT(result);
    2525             :   }
    2526             : 
    2527           0 :   bool isScrollbar = bool(hitInfo & gfx::CompositorHitTestInfo::eScrollbar);
    2528           0 :   bool isScrollbarThumb = bool(hitInfo & gfx::CompositorHitTestInfo::eScrollbarThumb);
    2529           0 :   ScrollDirection direction = (hitInfo & gfx::CompositorHitTestInfo::eScrollbarVertical)
    2530           0 :                             ? ScrollDirection::eVertical
    2531           0 :                             : ScrollDirection::eHorizontal;
    2532           0 :   if (isScrollbar || isScrollbarThumb) {
    2533           0 :     *aOutScrollbarNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
    2534           0 :       [&](HitTestingTreeNode* aNode) {
    2535           0 :         return (aNode->GetLayersId() == layersId) &&
    2536           0 :                (aNode->IsScrollbarNode() == isScrollbar) &&
    2537           0 :                (aNode->IsScrollThumbNode() == isScrollbarThumb) &&
    2538           0 :                (aNode->GetScrollbarDirection() == direction) &&
    2539           0 :                (aNode->GetScrollTargetId() == scrollId);
    2540           0 :       });
    2541             :   }
    2542             : 
    2543           0 :   *aOutHitResult = hitInfo;
    2544             :   return result.forget();
    2545             : }
    2546             : 
    2547             : RefPtr<const OverscrollHandoffChain>
    2548           0 : APZCTreeManager::BuildOverscrollHandoffChain(const RefPtr<AsyncPanZoomController>& aInitialTarget)
    2549             : {
    2550             :   // Scroll grabbing is a mechanism that allows content to specify that
    2551             :   // the initial target of a pan should be not the innermost scrollable
    2552             :   // frame at the touch point (which is what GetTargetAPZC finds), but
    2553             :   // something higher up in the tree.
    2554             :   // It's not sufficient to just find the initial target, however, as
    2555             :   // overscroll can be handed off to another APZC. Without scroll grabbing,
    2556             :   // handoff just occurs from child to parent. With scroll grabbing, the
    2557             :   // handoff order can be different, so we build a chain of APZCs in the
    2558             :   // order in which scroll will be handed off to them.
    2559             : 
    2560             :   // Grab tree lock since we'll be walking the APZC tree.
    2561           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2562             : 
    2563             :   // Build the chain. If there is a scroll parent link, we use that. This is
    2564             :   // needed to deal with scroll info layers, because they participate in handoff
    2565             :   // but do not follow the expected layer tree structure. If there are no
    2566             :   // scroll parent links we just walk up the tree to find the scroll parent.
    2567           0 :   OverscrollHandoffChain* result = new OverscrollHandoffChain;
    2568           0 :   AsyncPanZoomController* apzc = aInitialTarget;
    2569           0 :   while (apzc != nullptr) {
    2570           0 :     result->Add(apzc);
    2571             : 
    2572           0 :     if (apzc->GetScrollHandoffParentId() == FrameMetrics::NULL_SCROLL_ID) {
    2573           0 :       if (!apzc->IsRootForLayersId()) {
    2574             :         // This probably indicates a bug or missed case in layout code
    2575           0 :         NS_WARNING("Found a non-root APZ with no handoff parent");
    2576             :       }
    2577           0 :       apzc = apzc->GetParent();
    2578           0 :       continue;
    2579             :     }
    2580             : 
    2581             :     // Guard against a possible infinite-loop condition. If we hit this, the
    2582             :     // layout code that generates the handoff parents did something wrong.
    2583           0 :     MOZ_ASSERT(apzc->GetScrollHandoffParentId() != apzc->GetGuid().mScrollId);
    2584             :     RefPtr<AsyncPanZoomController> scrollParent =
    2585           0 :         GetTargetAPZC(apzc->GetGuid().mLayersId, apzc->GetScrollHandoffParentId());
    2586           0 :     apzc = scrollParent.get();
    2587             :   }
    2588             : 
    2589             :   // Now adjust the chain to account for scroll grabbing. Sorting is a bit
    2590             :   // of an overkill here, but scroll grabbing will likely be generalized
    2591             :   // to scroll priorities, so we might as well do it this way.
    2592           0 :   result->SortByScrollPriority();
    2593             : 
    2594             :   // Print the overscroll chain for debugging.
    2595           0 :   for (uint32_t i = 0; i < result->Length(); ++i) {
    2596             :     APZCTM_LOG("OverscrollHandoffChain[%d] = %p\n", i, result->GetApzcAtIndex(i).get());
    2597             :   }
    2598             : 
    2599           0 :   return result;
    2600             : }
    2601             : 
    2602             : void
    2603           0 : APZCTreeManager::SetLongTapEnabled(bool aLongTapEnabled)
    2604             : {
    2605           0 :   APZThreadUtils::AssertOnControllerThread();
    2606           0 :   GestureEventListener::SetLongTapEnabled(aLongTapEnabled);
    2607           0 : }
    2608             : 
    2609             : void
    2610           0 : APZCTreeManager::FindScrollThumbNode(const AsyncDragMetrics& aDragMetrics,
    2611             :                                      HitTestingTreeNodeAutoLock& aOutThumbNode)
    2612             : {
    2613           0 :   if (!aDragMetrics.mDirection) {
    2614             :     // The AsyncDragMetrics has not been initialized yet - there will be
    2615             :     // no matching node, so don't bother searching the tree.
    2616           0 :     return;
    2617             :   }
    2618             : 
    2619           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2620             : 
    2621             :   RefPtr<HitTestingTreeNode> result = DepthFirstSearch<ReverseIterator>(
    2622             :       mRootNode.get(),
    2623           0 :       [&aDragMetrics](HitTestingTreeNode* aNode) {
    2624             :         return aNode->MatchesScrollDragMetrics(aDragMetrics);
    2625           0 :       });
    2626           0 :   if (result) {
    2627           0 :     aOutThumbNode.Initialize(lock, result.forget(), mTreeLock);
    2628             :   }
    2629             : }
    2630             : 
    2631             : AsyncPanZoomController*
    2632           0 : APZCTreeManager::GetTargetApzcForNode(HitTestingTreeNode* aNode)
    2633             : {
    2634           0 :   for (const HitTestingTreeNode* n = aNode;
    2635           0 :        n && n->GetLayersId() == aNode->GetLayersId();
    2636             :        n = n->GetParent()) {
    2637           0 :     if (n->GetApzc()) {
    2638             :       APZCTM_LOG("Found target %p using ancestor lookup\n", n->GetApzc());
    2639           0 :       return n->GetApzc();
    2640             :     }
    2641           0 :     if (n->GetFixedPosTarget() != FrameMetrics::NULL_SCROLL_ID) {
    2642             :       RefPtr<AsyncPanZoomController> fpTarget =
    2643           0 :           GetTargetAPZC(n->GetLayersId(), n->GetFixedPosTarget());
    2644             :       APZCTM_LOG("Found target APZC %p using fixed-pos lookup on %" PRIu64 "\n", fpTarget.get(), n->GetFixedPosTarget());
    2645           0 :       return fpTarget.get();
    2646             :     }
    2647             :   }
    2648             :   return nullptr;
    2649             : }
    2650             : 
    2651             : AsyncPanZoomController*
    2652           0 : APZCTreeManager::GetAPZCAtPoint(HitTestingTreeNode* aNode,
    2653             :                                 const ScreenPoint& aHitTestPoint,
    2654             :                                 CompositorHitTestInfo* aOutHitResult,
    2655             :                                 HitTestingTreeNode** aOutScrollbarNode)
    2656             : {
    2657           0 :   mTreeLock.AssertCurrentThreadIn();
    2658             : 
    2659             :   // This walks the tree in depth-first, reverse order, so that it encounters
    2660             :   // APZCs front-to-back on the screen.
    2661             :   HitTestingTreeNode* resultNode;
    2662           0 :   HitTestingTreeNode* root = aNode;
    2663           0 :   std::stack<LayerPoint> hitTestPoints;
    2664             :   ParentLayerPoint point = ViewAs<ParentLayerPixel>(aHitTestPoint,
    2665           0 :       PixelCastJustification::ScreenIsParentLayerForRoot);
    2666           0 :   hitTestPoints.push(ViewAs<LayerPixel>(point,
    2667           0 :       PixelCastJustification::MovingDownToChildren));
    2668             : 
    2669           0 :   ForEachNode<ReverseIterator>(root,
    2670           0 :       [&hitTestPoints, this](HitTestingTreeNode* aNode) {
    2671           0 :         ParentLayerPoint hitTestPointForParent = ViewAs<ParentLayerPixel>(hitTestPoints.top(),
    2672           0 :             PixelCastJustification::MovingDownToChildren);
    2673           0 :         if (aNode->IsOutsideClip(hitTestPointForParent)) {
    2674             :           // If the point being tested is outside the clip region for this node
    2675             :           // then we don't need to test against this node or any of its children.
    2676             :           // Just skip it and move on.
    2677             :           APZCTM_LOG("Point %f %f outside clip for node %p\n",
    2678             :             hitTestPoints.top().x, hitTestPoints.top().y, aNode);
    2679             :           return TraversalFlag::Skip;
    2680             :         }
    2681             :         // First check the subtree rooted at this node, because deeper nodes
    2682             :         // are more "in front".
    2683             :         Maybe<LayerPoint> hitTestPoint = aNode->Untransform(
    2684           0 :             hitTestPointForParent, ComputeTransformForNode(aNode));
    2685             :         APZCTM_LOG("Transformed ParentLayer point %s to layer %s\n",
    2686             :                 Stringify(hitTestPointForParent).c_str(),
    2687             :                 hitTestPoint ? Stringify(hitTestPoint.ref()).c_str() : "nil");
    2688           0 :         if (!hitTestPoint) {
    2689             :           return TraversalFlag::Skip;
    2690             :         }
    2691           0 :         hitTestPoints.push(hitTestPoint.ref());
    2692           0 :         return TraversalFlag::Continue;
    2693             :       },
    2694           0 :       [&resultNode, &hitTestPoints, &aOutHitResult](HitTestingTreeNode* aNode) {
    2695           0 :         CompositorHitTestInfo hitResult = aNode->HitTest(hitTestPoints.top());
    2696           0 :         hitTestPoints.pop();
    2697             :         APZCTM_LOG("Testing Layer point %s against node %p\n",
    2698             :                 Stringify(hitTestPoints.top()).c_str(), aNode);
    2699           0 :         if (hitResult != CompositorHitTestInfo::eInvisibleToHitTest) {
    2700           0 :           resultNode = aNode;
    2701           0 :           *aOutHitResult = hitResult;
    2702           0 :           return TraversalFlag::Abort;
    2703             :         }
    2704             :         return TraversalFlag::Continue;
    2705             :       }
    2706           0 :   );
    2707             : 
    2708           0 :   if (*aOutHitResult != CompositorHitTestInfo::eInvisibleToHitTest) {
    2709           0 :     MOZ_ASSERT(resultNode);
    2710           0 :     for (HitTestingTreeNode* n = resultNode; n; n = n->GetParent()) {
    2711           0 :       if (n->IsScrollbarNode()) {
    2712           0 :         *aOutScrollbarNode = n;
    2713           0 :         *aOutHitResult |= CompositorHitTestInfo::eScrollbar;
    2714           0 :         if (n->IsScrollThumbNode()) {
    2715           0 :           *aOutHitResult |= CompositorHitTestInfo::eScrollbarThumb;
    2716             :         }
    2717           0 :         if (n->GetScrollbarDirection() == ScrollDirection::eVertical) {
    2718           0 :           *aOutHitResult |= CompositorHitTestInfo::eScrollbarVertical;
    2719             :         }
    2720             : 
    2721             :         // If we hit a scrollbar, target the APZC for the content scrolled
    2722             :         // by the scrollbar. (The scrollbar itself doesn't scroll with the
    2723             :         // scrolled content, so it doesn't carry the scrolled content's
    2724             :         // scroll metadata).
    2725             :         RefPtr<AsyncPanZoomController> scrollTarget =
    2726           0 :             GetTargetAPZC(n->GetLayersId(), n->GetScrollTargetId());
    2727           0 :         if (scrollTarget) {
    2728           0 :           return scrollTarget.get();
    2729             :         }
    2730             :       }
    2731             :     }
    2732             : 
    2733           0 :     AsyncPanZoomController* result = GetTargetApzcForNode(resultNode);
    2734           0 :     if (!result) {
    2735           0 :       result = FindRootApzcForLayersId(resultNode->GetLayersId());
    2736           0 :       MOZ_ASSERT(result);
    2737             :       APZCTM_LOG("Found target %p using root lookup\n", result);
    2738             :     }
    2739             :     APZCTM_LOG("Successfully matched APZC %p via node %p (hit result 0x%x)\n",
    2740             :         result, resultNode, (int)*aOutHitResult);
    2741             :     return result;
    2742             :   }
    2743             : 
    2744             :   return nullptr;
    2745             : }
    2746             : 
    2747             : AsyncPanZoomController*
    2748           0 : APZCTreeManager::FindRootApzcForLayersId(LayersId aLayersId) const
    2749             : {
    2750           0 :   mTreeLock.AssertCurrentThreadIn();
    2751             : 
    2752           0 :   HitTestingTreeNode* resultNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
    2753           0 :       [aLayersId](HitTestingTreeNode* aNode) {
    2754           0 :         AsyncPanZoomController* apzc = aNode->GetApzc();
    2755             :         return apzc
    2756           0 :             && apzc->GetLayersId() == aLayersId
    2757           0 :             && apzc->IsRootForLayersId();
    2758           0 :       });
    2759           0 :   return resultNode ? resultNode->GetApzc() : nullptr;
    2760             : }
    2761             : 
    2762             : AsyncPanZoomController*
    2763           0 : APZCTreeManager::FindRootContentApzcForLayersId(LayersId aLayersId) const
    2764             : {
    2765           0 :   mTreeLock.AssertCurrentThreadIn();
    2766             : 
    2767           0 :   HitTestingTreeNode* resultNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
    2768           0 :       [aLayersId](HitTestingTreeNode* aNode) {
    2769           0 :         AsyncPanZoomController* apzc = aNode->GetApzc();
    2770             :         return apzc
    2771           0 :             && apzc->GetLayersId() == aLayersId
    2772           0 :             && apzc->IsRootContent();
    2773           0 :       });
    2774           0 :   return resultNode ? resultNode->GetApzc() : nullptr;
    2775             : }
    2776             : 
    2777             : AsyncPanZoomController*
    2778           0 : APZCTreeManager::FindRootContentOrRootApzc() const
    2779             : {
    2780           0 :   mTreeLock.AssertCurrentThreadIn();
    2781             : 
    2782             :   // Note: this is intended to find the same "root" that would be found
    2783             :   // by AsyncCompositionManager::ApplyAsyncContentTransformToTree inside
    2784             :   // the MOZ_WIDGET_ANDROID block. That is, it should find the RCD node if there
    2785             :   // is one, or the root APZC if there is not.
    2786             :   // Since BreadthFirstSearch is a pre-order search, we first do a search for
    2787             :   // the RCD, and then if we don't find one, we do a search for the root APZC.
    2788           0 :   HitTestingTreeNode* resultNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
    2789           0 :       [](HitTestingTreeNode* aNode) {
    2790           0 :         AsyncPanZoomController* apzc = aNode->GetApzc();
    2791           0 :         return apzc && apzc->IsRootContent();
    2792           0 :       });
    2793           0 :   if (resultNode) {
    2794           0 :     return resultNode->GetApzc();
    2795             :   }
    2796           0 :   resultNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
    2797           0 :       [](HitTestingTreeNode* aNode) {
    2798           0 :         AsyncPanZoomController* apzc = aNode->GetApzc();
    2799           0 :         return (apzc != nullptr);
    2800           0 :       });
    2801           0 :   return resultNode ? resultNode->GetApzc() : nullptr;
    2802             : }
    2803             : 
    2804             : /* The methods GetScreenToApzcTransform() and GetApzcToGeckoTransform() return
    2805             :    some useful transformations that input events may need applied. This is best
    2806             :    illustrated with an example. Consider a chain of layers, L, M, N, O, P, Q, R. Layer L
    2807             :    is the layer that corresponds to the argument |aApzc|, and layer R is the root
    2808             :    of the layer tree. Layer M is the parent of L, N is the parent of M, and so on.
    2809             :    When layer L is displayed to the screen by the compositor, the set of transforms that
    2810             :    are applied to L are (in order from top to bottom):
    2811             : 
    2812             :         L's CSS transform                   (hereafter referred to as transform matrix LC)
    2813             :         L's nontransient async transform    (hereafter referred to as transform matrix LN)
    2814             :         L's transient async transform       (hereafter referred to as transform matrix LT)
    2815             :         M's CSS transform                   (hereafter referred to as transform matrix MC)
    2816             :         M's nontransient async transform    (hereafter referred to as transform matrix MN)
    2817             :         M's transient async transform       (hereafter referred to as transform matrix MT)
    2818             :         ...
    2819             :         R's CSS transform                   (hereafter referred to as transform matrix RC)
    2820             :         R's nontransient async transform    (hereafter referred to as transform matrix RN)
    2821             :         R's transient async transform       (hereafter referred to as transform matrix RT)
    2822             : 
    2823             :    Also, for any layer, the async transform is the combination of its transient and non-transient
    2824             :    parts. That is, for any layer L:
    2825             :                   LA === LN * LT
    2826             :         LA.Inverse() === LT.Inverse() * LN.Inverse()
    2827             : 
    2828             :    If we want user input to modify L's transient async transform, we have to first convert
    2829             :    user input from screen space to the coordinate space of L's transient async transform. Doing
    2830             :    this involves applying the following transforms (in order from top to bottom):
    2831             :         RT.Inverse()
    2832             :         RN.Inverse()
    2833             :         RC.Inverse()
    2834             :         ...
    2835             :         MT.Inverse()
    2836             :         MN.Inverse()
    2837             :         MC.Inverse()
    2838             :    This combined transformation is returned by GetScreenToApzcTransform().
    2839             : 
    2840             :    Next, if we want user inputs sent to gecko for event-dispatching, we will need to strip
    2841             :    out all of the async transforms that are involved in this chain. This is because async
    2842             :    transforms are stored only in the compositor and gecko does not account for them when
    2843             :    doing display-list-based hit-testing for event dispatching.
    2844             :    Furthermore, because these input events are processed by Gecko in a FIFO queue that
    2845             :    includes other things (specifically paint requests), it is possible that by time the
    2846             :    input event reaches gecko, it will have painted something else. Therefore, we need to
    2847             :    apply another transform to the input events to account for the possible disparity between
    2848             :    what we know gecko last painted and the last paint request we sent to gecko. Let this
    2849             :    transform be represented by LD, MD, ... RD.
    2850             :    Therefore, given a user input in screen space, the following transforms need to be applied
    2851             :    (in order from top to bottom):
    2852             :         RT.Inverse()
    2853             :         RN.Inverse()
    2854             :         RC.Inverse()
    2855             :         ...
    2856             :         MT.Inverse()
    2857             :         MN.Inverse()
    2858             :         MC.Inverse()
    2859             :         LT.Inverse()
    2860             :         LN.Inverse()
    2861             :         LC.Inverse()
    2862             :         LC
    2863             :         LD
    2864             :         MC
    2865             :         MD
    2866             :         ...
    2867             :         RC
    2868             :         RD
    2869             :    This sequence can be simplified and refactored to the following:
    2870             :         GetScreenToApzcTransform()
    2871             :         LA.Inverse()
    2872             :         LD
    2873             :         MC
    2874             :         MD
    2875             :         ...
    2876             :         RC
    2877             :         RD
    2878             :    Since GetScreenToApzcTransform() can be obtained by calling that function, GetApzcToGeckoTransform()
    2879             :    returns the remaining transforms (LA.Inverse() * LD * ... * RD), so that the caller code can
    2880             :    combine it with GetScreenToApzcTransform() to get the final transform required in this case.
    2881             : 
    2882             :    Note that for many of these layers, there will be no AsyncPanZoomController attached, and
    2883             :    so the async transform will be the identity transform. So, in the example above, if layers
    2884             :    L and P have APZC instances attached, MT, MN, MD, NT, NN, ND, OT, ON, OD, QT, QN, QD, RT,
    2885             :    RN and RD will be identity transforms.
    2886             :    Additionally, for space-saving purposes, each APZC instance stores its layer's individual
    2887             :    CSS transform and the accumulation of CSS transforms to its parent APZC. So the APZC for
    2888             :    layer L would store LC and (MC * NC * OC), and the layer P would store PC and (QC * RC).
    2889             :    The APZC instances track the last dispatched paint request and so are able to calculate LD and
    2890             :    PD using those internally stored values.
    2891             :    The APZCs also obviously have LT, LN, PT, and PN, so all of the above transformation combinations
    2892             :    required can be generated.
    2893             :  */
    2894             : 
    2895             : /*
    2896             :  * See the long comment above for a detailed explanation of this function.
    2897             :  */
    2898             : ScreenToParentLayerMatrix4x4
    2899           0 : APZCTreeManager::GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const
    2900             : {
    2901           0 :   Matrix4x4 result;
    2902           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2903             : 
    2904             :   // The comments below assume there is a chain of layers L..R with L and P having APZC instances as
    2905             :   // explained in the comment above. This function is called with aApzc at L, and the loop
    2906             :   // below performs one iteration, where parent is at P. The comments explain what values are stored
    2907             :   // in the variables at these two levels. All the comments use standard matrix notation where the
    2908             :   // leftmost matrix in a multiplication is applied first.
    2909             : 
    2910             :   // ancestorUntransform is PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
    2911           0 :   Matrix4x4 ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
    2912             : 
    2913             :   // result is initialized to PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
    2914           0 :   result = ancestorUntransform;
    2915             : 
    2916           0 :   for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) {
    2917             :     // ancestorUntransform is updated to RC.Inverse() * QC.Inverse() when parent == P
    2918           0 :     ancestorUntransform = parent->GetAncestorTransform().Inverse();
    2919             :     // asyncUntransform is updated to PA.Inverse() when parent == P
    2920           0 :     Matrix4x4 asyncUntransform = parent->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::eForHitTesting).Inverse().ToUnknownMatrix();
    2921             :     // untransformSinceLastApzc is RC.Inverse() * QC.Inverse() * PA.Inverse()
    2922           0 :     Matrix4x4 untransformSinceLastApzc = ancestorUntransform * asyncUntransform;
    2923             : 
    2924             :     // result is RC.Inverse() * QC.Inverse() * PA.Inverse() * PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
    2925           0 :     result = untransformSinceLastApzc * result;
    2926             : 
    2927             :     // The above value for result when parent == P matches the required output
    2928             :     // as explained in the comment above this method. Note that any missing
    2929             :     // terms are guaranteed to be identity transforms.
    2930             :   }
    2931             : 
    2932           0 :   return ViewAs<ScreenToParentLayerMatrix4x4>(result);
    2933             : }
    2934             : 
    2935             : /*
    2936             :  * See the long comment above GetScreenToApzcTransform() for a detailed
    2937             :  * explanation of this function.
    2938             :  */
    2939             : ParentLayerToScreenMatrix4x4
    2940           0 : APZCTreeManager::GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const
    2941             : {
    2942           0 :   Matrix4x4 result;
    2943           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2944             : 
    2945             :   // The comments below assume there is a chain of layers L..R with L and P having APZC instances as
    2946             :   // explained in the comment above. This function is called with aApzc at L, and the loop
    2947             :   // below performs one iteration, where parent is at P. The comments explain what values are stored
    2948             :   // in the variables at these two levels. All the comments use standard matrix notation where the
    2949             :   // leftmost matrix in a multiplication is applied first.
    2950             : 
    2951             :   // asyncUntransform is LA.Inverse()
    2952           0 :   Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::eForHitTesting).Inverse().ToUnknownMatrix();
    2953             : 
    2954             :   // aTransformToGeckoOut is initialized to LA.Inverse() * LD * MC * NC * OC * PC
    2955           0 :   result = asyncUntransform * aApzc->GetTransformToLastDispatchedPaint() * aApzc->GetAncestorTransform();
    2956             : 
    2957           0 :   for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) {
    2958             :     // aTransformToGeckoOut is LA.Inverse() * LD * MC * NC * OC * PC * PD * QC * RC
    2959           0 :     result = result * parent->GetTransformToLastDispatchedPaint() * parent->GetAncestorTransform();
    2960             : 
    2961             :     // The above value for result when parent == P matches the required output
    2962             :     // as explained in the comment above this method. Note that any missing
    2963             :     // terms are guaranteed to be identity transforms.
    2964             :   }
    2965             : 
    2966           0 :   return ViewAs<ParentLayerToScreenMatrix4x4>(result);
    2967             : }
    2968             : 
    2969             : ScreenPoint
    2970           0 : APZCTreeManager::GetCurrentMousePosition() const
    2971             : {
    2972           0 :   return mCurrentMousePosition;
    2973             : }
    2974             : 
    2975             : already_AddRefed<AsyncPanZoomController>
    2976           0 : APZCTreeManager::GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const
    2977             : {
    2978           0 :   RecursiveMutexAutoLock lock(mTreeLock);
    2979           0 :   RefPtr<AsyncPanZoomController> apzc;
    2980             :   // For now, we only ever want to do pinching on the root-content APZC for
    2981             :   // a given layers id.
    2982           0 :   if (aApzc1 && aApzc2 && aApzc1->GetLayersId() == aApzc2->GetLayersId()) {
    2983             :     // If the two APZCs have the same layers id, find the root-content APZC
    2984             :     // for that layers id. Don't call CommonAncestor() because there may not
    2985             :     // be a common ancestor for the layers id (e.g. if one APZCs is inside a
    2986             :     // fixed-position element).
    2987           0 :     apzc = FindRootContentApzcForLayersId(aApzc1->GetLayersId());
    2988             :   } else {
    2989             :     // Otherwise, find the common ancestor (to reach a common layers id), and
    2990             :     // get the root-content APZC for that layers id.
    2991           0 :     apzc = CommonAncestor(aApzc1, aApzc2);
    2992           0 :     if (apzc) {
    2993           0 :       apzc = FindRootContentApzcForLayersId(apzc->GetLayersId());
    2994             :     }
    2995             :   }
    2996           0 :   return apzc.forget();
    2997             : }
    2998             : 
    2999             : already_AddRefed<AsyncPanZoomController>
    3000           0 : APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const
    3001             : {
    3002           0 :   mTreeLock.AssertCurrentThreadIn();
    3003           0 :   RefPtr<AsyncPanZoomController> ancestor;
    3004             : 
    3005             :   // If either aApzc1 or aApzc2 is null, min(depth1, depth2) will be 0 and this function
    3006             :   // will return null.
    3007             : 
    3008             :   // Calculate depth of the APZCs in the tree
    3009           0 :   int depth1 = 0, depth2 = 0;
    3010           0 :   for (AsyncPanZoomController* parent = aApzc1; parent; parent = parent->GetParent()) {
    3011           0 :     depth1++;
    3012             :   }
    3013           0 :   for (AsyncPanZoomController* parent = aApzc2; parent; parent = parent->GetParent()) {
    3014           0 :     depth2++;
    3015             :   }
    3016             : 
    3017             :   // At most one of the following two loops will be executed; the deeper APZC pointer
    3018             :   // will get walked up to the depth of the shallower one.
    3019           0 :   int minDepth = depth1 < depth2 ? depth1 : depth2;
    3020           0 :   while (depth1 > minDepth) {
    3021           0 :     depth1--;
    3022           0 :     aApzc1 = aApzc1->GetParent();
    3023             :   }
    3024           0 :   while (depth2 > minDepth) {
    3025           0 :     depth2--;
    3026           0 :     aApzc2 = aApzc2->GetParent();
    3027             :   }
    3028             : 
    3029             :   // Walk up the ancestor chains of both APZCs, always staying at the same depth for
    3030             :   // either APZC, and return the the first common ancestor encountered.
    3031             :   while (true) {
    3032           0 :     if (aApzc1 == aApzc2) {
    3033             :       ancestor = aApzc1;
    3034             :       break;
    3035             :     }
    3036           0 :     if (depth1 <= 0) {
    3037             :       break;
    3038             :     }
    3039           0 :     aApzc1 = aApzc1->GetParent();
    3040           0 :     aApzc2 = aApzc2->GetParent();
    3041             :   }
    3042           0 :   return ancestor.forget();
    3043             : }
    3044             : 
    3045             : LayerToParentLayerMatrix4x4
    3046           0 : APZCTreeManager::ComputeTransformForNode(const HitTestingTreeNode* aNode) const
    3047             : {
    3048           0 :   mTreeLock.AssertCurrentThreadIn();
    3049           0 :   if (AsyncPanZoomController* apzc = aNode->GetApzc()) {
    3050             :     // If the node represents scrollable content, apply the async transform
    3051             :     // from its APZC.
    3052           0 :     return aNode->GetTransform() *
    3053           0 :         CompleteAsyncTransform(
    3054           0 :           apzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::eForHitTesting));
    3055           0 :   } else if (aNode->IsScrollThumbNode()) {
    3056             :     // If the node represents a scrollbar thumb, compute and apply the
    3057             :     // transformation that will be applied to the thumb in
    3058             :     // AsyncCompositionManager.
    3059           0 :     ScrollableLayerGuid guid{aNode->GetLayersId(), 0, aNode->GetScrollTargetId()};
    3060           0 :     if (RefPtr<HitTestingTreeNode> scrollTargetNode = GetTargetNode(guid, &GuidComparatorIgnoringPresShell)) {
    3061           0 :       AsyncPanZoomController* scrollTargetApzc = scrollTargetNode->GetApzc();
    3062           0 :       MOZ_ASSERT(scrollTargetApzc);
    3063             :       return scrollTargetApzc->CallWithLastContentPaintMetrics(
    3064           0 :         [&](const FrameMetrics& aMetrics) {
    3065             :           return ComputeTransformForScrollThumb(
    3066           0 :               aNode->GetTransform() * AsyncTransformMatrix(),
    3067           0 :               scrollTargetNode->GetTransform().ToUnknownMatrix(),
    3068           0 :               scrollTargetApzc,
    3069             :               aMetrics,
    3070             :               aNode->GetScrollbarData(),
    3071           0 :               scrollTargetNode->IsAncestorOf(aNode),
    3072             :               nullptr);
    3073           0 :         });
    3074             :     }
    3075             :   }
    3076             :   // Otherwise, the node does not have an async transform.
    3077           0 :   return aNode->GetTransform() * AsyncTransformMatrix();
    3078             : }
    3079             : 
    3080             : already_AddRefed<wr::WebRenderAPI>
    3081           0 : APZCTreeManager::GetWebRenderAPI() const
    3082             : {
    3083           0 :   RefPtr<wr::WebRenderAPI> api;
    3084           0 :   CompositorBridgeParent::CallWithIndirectShadowTree(mRootLayersId,
    3085           0 :     [&](LayerTreeState& aState) -> void {
    3086           0 :       if (aState.mWrBridge) {
    3087           0 :         api = aState.mWrBridge->GetWebRenderAPI();
    3088             :       }
    3089           0 :     });
    3090           0 :   return api.forget();
    3091             : }
    3092             : 
    3093             : already_AddRefed<GeckoContentController>
    3094           0 : APZCTreeManager::GetContentController(LayersId aLayersId) const
    3095             : {
    3096           0 :   RefPtr<GeckoContentController> controller;
    3097           0 :   CompositorBridgeParent::CallWithIndirectShadowTree(aLayersId,
    3098           0 :     [&](LayerTreeState& aState) -> void {
    3099           0 :       controller = aState.mController;
    3100           0 :     });
    3101           0 :   return controller.forget();
    3102             : }
    3103             : 
    3104             : bool
    3105           0 : APZCTreeManager::GetAPZTestData(LayersId aLayersId,
    3106             :                                 APZTestData* aOutData)
    3107             : {
    3108           0 :   AssertOnUpdaterThread();
    3109           0 :   MutexAutoLock lock(mTestDataLock);
    3110           0 :   auto it = mTestData.find(aLayersId);
    3111           0 :   if (it == mTestData.end()) {
    3112             :     return false;
    3113             :   }
    3114           0 :   *aOutData = *(it->second);
    3115           0 :   return true;
    3116             : }
    3117             : 
    3118             : /*static*/ LayerToParentLayerMatrix4x4
    3119           0 : APZCTreeManager::ComputeTransformForScrollThumb(
    3120             :     const LayerToParentLayerMatrix4x4& aCurrentTransform,
    3121             :     const Matrix4x4& aScrollableContentTransform,
    3122             :     AsyncPanZoomController* aApzc,
    3123             :     const FrameMetrics& aMetrics,
    3124             :     const ScrollbarData& aScrollbarData,
    3125             :     bool aScrollbarIsDescendant,
    3126             :     AsyncTransformComponentMatrix* aOutClipTransform)
    3127             : {
    3128             :   // We only apply the transform if the scroll-target layer has non-container
    3129             :   // children (i.e. when it has some possibly-visible content). This is to
    3130             :   // avoid moving scroll-bars in the situation that only a scroll information
    3131             :   // layer has been built for a scroll frame, as this would result in a
    3132             :   // disparity between scrollbars and visible content.
    3133           0 :   if (aMetrics.IsScrollInfoLayer()) {
    3134           0 :     return LayerToParentLayerMatrix4x4{};
    3135             :   }
    3136             : 
    3137           0 :   MOZ_RELEASE_ASSERT(aApzc);
    3138             : 
    3139             :   AsyncTransformComponentMatrix asyncTransform =
    3140           0 :     aApzc->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing);
    3141             : 
    3142             :   // |asyncTransform| represents the amount by which we have scrolled and
    3143             :   // zoomed since the last paint. Because the scrollbar was sized and positioned based
    3144             :   // on the painted content, we need to adjust it based on asyncTransform so that
    3145             :   // it reflects what the user is actually seeing now.
    3146           0 :   AsyncTransformComponentMatrix scrollbarTransform;
    3147           0 :   if (*aScrollbarData.mDirection == ScrollDirection::eVertical) {
    3148           0 :     const ParentLayerCoord asyncScrollY = asyncTransform._42;
    3149           0 :     const float asyncZoomY = asyncTransform._22;
    3150             : 
    3151             :     // The scroll thumb needs to be scaled in the direction of scrolling by the
    3152             :     // inverse of the async zoom. This is because zooming in decreases the
    3153             :     // fraction of the whole srollable rect that is in view.
    3154           0 :     const float yScale = 1.f / asyncZoomY;
    3155             : 
    3156             :     // Note: |metrics.GetZoom()| doesn't yet include the async zoom.
    3157           0 :     const CSSToParentLayerScale effectiveZoom(aMetrics.GetZoom().yScale * asyncZoomY);
    3158             : 
    3159             :     // Here we convert the scrollbar thumb ratio into a true unitless ratio by
    3160             :     // dividing out the conversion factor from the scrollframe's parent's space
    3161             :     // to the scrollframe's space.
    3162           0 :     const float ratio = aScrollbarData.mThumbRatio /
    3163           0 :         (aMetrics.GetPresShellResolution() * asyncZoomY);
    3164             :     // The scroll thumb needs to be translated in opposite direction of the
    3165             :     // async scroll. This is because scrolling down, which translates the layer
    3166             :     // content up, should result in moving the scroll thumb down.
    3167           0 :     ParentLayerCoord yTranslation = -asyncScrollY * ratio;
    3168             : 
    3169             :     // The scroll thumb additionally needs to be translated to compensate for
    3170             :     // the scale applied above. The origin with respect to which the scale is
    3171             :     // applied is the origin of the entire scrollbar, rather than the origin of
    3172             :     // the scroll thumb (meaning, for a vertical scrollbar it's at the top of
    3173             :     // the composition bounds). This means that empty space above the thumb
    3174             :     // is scaled too, effectively translating the thumb. We undo that
    3175             :     // translation here.
    3176             :     // (One can think of the adjustment being done to the translation here as
    3177             :     // a change of basis. We have a method to help with that,
    3178             :     // Matrix4x4::ChangeBasis(), but it wouldn't necessarily make the code
    3179             :     // cleaner in this case).
    3180           0 :     const CSSCoord thumbOrigin = (aMetrics.GetScrollOffset().y * ratio);
    3181           0 :     const CSSCoord thumbOriginScaled = thumbOrigin * yScale;
    3182           0 :     const CSSCoord thumbOriginDelta = thumbOriginScaled - thumbOrigin;
    3183           0 :     const ParentLayerCoord thumbOriginDeltaPL = thumbOriginDelta * effectiveZoom;
    3184           0 :     yTranslation -= thumbOriginDeltaPL;
    3185             : 
    3186           0 :     if (aMetrics.IsRootContent()) {
    3187             :       // Scrollbar for the root are painted at the same resolution as the
    3188             :       // content. Since the coordinate space we apply this transform in includes
    3189             :       // the resolution, we need to adjust for it as well here. Note that in
    3190             :       // another metrics.IsRootContent() hunk below we apply a
    3191             :       // resolution-cancelling transform which ensures the scroll thumb isn't
    3192             :       // actually rendered at a larger scale.
    3193           0 :       yTranslation *= aMetrics.GetPresShellResolution();
    3194             :     }
    3195             : 
    3196           0 :     scrollbarTransform.PostScale(1.f, yScale, 1.f);
    3197           0 :     scrollbarTransform.PostTranslate(0, yTranslation, 0);
    3198             :   }
    3199           0 :   if (*aScrollbarData.mDirection == ScrollDirection::eHorizontal) {
    3200             :     // See detailed comments under the VERTICAL case.
    3201             : 
    3202           0 :     const ParentLayerCoord asyncScrollX = asyncTransform._41;
    3203           0 :     const float asyncZoomX = asyncTransform._11;
    3204             : 
    3205           0 :     const float xScale = 1.f / asyncZoomX;
    3206             : 
    3207           0 :     const CSSToParentLayerScale effectiveZoom(aMetrics.GetZoom().xScale * asyncZoomX);
    3208             : 
    3209           0 :     const float ratio = aScrollbarData.mThumbRatio /
    3210           0 :         (aMetrics.GetPresShellResolution() * asyncZoomX);
    3211           0 :     ParentLayerCoord xTranslation = -asyncScrollX * ratio;
    3212             : 
    3213           0 :     const CSSCoord thumbOrigin = (aMetrics.GetScrollOffset().x * ratio);
    3214           0 :     const CSSCoord thumbOriginScaled = thumbOrigin * xScale;
    3215           0 :     const CSSCoord thumbOriginDelta = thumbOriginScaled - thumbOrigin;
    3216           0 :     const ParentLayerCoord thumbOriginDeltaPL = thumbOriginDelta * effectiveZoom;
    3217           0 :     xTranslation -= thumbOriginDeltaPL;
    3218             : 
    3219           0 :     if (aMetrics.IsRootContent()) {
    3220           0 :       xTranslation *= aMetrics.GetPresShellResolution();
    3221             :     }
    3222             : 
    3223           0 :     scrollbarTransform.PostScale(xScale, 1.f, 1.f);
    3224           0 :     scrollbarTransform.PostTranslate(xTranslation, 0, 0);
    3225             :   }
    3226             : 
    3227             :   LayerToParentLayerMatrix4x4 transform =
    3228           0 :       aCurrentTransform * scrollbarTransform;
    3229             : 
    3230           0 :   AsyncTransformComponentMatrix compensation;
    3231             :   // If the scrollbar layer is for the root then the content's resolution
    3232             :   // applies to the scrollbar as well. Since we don't actually want the scroll
    3233             :   // thumb's size to vary with the zoom (other than its length reflecting the
    3234             :   // fraction of the scrollable length that's in view, which is taken care of
    3235             :   // above), we apply a transform to cancel out this resolution.
    3236           0 :   if (aMetrics.IsRootContent()) {
    3237           0 :     compensation =
    3238           0 :         AsyncTransformComponentMatrix::Scaling(
    3239             :             aMetrics.GetPresShellResolution(),
    3240             :             aMetrics.GetPresShellResolution(),
    3241           0 :             1.0f).Inverse();
    3242             :   }
    3243             :   // If the scrollbar layer is a child of the content it is a scrollbar for,
    3244             :   // then we need to adjust for any async transform (including an overscroll
    3245             :   // transform) on the content. This needs to be cancelled out because layout
    3246             :   // positions and sizes the scrollbar on the assumption that there is no async
    3247             :   // transform, and without this adjustment the scrollbar will end up in the
    3248             :   // wrong place.
    3249             :   //
    3250             :   // Note that since the async transform is applied on top of the content's
    3251             :   // regular transform, we need to make sure to unapply the async transform in
    3252             :   // the same coordinate space. This requires applying the content transform
    3253             :   // and then unapplying it after unapplying the async transform.
    3254           0 :   if (aScrollbarIsDescendant) {
    3255             :     AsyncTransformComponentMatrix overscroll =
    3256           0 :         aApzc->GetOverscrollTransform(AsyncPanZoomController::eForCompositing);
    3257           0 :     Matrix4x4 asyncUntransform = (asyncTransform * overscroll).Inverse().ToUnknownMatrix();
    3258           0 :     const Matrix4x4& contentTransform = aScrollableContentTransform;
    3259           0 :     Matrix4x4 contentUntransform = contentTransform.Inverse();
    3260             : 
    3261           0 :     compensation *= ViewAs<AsyncTransformComponentMatrix>(
    3262             :                         contentTransform
    3263           0 :                       * asyncUntransform
    3264           0 :                       * contentUntransform);
    3265             : 
    3266             :     // Pass the total compensation out to the caller so that it can use it
    3267             :     // to transform clip transforms as needed.
    3268           0 :     if (aOutClipTransform) {
    3269           0 :       *aOutClipTransform = compensation;
    3270             :     }
    3271             :   }
    3272           0 :   transform = transform * compensation;
    3273             : 
    3274           0 :   return transform;
    3275             : }
    3276             : 
    3277             : APZSampler*
    3278          16 : APZCTreeManager::GetSampler() const
    3279             : {
    3280             :   // We should always have a sampler here, since in practice the sampler
    3281             :   // is destroyed at the same time that this APZCTreeMAnager instance is.
    3282          16 :   MOZ_ASSERT(mSampler);
    3283          16 :   return mSampler;
    3284             : }
    3285             : 
    3286             : void
    3287           0 : APZCTreeManager::AssertOnSamplerThread()
    3288             : {
    3289          16 :   GetSampler()->AssertOnSamplerThread();
    3290          16 : }
    3291             : 
    3292             : APZUpdater*
    3293          18 : APZCTreeManager::GetUpdater() const
    3294             : {
    3295             :   // We should always have an updater here, since in practice the updater
    3296             :   // is destroyed at the same time that this APZCTreeManager instance is.
    3297          18 :   MOZ_ASSERT(mUpdater);
    3298          18 :   return mUpdater;
    3299             : }
    3300             : 
    3301             : void
    3302           0 : APZCTreeManager::AssertOnUpdaterThread()
    3303             : {
    3304          16 :   GetUpdater()->AssertOnUpdaterThread();
    3305          16 : }
    3306             : 
    3307             : void
    3308           0 : APZCTreeManager::LockTree()
    3309             : {
    3310           0 :   AssertOnUpdaterThread();
    3311           0 :   mTreeLock.Lock();
    3312           0 : }
    3313             : 
    3314             : void
    3315           0 : APZCTreeManager::UnlockTree()
    3316             : {
    3317           0 :   AssertOnUpdaterThread();
    3318           0 :   mTreeLock.Unlock();
    3319           0 : }
    3320             : 
    3321             : void
    3322           0 : APZCTreeManager::SetDPI(float aDpiValue)
    3323             : {
    3324           0 :   APZThreadUtils::AssertOnControllerThread();
    3325           1 :   mDPI = aDpiValue;
    3326           1 : }
    3327             : 
    3328             : float
    3329           0 : APZCTreeManager::GetDPI() const
    3330             : {
    3331             :   APZThreadUtils::AssertOnControllerThread();
    3332             :   return mDPI;
    3333             : }
    3334             : 
    3335             : #if defined(MOZ_WIDGET_ANDROID)
    3336             : AndroidDynamicToolbarAnimator*
    3337             : APZCTreeManager::GetAndroidDynamicToolbarAnimator()
    3338             : {
    3339             :   return mToolbarAnimator;
    3340             : }
    3341             : #endif // defined(MOZ_WIDGET_ANDROID)
    3342             : 
    3343             : } // namespace layers
    3344             : } // namespace mozilla

Generated by: LCOV version 1.13-14-ga5dd952