1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_layers_APZTestCommon_h
8 #define mozilla_layers_APZTestCommon_h
9 
10 /**
11  * Defines a set of mock classes and utility functions/classes for
12  * writing APZ gtests.
13  */
14 
15 #include "gtest/gtest.h"
16 #include "gmock/gmock.h"
17 
18 #include "mozilla/Attributes.h"
19 #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
20 #include "mozilla/layers/GeckoContentController.h"
21 #include "mozilla/layers/CompositorBridgeParent.h"
22 #include "mozilla/layers/APZCTreeManager.h"
23 #include "mozilla/layers/LayerMetricsWrapper.h"
24 #include "mozilla/layers/APZThreadUtils.h"
25 #include "mozilla/UniquePtr.h"
26 #include "apz/src/AsyncPanZoomController.h"
27 #include "apz/src/HitTestingTreeNode.h"
28 #include "base/task.h"
29 #include "Layers.h"
30 #include "TestLayers.h"
31 #include "UnitTransforms.h"
32 #include "gfxPrefs.h"
33 
34 using namespace mozilla;
35 using namespace mozilla::gfx;
36 using namespace mozilla::layers;
37 using ::testing::_;
38 using ::testing::NiceMock;
39 using ::testing::AtLeast;
40 using ::testing::AtMost;
41 using ::testing::MockFunction;
42 using ::testing::InSequence;
43 typedef mozilla::layers::GeckoContentController::TapType TapType;
44 
45 template<class T>
46 class ScopedGfxPref {
47 public:
ScopedGfxPref(T (* aGetPrefFunc)(void),void (* aSetPrefFunc)(T),T aVal)48   ScopedGfxPref(T (*aGetPrefFunc)(void), void (*aSetPrefFunc)(T), T aVal)
49     : mSetPrefFunc(aSetPrefFunc)
50   {
51     mOldVal = aGetPrefFunc();
52     aSetPrefFunc(aVal);
53   }
54 
~ScopedGfxPref()55   ~ScopedGfxPref() {
56     mSetPrefFunc(mOldVal);
57   }
58 
59 private:
60   void (*mSetPrefFunc)(T);
61   T mOldVal;
62 };
63 
64 #define SCOPED_GFX_PREF(prefBase, prefType, prefValue) \
65   ScopedGfxPref<prefType> pref_##prefBase( \
66     &(gfxPrefs::prefBase), \
67     &(gfxPrefs::Set##prefBase), \
68     prefValue)
69 
GetStartupTime()70 static TimeStamp GetStartupTime() {
71   static TimeStamp sStartupTime = TimeStamp::Now();
72   return sStartupTime;
73 }
74 
75 class MockContentController : public GeckoContentController {
76 public:
77   MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
78   MOCK_METHOD2(RequestFlingSnap, void(const FrameMetrics::ViewID& aScrollId, const mozilla::CSSPoint& aDestination));
79   MOCK_METHOD2(AcknowledgeScrollUpdate, void(const FrameMetrics::ViewID&, const uint32_t& aScrollGeneration));
80   MOCK_METHOD5(HandleTap, void(TapType, const LayoutDevicePoint&, Modifiers, const ScrollableLayerGuid&, uint64_t));
81   MOCK_METHOD4(NotifyPinchGesture, void(PinchGestureInput::PinchGestureType, const ScrollableLayerGuid&, LayoutDeviceCoord, Modifiers));
82   // Can't use the macros with already_AddRefed :(
PostDelayedTask(already_AddRefed<Runnable> aTask,int aDelayMs)83   void PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs) {
84     RefPtr<Runnable> task = aTask;
85   }
IsRepaintThread()86   bool IsRepaintThread() {
87     return NS_IsMainThread();
88   }
DispatchToRepaintThread(already_AddRefed<Runnable> aTask)89   void DispatchToRepaintThread(already_AddRefed<Runnable> aTask) {
90     NS_DispatchToMainThread(Move(aTask));
91   }
92   MOCK_METHOD3(NotifyAPZStateChange, void(const ScrollableLayerGuid& aGuid, APZStateChange aChange, int aArg));
93   MOCK_METHOD0(NotifyFlushComplete, void());
94 };
95 
96 class MockContentControllerDelayed : public MockContentController {
97 public:
MockContentControllerDelayed()98   MockContentControllerDelayed()
99     : mTime(GetStartupTime())
100   {
101   }
102 
Time()103   const TimeStamp& Time() {
104     return mTime;
105   }
106 
AdvanceByMillis(int aMillis)107   void AdvanceByMillis(int aMillis) {
108     AdvanceBy(TimeDuration::FromMilliseconds(aMillis));
109   }
110 
AdvanceBy(const TimeDuration & aIncrement)111   void AdvanceBy(const TimeDuration& aIncrement) {
112     TimeStamp target = mTime + aIncrement;
113     while (mTaskQueue.Length() > 0 && mTaskQueue[0].second <= target) {
114       RunNextDelayedTask();
115     }
116     mTime = target;
117   }
118 
PostDelayedTask(already_AddRefed<Runnable> aTask,int aDelayMs)119   void PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs) {
120     RefPtr<Runnable> task = aTask;
121     TimeStamp runAtTime = mTime + TimeDuration::FromMilliseconds(aDelayMs);
122     int insIndex = mTaskQueue.Length();
123     while (insIndex > 0) {
124       if (mTaskQueue[insIndex - 1].second <= runAtTime) {
125         break;
126       }
127       insIndex--;
128     }
129     mTaskQueue.InsertElementAt(insIndex, std::make_pair(task, runAtTime));
130   }
131 
132   // Run all the tasks in the queue, returning the number of tasks
133   // run. Note that if a task queues another task while running, that
134   // new task will not be run. Therefore, there may be still be tasks
135   // in the queue after this function is called. Only when the return
136   // value is 0 is the queue guaranteed to be empty.
RunThroughDelayedTasks()137   int RunThroughDelayedTasks() {
138     nsTArray<std::pair<RefPtr<Runnable>, TimeStamp>> runQueue;
139     runQueue.SwapElements(mTaskQueue);
140     int numTasks = runQueue.Length();
141     for (int i = 0; i < numTasks; i++) {
142       mTime = runQueue[i].second;
143       runQueue[i].first->Run();
144 
145       // Deleting the task is important in order to release the reference to
146       // the callee object.
147       runQueue[i].first = nullptr;
148     }
149     return numTasks;
150   }
151 
152 private:
RunNextDelayedTask()153   void RunNextDelayedTask() {
154     std::pair<RefPtr<Runnable>, TimeStamp> next = mTaskQueue[0];
155     mTaskQueue.RemoveElementAt(0);
156     mTime = next.second;
157     next.first->Run();
158     // Deleting the task is important in order to release the reference to
159     // the callee object.
160     next.first = nullptr;
161   }
162 
163   // The following array is sorted by timestamp (tasks are inserted in order by
164   // timestamp).
165   nsTArray<std::pair<RefPtr<Runnable>, TimeStamp>> mTaskQueue;
166   TimeStamp mTime;
167 };
168 
169 class TestAPZCTreeManager : public APZCTreeManager {
170 public:
TestAPZCTreeManager(MockContentControllerDelayed * aMcc)171   explicit TestAPZCTreeManager(MockContentControllerDelayed* aMcc) : mcc(aMcc) {}
172 
GetInputQueue()173   RefPtr<InputQueue> GetInputQueue() const {
174     return mInputQueue;
175   }
176 
ClearContentController()177   void ClearContentController() {
178     mcc = nullptr;
179   }
180 
181 protected:
182   AsyncPanZoomController* NewAPZCInstance(uint64_t aLayersId,
183                                           GeckoContentController* aController) override;
184 
GetFrameTime()185   TimeStamp GetFrameTime() override {
186     return mcc->Time();
187   }
188 
189 private:
190   RefPtr<MockContentControllerDelayed> mcc;
191 };
192 
193 class TestAsyncPanZoomController : public AsyncPanZoomController {
194 public:
195   TestAsyncPanZoomController(uint64_t aLayersId, MockContentControllerDelayed* aMcc,
196                              TestAPZCTreeManager* aTreeManager,
197                              GestureBehavior aBehavior = DEFAULT_GESTURES)
198     : AsyncPanZoomController(aLayersId, aTreeManager, aTreeManager->GetInputQueue(),
199         aMcc, aBehavior)
200     , mWaitForMainThread(false)
201     , mcc(aMcc)
202   {}
203 
ReceiveInputEvent(const InputData & aEvent,ScrollableLayerGuid * aDummy,uint64_t * aOutInputBlockId)204   nsEventStatus ReceiveInputEvent(const InputData& aEvent, ScrollableLayerGuid* aDummy, uint64_t* aOutInputBlockId) {
205     // This is a function whose signature matches exactly the ReceiveInputEvent
206     // on APZCTreeManager. This allows us to templates for functions like
207     // TouchDown, TouchUp, etc so that we can reuse the code for dispatching
208     // events into both APZC and APZCTM.
209     return ReceiveInputEvent(aEvent, aOutInputBlockId);
210   }
211 
ReceiveInputEvent(const InputData & aEvent,uint64_t * aOutInputBlockId)212   nsEventStatus ReceiveInputEvent(const InputData& aEvent, uint64_t* aOutInputBlockId) {
213     return GetInputQueue()->ReceiveInputEvent(this, !mWaitForMainThread, aEvent, aOutInputBlockId);
214   }
215 
ContentReceivedInputBlock(uint64_t aInputBlockId,bool aPreventDefault)216   void ContentReceivedInputBlock(uint64_t aInputBlockId, bool aPreventDefault) {
217     GetInputQueue()->ContentReceivedInputBlock(aInputBlockId, aPreventDefault);
218   }
219 
ConfirmTarget(uint64_t aInputBlockId)220   void ConfirmTarget(uint64_t aInputBlockId) {
221     RefPtr<AsyncPanZoomController> target = this;
222     GetInputQueue()->SetConfirmedTargetApzc(aInputBlockId, target);
223   }
224 
SetAllowedTouchBehavior(uint64_t aInputBlockId,const nsTArray<TouchBehaviorFlags> & aBehaviors)225   void SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aBehaviors) {
226     GetInputQueue()->SetAllowedTouchBehavior(aInputBlockId, aBehaviors);
227   }
228 
SetFrameMetrics(const FrameMetrics & metrics)229   void SetFrameMetrics(const FrameMetrics& metrics) {
230     ReentrantMonitorAutoEnter lock(mMonitor);
231     mFrameMetrics = metrics;
232   }
233 
GetFrameMetrics()234   FrameMetrics& GetFrameMetrics() {
235     ReentrantMonitorAutoEnter lock(mMonitor);
236     return mFrameMetrics;
237   }
238 
GetScrollMetadata()239   ScrollMetadata& GetScrollMetadata() {
240     ReentrantMonitorAutoEnter lock(mMonitor);
241     return mScrollMetadata;
242   }
243 
GetFrameMetrics()244   const FrameMetrics& GetFrameMetrics() const {
245     ReentrantMonitorAutoEnter lock(mMonitor);
246     return mFrameMetrics;
247   }
248 
249   using AsyncPanZoomController::GetVelocityVector;
250 
AssertStateIsReset()251   void AssertStateIsReset() const {
252     ReentrantMonitorAutoEnter lock(mMonitor);
253     EXPECT_EQ(NOTHING, mState);
254   }
255 
AssertStateIsFling()256   void AssertStateIsFling() const {
257     ReentrantMonitorAutoEnter lock(mMonitor);
258     EXPECT_EQ(FLING, mState);
259   }
260 
261   void AdvanceAnimationsUntilEnd(const TimeDuration& aIncrement = TimeDuration::FromMilliseconds(10)) {
262     while (AdvanceAnimations(mcc->Time())) {
263       mcc->AdvanceBy(aIncrement);
264     }
265   }
266 
267   bool SampleContentTransformForFrame(AsyncTransform* aOutTransform,
268                                       ParentLayerPoint& aScrollOffset,
269                                       const TimeDuration& aIncrement = TimeDuration::FromMilliseconds(0)) {
270     mcc->AdvanceBy(aIncrement);
271     bool ret = AdvanceAnimations(mcc->Time());
272     if (aOutTransform) {
273       *aOutTransform = GetCurrentAsyncTransform(AsyncPanZoomController::NORMAL);
274     }
275     aScrollOffset = GetCurrentAsyncScrollOffset(AsyncPanZoomController::NORMAL);
276     return ret;
277   }
278 
SetWaitForMainThread()279   void SetWaitForMainThread() {
280     mWaitForMainThread = true;
281   }
282 
283 private:
284   bool mWaitForMainThread;
285   MockContentControllerDelayed* mcc;
286 };
287 
288 class APZCTesterBase : public ::testing::Test {
289 public:
APZCTesterBase()290   APZCTesterBase() {
291     mcc = new NiceMock<MockContentControllerDelayed>();
292   }
293 
294   template<class InputReceiver>
295   void Tap(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
296            TimeDuration aTapLength,
297            nsEventStatus (*aOutEventStatuses)[2] = nullptr,
298            uint64_t* aOutInputBlockId = nullptr);
299 
300   template<class InputReceiver>
301   void TapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
302                          const ScreenIntPoint& aPoint, TimeDuration aTapLength);
303 
304   template<class InputReceiver>
305   void Pan(const RefPtr<InputReceiver>& aTarget,
306            const ScreenIntPoint& aTouchStart,
307            const ScreenIntPoint& aTouchEnd,
308            bool aKeepFingerDown = false,
309            nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
310            nsEventStatus (*aOutEventStatuses)[4] = nullptr,
311            uint64_t* aOutInputBlockId = nullptr);
312 
313   /*
314    * A version of Pan() that only takes y coordinates rather than (x, y) points
315    * for the touch start and end points, and uses 10 for the x coordinates.
316    * This is for convenience, as most tests only need to pan in one direction.
317   */
318   template<class InputReceiver>
319   void Pan(const RefPtr<InputReceiver>& aTarget, int aTouchStartY,
320            int aTouchEndY, bool aKeepFingerDown = false,
321            nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
322            nsEventStatus (*aOutEventStatuses)[4] = nullptr,
323            uint64_t* aOutInputBlockId = nullptr);
324 
325   /*
326    * Dispatches mock touch events to the apzc and checks whether apzc properly
327    * consumed them and triggered scrolling behavior.
328   */
329   template<class InputReceiver>
330   void PanAndCheckStatus(const RefPtr<InputReceiver>& aTarget, int aTouchStartY,
331                          int aTouchEndY,
332                          bool aExpectConsumed,
333                          nsTArray<uint32_t>* aAllowedTouchBehaviors,
334                          uint64_t* aOutInputBlockId = nullptr);
335 
336   void ApzcPanNoFling(const RefPtr<TestAsyncPanZoomController>& aApzc,
337                       int aTouchStartY,
338                       int aTouchEndY,
339                       uint64_t* aOutInputBlockId = nullptr);
340 
341   template<class InputReceiver>
342   void DoubleTap(const RefPtr<InputReceiver>& aTarget,
343                  const ScreenIntPoint& aPoint,
344                  nsEventStatus (*aOutEventStatuses)[4] = nullptr,
345                  uint64_t (*aOutInputBlockIds)[2] = nullptr);
346 
347   template<class InputReceiver>
348   void DoubleTapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
349                                const ScreenIntPoint& aPoint,
350                                uint64_t (*aOutInputBlockIds)[2] = nullptr);
351 
352 protected:
353   RefPtr<MockContentControllerDelayed> mcc;
354 };
355 
356 template<class InputReceiver>
357 void
Tap(const RefPtr<InputReceiver> & aTarget,const ScreenIntPoint & aPoint,TimeDuration aTapLength,nsEventStatus (* aOutEventStatuses)[2],uint64_t * aOutInputBlockId)358 APZCTesterBase::Tap(const RefPtr<InputReceiver>& aTarget,
359                     const ScreenIntPoint& aPoint, TimeDuration aTapLength,
360                     nsEventStatus (*aOutEventStatuses)[2],
361                     uint64_t* aOutInputBlockId)
362 {
363   // Even if the caller doesn't care about the block id, we need it to set the
364   // allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
365   uint64_t blockId;
366   if (!aOutInputBlockId) {
367     aOutInputBlockId = &blockId;
368   }
369 
370   nsEventStatus status = TouchDown(aTarget, aPoint, mcc->Time(), aOutInputBlockId);
371   if (aOutEventStatuses) {
372     (*aOutEventStatuses)[0] = status;
373   }
374   mcc->AdvanceBy(aTapLength);
375 
376   // If touch-action is enabled then simulate the allowed touch behaviour
377   // notification that the main thread is supposed to deliver.
378   if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
379     SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId);
380   }
381 
382   status = TouchUp(aTarget, aPoint, mcc->Time());
383   if (aOutEventStatuses) {
384     (*aOutEventStatuses)[1] = status;
385   }
386 }
387 
388 template<class InputReceiver>
389 void
TapAndCheckStatus(const RefPtr<InputReceiver> & aTarget,const ScreenIntPoint & aPoint,TimeDuration aTapLength)390 APZCTesterBase::TapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
391                                   const ScreenIntPoint& aPoint,
392                                   TimeDuration aTapLength)
393 {
394   nsEventStatus statuses[2];
395   Tap(aTarget, aPoint, aTapLength, &statuses);
396   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
397   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[1]);
398 }
399 
400 template<class InputReceiver>
401 void
Pan(const RefPtr<InputReceiver> & aTarget,const ScreenIntPoint & aTouchStart,const ScreenIntPoint & aTouchEnd,bool aKeepFingerDown,nsTArray<uint32_t> * aAllowedTouchBehaviors,nsEventStatus (* aOutEventStatuses)[4],uint64_t * aOutInputBlockId)402 APZCTesterBase::Pan(const RefPtr<InputReceiver>& aTarget,
403                     const ScreenIntPoint& aTouchStart,
404                     const ScreenIntPoint& aTouchEnd,
405                     bool aKeepFingerDown,
406                     nsTArray<uint32_t>* aAllowedTouchBehaviors,
407                     nsEventStatus (*aOutEventStatuses)[4],
408                     uint64_t* aOutInputBlockId)
409 {
410   // Reduce the touch start and move tolerance to a tiny value.
411   // We can't use a scoped pref because this value might be read at some later
412   // time when the events are actually processed, rather than when we deliver
413   // them.
414   gfxPrefs::SetAPZTouchStartTolerance(1.0f / 1000.0f);
415   gfxPrefs::SetAPZTouchMoveTolerance(0.0f);
416   const int OVERCOME_TOUCH_TOLERANCE = 1;
417 
418   const TimeDuration TIME_BETWEEN_TOUCH_EVENT = TimeDuration::FromMilliseconds(50);
419 
420   // Even if the caller doesn't care about the block id, we need it to set the
421   // allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
422   uint64_t blockId;
423   if (!aOutInputBlockId) {
424     aOutInputBlockId = &blockId;
425   }
426 
427   // Make sure the move is large enough to not be handled as a tap
428   nsEventStatus status = TouchDown(aTarget,
429       ScreenIntPoint(aTouchStart.x, aTouchStart.y + OVERCOME_TOUCH_TOLERANCE),
430       mcc->Time(), aOutInputBlockId);
431   if (aOutEventStatuses) {
432     (*aOutEventStatuses)[0] = status;
433   }
434 
435   mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
436 
437   // Allowed touch behaviours must be set after sending touch-start.
438   if (status != nsEventStatus_eConsumeNoDefault) {
439     if (aAllowedTouchBehaviors) {
440       EXPECT_EQ(1UL, aAllowedTouchBehaviors->Length());
441       aTarget->SetAllowedTouchBehavior(*aOutInputBlockId, *aAllowedTouchBehaviors);
442     } else if (gfxPrefs::TouchActionEnabled()) {
443       SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId);
444     }
445   }
446 
447   status = TouchMove(aTarget, aTouchStart, mcc->Time());
448   if (aOutEventStatuses) {
449     (*aOutEventStatuses)[1] = status;
450   }
451 
452   mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
453 
454   status = TouchMove(aTarget, aTouchEnd, mcc->Time());
455   if (aOutEventStatuses) {
456     (*aOutEventStatuses)[2] = status;
457   }
458 
459   mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
460 
461   if (!aKeepFingerDown) {
462     status = TouchUp(aTarget, aTouchEnd, mcc->Time());
463   } else {
464     status = nsEventStatus_eIgnore;
465   }
466   if (aOutEventStatuses) {
467     (*aOutEventStatuses)[3] = status;
468   }
469 
470   // Don't increment the time here. Animations started on touch-up, such as
471   // flings, are affected by elapsed time, and we want to be able to sample
472   // them immediately after they start, without time having elapsed.
473 }
474 
475 template<class InputReceiver>
476 void
Pan(const RefPtr<InputReceiver> & aTarget,int aTouchStartY,int aTouchEndY,bool aKeepFingerDown,nsTArray<uint32_t> * aAllowedTouchBehaviors,nsEventStatus (* aOutEventStatuses)[4],uint64_t * aOutInputBlockId)477 APZCTesterBase::Pan(const RefPtr<InputReceiver>& aTarget,
478                     int aTouchStartY, int aTouchEndY, bool aKeepFingerDown,
479                     nsTArray<uint32_t>* aAllowedTouchBehaviors,
480                     nsEventStatus (*aOutEventStatuses)[4],
481                     uint64_t* aOutInputBlockId)
482 {
483   Pan(aTarget, ScreenIntPoint(10, aTouchStartY), ScreenIntPoint(10, aTouchEndY),
484       aKeepFingerDown, aAllowedTouchBehaviors, aOutEventStatuses, aOutInputBlockId);
485 }
486 
487 template<class InputReceiver>
488 void
PanAndCheckStatus(const RefPtr<InputReceiver> & aTarget,int aTouchStartY,int aTouchEndY,bool aExpectConsumed,nsTArray<uint32_t> * aAllowedTouchBehaviors,uint64_t * aOutInputBlockId)489 APZCTesterBase::PanAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
490                                   int aTouchStartY,
491                                   int aTouchEndY,
492                                   bool aExpectConsumed,
493                                   nsTArray<uint32_t>* aAllowedTouchBehaviors,
494                                   uint64_t* aOutInputBlockId)
495 {
496   nsEventStatus statuses[4]; // down, move, move, up
497   Pan(aTarget, aTouchStartY, aTouchEndY, false, aAllowedTouchBehaviors, &statuses, aOutInputBlockId);
498 
499   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
500 
501   nsEventStatus touchMoveStatus;
502   if (aExpectConsumed) {
503     touchMoveStatus = nsEventStatus_eConsumeDoDefault;
504   } else {
505     touchMoveStatus = nsEventStatus_eIgnore;
506   }
507   EXPECT_EQ(touchMoveStatus, statuses[1]);
508   EXPECT_EQ(touchMoveStatus, statuses[2]);
509 }
510 
511 void
ApzcPanNoFling(const RefPtr<TestAsyncPanZoomController> & aApzc,int aTouchStartY,int aTouchEndY,uint64_t * aOutInputBlockId)512 APZCTesterBase::ApzcPanNoFling(const RefPtr<TestAsyncPanZoomController>& aApzc,
513                                int aTouchStartY, int aTouchEndY,
514                                uint64_t* aOutInputBlockId)
515 {
516   Pan(aApzc, aTouchStartY, aTouchEndY, false, nullptr, nullptr, aOutInputBlockId);
517   aApzc->CancelAnimation();
518 }
519 
520 template<class InputReceiver>
521 void
DoubleTap(const RefPtr<InputReceiver> & aTarget,const ScreenIntPoint & aPoint,nsEventStatus (* aOutEventStatuses)[4],uint64_t (* aOutInputBlockIds)[2])522 APZCTesterBase::DoubleTap(const RefPtr<InputReceiver>& aTarget,
523                           const ScreenIntPoint& aPoint,
524                           nsEventStatus (*aOutEventStatuses)[4],
525                           uint64_t (*aOutInputBlockIds)[2])
526 {
527   uint64_t blockId;
528   nsEventStatus status = TouchDown(aTarget, aPoint, mcc->Time(), &blockId);
529   if (aOutEventStatuses) {
530     (*aOutEventStatuses)[0] = status;
531   }
532   if (aOutInputBlockIds) {
533     (*aOutInputBlockIds)[0] = blockId;
534   }
535   mcc->AdvanceByMillis(10);
536 
537   // If touch-action is enabled then simulate the allowed touch behaviour
538   // notification that the main thread is supposed to deliver.
539   if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
540     SetDefaultAllowedTouchBehavior(aTarget, blockId);
541   }
542 
543   status = TouchUp(aTarget, aPoint, mcc->Time());
544   if (aOutEventStatuses) {
545     (*aOutEventStatuses)[1] = status;
546   }
547   mcc->AdvanceByMillis(10);
548   status = TouchDown(aTarget, aPoint, mcc->Time(), &blockId);
549   if (aOutEventStatuses) {
550     (*aOutEventStatuses)[2] = status;
551   }
552   if (aOutInputBlockIds) {
553     (*aOutInputBlockIds)[1] = blockId;
554   }
555   mcc->AdvanceByMillis(10);
556 
557   if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
558     SetDefaultAllowedTouchBehavior(aTarget, blockId);
559   }
560 
561   status = TouchUp(aTarget, aPoint, mcc->Time());
562   if (aOutEventStatuses) {
563     (*aOutEventStatuses)[3] = status;
564   }
565 }
566 
567 template<class InputReceiver>
568 void
DoubleTapAndCheckStatus(const RefPtr<InputReceiver> & aTarget,const ScreenIntPoint & aPoint,uint64_t (* aOutInputBlockIds)[2])569 APZCTesterBase::DoubleTapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
570                                         const ScreenIntPoint& aPoint,
571                                         uint64_t (*aOutInputBlockIds)[2])
572 {
573   nsEventStatus statuses[4];
574   DoubleTap(aTarget, aPoint, &statuses, aOutInputBlockIds);
575   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
576   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[1]);
577   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[2]);
578   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[3]);
579 }
580 
581 AsyncPanZoomController*
NewAPZCInstance(uint64_t aLayersId,GeckoContentController * aController)582 TestAPZCTreeManager::NewAPZCInstance(uint64_t aLayersId,
583                                      GeckoContentController* aController)
584 {
585   MockContentControllerDelayed* mcc = static_cast<MockContentControllerDelayed*>(aController);
586   return new TestAsyncPanZoomController(aLayersId, mcc, this,
587       AsyncPanZoomController::USE_GESTURE_DETECTOR);
588 }
589 
590 FrameMetrics
TestFrameMetrics()591 TestFrameMetrics()
592 {
593   FrameMetrics fm;
594 
595   fm.SetDisplayPort(CSSRect(0, 0, 10, 10));
596   fm.SetCompositionBounds(ParentLayerRect(0, 0, 10, 10));
597   fm.SetCriticalDisplayPort(CSSRect(0, 0, 10, 10));
598   fm.SetScrollableRect(CSSRect(0, 0, 100, 100));
599 
600   return fm;
601 }
602 
603 uint32_t
MillisecondsSinceStartup(TimeStamp aTime)604 MillisecondsSinceStartup(TimeStamp aTime)
605 {
606   return (aTime - GetStartupTime()).ToMilliseconds();
607 }
608 
609 #endif // mozilla_layers_APZTestCommon_h
610