Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/apz/test/gtest/APZTestCommon.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#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/gfx/gfxVars.h"
20
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
21
#include "mozilla/layers/GeckoContentController.h"
22
#include "mozilla/layers/CompositorBridgeParent.h"
23
#include "mozilla/layers/LayerMetricsWrapper.h"
24
#include "mozilla/layers/APZThreadUtils.h"
25
#include "mozilla/TypedEnumBits.h"
26
#include "mozilla/UniquePtr.h"
27
#include "apz/src/APZCTreeManager.h"
28
#include "apz/src/AsyncPanZoomController.h"
29
#include "apz/src/HitTestingTreeNode.h"
30
#include "base/task.h"
31
#include "Layers.h"
32
#include "TestLayers.h"
33
#include "UnitTransforms.h"
34
#include "gfxPrefs.h"
35
36
using namespace mozilla;
37
using namespace mozilla::gfx;
38
using namespace mozilla::layers;
39
using ::testing::_;
40
using ::testing::NiceMock;
41
using ::testing::AtLeast;
42
using ::testing::AtMost;
43
using ::testing::MockFunction;
44
using ::testing::InSequence;
45
typedef mozilla::layers::GeckoContentController::TapType TapType;
46
47
// Some helper functions for constructing input event objects suitable to be
48
// passed either to an APZC (which expects an transformed point), or to an APZTM
49
// (which expects an untransformed point). We handle both cases by setting both
50
// the transformed and untransformed fields to the same value.
51
SingleTouchData
52
CreateSingleTouchData(int32_t aIdentifier, const ScreenIntPoint& aPoint)
53
0
{
54
0
  SingleTouchData touch(aIdentifier, aPoint, ScreenSize(0, 0), 0, 0);
55
0
  touch.mLocalScreenPoint = ParentLayerPoint(aPoint.x, aPoint.y);
56
0
  return touch;
57
0
}
58
59
// Convenience wrapper for CreateSingleTouchData() that takes loose coordinates.
60
SingleTouchData
61
CreateSingleTouchData(int32_t aIdentifier, ScreenIntCoord aX, ScreenIntCoord aY)
62
0
{
63
0
  return CreateSingleTouchData(aIdentifier, ScreenIntPoint(aX, aY));
64
0
}
65
66
template<class SetArg, class Storage>
67
class ScopedGfxSetting {
68
public:
69
  ScopedGfxSetting(SetArg (*aGetPrefFunc)(void), void (*aSetPrefFunc)(SetArg), SetArg aVal)
70
    : mSetPrefFunc(aSetPrefFunc)
71
0
  {
72
0
    mOldVal = aGetPrefFunc();
73
0
    aSetPrefFunc(aVal);
74
0
  }
Unexecuted instantiation: ScopedGfxSetting<float, float>::ScopedGfxSetting(float (*)(), void (*)(float), float)
Unexecuted instantiation: ScopedGfxSetting<bool, bool>::ScopedGfxSetting(bool (*)(), void (*)(bool), bool)
Unexecuted instantiation: ScopedGfxSetting<bool const&, bool>::ScopedGfxSetting(bool const& (*)(), void (*)(bool const&), bool const&)
Unexecuted instantiation: ScopedGfxSetting<int, int>::ScopedGfxSetting(int (*)(), void (*)(int), int)
75
76
0
  ~ScopedGfxSetting() {
77
0
    mSetPrefFunc(mOldVal);
78
0
  }
Unexecuted instantiation: ScopedGfxSetting<float, float>::~ScopedGfxSetting()
Unexecuted instantiation: ScopedGfxSetting<bool, bool>::~ScopedGfxSetting()
Unexecuted instantiation: ScopedGfxSetting<bool const&, bool>::~ScopedGfxSetting()
Unexecuted instantiation: ScopedGfxSetting<int, int>::~ScopedGfxSetting()
79
80
private:
81
  void (*mSetPrefFunc)(SetArg);
82
  Storage mOldVal;
83
};
84
85
#define SCOPED_GFX_PREF(prefBase, prefType, prefValue) \
86
0
  ScopedGfxSetting<prefType, prefType> pref_##prefBase( \
87
0
    &(gfxPrefs::prefBase), \
88
0
    &(gfxPrefs::Set##prefBase), \
89
0
    prefValue)
90
91
#define SCOPED_GFX_VAR(varBase, varType, varValue) \
92
0
  ScopedGfxSetting<const varType&, varType> var_##varBase( \
93
0
    &(gfxVars::varBase), \
94
0
    &(gfxVars::Set##varBase), \
95
0
    varValue)
96
97
0
static TimeStamp GetStartupTime() {
98
0
  static TimeStamp sStartupTime = TimeStamp::Now();
99
0
  return sStartupTime;
100
0
}
101
102
class MockContentController : public GeckoContentController {
103
public:
104
  MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
105
  MOCK_METHOD2(RequestFlingSnap, void(const FrameMetrics::ViewID& aScrollId, const mozilla::CSSPoint& aDestination));
106
  MOCK_METHOD2(AcknowledgeScrollUpdate, void(const FrameMetrics::ViewID&, const uint32_t& aScrollGeneration));
107
  MOCK_METHOD5(HandleTap, void(TapType, const LayoutDevicePoint&, Modifiers, const ScrollableLayerGuid&, uint64_t));
108
  MOCK_METHOD4(NotifyPinchGesture, void(PinchGestureInput::PinchGestureType, const ScrollableLayerGuid&, LayoutDeviceCoord, Modifiers));
109
  // Can't use the macros with already_AddRefed :(
110
0
  void PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs) {
111
0
    RefPtr<Runnable> task = aTask;
112
0
  }
