Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/apz/test/gtest/TestScrollHandoff.cpp
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
#include "APZCTreeManagerTester.h"
8
#include "APZTestCommon.h"
9
#include "InputUtils.h"
10
11
class APZScrollHandoffTester : public APZCTreeManagerTester {
12
protected:
13
  UniquePtr<ScopedLayerTreeRegistration> registration;
14
  TestAsyncPanZoomController* rootApzc;
15
16
0
  void CreateScrollHandoffLayerTree1() {
17
0
    const char* layerTreeSyntax = "c(t)";
18
0
    nsIntRegion layerVisibleRegion[] = {
19
0
      nsIntRegion(IntRect(0, 0, 100, 100)),
20
0
      nsIntRegion(IntRect(0, 50, 100, 50))
21
0
    };
22
0
    root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
23
0
    SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
24
0
    SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 100, 100));
25
0
    SetScrollHandoff(layers[1], root);
26
0
    registration = MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
27
0
    manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
28
0
    rootApzc = ApzcOf(root);
29
0
    rootApzc->GetFrameMetrics().SetIsRootContent(true);  // make root APZC zoomable
30
0
  }
31
32
0
  void CreateScrollHandoffLayerTree2() {
33
0
    const char* layerTreeSyntax = "c(c(t))";
34
0
    nsIntRegion layerVisibleRegion[] = {
35
0
      nsIntRegion(IntRect(0, 0, 100, 100)),
36
0
      nsIntRegion(IntRect(0, 0, 100, 100)),
37
0
      nsIntRegion(IntRect(0, 50, 100, 50))
38
0
    };
39
0
    root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
40
0
    SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
41
0
    SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 2, CSSRect(-100, -100, 200, 200));
42
0
    SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 100, 100));
43
0
    SetScrollHandoff(layers[1], root);
44
0
    SetScrollHandoff(layers[2], layers[1]);
45
0
    // No ScopedLayerTreeRegistration as that just needs to be done once per test
46
0
    // and this is the second layer tree for a particular test.
47
0
    MOZ_ASSERT(registration);
48
0
    manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
49
0
    rootApzc = ApzcOf(root);
50
0
  }
51
52
0
  void CreateScrollHandoffLayerTree3() {
53
0
    const char* layerTreeSyntax = "c(c(t)c(t))";
54
0
    nsIntRegion layerVisibleRegion[] = {
55
0
      nsIntRegion(IntRect(0, 0, 100, 100)),  // root
56
0
      nsIntRegion(IntRect(0, 0, 100, 50)),   // scrolling parent 1
57
0
      nsIntRegion(IntRect(0, 0, 100, 50)),   // scrolling child 1
58
0
      nsIntRegion(IntRect(0, 50, 100, 50)),  // scrolling parent 2
59
0
      nsIntRegion(IntRect(0, 50, 100, 50))   // scrolling child 2
60
0
    };
61
0
    root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
62
0
    SetScrollableFrameMetrics(layers[0], FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 100, 100));
63
0
    SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 100, 100));
64
0
    SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 2, CSSRect(0, 0, 100, 100));
65
0
    SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 3, CSSRect(0, 50, 100, 100));
66
0
    SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 4, CSSRect(0, 50, 100, 100));
67
0
    SetScrollHandoff(layers[1], layers[0]);
68
0
    SetScrollHandoff(layers[3], layers[0]);
69
0
    SetScrollHandoff(layers[2], layers[1]);
70
0
    SetScrollHandoff(layers[4], layers[3]);
71
0
    registration = MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
72
0
    manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
73
0
  }
74
75
  // Creates a layer tree with a parent layer that is only scrollable
76
  // horizontally, and a child layer that is only scrollable vertically.
77
0
  void CreateScrollHandoffLayerTree4() {
78
0
    const char* layerTreeSyntax = "c(t)";
79
0
    nsIntRegion layerVisibleRegion[] = {
80
0
      nsIntRegion(IntRect(0, 0, 100, 100)),
81
0
      nsIntRegion(IntRect(0, 0, 100, 100))
82
0
    };
83
0
    root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
84
0
    SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 100));
85
0
    SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 100, 200));
86
0
    SetScrollHandoff(layers[1], root);
