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 "APZCBasicTester.h"
8 #include "APZTestCommon.h"
9 #include "InputUtils.h"
10 #include "gtest/gtest.h"
11 
12 class APZCPanningTester : public APZCBasicTester {
13  protected:
DoPanTest(bool aShouldTriggerScroll,bool aShouldBeConsumed,uint32_t aBehavior)14   void DoPanTest(bool aShouldTriggerScroll, bool aShouldBeConsumed,
15                  uint32_t aBehavior) {
16     if (aShouldTriggerScroll) {
17       // Three repaint request for each pan.
18       EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(6);
19     } else {
20       EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
21     }
22 
23     int touchStart = 50;
24     int touchEnd = 10;
25     ParentLayerPoint pointOut;
26     AsyncTransform viewTransformOut;
27 
28     nsTArray<uint32_t> allowedTouchBehaviors;
29     allowedTouchBehaviors.AppendElement(aBehavior);
30 
31     // Pan down
32     PanAndCheckStatus(apzc, touchStart, touchEnd, aShouldBeConsumed,
33                       &allowedTouchBehaviors);
34     apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
35 
36     if (aShouldTriggerScroll) {
37       EXPECT_EQ(ParentLayerPoint(0, -(touchEnd - touchStart)), pointOut);
38       EXPECT_NE(AsyncTransform(), viewTransformOut);
39     } else {
40       EXPECT_EQ(ParentLayerPoint(), pointOut);
41       EXPECT_EQ(AsyncTransform(), viewTransformOut);
42     }
43 
44     // Clear the fling from the previous pan, or stopping it will
45     // consume the next touchstart
46     apzc->CancelAnimation();
47 
48     // Pan back
49     PanAndCheckStatus(apzc, touchEnd, touchStart, aShouldBeConsumed,
50                       &allowedTouchBehaviors);
51     apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
52 
53     EXPECT_EQ(ParentLayerPoint(), pointOut);
54     EXPECT_EQ(AsyncTransform(), viewTransformOut);
55   }
56 
DoPanWithPreventDefaultTest()57   void DoPanWithPreventDefaultTest() {
58     MakeApzcWaitForMainThread();
59 
60     int touchStart = 50;
61     int touchEnd = 10;
62     ParentLayerPoint pointOut;
63     AsyncTransform viewTransformOut;
64     uint64_t blockId = 0;
65 
66     // Pan down
67     nsTArray<uint32_t> allowedTouchBehaviors;
68     allowedTouchBehaviors.AppendElement(
69         mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
70     PanAndCheckStatus(apzc, touchStart, touchEnd, true, &allowedTouchBehaviors,
71                       &blockId);
72 
73     // Send the signal that content has handled and preventDefaulted the touch
74     // events. This flushes the event queue.
75     apzc->ContentReceivedInputBlock(blockId, true);
76 
77     apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
78     EXPECT_EQ(ParentLayerPoint(), pointOut);
79     EXPECT_EQ(AsyncTransform(), viewTransformOut);
80 
81     apzc->AssertStateIsReset();
82   }
83 };
84 
TEST_F(APZCPanningTester,Pan)85 TEST_F(APZCPanningTester, Pan) {
86   SCOPED_GFX_PREF_BOOL("layout.css.touch_action.enabled", false);
87   // Velocity bias can cause extra repaint requests.
88   SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0);
89   DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::NONE);
90 }
91 
92 // In the each of the following 4 pan tests we are performing two pan gestures:
93 // vertical pan from top to bottom and back - from bottom to top. According to
94 // the pointer-events/touch-action spec AUTO and PAN_Y touch-action values allow
95 // vertical scrolling while NONE and PAN_X forbid it. The first parameter of
96 // DoPanTest method specifies this behavior. However, the events will be marked
97 // as consumed even if the behavior in PAN_X, because the user could move their
98 // finger horizontally too - APZ has no way of knowing beforehand and so must
99 // consume the events.
TEST_F(APZCPanningTester,PanWithTouchActionAuto)100 TEST_F(APZCPanningTester, PanWithTouchActionAuto) {
101   SCOPED_GFX_PREF_BOOL("layout.css.touch_action.enabled", true);
102   // Velocity bias can cause extra repaint requests.
103   SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0);
104   DoPanTest(true, true,
105             mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN |
106                 mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
107 }
108 
TEST_F(APZCPanningTester,PanWithTouchActionNone)109 TEST_F(APZCPanningTester, PanWithTouchActionNone) {
110   SCOPED_GFX_PREF_BOOL("layout.css.touch_action.enabled", true);
111   // Velocity bias can cause extra repaint requests.
112   SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0);
113   DoPanTest(false, false, 0);
114 }
115 
TEST_F(APZCPanningTester,PanWithTouchActionPanX)116 TEST_F(APZCPanningTester, PanWithTouchActionPanX) {
117   SCOPED_GFX_PREF_BOOL("layout.css.touch_action.enabled", true);
118   // Velocity bias can cause extra repaint requests.
119   SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0);
120   DoPanTest(false, false,
121             mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN);
122 }
123 
TEST_F(APZCPanningTester,PanWithTouchActionPanY)124 TEST_F(APZCPanningTester, PanWithTouchActionPanY) {
125   SCOPED_GFX_PREF_BOOL("layout.css.touch_action.enabled", true);
126   // Velocity bias can cause extra repaint requests.
127   SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0);
128   DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
129 }
130 
TEST_F(APZCPanningTester,PanWithPreventDefaultAndTouchAction)131 TEST_F(APZCPanningTester, PanWithPreventDefaultAndTouchAction) {
132   SCOPED_GFX_PREF_BOOL("layout.css.touch_action.enabled", true);
133   DoPanWithPreventDefaultTest();
134 }
135 
TEST_F(APZCPanningTester,PanWithPreventDefault)136 TEST_F(APZCPanningTester, PanWithPreventDefault) {
137   SCOPED_GFX_PREF_BOOL("layout.css.touch_action.enabled", false);
138   DoPanWithPreventDefaultTest();
139 }
140 
TEST_F(APZCPanningTester,PanWithHistoricalTouchData)141 TEST_F(APZCPanningTester, PanWithHistoricalTouchData) {
142   SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0);
143 
144   // Simulate the same pan gesture, in three different ways.
145   // We start at y=50, with a 50ms resting period at the start of the pan.
146   // Then we accelerate the finger upwards towards y=10, reaching a 10px/10ms
147   // velocity towards the end of the panning motion.
148   //
149   // The first simulation fires touch move events with 10ms gaps.
150   // The second simulation skips two of the touch move events, simulating
151   // "jank". The third simulation also skips those two events, but reports the
152   // missed positions in the following event's historical coordinates.
153   //
154   // Consequently, the first and third simulation should estimate the same
155   // velocities, whereas the second simulation should estimate a different
156   // velocity because it is missing data.
157 
158   // First simulation: full data
159 
160   APZEventResult result = TouchDown(apzc, ScreenIntPoint(0, 50), mcc->Time());
161   if (result.GetStatus() != nsEventStatus_eConsumeNoDefault &&
162       StaticPrefs::layout_css_touch_action_enabled()) {
163     SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId);
164   }
165 
166   mcc->AdvanceByMillis(50);
167   result = TouchMove(apzc, ScreenIntPoint(0, 45), mcc->Time());
168   mcc->AdvanceByMillis(10);
169   result = TouchMove(apzc, ScreenIntPoint(0, 40), mcc->Time());
170   mcc->AdvanceByMillis(10);
171   result = TouchMove(apzc, ScreenIntPoint(0, 30), mcc->Time());
172   mcc->AdvanceByMillis(10);
173   result = TouchMove(apzc, ScreenIntPoint(0, 20), mcc->Time());
174   result = TouchUp(apzc, ScreenIntPoint(0, 20), mcc->Time());
175   auto velocityFromFullDataAsSeparateEvents = apzc->GetVelocityVector();
176   apzc->CancelAnimation();
177 
178   mcc->AdvanceByMillis(100);
179 
180   // Second simulation: partial data
181 
182   result = TouchDown(apzc, ScreenIntPoint(0, 50), mcc->Time());
183   if (result.GetStatus() != nsEventStatus_eConsumeNoDefault &&
184       StaticPrefs::layout_css_touch_action_enabled()) {
185     SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId);
186   }
187 
188   mcc->AdvanceByMillis(50);
189   result = TouchMove(apzc, ScreenIntPoint(0, 45), mcc->Time());
190   mcc->AdvanceByMillis(30);
191   result = TouchMove(apzc, ScreenIntPoint(0, 20), mcc->Time());
192   result = TouchUp(apzc, ScreenIntPoint(0, 20), mcc->Time());
193   auto velocityFromPartialData = apzc->GetVelocityVector();
194   apzc->CancelAnimation();
195 
196   mcc->AdvanceByMillis(100);
197 
198   // Third simulation: full data via historical data
199 
200   result = TouchDown(apzc, ScreenIntPoint(0, 50), mcc->Time());
201   if (result.GetStatus() != nsEventStatus_eConsumeNoDefault &&
202       StaticPrefs::layout_css_touch_action_enabled()) {
203     SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId);
204   }
205 
206   mcc->AdvanceByMillis(50);
207   result = TouchMove(apzc, ScreenIntPoint(0, 45), mcc->Time());
208   mcc->AdvanceByMillis(30);
209 
210   MultiTouchInput mti =
211       CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time());
212   auto singleTouchData = CreateSingleTouchData(0, ScreenIntPoint(0, 20));
213   singleTouchData.mHistoricalData.AppendElement(
214       SingleTouchData::HistoricalTouchData{
215           mcc->Time() - TimeDuration::FromMilliseconds(20),
216           ScreenIntPoint(0, 40),
217           {},
218           {},
219           0.0f,
220           0.0f});
221   singleTouchData.mHistoricalData.AppendElement(
222       SingleTouchData::HistoricalTouchData{
223           mcc->Time() - TimeDuration::FromMilliseconds(10),
224           ScreenIntPoint(0, 30),
225           {},
226           {},
227           0.0f,
228           0.0f});
229   mti.mTouches.AppendElement(singleTouchData);
230   result = apzc->ReceiveInputEvent(mti);
231 
232   result = TouchUp(apzc, ScreenIntPoint(0, 20), mcc->Time());
233   auto velocityFromFullDataViaHistory = apzc->GetVelocityVector();
234   apzc->CancelAnimation();
235 
236   EXPECT_EQ(velocityFromFullDataAsSeparateEvents,
237             velocityFromFullDataViaHistory);
238   EXPECT_NE(velocityFromPartialData, velocityFromFullDataViaHistory);
239 }
240