gfx/tests/gtest/TestAsyncPanZoomController.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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  */
     6 #include "gtest/gtest.h"
     7 #include "gmock/gmock.h"
     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"
    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;
    31 class Task;
    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 };
    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 };
    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 };
    65 class MockContentControllerDelayed : public MockContentController {
    66 public:
    67   MockContentControllerDelayed()
    68   {
    69   }
    71   void PostDelayedTask(Task* aTask, int aDelayMs) {
    72     mTaskQueue.AppendElement(aTask);
    73   }
    75   void CheckHasDelayedTask() {
    76     EXPECT_TRUE(mTaskQueue.Length() > 0);
    77   }
    79   void ClearDelayedTask() {
    80     mTaskQueue.RemoveElementAt(0);
    81   }
    83   void DestroyOldestTask() {
    84     delete mTaskQueue[0];
    85     mTaskQueue.RemoveElementAt(0);
    86   }
    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   }
    98 private:
    99   nsTArray<Task*> mTaskQueue;
   100 };
   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 };
   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   {}
   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   }
   131   void SetFrameMetrics(const FrameMetrics& metrics) {
   132     ReentrantMonitorAutoEnter lock(mMonitor);
   133     mFrameMetrics = metrics;
   134   }
   136   FrameMetrics GetFrameMetrics() {
   137     ReentrantMonitorAutoEnter lock(mMonitor);
   138     return mFrameMetrics;
   139   }
   140 };
   142 class TestAPZCTreeManager : public APZCTreeManager {
   143 protected:
   144   void AssertOnCompositorThread() MOZ_OVERRIDE { /* no-op */ }
   146 public:
   147   // Expose this so test code can call it directly.
   148   void BuildOverscrollHandoffChain(AsyncPanZoomController* aApzc) {
   149     APZCTreeManager::BuildOverscrollHandoffChain(aApzc);
   150   }
   151 };
   153 static
   154 FrameMetrics TestFrameMetrics() {
   155   FrameMetrics fm;
   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);
   163   return fm;
   164 }
   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) {
   180   const int TIME_BETWEEN_TOUCH_EVENT = 100;
   181   const int OVERCOME_TOUCH_TOLERANCE = 100;
   182   MultiTouchInput mti;
   183   nsEventStatus status;
   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);
   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   }
   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
   208   // Allowed touch behaviours must be set after sending touch-start.
   209   if (aAllowedTouchBehaviors) {
   210     apzc->SetAllowedTouchBehavior(*aAllowedTouchBehaviors);
   211   }
   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   }
   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);
   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);
   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 }
   241 static
   242 void DoPanTest(bool aShouldTriggerScroll, bool aShouldUseTouchAction, uint32_t aBehavior)
   243 {
   244   TimeStamp testStartTime = TimeStamp::Now();
   245   AsyncPanZoomController::SetFrameTime(testStartTime);
   247   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   248   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   249   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
   251   apzc->SetTouchActionEnabled(aShouldUseTouchAction);
   252   apzc->SetFrameMetrics(TestFrameMetrics());
   253   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
   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   }
   263   int time = 0;
   264   int touchStart = 50;
   265   int touchEnd = 10;
   266   ScreenPoint pointOut;
   267   ViewTransform viewTransformOut;
   269   nsTArray<uint32_t> allowedTouchBehaviors;
   270   allowedTouchBehaviors.AppendElement(aBehavior);
   272   // Pan down
   273   ApzcPan(apzc, tm, time, touchStart, touchEnd, !aShouldTriggerScroll, false, &allowedTouchBehaviors);
   274   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
   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   }
   284   // Pan back
   285   ApzcPan(apzc, tm, time, touchEnd, touchStart, !aShouldTriggerScroll, false, &allowedTouchBehaviors);
   286   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
   288   EXPECT_EQ(ScreenPoint(), pointOut);
   289   EXPECT_EQ(ViewTransform(), viewTransformOut);
   291   apzc->Destroy();
   292 }
   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 }
   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 }
   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 }
   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 }
   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 }
   355 TEST_F(AsyncPanZoomControllerTester, Pinch) {
   356   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   357   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
   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
   369   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   370   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
   372   ApzcPinch(apzc, 250, 300, 1.25);
   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);
   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
   387   ApzcPinch(apzc, 250, 300, 0.5);
   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);
   395   apzc->Destroy();
   396 }
   398 TEST_F(AsyncPanZoomControllerTester, PinchWithTouchActionNone) {
   399   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   400   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
   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
   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));
   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);
   421   apzc->SetAllowedTouchBehavior(values);
   422   ApzcPinch(apzc, 250, 300, 1.25);
   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 }
   432 TEST_F(AsyncPanZoomControllerTester, Overzoom) {
   433   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   434   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
   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
   446   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   447   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
   449   ApzcPinch(apzc, 50, 50, 0.5);
   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 }
   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());
   466   ScreenPoint pointOut;
   467   ViewTransform viewTransformOut;
   468   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
   470   EXPECT_EQ(ScreenPoint(), pointOut);
   471   EXPECT_EQ(ViewTransform(), viewTransformOut);
   472 }
   475 TEST_F(AsyncPanZoomControllerTester, ComplexTransform) {
   476   TimeStamp testStartTime = TimeStamp::Now();
   477   AsyncPanZoomController::SetFrameTime(testStartTime);
   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.
   494   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   495   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
   496   nsRefPtr<TestAsyncPanZoomController> childApzc = new TestAsyncPanZoomController(0, mcc);
   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
   511   nsTArray<nsRefPtr<Layer> > layers;
   512   nsRefPtr<LayerManager> lm;
   513   nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
   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);
   527   FrameMetrics childMetrics = metrics;
   528   childMetrics.SetScrollId(FrameMetrics::START_SCROLL_ID + 1);
   530   layers[0]->AsContainerLayer()->SetFrameMetrics(metrics);
   531   layers[1]->AsContainerLayer()->SetFrameMetrics(childMetrics);
   533   ScreenPoint pointOut;
   534   ViewTransform viewTransformOut;
   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
   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);
   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);
   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);
   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);
   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);
   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 }
   579 TEST_F(AsyncPanZoomControllerTester, Pan) {
   580   DoPanTest(true, false, mozilla::layers::AllowedTouchBehavior::NONE);
   581 }
   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 }
   593 TEST_F(AsyncPanZoomControllerTester, PanWithTouchActionNone) {
   594   DoPanTest(false, true, 0);
   595 }
   597 TEST_F(AsyncPanZoomControllerTester, PanWithTouchActionPanX) {
   598   DoPanTest(false, true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN);
   599 }
   601 TEST_F(AsyncPanZoomControllerTester, PanWithTouchActionPanY) {
   602   DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
   603 }
   605 TEST_F(AsyncPanZoomControllerTester, PanWithPreventDefault) {
   606   TimeStamp testStartTime = TimeStamp::Now();
   607   AsyncPanZoomController::SetFrameTime(testStartTime);
   609   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   610   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   611   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
   613   FrameMetrics frameMetrics(TestFrameMetrics());
   614   frameMetrics.mMayHaveTouchListeners = true;
   616   apzc->SetFrameMetrics(frameMetrics);
   617   apzc->NotifyLayersUpdated(frameMetrics, true);
   619   int time = 0;
   620   int touchStart = 50;
   621   int touchEnd = 10;
   622   ScreenPoint pointOut;
   623   ViewTransform viewTransformOut;
   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);
   631   // Send the signal that content has handled and preventDefaulted the touch
   632   // events. This flushes the event queue.
   633   apzc->ContentReceivedTouch(true);
   635   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
   636   EXPECT_EQ(ScreenPoint(), pointOut);
   637   EXPECT_EQ(ViewTransform(), viewTransformOut);
   639   apzc->Destroy();
   640 }
   642 TEST_F(AsyncPanZoomControllerTester, Fling) {
   643   TimeStamp testStartTime = TimeStamp::Now();
   644   AsyncPanZoomController::SetFrameTime(testStartTime);
   646   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   647   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   648   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
   650   apzc->SetFrameMetrics(TestFrameMetrics());
   651   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
   653   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   654   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
   656   int time = 0;
   657   int touchStart = 50;
   658   int touchEnd = 10;
   659   ScreenPoint pointOut;
   660   ViewTransform viewTransformOut;
   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 }
   672 TEST_F(AsyncPanZoomControllerTester, OverScrollPanning) {
   673   TimeStamp testStartTime = TimeStamp::Now();
   674   AsyncPanZoomController::SetFrameTime(testStartTime);
   676   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   677   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   678   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
   680   apzc->SetFrameMetrics(TestFrameMetrics());
   681   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
   683   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   684   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
   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;
   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 }
   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);
   705   apzc->SetFrameMetrics(TestFrameMetrics());
   706   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
   707   apzc->UpdateZoomConstraints(ZoomConstraints(false, false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
   709   int time = 0;
   710   nsEventStatus status = ApzcTap(apzc, 10, 10, time, 100, mcc.get());
   711   EXPECT_EQ(nsEventStatus_eIgnore, status);
   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();
   717   EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
   718   mcc->RunDelayedTask();
   720   apzc->Destroy();
   721 }
   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);
   729   apzc->SetFrameMetrics(TestFrameMetrics());
   730   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
   731   apzc->UpdateZoomConstraints(ZoomConstraints(false, false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
   733   int time = 0;
   734   nsEventStatus status = ApzcTap(apzc, 10, 10, time, 400, mcc.get());
   735   EXPECT_EQ(nsEventStatus_eIgnore, status);
   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();
   741   EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
   742   mcc->RunDelayedTask();
   744   apzc->Destroy();
   745 }
   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);
   754   apzc->SetFrameMetrics(TestFrameMetrics());
   755   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
   756   apzc->UpdateZoomConstraints(ZoomConstraints(false, false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
   758   apzc->SetTouchActionEnabled(aShouldUseTouchAction);
   760   int time = 0;
   762   nsEventStatus status = ApzcDown(apzc, 10, 10, time);
   763   EXPECT_EQ(nsEventStatus_eConsumeNoDefault, status);
   765   // SetAllowedTouchBehavior() must be called after sending touch-start.
   766   nsTArray<uint32_t> allowedTouchBehaviors;
   767   allowedTouchBehaviors.AppendElement(aBehavior);
   768   apzc->SetAllowedTouchBehavior(allowedTouchBehaviors);
   770   MockFunction<void(std::string checkPointName)> check;
   772   {
   773     InSequence s;
   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"));
   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   }
   784   mcc->CheckHasDelayedTask();
   786   // Manually invoke the longpress while the touch is currently down.
   787   check.Call("preHandleLongTap");
   788   mcc->RunDelayedTask();
   789   check.Call("postHandleLongTap");
   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);
   801   time += 1000;
   803   status = ApzcUp(apzc, 10, 10, time);
   804   EXPECT_EQ(nsEventStatus_eIgnore, status);
   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");
   813   apzc->Destroy();
   814 }
   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);
   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);
   830   apzc->SetFrameMetrics(TestFrameMetrics());
   831   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
   832   apzc->UpdateZoomConstraints(ZoomConstraints(false, false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
   834   apzc->SetTouchActionEnabled(aShouldUseTouchAction);
   836   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(0);
   837   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
   839   int touchX = 10,
   840       touchStartY = 10,
   841       touchEndY = 50;
   843   nsEventStatus status = ApzcDown(apzc, touchX, touchStartY, time);
   844   EXPECT_EQ(nsEventStatus_eConsumeNoDefault, status);
   846   // SetAllowedTouchBehavior() must be called after sending touch-start.
   847   nsTArray<uint32_t> allowedTouchBehaviors;
   848   allowedTouchBehaviors.AppendElement(aBehavior);
   849   apzc->SetAllowedTouchBehavior(allowedTouchBehaviors);
   851   MockFunction<void(std::string checkPointName)> check;
   853   {
   854     InSequence s;
   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   }
   861   mcc->CheckHasDelayedTask();
   863   // Manually invoke the longpress while the touch is currently down.
   864   check.Call("preHandleLongTap");
   865   mcc->RunDelayedTask();
   866   check.Call("postHandleLongTap");
   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);
   876   time += 1000;
   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);
   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);
   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);
   892   ScreenPoint pointOut;
   893   ViewTransform viewTransformOut;
   894   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
   896   EXPECT_EQ(ScreenPoint(), pointOut);
   897   EXPECT_EQ(ViewTransform(), viewTransformOut);
   899   apzc->Destroy();
   900 }
   902 TEST_F(AsyncPanZoomControllerTester, LongPress) {
   903   DoLongPressTest(false, mozilla::layers::AllowedTouchBehavior::NONE);
   904 }
   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 }
   912 TEST_F(AsyncPanZoomControllerTester, LongPressPreventDefault) {
   913   DoLongPressPreventDefaultTest(false, mozilla::layers::AllowedTouchBehavior::NONE);
   914 }
   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 }
   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 }
   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 }
   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 }
   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 }
   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);
   998   TimeStamp testStartTime = TimeStamp::Now();
   999   AsyncPanZoomController::SetFrameTime(testStartTime);
  1000   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
  1001   ScopedLayerTreeRegistration controller(0, root, mcc);
  1003   nsRefPtr<APZCTreeManager> manager = new TestAPZCTreeManager();
  1004   gfx3DMatrix transformToApzc;
  1005   gfx3DMatrix transformToGecko;
  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);
  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)));
  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)));
  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)));
  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)));
  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);
  1061   manager->ClearTree();
  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);
  1070   TimeStamp testStartTime = TimeStamp::Now();
  1071   AsyncPanZoomController::SetFrameTime(testStartTime);
  1072   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
  1073   ScopedLayerTreeRegistration controller(0, root, mcc);
  1075   nsRefPtr<TestAPZCTreeManager> manager = new TestAPZCTreeManager();
  1076   nsRefPtr<AsyncPanZoomController> hit;
  1077   gfx3DMatrix transformToApzc;
  1078   gfx3DMatrix transformToGecko;
  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);
  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));
  1090   manager->UpdatePanZoomControllerTree(nullptr, root, false, 0);
  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)
  1098   AsyncPanZoomController* apzcroot = root->AsContainerLayer()->GetAsyncPanZoomController();
  1099   AsyncPanZoomController* apzc1 = layers[1]->AsContainerLayer()->GetAsyncPanZoomController();
  1100   AsyncPanZoomController* apzc3 = layers[3]->AsContainerLayer()->GetAsyncPanZoomController();
  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)));
  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)));
  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)));
  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)));
  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)));
  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);
  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);
  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)));
  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)));
  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);
  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)));
  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)));
  1201   manager->ClearTree();

mercurial