87
0
    registration = MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
88
0
    manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
89
0
    rootApzc = ApzcOf(root);
90
0
  }
91
92
0
  void CreateScrollgrabLayerTree(bool makeParentScrollable = true) {
93
0
    const char* layerTreeSyntax = "c(t)";
94
0
    nsIntRegion layerVisibleRegion[] = {
95
0
      nsIntRegion(IntRect(0, 0, 100, 100)),  // scroll-grabbing parent
96
0
      nsIntRegion(IntRect(0, 20, 100, 80))   // child
97
0
    };
98
0
    root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
99
0
    float parentHeight = makeParentScrollable ? 120 : 100;
100
0
    SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 100, parentHeight));
101
0
    SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 100, 200));
102
0
    SetScrollHandoff(layers[1], root);
103
0
    registration = MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
104
0
    manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
105
0
    rootApzc = ApzcOf(root);
106
0
    rootApzc->GetScrollMetadata().SetHasScrollgrab(true);
107
0
  }
108
109
0
  void TestFlingAcceleration() {
110
0
    // Jack up the fling acceleration multiplier so we can easily determine
111
0
    // whether acceleration occured.
112
0
    const float kAcceleration = 100.0f;
113
0
    SCOPED_GFX_PREF(APZFlingAccelBaseMultiplier, float, kAcceleration);
114
0
    SCOPED_GFX_PREF(APZFlingAccelMinVelocity, float, 0.0);
115
0
116
0
    RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
117
0
118
0
    // Pan once, enough to fully scroll the scrollgrab parent and then scroll
119
0
    // and fling the child.
120
0
    Pan(manager, 70, 40);
121
0
122
0
    // Give the fling animation a chance to start.
123
0
    SampleAnimationsOnce();
124
0
125
0
    float childVelocityAfterFling1 = childApzc->GetVelocityVector().y;
126
0
127
0
    // Pan again.
128
0
    Pan(manager, 70, 40);
129
0
130
0
    // Give the fling animation a chance to start.
131
0
    // This time it should be accelerated.
132
0
    SampleAnimationsOnce();
133
0
134
0
    float childVelocityAfterFling2 = childApzc->GetVelocityVector().y;
135
0
136
0
    // We should have accelerated once.
137
0
    // The division by 2 is to account for friction.
138
0
    EXPECT_GT(childVelocityAfterFling2,
139
0
              childVelocityAfterFling1 * kAcceleration / 2);
140
0
141
0
    // We should not have accelerated twice.
142
0
    // The division by 4 is to account for friction.
143
0
    EXPECT_LE(childVelocityAfterFling2,
144
0
              childVelocityAfterFling1 * kAcceleration * kAcceleration / 4);
145
0
  }
146
147
0
  void TestCrossApzcAxisLock() {
148
0
    SCOPED_GFX_PREF(APZAxisLockMode, int32_t, 1);
149
0
150
0
    CreateScrollHandoffLayerTree1();
151
0
152
0
    RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
153
0
    Pan(childApzc, ScreenIntPoint(10, 60), ScreenIntPoint(15, 90),
154
0
        PanOptions::KeepFingerDown | PanOptions::ExactCoordinates);
155
0
156
0
    childApzc->AssertAxisLocked(ScrollDirection::eVertical);
157
0
  }
