LCOV - code coverage report
Current view: top level - gfx/layers/apz/src - APZCTreeManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 370 1036 35.7 %
Date: 2017-07-14 16:53:18 Functions: 39 112 34.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include <stack>
       7             : #include <unordered_set>
       8             : #include "APZCTreeManager.h"
       9             : #include "AsyncPanZoomController.h"
      10             : #include "Compositor.h"                 // for Compositor
      11             : #include "DragTracker.h"                // for DragTracker
      12             : #include "gfxPrefs.h"                   // for gfxPrefs
      13             : #include "HitTestingTreeNode.h"         // for HitTestingTreeNode
      14             : #include "InputBlockState.h"            // for InputBlockState
      15             : #include "InputData.h"                  // for InputData, etc
      16             : #include "Layers.h"                     // for Layer, etc
      17             : #include "mozilla/dom/Touch.h"          // for Touch
      18             : #include "mozilla/gfx/GPUParent.h"      // for GPUParent
      19             : #include "mozilla/gfx/Logging.h"        // for gfx::TreeLog
      20             : #include "mozilla/gfx/Point.h"          // for Point
      21             : #include "mozilla/layers/APZThreadUtils.h"  // for AssertOnCompositorThread, etc
      22             : #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
      23             : #include "mozilla/layers/AsyncDragMetrics.h" // for AsyncDragMetrics
      24             : #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent, etc
      25             : #include "mozilla/layers/FocusState.h"  // for FocusState
      26             : #include "mozilla/layers/LayerMetricsWrapper.h"
      27             : #include "mozilla/layers/WebRenderScrollDataWrapper.h"
      28             : #include "mozilla/MouseEvents.h"
      29             : #include "mozilla/mozalloc.h"           // for operator new
      30             : #include "mozilla/TouchEvents.h"
      31             : #include "mozilla/Preferences.h"        // for Preferences
      32             : #include "mozilla/EventStateManager.h"  // for WheelPrefs
      33             : #include "mozilla/webrender/WebRenderAPI.h"
      34             : #include "nsDebug.h"                    // for NS_WARNING
      35             : #include "nsPoint.h"                    // for nsIntPoint
      36             : #include "nsThreadUtils.h"              // for NS_IsMainThread
      37             : #include "OverscrollHandoffState.h"     // for OverscrollHandoffState
      38             : #include "TreeTraversal.h"              // for ForEachNode, BreadthFirstSearch, etc
      39             : #include "LayersLogging.h"              // for Stringify
      40             : #include "Units.h"                      // for ParentlayerPixel
      41             : #include "GestureEventListener.h"       // for GestureEventListener::setLongTapEnabled
      42             : #include "UnitTransforms.h"             // for ViewAs
      43             : 
      44             : #define ENABLE_APZCTM_LOGGING 0
      45             : // #define ENABLE_APZCTM_LOGGING 1
      46             : 
      47             : #if ENABLE_APZCTM_LOGGING
      48             : #  define APZCTM_LOG(...) printf_stderr("APZCTM: " __VA_ARGS__)
      49             : #else
      50             : #  define APZCTM_LOG(...)
      51             : #endif
      52             : 
      53             : // #define APZ_KEY_LOG(...) printf_stderr("APZKEY: " __VA_ARGS__)
      54             : #define APZ_KEY_LOG(...)
      55             : 
      56             : namespace mozilla {
      57             : namespace layers {
      58             : 
      59             : typedef mozilla::gfx::Point Point;
      60             : typedef mozilla::gfx::Point4D Point4D;
      61             : typedef mozilla::gfx::Matrix4x4 Matrix4x4;
      62             : 
      63             : typedef CompositorBridgeParent::LayerTreeState LayerTreeState;
      64             : 
      65             : float APZCTreeManager::sDPI = 160.0;
      66             : 
      67          28 : struct APZCTreeManager::TreeBuildingState {
      68          28 :   TreeBuildingState(const LayerTreeState* const aLayerTreeState,
      69             :                     bool aIsFirstPaint, uint64_t aOriginatingLayersId,
      70             :                     APZTestData* aTestData, uint32_t aPaintSequence)
      71          28 :     : mLayerTreeState(aLayerTreeState)
      72             :     , mIsFirstPaint(aIsFirstPaint)
      73             :     , mOriginatingLayersId(aOriginatingLayersId)
      74          28 :     , mPaintLogger(aTestData, aPaintSequence)
      75             :   {
      76          28 :   }
      77             : 
      78             :   // State that doesn't change as we recurse in the tree building
      79             :   const LayerTreeState* const mLayerTreeState;
      80             :   const bool mIsFirstPaint;
      81             :   const uint64_t mOriginatingLayersId;
      82             :   const APZPaintLogHelper mPaintLogger;
      83             : 
      84             :   // State that is updated as we perform the tree build
      85             : 
      86             :   // A list of nodes that need to be destroyed at the end of the tree building.
      87             :   // This is initialized with all nodes in the old tree, and nodes are removed
      88             :   // from it as we reuse them in the new tree.
      89             :   nsTArray<RefPtr<HitTestingTreeNode>> mNodesToDestroy;
      90             :   // A set of layer trees that are no longer in the hit testing tree. This is
      91             :   // used to destroy unneeded focus targets at the end of tree building. This
      92             :   // is needed in addition to mNodesToDestroy because a hit testing node for a
      93             :   // layer tree can be removed without the whole layer tree being removed.
      94             :   std::unordered_set<uint64_t> mLayersIdsToDestroy;
      95             : 
      96             :   // This map is populated as we place APZCs into the new tree. Its purpose is
      97             :   // to facilitate re-using the same APZC for different layers that scroll
      98             :   // together (and thus have the same ScrollableLayerGuid).
      99             :   std::unordered_map<ScrollableLayerGuid, AsyncPanZoomController*, ScrollableLayerGuidHash> mApzcMap;
     100             : };
     101             : 
     102             : class APZCTreeManager::CheckerboardFlushObserver : public nsIObserver {
     103             : public:
     104             :   NS_DECL_ISUPPORTS
     105             :   NS_DECL_NSIOBSERVER
     106             : 
     107           1 :   explicit CheckerboardFlushObserver(APZCTreeManager* aTreeManager)
     108           1 :     : mTreeManager(aTreeManager)
     109             :   {
     110           1 :     MOZ_ASSERT(NS_IsMainThread());
     111           2 :     nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
     112           1 :     MOZ_ASSERT(obsSvc);
     113           1 :     if (obsSvc) {
     114           1 :       obsSvc->AddObserver(this, "APZ:FlushActiveCheckerboard", false);
     115             :     }
     116           1 :   }
     117             : 
     118           0 :   void Unregister()
     119             :   {
     120           0 :     MOZ_ASSERT(NS_IsMainThread());
     121           0 :     nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
     122           0 :     if (obsSvc) {
     123           0 :       obsSvc->RemoveObserver(this, "APZ:FlushActiveCheckerboard");
     124             :     }
     125           0 :     mTreeManager = nullptr;
     126           0 :   }
     127             : 
     128             : protected:
     129           0 :   virtual ~CheckerboardFlushObserver() {}
     130             : 
     131             : private:
     132             :   RefPtr<APZCTreeManager> mTreeManager;
     133             : };
     134             : 
     135           2 : NS_IMPL_ISUPPORTS(APZCTreeManager::CheckerboardFlushObserver, nsIObserver)
     136             : 
     137             : NS_IMETHODIMP
     138           0 : APZCTreeManager::CheckerboardFlushObserver::Observe(nsISupports* aSubject,
     139             :                                                     const char* aTopic,
     140             :                                                     const char16_t*)
     141             : {
     142           0 :   MOZ_ASSERT(NS_IsMainThread());
     143           0 :   MOZ_ASSERT(mTreeManager.get());
     144             : 
     145           0 :   MutexAutoLock lock(mTreeManager->mTreeLock);
     146           0 :   if (mTreeManager->mRootNode) {
     147           0 :     ForEachNode<ReverseIterator>(mTreeManager->mRootNode.get(),
     148           0 :         [](HitTestingTreeNode* aNode)
     149             :         {
     150           0 :           if (aNode->IsPrimaryHolder()) {
     151           0 :             MOZ_ASSERT(aNode->GetApzc());
     152           0 :             aNode->GetApzc()->FlushActiveCheckerboardReport();
     153             :           }
     154           0 :         });
     155             :   }
     156           0 :   if (XRE_IsGPUProcess()) {
     157           0 :     if (gfx::GPUParent* gpu = gfx::GPUParent::GetSingleton()) {
     158           0 :       nsCString topic("APZ:FlushActiveCheckerboard:Done");
     159           0 :       Unused << gpu->SendNotifyUiObservers(topic);
     160             :     }
     161             :   } else {
     162           0 :     MOZ_ASSERT(XRE_IsParentProcess());
     163           0 :     nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
     164           0 :     if (obsSvc) {
     165           0 :       obsSvc->NotifyObservers(nullptr, "APZ:FlushActiveCheckerboard:Done", nullptr);
     166             :     }
     167             :   }
     168           0 :   return NS_OK;
     169             : }
     170             : 
     171             : /**
     172             :  * A RAII class used for setting the focus sequence number on input events
     173             :  * as they are being processed. Any input event is assumed to be potentially
     174             :  * focus changing unless explicitly marked otherwise.
     175             :  */
     176             : class MOZ_RAII AutoFocusSequenceNumberSetter
     177             : {
     178             : public:
     179           4 :   AutoFocusSequenceNumberSetter(FocusState& aFocusState, InputData& aEvent)
     180           4 :     : mFocusState(aFocusState)
     181             :     , mEvent(aEvent)
     182           4 :     , mMayChangeFocus(true)
     183           4 :   { }
     184             : 
     185           0 :   void MarkAsNonFocusChanging() { mMayChangeFocus = false; }
     186             : 
     187           4 :   ~AutoFocusSequenceNumberSetter()
     188           4 :   {
     189           4 :     if (mMayChangeFocus) {
     190           4 :       mFocusState.ReceiveFocusChangingEvent();
     191             : 
     192             :       APZ_KEY_LOG("Marking input with type=%d as focus changing with seq=%" PRIu64 "\n",
     193             :                   (int)mEvent.mInputType,
     194             :                   mFocusState.LastAPZProcessedEvent());
     195             :     } else {
     196             :       APZ_KEY_LOG("Marking input with type=%d as non focus changing with seq=%" PRIu64 "\n",
     197             :                   (int)mEvent.mInputType,
     198             :                   mFocusState.LastAPZProcessedEvent());
     199             :     }
     200             : 
     201           4 :     mEvent.mFocusSequenceNumber = mFocusState.LastAPZProcessedEvent();
     202           4 :   }
     203             : 
     204             : private:
     205             :   FocusState& mFocusState;
     206             :   InputData& mEvent;
     207             :   bool mMayChangeFocus;
     208             : };
     209             : 
     210             : /*static*/ const ScreenMargin
     211           0 : APZCTreeManager::CalculatePendingDisplayPort(
     212             :   const FrameMetrics& aFrameMetrics,
     213             :   const ParentLayerPoint& aVelocity)
     214             : {
     215             :   return AsyncPanZoomController::CalculatePendingDisplayPort(
     216           0 :     aFrameMetrics, aVelocity);
     217             : }
     218             : 
     219           1 : APZCTreeManager::APZCTreeManager()
     220           1 :     : mInputQueue(new InputQueue()),
     221             :       mTreeLock("APZCTreeLock"),
     222             :       mHitResultForInputBlock(HitNothing),
     223             :       mRetainedTouchIdentifier(-1),
     224           2 :       mApzcTreeLog("apzctree")
     225             : {
     226           2 :   RefPtr<APZCTreeManager> self(this);
     227           2 :   NS_DispatchToMainThread(
     228           6 :     NS_NewRunnableFunction("layers::APZCTreeManager::APZCTreeManager", [self] {
     229           2 :       self->mFlushObserver = new CheckerboardFlushObserver(self);
     230           2 :     }));
     231           1 :   AsyncPanZoomController::InitializeGlobalState();
     232           1 :   mApzcTreeLog.ConditionOnPrefFunction(gfxPrefs::APZPrintTree);
     233             : #if defined(MOZ_WIDGET_ANDROID)
     234             :   mToolbarAnimator = new AndroidDynamicToolbarAnimator();
     235             : #endif // (MOZ_WIDGET_ANDROID)
     236           1 : }
     237             : 
     238           0 : APZCTreeManager::~APZCTreeManager()
     239             : {
     240           0 : }
     241             : 
     242             : /*static*/ void
     243           0 : APZCTreeManager::InitializeGlobalState()
     244             : {
     245           0 :   MOZ_ASSERT(NS_IsMainThread());
     246           0 :   AsyncPanZoomController::InitializeGlobalState();
     247           0 : }
     248             : 
     249             : AsyncPanZoomController*
     250           2 : APZCTreeManager::NewAPZCInstance(uint64_t aLayersId,
     251             :                                  GeckoContentController* aController)
     252             : {
     253             :   return new AsyncPanZoomController(aLayersId, this, mInputQueue,
     254           2 :     aController, AsyncPanZoomController::USE_GESTURE_DETECTOR);
     255             : }
     256             : 
     257             : TimeStamp
     258           4 : APZCTreeManager::GetFrameTime()
     259             : {
     260           4 :   return TimeStamp::Now();
     261             : }
     262             : 
     263             : void
     264           0 : APZCTreeManager::SetAllowedTouchBehavior(uint64_t aInputBlockId,
     265             :                                          const nsTArray<TouchBehaviorFlags> &aValues)
     266             : {
     267           0 :   mInputQueue->SetAllowedTouchBehavior(aInputBlockId, aValues);
     268           0 : }
     269             : 
     270             : template<class ScrollNode> void // ScrollNode is a LayerMetricsWrapper or a WebRenderScrollDataWrapper
     271          28 : APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
     272             :                                           const ScrollNode& aRoot,
     273             :                                           bool aIsFirstPaint,
     274             :                                           uint64_t aOriginatingLayersId,
     275             :                                           uint32_t aPaintSequenceNumber)
     276             : {
     277          28 :   APZThreadUtils::AssertOnCompositorThread();
     278             : 
     279          56 :   MutexAutoLock lock(mTreeLock);
     280             : 
     281             :   // For testing purposes, we log some data to the APZTestData associated with
     282             :   // the layers id that originated this update.
     283          28 :   APZTestData* testData = nullptr;
     284          28 :   if (gfxPrefs::APZTestLoggingEnabled()) {
     285           0 :     if (LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(aOriginatingLayersId)) {
     286           0 :       testData = &state->mApzTestData;
     287           0 :       testData->StartNewPaint(aPaintSequenceNumber);
     288             :     }
     289             :   }
     290             : 
     291             :   const LayerTreeState* treeState =
     292          28 :     CompositorBridgeParent::GetIndirectShadowTree(aRootLayerTreeId);
     293          28 :   MOZ_ASSERT(treeState);
     294             :   TreeBuildingState state(treeState, aIsFirstPaint, aOriginatingLayersId,
     295          56 :                           testData, aPaintSequenceNumber);
     296             : 
     297             :   // We do this business with collecting the entire tree into an array because otherwise
     298             :   // it's very hard to determine which APZC instances need to be destroyed. In the worst
     299             :   // case, there are two scenarios: (a) a layer with an APZC is removed from the layer
     300             :   // tree and (b) a layer with an APZC is moved in the layer tree from one place to a
     301             :   // completely different place. In scenario (a) we would want to destroy the APZC while
     302             :   // walking the layer tree and noticing that the layer/APZC is no longer there. But if
     303             :   // we do that then we run into a problem in scenario (b) because we might encounter that
     304             :   // layer later during the walk. To handle both of these we have to 'remember' that the
     305             :   // layer was not found, and then do the destroy only at the end of the tree walk after
     306             :   // we are sure that the layer was removed and not just transplanted elsewhere. Doing that
     307             :   // as part of a recursive tree walk is hard and so maintaining a list and removing
     308             :   // APZCs that are still alive is much simpler.
     309          28 :   ForEachNode<ReverseIterator>(mRootNode.get(),
     310         204 :       [&state] (HitTestingTreeNode* aNode)
     311         204 :       {
     312         204 :         state.mNodesToDestroy.AppendElement(aNode);
     313         204 :       });
     314          28 :   state.mLayersIdsToDestroy = mFocusState.GetFocusTargetLayerIds();
     315          28 :   mRootNode = nullptr;
     316             : 
     317          28 :   if (aRoot) {
     318          56 :     std::stack<gfx::TreeAutoIndent> indents;
     319          56 :     std::stack<gfx::Matrix4x4> ancestorTransforms;
     320          28 :     HitTestingTreeNode* parent = nullptr;
     321          28 :     HitTestingTreeNode* next = nullptr;
     322          28 :     uint64_t layersId = aRootLayerTreeId;
     323          28 :     ancestorTransforms.push(Matrix4x4());
     324             : 
     325          28 :     state.mLayersIdsToDestroy.erase(aRootLayerTreeId);
     326             : 
     327          28 :     mApzcTreeLog << "[start]\n";
     328          28 :     mTreeLock.AssertCurrentThreadOwns();
     329             : 
     330          28 :     ForEachNode<ReverseIterator>(aRoot,
     331         211 :         [&](ScrollNode aLayerMetrics)
     332             :         {
     333         844 :           mApzcTreeLog << aLayerMetrics.Name() << '\t';
     334             : 
     335             :           HitTestingTreeNode* node = PrepareNodeForLayer(aLayerMetrics,
     336         650 :                 aLayerMetrics.Metrics(), layersId, ancestorTransforms.top(),
     337        1083 :                 parent, next, state);
     338         211 :           MOZ_ASSERT(node);
     339         211 :           AsyncPanZoomController* apzc = node->GetApzc();
     340         211 :           aLayerMetrics.SetApzc(apzc);
     341             : 
     342         422 :           mApzcTreeLog << '\n';
     343             : 
     344             :           // Accumulate the CSS transform between layers that have an APZC.
     345             :           // In the terminology of the big comment above APZCTreeManager::GetScreenToApzcTransform, if
     346             :           // we are at layer M, then aAncestorTransform is NC * OC * PC, and we left-multiply MC and
     347             :           // compute ancestorTransform to be MC * NC * OC * PC. This gets passed down as the ancestor
     348             :           // transform to layer L when we recurse into the children below. If we are at a layer
     349             :           // with an APZC, such as P, then we reset the ancestorTransform to just PC, to start
     350             :           // the new accumulation as we go down.
     351             :           // If a transform is a perspective transform, it's ignored for this purpose
     352             :           // (see bug 1168263).
     353         211 :           Matrix4x4 currentTransform = aLayerMetrics.TransformIsPerspective() ? Matrix4x4() : aLayerMetrics.GetTransform();
     354         211 :           if (!apzc) {
     355         172 :             currentTransform = currentTransform * ancestorTransforms.top();
     356             :           }
     357         211 :           ancestorTransforms.push(currentTransform);
     358             : 
     359             :           // Note that |node| at this point will not have any children, otherwise we
     360             :           // we would have to set next to node->GetFirstChild().
     361         211 :           MOZ_ASSERT(!node->GetFirstChild());
     362         211 :           parent = node;
     363         211 :           next = nullptr;
     364             : 
     365             :           // Update the layersId if we have a new one
     366         422 :           if (Maybe<uint64_t> newLayersId = aLayerMetrics.GetReferentId()) {
     367          28 :             layersId = *newLayersId;
     368             : 
     369             :             // Mark that this layer tree is being used
     370          28 :             state.mLayersIdsToDestroy.erase(layersId);
     371             :           }
     372             : 
     373         211 :           indents.push(gfx::TreeAutoIndent(mApzcTreeLog));
     374         211 :         },
     375         211 :         [&](ScrollNode aLayerMetrics)
     376             :         {
     377         422 :           next = parent;
     378         211 :           parent = parent->GetParent();
     379         422 :           layersId = next->GetLayersId();
     380         211 :           ancestorTransforms.pop();
     381         211 :           indents.pop();
     382         211 :         });
     383             : 
     384          28 :     mApzcTreeLog << "[end]\n";
     385             :   }
     386             : 
     387             :   // We do not support tree structures where the root node has siblings.
     388          28 :   MOZ_ASSERT(!(mRootNode && mRootNode->GetPrevSibling()));
     389             : 
     390          34 :   for (size_t i = 0; i < state.mNodesToDestroy.Length(); i++) {
     391             :     APZCTM_LOG("Destroying node at %p with APZC %p\n",
     392             :         state.mNodesToDestroy[i].get(),
     393             :         state.mNodesToDestroy[i]->GetApzc());
     394           6 :     state.mNodesToDestroy[i]->Destroy();
     395             :   }
     396             : 
     397             :   // Clear out any focus targets that are no longer needed
     398          28 :   for (auto layersId : state.mLayersIdsToDestroy) {
     399           0 :     mFocusState.RemoveFocusTarget(layersId);
     400             :   }
     401             : 
     402             : #if ENABLE_APZCTM_LOGGING
     403             :   // Make the hit-test tree line up with the layer dump
     404             :   printf_stderr("APZCTreeManager (%p)\n", this);
     405             :   mRootNode->Dump("  ");
     406             : #endif
     407          28 : }
     408             : 
     409             : void
     410          28 : APZCTreeManager::UpdateFocusState(uint64_t aRootLayerTreeId,
     411             :                                   uint64_t aOriginatingLayersId,
     412             :                                   const FocusTarget& aFocusTarget)
     413             : {
     414          28 :   if (!gfxPrefs::APZKeyboardEnabled()) {
     415          28 :     return;
     416             :   }
     417             : 
     418           0 :   mFocusState.Update(aRootLayerTreeId,
     419             :                      aOriginatingLayersId,
     420           0 :                      aFocusTarget);
     421             : }
     422             : 
     423             : void
     424          28 : APZCTreeManager::UpdateHitTestingTree(uint64_t aRootLayerTreeId,
     425             :                                       Layer* aRoot,
     426             :                                       bool aIsFirstPaint,
     427             :                                       uint64_t aOriginatingLayersId,
     428             :                                       uint32_t aPaintSequenceNumber)
     429             : {
     430          28 :   LayerMetricsWrapper root(aRoot);
     431          28 :   UpdateHitTestingTreeImpl(aRootLayerTreeId, root, aIsFirstPaint,
     432          28 :                            aOriginatingLayersId, aPaintSequenceNumber);
     433          28 : }
     434             : 
     435             : void
     436           0 : APZCTreeManager::UpdateHitTestingTree(uint64_t aRootLayerTreeId,
     437             :                                       const WebRenderScrollData& aScrollData,
     438             :                                       bool aIsFirstPaint,
     439             :                                       uint64_t aOriginatingLayersId,
     440             :                                       uint32_t aPaintSequenceNumber)
     441             : {
     442           0 :   WebRenderScrollDataWrapper wrapper(&aScrollData);
     443           0 :   UpdateHitTestingTreeImpl(aRootLayerTreeId, wrapper, aIsFirstPaint,
     444           0 :                            aOriginatingLayersId, aPaintSequenceNumber);
     445           0 : }
     446             : 
     447             : bool
     448           0 : APZCTreeManager::PushStateToWR(wr::WebRenderAPI* aWrApi,
     449             :                                const TimeStamp& aSampleTime,
     450             :                                nsTArray<WrTransformProperty>& aTransformArray)
     451             : {
     452           0 :   APZThreadUtils::AssertOnCompositorThread();
     453           0 :   MOZ_ASSERT(aWrApi);
     454             : 
     455           0 :   MutexAutoLock lock(mTreeLock);
     456             : 
     457             :   // During the first pass through the tree, we build a cache of guid->HTTN so
     458             :   // that we can find the relevant APZC instances quickly in subsequent passes,
     459             :   // such as the one below to generate scrollbar transforms. Without this, perf
     460             :   // could end up being O(n^2) instead of O(n log n) because we'd have to search
     461             :   // the tree to find the corresponding APZC every time we hit a thumb node.
     462           0 :   std::unordered_map<ScrollableLayerGuid, HitTestingTreeNode*, ScrollableLayerGuidHash> httnMap;
     463             : 
     464           0 :   bool activeAnimations = false;
     465           0 :   uint64_t lastLayersId = -1;
     466             :   WrPipelineId lastPipelineId;
     467             : 
     468             :   // We iterate backwards here because the HitTestingTreeNode is optimized
     469             :   // for backwards iteration. The equivalent code in AsyncCompositionManager
     470             :   // iterates forwards, but the direction shouldn't really matter in practice
     471             :   // so we do what's faster. In the future, if we need to start doing the
     472             :   // equivalent of AlignFixedAndStickyLayers here, then the order will become
     473             :   // important and we'll need to take that into consideration.
     474           0 :   ForEachNode<ReverseIterator>(mRootNode.get(),
     475           0 :       [&](HitTestingTreeNode* aNode)
     476             :       {
     477           0 :         if (!aNode->IsPrimaryHolder()) {
     478           0 :           return;
     479             :         }
     480           0 :         AsyncPanZoomController* apzc = aNode->GetApzc();
     481           0 :         MOZ_ASSERT(apzc);
     482             : 
     483           0 :         if (aNode->GetLayersId() != lastLayersId) {
     484             :           // If we walked into or out of a subtree, we need to get the new
     485             :           // pipeline id.
     486           0 :           const LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(aNode->GetLayersId());
     487           0 :           if (!(state && state->mWrBridge)) {
     488             :             // During shutdown we might have layer tree information for stuff
     489             :             // that has already been torn down. In that case just skip over
     490             :             // those layers.
     491           0 :             return;
     492             :           }
     493           0 :           lastPipelineId = state->mWrBridge->PipelineId();
     494           0 :           lastLayersId = aNode->GetLayersId();
     495             :         }
     496             : 
     497             :         // Use a 0 presShellId because when we do a lookup in this map for the
     498             :         // scrollbar below we don't have (or care about) the presShellId.
     499           0 :         ScrollableLayerGuid guid(lastLayersId, 0, apzc->GetGuid().mScrollId);
     500           0 :         httnMap.emplace(guid, aNode);
     501             : 
     502           0 :         ParentLayerPoint layerTranslation = apzc->GetCurrentAsyncTransform(
     503           0 :             AsyncPanZoomController::eForCompositing).mTranslation;
     504             :         // The positive translation means the painted content is supposed to
     505             :         // move down (or to the right), and that corresponds to a reduction in
     506             :         // the scroll offset. Since we are effectively giving WR the async
     507             :         // scroll delta here, we want to negate the translation.
     508           0 :         ParentLayerPoint asyncScrollDelta = -layerTranslation;
     509           0 :         aWrApi->UpdateScrollPosition(lastPipelineId, apzc->GetGuid().mScrollId,
     510           0 :             wr::ToWrPoint(asyncScrollDelta));
     511             : 
     512           0 :         apzc->ReportCheckerboard(aSampleTime);
     513           0 :         activeAnimations |= apzc->AdvanceAnimations(aSampleTime);
     514           0 :       });
     515             : 
     516             :   // Now we iterate over the nodes again, and generate the transforms needed
     517             :   // for scrollbar thumbs. Although we *could* do this as part of the previous
     518             :   // iteration, it's cleaner and more efficient to do it as a separate pass
     519             :   // because now we have a populated httnMap which allows O(log n) lookup here,
     520             :   // resulting in O(n log n) runtime.
     521           0 :   ForEachNode<ReverseIterator>(mRootNode.get(),
     522           0 :       [&](HitTestingTreeNode* aNode)
     523             :       {
     524           0 :         if (!aNode->IsScrollThumbNode()) {
     525           0 :           return;
     526             :         }
     527           0 :         ScrollableLayerGuid guid(aNode->GetLayersId(), 0, aNode->GetScrollTargetId());
     528           0 :         auto it = httnMap.find(guid);
     529           0 :         if (it == httnMap.end()) {
     530             :           // A scrollbar for content which didn't have an APZC. Possibly the
     531             :           // content isn't layerized. Regardless, we can't async-scroll it so
     532             :           // we can skip the async transform on the scrollbar.
     533           0 :           return;
     534             :         }
     535             : 
     536           0 :         HitTestingTreeNode* scrollTargetNode = it->second;
     537           0 :         AsyncPanZoomController* scrollTargetApzc = scrollTargetNode->GetApzc();
     538           0 :         MOZ_ASSERT(scrollTargetApzc);
     539             :         LayerToParentLayerMatrix4x4 transform = scrollTargetApzc->CallWithLastContentPaintMetrics(
     540           0 :             [&](const FrameMetrics& aMetrics) {
     541             :                 return AsyncCompositionManager::ComputeTransformForScrollThumb(
     542           0 :                     aNode->GetTransform() * AsyncTransformMatrix(),
     543           0 :                     scrollTargetNode->GetTransform().ToUnknownMatrix(),
     544           0 :                     scrollTargetApzc,
     545             :                     aMetrics,
     546             :                     aNode->GetScrollThumbData(),
     547           0 :                     scrollTargetNode->IsAncestorOf(aNode),
     548             :                     nullptr);
     549           0 :             });
     550           0 :         aTransformArray.AppendElement(wr::ToWrTransformProperty(
     551           0 :             aNode->GetScrollbarAnimationId(),
     552           0 :             transform));
     553           0 :       });
     554             : 
     555           0 :   return activeAnimations;
     556             : }
     557             : 
     558             : // Compute the clip region to be used for a layer with an APZC. This function
     559             : // is only called for layers which actually have scrollable metrics and an APZC.
     560             : template<class ScrollNode> static ParentLayerIntRegion
     561          39 : ComputeClipRegion(GeckoContentController* aController,
     562             :                   const ScrollNode& aLayer)
     563             : {
     564          39 :   ParentLayerIntRegion clipRegion;
     565          39 :   if (aLayer.GetClipRect()) {
     566          11 :     clipRegion = *aLayer.GetClipRect();
     567             :   } else {
     568             :     // if there is no clip on this layer (which should only happen for the
     569             :     // root scrollable layer in a process, or for some of the LayerMetrics
     570             :     // expansions of a multi-metrics layer), fall back to using the comp
     571             :     // bounds which should be equivalent.
     572          28 :     clipRegion = RoundedToInt(aLayer.Metrics().GetCompositionBounds());
     573             :   }
     574             : 
     575          39 :   return clipRegion;
     576             : }
     577             : 
     578             : template<class ScrollNode> void
     579          39 : APZCTreeManager::PrintAPZCInfo(const ScrollNode& aLayer,
     580             :                                const AsyncPanZoomController* apzc)
     581             : {
     582          39 :   const FrameMetrics& metrics = aLayer.Metrics();
     583          78 :   mApzcTreeLog << "APZC " << apzc->GetGuid()
     584          78 :                << "\tcb=" << metrics.GetCompositionBounds()
     585          78 :                << "\tsr=" << metrics.GetScrollableRect()
     586         117 :                << (aLayer.IsScrollInfoLayer() ? "\tscrollinfo" : "")
     587         117 :                << (apzc->HasScrollgrab() ? "\tscrollgrab" : "") << "\t"
     588          78 :                << aLayer.Metadata().GetContentDescription().get();
     589          39 : }
     590             : 
     591             : void
     592         211 : APZCTreeManager::AttachNodeToTree(HitTestingTreeNode* aNode,
     593             :                                   HitTestingTreeNode* aParent,
     594             :                                   HitTestingTreeNode* aNextSibling)
     595             : {
     596         211 :   if (aNextSibling) {
     597          93 :     aNextSibling->SetPrevSibling(aNode);
     598         118 :   } else if (aParent) {
     599          90 :     aParent->SetLastChild(aNode);
     600             :   } else {
     601          28 :     MOZ_ASSERT(!mRootNode);
     602          28 :     mRootNode = aNode;
     603          28 :     aNode->MakeRoot();
     604             :   }
     605         211 : }
     606             : 
     607             : template<class ScrollNode> static EventRegions
     608         211 : GetEventRegions(const ScrollNode& aLayer)
     609             : {
     610         211 :   if (aLayer.IsScrollInfoLayer()) {
     611           0 :     ParentLayerIntRect compositionBounds(RoundedToInt(aLayer.Metrics().GetCompositionBounds()));
     612           0 :     nsIntRegion hitRegion(compositionBounds.ToUnknownRect());
     613           0 :     EventRegions eventRegions(hitRegion);
     614           0 :     eventRegions.mDispatchToContentHitRegion = eventRegions.mHitRegion;
     615           0 :     return eventRegions;
     616             :   }
     617         211 :   return aLayer.GetEventRegions();
     618             : }
     619             : 
     620             : 
     621             : 
     622             : already_AddRefed<HitTestingTreeNode>
     623         177 : APZCTreeManager::RecycleOrCreateNode(TreeBuildingState& aState,
     624             :                                      AsyncPanZoomController* aApzc,
     625             :                                      uint64_t aLayersId)
     626             : {
     627             :   // Find a node without an APZC and return it. Note that unless the layer tree
     628             :   // actually changes, this loop should generally do an early-return on the
     629             :   // first iteration, so it should be cheap in the common case.
     630         177 :   for (size_t i = 0; i < aState.mNodesToDestroy.Length(); i++) {
     631         166 :     RefPtr<HitTestingTreeNode> node = aState.mNodesToDestroy[i];
     632         166 :     if (!node->IsPrimaryHolder()) {
     633         166 :       aState.mNodesToDestroy.RemoveElement(node);
     634         166 :       node->RecycleWith(aApzc, aLayersId);
     635         166 :       return node.forget();
     636             :     }
     637             :   }
     638          22 :   RefPtr<HitTestingTreeNode> node = new HitTestingTreeNode(aApzc, false, aLayersId);
     639          11 :   return node.forget();
     640             : }
     641             : 
     642             : template<class ScrollNode> static EventRegionsOverride
     643         211 : GetEventRegionsOverride(HitTestingTreeNode* aParent,
     644             :                        const ScrollNode& aLayer)
     645             : {
     646             :   // Make it so that if the flag is set on the layer tree, it automatically
     647             :   // propagates to all the nodes in the corresponding subtree rooted at that
     648             :   // layer in the hit-test tree. This saves having to walk up the tree every
     649             :   // we want to see if a hit-test node is affected by this flag.
     650         211 :   EventRegionsOverride result = aLayer.GetEventRegionsOverride();
     651         211 :   if (aParent) {
     652         183 :     result |= aParent->GetEventRegionsOverride();
     653             :   }
     654         211 :   return result;
     655             : }
     656             : 
     657             : void
     658           0 : APZCTreeManager::StartScrollbarDrag(const ScrollableLayerGuid& aGuid,
     659             :                                     const AsyncDragMetrics& aDragMetrics)
     660             : {
     661             : 
     662           0 :   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
     663           0 :   if (!apzc) {
     664           0 :     NotifyScrollbarDragRejected(aGuid);
     665           0 :     return;
     666             :   }
     667             : 
     668           0 :   uint64_t inputBlockId = aDragMetrics.mDragStartSequenceNumber;
     669           0 :   mInputQueue->ConfirmDragBlock(inputBlockId, apzc, aDragMetrics);
     670             : }
     671             : 
     672             : void
     673           0 : APZCTreeManager::NotifyScrollbarDragRejected(const ScrollableLayerGuid& aGuid) const
     674             : {
     675           0 :   const LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(aGuid.mLayersId);
     676           0 :   MOZ_ASSERT(state && state->mController);
     677           0 :   state->mController->NotifyAsyncScrollbarDragRejected(aGuid.mScrollId);
     678           0 : }
     679             : 
     680             : template<class ScrollNode> HitTestingTreeNode*
     681         211 : APZCTreeManager::PrepareNodeForLayer(const ScrollNode& aLayer,
     682             :                                      const FrameMetrics& aMetrics,
     683             :                                      uint64_t aLayersId,
     684             :                                      const gfx::Matrix4x4& aAncestorTransform,
     685             :                                      HitTestingTreeNode* aParent,
     686             :                                      HitTestingTreeNode* aNextSibling,
     687             :                                      TreeBuildingState& aState)
     688             : {
     689         211 :   mTreeLock.AssertCurrentThreadOwns();
     690             : 
     691         211 :   bool needsApzc = true;
     692         211 :   if (!aMetrics.IsScrollable()) {
     693         172 :     needsApzc = false;
     694             :   }
     695             : 
     696         211 :   const LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
     697         211 :   if (!(state && state->mController.get())) {
     698           0 :     needsApzc = false;
     699             :   }
     700             : 
     701         422 :   RefPtr<HitTestingTreeNode> node = nullptr;
     702         211 :   if (!needsApzc) {
     703             :     // Note: if layer properties must be propagated to nodes, RecvUpdate in
     704             :     // LayerTransactionParent.cpp must ensure that APZ will be notified
     705             :     // when those properties change.
     706         172 :     node = RecycleOrCreateNode(aState, nullptr, aLayersId);
     707         172 :     AttachNodeToTree(node, aParent, aNextSibling);
     708         172 :     node->SetHitTestData(
     709             :         GetEventRegions(aLayer),
     710             :         aLayer.GetVisibleRegion(),
     711             :         aLayer.GetTransformTyped(),
     712         344 :         aLayer.GetClipRect() ? Some(ParentLayerIntRegion(*aLayer.GetClipRect())) : Nothing(),
     713         344 :         GetEventRegionsOverride(aParent, aLayer));
     714         172 :     node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(),
     715             :                            aLayer.GetScrollbarAnimationId(),
     716             :                            aLayer.GetScrollThumbData(),
     717             :                            aLayer.IsScrollbarContainer());
     718         172 :     node->SetFixedPosData(aLayer.GetFixedPositionScrollContainerId());
     719         172 :     return node;
     720             :   }
     721             : 
     722          39 :   AsyncPanZoomController* apzc = nullptr;
     723             :   // If we get here, aLayer is a scrollable layer and somebody
     724             :   // has registered a GeckoContentController for it, so we need to ensure
     725             :   // it has an APZC instance to manage its scrolling.
     726             : 
     727             :   // aState.mApzcMap allows reusing the exact same APZC instance for different layers
     728             :   // with the same FrameMetrics data. This is needed because in some cases content
     729             :   // that is supposed to scroll together is split into multiple layers because of
     730             :   // e.g. non-scrolling content interleaved in z-index order.
     731          78 :   ScrollableLayerGuid guid(aLayersId, aMetrics);
     732          39 :   auto insertResult = aState.mApzcMap.insert(std::make_pair(guid, static_cast<AsyncPanZoomController*>(nullptr)));
     733          39 :   if (!insertResult.second) {
     734           5 :     apzc = insertResult.first->second;
     735           5 :     PrintAPZCInfo(aLayer, apzc);
     736             :   }
     737             :   APZCTM_LOG("Found APZC %p for layer %p with identifiers %" PRId64 " %" PRId64 "\n", apzc, aLayer.GetLayer(), guid.mLayersId, guid.mScrollId);
     738             : 
     739             :   // If we haven't encountered a layer already with the same metrics, then we need to
     740             :   // do the full reuse-or-make-an-APZC algorithm, which is contained inside the block
     741             :   // below.
     742          39 :   if (apzc == nullptr) {
     743          34 :     apzc = aLayer.GetApzc();
     744             : 
     745             :     // If the content represented by the scrollable layer has changed (which may
     746             :     // be possible because of DLBI heuristics) then we don't want to keep using
     747             :     // the same old APZC for the new content. Also, when reparenting a tab into a
     748             :     // new window a layer might get moved to a different layer tree with a
     749             :     // different APZCTreeManager. In these cases we don't want to reuse the same
     750             :     // APZC, so null it out so we run through the code to find another one or
     751             :     // create one.
     752          34 :     if (apzc && (!apzc->Matches(guid) || !apzc->HasTreeManager(this))) {
     753           0 :       apzc = nullptr;
     754             :     }
     755             : 
     756             :     // See if we can find an APZC from the previous tree that matches the
     757             :     // ScrollableLayerGuid from this layer. If there is one, then we know that
     758             :     // the layout of the page changed causing the layer tree to be rebuilt, but
     759             :     // the underlying content for the APZC is still there somewhere. Therefore,
     760             :     // we want to find the APZC instance and continue using it here.
     761             :     //
     762             :     // We particularly want to find the primary-holder node from the previous
     763             :     // tree that matches, because we don't want that node to get destroyed. If
     764             :     // it does get destroyed, then the APZC will get destroyed along with it by
     765             :     // definition, but we want to keep that APZC around in the new tree.
     766             :     // We leave non-primary-holder nodes in the destroy list because we don't
     767             :     // care about those nodes getting destroyed.
     768          40 :     for (size_t i = 0; i < aState.mNodesToDestroy.Length(); i++) {
     769          44 :       RefPtr<HitTestingTreeNode> n = aState.mNodesToDestroy[i];
     770          38 :       if (n->IsPrimaryHolder() && n->GetApzc() && n->GetApzc()->Matches(guid)) {
     771          32 :         node = n;
     772          32 :         if (apzc != nullptr) {
     773             :           // If there is an APZC already then it should match the one from the
     774             :           // old primary-holder node
     775          32 :           MOZ_ASSERT(apzc == node->GetApzc());
     776             :         }
     777          32 :         apzc = node->GetApzc();
     778          32 :         break;
     779             :       }
     780             :     }
     781             : 
     782             :     // The APZC we get off the layer may have been destroyed previously if the
     783             :     // layer was inactive or omitted from the layer tree for whatever reason
     784             :     // from a layers update. If it later comes back it will have a reference to
     785             :     // a destroyed APZC and so we need to throw that out and make a new one.
     786          34 :     bool newApzc = (apzc == nullptr || apzc->IsDestroyed());
     787          34 :     if (newApzc) {
     788           2 :       MOZ_ASSERT(aState.mLayerTreeState);
     789           2 :       apzc = NewAPZCInstance(aLayersId, state->mController);
     790           2 :       apzc->SetCompositorController(aState.mLayerTreeState->GetCompositorController());
     791           2 :       if (state->mCrossProcessParent) {
     792           1 :         apzc->SetMetricsSharingController(state->CrossProcessSharingController());
     793             :       } else {
     794           1 :         apzc->SetMetricsSharingController(aState.mLayerTreeState->InProcessSharingController());
     795             :       }
     796           2 :       MOZ_ASSERT(node == nullptr);
     797           2 :       node = new HitTestingTreeNode(apzc, true, aLayersId);
     798             :     } else {
     799             :       // If we are re-using a node for this layer clear the tree pointers
     800             :       // so that it doesn't continue pointing to nodes that might no longer
     801             :       // be in the tree. These pointers will get reset properly as we continue
     802             :       // building the tree. Also remove it from the set of nodes that are going
     803             :       // to be destroyed, because it's going to remain active.
     804          32 :       aState.mNodesToDestroy.RemoveElement(node);
     805          32 :       node->SetPrevSibling(nullptr);
     806          32 :       node->SetLastChild(nullptr);
     807             :     }
     808             : 
     809             :     APZCTM_LOG("Using APZC %p for layer %p with identifiers %" PRId64 " %" PRId64 "\n", apzc, aLayer.GetLayer(), aLayersId, aMetrics.GetScrollId());
     810             : 
     811          34 :     apzc->NotifyLayersUpdated(aLayer.Metadata(), aState.mIsFirstPaint,
     812          34 :         aLayersId == aState.mOriginatingLayersId);
     813             : 
     814             :     // Since this is the first time we are encountering an APZC with this guid,
     815             :     // the node holding it must be the primary holder. It may be newly-created
     816             :     // or not, depending on whether it went through the newApzc branch above.
     817          34 :     MOZ_ASSERT(node->IsPrimaryHolder() && node->GetApzc() && node->GetApzc()->Matches(guid));
     818             : 
     819          68 :     ParentLayerIntRegion clipRegion = ComputeClipRegion(state->mController, aLayer);
     820          34 :     node->SetHitTestData(
     821             :         GetEventRegions(aLayer),
     822             :         aLayer.GetVisibleRegion(),
     823             :         aLayer.GetTransformTyped(),
     824             :         Some(clipRegion),
     825          68 :         GetEventRegionsOverride(aParent, aLayer));
     826          34 :     apzc->SetAncestorTransform(aAncestorTransform);
     827             : 
     828          34 :     PrintAPZCInfo(aLayer, apzc);
     829             : 
     830             :     // Bind the APZC instance into the tree of APZCs
     831          34 :     AttachNodeToTree(node, aParent, aNextSibling);
     832             : 
     833             :     // For testing, log the parent scroll id of every APZC that has a
     834             :     // parent. This allows test code to reconstruct the APZC tree.
     835             :     // Note that we currently only do this for APZCs in the layer tree
     836             :     // that originated the update, because the only identifying information
     837             :     // we are logging about APZCs is the scroll id, and otherwise we could
     838             :     // confuse APZCs from different layer trees with the same scroll id.
     839          34 :     if (aLayersId == aState.mOriginatingLayersId) {
     840          26 :       if (apzc->HasNoParentWithSameLayersId()) {
     841          26 :         aState.mPaintLogger.LogTestData(aMetrics.GetScrollId(),
     842             :             "hasNoParentWithSameLayersId", true);
     843             :       } else {
     844           0 :         MOZ_ASSERT(apzc->GetParent());
     845           0 :         aState.mPaintLogger.LogTestData(aMetrics.GetScrollId(),
     846           0 :             "parentScrollId", apzc->GetParent()->GetGuid().mScrollId);
     847             :       }
     848          26 :       if (aMetrics.IsRootContent()) {
     849           2 :         aState.mPaintLogger.LogTestData(aMetrics.GetScrollId(),
     850             :             "isRootContent", true);
     851             :       }
     852             :       // Note that the async scroll offset is in ParentLayer pixels
     853          26 :       aState.mPaintLogger.LogTestData(aMetrics.GetScrollId(), "asyncScrollOffset",
     854          52 :           apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting));
     855             :     }
     856             : 
     857          34 :     if (newApzc) {
     858           2 :       auto it = mZoomConstraints.find(guid);
     859           2 :       if (it != mZoomConstraints.end()) {
     860             :         // We have a zoomconstraints for this guid, apply it.
     861           1 :         apzc->UpdateZoomConstraints(it->second);
     862           1 :       } else if (!apzc->HasNoParentWithSameLayersId()) {
     863             :         // This is a sub-APZC, so inherit the zoom constraints from its parent.
     864             :         // This ensures that if e.g. user-scalable=no was specified, none of the
     865             :         // APZCs for that subtree allow double-tap to zoom.
     866           0 :         apzc->UpdateZoomConstraints(apzc->GetParent()->GetZoomConstraints());
     867             :       }
     868             :       // Otherwise, this is the root of a layers id, but we didn't have a saved
     869             :       // zoom constraints. Leave it empty for now.
     870             :     }
     871             : 
     872             :     // Add a guid -> APZC mapping for the newly created APZC.
     873          34 :     insertResult.first->second = apzc;
     874             :   } else {
     875             :     // We already built an APZC earlier in this tree walk, but we have another layer
     876             :     // now that will also be using that APZC. The hit-test region on the APZC needs
     877             :     // to be updated to deal with the new layer's hit region.
     878             : 
     879           5 :     node = RecycleOrCreateNode(aState, apzc, aLayersId);
     880           5 :     AttachNodeToTree(node, aParent, aNextSibling);
     881             : 
     882             :     // Even though different layers associated with a given APZC may be at
     883             :     // different levels in the layer tree (e.g. one being an uncle of another),
     884             :     // we require from Layout that the CSS transforms up to their common
     885             :     // ancestor be roughly the same. There are cases in which the transforms
     886             :     // are not exactly the same, for example if the parent is container layer
     887             :     // for an opacity, and this container layer has a resolution-induced scale
     888             :     // as its base transform and a prescale that is supposed to undo that scale.
     889             :     // Due to floating point inaccuracies those transforms can end up not quite
     890             :     // canceling each other. That's why we're using a fuzzy comparison here
     891             :     // instead of an exact one.
     892           5 :     MOZ_ASSERT(aAncestorTransform.FuzzyEqualsMultiplicative(apzc->GetAncestorTransform()));
     893             : 
     894          10 :     ParentLayerIntRegion clipRegion = ComputeClipRegion(state->mController, aLayer);
     895           5 :     node->SetHitTestData(
     896             :         GetEventRegions(aLayer),
     897             :         aLayer.GetVisibleRegion(),
     898             :         aLayer.GetTransformTyped(),
     899             :         Some(clipRegion),
     900          10 :         GetEventRegionsOverride(aParent, aLayer));
     901             :   }
     902             : 
     903             :   // Note: if layer properties must be propagated to nodes, RecvUpdate in
     904             :   // LayerTransactionParent.cpp must ensure that APZ will be notified
     905             :   // when those properties change.
     906          39 :   node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(),
     907             :                          aLayer.GetScrollbarAnimationId(),
     908             :                          aLayer.GetScrollThumbData(),
     909             :                          aLayer.IsScrollbarContainer());
     910          39 :   node->SetFixedPosData(aLayer.GetFixedPositionScrollContainerId());
     911          39 :   return node;
     912             : }
     913             : 
     914             : template<typename PanGestureOrScrollWheelInput>
     915             : static bool
     916           0 : WillHandleInput(const PanGestureOrScrollWheelInput& aPanInput)
     917             : {
     918           0 :   if (!NS_IsMainThread()) {
     919           0 :     return true;
     920             :   }
     921             : 
     922           0 :   WidgetWheelEvent wheelEvent = aPanInput.ToWidgetWheelEvent(nullptr);
     923           0 :   return IAPZCTreeManager::WillHandleWheelEvent(&wheelEvent);
     924             : }
     925             : 
     926             : void
     927           0 : APZCTreeManager::FlushApzRepaints(uint64_t aLayersId)
     928             : {
     929             :   // Previously, paints were throttled and therefore this method was used to
     930             :   // ensure any pending paints were flushed. Now, paints are flushed
     931             :   // immediately, so it is safe to simply send a notification now.
     932             :   APZCTM_LOG("Flushing repaints for layers id %" PRIu64, aLayersId);
     933             :   const LayerTreeState* state =
     934           0 :     CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
     935           0 :   MOZ_ASSERT(state && state->mController);
     936           0 :   state->mController->DispatchToRepaintThread(
     937           0 :     NewRunnableMethod("layers::GeckoContentController::NotifyFlushComplete",
     938             :                       state->mController,
     939           0 :                       &GeckoContentController::NotifyFlushComplete));
     940           0 : }
     941             : 
     942             : nsEventStatus
     943           4 : APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
     944             :                                    ScrollableLayerGuid* aOutTargetGuid,
     945             :                                    uint64_t* aOutInputBlockId)
     946             : {
     947           4 :   APZThreadUtils::AssertOnControllerThread();
     948             : 
     949             :   // Use a RAII class for updating the focus sequence number of this event
     950           8 :   AutoFocusSequenceNumberSetter focusSetter(mFocusState, aEvent);
     951             : 
     952             : #if defined(MOZ_WIDGET_ANDROID)
     953             :   MOZ_ASSERT(mToolbarAnimator);
     954             :   ScreenPoint scrollOffset;
     955             :   {
     956             :     MutexAutoLock lock(mTreeLock);
     957             :     RefPtr<AsyncPanZoomController> apzc = FindRootContentOrRootApzc();
     958             :     if (apzc) {
     959             :       scrollOffset = ViewAs<ScreenPixel>(apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting),
     960             :                                          PixelCastJustification::ScreenIsParentLayerForRoot);
     961             :     }
     962             :   }
     963             :   nsEventStatus isConsumed = mToolbarAnimator->ReceiveInputEvent(aEvent, scrollOffset);
     964             :   // Check if the mToolbarAnimator consumed the event.
     965             :   if (isConsumed == nsEventStatus_eConsumeNoDefault) {
     966             :     APZCTM_LOG("Dynamic toolbar consumed event");
     967             :     return isConsumed;
     968             :   }
     969             : #endif // (MOZ_WIDGET_ANDROID)
     970             : 
     971             :   // Initialize aOutInputBlockId to a sane value, and then later we overwrite
     972             :   // it if the input event goes into a block.
     973           4 :   if (aOutInputBlockId) {
     974           4 :     *aOutInputBlockId = InputBlockState::NO_BLOCK_ID;
     975             :   }
     976           4 :   nsEventStatus result = nsEventStatus_eIgnore;
     977           4 :   HitTestResult hitResult = HitNothing;
     978           4 :   switch (aEvent.mInputType) {
     979             :     case MULTITOUCH_INPUT: {
     980           0 :       MultiTouchInput& touchInput = aEvent.AsMultiTouchInput();
     981           0 :       result = ProcessTouchInput(touchInput, aOutTargetGuid, aOutInputBlockId);
     982           0 :       break;
     983             :     } case MOUSE_INPUT: {
     984           4 :       MouseInput& mouseInput = aEvent.AsMouseInput();
     985           4 :       mouseInput.mHandledByAPZ = true;
     986             : 
     987           4 :       bool startsDrag = DragTracker::StartsDrag(mouseInput);
     988           4 :       if (startsDrag) {
     989             :         // If this is the start of a drag we need to unambiguously know if it's
     990             :         // going to land on a scrollbar or not. We can't apply an untransform
     991             :         // here without knowing that, so we need to ensure the untransform is
     992             :         // a no-op.
     993           0 :         FlushRepaintsToClearScreenToGeckoTransform();
     994             :       }
     995             : 
     996           4 :       HitTestingTreeNode* hitScrollbarNode = nullptr;
     997           8 :       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(mouseInput.mOrigin,
     998           8 :             &hitResult, &hitScrollbarNode);
     999           4 :       bool hitScrollbar = hitScrollbarNode;
    1000             : 
    1001             :       // When the mouse is outside the window we still want to handle dragging
    1002             :       // but we won't find an APZC. Fallback to root APZC then.
    1003             :       { // scope lock
    1004           8 :         MutexAutoLock lock(mTreeLock);
    1005           4 :         if (!apzc && mRootNode) {
    1006           0 :           apzc = mRootNode->GetApzc();
    1007             :         }
    1008             :       }
    1009             : 
    1010           4 :       if (apzc) {
    1011           4 :         bool targetConfirmed = (hitResult != HitNothing && hitResult != HitDispatchToContentRegion);
    1012           4 :         bool apzDragEnabled = gfxPrefs::APZDragEnabled();
    1013           4 :         if (apzDragEnabled && hitScrollbar) {
    1014             :           // If scrollbar dragging is enabled and we hit a scrollbar, wait
    1015             :           // for the main-thread confirmation because it contains drag metrics
    1016             :           // that we need.
    1017           0 :           targetConfirmed = false;
    1018             :         }
    1019           4 :         result = mInputQueue->ReceiveInputEvent(
    1020             :           apzc, targetConfirmed,
    1021           4 :           mouseInput, aOutInputBlockId);
    1022             : 
    1023             :         // If we're starting an async scrollbar drag
    1024           8 :         if (apzDragEnabled && startsDrag && hitScrollbarNode &&
    1025           0 :             hitScrollbarNode->IsScrollThumbNode() &&
    1026           4 :             hitScrollbarNode->GetScrollThumbData().mIsAsyncDraggable &&
    1027           0 :             mInputQueue->GetCurrentDragBlock()) {
    1028           0 :           DragBlockState* dragBlock = mInputQueue->GetCurrentDragBlock();
    1029           0 :           const ScrollThumbData& thumbData = hitScrollbarNode->GetScrollThumbData();
    1030             : 
    1031             :           // Record the thumb's position at the start of the drag.
    1032             :           // We snap back to this position if, during the drag, the mouse
    1033             :           // gets sufficiently far away from the scrollbar.
    1034           0 :           dragBlock->SetInitialThumbPos(thumbData.mThumbStart);
    1035             : 
    1036             :           // Under some conditions, we can confirm the drag block right away.
    1037             :           // Otherwise, we have to wait for a main-thread confirmation.
    1038           0 :           if (gfxPrefs::APZDragInitiationEnabled() &&
    1039             :               // check that the scrollbar's target scroll frame is layerized
    1040           0 :               hitScrollbarNode->GetScrollTargetId() == apzc->GetGuid().mScrollId &&
    1041           0 :               !apzc->IsScrollInfoLayer()) {
    1042           0 :             uint64_t dragBlockId = dragBlock->GetBlockId();
    1043             :             // AsyncPanZoomController::HandleInputEvent() will call
    1044             :             // TransformToLocal() on the event, but we need its mLocalOrigin now
    1045             :             // to compute a drag start offset for the AsyncDragMetrics.
    1046           0 :             mouseInput.TransformToLocal(apzc->GetTransformToThis());
    1047             :             CSSCoord dragStart = apzc->ConvertScrollbarPoint(
    1048           0 :                 mouseInput.mLocalOrigin, thumbData);
    1049             :             // ConvertScrollbarPoint() got the drag start offset relative to
    1050             :             // the scroll track. Now get it relative to the thumb.
    1051             :             // ScrollThumbData::mThumbStart stores the offset of the thumb
    1052             :             // relative to the scroll track at the time of the last paint.
    1053             :             // Since that paint, the thumb may have acquired an async transform
    1054             :             // due to async scrolling, so look that up and apply it.
    1055           0 :             LayerToParentLayerMatrix4x4 thumbTransform;
    1056             :             {
    1057           0 :               MutexAutoLock lock(mTreeLock);
    1058           0 :               thumbTransform = ComputeTransformForNode(hitScrollbarNode);
    1059             :             }
    1060             :             // Only consider the translation, since we do not support both
    1061             :             // zooming and scrollbar dragging on any platform.
    1062             :             CSSCoord thumbStart = thumbData.mThumbStart
    1063           0 :                                 + ((thumbData.mDirection == ScrollDirection::HORIZONTAL)
    1064           0 :                                    ? thumbTransform._41 : thumbTransform._42);
    1065           0 :             dragStart -= thumbStart;
    1066             : 
    1067             :             // Content can't prevent scrollbar dragging with preventDefault(),
    1068             :             // so we don't need to wait for a content response. It's important
    1069             :             // to do this before calling ConfirmDragBlock() since that can
    1070             :             // potentially process and consume the block.
    1071           0 :             dragBlock->SetContentResponse(false);
    1072             : 
    1073           0 :             mInputQueue->ConfirmDragBlock(
    1074             :                 dragBlockId, apzc,
    1075           0 :                 AsyncDragMetrics(apzc->GetGuid().mScrollId,
    1076           0 :                                  apzc->GetGuid().mPresShellId,
    1077             :                                  dragBlockId,
    1078             :                                  dragStart,
    1079           0 :                                  thumbData.mDirection));
    1080             :           }
    1081             :         }
    1082             : 
    1083           4 :         if (result == nsEventStatus_eConsumeDoDefault) {
    1084             :           // This input event is part of a drag block, so whether or not it is
    1085             :           // directed at a scrollbar depends on whether the drag block started
    1086             :           // on a scrollbar.
    1087           0 :           hitScrollbar = mInputQueue->IsDragOnScrollbar(hitScrollbar);
    1088             :         }
    1089             : 
    1090             :         // Update the out-parameters so they are what the caller expects.
    1091           4 :         apzc->GetGuid(aOutTargetGuid);
    1092             : 
    1093           4 :         if (!hitScrollbar) {
    1094             :           // The input was not targeted at a scrollbar, so we untransform it
    1095             :           // like we do for other content. Scrollbars are "special" because they
    1096             :           // have special handling in AsyncCompositionManager when resolution is
    1097             :           // applied. TODO: we should find a better way to deal with this.
    1098           4 :           ScreenToParentLayerMatrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
    1099           4 :           ParentLayerToScreenMatrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
    1100           4 :           ScreenToScreenMatrix4x4 outTransform = transformToApzc * transformToGecko;
    1101             :           Maybe<ScreenPoint> untransformedRefPoint = UntransformBy(
    1102           8 :             outTransform, mouseInput.mOrigin);
    1103           4 :           if (untransformedRefPoint) {
    1104           4 :             mouseInput.mOrigin = *untransformedRefPoint;
    1105             :           }
    1106             :         } else {
    1107             :           // Likewise, if the input was targeted at a scrollbar, we don't want to
    1108             :           // apply the callback transform in the main thread, so we remove the
    1109             :           // scrollid from the guid. We need to keep the layersId intact so
    1110             :           // that the response from the child process doesn't get discarded.
    1111           0 :           aOutTargetGuid->mScrollId = FrameMetrics::NULL_SCROLL_ID;
    1112             :         }
    1113             :       }
    1114           4 :       break;
    1115             :     } case SCROLLWHEEL_INPUT: {
    1116           0 :       FlushRepaintsToClearScreenToGeckoTransform();
    1117             : 
    1118           0 :       ScrollWheelInput& wheelInput = aEvent.AsScrollWheelInput();
    1119           0 :       wheelInput.mHandledByAPZ = WillHandleInput(wheelInput);
    1120           0 :       if (!wheelInput.mHandledByAPZ) {
    1121           0 :         return result;
    1122             :       }
    1123             : 
    1124           0 :       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(wheelInput.mOrigin,
    1125           0 :                                                             &hitResult);
    1126           0 :       if (apzc) {
    1127           0 :         MOZ_ASSERT(hitResult != HitNothing);
    1128             : 
    1129             :         // For wheel events, the call to ReceiveInputEvent below may result in
    1130             :         // scrolling, which changes the async transform. However, the event we
    1131             :         // want to pass to gecko should be the pre-scroll event coordinates,
    1132             :         // transformed into the gecko space. (pre-scroll because the mouse
    1133             :         // cursor is stationary during wheel scrolling, unlike touchmove
    1134             :         // events). Since we just flushed the pending repaints the transform to
    1135             :         // gecko space should only consist of overscroll-cancelling transforms.
    1136           0 :         ScreenToScreenMatrix4x4 transformToGecko = GetScreenToApzcTransform(apzc)
    1137           0 :                                                  * GetApzcToGeckoTransform(apzc);
    1138             :         Maybe<ScreenPoint> untransformedOrigin = UntransformBy(
    1139           0 :           transformToGecko, wheelInput.mOrigin);
    1140             : 
    1141           0 :         if (!untransformedOrigin) {
    1142           0 :           return result;
    1143             :         }
    1144             : 
    1145           0 :         result = mInputQueue->ReceiveInputEvent(
    1146             :           apzc,
    1147             :           /* aTargetConfirmed = */ hitResult != HitDispatchToContentRegion,
    1148           0 :           wheelInput, aOutInputBlockId);
    1149             : 
    1150             :         // Update the out-parameters so they are what the caller expects.
    1151           0 :         apzc->GetGuid(aOutTargetGuid);
    1152           0 :         wheelInput.mOrigin = *untransformedOrigin;
    1153             :       }
    1154           0 :       break;
    1155             :     } case PANGESTURE_INPUT: {
    1156           0 :       FlushRepaintsToClearScreenToGeckoTransform();
    1157             : 
    1158           0 :       PanGestureInput& panInput = aEvent.AsPanGestureInput();
    1159           0 :       panInput.mHandledByAPZ = WillHandleInput(panInput);
    1160           0 :       if (!panInput.mHandledByAPZ) {
    1161           0 :         return result;
    1162             :       }
    1163             : 
    1164             :       // If/when we enable support for pan inputs off-main-thread, we'll need
    1165             :       // to duplicate this EventStateManager code or something. See the call to
    1166             :       // GetUserPrefsForWheelEvent in IAPZCTreeManager.cpp for why these fields
    1167             :       // are stored separately.
    1168           0 :       MOZ_ASSERT(NS_IsMainThread());
    1169           0 :       WidgetWheelEvent wheelEvent = panInput.ToWidgetWheelEvent(nullptr);
    1170           0 :       EventStateManager::GetUserPrefsForWheelEvent(&wheelEvent,
    1171             :         &panInput.mUserDeltaMultiplierX,
    1172           0 :         &panInput.mUserDeltaMultiplierY);
    1173             : 
    1174           0 :       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(panInput.mPanStartPoint,
    1175           0 :                                                             &hitResult);
    1176           0 :       if (apzc) {
    1177           0 :         MOZ_ASSERT(hitResult != HitNothing);
    1178             : 
    1179             :         // For pan gesture events, the call to ReceiveInputEvent below may result in
    1180             :         // scrolling, which changes the async transform. However, the event we
    1181             :         // want to pass to gecko should be the pre-scroll event coordinates,
    1182             :         // transformed into the gecko space. (pre-scroll because the mouse
    1183             :         // cursor is stationary during pan gesture scrolling, unlike touchmove
    1184             :         // events). Since we just flushed the pending repaints the transform to
    1185             :         // gecko space should only consist of overscroll-cancelling transforms.
    1186           0 :         ScreenToScreenMatrix4x4 transformToGecko = GetScreenToApzcTransform(apzc)
    1187           0 :                                                  * GetApzcToGeckoTransform(apzc);
    1188             :         Maybe<ScreenPoint> untransformedStartPoint = UntransformBy(
    1189           0 :           transformToGecko, panInput.mPanStartPoint);
    1190             :         Maybe<ScreenPoint> untransformedDisplacement = UntransformVector(
    1191           0 :             transformToGecko, panInput.mPanDisplacement, panInput.mPanStartPoint);
    1192             : 
    1193           0 :         if (!untransformedStartPoint || !untransformedDisplacement) {
    1194           0 :           return result;
    1195             :         }
    1196             : 
    1197           0 :         result = mInputQueue->ReceiveInputEvent(
    1198             :             apzc,
    1199             :             /* aTargetConfirmed = */ hitResult != HitDispatchToContentRegion,
    1200           0 :             panInput, aOutInputBlockId);
    1201             : 
    1202             :         // Update the out-parameters so they are what the caller expects.
    1203           0 :         apzc->GetGuid(aOutTargetGuid);
    1204           0 :         panInput.mPanStartPoint = *untransformedStartPoint;
    1205           0 :         panInput.mPanDisplacement = *untransformedDisplacement;
    1206             :       }
    1207           0 :       break;
    1208             :     } case PINCHGESTURE_INPUT: {  // note: no one currently sends these
    1209           0 :       PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput();
    1210           0 :       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(pinchInput.mFocusPoint,
    1211           0 :                                                             &hitResult);
    1212           0 :       if (apzc) {
    1213           0 :         MOZ_ASSERT(hitResult != HitNothing);
    1214             : 
    1215           0 :         ScreenToScreenMatrix4x4 outTransform = GetScreenToApzcTransform(apzc)
    1216           0 :                                              * GetApzcToGeckoTransform(apzc);
    1217             :         Maybe<ScreenPoint> untransformedFocusPoint = UntransformBy(
    1218           0 :           outTransform, pinchInput.mFocusPoint);
    1219             : 
    1220           0 :         if (!untransformedFocusPoint) {
    1221           0 :           return result;
    1222             :         }
    1223             : 
    1224           0 :         result = mInputQueue->ReceiveInputEvent(
    1225             :             apzc,
    1226             :             /* aTargetConfirmed = */ hitResult != HitDispatchToContentRegion,
    1227           0 :             pinchInput, aOutInputBlockId);
    1228             : 
    1229             :         // Update the out-parameters so they are what the caller expects.
    1230           0 :         apzc->GetGuid(aOutTargetGuid);
    1231           0 :         pinchInput.mFocusPoint = *untransformedFocusPoint;
    1232             :       }
    1233           0 :       break;
    1234             :     } case TAPGESTURE_INPUT: {  // note: no one currently sends these
    1235           0 :       TapGestureInput& tapInput = aEvent.AsTapGestureInput();
    1236           0 :       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(tapInput.mPoint,
    1237           0 :                                                             &hitResult);
    1238           0 :       if (apzc) {
    1239           0 :         MOZ_ASSERT(hitResult != HitNothing);
    1240             : 
    1241           0 :         ScreenToScreenMatrix4x4 outTransform = GetScreenToApzcTransform(apzc)
    1242           0 :                                              * GetApzcToGeckoTransform(apzc);
    1243             :         Maybe<ScreenIntPoint> untransformedPoint =
    1244           0 :           UntransformBy(outTransform, tapInput.mPoint);
    1245             : 
    1246           0 :         if (!untransformedPoint) {
    1247           0 :           return result;
    1248             :         }
    1249             : 
    1250           0 :         result = mInputQueue->ReceiveInputEvent(
    1251             :             apzc,
    1252             :             /* aTargetConfirmed = */ hitResult != HitDispatchToContentRegion,
    1253           0 :             tapInput, aOutInputBlockId);
    1254             : 
    1255             :         // Update the out-parameters so they are what the caller expects.
    1256           0 :         apzc->GetGuid(aOutTargetGuid);
    1257           0 :         tapInput.mPoint = *untransformedPoint;
    1258             :       }
    1259           0 :       break;
    1260             :     } case KEYBOARD_INPUT: {
    1261             :       // Disable async keyboard scrolling when accessibility.browsewithcaret is enabled
    1262           0 :       if (!gfxPrefs::APZKeyboardEnabled() ||
    1263           0 :           gfxPrefs::AccessibilityBrowseWithCaret()) {
    1264             :         APZ_KEY_LOG("Skipping key input from invalid prefs\n");
    1265           0 :         return result;
    1266             :       }
    1267             : 
    1268           0 :       KeyboardInput& keyInput = aEvent.AsKeyboardInput();
    1269             : 
    1270             :       // Try and find a matching shortcut for this keyboard input
    1271           0 :       Maybe<KeyboardShortcut> shortcut = mKeyboardMap.FindMatch(keyInput);
    1272             : 
    1273           0 :       if (!shortcut) {
    1274             :         APZ_KEY_LOG("Skipping key input with no shortcut\n");
    1275             : 
    1276             :         // If we don't have a shortcut for this key event, then we can keep our focus
    1277             :         // only if we know there are no key event listeners for this target
    1278           0 :         if (mFocusState.CanIgnoreKeyboardShortcutMisses()) {
    1279           0 :           focusSetter.MarkAsNonFocusChanging();
    1280             :         }
    1281           0 :         return result;
    1282             :       }
    1283             : 
    1284             :       // Check if this shortcut needs to be dispatched to content. Anything matching
    1285             :       // this is assumed to be able to change focus.
    1286           0 :       if (shortcut->mDispatchToContent) {
    1287             :         APZ_KEY_LOG("Skipping key input with dispatch-to-content shortcut\n");
    1288           0 :         return result;
    1289             :       }
    1290             : 
    1291             :       // We know we have an action to execute on whatever is the current focus target
    1292           0 :       const KeyboardScrollAction& action = shortcut->mAction;
    1293             : 
    1294             :       // The current focus target depends on which direction the scroll is to happen
    1295           0 :       Maybe<ScrollableLayerGuid> targetGuid;
    1296           0 :       switch (action.mType)
    1297             :       {
    1298             :         case KeyboardScrollAction::eScrollCharacter: {
    1299           0 :           targetGuid = mFocusState.GetHorizontalTarget();
    1300           0 :           break;
    1301             :         }
    1302             :         case KeyboardScrollAction::eScrollLine:
    1303             :         case KeyboardScrollAction::eScrollPage:
    1304             :         case KeyboardScrollAction::eScrollComplete: {
    1305           0 :           targetGuid = mFocusState.GetVerticalTarget();
    1306           0 :           break;
    1307             :         }
    1308             :       }
    1309             : 
    1310             :       // If we don't have a scroll target then either we have a stale focus target,
    1311             :       // the focused element has event listeners, or the focused element doesn't have a
    1312             :       // layerized scroll frame. In any case we need to dispatch to content.
    1313           0 :       if (!targetGuid) {
    1314             :         APZ_KEY_LOG("Skipping key input with no current focus target\n");
    1315           0 :         return result;
    1316             :       }
    1317             : 
    1318           0 :       RefPtr<AsyncPanZoomController> targetApzc = GetTargetAPZC(targetGuid->mLayersId,
    1319           0 :                                                                 targetGuid->mScrollId);
    1320             : 
    1321           0 :       if (!targetApzc) {
    1322             :         APZ_KEY_LOG("Skipping key input with focus target but no APZC\n");
    1323           0 :         return result;
    1324             :       }
    1325             : 
    1326             :       // Attach the keyboard scroll action to the input event for processing
    1327             :       // by the input queue.
    1328           0 :       keyInput.mAction = action;
    1329             : 
    1330             :       APZ_KEY_LOG("Dispatching key input with apzc=%p\n",
    1331             :                   targetApzc.get());
    1332             : 
    1333             :       // Dispatch the event to the input queue.
    1334           0 :       result = mInputQueue->ReceiveInputEvent(
    1335             :           targetApzc,
    1336             :           /* aTargetConfirmed = */ true,
    1337           0 :           keyInput, aOutInputBlockId);
    1338             : 
    1339             :       // Any keyboard event that is dispatched to the input queue at this point
    1340             :       // should have been consumed
    1341           0 :       MOZ_ASSERT(result == nsEventStatus_eConsumeNoDefault);
    1342             : 
    1343           0 :       keyInput.mHandledByAPZ = true;
    1344           0 :       focusSetter.MarkAsNonFocusChanging();
    1345             : 
    1346           0 :       break;
    1347             :     }
    1348             :   }
    1349           4 :   return result;
    1350             : }
    1351             : 
    1352             : static TouchBehaviorFlags
    1353           0 : ConvertToTouchBehavior(HitTestResult result)
    1354             : {
    1355           0 :   switch (result) {
    1356             :     case HitNothing:
    1357           0 :       return AllowedTouchBehavior::NONE;
    1358             :     case HitLayer:
    1359             :       return AllowedTouchBehavior::VERTICAL_PAN
    1360             :            | AllowedTouchBehavior::HORIZONTAL_PAN
    1361             :            | AllowedTouchBehavior::PINCH_ZOOM
    1362           0 :            | AllowedTouchBehavior::DOUBLE_TAP_ZOOM;
    1363             :     case HitLayerTouchActionNone:
    1364           0 :       return AllowedTouchBehavior::NONE;
    1365             :     case HitLayerTouchActionPanX:
    1366           0 :       return AllowedTouchBehavior::HORIZONTAL_PAN;
    1367             :     case HitLayerTouchActionPanY:
    1368           0 :       return AllowedTouchBehavior::VERTICAL_PAN;
    1369             :     case HitLayerTouchActionPanXY:
    1370             :       return AllowedTouchBehavior::HORIZONTAL_PAN
    1371           0 :            | AllowedTouchBehavior::VERTICAL_PAN;
    1372             :     case HitDispatchToContentRegion:
    1373           0 :       return AllowedTouchBehavior::UNKNOWN;
    1374             :   }
    1375           0 :   MOZ_ASSERT_UNREACHABLE("Invalid value");
    1376             :   return AllowedTouchBehavior::UNKNOWN;
    1377             : }
    1378             : 
    1379             : already_AddRefed<AsyncPanZoomController>
    1380           0 : APZCTreeManager::GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
    1381             :                                         nsTArray<TouchBehaviorFlags>* aOutTouchBehaviors,
    1382             :                                         HitTestResult* aOutHitResult)
    1383             : {
    1384           0 :   RefPtr<AsyncPanZoomController> apzc;
    1385           0 :   if (aEvent.mTouches.Length() == 0) {
    1386           0 :     return apzc.forget();
    1387             :   }
    1388             : 
    1389           0 :   FlushRepaintsToClearScreenToGeckoTransform();
    1390             : 
    1391             :   HitTestResult hitResult;
    1392           0 :   apzc = GetTargetAPZC(aEvent.mTouches[0].mScreenPoint, &hitResult);
    1393           0 :   if (aOutTouchBehaviors) {
    1394           0 :     aOutTouchBehaviors->AppendElement(ConvertToTouchBehavior(hitResult));
    1395             :   }
    1396           0 :   for (size_t i = 1; i < aEvent.mTouches.Length(); i++) {
    1397           0 :     RefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(aEvent.mTouches[i].mScreenPoint, &hitResult);
    1398           0 :     if (aOutTouchBehaviors) {
    1399           0 :       aOutTouchBehaviors->AppendElement(ConvertToTouchBehavior(hitResult));
    1400             :     }
    1401           0 :     apzc = GetMultitouchTarget(apzc, apzc2);
    1402             :     APZCTM_LOG("Using APZC %p as the root APZC for multi-touch\n", apzc.get());
    1403             :   }
    1404             : 
    1405           0 :   if (aOutHitResult) {
    1406             :     // XXX we should probably be combining the hit results from the different
    1407             :     // touch points somehow, instead of just using the last one.
    1408           0 :     *aOutHitResult = hitResult;
    1409             :   }
    1410           0 :   return apzc.forget();
    1411             : }
    1412             : 
    1413             : nsEventStatus
    1414           0 : APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
    1415             :                                    ScrollableLayerGuid* aOutTargetGuid,
    1416             :                                    uint64_t* aOutInputBlockId)
    1417             : {
    1418           0 :   aInput.mHandledByAPZ = true;
    1419           0 :   nsTArray<TouchBehaviorFlags> touchBehaviors;
    1420           0 :   if (aInput.mType == MultiTouchInput::MULTITOUCH_START) {
    1421             :     // If we are panned into overscroll and a second finger goes down,
    1422             :     // ignore that second touch point completely. The touch-start for it is
    1423             :     // dropped completely; subsequent touch events until the touch-end for it
    1424             :     // will have this touch point filtered out.
    1425             :     // (By contrast, if we're in overscroll but not panning, such as after
    1426             :     // putting two fingers down during an overscroll animation, we process the
    1427             :     // second touch and proceed to pinch.)
    1428           0 :     if (mApzcForInputBlock &&
    1429           0 :         mApzcForInputBlock->IsInPanningState() &&
    1430           0 :         BuildOverscrollHandoffChain(mApzcForInputBlock)->HasOverscrolledApzc()) {
    1431           0 :       if (mRetainedTouchIdentifier == -1) {
    1432           0 :         mRetainedTouchIdentifier = mApzcForInputBlock->GetLastTouchIdentifier();
    1433             :       }
    1434           0 :       return nsEventStatus_eConsumeNoDefault;
    1435             :     }
    1436             : 
    1437           0 :     mHitResultForInputBlock = HitNothing;
    1438           0 :     mApzcForInputBlock = GetTouchInputBlockAPZC(aInput, &touchBehaviors, &mHitResultForInputBlock);
    1439           0 :     MOZ_ASSERT(touchBehaviors.Length() == aInput.mTouches.Length());
    1440           0 :     for (size_t i = 0; i < touchBehaviors.Length(); i++) {
    1441             :       APZCTM_LOG("Touch point has allowed behaviours 0x%02x\n", touchBehaviors[i]);
    1442           0 :       if (touchBehaviors[i] == AllowedTouchBehavior::UNKNOWN) {
    1443             :         // If there's any unknown items in the list, throw it out and we'll
    1444             :         // wait for the main thread to send us a notification.
    1445           0 :         touchBehaviors.Clear();
    1446           0 :         break;
    1447             :       }
    1448             :     }
    1449           0 :   } else if (mApzcForInputBlock) {
    1450             :     APZCTM_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get());
    1451             :   }
    1452             : 
    1453             :   // If we receive a touch-cancel, it means all touches are finished, so we
    1454             :   // can stop ignoring any that we were ignoring.
    1455           0 :   if (aInput.mType == MultiTouchInput::MULTITOUCH_CANCEL) {
    1456           0 :     mRetainedTouchIdentifier = -1;
    1457             :   }
    1458             : 
    1459             :   // If we are currently ignoring any touch points, filter them out from the
    1460             :   // set of touch points included in this event. Note that we modify aInput
    1461             :   // itself, so that the touch points are also filtered out when the caller
    1462             :   // passes the event on to content.
    1463           0 :   if (mRetainedTouchIdentifier != -1) {
    1464           0 :     for (size_t j = 0; j < aInput.mTouches.Length(); ++j) {
    1465           0 :       if (aInput.mTouches[j].mIdentifier != mRetainedTouchIdentifier) {
    1466           0 :         aInput.mTouches.RemoveElementAt(j);
    1467           0 :         if (!touchBehaviors.IsEmpty()) {
    1468           0 :           MOZ_ASSERT(touchBehaviors.Length() > j);
    1469           0 :           touchBehaviors.RemoveElementAt(j);
    1470             :         }
    1471           0 :         --j;
    1472             :       }
    1473             :     }
    1474           0 :     if (aInput.mTouches.IsEmpty()) {
    1475           0 :       return nsEventStatus_eConsumeNoDefault;
    1476             :     }
    1477             :   }
    1478             : 
    1479           0 :   nsEventStatus result = nsEventStatus_eIgnore;
    1480           0 :   if (mApzcForInputBlock) {
    1481           0 :     MOZ_ASSERT(mHitResultForInputBlock != HitNothing);
    1482             : 
    1483           0 :     mApzcForInputBlock->GetGuid(aOutTargetGuid);
    1484           0 :     uint64_t inputBlockId = 0;
    1485           0 :     result = mInputQueue->ReceiveInputEvent(mApzcForInputBlock,
    1486           0 :         /* aTargetConfirmed = */ mHitResultForInputBlock != HitDispatchToContentRegion,
    1487           0 :         aInput, &inputBlockId);
    1488           0 :     if (aOutInputBlockId) {
    1489           0 :       *aOutInputBlockId = inputBlockId;
    1490             :     }
    1491           0 :     if (!touchBehaviors.IsEmpty()) {
    1492           0 :       mInputQueue->SetAllowedTouchBehavior(inputBlockId, touchBehaviors);
    1493             :     }
    1494             : 
    1495             :     // For computing the event to pass back to Gecko, use up-to-date transforms
    1496             :     // (i.e. not anything cached in an input block).
    1497             :     // This ensures that transformToApzc and transformToGecko are in sync.
    1498           0 :     ScreenToParentLayerMatrix4x4 transformToApzc = GetScreenToApzcTransform(mApzcForInputBlock);
    1499           0 :     ParentLayerToScreenMatrix4x4 transformToGecko = GetApzcToGeckoTransform(mApzcForInputBlock);
    1500           0 :     ScreenToScreenMatrix4x4 outTransform = transformToApzc * transformToGecko;
    1501             : 
    1502           0 :     for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
    1503           0 :       SingleTouchData& touchData = aInput.mTouches[i];
    1504             :       Maybe<ScreenIntPoint> untransformedScreenPoint = UntransformBy(
    1505           0 :           outTransform, touchData.mScreenPoint);
    1506           0 :       if (!untransformedScreenPoint) {
    1507           0 :         return nsEventStatus_eIgnore;
    1508             :       }
    1509           0 :       touchData.mScreenPoint = *untransformedScreenPoint;
    1510             :     }
    1511             :   }
    1512             : 
    1513           0 :   mTouchCounter.Update(aInput);
    1514             : 
    1515             :   // If it's the end of the touch sequence then clear out variables so we
    1516             :   // don't keep dangling references and leak things.
    1517           0 :   if (mTouchCounter.GetActiveTouchCount() == 0) {
    1518           0 :     mApzcForInputBlock = nullptr;
    1519           0 :     mHitResultForInputBlock = HitNothing;
    1520           0 :     mRetainedTouchIdentifier = -1;
    1521             :   }
    1522             : 
    1523           0 :   return result;
    1524             : }
    1525             : 
    1526             : void
    1527           6 : APZCTreeManager::UpdateWheelTransaction(LayoutDeviceIntPoint aRefPoint,
    1528             :                                         EventMessage aEventMessage)
    1529             : {
    1530           6 :   WheelBlockState* txn = mInputQueue->GetActiveWheelTransaction();
    1531           6 :   if (!txn) {
    1532           6 :     return;
    1533             :   }
    1534             : 
    1535             :   // If the transaction has simply timed out, we don't need to do anything
    1536             :   // else.
    1537           0 :   if (txn->MaybeTimeout(TimeStamp::Now())) {
    1538           0 :     return;
    1539             :   }
    1540             : 
    1541           0 :   switch (aEventMessage) {
    1542             :    case eMouseMove:
    1543             :    case eDragOver: {
    1544             : 
    1545             :     ScreenIntPoint point =
    1546             :      ViewAs<ScreenPixel>(aRefPoint,
    1547           0 :        PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
    1548             : 
    1549           0 :     txn->OnMouseMove(point);
    1550             : 
    1551           0 :     return;
    1552             :    }
    1553             :    case eKeyPress:
    1554             :    case eKeyUp:
    1555             :    case eKeyDown:
    1556             :    case eMouseUp:
    1557             :    case eMouseDown:
    1558             :    case eMouseDoubleClick:
    1559             :    case eMouseAuxClick:
    1560             :    case eMouseClick:
    1561             :    case eContextMenu:
    1562             :    case eDrop:
    1563           0 :      txn->EndTransaction();
    1564           0 :      return;
    1565             :    default:
    1566           0 :      break;
    1567             :   }
    1568             : }
    1569             : 
    1570             : void
    1571           2 : APZCTreeManager::ProcessUnhandledEvent(LayoutDeviceIntPoint* aRefPoint,
    1572             :                                         ScrollableLayerGuid*  aOutTargetGuid,
    1573             :                                         uint64_t*             aOutFocusSequenceNumber)
    1574             : {
    1575             :   // Transform the aRefPoint.
    1576             :   // If the event hits an overscrolled APZC, instruct the caller to ignore it.
    1577           2 :   HitTestResult hitResult = HitNothing;
    1578           2 :   PixelCastJustification LDIsScreen = PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent;
    1579             :   ScreenIntPoint refPointAsScreen =
    1580           2 :     ViewAs<ScreenPixel>(*aRefPoint, LDIsScreen);
    1581           4 :   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(refPointAsScreen, &hitResult);
    1582           2 :   if (apzc) {
    1583           1 :     MOZ_ASSERT(hitResult != HitNothing);
    1584           1 :     apzc->GetGuid(aOutTargetGuid);
    1585           1 :     ScreenToParentLayerMatrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
    1586           1 :     ParentLayerToScreenMatrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
    1587           1 :     ScreenToScreenMatrix4x4 outTransform = transformToApzc * transformToGecko;
    1588             :     Maybe<ScreenIntPoint> untransformedRefPoint =
    1589           2 :       UntransformBy(outTransform, refPointAsScreen);
    1590           1 :     if (untransformedRefPoint) {
    1591             :       *aRefPoint =
    1592           1 :         ViewAs<LayoutDevicePixel>(*untransformedRefPoint, LDIsScreen);
    1593             :     }
    1594             :   }
    1595             : 
    1596             :   // Update the focus sequence number and attach it to the event
    1597           2 :   mFocusState.ReceiveFocusChangingEvent();
    1598           2 :   *aOutFocusSequenceNumber = mFocusState.LastAPZProcessedEvent();
    1599           2 : }
    1600             : 
    1601             : void
    1602           0 : APZCTreeManager::ProcessTouchVelocity(uint32_t aTimestampMs, float aSpeedY)
    1603             : {
    1604           0 :   if (mApzcForInputBlock) {
    1605           0 :     mApzcForInputBlock->HandleTouchVelocity(aTimestampMs, aSpeedY);
    1606             :   }
    1607           0 : }
    1608             : 
    1609             : void
    1610           0 : APZCTreeManager::SetKeyboardMap(const KeyboardMap& aKeyboardMap)
    1611             : {
    1612           0 :   mKeyboardMap = aKeyboardMap;
    1613           0 : }
    1614             : 
    1615             : void
    1616           0 : APZCTreeManager::ZoomToRect(const ScrollableLayerGuid& aGuid,
    1617             :                             const CSSRect& aRect,
    1618             :                             const uint32_t aFlags)
    1619             : {
    1620           0 :   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
    1621           0 :   if (apzc) {
    1622           0 :     apzc->ZoomToRect(aRect, aFlags);
    1623             :   }
    1624           0 : }
    1625             : 
    1626             : void
    1627           0 : APZCTreeManager::ContentReceivedInputBlock(uint64_t aInputBlockId, bool aPreventDefault)
    1628             : {
    1629           0 :   APZThreadUtils::AssertOnControllerThread();
    1630             : 
    1631           0 :   mInputQueue->ContentReceivedInputBlock(aInputBlockId, aPreventDefault);
    1632           0 : }
    1633             : 
    1634             : void
    1635           0 : APZCTreeManager::SetTargetAPZC(uint64_t aInputBlockId,
    1636             :                                const nsTArray<ScrollableLayerGuid>& aTargets)
    1637             : {
    1638           0 :   APZThreadUtils::AssertOnControllerThread();
    1639             : 
    1640           0 :   RefPtr<AsyncPanZoomController> target = nullptr;
    1641           0 :   if (aTargets.Length() > 0) {
    1642           0 :     target = GetTargetAPZC(aTargets[0]);
    1643             :   }
    1644           0 :   for (size_t i = 1; i < aTargets.Length(); i++) {
    1645           0 :     RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aTargets[i]);
    1646           0 :     target = GetMultitouchTarget(target, apzc);
    1647             :   }
    1648           0 :   mInputQueue->SetConfirmedTargetApzc(aInputBlockId, target);
    1649           0 : }
    1650             : 
    1651             : void
    1652           0 : APZCTreeManager::SetTargetAPZC(uint64_t aInputBlockId, const ScrollableLayerGuid& aTarget)
    1653             : {
    1654           0 :   APZThreadUtils::AssertOnControllerThread();
    1655             : 
    1656           0 :   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aTarget);
    1657           0 :   mInputQueue->SetConfirmedTargetApzc(aInputBlockId, apzc);
    1658           0 : }
    1659             : 
    1660             : void
    1661           1 : APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
    1662             :                                        const Maybe<ZoomConstraints>& aConstraints)
    1663             : {
    1664           2 :   MutexAutoLock lock(mTreeLock);
    1665           2 :   RefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, nullptr);
    1666           1 :   MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
    1667             : 
    1668             :   // Propagate the zoom constraints down to the subtree, stopping at APZCs
    1669             :   // which have their own zoom constraints or are in a different layers id.
    1670           1 :   if (aConstraints) {
    1671             :     APZCTM_LOG("Recording constraints %s for guid %s\n",
    1672             :       Stringify(aConstraints.value()).c_str(), Stringify(aGuid).c_str());
    1673           1 :     mZoomConstraints[aGuid] = aConstraints.ref();
    1674             :   } else {
    1675             :     APZCTM_LOG("Removing constraints for guid %s\n", Stringify(aGuid).c_str());
    1676           0 :     mZoomConstraints.erase(aGuid);
    1677             :   }
    1678           1 :   if (node && aConstraints) {
    1679           0 :     ForEachNode<ReverseIterator>(node.get(),
    1680           0 :         [&aConstraints, &node, this](HitTestingTreeNode* aNode)
    1681           0 :         {
    1682           0 :           if (aNode != node) {
    1683           0 :             if (AsyncPanZoomController* childApzc = aNode->GetApzc()) {
    1684             :               // We can have subtrees with their own zoom constraints or separate layers
    1685             :               // id - leave these alone.
    1686           0 :               if (childApzc->HasNoParentWithSameLayersId() ||
    1687           0 :                   this->mZoomConstraints.find(childApzc->GetGuid()) != this->mZoomConstraints.end()) {
    1688           0 :                 return TraversalFlag::Skip;
    1689             :               }
    1690             :             }
    1691             :           }
    1692           0 :           if (aNode->IsPrimaryHolder()) {
    1693           0 :             MOZ_ASSERT(aNode->GetApzc());
    1694           0 :             aNode->GetApzc()->UpdateZoomConstraints(aConstraints.ref());
    1695             :           }
    1696           0 :           return TraversalFlag::Continue;
    1697           0 :         });
    1698             :   }
    1699           1 : }
    1700             : 
    1701             : void
    1702           0 : APZCTreeManager::FlushRepaintsToClearScreenToGeckoTransform()
    1703             : {
    1704             :   // As the name implies, we flush repaint requests for the entire APZ tree in
    1705             :   // order to clear the screen-to-gecko transform (aka the "untransform" applied
    1706             :   // to incoming input events before they can be passed on to Gecko).
    1707             :   //
    1708             :   // The primary reason we do this is to avoid the problem where input events,
    1709             :   // after being untransformed, end up hit-testing differently in Gecko. This
    1710             :   // might happen in cases where the input event lands on content that is async-
    1711             :   // scrolled into view, but Gecko still thinks it is out of view given the
    1712             :   // visible area of a scrollframe.
    1713             :   //
    1714             :   // Another reason we want to clear the untransform is that if our APZ hit-test
    1715             :   // hits a dispatch-to-content region then that's an ambiguous result and we
    1716             :   // need to ask Gecko what actually got hit. In order to do this we need to
    1717             :   // untransform the input event into Gecko space - but to do that we need to
    1718             :   // know which APZC got hit! This leads to a circular dependency; the only way
    1719             :   // to get out of it is to make sure that the untransform for all the possible
    1720             :   // matched APZCs is the same. It is simplest to ensure that by flushing the
    1721             :   // pending repaint requests, which makes all of the untransforms empty (and
    1722             :   // therefore equal).
    1723           0 :   MutexAutoLock lock(mTreeLock);
    1724           0 :   mTreeLock.AssertCurrentThreadOwns();
    1725             : 
    1726           0 :   ForEachNode<ReverseIterator>(mRootNode.get(),
    1727           0 :       [](HitTestingTreeNode* aNode)
    1728             :       {
    1729           0 :         if (aNode->IsPrimaryHolder()) {
    1730           0 :           MOZ_ASSERT(aNode->GetApzc());
    1731           0 :           aNode->GetApzc()->FlushRepaintForNewInputBlock();
    1732             :         }
    1733           0 :       });
    1734           0 : }
    1735             : 
    1736             : void
    1737           0 : APZCTreeManager::CancelAnimation(const ScrollableLayerGuid &aGuid)
    1738             : {
    1739           0 :   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
    1740           0 :   if (apzc) {
    1741           0 :     apzc->CancelAnimation();
    1742             :   }
    1743           0 : }
    1744             : 
    1745             : void
    1746           0 : APZCTreeManager::AdjustScrollForSurfaceShift(const ScreenPoint& aShift)
    1747             : {
    1748           0 :   MutexAutoLock lock(mTreeLock);
    1749           0 :   RefPtr<AsyncPanZoomController> apzc = FindRootContentOrRootApzc();
    1750           0 :   if (apzc) {
    1751           0 :     apzc->AdjustScrollForSurfaceShift(aShift);
    1752             :   }
    1753           0 : }
    1754             : 
    1755             : void
    1756           0 : APZCTreeManager::ClearTree()
    1757             : {
    1758             :   // Ensure that no references to APZCs are alive in any lingering input
    1759             :   // blocks. This breaks cycles from InputBlockState::mTargetApzc back to
    1760             :   // the InputQueue.
    1761           0 :   APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
    1762           0 :     "layers::InputQueue::Clear", mInputQueue, &InputQueue::Clear));
    1763             : 
    1764           0 :   MutexAutoLock lock(mTreeLock);
    1765             : 
    1766             :   // Collect the nodes into a list, and then destroy each one.
    1767             :   // We can't destroy them as we collect them, because ForEachNode()
    1768             :   // does a pre-order traversal of the tree, and Destroy() nulls out
    1769             :   // the fields needed to reach the children of the node.
    1770           0 :   nsTArray<RefPtr<HitTestingTreeNode>> nodesToDestroy;
    1771           0 :   ForEachNode<ReverseIterator>(mRootNode.get(),
    1772           0 :       [&nodesToDestroy](HitTestingTreeNode* aNode)
    1773           0 :       {
    1774           0 :         nodesToDestroy.AppendElement(aNode);
    1775           0 :       });
    1776             : 
    1777           0 :   for (size_t i = 0; i < nodesToDestroy.Length(); i++) {
    1778           0 :     nodesToDestroy[i]->Destroy();
    1779             :   }
    1780           0 :   mRootNode = nullptr;
    1781             : 
    1782           0 :   RefPtr<APZCTreeManager> self(this);
    1783           0 :   NS_DispatchToMainThread(
    1784           0 :     NS_NewRunnableFunction("layers::APZCTreeManager::ClearTree", [self] {
    1785           0 :       self->mFlushObserver->Unregister();
    1786           0 :       self->mFlushObserver = nullptr;
    1787           0 :     }));
    1788           0 : }
    1789             : 
    1790             : RefPtr<HitTestingTreeNode>
    1791           0 : APZCTreeManager::GetRootNode() const
    1792             : {
    1793           0 :   MutexAutoLock lock(mTreeLock);
    1794           0 :   return mRootNode;
    1795             : }
    1796             : 
    1797             : /**
    1798             :  * Transform a displacement from the ParentLayer coordinates of a source APZC
    1799             :  * to the ParentLayer coordinates of a target APZC.
    1800             :  * @param aTreeManager the tree manager for the APZC tree containing |aSource|
    1801             :  *                     and |aTarget|
    1802             :  * @param aSource the source APZC
    1803             :  * @param aTarget the target APZC
    1804             :  * @param aStartPoint the start point of the displacement
    1805             :  * @param aEndPoint the end point of the displacement
    1806             :  * @return true on success, false if aStartPoint or aEndPoint cannot be transformed into target's coordinate space
    1807             :  */
    1808             : static bool
    1809           0 : TransformDisplacement(APZCTreeManager* aTreeManager,
    1810             :                       AsyncPanZoomController* aSource,
    1811             :                       AsyncPanZoomController* aTarget,
    1812             :                       ParentLayerPoint& aStartPoint,
    1813             :                       ParentLayerPoint& aEndPoint) {
    1814           0 :   if (aSource == aTarget) {
    1815           0 :     return true;
    1816             :   }
    1817             : 
    1818             :   // Convert start and end points to Screen coordinates.
    1819           0 :   ParentLayerToScreenMatrix4x4 untransformToApzc = aTreeManager->GetScreenToApzcTransform(aSource).Inverse();
    1820           0 :   ScreenPoint screenStart = TransformBy(untransformToApzc, aStartPoint);
    1821           0 :   ScreenPoint screenEnd = TransformBy(untransformToApzc, aEndPoint);
    1822             : 
    1823             :   // Convert start and end points to aTarget's ParentLayer coordinates.
    1824           0 :   ScreenToParentLayerMatrix4x4 transformToApzc = aTreeManager->GetScreenToApzcTransform(aTarget);
    1825           0 :   Maybe<ParentLayerPoint> startPoint = UntransformBy(transformToApzc, screenStart);
    1826           0 :   Maybe<ParentLayerPoint> endPoint = UntransformBy(transformToApzc, screenEnd);
    1827           0 :   if (!startPoint || !endPoint) {
    1828           0 :     return false;
    1829             :   }
    1830           0 :   aEndPoint = *endPoint;
    1831           0 :   aStartPoint = *startPoint;
    1832             : 
    1833           0 :   return true;
    1834             : }
    1835             : 
    1836             : void
    1837           0 : APZCTreeManager::DispatchScroll(AsyncPanZoomController* aPrev,
    1838             :                                 ParentLayerPoint& aStartPoint,
    1839             :                                 ParentLayerPoint& aEndPoint,
    1840             :                                 OverscrollHandoffState& aOverscrollHandoffState)
    1841             : {
    1842           0 :   const OverscrollHandoffChain& overscrollHandoffChain = aOverscrollHandoffState.mChain;
    1843           0 :   uint32_t overscrollHandoffChainIndex = aOverscrollHandoffState.mChainIndex;
    1844           0 :   RefPtr<AsyncPanZoomController> next;
    1845             :   // If we have reached the end of the overscroll handoff chain, there is
    1846             :   // nothing more to scroll, so we ignore the rest of the pan gesture.
    1847           0 :   if (overscrollHandoffChainIndex >= overscrollHandoffChain.Length()) {
    1848             :     // Nothing more to scroll - ignore the rest of the pan gesture.
    1849           0 :     return;
    1850             :   }
    1851             : 
    1852           0 :   next = overscrollHandoffChain.GetApzcAtIndex(overscrollHandoffChainIndex);
    1853             : 
    1854           0 :   if (next == nullptr || next->IsDestroyed()) {
    1855           0 :     return;
    1856             :   }
    1857             : 
    1858             :   // Convert the start and end points from |aPrev|'s coordinate space to
    1859             :   // |next|'s coordinate space.
    1860           0 :   if (!TransformDisplacement(this, aPrev, next, aStartPoint, aEndPoint)) {
    1861           0 :     return;
    1862             :   }
    1863             : 
    1864             :   // Scroll |next|. If this causes overscroll, it will call DispatchScroll()
    1865             :   // again with an incremented index.
    1866           0 :   if (!next->AttemptScroll(aStartPoint, aEndPoint, aOverscrollHandoffState)) {
    1867             :     // Transform |aStartPoint| and |aEndPoint| (which now represent the
    1868             :     // portion of the displacement that wasn't consumed by APZCs later
    1869             :     // in the handoff chain) back into |aPrev|'s coordinate space. This
    1870             :     // allows the caller (which is |aPrev|) to interpret the unconsumed
    1871             :     // displacement in its own coordinate space, and make use of it
    1872             :     // (e.g. by going into overscroll).
    1873           0 :     if (!TransformDisplacement(this, next, aPrev, aStartPoint, aEndPoint)) {
    1874           0 :       NS_WARNING("Failed to untransform scroll points during dispatch");
    1875             :     }
    1876             :   }
    1877             : }
    1878             : 
    1879             : void
    1880           0 : APZCTreeManager::DispatchFling(AsyncPanZoomController* aPrev,
    1881             :                                FlingHandoffState& aHandoffState)
    1882             : {
    1883             :   // If immediate handoff is disallowed, do not allow handoff beyond the
    1884             :   // single APZC that's scrolled by the input block that triggered this fling.
    1885           0 :   if (aHandoffState.mIsHandoff &&
    1886           0 :       !gfxPrefs::APZAllowImmediateHandoff() &&
    1887           0 :       aHandoffState.mScrolledApzc == aPrev) {
    1888           0 :     return;
    1889             :   }
    1890             : 
    1891           0 :   const OverscrollHandoffChain* chain = aHandoffState.mChain;
    1892           0 :   RefPtr<AsyncPanZoomController> current;
    1893           0 :   uint32_t overscrollHandoffChainLength = chain->Length();
    1894             :   uint32_t startIndex;
    1895             : 
    1896             :   // This will store any velocity left over after the entire handoff.
    1897           0 :   ParentLayerPoint finalResidualVelocity = aHandoffState.mVelocity;
    1898             : 
    1899             :   // The fling's velocity needs to be transformed from the screen coordinates
    1900             :   // of |aPrev| to the screen coordinates of |next|. To transform a velocity
    1901             :   // correctly, we need to convert it to a displacement. For now, we do this
    1902             :   // by anchoring it to a start point of (0, 0).
    1903             :   // TODO: For this to be correct in the presence of 3D transforms, we should
    1904             :   // use the end point of the touch that started the fling as the start point
    1905             :   // rather than (0, 0).
    1906           0 :   ParentLayerPoint startPoint;  // (0, 0)
    1907           0 :   ParentLayerPoint endPoint;
    1908             : 
    1909           0 :   if (aHandoffState.mIsHandoff) {
    1910           0 :     startIndex = chain->IndexOf(aPrev) + 1;
    1911             : 
    1912             :     // IndexOf will return aOverscrollHandoffChain->Length() if
    1913             :     // |aPrev| is not found.
    1914           0 :     if (startIndex >= overscrollHandoffChainLength) {
    1915           0 :       return;
    1916             :     }
    1917             :   } else {
    1918           0 :     startIndex = 0;
    1919             :   }
    1920             : 
    1921           0 :   for (; startIndex < overscrollHandoffChainLength; startIndex++) {
    1922           0 :     current = chain->GetApzcAtIndex(startIndex);
    1923             : 
    1924             :     // Make sure the apcz about to be handled can be handled
    1925           0 :     if (current == nullptr || current->IsDestroyed()) {
    1926           0 :       return;
    1927             :     }
    1928             : 
    1929           0 :     endPoint = startPoint + aHandoffState.mVelocity;
    1930             : 
    1931             :     // Only transform when current apcz can be transformed with previous
    1932           0 :     if (startIndex > 0) {
    1933           0 :       if (!TransformDisplacement(this,
    1934           0 :                                  chain->GetApzcAtIndex(startIndex - 1),
    1935             :                                  current,
    1936             :                                  startPoint,
    1937             :                                  endPoint)) {
    1938           0 :         return;
    1939             :       }
    1940             :     }
    1941             : 
    1942           0 :     ParentLayerPoint transformedVelocity = endPoint - startPoint;
    1943           0 :     aHandoffState.mVelocity = transformedVelocity;
    1944             : 
    1945           0 :     if (current->AttemptFling(aHandoffState)) {
    1946             :       // Coming out of AttemptFling(), the handoff state's velocity is the
    1947             :       // residual velocity after attempting to fling |current|.
    1948           0 :       ParentLayerPoint residualVelocity = aHandoffState.mVelocity;
    1949             : 
    1950             :       // If there's no residual velocity, there's nothing more to hand off.
    1951           0 :       if (IsZero(residualVelocity)) {
    1952           0 :         finalResidualVelocity = ParentLayerPoint();
    1953           0 :         break;
    1954             :       }
    1955             : 
    1956             :       // If there is residual velocity, subtract the proportion of used
    1957             :       // velocity from finalResidualVelocity and continue handoff along the
    1958             :       // chain.
    1959           0 :       if (!FuzzyEqualsAdditive(transformedVelocity.x,
    1960             :                                residualVelocity.x, COORDINATE_EPSILON)) {
    1961           0 :         finalResidualVelocity.x *= (residualVelocity.x / transformedVelocity.x);
    1962             :       }
    1963           0 :       if (!FuzzyEqualsAdditive(transformedVelocity.y,
    1964             :                                residualVelocity.y, COORDINATE_EPSILON)) {
    1965           0 :         finalResidualVelocity.y *= (residualVelocity.y / transformedVelocity.y);
    1966             :       }
    1967             :     }
    1968             :   }
    1969             : 
    1970             :   // Set the handoff state's velocity to any residual velocity left over
    1971             :   // after the entire handoff process.
    1972           0 :   aHandoffState.mVelocity = finalResidualVelocity;
    1973             : }
    1974             : 
    1975             : bool
    1976           0 : APZCTreeManager::HitTestAPZC(const ScreenIntPoint& aPoint)
    1977             : {
    1978           0 :   RefPtr<AsyncPanZoomController> target = GetTargetAPZC(aPoint, nullptr);
    1979           0 :   return target != nullptr;
    1980             : }
    1981             : 
    1982             : already_AddRefed<AsyncPanZoomController>
    1983           0 : APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
    1984             : {
    1985           0 :   MutexAutoLock lock(mTreeLock);
    1986           0 :   RefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, nullptr);
    1987           0 :   MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
    1988           0 :   RefPtr<AsyncPanZoomController> apzc = node ? node->GetApzc() : nullptr;
    1989           0 :   return apzc.forget();
    1990             : }
    1991             : 
    1992             : static bool
    1993           0 : GuidComparatorIgnoringPresShell(const ScrollableLayerGuid& aOne, const ScrollableLayerGuid& aTwo)
    1994             : {
    1995           0 :   return aOne.mLayersId == aTwo.mLayersId
    1996           0 :       && aOne.mScrollId == aTwo.mScrollId;
    1997             : }
    1998             : 
    1999             : already_AddRefed<AsyncPanZoomController>
    2000           0 : APZCTreeManager::GetTargetAPZC(const uint64_t& aLayersId,
    2001             :                                const FrameMetrics::ViewID& aScrollId)
    2002             : {
    2003           0 :   MutexAutoLock lock(mTreeLock);
    2004           0 :   ScrollableLayerGuid guid(aLayersId, 0, aScrollId);
    2005           0 :   RefPtr<HitTestingTreeNode> node = GetTargetNode(guid, &GuidComparatorIgnoringPresShell);
    2006           0 :   MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
    2007           0 :   RefPtr<AsyncPanZoomController> apzc = node ? node->GetApzc() : nullptr;
    2008           0 :   return apzc.forget();
    2009             : }
    2010             : 
    2011             : already_AddRefed<HitTestingTreeNode>
    2012           1 : APZCTreeManager::GetTargetNode(const ScrollableLayerGuid& aGuid,
    2013             :                                GuidComparator aComparator) const
    2014             : {
    2015           1 :   mTreeLock.AssertCurrentThreadOwns();
    2016             :   RefPtr<HitTestingTreeNode> target = DepthFirstSearchPostOrder<ReverseIterator>(mRootNode.get(),
    2017           9 :       [&aGuid, &aComparator](HitTestingTreeNode* node)
    2018           2 :       {
    2019           9 :         bool matches = false;
    2020           9 :         if (node->GetApzc()) {
    2021           1 :           if (aComparator) {
    2022           0 :             matches = aComparator(aGuid, node->GetApzc()->GetGuid());
    2023             :           } else {
    2024           1 :             matches = node->GetApzc()->Matches(aGuid);
    2025             :           }
    2026             :         }
    2027           9 :         return matches;
    2028             :       }
    2029           2 :   );
    2030           2 :   return target.forget();
    2031             : }
    2032             : 
    2033             : already_AddRefed<AsyncPanZoomController>
    2034           6 : APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint,
    2035             :                                HitTestResult* aOutHitResult,
    2036             :                                HitTestingTreeNode** aOutHitScrollbar)
    2037             : {
    2038          12 :   MutexAutoLock lock(mTreeLock);
    2039           6 :   HitTestResult hitResult = HitNothing;
    2040             :   ParentLayerPoint point = ViewAs<ParentLayerPixel>(aPoint,
    2041           6 :     PixelCastJustification::ScreenIsParentLayerForRoot);
    2042             :   RefPtr<AsyncPanZoomController> target = GetAPZCAtPoint(mRootNode, point,
    2043          12 :       &hitResult, aOutHitScrollbar);
    2044             : 
    2045           6 :   if (aOutHitResult) {
    2046           6 :     *aOutHitResult = hitResult;
    2047             :   }
    2048          12 :   return target.forget();
    2049             : }
    2050             : 
    2051             : RefPtr<const OverscrollHandoffChain>
    2052           0 : APZCTreeManager::BuildOverscrollHandoffChain(const RefPtr<AsyncPanZoomController>& aInitialTarget)
    2053             : {
    2054             :   // Scroll grabbing is a mechanism that allows content to specify that
    2055             :   // the initial target of a pan should be not the innermost scrollable
    2056             :   // frame at the touch point (which is what GetTargetAPZC finds), but
    2057             :   // something higher up in the tree.
    2058             :   // It's not sufficient to just find the initial target, however, as
    2059             :   // overscroll can be handed off to another APZC. Without scroll grabbing,
    2060             :   // handoff just occurs from child to parent. With scroll grabbing, the
    2061             :   // handoff order can be different, so we build a chain of APZCs in the
    2062             :   // order in which scroll will be handed off to them.
    2063             : 
    2064             :   // Grab tree lock since we'll be walking the APZC tree.
    2065           0 :   MutexAutoLock lock(mTreeLock);
    2066             : 
    2067             :   // Build the chain. If there is a scroll parent link, we use that. This is
    2068             :   // needed to deal with scroll info layers, because they participate in handoff
    2069             :   // but do not follow the expected layer tree structure. If there are no
    2070             :   // scroll parent links we just walk up the tree to find the scroll parent.
    2071           0 :   OverscrollHandoffChain* result = new OverscrollHandoffChain;
    2072           0 :   AsyncPanZoomController* apzc = aInitialTarget;
    2073           0 :   while (apzc != nullptr) {
    2074           0 :     result->Add(apzc);
    2075             : 
    2076           0 :     if (apzc->GetScrollHandoffParentId() == FrameMetrics::NULL_SCROLL_ID) {
    2077           0 :       if (!apzc->IsRootForLayersId()) {
    2078             :         // This probably indicates a bug or missed case in layout code
    2079           0 :         NS_WARNING("Found a non-root APZ with no handoff parent");
    2080             :       }
    2081           0 :       apzc = apzc->GetParent();
    2082           0 :       continue;
    2083             :     }
    2084             : 
    2085             :     // Guard against a possible infinite-loop condition. If we hit this, the
    2086             :     // layout code that generates the handoff parents did something wrong.
    2087           0 :     MOZ_ASSERT(apzc->GetScrollHandoffParentId() != apzc->GetGuid().mScrollId);
    2088             : 
    2089             :     // Find the AsyncPanZoomController instance with a matching layersId and
    2090             :     // the scroll id that matches apzc->GetScrollHandoffParentId().
    2091             :     // As an optimization, we start by walking up the APZC tree from 'apzc'
    2092             :     // until we reach the top of the layer subtree for this layers id.
    2093           0 :     AsyncPanZoomController* scrollParent = nullptr;
    2094           0 :     AsyncPanZoomController* parent = apzc;
    2095           0 :     while (!parent->HasNoParentWithSameLayersId()) {
    2096           0 :       parent = parent->GetParent();
    2097             :       // While walking up to find the root of the subtree, if we encounter the
    2098             :       // handoff parent, we don't actually need to do the search so we can
    2099             :       // just abort here.
    2100           0 :       if (parent->GetGuid().mScrollId == apzc->GetScrollHandoffParentId()) {
    2101           0 :         scrollParent = parent;
    2102           0 :         break;
    2103             :       }
    2104             :     }
    2105             :     // If that heuristic didn't turn up the scroll parent, do a full tree search.
    2106           0 :     if (!scrollParent) {
    2107           0 :       ScrollableLayerGuid guid(parent->GetGuid().mLayersId, 0, apzc->GetScrollHandoffParentId());
    2108           0 :       RefPtr<HitTestingTreeNode> node = GetTargetNode(guid, &GuidComparatorIgnoringPresShell);
    2109           0 :       MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
    2110           0 :       scrollParent = node ? node->GetApzc() : nullptr;
    2111             :     }
    2112           0 :     apzc = scrollParent;
    2113             :   }
    2114             : 
    2115             :   // Now adjust the chain to account for scroll grabbing. Sorting is a bit
    2116             :   // of an overkill here, but scroll grabbing will likely be generalized
    2117             :   // to scroll priorities, so we might as well do it this way.
    2118           0 :   result->SortByScrollPriority();
    2119             : 
    2120             :   // Print the overscroll chain for debugging.
    2121           0 :   for (uint32_t i = 0; i < result->Length(); ++i) {
    2122             :     APZCTM_LOG("OverscrollHandoffChain[%d] = %p\n", i, result->GetApzcAtIndex(i).get());
    2123             :   }
    2124             : 
    2125           0 :   return result;
    2126             : }
    2127             : 
    2128             : void
    2129           0 : APZCTreeManager::SetLongTapEnabled(bool aLongTapEnabled)
    2130             : {
    2131             :   APZThreadUtils::RunOnControllerThread(
    2132           0 :     NewRunnableFunction(GestureEventListener::SetLongTapEnabled, aLongTapEnabled));
    2133           0 : }
    2134             : 
    2135             : RefPtr<HitTestingTreeNode>
    2136           0 : APZCTreeManager::FindScrollThumbNode(const AsyncDragMetrics& aDragMetrics)
    2137             : {
    2138           0 :   MutexAutoLock lock(mTreeLock);
    2139             : 
    2140             :   return DepthFirstSearch<ReverseIterator>(mRootNode.get(),
    2141           0 :       [&aDragMetrics](HitTestingTreeNode* aNode) {
    2142             :         return aNode->MatchesScrollDragMetrics(aDragMetrics);
    2143           0 :       });
    2144             : }
    2145             : 
    2146             : AsyncPanZoomController*
    2147           5 : APZCTreeManager::GetTargetApzcForNode(HitTestingTreeNode* aNode)
    2148             : {
    2149          20 :   for (const HitTestingTreeNode* n = aNode;
    2150          10 :        n && n->GetLayersId() == aNode->GetLayersId();
    2151             :        n = n->GetParent()) {
    2152          10 :     if (n->GetApzc()) {
    2153             :       APZCTM_LOG("Found target %p using ancestor lookup\n", n->GetApzc());
    2154           5 :       return n->GetApzc();
    2155             :     }
    2156           5 :     if (n->GetFixedPosTarget() != FrameMetrics::NULL_SCROLL_ID) {
    2157           0 :       ScrollableLayerGuid guid(n->GetLayersId(), 0, n->GetFixedPosTarget());
    2158           0 :       RefPtr<HitTestingTreeNode> fpNode = GetTargetNode(guid, &GuidComparatorIgnoringPresShell);
    2159             :       APZCTM_LOG("Found target node %p using fixed-pos lookup on %" PRIu64 "\n", fpNode.get(), n->GetFixedPosTarget());
    2160           0 :       return fpNode ? fpNode->GetApzc() : nullptr;
    2161             :     }
    2162             :   }
    2163           0 :   return nullptr;
    2164             : }
    2165             : 
    2166             : AsyncPanZoomController*
    2167           6 : APZCTreeManager::GetAPZCAtPoint(HitTestingTreeNode* aNode,
    2168             :                                 const ParentLayerPoint& aHitTestPoint,
    2169             :                                 HitTestResult* aOutHitResult,
    2170             :                                 HitTestingTreeNode** aOutScrollbarNode)
    2171             : {
    2172           6 :   mTreeLock.AssertCurrentThreadOwns();
    2173             : 
    2174             :   // This walks the tree in depth-first, reverse order, so that it encounters
    2175             :   // APZCs front-to-back on the screen.
    2176             :   HitTestingTreeNode* resultNode;
    2177           6 :   HitTestingTreeNode* root = aNode;
    2178          12 :   std::stack<LayerPoint> hitTestPoints;
    2179          12 :   hitTestPoints.push(ViewAs<LayerPixel>(aHitTestPoint,
    2180           6 :       PixelCastJustification::MovingDownToChildren));
    2181             : 
    2182          12 :   ForEachNode<ReverseIterator>(root,
    2183          61 :       [&hitTestPoints, this](HitTestingTreeNode* aNode) {
    2184          21 :         ParentLayerPoint hitTestPointForParent = ViewAs<ParentLayerPixel>(hitTestPoints.top(),
    2185          21 :             PixelCastJustification::MovingDownToChildren);
    2186          21 :         if (aNode->IsOutsideClip(hitTestPointForParent)) {
    2187             :           // If the point being tested is outside the clip region for this node
    2188             :           // then we don't need to test against this node or any of its children.
    2189             :           // Just skip it and move on.
    2190             :           APZCTM_LOG("Point %f %f outside clip for node %p\n",
    2191             :             hitTestPoints.top().x, hitTestPoints.top().y, aNode);
    2192           1 :           return TraversalFlag::Skip;
    2193             :         }
    2194             :         // First check the subtree rooted at this node, because deeper nodes
    2195             :         // are more "in front".
    2196             :         Maybe<LayerPoint> hitTestPoint = aNode->Untransform(
    2197          40 :             hitTestPointForParent, ComputeTransformForNode(aNode));
    2198             :         APZCTM_LOG("Transformed ParentLayer point %s to layer %s\n",
    2199             :                 Stringify(hitTestPointForParent).c_str(),
    2200             :                 hitTestPoint ? Stringify(hitTestPoint.ref()).c_str() : "nil");
    2201          20 :         if (!hitTestPoint) {
    2202           0 :           return TraversalFlag::Skip;
    2203             :         }
    2204          40 :         hitTestPoints.push(hitTestPoint.ref());
    2205          20 :         return TraversalFlag::Continue;
    2206             :       },
    2207          40 :       [&resultNode, &hitTestPoints, &aOutHitResult](HitTestingTreeNode* aNode) {
    2208          15 :         HitTestResult hitResult = aNode->HitTest(hitTestPoints.top());
    2209          15 :         hitTestPoints.pop();
    2210             :         APZCTM_LOG("Testing Layer point %s against node %p\n",
    2211             :                 Stringify(hitTestPoints.top()).c_str(), aNode);
    2212          15 :         if (hitResult != HitTestResult::HitNothing) {
    2213           5 :           resultNode = aNode;
    2214             :           // If event regions are disabled, *aOutHitResult will be HitLayer
    2215           5 :           *aOutHitResult = hitResult;
    2216           5 :           return TraversalFlag::Abort;
    2217             :         }
    2218          10 :         return TraversalFlag::Continue;
    2219             :       }
    2220           6 :   );
    2221             : 
    2222           6 :   if (*aOutHitResult != HitNothing) {
    2223           5 :       MOZ_ASSERT(resultNode);
    2224          15 :       for (HitTestingTreeNode* n = resultNode; n; n = n->GetParent()) {
    2225          10 :         if (n->IsScrollbarNode()) {
    2226           0 :           if (aOutScrollbarNode) {
    2227           0 :             *aOutScrollbarNode = n;
    2228             :           }
    2229             :           // If we hit a scrollbar, target the APZC for the content scrolled
    2230             :           // by the scrollbar. (The scrollbar itself doesn't scroll with the
    2231             :           // scrolled content, so it doesn't carry the scrolled content's
    2232             :           // scroll metadata).
    2233           0 :           ScrollableLayerGuid guid(n->GetLayersId(), 0, n->GetScrollTargetId());
    2234           0 :           if (RefPtr<HitTestingTreeNode> scrollTarget = GetTargetNode(guid, &GuidComparatorIgnoringPresShell)) {
    2235           0 :             MOZ_ASSERT(scrollTarget->GetApzc());
    2236           0 :             return scrollTarget->GetApzc();
    2237             :           }
    2238             :         }
    2239             :       }
    2240             : 
    2241           5 :       AsyncPanZoomController* result = GetTargetApzcForNode(resultNode);
    2242           5 :       if (!result) {
    2243           0 :         result = FindRootApzcForLayersId(resultNode->GetLayersId());
    2244           0 :         MOZ_ASSERT(result);
    2245             :         APZCTM_LOG("Found target %p using root lookup\n", result);
    2246             :       }
    2247             :       APZCTM_LOG("Successfully matched APZC %p via node %p (hit result %d)\n",
    2248             :           result, resultNode, *aOutHitResult);
    2249           5 :       return result;
    2250             :   }
    2251             : 
    2252           1 :   return nullptr;
    2253             : }
    2254             : 
    2255             : AsyncPanZoomController*
    2256           0 : APZCTreeManager::FindRootApzcForLayersId(uint64_t aLayersId) const
    2257             : {
    2258           0 :   mTreeLock.AssertCurrentThreadOwns();
    2259             : 
    2260           0 :   HitTestingTreeNode* resultNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
    2261           0 :       [aLayersId](HitTestingTreeNode* aNode) {
    2262           0 :         AsyncPanZoomController* apzc = aNode->GetApzc();
    2263             :         return apzc
    2264           0 :             && apzc->GetLayersId() == aLayersId
    2265           0 :             && apzc->IsRootForLayersId();
    2266           0 :       });
    2267           0 :   return resultNode ? resultNode->GetApzc() : nullptr;
    2268             : }
    2269             : 
    2270             : AsyncPanZoomController*
    2271           0 : APZCTreeManager::FindRootContentApzcForLayersId(uint64_t aLayersId) const
    2272             : {
    2273           0 :   mTreeLock.AssertCurrentThreadOwns();
    2274             : 
    2275           0 :   HitTestingTreeNode* resultNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
    2276           0 :       [aLayersId](HitTestingTreeNode* aNode) {
    2277           0 :         AsyncPanZoomController* apzc = aNode->GetApzc();
    2278             :         return apzc
    2279           0 :             && apzc->GetLayersId() == aLayersId
    2280           0 :             && apzc->IsRootContent();
    2281           0 :       });
    2282           0 :   return resultNode ? resultNode->GetApzc() : nullptr;
    2283             : }
    2284             : 
    2285             : AsyncPanZoomController*
    2286           0 : APZCTreeManager::FindRootContentOrRootApzc() const
    2287             : {
    2288           0 :   mTreeLock.AssertCurrentThreadOwns();
    2289             : 
    2290             :   // Note: this is intended to find the same "root" that would be found
    2291             :   // by AsyncCompositionManager::ApplyAsyncContentTransformToTree inside
    2292             :   // the MOZ_WIDGET_ANDROID block. That is, it should find the RCD node if there
    2293             :   // is one, or the root APZC if there is not.
    2294             :   // Since BreadthFirstSearch is a pre-order search, we first do a search for
    2295             :   // the RCD, and then if we don't find one, we do a search for the root APZC.
    2296           0 :   HitTestingTreeNode* resultNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
    2297           0 :       [](HitTestingTreeNode* aNode) {
    2298           0 :         AsyncPanZoomController* apzc = aNode->GetApzc();
    2299           0 :         return apzc && apzc->IsRootContent();
    2300           0 :       });
    2301           0 :   if (resultNode) {
    2302           0 :     return resultNode->GetApzc();
    2303             :   }
    2304           0 :   resultNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
    2305           0 :       [](HitTestingTreeNode* aNode) {
    2306           0 :         AsyncPanZoomController* apzc = aNode->GetApzc();
    2307           0 :         return (apzc != nullptr);
    2308           0 :       });
    2309           0 :   return resultNode ? resultNode->GetApzc() : nullptr;
    2310             : }
    2311             : 
    2312             : /* The methods GetScreenToApzcTransform() and GetApzcToGeckoTransform() return
    2313             :    some useful transformations that input events may need applied. This is best
    2314             :    illustrated with an example. Consider a chain of layers, L, M, N, O, P, Q, R. Layer L
    2315             :    is the layer that corresponds to the argument |aApzc|, and layer R is the root
    2316             :    of the layer tree. Layer M is the parent of L, N is the parent of M, and so on.
    2317             :    When layer L is displayed to the screen by the compositor, the set of transforms that
    2318             :    are applied to L are (in order from top to bottom):
    2319             : 
    2320             :         L's CSS transform                   (hereafter referred to as transform matrix LC)
    2321             :         L's nontransient async transform    (hereafter referred to as transform matrix LN)
    2322             :         L's transient async transform       (hereafter referred to as transform matrix LT)
    2323             :         M's CSS transform                   (hereafter referred to as transform matrix MC)
    2324             :         M's nontransient async transform    (hereafter referred to as transform matrix MN)
    2325             :         M's transient async transform       (hereafter referred to as transform matrix MT)
    2326             :         ...
    2327             :         R's CSS transform                   (hereafter referred to as transform matrix RC)
    2328             :         R's nontransient async transform    (hereafter referred to as transform matrix RN)
    2329             :         R's transient async transform       (hereafter referred to as transform matrix RT)
    2330             : 
    2331             :    Also, for any layer, the async transform is the combination of its transient and non-transient
    2332             :    parts. That is, for any layer L:
    2333             :                   LA === LN * LT
    2334             :         LA.Inverse() === LT.Inverse() * LN.Inverse()
    2335             : 
    2336             :    If we want user input to modify L's transient async transform, we have to first convert
    2337             :    user input from screen space to the coordinate space of L's transient async transform. Doing
    2338             :    this involves applying the following transforms (in order from top to bottom):
    2339             :         RT.Inverse()
    2340             :         RN.Inverse()
    2341             :         RC.Inverse()
    2342             :         ...
    2343             :         MT.Inverse()
    2344             :         MN.Inverse()
    2345             :         MC.Inverse()
    2346             :    This combined transformation is returned by GetScreenToApzcTransform().
    2347             : 
    2348             :    Next, if we want user inputs sent to gecko for event-dispatching, we will need to strip
    2349             :    out all of the async transforms that are involved in this chain. This is because async
    2350             :    transforms are stored only in the compositor and gecko does not account for them when
    2351             :    doing display-list-based hit-testing for event dispatching.
    2352             :    Furthermore, because these input events are processed by Gecko in a FIFO queue that
    2353             :    includes other things (specifically paint requests), it is possible that by time the
    2354             :    input event reaches gecko, it will have painted something else. Therefore, we need to
    2355             :    apply another transform to the input events to account for the possible disparity between
    2356             :    what we know gecko last painted and the last paint request we sent to gecko. Let this
    2357             :    transform be represented by LD, MD, ... RD.
    2358             :    Therefore, given a user input in screen space, the following transforms need to be applied
    2359             :    (in order from top to bottom):
    2360             :         RT.Inverse()
    2361             :         RN.Inverse()
    2362             :         RC.Inverse()
    2363             :         ...
    2364             :         MT.Inverse()
    2365             :         MN.Inverse()
    2366             :         MC.Inverse()
    2367             :         LT.Inverse()
    2368             :         LN.Inverse()
    2369             :         LC.Inverse()
    2370             :         LC
    2371             :         LD
    2372             :         MC
    2373             :         MD
    2374             :         ...
    2375             :         RC
    2376             :         RD
    2377             :    This sequence can be simplified and refactored to the following:
    2378             :         GetScreenToApzcTransform()
    2379             :         LA.Inverse()
    2380             :         LD
    2381             :         MC
    2382             :         MD
    2383             :         ...
    2384             :         RC
    2385             :         RD
    2386             :    Since GetScreenToApzcTransform() can be obtained by calling that function, GetApzcToGeckoTransform()
    2387             :    returns the remaining transforms (LA.Inverse() * LD * ... * RD), so that the caller code can
    2388             :    combine it with GetScreenToApzcTransform() to get the final transform required in this case.
    2389             : 
    2390             :    Note that for many of these layers, there will be no AsyncPanZoomController attached, and
    2391             :    so the async transform will be the identity transform. So, in the example above, if layers
    2392             :    L and P have APZC instances attached, MT, MN, MD, NT, NN, ND, OT, ON, OD, QT, QN, QD, RT,
    2393             :    RN and RD will be identity transforms.
    2394             :    Additionally, for space-saving purposes, each APZC instance stores its layer's individual
    2395             :    CSS transform and the accumulation of CSS transforms to its parent APZC. So the APZC for
    2396             :    layer L would store LC and (MC * NC * OC), and the layer P would store PC and (QC * RC).
    2397             :    The APZC instances track the last dispatched paint request and so are able to calculate LD and
    2398             :    PD using those internally stored values.
    2399             :    The APZCs also obviously have LT, LN, PT, and PN, so all of the above transformation combinations
    2400             :    required can be generated.
    2401             :  */
    2402             : 
    2403             : /*
    2404             :  * See the long comment above for a detailed explanation of this function.
    2405             :  */
    2406             : ScreenToParentLayerMatrix4x4
    2407           5 : APZCTreeManager::GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const
    2408             : {
    2409           5 :   Matrix4x4 result;
    2410          10 :   MutexAutoLock lock(mTreeLock);
    2411             : 
    2412             :   // The comments below assume there is a chain of layers L..R with L and P having APZC instances as
    2413             :   // explained in the comment above. This function is called with aApzc at L, and the loop
    2414             :   // below performs one iteration, where parent is at P. The comments explain what values are stored
    2415             :   // in the variables at these two levels. All the comments use standard matrix notation where the
    2416             :   // leftmost matrix in a multiplication is applied first.
    2417             : 
    2418             :   // ancestorUntransform is PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
    2419           5 :   Matrix4x4 ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
    2420             : 
    2421             :   // result is initialized to PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
    2422           5 :   result = ancestorUntransform;
    2423             : 
    2424           5 :   for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) {
    2425             :     // ancestorUntransform is updated to RC.Inverse() * QC.Inverse() when parent == P
    2426           0 :     ancestorUntransform = parent->GetAncestorTransform().Inverse();
    2427             :     // asyncUntransform is updated to PA.Inverse() when parent == P
    2428           0 :     Matrix4x4 asyncUntransform = parent->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::eForHitTesting).Inverse().ToUnknownMatrix();
    2429             :     // untransformSinceLastApzc is RC.Inverse() * QC.Inverse() * PA.Inverse()
    2430           0 :     Matrix4x4 untransformSinceLastApzc = ancestorUntransform * asyncUntransform;
    2431             : 
    2432             :     // result is RC.Inverse() * QC.Inverse() * PA.Inverse() * PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
    2433           0 :     result = untransformSinceLastApzc * result;
    2434             : 
    2435             :     // The above value for result when parent == P matches the required output
    2436             :     // as explained in the comment above this method. Note that any missing
    2437             :     // terms are guaranteed to be identity transforms.
    2438             :   }
    2439             : 
    2440          10 :   return ViewAs<ScreenToParentLayerMatrix4x4>(result);
    2441             : }
    2442             : 
    2443             : /*
    2444             :  * See the long comment above GetScreenToApzcTransform() for a detailed
    2445             :  * explanation of this function.
    2446             :  */
    2447             : ParentLayerToScreenMatrix4x4
    2448           5 : APZCTreeManager::GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const
    2449             : {
    2450           5 :   Matrix4x4 result;
    2451          10 :   MutexAutoLock lock(mTreeLock);
    2452             : 
    2453             :   // The comments below assume there is a chain of layers L..R with L and P having APZC instances as
    2454             :   // explained in the comment above. This function is called with aApzc at L, and the loop
    2455             :   // below performs one iteration, where parent is at P. The comments explain what values are stored
    2456             :   // in the variables at these two levels. All the comments use standard matrix notation where the
    2457             :   // leftmost matrix in a multiplication is applied first.
    2458             : 
    2459             :   // asyncUntransform is LA.Inverse()
    2460           5 :   Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::eForHitTesting).Inverse().ToUnknownMatrix();
    2461             : 
    2462             :   // aTransformToGeckoOut is initialized to LA.Inverse() * LD * MC * NC * OC * PC
    2463           5 :   result = asyncUntransform * aApzc->GetTransformToLastDispatchedPaint() * aApzc->GetAncestorTransform();
    2464             : 
    2465           5 :   for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) {
    2466             :     // aTransformToGeckoOut is LA.Inverse() * LD * MC * NC * OC * PC * PD * QC * RC
    2467           0 :     result = result * parent->GetTransformToLastDispatchedPaint() * parent->GetAncestorTransform();
    2468             : 
    2469             :     // The above value for result when parent == P matches the required output
    2470             :     // as explained in the comment above this method. Note that any missing
    2471             :     // terms are guaranteed to be identity transforms.
    2472             :   }
    2473             : 
    2474          10 :   return ViewAs<ParentLayerToScreenMatrix4x4>(result);
    2475             : }
    2476             : 
    2477             : already_AddRefed<AsyncPanZoomController>
    2478           0 : APZCTreeManager::GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const
    2479             : {
    2480           0 :   MutexAutoLock lock(mTreeLock);
    2481           0 :   RefPtr<AsyncPanZoomController> apzc;
    2482             :   // For now, we only ever want to do pinching on the root-content APZC for
    2483             :   // a given layers id.
    2484           0 :   if (aApzc1 && aApzc2 && aApzc1->GetLayersId() == aApzc2->GetLayersId()) {
    2485             :     // If the two APZCs have the same layers id, find the root-content APZC
    2486             :     // for that layers id. Don't call CommonAncestor() because there may not
    2487             :     // be a common ancestor for the layers id (e.g. if one APZCs is inside a
    2488             :     // fixed-position element).
    2489           0 :     apzc = FindRootContentApzcForLayersId(aApzc1->GetLayersId());
    2490             :   } else {
    2491             :     // Otherwise, find the common ancestor (to reach a common layers id), and
    2492             :     // get the root-content APZC for that layers id.
    2493           0 :     apzc = CommonAncestor(aApzc1, aApzc2);
    2494           0 :     if (apzc) {
    2495           0 :       apzc = FindRootContentApzcForLayersId(apzc->GetLayersId());
    2496             :     }
    2497             :   }
    2498           0 :   return apzc.forget();
    2499             : }
    2500             : 
    2501             : already_AddRefed<AsyncPanZoomController>
    2502           0 : APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const
    2503             : {
    2504           0 :   mTreeLock.AssertCurrentThreadOwns();
    2505           0 :   RefPtr<AsyncPanZoomController> ancestor;
    2506             : 
    2507             :   // If either aApzc1 or aApzc2 is null, min(depth1, depth2) will be 0 and this function
    2508             :   // will return null.
    2509             : 
    2510             :   // Calculate depth of the APZCs in the tree
    2511           0 :   int depth1 = 0, depth2 = 0;
    2512           0 :   for (AsyncPanZoomController* parent = aApzc1; parent; parent = parent->GetParent()) {
    2513           0 :     depth1++;
    2514             :   }
    2515           0 :   for (AsyncPanZoomController* parent = aApzc2; parent; parent = parent->GetParent()) {
    2516           0 :     depth2++;
    2517             :   }
    2518             : 
    2519             :   // At most one of the following two loops will be executed; the deeper APZC pointer
    2520             :   // will get walked up to the depth of the shallower one.
    2521           0 :   int minDepth = depth1 < depth2 ? depth1 : depth2;
    2522           0 :   while (depth1 > minDepth) {
    2523           0 :     depth1--;
    2524           0 :     aApzc1 = aApzc1->GetParent();
    2525             :   }
    2526           0 :   while (depth2 > minDepth) {
    2527           0 :     depth2--;
    2528           0 :     aApzc2 = aApzc2->GetParent();
    2529             :   }
    2530             : 
    2531             :   // Walk up the ancestor chains of both APZCs, always staying at the same depth for
    2532             :   // either APZC, and return the the first common ancestor encountered.
    2533             :   while (true) {
    2534           0 :     if (aApzc1 == aApzc2) {
    2535           0 :       ancestor = aApzc1;
    2536           0 :       break;
    2537             :     }
    2538           0 :     if (depth1 <= 0) {
    2539           0 :       break;
    2540             :     }
    2541           0 :     aApzc1 = aApzc1->GetParent();
    2542           0 :     aApzc2 = aApzc2->GetParent();
    2543             :   }
    2544           0 :   return ancestor.forget();
    2545             : }
    2546             : 
    2547             : LayerToParentLayerMatrix4x4
    2548          20 : APZCTreeManager::ComputeTransformForNode(const HitTestingTreeNode* aNode) const
    2549             : {
    2550          20 :   if (AsyncPanZoomController* apzc = aNode->GetApzc()) {
    2551             :     // If the node represents scrollable content, apply the async transform
    2552             :     // from its APZC.
    2553           5 :     return aNode->GetTransform() *
    2554          10 :         CompleteAsyncTransform(
    2555          15 :           apzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::eForHitTesting));
    2556          15 :   } else if (aNode->IsScrollThumbNode()) {
    2557             :     // If the node represents a scrollbar thumb, compute and apply the
    2558             :     // transformation that will be applied to the thumb in
    2559             :     // AsyncCompositionManager.
    2560           0 :     ScrollableLayerGuid guid{aNode->GetLayersId(), 0, aNode->GetScrollTargetId()};
    2561           0 :     if (RefPtr<HitTestingTreeNode> scrollTargetNode = GetTargetNode(guid, &GuidComparatorIgnoringPresShell)) {
    2562           0 :       AsyncPanZoomController* scrollTargetApzc = scrollTargetNode->GetApzc();
    2563           0 :       MOZ_ASSERT(scrollTargetApzc);
    2564             :       return scrollTargetApzc->CallWithLastContentPaintMetrics(
    2565           0 :         [&](const FrameMetrics& aMetrics) {
    2566             :           return AsyncCompositionManager::ComputeTransformForScrollThumb(
    2567           0 :               aNode->GetTransform() * AsyncTransformMatrix(),
    2568           0 :               scrollTargetNode->GetTransform().ToUnknownMatrix(),
    2569           0 :               scrollTargetApzc,
    2570             :               aMetrics,
    2571             :               aNode->GetScrollThumbData(),
    2572           0 :               scrollTargetNode->IsAncestorOf(aNode),
    2573             :               nullptr);
    2574           0 :         });
    2575             :     }
    2576             :   }
    2577             :   // Otherwise, the node does not have an async transform.
    2578          15 :   return aNode->GetTransform() * AsyncTransformMatrix();
    2579             : }
    2580             : 
    2581             : #if defined(MOZ_WIDGET_ANDROID)
    2582             : void
    2583             : APZCTreeManager::InitializeDynamicToolbarAnimator(const int64_t& aRootLayerTreeId)
    2584             : {
    2585             :   MOZ_ASSERT(mToolbarAnimator);
    2586             :   mToolbarAnimator->Initialize(aRootLayerTreeId);
    2587             : }
    2588             : 
    2589             : AndroidDynamicToolbarAnimator*
    2590             : APZCTreeManager::GetAndroidDynamicToolbarAnimator()
    2591             : {
    2592             :   return mToolbarAnimator;
    2593             : }
    2594             : #endif // defined(MOZ_WIDGET_ANDROID)
    2595             : 
    2596             : } // namespace layers
    2597             : } // namespace mozilla

Generated by: LCOV version 1.13