113
0
  bool IsRepaintThread() {
114
0
    return NS_IsMainThread();
115
0
  }
116
0
  void DispatchToRepaintThread(already_AddRefed<Runnable> aTask) {
117
0
    NS_DispatchToMainThread(std::move(aTask));
118
0
  }
119
  MOCK_METHOD3(NotifyAPZStateChange, void(const ScrollableLayerGuid& aGuid, APZStateChange aChange, int aArg));
120
  MOCK_METHOD0(NotifyFlushComplete, void());
121
  MOCK_METHOD1(NotifyAsyncScrollbarDragRejected, void(const FrameMetrics::ViewID&));
122
  MOCK_METHOD1(NotifyAsyncAutoscrollRejected, void(const FrameMetrics::ViewID&));
123
  MOCK_METHOD1(CancelAutoscroll, void(const ScrollableLayerGuid&));
124
};
125
126
class MockContentControllerDelayed : public MockContentController {
127
public:
128
  MockContentControllerDelayed()
129
    : mTime(GetStartupTime())
130
0
  {
131
0
  }
132
133
0
  const TimeStamp& Time() {
134
0
    return mTime;
135
0
  }
136
137
0
  void AdvanceByMillis(int aMillis) {
138
0
    AdvanceBy(TimeDuration::FromMilliseconds(aMillis));
139
0
  }
140
141
0
  void AdvanceBy(const TimeDuration& aIncrement) {
142
0
    TimeStamp target = mTime + aIncrement;
143
0
    while (mTaskQueue.Length() > 0 && mTaskQueue[0].second <= target) {
144
0
      RunNextDelayedTask();
145
0
    }
146
0
    mTime = target;
147
0
  }
148
149
0
  void PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs) {
150
0
    RefPtr<Runnable> task = aTask;
151
0
    TimeStamp runAtTime = mTime + TimeDuration::FromMilliseconds(aDelayMs);
152
0
    int insIndex = mTaskQueue.Length();
153
0
    while (insIndex > 0) {
154
0
      if (mTaskQueue[insIndex - 1].second <= runAtTime) {
155
0
        break;
156
0
      }
157
0
      insIndex--;
158
0
    }
159
0
    mTaskQueue.InsertElementAt(insIndex, std::make_pair(task, runAtTime));
160
0
  }
161
162
  // Run all the tasks in the queue, returning the number of tasks
163
  // run. Note that if a task queues another task while running, that
164
  // new task will not be run. Therefore, there may be still be tasks
165
  // in the queue after this function is called. Only when the return
166
  // value is 0 is the queue guaranteed to be empty.
167
0
  int RunThroughDelayedTasks() {
168
0
    nsTArray<std::pair<RefPtr<Runnable>, TimeStamp>> runQueue;
169
0
    runQueue.SwapElements(mTaskQueue);
170
0
    int numTasks = runQueue.Length();
171
0
    for (int i = 0; i < numTasks; i++) {
172
0
      mTime = runQueue[i].second;
173
0
      runQueue[i].first->Run();
174
0
175
0
      // Deleting the task is important in order to release the reference to
176
0
      // the callee object.
177
0
      runQueue[i].first = nullptr;
178
0
    }
179
0
    return numTasks;
180
0
  }
181
182
private:
183
0
  void RunNextDelayedTask() {
184
0
    std::pair<RefPtr<Runnable>, TimeStamp> next = mTaskQueue[0];
185
0
    mTaskQueue.RemoveElementAt(0);
186
0
    mTime = next.second;
187
0
    next.first->Run();
188
0
    // Deleting the task is important in order to release the reference to
189
0
    // the callee object.
190
0
    next.first = nullptr;
191
0
  }
192
193
  // The following array is sorted by timestamp (tasks are inserted in order by
194
  // timestamp).
195
  nsTArray<std::pair<RefPtr<Runnable>, TimeStamp>> mTaskQueue;
196
  TimeStamp mTime;