158
};
159
160
// Here we test that if the processing of a touch block is deferred while we
161
// wait for content to send a prevent-default message, overscroll is still
162
// handed off correctly when the block is processed.
163
0
TEST_F(APZScrollHandoffTester, DeferredInputEventProcessing) {
164
0
  // Set up the APZC tree.
165
0
  CreateScrollHandoffLayerTree1();
166
0
167
0
  RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
168
0
169
0
  // Enable touch-listeners so that we can separate the queueing of input
170
0
  // events from them being processed.
171
0
  childApzc->SetWaitForMainThread();
172
0
173
0
  // Queue input events for a pan.
174
0
  uint64_t blockId = 0;
175
0
  Pan(childApzc, 90, 30, PanOptions::NoFling, nullptr, nullptr, &blockId);
176
0
177
0
  // Allow the pan to be processed.
178
0
  childApzc->ContentReceivedInputBlock(blockId, false);
179
0
  childApzc->ConfirmTarget(blockId);
180
0
181
0
  // Make sure overscroll was handed off correctly.
182
0
  EXPECT_EQ(50, childApzc->GetFrameMetrics().GetScrollOffset().y);
183
0
  EXPECT_EQ(10, rootApzc->GetFrameMetrics().GetScrollOffset().y);
184
0
}
185
186
// Here we test that if the layer structure changes in between two input
187
// blocks being queued, and the first block is only processed after the second
188
// one has been queued, overscroll handoff for the first block follows
189
// the original layer structure while overscroll handoff for the second block
190
// follows the new layer structure.
191
0
TEST_F(APZScrollHandoffTester, LayerStructureChangesWhileEventsArePending) {
192
0
  // Set up an initial APZC tree.
193
0
  CreateScrollHandoffLayerTree1();
194
0
195
0
  RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
196
0
197
0
  // Enable touch-listeners so that we can separate the queueing of input
198
0
  // events from them being processed.
199
0
  childApzc->SetWaitForMainThread();
200
0
201
0
  // Queue input events for a pan.
202
0
  uint64_t blockId = 0;
203
0
  Pan(childApzc, 90, 30, PanOptions::NoFling, nullptr, nullptr, &blockId);
204
0
205
0
  // Modify the APZC tree to insert a new APZC 'middle' into the handoff chain
206
0
  // between the child and the root.
207
0
  CreateScrollHandoffLayerTree2();
208
0
  RefPtr<Layer> middle = layers[1];
209
0
  childApzc->SetWaitForMainThread();
210
0
  TestAsyncPanZoomController* middleApzc = ApzcOf(middle);
211
0
212
0
  // Queue input events for another pan.
213
0
  uint64_t secondBlockId = 0;
214
0
  Pan(childApzc, 30, 90, PanOptions::NoFling, nullptr, nullptr, &secondBlockId);
215
0
216
0
  // Allow the first pan to be processed.
217
0
  childApzc->ContentReceivedInputBlock(blockId, false);
218
0
  childApzc->ConfirmTarget(blockId);
219
0
220
0
  // Make sure things have scrolled according to the handoff chain in
221
0
  // place at the time the touch-start of the first pan was queued.
222
0
  EXPECT_EQ(50, childApzc->GetFrameMetrics().GetScrollOffset().y);
223
0
  EXPECT_EQ(10, rootApzc->GetFrameMetrics().GetScrollOffset().y);
224
0
  EXPECT_EQ(0, middleApzc->GetFrameMetrics().GetScrollOffset().y);
225
0
226
0
  // Allow the second pan to be processed.
227
0
  childApzc->ContentReceivedInputBlock(secondBlockId, false);
228
0
  childApzc->ConfirmTarget(secondBlockId);
229
0
230
0
  // Make sure things have scrolled according to the handoff chain in
231
0
  // place at the time the touch-start of the second pan was queued.
232
0
  EXPECT_EQ(0, childApzc->GetFrameMetrics().GetScrollOffset().y);
233
0
  EXPECT_EQ(10, rootApzc->GetFrameMetrics().GetScrollOffset().y);
234
0
  EXPECT_EQ(-10, middleApzc->GetFrameMetrics().GetScrollOffset().y);
235
0
}
236
237
// Test that putting a second finger down on an APZC while a down-chain APZC
238
// is overscrolled doesn't result in being stuck in overscroll.
239
0
TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1073250) {
240
0
  // Enable overscrolling.
241
0
  SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
242
0
  SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
243
0
  SCOPED_GFX_VAR(UseWebRender, bool, false);
244
0
245
0
  CreateScrollHandoffLayerTree1();
246
0
247
0
  TestAsyncPanZoomController* child = ApzcOf(layers[1]);
248
0
249
0
  // Pan, causing the parent APZC to overscroll.
250
0
  Pan(manager, 10, 40, PanOptions::KeepFingerDown);
251
0
  EXPECT_FALSE(child->IsOverscrolled());
252
0
  EXPECT_TRUE(rootApzc->IsOverscrolled());
253
0
254
0
  // Put a second finger down.
255
0
  MultiTouchInput secondFingerDown(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
256
0
  // Use the same touch identifier for the first touch (0) as Pan(). (A bit hacky.)
257
0
  secondFingerDown.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, 40), ScreenSize(0, 0), 0, 0));
