gfx/tests/gtest/TestAsyncPanZoomController.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* vim:set ts=2 sw=2 sts=2 et: */
michael@0 2 /* Any copyright is dedicated to the Public Domain.
michael@0 3 * http://creativecommons.org/publicdomain/zero/1.0/
michael@0 4 */
michael@0 5
michael@0 6 #include "gtest/gtest.h"
michael@0 7 #include "gmock/gmock.h"
michael@0 8
michael@0 9 #include "mozilla/Attributes.h"
michael@0 10 #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
michael@0 11 #include "mozilla/layers/AsyncPanZoomController.h"
michael@0 12 #include "mozilla/layers/LayerManagerComposite.h"
michael@0 13 #include "mozilla/layers/GeckoContentController.h"
michael@0 14 #include "mozilla/layers/CompositorParent.h"
michael@0 15 #include "mozilla/layers/APZCTreeManager.h"
michael@0 16 #include "base/task.h"
michael@0 17 #include "Layers.h"
michael@0 18 #include "TestLayers.h"
michael@0 19 #include "gfxPrefs.h"
michael@0 20
michael@0 21 using namespace mozilla;
michael@0 22 using namespace mozilla::gfx;
michael@0 23 using namespace mozilla::layers;
michael@0 24 using ::testing::_;
michael@0 25 using ::testing::NiceMock;
michael@0 26 using ::testing::AtLeast;
michael@0 27 using ::testing::AtMost;
michael@0 28 using ::testing::MockFunction;
michael@0 29 using ::testing::InSequence;
michael@0 30
michael@0 31 class Task;
michael@0 32
michael@0 33 class AsyncPanZoomControllerTester : public ::testing::Test {
michael@0 34 protected:
michael@0 35 virtual void SetUp() {
michael@0 36 gfxPrefs::GetSingleton();
michael@0 37 }
michael@0 38 virtual void TearDown() {
michael@0 39 gfxPrefs::DestroySingleton();
michael@0 40 }
michael@0 41 };
michael@0 42
michael@0 43 class APZCTreeManagerTester : public ::testing::Test {
michael@0 44 protected:
michael@0 45 virtual void SetUp() {
michael@0 46 gfxPrefs::GetSingleton();
michael@0 47 }
michael@0 48 virtual void TearDown() {
michael@0 49 gfxPrefs::DestroySingleton();
michael@0 50 }
michael@0 51 };
michael@0 52
michael@0 53 class MockContentController : public GeckoContentController {
michael@0 54 public:
michael@0 55 MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
michael@0 56 MOCK_METHOD2(AcknowledgeScrollUpdate, void(const FrameMetrics::ViewID&, const uint32_t& aScrollGeneration));
michael@0 57 MOCK_METHOD3(HandleDoubleTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
michael@0 58 MOCK_METHOD3(HandleSingleTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
michael@0 59 MOCK_METHOD3(HandleLongTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
michael@0 60 MOCK_METHOD3(HandleLongTapUp, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
michael@0 61 MOCK_METHOD3(SendAsyncScrollDOMEvent, void(bool aIsRoot, const CSSRect &aContentRect, const CSSSize &aScrollableSize));
michael@0 62 MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs));
michael@0 63 };
michael@0 64
michael@0 65 class MockContentControllerDelayed : public MockContentController {
michael@0 66 public:
michael@0 67 MockContentControllerDelayed()
michael@0 68 {
michael@0 69 }
michael@0 70
michael@0 71 void PostDelayedTask(Task* aTask, int aDelayMs) {
michael@0 72 mTaskQueue.AppendElement(aTask);
michael@0 73 }
michael@0 74
michael@0 75 void CheckHasDelayedTask() {
michael@0 76 EXPECT_TRUE(mTaskQueue.Length() > 0);
michael@0 77 }
michael@0 78
michael@0 79 void ClearDelayedTask() {
michael@0 80 mTaskQueue.RemoveElementAt(0);
michael@0 81 }
michael@0 82
michael@0 83 void DestroyOldestTask() {
michael@0 84 delete mTaskQueue[0];
michael@0 85 mTaskQueue.RemoveElementAt(0);
michael@0 86 }
michael@0 87
michael@0 88 // Note that deleting mCurrentTask is important in order to
michael@0 89 // release the reference to the callee object. Without this
michael@0 90 // that object might be leaked. This is also why we don't
michael@0 91 // expose mTaskQueue to any users of MockContentControllerDelayed.
michael@0 92 void RunDelayedTask() {
michael@0 93 mTaskQueue[0]->Run();
michael@0 94 delete mTaskQueue[0];
michael@0 95 mTaskQueue.RemoveElementAt(0);
michael@0 96 }
michael@0 97
michael@0 98 private:
michael@0 99 nsTArray<Task*> mTaskQueue;
michael@0 100 };
michael@0 101
michael@0 102
michael@0 103 class TestAPZCContainerLayer : public ContainerLayer {
michael@0 104 public:
michael@0 105 TestAPZCContainerLayer()
michael@0 106 : ContainerLayer(nullptr, nullptr)
michael@0 107 {}
michael@0 108 bool RemoveChild(Layer* aChild) { return true; }
michael@0 109 bool InsertAfter(Layer* aChild, Layer* aAfter) { return true; }
michael@0 110 void ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) {}
michael@0 111 bool RepositionChild(Layer* aChild, Layer* aAfter) { return true; }
michael@0 112 };
michael@0 113
michael@0 114 class TestAsyncPanZoomController : public AsyncPanZoomController {
michael@0 115 public:
michael@0 116 TestAsyncPanZoomController(uint64_t aLayersId, MockContentController* aMcc,
michael@0 117 APZCTreeManager* aTreeManager = nullptr,
michael@0 118 GestureBehavior aBehavior = DEFAULT_GESTURES)
michael@0 119 : AsyncPanZoomController(aLayersId, aTreeManager, aMcc, aBehavior)
michael@0 120 {}
michael@0 121
michael@0 122 // Since touch-action-enabled property is global - setting it for each test
michael@0 123 // separately isn't safe from the concurrency point of view. To make tests
michael@0 124 // run concurrent and independent from each other we have a member variable
michael@0 125 // mTouchActionEnabled for each apzc and setter defined here.
michael@0 126 void SetTouchActionEnabled(const bool touchActionEnabled) {
michael@0 127 ReentrantMonitorAutoEnter lock(mMonitor);
michael@0 128 mTouchActionPropertyEnabled = touchActionEnabled;
michael@0 129 }
michael@0 130
michael@0 131 void SetFrameMetrics(const FrameMetrics& metrics) {
michael@0 132 ReentrantMonitorAutoEnter lock(mMonitor);
michael@0 133 mFrameMetrics = metrics;
michael@0 134 }
michael@0 135
michael@0 136 FrameMetrics GetFrameMetrics() {
michael@0 137 ReentrantMonitorAutoEnter lock(mMonitor);
michael@0 138 return mFrameMetrics;
michael@0 139 }
michael@0 140 };
michael@0 141
michael@0 142 class TestAPZCTreeManager : public APZCTreeManager {
michael@0 143 protected:
michael@0 144 void AssertOnCompositorThread() MOZ_OVERRIDE { /* no-op */ }
michael@0 145
michael@0 146 public:
michael@0 147 // Expose this so test code can call it directly.
michael@0 148 void BuildOverscrollHandoffChain(AsyncPanZoomController* aApzc) {
michael@0 149 APZCTreeManager::BuildOverscrollHandoffChain(aApzc);
michael@0 150 }
michael@0 151 };
michael@0 152
michael@0 153 static
michael@0 154 FrameMetrics TestFrameMetrics() {
michael@0 155 FrameMetrics fm;
michael@0 156
michael@0 157 fm.mDisplayPort = CSSRect(0, 0, 10, 10);
michael@0 158 fm.mCompositionBounds = ParentLayerIntRect(0, 0, 10, 10);
michael@0 159 fm.mCriticalDisplayPort = CSSRect(0, 0, 10, 10);
michael@0 160 fm.mScrollableRect = CSSRect(0, 0, 100, 100);
michael@0 161 fm.mViewport = CSSRect(0, 0, 10, 10);
michael@0 162
michael@0 163 return fm;
michael@0 164 }
michael@0 165
michael@0 166 /*
michael@0 167 * Dispatches mock touch events to the apzc and checks whether apzc properly
michael@0 168 * consumed them and triggered scrolling behavior.
michael@0 169 */
michael@0 170 static
michael@0 171 void ApzcPan(AsyncPanZoomController* apzc,
michael@0 172 TestAPZCTreeManager* aTreeManager,
michael@0 173 int& aTime,
michael@0 174 int aTouchStartY,
michael@0 175 int aTouchEndY,
michael@0 176 bool expectIgnoredPan = false,
michael@0 177 bool hasTouchListeners = false,
michael@0 178 nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr) {
michael@0 179
michael@0 180 const int TIME_BETWEEN_TOUCH_EVENT = 100;
michael@0 181 const int OVERCOME_TOUCH_TOLERANCE = 100;
michael@0 182 MultiTouchInput mti;
michael@0 183 nsEventStatus status;
michael@0 184
michael@0 185 // Since we're passing inputs directly to the APZC instead of going through
michael@0 186 // the tree manager, we need to build the overscroll handoff chain explicitly
michael@0 187 // for panning to work correctly.
michael@0 188 aTreeManager->BuildOverscrollHandoffChain(apzc);
michael@0 189
michael@0 190 nsEventStatus touchStartStatus;
michael@0 191 if (hasTouchListeners) {
michael@0 192 // APZC shouldn't consume the start event now, instead queueing it up
michael@0 193 // waiting for content's response.
michael@0 194 touchStartStatus = nsEventStatus_eIgnore;
michael@0 195 } else {
michael@0 196 // APZC should go into the touching state and therefore consume the event.
michael@0 197 touchStartStatus = nsEventStatus_eConsumeNoDefault;
michael@0 198 }
michael@0 199
michael@0 200 mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, aTime, 0);
michael@0 201 aTime += TIME_BETWEEN_TOUCH_EVENT;
michael@0 202 // Make sure the move is large enough to not be handled as a tap
michael@0 203 mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchStartY+OVERCOME_TOUCH_TOLERANCE), ScreenSize(0, 0), 0, 0));
michael@0 204 status = apzc->ReceiveInputEvent(mti);
michael@0 205 EXPECT_EQ(touchStartStatus, status);
michael@0 206 // APZC should be in TOUCHING state
michael@0 207
michael@0 208 // Allowed touch behaviours must be set after sending touch-start.
michael@0 209 if (aAllowedTouchBehaviors) {
michael@0 210 apzc->SetAllowedTouchBehavior(*aAllowedTouchBehaviors);
michael@0 211 }
michael@0 212
michael@0 213 nsEventStatus touchMoveStatus;
michael@0 214 if (expectIgnoredPan) {
michael@0 215 // APZC should ignore panning, be in TOUCHING state and therefore return eIgnore.
michael@0 216 // The same applies to all consequent touch move events.
michael@0 217 touchMoveStatus = nsEventStatus_eIgnore;
michael@0 218 } else {
michael@0 219 // APZC should go into the panning state and therefore consume the event.
michael@0 220 touchMoveStatus = nsEventStatus_eConsumeNoDefault;
michael@0 221 }
michael@0 222
michael@0 223 mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime, 0);
michael@0 224 aTime += TIME_BETWEEN_TOUCH_EVENT;
michael@0 225 mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchStartY), ScreenSize(0, 0), 0, 0));
michael@0 226 status = apzc->ReceiveInputEvent(mti);
michael@0 227 EXPECT_EQ(touchMoveStatus, status);
michael@0 228
michael@0 229 mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime, 0);
michael@0 230 aTime += TIME_BETWEEN_TOUCH_EVENT;
michael@0 231 mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchEndY), ScreenSize(0, 0), 0, 0));
michael@0 232 status = apzc->ReceiveInputEvent(mti);
michael@0 233 EXPECT_EQ(touchMoveStatus, status);
michael@0 234
michael@0 235 mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, aTime, 0);
michael@0 236 aTime += TIME_BETWEEN_TOUCH_EVENT;
michael@0 237 mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchEndY), ScreenSize(0, 0), 0, 0));
michael@0 238 status = apzc->ReceiveInputEvent(mti);
michael@0 239 }
michael@0 240
michael@0 241 static
michael@0 242 void DoPanTest(bool aShouldTriggerScroll, bool aShouldUseTouchAction, uint32_t aBehavior)
michael@0 243 {
michael@0 244 TimeStamp testStartTime = TimeStamp::Now();
michael@0 245 AsyncPanZoomController::SetFrameTime(testStartTime);
michael@0 246
michael@0 247 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 248 nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
michael@0 249 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
michael@0 250
michael@0 251 apzc->SetTouchActionEnabled(aShouldUseTouchAction);
michael@0 252 apzc->SetFrameMetrics(TestFrameMetrics());
michael@0 253 apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
michael@0 254
michael@0 255 if (aShouldTriggerScroll) {
michael@0 256 EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
michael@0 257 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
michael@0 258 } else {
michael@0 259 EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(0);
michael@0 260 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
michael@0 261 }
michael@0 262
michael@0 263 int time = 0;
michael@0 264 int touchStart = 50;
michael@0 265 int touchEnd = 10;
michael@0 266 ScreenPoint pointOut;
michael@0 267 ViewTransform viewTransformOut;
michael@0 268
michael@0 269 nsTArray<uint32_t> allowedTouchBehaviors;
michael@0 270 allowedTouchBehaviors.AppendElement(aBehavior);
michael@0 271
michael@0 272 // Pan down
michael@0 273 ApzcPan(apzc, tm, time, touchStart, touchEnd, !aShouldTriggerScroll, false, &allowedTouchBehaviors);
michael@0 274 apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
michael@0 275
michael@0 276 if (aShouldTriggerScroll) {
michael@0 277 EXPECT_EQ(ScreenPoint(0, -(touchEnd-touchStart)), pointOut);
michael@0 278 EXPECT_NE(ViewTransform(), viewTransformOut);
michael@0 279 } else {
michael@0 280 EXPECT_EQ(ScreenPoint(), pointOut);
michael@0 281 EXPECT_EQ(ViewTransform(), viewTransformOut);
michael@0 282 }
michael@0 283
michael@0 284 // Pan back
michael@0 285 ApzcPan(apzc, tm, time, touchEnd, touchStart, !aShouldTriggerScroll, false, &allowedTouchBehaviors);
michael@0 286 apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
michael@0 287
michael@0 288 EXPECT_EQ(ScreenPoint(), pointOut);
michael@0 289 EXPECT_EQ(ViewTransform(), viewTransformOut);
michael@0 290
michael@0 291 apzc->Destroy();
michael@0 292 }
michael@0 293
michael@0 294 static void
michael@0 295 ApzcPinch(AsyncPanZoomController* aApzc, int aFocusX, int aFocusY, float aScale) {
michael@0 296 aApzc->HandleGestureEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
michael@0 297 0,
michael@0 298 ScreenPoint(aFocusX, aFocusY),
michael@0 299 10.0,
michael@0 300 10.0,
michael@0 301 0));
michael@0 302 aApzc->HandleGestureEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
michael@0 303 0,
michael@0 304 ScreenPoint(aFocusX, aFocusY),
michael@0 305 10.0 * aScale,
michael@0 306 10.0,
michael@0 307 0));
michael@0 308 aApzc->HandleGestureEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
michael@0 309 0,
michael@0 310 ScreenPoint(aFocusX, aFocusY),
michael@0 311 // note: negative values here tell APZC
michael@0 312 // not to turn the pinch into a pan
michael@0 313 -1.0,
michael@0 314 -1.0,
michael@0 315 0));
michael@0 316 }
michael@0 317
michael@0 318 static nsEventStatus
michael@0 319 ApzcDown(AsyncPanZoomController* apzc, int aX, int aY, int& aTime) {
michael@0 320 MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, aTime, 0);
michael@0 321 mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(aX, aY), ScreenSize(0, 0), 0, 0));
michael@0 322 return apzc->ReceiveInputEvent(mti);
michael@0 323 }
michael@0 324
michael@0 325 static nsEventStatus
michael@0 326 ApzcUp(AsyncPanZoomController* apzc, int aX, int aY, int& aTime) {
michael@0 327 MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, aTime, 0);
michael@0 328 mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(aX, aY), ScreenSize(0, 0), 0, 0));
michael@0 329 return apzc->ReceiveInputEvent(mti);
michael@0 330 }
michael@0 331
michael@0 332 static nsEventStatus
michael@0 333 ApzcTap(AsyncPanZoomController* apzc, int aX, int aY, int& aTime, int aTapLength, MockContentControllerDelayed* mcc = nullptr) {
michael@0 334 nsEventStatus status = ApzcDown(apzc, aX, aY, aTime);
michael@0 335 if (mcc != nullptr) {
michael@0 336 // There will be delayed tasks posted for the long-tap and MAX_TAP timeouts, but
michael@0 337 // if we were provided a non-null mcc we want to clear them.
michael@0 338 mcc->CheckHasDelayedTask();
michael@0 339 mcc->ClearDelayedTask();
michael@0 340 mcc->CheckHasDelayedTask();
michael@0 341 mcc->ClearDelayedTask();
michael@0 342 }
michael@0 343 EXPECT_EQ(nsEventStatus_eConsumeNoDefault, status);
michael@0 344 aTime += aTapLength;
michael@0 345 return ApzcUp(apzc, aX, aY, aTime);
michael@0 346 }
michael@0 347
michael@0 348 TEST_F(AsyncPanZoomControllerTester, Constructor) {
michael@0 349 // RefCounted class can't live in the stack
michael@0 350 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 351 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
michael@0 352 apzc->SetFrameMetrics(TestFrameMetrics());
michael@0 353 }
michael@0 354
michael@0 355 TEST_F(AsyncPanZoomControllerTester, Pinch) {
michael@0 356 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 357 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
michael@0 358
michael@0 359 FrameMetrics fm;
michael@0 360 fm.mViewport = CSSRect(0, 0, 980, 480);
michael@0 361 fm.mCompositionBounds = ParentLayerIntRect(200, 200, 100, 200);
michael@0 362 fm.mScrollableRect = CSSRect(0, 0, 980, 1000);
michael@0 363 fm.SetScrollOffset(CSSPoint(300, 300));
michael@0 364 fm.SetZoom(CSSToScreenScale(2.0));
michael@0 365 apzc->SetFrameMetrics(fm);
michael@0 366 apzc->UpdateZoomConstraints(ZoomConstraints(true, true, CSSToScreenScale(0.25), CSSToScreenScale(4.0)));
michael@0 367 // the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100
michael@0 368
michael@0 369 EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
michael@0 370 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
michael@0 371
michael@0 372 ApzcPinch(apzc, 250, 300, 1.25);
michael@0 373
michael@0 374 // the visible area of the document in CSS pixels is now x=305 y=310 w=40 h=80
michael@0 375 fm = apzc->GetFrameMetrics();
michael@0 376 EXPECT_EQ(2.5f, fm.GetZoom().scale);
michael@0 377 EXPECT_EQ(305, fm.GetScrollOffset().x);
michael@0 378 EXPECT_EQ(310, fm.GetScrollOffset().y);
michael@0 379
michael@0 380 // part 2 of the test, move to the top-right corner of the page and pinch and
michael@0 381 // make sure we stay in the correct spot
michael@0 382 fm.SetZoom(CSSToScreenScale(2.0));
michael@0 383 fm.SetScrollOffset(CSSPoint(930, 5));
michael@0 384 apzc->SetFrameMetrics(fm);
michael@0 385 // the visible area of the document in CSS pixels is x=930 y=5 w=50 h=100
michael@0 386
michael@0 387 ApzcPinch(apzc, 250, 300, 0.5);
michael@0 388
michael@0 389 // the visible area of the document in CSS pixels is now x=880 y=0 w=100 h=200
michael@0 390 fm = apzc->GetFrameMetrics();
michael@0 391 EXPECT_EQ(1.0f, fm.GetZoom().scale);
michael@0 392 EXPECT_EQ(880, fm.GetScrollOffset().x);
michael@0 393 EXPECT_EQ(0, fm.GetScrollOffset().y);
michael@0 394
michael@0 395 apzc->Destroy();
michael@0 396 }
michael@0 397
michael@0 398 TEST_F(AsyncPanZoomControllerTester, PinchWithTouchActionNone) {
michael@0 399 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 400 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
michael@0 401
michael@0 402 FrameMetrics fm;
michael@0 403 fm.mViewport = CSSRect(0, 0, 980, 480);
michael@0 404 fm.mCompositionBounds = ParentLayerIntRect(200, 200, 100, 200);
michael@0 405 fm.mScrollableRect = CSSRect(0, 0, 980, 1000);
michael@0 406 fm.SetScrollOffset(CSSPoint(300, 300));
michael@0 407 fm.SetZoom(CSSToScreenScale(2.0));
michael@0 408 apzc->SetFrameMetrics(fm);
michael@0 409 // the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100
michael@0 410
michael@0 411 // Apzc's OnScaleEnd method calls once SendAsyncScrollDOMEvent and RequestContentRepaint methods,
michael@0 412 // therefore we're setting these specific values.
michael@0 413 EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtMost(1));
michael@0 414 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtMost(1));
michael@0 415
michael@0 416 nsTArray<uint32_t> values;
michael@0 417 values.AppendElement(mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
michael@0 418 values.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
michael@0 419 apzc->SetTouchActionEnabled(true);
michael@0 420
michael@0 421 apzc->SetAllowedTouchBehavior(values);
michael@0 422 ApzcPinch(apzc, 250, 300, 1.25);
michael@0 423
michael@0 424 // The frame metrics should stay the same since touch-action:none makes
michael@0 425 // apzc ignore pinch gestures.
michael@0 426 fm = apzc->GetFrameMetrics();
michael@0 427 EXPECT_EQ(2.0f, fm.GetZoom().scale);
michael@0 428 EXPECT_EQ(300, fm.GetScrollOffset().x);
michael@0 429 EXPECT_EQ(300, fm.GetScrollOffset().y);
michael@0 430 }
michael@0 431
michael@0 432 TEST_F(AsyncPanZoomControllerTester, Overzoom) {
michael@0 433 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 434 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
michael@0 435
michael@0 436 FrameMetrics fm;
michael@0 437 fm.mViewport = CSSRect(0, 0, 100, 100);
michael@0 438 fm.mCompositionBounds = ParentLayerIntRect(0, 0, 100, 100);
michael@0 439 fm.mScrollableRect = CSSRect(0, 0, 125, 150);
michael@0 440 fm.SetScrollOffset(CSSPoint(10, 0));
michael@0 441 fm.SetZoom(CSSToScreenScale(1.0));
michael@0 442 apzc->SetFrameMetrics(fm);
michael@0 443 apzc->UpdateZoomConstraints(ZoomConstraints(true, true, CSSToScreenScale(0.25), CSSToScreenScale(4.0)));
michael@0 444 // the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100
michael@0 445
michael@0 446 EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
michael@0 447 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
michael@0 448
michael@0 449 ApzcPinch(apzc, 50, 50, 0.5);
michael@0 450
michael@0 451 fm = apzc->GetFrameMetrics();
michael@0 452 EXPECT_EQ(0.8f, fm.GetZoom().scale);
michael@0 453 // bug 936721 - PGO builds introduce rounding error so
michael@0 454 // use a fuzzy match instead
michael@0 455 EXPECT_LT(abs(fm.GetScrollOffset().x), 1e-5);
michael@0 456 EXPECT_LT(abs(fm.GetScrollOffset().y), 1e-5);
michael@0 457 }
michael@0 458
michael@0 459 TEST_F(AsyncPanZoomControllerTester, SimpleTransform) {
michael@0 460 TimeStamp testStartTime = TimeStamp::Now();
michael@0 461 // RefCounted class can't live in the stack
michael@0 462 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 463 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
michael@0 464 apzc->SetFrameMetrics(TestFrameMetrics());
michael@0 465
michael@0 466 ScreenPoint pointOut;
michael@0 467 ViewTransform viewTransformOut;
michael@0 468 apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
michael@0 469
michael@0 470 EXPECT_EQ(ScreenPoint(), pointOut);
michael@0 471 EXPECT_EQ(ViewTransform(), viewTransformOut);
michael@0 472 }
michael@0 473
michael@0 474
michael@0 475 TEST_F(AsyncPanZoomControllerTester, ComplexTransform) {
michael@0 476 TimeStamp testStartTime = TimeStamp::Now();
michael@0 477 AsyncPanZoomController::SetFrameTime(testStartTime);
michael@0 478
michael@0 479 // This test assumes there is a page that gets rendered to
michael@0 480 // two layers. In CSS pixels, the first layer is 50x50 and
michael@0 481 // the second layer is 25x50. The widget scale factor is 3.0
michael@0 482 // and the presShell resolution is 2.0. Therefore, these layers
michael@0 483 // end up being 300x300 and 150x300 in layer pixels.
michael@0 484 //
michael@0 485 // The second (child) layer has an additional CSS transform that
michael@0 486 // stretches it by 2.0 on the x-axis. Therefore, after applying
michael@0 487 // CSS transforms, the two layers are the same size in screen
michael@0 488 // pixels.
michael@0 489 //
michael@0 490 // The screen itself is 24x24 in screen pixels (therefore 4x4 in
michael@0 491 // CSS pixels). The displayport is 1 extra CSS pixel on all
michael@0 492 // sides.
michael@0 493
michael@0 494 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 495 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
michael@0 496 nsRefPtr<TestAsyncPanZoomController> childApzc = new TestAsyncPanZoomController(0, mcc);
michael@0 497
michael@0 498 const char* layerTreeSyntax = "c(c)";
michael@0 499 // LayerID 0 1
michael@0 500 nsIntRegion layerVisibleRegion[] = {
michael@0 501 nsIntRegion(nsIntRect(0, 0, 300, 300)),
michael@0 502 nsIntRegion(nsIntRect(0, 0, 150, 300)),
michael@0 503 };
michael@0 504 gfx3DMatrix transforms[] = {
michael@0 505 gfx3DMatrix(),
michael@0 506 gfx3DMatrix(),
michael@0 507 };
michael@0 508 transforms[0].ScalePost(0.5f, 0.5f, 1.0f); // this results from the 2.0 resolution on the root layer
michael@0 509 transforms[1].ScalePost(2.0f, 1.0f, 1.0f); // this is the 2.0 x-axis CSS transform on the child layer
michael@0 510
michael@0 511 nsTArray<nsRefPtr<Layer> > layers;
michael@0 512 nsRefPtr<LayerManager> lm;
michael@0 513 nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
michael@0 514
michael@0 515 FrameMetrics metrics;
michael@0 516 metrics.mCompositionBounds = ParentLayerIntRect(0, 0, 24, 24);
michael@0 517 metrics.mDisplayPort = CSSRect(-1, -1, 6, 6);
michael@0 518 metrics.mViewport = CSSRect(0, 0, 4, 4);
michael@0 519 metrics.SetScrollOffset(CSSPoint(10, 10));
michael@0 520 metrics.mScrollableRect = CSSRect(0, 0, 50, 50);
michael@0 521 metrics.mCumulativeResolution = LayoutDeviceToLayerScale(2);
michael@0 522 metrics.mResolution = ParentLayerToLayerScale(2);
michael@0 523 metrics.SetZoom(CSSToScreenScale(6));
michael@0 524 metrics.mDevPixelsPerCSSPixel = CSSToLayoutDeviceScale(3);
michael@0 525 metrics.SetScrollId(FrameMetrics::START_SCROLL_ID);
michael@0 526
michael@0 527 FrameMetrics childMetrics = metrics;
michael@0 528 childMetrics.SetScrollId(FrameMetrics::START_SCROLL_ID + 1);
michael@0 529
michael@0 530 layers[0]->AsContainerLayer()->SetFrameMetrics(metrics);
michael@0 531 layers[1]->AsContainerLayer()->SetFrameMetrics(childMetrics);
michael@0 532
michael@0 533 ScreenPoint pointOut;
michael@0 534 ViewTransform viewTransformOut;
michael@0 535
michael@0 536 // Both the parent and child layer should behave exactly the same here, because
michael@0 537 // the CSS transform on the child layer does not affect the SampleContentTransformForFrame code
michael@0 538
michael@0 539 // initial transform
michael@0 540 apzc->SetFrameMetrics(metrics);
michael@0 541 apzc->NotifyLayersUpdated(metrics, true);
michael@0 542 apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
michael@0 543 EXPECT_EQ(ViewTransform(LayerPoint(), ParentLayerToScreenScale(2)), viewTransformOut);
michael@0 544 EXPECT_EQ(ScreenPoint(60, 60), pointOut);
michael@0 545
michael@0 546 childApzc->SetFrameMetrics(childMetrics);
michael@0 547 childApzc->NotifyLayersUpdated(childMetrics, true);
michael@0 548 childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
michael@0 549 EXPECT_EQ(ViewTransform(LayerPoint(), ParentLayerToScreenScale(2)), viewTransformOut);
michael@0 550 EXPECT_EQ(ScreenPoint(60, 60), pointOut);
michael@0 551
michael@0 552 // do an async scroll by 5 pixels and check the transform
michael@0 553 metrics.ScrollBy(CSSPoint(5, 0));
michael@0 554 apzc->SetFrameMetrics(metrics);
michael@0 555 apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
michael@0 556 EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), ParentLayerToScreenScale(2)), viewTransformOut);
michael@0 557 EXPECT_EQ(ScreenPoint(90, 60), pointOut);
michael@0 558
michael@0 559 childMetrics.ScrollBy(CSSPoint(5, 0));
michael@0 560 childApzc->SetFrameMetrics(childMetrics);
michael@0 561 childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
michael@0 562 EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), ParentLayerToScreenScale(2)), viewTransformOut);
michael@0 563 EXPECT_EQ(ScreenPoint(90, 60), pointOut);
michael@0 564
michael@0 565 // do an async zoom of 1.5x and check the transform
michael@0 566 metrics.ZoomBy(1.5f);
michael@0 567 apzc->SetFrameMetrics(metrics);
michael@0 568 apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
michael@0 569 EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), ParentLayerToScreenScale(3)), viewTransformOut);
michael@0 570 EXPECT_EQ(ScreenPoint(135, 90), pointOut);
michael@0 571
michael@0 572 childMetrics.ZoomBy(1.5f);
michael@0 573 childApzc->SetFrameMetrics(childMetrics);
michael@0 574 childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
michael@0 575 EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), ParentLayerToScreenScale(3)), viewTransformOut);
michael@0 576 EXPECT_EQ(ScreenPoint(135, 90), pointOut);
michael@0 577 }
michael@0 578
michael@0 579 TEST_F(AsyncPanZoomControllerTester, Pan) {
michael@0 580 DoPanTest(true, false, mozilla::layers::AllowedTouchBehavior::NONE);
michael@0 581 }
michael@0 582
michael@0 583 // In the each of the following 4 pan tests we are performing two pan gestures: vertical pan from top
michael@0 584 // to bottom and back - from bottom to top.
michael@0 585 // According to the pointer-events/touch-action spec AUTO and PAN_Y touch-action values allow vertical
michael@0 586 // scrolling while NONE and PAN_X forbid it. The first parameter of DoPanTest method specifies this
michael@0 587 // behavior.
michael@0 588 TEST_F(AsyncPanZoomControllerTester, PanWithTouchActionAuto) {
michael@0 589 DoPanTest(true, true,
michael@0 590 mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN | mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
michael@0 591 }
michael@0 592
michael@0 593 TEST_F(AsyncPanZoomControllerTester, PanWithTouchActionNone) {
michael@0 594 DoPanTest(false, true, 0);
michael@0 595 }
michael@0 596
michael@0 597 TEST_F(AsyncPanZoomControllerTester, PanWithTouchActionPanX) {
michael@0 598 DoPanTest(false, true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN);
michael@0 599 }
michael@0 600
michael@0 601 TEST_F(AsyncPanZoomControllerTester, PanWithTouchActionPanY) {
michael@0 602 DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
michael@0 603 }
michael@0 604
michael@0 605 TEST_F(AsyncPanZoomControllerTester, PanWithPreventDefault) {
michael@0 606 TimeStamp testStartTime = TimeStamp::Now();
michael@0 607 AsyncPanZoomController::SetFrameTime(testStartTime);
michael@0 608
michael@0 609 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 610 nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
michael@0 611 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
michael@0 612
michael@0 613 FrameMetrics frameMetrics(TestFrameMetrics());
michael@0 614 frameMetrics.mMayHaveTouchListeners = true;
michael@0 615
michael@0 616 apzc->SetFrameMetrics(frameMetrics);
michael@0 617 apzc->NotifyLayersUpdated(frameMetrics, true);
michael@0 618
michael@0 619 int time = 0;
michael@0 620 int touchStart = 50;
michael@0 621 int touchEnd = 10;
michael@0 622 ScreenPoint pointOut;
michael@0 623 ViewTransform viewTransformOut;
michael@0 624
michael@0 625 // Pan down
michael@0 626 nsTArray<uint32_t> allowedTouchBehaviors;
michael@0 627 allowedTouchBehaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
michael@0 628 apzc->SetTouchActionEnabled(true);
michael@0 629 ApzcPan(apzc, tm, time, touchStart, touchEnd, true, true, &allowedTouchBehaviors);
michael@0 630
michael@0 631 // Send the signal that content has handled and preventDefaulted the touch
michael@0 632 // events. This flushes the event queue.
michael@0 633 apzc->ContentReceivedTouch(true);
michael@0 634
michael@0 635 apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
michael@0 636 EXPECT_EQ(ScreenPoint(), pointOut);
michael@0 637 EXPECT_EQ(ViewTransform(), viewTransformOut);
michael@0 638
michael@0 639 apzc->Destroy();
michael@0 640 }
michael@0 641
michael@0 642 TEST_F(AsyncPanZoomControllerTester, Fling) {
michael@0 643 TimeStamp testStartTime = TimeStamp::Now();
michael@0 644 AsyncPanZoomController::SetFrameTime(testStartTime);
michael@0 645
michael@0 646 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 647 nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
michael@0 648 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
michael@0 649
michael@0 650 apzc->SetFrameMetrics(TestFrameMetrics());
michael@0 651 apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
michael@0 652
michael@0 653 EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
michael@0 654 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
michael@0 655
michael@0 656 int time = 0;
michael@0 657 int touchStart = 50;
michael@0 658 int touchEnd = 10;
michael@0 659 ScreenPoint pointOut;
michael@0 660 ViewTransform viewTransformOut;
michael@0 661
michael@0 662 // Fling down. Each step scroll further down
michael@0 663 ApzcPan(apzc, tm, time, touchStart, touchEnd);
michael@0 664 ScreenPoint lastPoint;
michael@0 665 for (int i = 1; i < 50; i+=1) {
michael@0 666 apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(i), &viewTransformOut, pointOut);
michael@0 667 EXPECT_GT(pointOut.y, lastPoint.y);
michael@0 668 lastPoint = pointOut;
michael@0 669 }
michael@0 670 }
michael@0 671
michael@0 672 TEST_F(AsyncPanZoomControllerTester, OverScrollPanning) {
michael@0 673 TimeStamp testStartTime = TimeStamp::Now();
michael@0 674 AsyncPanZoomController::SetFrameTime(testStartTime);
michael@0 675
michael@0 676 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 677 nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
michael@0 678 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
michael@0 679
michael@0 680 apzc->SetFrameMetrics(TestFrameMetrics());
michael@0 681 apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
michael@0 682
michael@0 683 EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
michael@0 684 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
michael@0 685
michael@0 686 // Pan sufficiently to hit overscroll behavior
michael@0 687 int time = 0;
michael@0 688 int touchStart = 500;
michael@0 689 int touchEnd = 10;
michael@0 690 ScreenPoint pointOut;
michael@0 691 ViewTransform viewTransformOut;
michael@0 692
michael@0 693 // Pan down
michael@0 694 ApzcPan(apzc, tm, time, touchStart, touchEnd);
michael@0 695 apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(1000), &viewTransformOut, pointOut);
michael@0 696 EXPECT_EQ(ScreenPoint(0, 90), pointOut);
michael@0 697 }
michael@0 698
michael@0 699 TEST_F(AsyncPanZoomControllerTester, ShortPress) {
michael@0 700 nsRefPtr<MockContentControllerDelayed> mcc = new NiceMock<MockContentControllerDelayed>();
michael@0 701 nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
michael@0 702 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
michael@0 703 0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
michael@0 704
michael@0 705 apzc->SetFrameMetrics(TestFrameMetrics());
michael@0 706 apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
michael@0 707 apzc->UpdateZoomConstraints(ZoomConstraints(false, false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
michael@0 708
michael@0 709 int time = 0;
michael@0 710 nsEventStatus status = ApzcTap(apzc, 10, 10, time, 100, mcc.get());
michael@0 711 EXPECT_EQ(nsEventStatus_eIgnore, status);
michael@0 712
michael@0 713 // This verifies that the single tap notification is sent after the
michael@0 714 // touchdown is fully processed. The ordering here is important.
michael@0 715 mcc->CheckHasDelayedTask();
michael@0 716
michael@0 717 EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
michael@0 718 mcc->RunDelayedTask();
michael@0 719
michael@0 720 apzc->Destroy();
michael@0 721 }
michael@0 722
michael@0 723 TEST_F(AsyncPanZoomControllerTester, MediumPress) {
michael@0 724 nsRefPtr<MockContentControllerDelayed> mcc = new NiceMock<MockContentControllerDelayed>();
michael@0 725 nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
michael@0 726 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
michael@0 727 0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
michael@0 728
michael@0 729 apzc->SetFrameMetrics(TestFrameMetrics());
michael@0 730 apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
michael@0 731 apzc->UpdateZoomConstraints(ZoomConstraints(false, false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
michael@0 732
michael@0 733 int time = 0;
michael@0 734 nsEventStatus status = ApzcTap(apzc, 10, 10, time, 400, mcc.get());
michael@0 735 EXPECT_EQ(nsEventStatus_eIgnore, status);
michael@0 736
michael@0 737 // This verifies that the single tap notification is sent after the
michael@0 738 // touchdown is fully processed. The ordering here is important.
michael@0 739 mcc->CheckHasDelayedTask();
michael@0 740
michael@0 741 EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
michael@0 742 mcc->RunDelayedTask();
michael@0 743
michael@0 744 apzc->Destroy();
michael@0 745 }
michael@0 746
michael@0 747 void
michael@0 748 DoLongPressTest(bool aShouldUseTouchAction, uint32_t aBehavior) {
michael@0 749 nsRefPtr<MockContentControllerDelayed> mcc = new MockContentControllerDelayed();
michael@0 750 nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
michael@0 751 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
michael@0 752 0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
michael@0 753
michael@0 754 apzc->SetFrameMetrics(TestFrameMetrics());
michael@0 755 apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
michael@0 756 apzc->UpdateZoomConstraints(ZoomConstraints(false, false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
michael@0 757
michael@0 758 apzc->SetTouchActionEnabled(aShouldUseTouchAction);
michael@0 759
michael@0 760 int time = 0;
michael@0 761
michael@0 762 nsEventStatus status = ApzcDown(apzc, 10, 10, time);
michael@0 763 EXPECT_EQ(nsEventStatus_eConsumeNoDefault, status);
michael@0 764
michael@0 765 // SetAllowedTouchBehavior() must be called after sending touch-start.
michael@0 766 nsTArray<uint32_t> allowedTouchBehaviors;
michael@0 767 allowedTouchBehaviors.AppendElement(aBehavior);
michael@0 768 apzc->SetAllowedTouchBehavior(allowedTouchBehaviors);
michael@0 769
michael@0 770 MockFunction<void(std::string checkPointName)> check;
michael@0 771
michael@0 772 {
michael@0 773 InSequence s;
michael@0 774
michael@0 775 EXPECT_CALL(check, Call("preHandleLongTap"));
michael@0 776 EXPECT_CALL(*mcc, HandleLongTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
michael@0 777 EXPECT_CALL(check, Call("postHandleLongTap"));
michael@0 778
michael@0 779 EXPECT_CALL(check, Call("preHandleLongTapUp"));
michael@0 780 EXPECT_CALL(*mcc, HandleLongTapUp(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
michael@0 781 EXPECT_CALL(check, Call("postHandleLongTapUp"));
michael@0 782 }
michael@0 783
michael@0 784 mcc->CheckHasDelayedTask();
michael@0 785
michael@0 786 // Manually invoke the longpress while the touch is currently down.
michael@0 787 check.Call("preHandleLongTap");
michael@0 788 mcc->RunDelayedTask();
michael@0 789 check.Call("postHandleLongTap");
michael@0 790
michael@0 791 // Destroy pending MAX_TAP timeout task
michael@0 792 mcc->DestroyOldestTask();
michael@0 793 // There should be a TimeoutContentResponse task in the queue still
michael@0 794 // Clear the waiting-for-content timeout task, then send the signal that
michael@0 795 // content has handled this long tap. This takes the place of the
michael@0 796 // "contextmenu" event.
michael@0 797 mcc->CheckHasDelayedTask();
michael@0 798 mcc->ClearDelayedTask();
michael@0 799 apzc->ContentReceivedTouch(true);
michael@0 800
michael@0 801 time += 1000;
michael@0 802
michael@0 803 status = ApzcUp(apzc, 10, 10, time);
michael@0 804 EXPECT_EQ(nsEventStatus_eIgnore, status);
michael@0 805
michael@0 806 // To get a LongTapUp event, we must kick APZC to flush its event queue. This
michael@0 807 // would normally happen if we had a (Tab|RenderFrame)(Parent|Child)
michael@0 808 // mechanism.
michael@0 809 check.Call("preHandleLongTapUp");
michael@0 810 apzc->ContentReceivedTouch(false);
michael@0 811 check.Call("postHandleLongTapUp");
michael@0 812
michael@0 813 apzc->Destroy();
michael@0 814 }
michael@0 815
michael@0 816 void
michael@0 817 DoLongPressPreventDefaultTest(bool aShouldUseTouchAction, uint32_t aBehavior) {
michael@0 818 // We have to initialize both an integer time and TimeStamp time because
michael@0 819 // TimeStamp doesn't have any ToXXX() functions for converting back to
michael@0 820 // primitives.
michael@0 821 TimeStamp testStartTime = TimeStamp::Now();
michael@0 822 int time = 0;
michael@0 823 AsyncPanZoomController::SetFrameTime(testStartTime);
michael@0 824
michael@0 825 nsRefPtr<MockContentControllerDelayed> mcc = new MockContentControllerDelayed();
michael@0 826 nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
michael@0 827 nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
michael@0 828 0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
michael@0 829
michael@0 830 apzc->SetFrameMetrics(TestFrameMetrics());
michael@0 831 apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
michael@0 832 apzc->UpdateZoomConstraints(ZoomConstraints(false, false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
michael@0 833
michael@0 834 apzc->SetTouchActionEnabled(aShouldUseTouchAction);
michael@0 835
michael@0 836 EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(0);
michael@0 837 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
michael@0 838
michael@0 839 int touchX = 10,
michael@0 840 touchStartY = 10,
michael@0 841 touchEndY = 50;
michael@0 842
michael@0 843 nsEventStatus status = ApzcDown(apzc, touchX, touchStartY, time);
michael@0 844 EXPECT_EQ(nsEventStatus_eConsumeNoDefault, status);
michael@0 845
michael@0 846 // SetAllowedTouchBehavior() must be called after sending touch-start.
michael@0 847 nsTArray<uint32_t> allowedTouchBehaviors;
michael@0 848 allowedTouchBehaviors.AppendElement(aBehavior);
michael@0 849 apzc->SetAllowedTouchBehavior(allowedTouchBehaviors);
michael@0 850
michael@0 851 MockFunction<void(std::string checkPointName)> check;
michael@0 852
michael@0 853 {
michael@0 854 InSequence s;
michael@0 855
michael@0 856 EXPECT_CALL(check, Call("preHandleLongTap"));
michael@0 857 EXPECT_CALL(*mcc, HandleLongTap(CSSPoint(touchX, touchStartY), 0, apzc->GetGuid())).Times(1);
michael@0 858 EXPECT_CALL(check, Call("postHandleLongTap"));
michael@0 859 }
michael@0 860
michael@0 861 mcc->CheckHasDelayedTask();
michael@0 862
michael@0 863 // Manually invoke the longpress while the touch is currently down.
michael@0 864 check.Call("preHandleLongTap");
michael@0 865 mcc->RunDelayedTask();
michael@0 866 check.Call("postHandleLongTap");
michael@0 867
michael@0 868 // Destroy pending MAX_TAP timeout task
michael@0 869 mcc->DestroyOldestTask();
michael@0 870 // Clear the waiting-for-content timeout task, then send the signal that
michael@0 871 // content has handled this long tap. This takes the place of the
michael@0 872 // "contextmenu" event.
michael@0 873 mcc->ClearDelayedTask();
michael@0 874 apzc->ContentReceivedTouch(true);
michael@0 875
michael@0 876 time += 1000;
michael@0 877
michael@0 878 MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, time, 0);
michael@0 879 mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(touchX, touchEndY), ScreenSize(0, 0), 0, 0));
michael@0 880 status = apzc->ReceiveInputEvent(mti);
michael@0 881 EXPECT_EQ(nsEventStatus_eIgnore, status);
michael@0 882
michael@0 883 EXPECT_CALL(*mcc, HandleLongTapUp(CSSPoint(touchX, touchEndY), 0, apzc->GetGuid())).Times(1);
michael@0 884 status = ApzcUp(apzc, touchX, touchEndY, time);
michael@0 885 EXPECT_EQ(nsEventStatus_eIgnore, status);
michael@0 886
michael@0 887 // Flush the event queue. Once the "contextmenu" event is handled, any touch
michael@0 888 // events that come from the same series of start->n*move->end events should
michael@0 889 // be discarded, even if only the "contextmenu" event is preventDefaulted.
michael@0 890 apzc->ContentReceivedTouch(false);
michael@0 891
michael@0 892 ScreenPoint pointOut;
michael@0 893 ViewTransform viewTransformOut;
michael@0 894 apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
michael@0 895
michael@0 896 EXPECT_EQ(ScreenPoint(), pointOut);
michael@0 897 EXPECT_EQ(ViewTransform(), viewTransformOut);
michael@0 898
michael@0 899 apzc->Destroy();
michael@0 900 }
michael@0 901
michael@0 902 TEST_F(AsyncPanZoomControllerTester, LongPress) {
michael@0 903 DoLongPressTest(false, mozilla::layers::AllowedTouchBehavior::NONE);
michael@0 904 }
michael@0 905
michael@0 906 TEST_F(AsyncPanZoomControllerTester, LongPressWithTouchAction) {
michael@0 907 DoLongPressTest(true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
michael@0 908 | mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN
michael@0 909 | mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
michael@0 910 }
michael@0 911
michael@0 912 TEST_F(AsyncPanZoomControllerTester, LongPressPreventDefault) {
michael@0 913 DoLongPressPreventDefaultTest(false, mozilla::layers::AllowedTouchBehavior::NONE);
michael@0 914 }
michael@0 915
michael@0 916 TEST_F(AsyncPanZoomControllerTester, LongPressPreventDefaultWithTouchAction) {
michael@0 917 DoLongPressPreventDefaultTest(true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
michael@0 918 | mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN
michael@0 919 | mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
michael@0 920 }
michael@0 921
michael@0 922 // Layer tree for HitTesting1
michael@0 923 static already_AddRefed<mozilla::layers::Layer>
michael@0 924 CreateTestLayerTree1(nsRefPtr<LayerManager>& aLayerManager, nsTArray<nsRefPtr<Layer> >& aLayers) {
michael@0 925 const char* layerTreeSyntax = "c(ttcc)";
michael@0 926 // LayerID 0 1234
michael@0 927 nsIntRegion layerVisibleRegion[] = {
michael@0 928 nsIntRegion(nsIntRect(0,0,100,100)),
michael@0 929 nsIntRegion(nsIntRect(0,0,100,100)),
michael@0 930 nsIntRegion(nsIntRect(10,10,20,20)),
michael@0 931 nsIntRegion(nsIntRect(10,10,20,20)),
michael@0 932 nsIntRegion(nsIntRect(5,5,20,20)),
michael@0 933 };
michael@0 934 gfx3DMatrix transforms[] = {
michael@0 935 gfx3DMatrix(),
michael@0 936 gfx3DMatrix(),
michael@0 937 gfx3DMatrix(),
michael@0 938 gfx3DMatrix(),
michael@0 939 gfx3DMatrix(),
michael@0 940 };
michael@0 941 return CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, aLayerManager, aLayers);
michael@0 942 }
michael@0 943
michael@0 944 // Layer Tree for HitTesting2
michael@0 945 static already_AddRefed<mozilla::layers::Layer>
michael@0 946 CreateTestLayerTree2(nsRefPtr<LayerManager>& aLayerManager, nsTArray<nsRefPtr<Layer> >& aLayers) {
michael@0 947 const char* layerTreeSyntax = "c(cc(c))";
michael@0 948 // LayerID 0 12 3
michael@0 949 nsIntRegion layerVisibleRegion[] = {
michael@0 950 nsIntRegion(nsIntRect(0,0,100,100)),
michael@0 951 nsIntRegion(nsIntRect(10,10,40,40)),
michael@0 952 nsIntRegion(nsIntRect(10,60,40,40)),
michael@0 953 nsIntRegion(nsIntRect(10,60,40,40)),
michael@0 954 };
michael@0 955 gfx3DMatrix transforms[] = {
michael@0 956 gfx3DMatrix(),
michael@0 957 gfx3DMatrix(),
michael@0 958 gfx3DMatrix(),
michael@0 959 gfx3DMatrix(),
michael@0 960 };
michael@0 961 return CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, aLayerManager, aLayers);
michael@0 962 }
michael@0 963
michael@0 964 static void
michael@0 965 SetScrollableFrameMetrics(Layer* aLayer, FrameMetrics::ViewID aScrollId,
michael@0 966 // The scrollable rect is only used in HitTesting2,
michael@0 967 // HitTesting1 doesn't care about it.
michael@0 968 CSSRect aScrollableRect = CSSRect(-1, -1, -1, -1))
michael@0 969 {
michael@0 970 ContainerLayer* container = aLayer->AsContainerLayer();
michael@0 971 FrameMetrics metrics;
michael@0 972 metrics.SetScrollId(aScrollId);
michael@0 973 nsIntRect layerBound = aLayer->GetVisibleRegion().GetBounds();
michael@0 974 metrics.mCompositionBounds = ParentLayerIntRect(layerBound.x, layerBound.y,
michael@0 975 layerBound.width, layerBound.height);
michael@0 976 metrics.mScrollableRect = aScrollableRect;
michael@0 977 metrics.SetScrollOffset(CSSPoint(0, 0));
michael@0 978 container->SetFrameMetrics(metrics);
michael@0 979 }
michael@0 980
michael@0 981 static already_AddRefed<AsyncPanZoomController>
michael@0 982 GetTargetAPZC(APZCTreeManager* manager, const ScreenPoint& aPoint,
michael@0 983 gfx3DMatrix& aTransformToApzcOut, gfx3DMatrix& aTransformToGeckoOut)
michael@0 984 {
michael@0 985 nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(aPoint);
michael@0 986 if (hit) {
michael@0 987 manager->GetInputTransforms(hit.get(), aTransformToApzcOut, aTransformToGeckoOut);
michael@0 988 }
michael@0 989 return hit.forget();
michael@0 990 }
michael@0 991
michael@0 992 // A simple hit testing test that doesn't involve any transforms on layers.
michael@0 993 TEST_F(APZCTreeManagerTester, HitTesting1) {
michael@0 994 nsTArray<nsRefPtr<Layer> > layers;
michael@0 995 nsRefPtr<LayerManager> lm;
michael@0 996 nsRefPtr<Layer> root = CreateTestLayerTree1(lm, layers);
michael@0 997
michael@0 998 TimeStamp testStartTime = TimeStamp::Now();
michael@0 999 AsyncPanZoomController::SetFrameTime(testStartTime);
michael@0 1000 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 1001 ScopedLayerTreeRegistration controller(0, root, mcc);
michael@0 1002
michael@0 1003 nsRefPtr<APZCTreeManager> manager = new TestAPZCTreeManager();
michael@0 1004 gfx3DMatrix transformToApzc;
michael@0 1005 gfx3DMatrix transformToGecko;
michael@0 1006
michael@0 1007 // No APZC attached so hit testing will return no APZC at (20,20)
michael@0 1008 nsRefPtr<AsyncPanZoomController> hit = GetTargetAPZC(manager, ScreenPoint(20, 20), transformToApzc, transformToGecko);
michael@0 1009 AsyncPanZoomController* nullAPZC = nullptr;
michael@0 1010 EXPECT_EQ(nullAPZC, hit.get());
michael@0 1011 EXPECT_EQ(gfx3DMatrix(), transformToApzc);
michael@0 1012 EXPECT_EQ(gfx3DMatrix(), transformToGecko);
michael@0 1013
michael@0 1014 // Now we have a root APZC that will match the page
michael@0 1015 SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
michael@0 1016 manager->UpdatePanZoomControllerTree(nullptr, root, false, 0);
michael@0 1017 hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
michael@0 1018 EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
michael@0 1019 // expect hit point at LayerIntPoint(15, 15)
michael@0 1020 EXPECT_EQ(gfxPoint(15, 15), transformToApzc.Transform(gfxPoint(15, 15)));
michael@0 1021 EXPECT_EQ(gfxPoint(15, 15), transformToGecko.Transform(gfxPoint(15, 15)));
michael@0 1022
michael@0 1023 // Now we have a sub APZC with a better fit
michael@0 1024 SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 1);
michael@0 1025 manager->UpdatePanZoomControllerTree(nullptr, root, false, 0);
michael@0 1026 EXPECT_NE(root->AsContainerLayer()->GetAsyncPanZoomController(), layers[3]->AsContainerLayer()->GetAsyncPanZoomController());
michael@0 1027 hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
michael@0 1028 EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
michael@0 1029 // expect hit point at LayerIntPoint(15, 15)
michael@0 1030 EXPECT_EQ(gfxPoint(15, 15), transformToApzc.Transform(gfxPoint(15, 15)));
michael@0 1031 EXPECT_EQ(gfxPoint(15, 15), transformToGecko.Transform(gfxPoint(15, 15)));
michael@0 1032
michael@0 1033 // Now test hit testing when we have two scrollable layers
michael@0 1034 hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
michael@0 1035 EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
michael@0 1036 SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 2);
michael@0 1037 manager->UpdatePanZoomControllerTree(nullptr, root, false, 0);
michael@0 1038 hit = GetTargetAPZC(manager, ScreenPoint(15, 15), transformToApzc, transformToGecko);
michael@0 1039 EXPECT_EQ(layers[4]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
michael@0 1040 // expect hit point at LayerIntPoint(15, 15)
michael@0 1041 EXPECT_EQ(gfxPoint(15, 15), transformToApzc.Transform(gfxPoint(15, 15)));
michael@0 1042 EXPECT_EQ(gfxPoint(15, 15), transformToGecko.Transform(gfxPoint(15, 15)));
michael@0 1043
michael@0 1044 // Hit test ouside the reach of layer[3,4] but inside root
michael@0 1045 hit = GetTargetAPZC(manager, ScreenPoint(90, 90), transformToApzc, transformToGecko);
michael@0 1046 EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
michael@0 1047 // expect hit point at LayerIntPoint(90, 90)
michael@0 1048 EXPECT_EQ(gfxPoint(90, 90), transformToApzc.Transform(gfxPoint(90, 90)));
michael@0 1049 EXPECT_EQ(gfxPoint(90, 90), transformToGecko.Transform(gfxPoint(90, 90)));
michael@0 1050
michael@0 1051 // Hit test ouside the reach of any layer
michael@0 1052 hit = GetTargetAPZC(manager, ScreenPoint(1000, 10), transformToApzc, transformToGecko);
michael@0 1053 EXPECT_EQ(nullAPZC, hit.get());
michael@0 1054 EXPECT_EQ(gfx3DMatrix(), transformToApzc);
michael@0 1055 EXPECT_EQ(gfx3DMatrix(), transformToGecko);
michael@0 1056 hit = GetTargetAPZC(manager, ScreenPoint(-1000, 10), transformToApzc, transformToGecko);
michael@0 1057 EXPECT_EQ(nullAPZC, hit.get());
michael@0 1058 EXPECT_EQ(gfx3DMatrix(), transformToApzc);
michael@0 1059 EXPECT_EQ(gfx3DMatrix(), transformToGecko);
michael@0 1060
michael@0 1061 manager->ClearTree();
michael@0 1062 }
michael@0 1063
michael@0 1064 // A more involved hit testing test that involves css and async transforms.
michael@0 1065 TEST_F(APZCTreeManagerTester, HitTesting2) {
michael@0 1066 nsTArray<nsRefPtr<Layer> > layers;
michael@0 1067 nsRefPtr<LayerManager> lm;
michael@0 1068 nsRefPtr<Layer> root = CreateTestLayerTree2(lm, layers);
michael@0 1069
michael@0 1070 TimeStamp testStartTime = TimeStamp::Now();
michael@0 1071 AsyncPanZoomController::SetFrameTime(testStartTime);
michael@0 1072 nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
michael@0 1073 ScopedLayerTreeRegistration controller(0, root, mcc);
michael@0 1074
michael@0 1075 nsRefPtr<TestAPZCTreeManager> manager = new TestAPZCTreeManager();
michael@0 1076 nsRefPtr<AsyncPanZoomController> hit;
michael@0 1077 gfx3DMatrix transformToApzc;
michael@0 1078 gfx3DMatrix transformToGecko;
michael@0 1079
michael@0 1080 // Set a CSS transform on one of the layers.
michael@0 1081 Matrix4x4 transform;
michael@0 1082 transform = transform * Matrix4x4().Scale(2, 1, 1);
michael@0 1083 layers[2]->SetBaseTransform(transform);
michael@0 1084
michael@0 1085 // Make some other layers scrollable.
michael@0 1086 SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
michael@0 1087 SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 80, 80));
michael@0 1088 SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 2, CSSRect(0, 0, 80, 80));
michael@0 1089
michael@0 1090 manager->UpdatePanZoomControllerTree(nullptr, root, false, 0);
michael@0 1091
michael@0 1092 // At this point, the following holds (all coordinates in screen pixels):
michael@0 1093 // layers[0] has content from (0,0)-(200,200), clipped by composition bounds (0,0)-(100,100)
michael@0 1094 // layers[1] has content from (10,10)-(90,90), clipped by composition bounds (10,10)-(50,50)
michael@0 1095 // layers[2] has content from (20,60)-(100,100). no clipping as it's not a scrollable layer
michael@0 1096 // layers[3] has content from (20,60)-(180,140), clipped by composition bounds (20,60)-(100,100)
michael@0 1097
michael@0 1098 AsyncPanZoomController* apzcroot = root->AsContainerLayer()->GetAsyncPanZoomController();
michael@0 1099 AsyncPanZoomController* apzc1 = layers[1]->AsContainerLayer()->GetAsyncPanZoomController();
michael@0 1100 AsyncPanZoomController* apzc3 = layers[3]->AsContainerLayer()->GetAsyncPanZoomController();
michael@0 1101
michael@0 1102 // Hit an area that's clearly on the root layer but not any of the child layers.
michael@0 1103 hit = GetTargetAPZC(manager, ScreenPoint(75, 25), transformToApzc, transformToGecko);
michael@0 1104 EXPECT_EQ(apzcroot, hit.get());
michael@0 1105 EXPECT_EQ(gfxPoint(75, 25), transformToApzc.Transform(gfxPoint(75, 25)));
michael@0 1106 EXPECT_EQ(gfxPoint(75, 25), transformToGecko.Transform(gfxPoint(75, 25)));
michael@0 1107
michael@0 1108 // Hit an area on the root that would be on layers[3] if layers[2]
michael@0 1109 // weren't transformed.
michael@0 1110 // Note that if layers[2] were scrollable, then this would hit layers[2]
michael@0 1111 // because its composition bounds would be at (10,60)-(50,100) (and the
michael@0 1112 // scale-only transform that we set on layers[2] would be invalid because
michael@0 1113 // it would place the layer into overscroll, as its composition bounds
michael@0 1114 // start at x=10 but its content at x=20).
michael@0 1115 hit = GetTargetAPZC(manager, ScreenPoint(15, 75), transformToApzc, transformToGecko);
michael@0 1116 EXPECT_EQ(apzcroot, hit.get());
michael@0 1117 EXPECT_EQ(gfxPoint(15, 75), transformToApzc.Transform(gfxPoint(15, 75)));
michael@0 1118 EXPECT_EQ(gfxPoint(15, 75), transformToGecko.Transform(gfxPoint(15, 75)));
michael@0 1119
michael@0 1120 // Hit an area on layers[1].
michael@0 1121 hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
michael@0 1122 EXPECT_EQ(apzc1, hit.get());
michael@0 1123 EXPECT_EQ(gfxPoint(25, 25), transformToApzc.Transform(gfxPoint(25, 25)));
michael@0 1124 EXPECT_EQ(gfxPoint(25, 25), transformToGecko.Transform(gfxPoint(25, 25)));
michael@0 1125
michael@0 1126 // Hit an area on layers[3].
michael@0 1127 hit = GetTargetAPZC(manager, ScreenPoint(25, 75), transformToApzc, transformToGecko);
michael@0 1128 EXPECT_EQ(apzc3, hit.get());
michael@0 1129 // transformToApzc should unapply layers[2]'s transform
michael@0 1130 EXPECT_EQ(gfxPoint(12.5, 75), transformToApzc.Transform(gfxPoint(25, 75)));
michael@0 1131 // and transformToGecko should reapply it
michael@0 1132 EXPECT_EQ(gfxPoint(25, 75), transformToGecko.Transform(gfxPoint(12.5, 75)));
michael@0 1133
michael@0 1134 // Hit an area on layers[3] that would be on the root if layers[2]
michael@0 1135 // weren't transformed.
michael@0 1136 hit = GetTargetAPZC(manager, ScreenPoint(75, 75), transformToApzc, transformToGecko);
michael@0 1137 EXPECT_EQ(apzc3, hit.get());
michael@0 1138 // transformToApzc should unapply layers[2]'s transform
michael@0 1139 EXPECT_EQ(gfxPoint(37.5, 75), transformToApzc.Transform(gfxPoint(75, 75)));
michael@0 1140 // and transformToGecko should reapply it
michael@0 1141 EXPECT_EQ(gfxPoint(75, 75), transformToGecko.Transform(gfxPoint(37.5, 75)));
michael@0 1142
michael@0 1143 // Pan the root layer upward by 50 pixels.
michael@0 1144 // This causes layers[1] to scroll out of view, and an async transform
michael@0 1145 // of -50 to be set on the root layer.
michael@0 1146 int time = 0;
michael@0 1147 // Silence GMock warnings about "uninteresting mock function calls".
michael@0 1148 EXPECT_CALL(*mcc, PostDelayedTask(_,_)).Times(AtLeast(1));
michael@0 1149 EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
michael@0 1150 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
michael@0 1151
michael@0 1152 // This first pan will move the APZC by 50 pixels, and dispatch a paint request.
michael@0 1153 // Since this paint request is in the queue to Gecko, transformToGecko will
michael@0 1154 // take it into account.
michael@0 1155 ApzcPan(apzcroot, manager, time, 100, 50);
michael@0 1156
michael@0 1157 // Hit where layers[3] used to be. It should now hit the root.
michael@0 1158 hit = GetTargetAPZC(manager, ScreenPoint(75, 75), transformToApzc, transformToGecko);
michael@0 1159 EXPECT_EQ(apzcroot, hit.get());
michael@0 1160 // transformToApzc doesn't unapply the root's own async transform
michael@0 1161 EXPECT_EQ(gfxPoint(75, 75), transformToApzc.Transform(gfxPoint(75, 75)));
michael@0 1162 // and transformToGecko unapplies it and then reapplies it, because by the
michael@0 1163 // time the event being transformed reaches Gecko the new paint request will
michael@0 1164 // have been handled.
michael@0 1165 EXPECT_EQ(gfxPoint(75, 75), transformToGecko.Transform(gfxPoint(75, 75)));
michael@0 1166
michael@0 1167 // Hit where layers[1] used to be and where layers[3] should now be.
michael@0 1168 hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
michael@0 1169 EXPECT_EQ(apzc3, hit.get());
michael@0 1170 // transformToApzc unapplies both layers[2]'s css transform and the root's
michael@0 1171 // async transform
michael@0 1172 EXPECT_EQ(gfxPoint(12.5, 75), transformToApzc.Transform(gfxPoint(25, 25)));
michael@0 1173 // transformToGecko reapplies both the css transform and the async transform
michael@0 1174 // because we have already issued a paint request with it.
michael@0 1175 EXPECT_EQ(gfxPoint(25, 25), transformToGecko.Transform(gfxPoint(12.5, 75)));
michael@0 1176
michael@0 1177 // This second pan will move the APZC by another 50 pixels but since the paint
michael@0 1178 // request dispatched above has not "completed", we will not dispatch another
michael@0 1179 // one yet. Now we have an async transform on top of the pending paint request
michael@0 1180 // transform.
michael@0 1181 ApzcPan(apzcroot, manager, time, 100, 50);
michael@0 1182
michael@0 1183 // Hit where layers[3] used to be. It should now hit the root.
michael@0 1184 hit = GetTargetAPZC(manager, ScreenPoint(75, 75), transformToApzc, transformToGecko);
michael@0 1185 EXPECT_EQ(apzcroot, hit.get());
michael@0 1186 // transformToApzc doesn't unapply the root's own async transform
michael@0 1187 EXPECT_EQ(gfxPoint(75, 75), transformToApzc.Transform(gfxPoint(75, 75)));
michael@0 1188 // transformToGecko unapplies the full async transform of -100 pixels, and then
michael@0 1189 // reapplies the "D" transform of -50 leading to an overall adjustment of +50
michael@0 1190 EXPECT_EQ(gfxPoint(75, 125), transformToGecko.Transform(gfxPoint(75, 75)));
michael@0 1191
michael@0 1192 // Hit where layers[1] used to be. It should now hit the root.
michael@0 1193 hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko);
michael@0 1194 EXPECT_EQ(apzcroot, hit.get());
michael@0 1195 // transformToApzc doesn't unapply the root's own async transform
michael@0 1196 EXPECT_EQ(gfxPoint(25, 25), transformToApzc.Transform(gfxPoint(25, 25)));
michael@0 1197 // transformToGecko unapplies the full async transform of -100 pixels, and then
michael@0 1198 // reapplies the "D" transform of -50 leading to an overall adjustment of +50
michael@0 1199 EXPECT_EQ(gfxPoint(25, 75), transformToGecko.Transform(gfxPoint(25, 25)));
michael@0 1200
michael@0 1201 manager->ClearTree();
michael@0 1202 }

mercurial