197
};
198
199
class TestAPZCTreeManager : public APZCTreeManager {
200
public:
201
  explicit TestAPZCTreeManager(MockContentControllerDelayed* aMcc)
202
    : APZCTreeManager(LayersId{0})
203
    , mcc(aMcc)
204
0
  {}
205
206
0
  RefPtr<InputQueue> GetInputQueue() const {
207
0
    return mInputQueue;
208
0
  }
209
210
0
  void ClearContentController() {
211
0
    mcc = nullptr;
212
0
  }
213
214
  /**
215
   * This function is not currently implemented.
216
   * See bug 1468804 for more information.
217
   **/
218
0
  void CancelAnimation() {
219
0
    EXPECT_TRUE(false);
220
0
  }
221
222
protected:
223
  AsyncPanZoomController* NewAPZCInstance(LayersId aLayersId,
224
                                          GeckoContentController* aController) override;
225
226
0
  TimeStamp GetFrameTime() override {
227
0
    return mcc->Time();
228
0
  }
229
230
231
private:
232
  RefPtr<MockContentControllerDelayed> mcc;
233
};
234
235
class TestAsyncPanZoomController : public AsyncPanZoomController {
236
public:
237
  TestAsyncPanZoomController(LayersId aLayersId, MockContentControllerDelayed* aMcc,
238
                             TestAPZCTreeManager* aTreeManager,
239
                             GestureBehavior aBehavior = DEFAULT_GESTURES)
240
    : AsyncPanZoomController(aLayersId, aTreeManager, aTreeManager->GetInputQueue(),
241
        aMcc, aBehavior)
242
    , mWaitForMainThread(false)
243
    , mcc(aMcc)
244
0
  {}
245
246
0
  nsEventStatus ReceiveInputEvent(const InputData& aEvent, ScrollableLayerGuid* aDummy, uint64_t* aOutInputBlockId) {
247
0
    // This is a function whose signature matches exactly the ReceiveInputEvent
248
0
    // on APZCTreeManager. This allows us to templates for functions like
249
0
    // TouchDown, TouchUp, etc so that we can reuse the code for dispatching
250
0
    // events into both APZC and APZCTM.
251
0
    return ReceiveInputEvent(aEvent, aOutInputBlockId);
252
0
  }
253
254
0
  nsEventStatus ReceiveInputEvent(const InputData& aEvent, uint64_t* aOutInputBlockId) {
255
0
    return GetInputQueue()->ReceiveInputEvent(this, TargetConfirmationFlags{!mWaitForMainThread}, aEvent, aOutInputBlockId);
256
0
  }
257
258
0
  void ContentReceivedInputBlock(uint64_t aInputBlockId, bool aPreventDefault) {
259
0
    GetInputQueue()->ContentReceivedInputBlock(aInputBlockId, aPreventDefault);
260
0
  }
261
262
0
  void ConfirmTarget(uint64_t aInputBlockId) {
263
0
    RefPtr<AsyncPanZoomController> target = this;
264
0
    GetInputQueue()->SetConfirmedTargetApzc(aInputBlockId, target);
265
0
  }
266
267
0
  void SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aBehaviors) {
268
0
    GetInputQueue()->SetAllowedTouchBehavior(aInputBlockId, aBehaviors);
269
0
  }
270
271
0
  void SetFrameMetrics(const FrameMetrics& metrics) {
272
0
    RecursiveMutexAutoLock lock(mRecursiveMutex);
273
0
    Metrics() = metrics;
274
0
  }
275
276
0
  FrameMetrics& GetFrameMetrics() {
277
0
    RecursiveMutexAutoLock lock(mRecursiveMutex);
278
0
    return mScrollMetadata.GetMetrics();
279
0
  }
280
281
0
  ScrollMetadata& GetScrollMetadata() {
282
0
    RecursiveMutexAutoLock lock(mRecursiveMutex);
283
0
    return mScrollMetadata;
284
0
  }
285
286
0
  const FrameMetrics& GetFrameMetrics() const {
287
0
    RecursiveMutexAutoLock lock(mRecursiveMutex);
288
0
    return mScrollMetadata.GetMetrics();
289
0
  }
290
291
  using AsyncPanZoomController::GetVelocityVector;
292
293
0
  void AssertStateIsReset() const {
294
0
    RecursiveMutexAutoLock lock(mRecursiveMutex);
295
0
    EXPECT_EQ(NOTHING, mState);
296
0
  }
297
298
0
  void AssertStateIsFling() const {
299
0
    RecursiveMutexAutoLock lock(mRecursiveMutex);
300
0
    EXPECT_EQ(FLING, mState);
301
0
  }
302
303
0
  void AssertStateIsSmoothScroll() const {
304
0
    RecursiveMutexAutoLock lock(mRecursiveMutex);
305
0
    EXPECT_EQ(SMOOTH_SCROLL, mState);
306
0
  }
307
308
0
  void AssertNotAxisLocked() const {
309
0
    RecursiveMutexAutoLock lock(mRecursiveMutex);
310
0
    EXPECT_EQ(PANNING, mState);
311
0
  }
312
313
0
  void AssertAxisLocked(ScrollDirection aDirection) const {
314
0
    RecursiveMutexAutoLock lock(mRecursiveMutex);
315
0
    switch (aDirection) {
316
0
    case ScrollDirection::eHorizontal:
317
0
      EXPECT_EQ(PANNING_LOCKED_X, mState);
318
0
      break;
319
0
    case ScrollDirection::eVertical:
320
0
      EXPECT_EQ(PANNING_LOCKED_Y, mState);
321
0
      break;
322
0
    }
323
0
  }
324
325
0
  void AdvanceAnimationsUntilEnd(const TimeDuration& aIncrement = TimeDuration::FromMilliseconds(10)) {
326
0
    while (AdvanceAnimations(mcc->Time())) {
327
0
      mcc->AdvanceBy(aIncrement);
328
0
    }
329
0
  }