258
0
  secondFingerDown.mTouches.AppendElement(SingleTouchData(1, ScreenIntPoint(30, 20), ScreenSize(0, 0), 0, 0));
259
0
  manager->ReceiveInputEvent(secondFingerDown, nullptr, nullptr);
260
0
261
0
  // Release the fingers.
262
0
  MultiTouchInput fingersUp = secondFingerDown;
263
0
  fingersUp.mType = MultiTouchInput::MULTITOUCH_END;
264
0
  manager->ReceiveInputEvent(fingersUp, nullptr, nullptr);
265
0
266
0
  // Allow any animations to run their course.
267
0
  child->AdvanceAnimationsUntilEnd();
268
0
  rootApzc->AdvanceAnimationsUntilEnd();
269
0
270
0
  // Make sure nothing is overscrolled.
271
0
  EXPECT_FALSE(child->IsOverscrolled());
272
0
  EXPECT_FALSE(rootApzc->IsOverscrolled());
273
0
}
274
275
// This is almost exactly like StuckInOverscroll_Bug1073250, except the
276
// APZC receiving the input events for the first touch block is the child
277
// (and thus not the same APZC that overscrolls, which is the parent).
278
0
TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1231228) {
279
0
  // Enable overscrolling.
280
0
  SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
281
0
  SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
282
0
  SCOPED_GFX_VAR(UseWebRender, bool, false);
283
0
284
0
  CreateScrollHandoffLayerTree1();
285
0
286
0
  TestAsyncPanZoomController* child = ApzcOf(layers[1]);
287
0
288
0
  // Pan, causing the parent APZC to overscroll.
289
0
  Pan(manager, 60, 90, PanOptions::KeepFingerDown);
290
0
  EXPECT_FALSE(child->IsOverscrolled());
291
0
  EXPECT_TRUE(rootApzc->IsOverscrolled());
292
0
293
0
  // Put a second finger down.
294
0
  MultiTouchInput secondFingerDown(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
295
0
  // Use the same touch identifier for the first touch (0) as Pan(). (A bit hacky.)
296
0
  secondFingerDown.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, 40), ScreenSize(0, 0), 0, 0));
297
0
  secondFingerDown.mTouches.AppendElement(SingleTouchData(1, ScreenIntPoint(30, 20), ScreenSize(0, 0), 0, 0));
298
0
  manager->ReceiveInputEvent(secondFingerDown, nullptr, nullptr);
299
0
300
0
  // Release the fingers.
301
0
  MultiTouchInput fingersUp = secondFingerDown;
302
0
  fingersUp.mType = MultiTouchInput::MULTITOUCH_END;
303
0
  manager->ReceiveInputEvent(fingersUp, nullptr, nullptr);
304
0
305
0
  // Allow any animations to run their course.
306
0
  child->AdvanceAnimationsUntilEnd();
307
0
  rootApzc->AdvanceAnimationsUntilEnd();
308
0
309
0
  // Make sure nothing is overscrolled.
310
0
  EXPECT_FALSE(child->IsOverscrolled());
311
0
  EXPECT_FALSE(rootApzc->IsOverscrolled());
