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