330
331
  bool SampleContentTransformForFrame(AsyncTransform* aOutTransform,
332
                                      ParentLayerPoint& aScrollOffset,
333
0
                                      const TimeDuration& aIncrement = TimeDuration::FromMilliseconds(0)) {
334
0
    mcc->AdvanceBy(aIncrement);
335
0
    bool ret = AdvanceAnimations(mcc->Time());
336
0
    if (aOutTransform) {
337
0
      *aOutTransform = GetCurrentAsyncTransform(AsyncPanZoomController::eForHitTesting);
338
0
    }
339
0
    aScrollOffset = GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting);
340
0
    return ret;
341
0
  }
342
343
0
  void SetWaitForMainThread() {
344
0
    mWaitForMainThread = true;
345
0
  }
346
347
private:
348
  bool mWaitForMainThread;
349
  MockContentControllerDelayed* mcc;
350
};
351
352
class APZCTesterBase : public ::testing::Test {
353
public:
354
0
  APZCTesterBase() {
355
0
    mcc = new NiceMock<MockContentControllerDelayed>();
356
0
  }
357
358
  enum class PanOptions {
359
    None = 0,
360
    KeepFingerDown = 0x1,
361
    /*
362
     * Do not adjust the touch-start coordinates to overcome the touch-start
363
     * tolerance threshold. If this option is passed, it's up to the caller
364
     * to pass in coordinates that are sufficient to overcome the touch-start
365
     * tolerance *and* cause the desired amount of scrolling.
366
     */
367
    ExactCoordinates = 0x2,
368
    NoFling = 0x4
369
  };
370
371
  enum class PinchOptions {
372
    None = 0,
373
    LiftFinger1 = 0x1,
374
    LiftFinger2 = 0x2,
375
    /*
376
     * The bitwise OR result of (LiftFinger1 | LiftFinger2).
377
     * Defined explicitly here because it is used as the default
378
     * argument for PinchWithTouchInput which is defined BEFORE the
379
     * definition of operator| for this class.
380
     */
381
    LiftBothFingers = 0x3
382
  };
383
384
  template<class InputReceiver>
385
  void Tap(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
386
           TimeDuration aTapLength,
387
           nsEventStatus (*aOutEventStatuses)[2] = nullptr,
388
           uint64_t* aOutInputBlockId = nullptr);
389
390
  template<class InputReceiver>
391
  void TapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
392
                         const ScreenIntPoint& aPoint, TimeDuration aTapLength);
393
394
  template<class InputReceiver>
395
  void Pan(const RefPtr<InputReceiver>& aTarget,
396
           const ScreenIntPoint& aTouchStart,
397
           const ScreenIntPoint& aTouchEnd,
398
           PanOptions aOptions = PanOptions::None,
399
           nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
400
           nsEventStatus (*aOutEventStatuses)[4] = nullptr,
401
           uint64_t* aOutInputBlockId = nullptr);
402
403
  /*
404
   * A version of Pan() that only takes y coordinates rather than (x, y) points
405
   * for the touch start and end points, and uses 10 for the x coordinates.
406
   * This is for convenience, as most tests only need to pan in one direction.
407
  */
408
  template<class InputReceiver>
409
  void Pan(const RefPtr<InputReceiver>& aTarget, int aTouchStartY,
410
           int aTouchEndY, PanOptions aOptions = PanOptions::None,
411
           nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
412
           nsEventStatus (*aOutEventStatuses)[4] = nullptr,
413
           uint64_t* aOutInputBlockId = nullptr);
414
415
  /*
416
   * Dispatches mock touch events to the apzc and checks whether apzc properly
417
   * consumed them and triggered scrolling behavior.
418
  */
419
  template<class InputReceiver>
420
  void PanAndCheckStatus(const RefPtr<InputReceiver>& aTarget, int aTouchStartY,
421
                         int aTouchEndY,
422
                         bool aExpectConsumed,
423
                         nsTArray<uint32_t>* aAllowedTouchBehaviors,
424
                         uint64_t* aOutInputBlockId = nullptr);
425
426
  template<class InputReceiver>
427
  void DoubleTap(const RefPtr<InputReceiver>& aTarget,
428
                 const ScreenIntPoint& aPoint,
429
                 nsEventStatus (*aOutEventStatuses)[4] = nullptr,
430
                 uint64_t (*aOutInputBlockIds)[2] = nullptr);
431
432
  template<class InputReceiver>
433
  void DoubleTapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
434
                               const ScreenIntPoint& aPoint,
435
                               uint64_t (*aOutInputBlockIds)[2] = nullptr);
436
437
  template<class InputReceiver>
438
  void PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
439
                           const ScreenIntPoint& aFocus, const ScreenIntPoint& aSecondFocus,
440
                           float aScale,
441
                           int& inputId,
442
                           nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
443
                           nsEventStatus (*aOutEventStatuses)[4] = nullptr,
444
                           uint64_t* aOutInputBlockId = nullptr,
445
                           PinchOptions aOptions = PinchOptions::LiftBothFingers);