312
0
}
313
314
0
TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1240202a) {
315
0
  // Enable overscrolling.
316
0
  SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
317
0
318
0
  CreateScrollHandoffLayerTree1();
319
0
320
0
  TestAsyncPanZoomController* child = ApzcOf(layers[1]);
321
0
322
0
  // Pan, causing the parent APZC to overscroll.
323
0
  Pan(manager, 60, 90, PanOptions::KeepFingerDown);
324
0
  EXPECT_FALSE(child->IsOverscrolled());
325
0
  EXPECT_TRUE(rootApzc->IsOverscrolled());
326
0
327
0
  // Lift the finger, triggering an overscroll animation
328
0
  // (but don't allow it to run).
329
0
  TouchUp(manager, ScreenIntPoint(10, 90), mcc->Time());
330
0
331
0
  // Put the finger down again, interrupting the animation
332
0
  // and entering the TOUCHING state.
333
0
  TouchDown(manager, ScreenIntPoint(10, 90), mcc->Time());
334
0
335
0
  // Lift the finger once again.
336
0
  TouchUp(manager, ScreenIntPoint(10, 90), mcc->Time());
337
0
338
0
  // Allow any animations to run their course.
339
0
  child->AdvanceAnimationsUntilEnd();
340
0
  rootApzc->AdvanceAnimationsUntilEnd();
341
0
342
0
  // Make sure nothing is overscrolled.
343
0
  EXPECT_FALSE(child->IsOverscrolled());
344
0
  EXPECT_FALSE(rootApzc->IsOverscrolled());
345
0
}
346
347
0
TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1240202b) {
348
0
  // Enable overscrolling.
349
0
  SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
350
0
  SCOPED_GFX_VAR(UseWebRender, bool, false);
351
0
352
0
  CreateScrollHandoffLayerTree1();
353
0
354
0
  TestAsyncPanZoomController* child = ApzcOf(layers[1]);
355
0
356
0
  // Pan, causing the parent APZC to overscroll.
357
0
  Pan(manager, 60, 90, PanOptions::KeepFingerDown);
358
0
  EXPECT_FALSE(child->IsOverscrolled());
359
0
  EXPECT_TRUE(rootApzc->IsOverscrolled());
360
0
361
0
  // Lift the finger, triggering an overscroll animation
362
0
  // (but don't allow it to run).
363
0
  TouchUp(manager, ScreenIntPoint(10, 90), mcc->Time());
364
0
365
0
  // Put the finger down again, interrupting the animation
366
0
  // and entering the TOUCHING state.
367
0
  TouchDown(manager, ScreenIntPoint(10, 90), mcc->Time());
368
0
369
0
  // Put a second finger down. Since we're in the TOUCHING state,
370
0
  // the "are we panned into overscroll" check will fail and we
371
0
  // will not ignore the second finger, instead entering the
372
0
  // PINCHING state.
373
0
  MultiTouchInput secondFingerDown(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
374
0
  // Use the same touch identifier for the first touch (0) as TouchDown(). (A bit hacky.)
375
0
  secondFingerDown.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, 90), ScreenSize(0, 0), 0, 0));
376
0
  secondFingerDown.mTouches.AppendElement(SingleTouchData(1, ScreenIntPoint(10, 80), ScreenSize(0, 0), 0, 0));
377
0
  manager->ReceiveInputEvent(secondFingerDown, nullptr, nullptr);
378
0
379
0
  // Release the fingers.
380
0
  MultiTouchInput fingersUp = secondFingerDown;
381
0
  fingersUp.mType = MultiTouchInput::MULTITOUCH_END;
382
0
  manager->ReceiveInputEvent(fingersUp, nullptr, nullptr);
383
0
384
0
  // Allow any animations to run their course.
385
0
  child->AdvanceAnimationsUntilEnd();
386
0
  rootApzc->AdvanceAnimationsUntilEnd();
387
0
388
0
  // Make sure nothing is overscrolled.
389
0
  EXPECT_FALSE(child->IsOverscrolled());
390
0
  EXPECT_FALSE(rootApzc->IsOverscrolled());
