TestFlingAcceleration.cpp (10199B)
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 <initializer_list> 8 #include "APZCTreeManagerTester.h" 9 #include "APZTestCommon.h" 10 #include "InputUtils.h" 11 12 class APZCFlingAccelerationTester : public APZCTreeManagerTester { 13 protected: 14 void SetUp() { 15 APZCTreeManagerTester::SetUp(); 16 const char* treeShape = "x"; 17 LayerIntRect layerVisibleRect[] = { 18 LayerIntRect(0, 0, 800, 1000), 19 }; 20 CreateScrollData(treeShape, layerVisibleRect); 21 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 22 CSSRect(0, 0, 800, 50000)); 23 // Scroll somewhere into the middle of the scroll range, so that we have 24 // lots of space to scroll in both directions. 25 ModifyFrameMetrics(root, [](ScrollMetadata& aSm, FrameMetrics& aMetrics) { 26 aMetrics.SetVisualScrollUpdateType( 27 FrameMetrics::ScrollOffsetUpdateType::eMainThread); 28 aMetrics.SetVisualDestination(CSSPoint(0, 25000)); 29 }); 30 31 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 32 UpdateHitTestingTree(); 33 34 apzc = ApzcOf(root); 35 } 36 37 void ExecutePanGesture100Hz(const ScreenIntPoint& aStartPoint, 38 std::initializer_list<int32_t> aYDeltas) { 39 APZEventResult result = TouchDown(apzc, aStartPoint, mcc->Time()); 40 41 // Allowed touch behaviours must be set after sending touch-start. 42 if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) { 43 SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId); 44 } 45 46 const TimeDuration kTouchTimeDelta100Hz = 47 TimeDuration::FromMilliseconds(10); 48 49 ScreenIntPoint currentLocation = aStartPoint; 50 for (int32_t delta : aYDeltas) { 51 mcc->AdvanceBy(kTouchTimeDelta100Hz); 52 if (delta != 0) { 53 currentLocation.y += delta; 54 (void)TouchMove(apzc, currentLocation, mcc->Time()); 55 } 56 } 57 58 (void)TouchUp(apzc, currentLocation, mcc->Time()); 59 } 60 61 void ExecuteWait(const TimeDuration& aDuration) { 62 TimeDuration remaining = aDuration; 63 const TimeDuration TIME_BETWEEN_FRAMES = 64 TimeDuration::FromSeconds(1) / int64_t(60); 65 while (remaining.ToMilliseconds() > 0) { 66 mcc->AdvanceBy(TIME_BETWEEN_FRAMES); 67 apzc->AdvanceAnimations(mcc->GetSampleTime()); 68 remaining -= TIME_BETWEEN_FRAMES; 69 } 70 } 71 72 RefPtr<TestAsyncPanZoomController> apzc; 73 UniquePtr<ScopedLayerTreeRegistration> registration; 74 }; 75 76 enum class UpOrDown : uint8_t { Up, Down }; 77 78 // This is a macro so that the assertions print useful line numbers. 79 #define CHECK_VELOCITY(aUpOrDown, aLowerBound, aUpperBound) \ 80 do { \ 81 auto vel = apzc->GetVelocityVector(); \ 82 if (UpOrDown::aUpOrDown == UpOrDown::Up) { \ 83 EXPECT_LT(vel.y, 0.0); \ 84 } else { \ 85 EXPECT_GT(vel.y, 0.0); \ 86 } \ 87 EXPECT_GE(vel.Length(), aLowerBound); \ 88 EXPECT_LE(vel.Length(), aUpperBound); \ 89 } while (0) 90 91 // These tests have the following pattern: Two flings are executed, with a bit 92 // of wait time in between. The deltas in each pan gesture have been captured 93 // from a real phone, from touch events triggered by real fingers. 94 // We check the velocity at the end to detect whether the fling was accelerated 95 // or not. As an additional safety precaution, we also check the velocities for 96 // the first fling, so that changes in behavior are easier to analyze. 97 // One added challenge of this test is the fact that it has to work with on 98 // multiple platforms, and we use different velocity estimation strategies and 99 // different fling physics depending on the platform. 100 // The upper and lower bounds for the velocities were chosen in such a way that 101 // the test passes on all platforms. At the time of writing, we usually end up 102 // with higher velocities on Android than on Desktop, so the observed velocities 103 // on Android became the upper bounds and the observed velocities on Desktop 104 // becaume the lower bounds, each rounded out to a multiple of 0.1. 105 106 TEST_F(APZCFlingAccelerationTester, TwoNormalFlingsShouldAccelerate) { 107 ExecutePanGesture100Hz(ScreenIntPoint{665, 1244}, 108 {0, 0, -21, -44, -52, -55, -53, -49, -46, -47}); 109 CHECK_VELOCITY(Down, 4.5, 6.8); 110 111 ExecuteWait(TimeDuration::FromMilliseconds(375)); 112 CHECK_VELOCITY(Down, 2.2, 5.1); 113 114 ExecutePanGesture100Hz(ScreenIntPoint{623, 1211}, 115 {-6, -51, -55, 0, -53, -57, -60, -60, -56}); 116 CHECK_VELOCITY(Down, 9.0, 14.0); 117 } 118 119 TEST_F(APZCFlingAccelerationTester, TwoFastFlingsShouldAccelerate) { 120 ExecutePanGesture100Hz(ScreenIntPoint{764, 714}, 121 {9, 30, 49, 60, 64, 64, 62, 59, 51}); 122 CHECK_VELOCITY(Up, 5.0, 7.5); 123 124 ExecuteWait(TimeDuration::FromMilliseconds(447)); 125 CHECK_VELOCITY(Up, 2.3, 5.2); 126 127 ExecutePanGesture100Hz(ScreenIntPoint{743, 739}, 128 {7, 0, 38, 66, 75, 146, 0, 119}); 129 CHECK_VELOCITY(Up, 13.0, 20.0); 130 } 131 132 TEST_F(APZCFlingAccelerationTester, 133 FlingsInOppositeDirectionShouldNotAccelerate) { 134 ExecutePanGesture100Hz(ScreenIntPoint{728, 1381}, 135 {0, 0, 0, -12, -24, -32, -43, -46, 0}); 136 CHECK_VELOCITY(Down, 2.9, 5.3); 137 138 ExecuteWait(TimeDuration::FromMilliseconds(153)); 139 CHECK_VELOCITY(Down, 2.1, 4.8); 140 141 ExecutePanGesture100Hz(ScreenIntPoint{698, 1059}, 142 {0, 0, 14, 61, 41, 0, 45, 35}); 143 CHECK_VELOCITY(Up, 3.2, 4.3); 144 } 145 146 TEST_F(APZCFlingAccelerationTester, 147 ShouldNotAccelerateWhenPreviousFlingHasSlowedDown) { 148 ExecutePanGesture100Hz(ScreenIntPoint{748, 1046}, 149 {0, 9, 15, 23, 31, 30, 0, 34, 31, 29, 28, 24, 24, 11}); 150 CHECK_VELOCITY(Up, 2.2, 3.0); 151 ExecuteWait(TimeDuration::FromMilliseconds(498)); 152 CHECK_VELOCITY(Up, 0.5, 1.0); 153 ExecutePanGesture100Hz(ScreenIntPoint{745, 1056}, 154 {0, 10, 17, 29, 29, 33, 33, 0, 31, 27, 13}); 155 CHECK_VELOCITY(Up, 1.8, 2.7); 156 } 157 158 TEST_F(APZCFlingAccelerationTester, ShouldNotAccelerateWhenPausedAtStartOfPan) { 159 ExecutePanGesture100Hz( 160 ScreenIntPoint{711, 1468}, 161 {0, 0, 0, 0, -8, 0, -18, -32, -50, -57, -66, -68, -63, -60}); 162 CHECK_VELOCITY(Down, 6.2, 8.6); 163 164 ExecuteWait(TimeDuration::FromMilliseconds(285)); 165 CHECK_VELOCITY(Down, 3.4, 7.4); 166 167 ExecutePanGesture100Hz( 168 ScreenIntPoint{658, 1352}, 169 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170 0, 0, 0, 0, 0, -8, -18, -34, -53, -70, -75, -75, -64}); 171 CHECK_VELOCITY(Down, 6.7, 9.1); 172 } 173 174 TEST_F(APZCFlingAccelerationTester, ShouldNotAccelerateWhenPausedDuringPan) { 175 ExecutePanGesture100Hz( 176 ScreenIntPoint{732, 1423}, 177 {0, 0, 0, -5, 0, -15, -41, -71, -90, -93, -85, -64, -44}); 178 CHECK_VELOCITY(Down, 7.5, 10.1); 179 180 ExecuteWait(TimeDuration::FromMilliseconds(204)); 181 CHECK_VELOCITY(Down, 4.8, 9.4); 182 183 ExecutePanGesture100Hz( 184 ScreenIntPoint{651, 1372}, 185 {0, 0, 0, -6, 0, -16, -26, -41, -49, -65, -66, -61, -50, -35, -24, 186 -17, -11, -8, -6, -5, -4, -3, -2, -2, -2, -2, -2, -2, -2, -2, 187 -3, -4, -5, -7, -9, -10, -10, -12, -18, -25, -23, -28, -30, -24}); 188 CHECK_VELOCITY(Down, 2.5, 3.4); 189 } 190 191 TEST_F(APZCFlingAccelerationTester, 192 ShouldNotAccelerateWhenOppositeDirectionDuringPan) { 193 ExecutePanGesture100Hz(ScreenIntPoint{663, 1371}, 194 {0, 0, 0, -5, -18, -31, -49, -56, -61, -54, -55}); 195 CHECK_VELOCITY(Down, 5.4, 7.1); 196 197 ExecuteWait(TimeDuration::FromMilliseconds(255)); 198 CHECK_VELOCITY(Down, 3.1, 6.0); 199 200 ExecutePanGesture100Hz( 201 ScreenIntPoint{726, 930}, 202 {0, 0, 0, 0, 30, 0, 19, 24, 32, 30, 37, 33, 203 33, 32, 25, 23, 23, 18, 13, 9, 5, 3, 1, 0, 204 -7, -19, -38, -53, -68, -79, -85, -73, -64, -54}); 205 CHECK_VELOCITY(Down, 7.0, 10.0); 206 } 207 208 TEST_F(APZCFlingAccelerationTester, 209 ShouldAccelerateAfterLongWaitIfVelocityStillHigh) { 210 // Reduce friction with the "Desktop" fling physics a little, so that it 211 // behaves more similarly to the Android fling physics, and has enough 212 // velocity after the wait time to allow for acceleration. 213 SCOPED_GFX_PREF_FLOAT("apz.fling_friction", 0.0012); 214 215 ExecutePanGesture100Hz(ScreenIntPoint{739, 1424}, 216 {0, 0, -5, -10, -20, 0, -110, -86, 0, -102, -105}); 217 CHECK_VELOCITY(Down, 6.3, 9.4); 218 219 ExecuteWait(TimeDuration::FromMilliseconds(1117)); 220 CHECK_VELOCITY(Down, 1.6, 3.3); 221 222 ExecutePanGesture100Hz(ScreenIntPoint{726, 1380}, 223 {0, -8, 0, -30, -60, -87, -104, -111}); 224 CHECK_VELOCITY(Down, 13.0, 23.0); 225 } 226 227 TEST_F(APZCFlingAccelerationTester, ShouldNotAccelerateAfterCanceledWithTap) { 228 // First, build up a lot of speed. 229 ExecutePanGesture100Hz(ScreenIntPoint{569, 710}, 230 {11, 2, 107, 18, 148, 57, 133, 159, 21}); 231 ExecuteWait(TimeDuration::FromMilliseconds(154)); 232 ExecutePanGesture100Hz(ScreenIntPoint{581, 650}, 233 {12, 68, 0, 162, 78, 140, 167}); 234 ExecuteWait(TimeDuration::FromMilliseconds(123)); 235 ExecutePanGesture100Hz(ScreenIntPoint{568, 723}, {11, 0, 79, 91, 131, 171}); 236 ExecuteWait(TimeDuration::FromMilliseconds(123)); 237 ExecutePanGesture100Hz(ScreenIntPoint{598, 678}, 238 {8, 55, 22, 87, 117, 220, 54}); 239 ExecuteWait(TimeDuration::FromMilliseconds(134)); 240 ExecutePanGesture100Hz(ScreenIntPoint{585, 854}, {45, 137, 107, 102, 79}); 241 ExecuteWait(TimeDuration::FromMilliseconds(246)); 242 243 // Then, interrupt with a tap. 244 ExecutePanGesture100Hz(ScreenIntPoint{566, 812}, {0, 0, 0, 0}); 245 ExecuteWait(TimeDuration::FromMilliseconds(869)); 246 247 // Then do a regular fling. 248 ExecutePanGesture100Hz(ScreenIntPoint{599, 819}, 249 {0, 0, 8, 35, 8, 38, 29, 37}); 250 251 CHECK_VELOCITY(Up, 2.8, 4.2); 252 }