446
447
  // Pinch with one focus point. Zooms in place with no panning
448
  template<class InputReceiver>
449
  void PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
450
                           const ScreenIntPoint& aFocus, float aScale,
451
                           int& inputId,
452
                           nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
453
                           nsEventStatus (*aOutEventStatuses)[4] = nullptr,
454
                           uint64_t* aOutInputBlockId = nullptr,
455
                           PinchOptions aOptions = PinchOptions::LiftBothFingers);
456
457
  template<class InputReceiver>
458
  void PinchWithTouchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
459
                                         const ScreenIntPoint& aFocus, float aScale,
460
                                         int& inputId, bool aShouldTriggerPinch,
461
                                         nsTArray<uint32_t>* aAllowedTouchBehaviors);
462
463
protected:
464
  RefPtr<MockContentControllerDelayed> mcc;
465
};
466
467
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(APZCTesterBase::PanOptions)
468
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(APZCTesterBase::PinchOptions)
469
470
template<class InputReceiver>
471
void
472
APZCTesterBase::Tap(const RefPtr<InputReceiver>& aTarget,
473
                    const ScreenIntPoint& aPoint, TimeDuration aTapLength,
474
                    nsEventStatus (*aOutEventStatuses)[2],
475
                    uint64_t* aOutInputBlockId)
476
0
{
477
0
  // Even if the caller doesn't care about the block id, we need it to set the
478
0
  // allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
479
0
  uint64_t blockId;
480
0
  if (!aOutInputBlockId) {
481
0
    aOutInputBlockId = &blockId;
482
0
  }
483
0
484
0
  nsEventStatus status = TouchDown(aTarget, aPoint, mcc->Time(), aOutInputBlockId);
485
0
  if (aOutEventStatuses) {
486
0
    (*aOutEventStatuses)[0] = status;
487
0
  }
488
0
  mcc->AdvanceBy(aTapLength);
489
0
490
0
  // If touch-action is enabled then simulate the allowed touch behaviour
491
0
  // notification that the main thread is supposed to deliver.
492
0
  if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
493
0
    SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId);
494
0
  }
495
0
496
0
  status = TouchUp(aTarget, aPoint, mcc->Time());
497
0
  if (aOutEventStatuses) {
498
0
    (*aOutEventStatuses)[1] = status;
499
0
  }
500
0
}
Unexecuted instantiation: void APZCTesterBase::Tap<TestAPZCTreeManager>(RefPtr<TestAPZCTreeManager> const&, mozilla::gfx::IntPointTyped<mozilla::ScreenPixel> const&, mozilla::BaseTimeDuration<mozilla::TimeDurationValueCalculator>, nsEventStatus (*) [2], unsigned long*)
Unexecuted instantiation: void APZCTesterBase::Tap<TestAsyncPanZoomController>(RefPtr<TestAsyncPanZoomController> const&, mozilla::gfx::IntPointTyped<mozilla::ScreenPixel> const&, mozilla::BaseTimeDuration<mozilla::TimeDurationValueCalculator>, nsEventStatus (*) [2], unsigned long*)
501
502
template<class InputReceiver>
503
void
504
APZCTesterBase::TapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
505
                                  const ScreenIntPoint& aPoint,
506
                                  TimeDuration aTapLength)
507
0
{
508
0
  nsEventStatus statuses[2];
509
0
  Tap(aTarget, aPoint, aTapLength, &statuses);
510
0
  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
511
0
  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[1]);
512
0
}
513
514
template<class InputReceiver>
515
void
516
APZCTesterBase::Pan(const RefPtr<InputReceiver>& aTarget,
517
                    const ScreenIntPoint& aTouchStart,
518
                    const ScreenIntPoint& aTouchEnd,
519
                    PanOptions aOptions,
520
                    nsTArray<uint32_t>* aAllowedTouchBehaviors,
521
                    nsEventStatus (*aOutEventStatuses)[4],
522
                    uint64_t* aOutInputBlockId)