391
0
}
392
393
0
TEST_F(APZScrollHandoffTester, OpposingConstrainedAxes_Bug1201098) {
394
0
  // Enable overscrolling.
395
0
  SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
396
0
397
0
  CreateScrollHandoffLayerTree4();
398
0
399
0
  RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
400
0
401
0
  // Pan, causing the child APZC to overscroll.
402
0
  Pan(childApzc, 50, 60);
403
0
404
0
  //Make sure only the child is overscrolled.
405
0
  EXPECT_TRUE(childApzc->IsOverscrolled());
406
0
  EXPECT_FALSE(rootApzc->IsOverscrolled());
407
0
}
408
409
// Test that flinging in a direction where one component of the fling goes into
410
// overscroll but the other doesn't, results in just the one component being
411
// handed off to the parent, while the original APZC continues flinging in the
412
// other direction.
413
0
TEST_F(APZScrollHandoffTester, PartialFlingHandoff) {
414
0
  SCOPED_GFX_VAR(UseWebRender, bool, false);
415
0
  SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
416
0
417
0
  CreateScrollHandoffLayerTree1();
418
0
419
0
  // Fling up and to the left. The child APZC has room to scroll up, but not
420
0
  // to the left, so the horizontal component of the fling should be handed
421
0
  // off to the parent APZC.
422
0
  Pan(manager, ScreenIntPoint(90, 90), ScreenIntPoint(55, 55));
423
0
424
0
  RefPtr<TestAsyncPanZoomController> parent = ApzcOf(root);
425
0
  RefPtr<TestAsyncPanZoomController> child = ApzcOf(layers[1]);
426
0
427
0
  // Advance the child's fling animation once to give the partial handoff
428
0
  // a chance to occur.
429
0
  mcc->AdvanceByMillis(10);
430
0
  child->AdvanceAnimations(mcc->Time());
431
0
432
0
  // Assert that partial handoff has occurred.
433
0
  child->AssertStateIsFling();
434
0
  parent->AssertStateIsFling();
435
0
}
436
437
// Here we test that if two flings are happening simultaneously, overscroll
438
// is handed off correctly for each.
439
0
TEST_F(APZScrollHandoffTester, SimultaneousFlings) {
440
0
  SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
441
0
442
0
  // Set up an initial APZC tree.
443
0
  CreateScrollHandoffLayerTree3();
444
0
445
0
  RefPtr<TestAsyncPanZoomController> parent1 = ApzcOf(layers[1]);
446
0
  RefPtr<TestAsyncPanZoomController> child1 = ApzcOf(layers[2]);
447
0
  RefPtr<TestAsyncPanZoomController> parent2 = ApzcOf(layers[3]);
448
0
  RefPtr<TestAsyncPanZoomController> child2 = ApzcOf(layers[4]);
449
0
450
0
  // Pan on the lower child.
451
0
  Pan(child2, 45, 5);
452
0
453
0
  // Pan on the upper child.
454
0
  Pan(child1, 95, 55);
455
0
456
0
  // Check that child1 and child2 are in a FLING state.
457
0
  child1->AssertStateIsFling();
458
0
  child2->AssertStateIsFling();
459
0
460
0
  // Advance the animations on child1 and child2 until their end.
461
0
  child1->AdvanceAnimationsUntilEnd();
462
0
  child2->AdvanceAnimationsUntilEnd();
463
0
464
0
  // Check that the flings have been handed off to the parents.
465
0
  child1->AssertStateIsReset();
466
0
  parent1->AssertStateIsFling();
467
0
  child2->AssertStateIsReset();
468
0
  parent2->AssertStateIsFling();
469
0
}
470
471
0
TEST_F(APZScrollHandoffTester, Scrollgrab) {
472
0
  // Set up the layer tree
473
0
  CreateScrollgrabLayerTree();
474
0
475
0
  RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
476
0
477
0
  // Pan on the child, enough to fully scroll the scrollgrab parent (20 px)
478
0
  // and leave some more (another 15 px) for the child.
479
0
  Pan(childApzc, 80, 45);
480
0
481
0
  // Check that the parent and child have scrolled as much as we expect.
482
0
  EXPECT_EQ(20, rootApzc->GetFrameMetrics().GetScrollOffset().y);
483
0
  EXPECT_EQ(15, childApzc->GetFrameMetrics().GetScrollOffset().y);
484
0
}
485
486
0
TEST_F(APZScrollHandoffTester, ScrollgrabFling) {
487
0
  SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
488
0
  // Set up the layer tree
489
0
  CreateScrollgrabLayerTree();
490
0
491
0
  RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
492
0
493
0
  // Pan on the child, not enough to fully scroll the scrollgrab parent.
494
0
  Pan(childApzc, 80, 70);
495
0
496
0
  // Check that it is the scrollgrab parent that's in a fling, not the child.
497
0
  rootApzc->AssertStateIsFling();
498
0
  childApzc->AssertStateIsReset();
499
0
}
500
501
0
TEST_F(APZScrollHandoffTester, ScrollgrabFlingAcceleration1) {
502
0
  SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
503
0
  SCOPED_GFX_VAR(UseWebRender, bool, false);
504
0
  CreateScrollgrabLayerTree(true /* make parent scrollable */);
505
0
  TestFlingAcceleration();
506
0
}
507
508
0
TEST_F(APZScrollHandoffTester, ScrollgrabFlingAcceleration2) {
509
0
  SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
510
0
  SCOPED_GFX_VAR(UseWebRender, bool, false);
511
0
  CreateScrollgrabLayerTree(false /* do not make parent scrollable */);
512
0
  TestFlingAcceleration();
513
0
}
514
515
0
TEST_F(APZScrollHandoffTester, ImmediateHandoffDisallowed_Pan) {
516
0
  SCOPED_GFX_PREF(APZAllowImmediateHandoff, bool, false);
517
0
518
0
  CreateScrollHandoffLayerTree1();
519
0
520
0
  RefPtr<TestAsyncPanZoomController> parentApzc = ApzcOf(root);
521
0
  RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
522
0
523
0
  // Pan on the child, enough to scroll it to its end and have scroll
524
0
  // left to hand off. Since immediate handoff is disallowed, we expect
525
0
  // the leftover scroll not to be handed off.
526
0
  Pan(childApzc, 60, 5);
527
0
528
0
  // Verify that the parent has not scrolled.
529
0
  EXPECT_EQ(50, childApzc->GetFrameMetrics().GetScrollOffset().y);
530
0
  EXPECT_EQ(0, parentApzc->GetFrameMetrics().GetScrollOffset().y);
531
0
532
0
  // Pan again on the child. This time, since the child was scrolled to
533
0
  // its end when the gesture began, we expect the scroll to be handed off.
534
0
  Pan(childApzc, 60, 50);
535
0
536
0
  // Verify that the parent scrolled.
537
0
  EXPECT_EQ(10, parentApzc->GetFrameMetrics().GetScrollOffset().y);
538
0
}
539
540
0
TEST_F(APZScrollHandoffTester, ImmediateHandoffDisallowed_Fling) {
541
0
  SCOPED_GFX_PREF(APZAllowImmediateHandoff, bool, false);
542
0
  SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
543
0
544
0
  CreateScrollHandoffLayerTree1();
545
0
546
0
  RefPtr<TestAsyncPanZoomController> parentApzc = ApzcOf(root);
547
0
  RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
548
0
549
0
  // Pan on the child, enough to get very close to the end, so that the
550
0
  // subsequent fling reaches the end and has leftover velocity to hand off.
551
0
  Pan(childApzc, 60, 12);
552
0
553
0
  // Allow the fling to run its course.
554
0
  childApzc->AdvanceAnimationsUntilEnd();
555
0
  parentApzc->AdvanceAnimationsUntilEnd();
556
0
557
0
  // Verify that the parent has not scrolled.
558
0
  // The first comparison needs to be an ASSERT_NEAR because the fling
559
0
  // computations are such that the final scroll position can be within
560
0
  // COORDINATE_EPSILON of the end rather than right at the end.
561
0
  ASSERT_NEAR(50, childApzc->GetFrameMetrics().GetScrollOffset().y, COORDINATE_EPSILON);
562
0
  EXPECT_EQ(0, parentApzc->GetFrameMetrics().GetScrollOffset().y);
563
0
564
0
  // Pan again on the child. This time, since the child was scrolled to
565
0
  // its end when the gesture began, we expect the scroll to be handed off.
566
0
  Pan(childApzc, 60, 50);
567
0
568
0
  // Allow the fling to run its course. The fling should also be handed off.
569
0
  childApzc->AdvanceAnimationsUntilEnd();
570
0
  parentApzc->AdvanceAnimationsUntilEnd();
571
0
572
0
  // Verify that the parent scrolled from the fling.
573
0
  EXPECT_GT(parentApzc->GetFrameMetrics().GetScrollOffset().y, 10);
574
0
}
575
576
0
TEST_F(APZScrollHandoffTester, CrossApzcAxisLock_NoTouchAction) {
577
0
  SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
578
0
  TestCrossApzcAxisLock();
579
0
}
580
581
0
TEST_F(APZScrollHandoffTester, CrossApzcAxisLock_TouchAction) {
582
0
  SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
583
0
  TestCrossApzcAxisLock();
584
0
}