523
0
{
524
0
  // Reduce the touch start and move tolerance to a tiny value.
525
0
  // We can't use a scoped pref because this value might be read at some later
526
0
  // time when the events are actually processed, rather than when we deliver
527
0
  // them.
528
0
  gfxPrefs::SetAPZTouchStartTolerance(1.0f / 1000.0f);
529
0
  gfxPrefs::SetAPZTouchMoveTolerance(0.0f);
530
0
  int overcomeTouchToleranceX = 0;
531
0
  int overcomeTouchToleranceY = 0;
532
0
  if (!(aOptions & PanOptions::ExactCoordinates)) {
533
0
    // Have the direction of the adjustment to overcome the touch tolerance
534
0
    // match the direction of the entire gesture, otherwise we run into
535
0
    // trouble such as accidentally activating the axis lock.
536
0
    if (aTouchStart.x != aTouchEnd.x) {
537
0
      overcomeTouchToleranceX = 1;
538
0
    }
539
0
    if (aTouchStart.y != aTouchEnd.y) {
540
0
      overcomeTouchToleranceY = 1;
541
0
    }
542
0
  }
543
0
544
0
  const TimeDuration TIME_BETWEEN_TOUCH_EVENT = TimeDuration::FromMilliseconds(50);
545
0
546
0
  // Even if the caller doesn't care about the block id, we need it to set the
547
0
  // allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
548
0
  uint64_t blockId;
549
0
  if (!aOutInputBlockId) {
550
0
    aOutInputBlockId = &blockId;
551
0
  }
552
0
553
0
  // Make sure the move is large enough to not be handled as a tap
554
0
  nsEventStatus status = TouchDown(aTarget,
555
0
      ScreenIntPoint(aTouchStart.x + overcomeTouchToleranceX,
556
0
                     aTouchStart.y + overcomeTouchToleranceY),
557
0
      mcc->Time(), aOutInputBlockId);
558
0
  if (aOutEventStatuses) {
559
0
    (*aOutEventStatuses)[0] = status;
560
0
  }
561
0
562
0
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
563
0
564
0
  // Allowed touch behaviours must be set after sending touch-start.
565
0
  if (status != nsEventStatus_eConsumeNoDefault) {
566
0
    if (aAllowedTouchBehaviors) {
567
0
      EXPECT_EQ(1UL, aAllowedTouchBehaviors->Length());
568
0
      aTarget->SetAllowedTouchBehavior(*aOutInputBlockId, *aAllowedTouchBehaviors);
569
0
    } else if (gfxPrefs::TouchActionEnabled()) {
570
0
      SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId);
571
0
    }
572
0
  }
573
0
574
0
  status = TouchMove(aTarget, aTouchStart, mcc->Time());
575
0
  if (aOutEventStatuses) {
576
0
    (*aOutEventStatuses)[1] = status;
577
0
  }
578
0
579
0
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
580
0
581
0
  status = TouchMove(aTarget, aTouchEnd, mcc->Time());
582
0
  if (aOutEventStatuses) {
583
0
    (*aOutEventStatuses)[2] = status;
584
0
  }
585
0
586
0
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
587
0
588
0
  if (!(aOptions & PanOptions::KeepFingerDown)) {
589
0
    status = TouchUp(aTarget, aTouchEnd, mcc->Time());
590
0
  } else {
591
0
    status = nsEventStatus_eIgnore;
592
0
  }
593
0
  if (aOutEventStatuses) {
594
0
    (*aOutEventStatuses)[3] = status;
595
0
  }
596
0
597
0
  if ((aOptions & PanOptions::NoFling)) {
598
0
    aTarget->CancelAnimation();
599
0
  }
600
0
601
0
  // Don't increment the time here. Animations started on touch-up, such as
602
0
  // flings, are affected by elapsed time, and we want to be able to sample
603
0
  // them immediately after they start, without time having elapsed.
604
0
}
Unexecuted instantiation: void APZCTesterBase::Pan<TestAsyncPanZoomController>(RefPtr<TestAsyncPanZoomController> const&, mozilla::gfx::IntPointTyped<mozilla::ScreenPixel> const&, mozilla::gfx::IntPointTyped<mozilla::ScreenPixel> const&, APZCTesterBase::PanOptions, nsTArray<unsigned int>*, nsEventStatus (*) [4], unsigned long*)
Unexecuted instantiation: void APZCTesterBase::Pan<TestAPZCTreeManager>(RefPtr<TestAPZCTreeManager> const&, mozilla::gfx::IntPointTyped<mozilla::ScreenPixel> const&, mozilla::gfx::IntPointTyped<mozilla::ScreenPixel> const&, APZCTesterBase::PanOptions, nsTArray<unsigned int>*, nsEventStatus (*) [4], unsigned long*)
605
606
template<class InputReceiver>
607
void
608
APZCTesterBase::Pan(const RefPtr<InputReceiver>& aTarget,
609
                    int aTouchStartY, int aTouchEndY, PanOptions aOptions,
610
                    nsTArray<uint32_t>* aAllowedTouchBehaviors,
611
                    nsEventStatus (*aOutEventStatuses)[4],
612
                    uint64_t* aOutInputBlockId)
613
0
{
614
0
  Pan(aTarget, ScreenIntPoint(10, aTouchStartY), ScreenIntPoint(10, aTouchEndY),
615
0
      aOptions, aAllowedTouchBehaviors, aOutEventStatuses, aOutInputBlockId);
616
0
}
Unexecuted instantiation: void APZCTesterBase::Pan<TestAsyncPanZoomController>(RefPtr<TestAsyncPanZoomController> const&, int, int, APZCTesterBase::PanOptions, nsTArray<unsigned int>*, nsEventStatus (*) [4], unsigned long*)
Unexecuted instantiation: void APZCTesterBase::Pan<TestAPZCTreeManager>(RefPtr<TestAPZCTreeManager> const&, int, int, APZCTesterBase::PanOptions, nsTArray<unsigned int>*, nsEventStatus (*) [4], unsigned long*)
617
618
template<class InputReceiver>
619
void
620
APZCTesterBase::PanAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
621
                                  int aTouchStartY,
622
                                  int aTouchEndY,
623
                                  bool aExpectConsumed,
624
                                  nsTArray<uint32_t>* aAllowedTouchBehaviors,
625
                                  uint64_t* aOutInputBlockId)
626
0
{
627
0
  nsEventStatus statuses[4]; // down, move, move, up
628
0
  Pan(aTarget, aTouchStartY, aTouchEndY, PanOptions::None, aAllowedTouchBehaviors, &statuses, aOutInputBlockId);
629
0
630
0
  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
631
0
632
0
  nsEventStatus touchMoveStatus;
633
0
  if (aExpectConsumed) {
634
0
    touchMoveStatus = nsEventStatus_eConsumeDoDefault;
635
0
  } else {
636
0
    touchMoveStatus = nsEventStatus_eIgnore;
637
0
  }
638
0
  EXPECT_EQ(touchMoveStatus, statuses[1]);
639
0
  EXPECT_EQ(touchMoveStatus, statuses[2]);
640
0
}
641
642
template<class InputReceiver>
643
void
644
APZCTesterBase::DoubleTap(const RefPtr<InputReceiver>& aTarget,
645
                          const ScreenIntPoint& aPoint,
646
                          nsEventStatus (*aOutEventStatuses)[4],
647
                          uint64_t (*aOutInputBlockIds)[2])
648
0
{
649
0
  uint64_t blockId;
650
0
  nsEventStatus status = TouchDown(aTarget, aPoint, mcc->Time(), &blockId);
651
0
  if (aOutEventStatuses) {
652
0
    (*aOutEventStatuses)[0] = status;
653
0
  }
654
0
  if (aOutInputBlockIds) {
655
0
    (*aOutInputBlockIds)[0] = blockId;
656
0
  }
657
0
  mcc->AdvanceByMillis(10);
658
0
659
0
  // If touch-action is enabled then simulate the allowed touch behaviour
660
0
  // notification that the main thread is supposed to deliver.
661
0
  if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
662
0
    SetDefaultAllowedTouchBehavior(aTarget, blockId);
663
0
  }
664
0
665
0
  status = TouchUp(aTarget, aPoint, mcc->Time());
666
0
  if (aOutEventStatuses) {
667
0
    (*aOutEventStatuses)[1] = status;
668
0
  }
669
0
  mcc->AdvanceByMillis(10);
670
0
  status = TouchDown(aTarget, aPoint, mcc->Time(), &blockId);
671
0
  if (aOutEventStatuses) {
672
0
    (*aOutEventStatuses)[2] = status;
673
0
  }
674
0
  if (aOutInputBlockIds) {
675
0
    (*aOutInputBlockIds)[1] = blockId;
676
0
  }
677
0
  mcc->AdvanceByMillis(10);
678
0
679
0
  if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
680
0
    SetDefaultAllowedTouchBehavior(aTarget, blockId);
681
0
  }
682
0
683
0
  status = TouchUp(aTarget, aPoint, mcc->Time());
684
0
  if (aOutEventStatuses) {
685
0
    (*aOutEventStatuses)[3] = status;
686
0
  }
687
0
}
688
689
template<class InputReceiver>
690
void
691
APZCTesterBase::DoubleTapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
692
                                        const ScreenIntPoint& aPoint,
693
                                        uint64_t (*aOutInputBlockIds)[2])
694
0
{
695
0
  nsEventStatus statuses[4];
696
0
  DoubleTap(aTarget, aPoint, &statuses, aOutInputBlockIds);
697
0
  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
698
0
  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[1]);
699
0
  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[2]);
700
0
  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[3]);
701
0
}
702
703
template<class InputReceiver>
704
void
705
APZCTesterBase::PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
706
                                    const ScreenIntPoint& aFocus, float aScale,
707
                                    int& inputId,
708
                                    nsTArray<uint32_t>* aAllowedTouchBehaviors,
709
                                    nsEventStatus (*aOutEventStatuses)[4],
710
                                    uint64_t* aOutInputBlockId,
711
                                    PinchOptions aOptions)
712
0
{
713
0
  //Perform a pinch gesture with the same start & end focus point
714
0
  PinchWithTouchInput(aTarget, aFocus, aFocus, aScale, inputId,
715
0
                      aAllowedTouchBehaviors, aOutEventStatuses,
716
0
                      aOutInputBlockId, aOptions);
717
0
}
718
719
template<class InputReceiver>
720
void
721
APZCTesterBase::PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
722
                                    const ScreenIntPoint& aFocus, const ScreenIntPoint& aSecondFocus,
723
                                    float aScale,
724
                                    int& inputId,
725
                                    nsTArray<uint32_t>* aAllowedTouchBehaviors,
726
                                    nsEventStatus (*aOutEventStatuses)[4],
727
                                    uint64_t* aOutInputBlockId,
728
                                    PinchOptions aOptions)
729
0
{
730
0
  // Having pinch coordinates in float type may cause problems with high-precision scale values
731
0
  // since SingleTouchData accepts integer value. But for trivial tests it should be ok.
732
0
  float pinchLength = 100.0;
733
0
  float pinchLengthScaled = pinchLength * aScale;
734
0
735
0
  // Even if the caller doesn't care about the block id, we need it to set the
736
0
  // allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
737
0
  uint64_t blockId;
738
0
  if (!aOutInputBlockId) {
739
0
    aOutInputBlockId = &blockId;
740
0
  }
741
0
742
0
  const TimeDuration TIME_BETWEEN_TOUCH_EVENT = TimeDuration::FromMilliseconds(50);
743
0
744
0
  MultiTouchInput mtiStart = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, mcc->Time(), 0);
745
0
  mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus));
746
0
  mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus));
747
0
  nsEventStatus status = aTarget->ReceiveInputEvent(mtiStart, aOutInputBlockId);
748
0
  if (aOutEventStatuses) {
749
0
    (*aOutEventStatuses)[0] = status;
750
0
  }
751
0
752
0
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
753
0
754
0
  if (aAllowedTouchBehaviors) {
755
0
    EXPECT_EQ(2UL, aAllowedTouchBehaviors->Length());
756
0
    aTarget->SetAllowedTouchBehavior(*aOutInputBlockId, *aAllowedTouchBehaviors);
757
0
  } else if (gfxPrefs::TouchActionEnabled()) {
758
0
    SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId, 2);
759
0
  }
760
0
761
0
  MultiTouchInput mtiMove1 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
762
0
  mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLength, aFocus.y));
763
0
  mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLength, aFocus.y));
764
0
  status = aTarget->ReceiveInputEvent(mtiMove1, nullptr);
765
0
  if (aOutEventStatuses) {
766
0
    (*aOutEventStatuses)[1] = status;
767
0
  }
768
0
769
0
  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
770
0
771
0
  MultiTouchInput mtiMove2 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
772
0
  mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, aSecondFocus.x - pinchLengthScaled, aSecondFocus.y));
773
0
  mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aSecondFocus.x + pinchLengthScaled, aSecondFocus.y));
774
0
  status = aTarget->ReceiveInputEvent(mtiMove2, nullptr);
775
0
  if (aOutEventStatuses) {
776
0
    (*aOutEventStatuses)[2] = status;
777
0
  }
778
0
779
0
  if (aOptions & (PinchOptions::LiftFinger1 | PinchOptions::LiftFinger2)) {
780
0
    mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
781
0
782
0
    MultiTouchInput mtiEnd = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, mcc->Time(), 0);
783
0
    if (aOptions & PinchOptions::LiftFinger1) {
784
0
      mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, aSecondFocus.x - pinchLengthScaled, aSecondFocus.y));
785
0
    }
786
0
    if (aOptions & PinchOptions::LiftFinger2) {
787
0
      mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aSecondFocus.x + pinchLengthScaled, aSecondFocus.y));
788
0
    }
789
0
    status = aTarget->ReceiveInputEvent(mtiEnd, nullptr);
790
0
    if (aOutEventStatuses) {
791
0
      (*aOutEventStatuses)[3] = status;
792
0
    }
793
0
  }
794
0
795
0
  inputId += 2;
796
0
}
797
798
template<class InputReceiver>
799
void
800
APZCTesterBase::PinchWithTouchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
801
                                                  const ScreenIntPoint& aFocus, float aScale,
802
                                                  int& inputId, bool aShouldTriggerPinch,
803
                                                  nsTArray<uint32_t>* aAllowedTouchBehaviors)
804
0
{
805
0
  nsEventStatus statuses[4];  // down, move, move, up
806
0
  PinchWithTouchInput(aTarget, aFocus, aScale, inputId, aAllowedTouchBehaviors, &statuses);
807
0
808
0
  nsEventStatus expectedMoveStatus = aShouldTriggerPinch
809
0
      ? nsEventStatus_eConsumeDoDefault
810
0
      : nsEventStatus_eIgnore;
811
0
  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
812
0
  EXPECT_EQ(expectedMoveStatus, statuses[1]);
813
0
  EXPECT_EQ(expectedMoveStatus, statuses[2]);
814
0
}
815
816
AsyncPanZoomController*
817
TestAPZCTreeManager::NewAPZCInstance(LayersId aLayersId,
818
                                     GeckoContentController* aController)
819
0
{
820
0
  MockContentControllerDelayed* mcc = static_cast<MockContentControllerDelayed*>(aController);
821
0
  return new TestAsyncPanZoomController(aLayersId, mcc, this,
822
0
      AsyncPanZoomController::USE_GESTURE_DETECTOR);
823
0
}
824
825
FrameMetrics
826
TestFrameMetrics()
827
0
{
828
0
  FrameMetrics fm;
829
0
830
0
  fm.SetDisplayPort(CSSRect(0, 0, 10, 10));
831
0
  fm.SetCompositionBounds(ParentLayerRect(0, 0, 10, 10));
832
0
  fm.SetCriticalDisplayPort(CSSRect(0, 0, 10, 10));
833
0
  fm.SetScrollableRect(CSSRect(0, 0, 100, 100));
834
0
835
0
  return fm;
836
0
}
837
838
uint32_t
839
MillisecondsSinceStartup(TimeStamp aTime)
840
0
{
841
0
  return (aTime - GetStartupTime()).ToMilliseconds();
842
0
}
843
844
#endif // mozilla_layers_APZTestCommon_h