2013-06-24 23:24:42 +04:00
|
|
|
/* vim:set ts=2 sw=2 sts=2 et: */
|
|
|
|
/* Any copyright is dedicated to the Public Domain.
|
|
|
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "gmock/gmock.h"
|
|
|
|
|
2013-08-15 16:03:31 +04:00
|
|
|
#include "mozilla/Attributes.h"
|
2013-06-24 23:24:42 +04:00
|
|
|
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
|
|
|
|
#include "mozilla/layers/GeckoContentController.h"
|
2013-07-30 22:03:41 +04:00
|
|
|
#include "mozilla/layers/CompositorParent.h"
|
|
|
|
#include "mozilla/layers/APZCTreeManager.h"
|
2014-08-28 06:13:43 +04:00
|
|
|
#include "mozilla/layers/LayerMetricsWrapper.h"
|
2015-02-10 16:24:23 +03:00
|
|
|
#include "mozilla/layers/APZThreadUtils.h"
|
2014-07-31 17:04:34 +04:00
|
|
|
#include "mozilla/UniquePtr.h"
|
2014-10-16 17:23:52 +04:00
|
|
|
#include "apz/src/AsyncPanZoomController.h"
|
2015-01-08 17:40:01 +03:00
|
|
|
#include "apz/src/HitTestingTreeNode.h"
|
2013-12-12 04:39:06 +04:00
|
|
|
#include "base/task.h"
|
2013-06-24 23:24:42 +04:00
|
|
|
#include "Layers.h"
|
2013-07-02 20:27:17 +04:00
|
|
|
#include "TestLayers.h"
|
2015-04-12 05:03:00 +03:00
|
|
|
#include "UnitTransforms.h"
|
2014-02-28 21:45:27 +04:00
|
|
|
#include "gfxPrefs.h"
|
2013-06-24 23:24:42 +04:00
|
|
|
|
|
|
|
using namespace mozilla;
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
using namespace mozilla::layers;
|
|
|
|
using ::testing::_;
|
2014-01-15 19:03:16 +04:00
|
|
|
using ::testing::NiceMock;
|
2013-12-07 21:45:19 +04:00
|
|
|
using ::testing::AtLeast;
|
2014-01-15 19:03:16 +04:00
|
|
|
using ::testing::AtMost;
|
2014-02-13 20:24:53 +04:00
|
|
|
using ::testing::MockFunction;
|
|
|
|
using ::testing::InSequence;
|
2013-06-24 23:24:42 +04:00
|
|
|
|
2013-12-12 04:39:06 +04:00
|
|
|
class Task;
|
|
|
|
|
2014-07-15 03:07:53 +04:00
|
|
|
template<class T>
|
|
|
|
class ScopedGfxPref {
|
|
|
|
public:
|
|
|
|
ScopedGfxPref(T (*aGetPrefFunc)(void), void (*aSetPrefFunc)(T), T aVal)
|
|
|
|
: mSetPrefFunc(aSetPrefFunc)
|
|
|
|
{
|
|
|
|
mOldVal = aGetPrefFunc();
|
|
|
|
aSetPrefFunc(aVal);
|
2014-07-11 16:25:13 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:53 +04:00
|
|
|
~ScopedGfxPref() {
|
|
|
|
mSetPrefFunc(mOldVal);
|
2014-07-11 16:25:13 +04:00
|
|
|
}
|
2014-07-15 03:07:53 +04:00
|
|
|
|
|
|
|
private:
|
|
|
|
void (*mSetPrefFunc)(T);
|
|
|
|
T mOldVal;
|
2014-07-11 16:25:13 +04:00
|
|
|
};
|
|
|
|
|
2014-07-15 03:07:53 +04:00
|
|
|
#define SCOPED_GFX_PREF(prefBase, prefType, prefValue) \
|
|
|
|
ScopedGfxPref<prefType> pref_##prefBase( \
|
|
|
|
&(gfxPrefs::prefBase), \
|
|
|
|
&(gfxPrefs::Set##prefBase), \
|
|
|
|
prefValue)
|
|
|
|
|
2013-06-24 23:24:42 +04:00
|
|
|
class MockContentController : public GeckoContentController {
|
|
|
|
public:
|
|
|
|
MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
|
2015-02-20 02:53:30 +03:00
|
|
|
MOCK_METHOD2(RequestFlingSnap, void(const FrameMetrics::ViewID& aScrollId, const mozilla::CSSPoint& aDestination));
|
2014-02-06 02:43:20 +04:00
|
|
|
MOCK_METHOD2(AcknowledgeScrollUpdate, void(const FrameMetrics::ViewID&, const uint32_t& aScrollGeneration));
|
2015-03-03 00:38:07 +03:00
|
|
|
MOCK_METHOD3(HandleDoubleTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&));
|
|
|
|
MOCK_METHOD3(HandleSingleTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&));
|
|
|
|
MOCK_METHOD4(HandleLongTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&, uint64_t));
|
2013-11-09 04:07:00 +04:00
|
|
|
MOCK_METHOD3(SendAsyncScrollDOMEvent, void(bool aIsRoot, const CSSRect &aContentRect, const CSSSize &aScrollableSize));
|
2013-06-24 23:24:42 +04:00
|
|
|
MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs));
|
2014-09-12 19:41:28 +04:00
|
|
|
MOCK_METHOD3(NotifyAPZStateChange, void(const ScrollableLayerGuid& aGuid, APZStateChange aChange, int aArg));
|
2013-06-24 23:24:42 +04:00
|
|
|
};
|
|
|
|
|
2013-12-12 04:39:06 +04:00
|
|
|
class MockContentControllerDelayed : public MockContentController {
|
|
|
|
public:
|
2014-02-11 19:42:42 +04:00
|
|
|
MockContentControllerDelayed()
|
2015-06-01 21:36:12 +03:00
|
|
|
: mTime(TimeStamp::Now())
|
2014-02-11 19:42:42 +04:00
|
|
|
{
|
|
|
|
}
|
2013-12-12 04:39:06 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
const TimeStamp& Time() {
|
|
|
|
return mTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AdvanceByMillis(int aMillis) {
|
|
|
|
AdvanceBy(TimeDuration::FromMilliseconds(aMillis));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AdvanceBy(const TimeDuration& aIncrement) {
|
2015-06-01 21:36:12 +03:00
|
|
|
TimeStamp target = mTime + aIncrement;
|
|
|
|
while (mTaskQueue.Length() > 0 && mTaskQueue[0].second <= target) {
|
|
|
|
RunNextDelayedTask();
|
|
|
|
}
|
|
|
|
mTime = target;
|
2015-06-01 21:36:12 +03:00
|
|
|
}
|
|
|
|
|
2013-12-12 04:39:06 +04:00
|
|
|
void PostDelayedTask(Task* aTask, int aDelayMs) {
|
2015-06-01 21:36:12 +03:00
|
|
|
TimeStamp runAtTime = mTime + TimeDuration::FromMilliseconds(aDelayMs);
|
|
|
|
int insIndex = mTaskQueue.Length();
|
|
|
|
while (insIndex > 0) {
|
|
|
|
if (mTaskQueue[insIndex - 1].second <= runAtTime) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
insIndex--;
|
|
|
|
}
|
|
|
|
mTaskQueue.InsertElementAt(insIndex, std::make_pair(aTask, runAtTime));
|
2013-12-12 04:39:06 +04:00
|
|
|
}
|
|
|
|
|
2014-06-27 02:37:44 +04:00
|
|
|
// Run all the tasks in the queue, returning the number of tasks
|
|
|
|
// run. Note that if a task queues another task while running, that
|
|
|
|
// new task will not be run. Therefore, there may be still be tasks
|
|
|
|
// in the queue after this function is called. Only when the return
|
|
|
|
// value is 0 is the queue guaranteed to be empty.
|
|
|
|
int RunThroughDelayedTasks() {
|
2015-06-01 21:36:12 +03:00
|
|
|
nsTArray<std::pair<Task*, TimeStamp>> runQueue;
|
|
|
|
runQueue.SwapElements(mTaskQueue);
|
|
|
|
int numTasks = runQueue.Length();
|
2014-06-27 02:37:44 +04:00
|
|
|
for (int i = 0; i < numTasks; i++) {
|
2015-06-01 21:36:12 +03:00
|
|
|
mTime = runQueue[i].second;
|
|
|
|
runQueue[i].first->Run();
|
|
|
|
|
|
|
|
// Deleting the task is important in order to release the reference to
|
|
|
|
// the callee object.
|
|
|
|
delete runQueue[i].first;
|
2014-06-27 02:37:44 +04:00
|
|
|
}
|
|
|
|
return numTasks;
|
|
|
|
}
|
|
|
|
|
2013-12-12 04:39:06 +04:00
|
|
|
private:
|
2015-06-01 21:36:12 +03:00
|
|
|
void RunNextDelayedTask() {
|
|
|
|
std::pair<Task*, TimeStamp> next = mTaskQueue[0];
|
|
|
|
mTaskQueue.RemoveElementAt(0);
|
|
|
|
mTime = next.second;
|
|
|
|
next.first->Run();
|
|
|
|
// Deleting the task is important in order to release the reference to
|
|
|
|
// the callee object.
|
|
|
|
delete next.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The following array is sorted by timestamp (tasks are inserted in order by
|
|
|
|
// timestamp).
|
2015-06-01 21:36:12 +03:00
|
|
|
nsTArray<std::pair<Task*, TimeStamp>> mTaskQueue;
|
2015-06-01 21:36:12 +03:00
|
|
|
TimeStamp mTime;
|
2013-12-12 04:39:06 +04:00
|
|
|
};
|
|
|
|
|
2014-10-24 21:29:34 +04:00
|
|
|
class TestAPZCTreeManager : public APZCTreeManager {
|
|
|
|
public:
|
2015-06-01 21:36:12 +03:00
|
|
|
TestAPZCTreeManager() {}
|
2015-05-15 19:45:27 +03:00
|
|
|
|
2014-10-24 21:29:34 +04:00
|
|
|
nsRefPtr<InputQueue> GetInputQueue() const {
|
|
|
|
return mInputQueue;
|
|
|
|
}
|
2014-12-11 18:39:19 +03:00
|
|
|
|
|
|
|
protected:
|
2015-03-21 19:28:04 +03:00
|
|
|
AsyncPanZoomController* MakeAPZCInstance(uint64_t aLayersId, GeckoContentController* aController) override;
|
2014-10-24 21:29:34 +04:00
|
|
|
};
|
|
|
|
|
2013-07-30 22:03:40 +04:00
|
|
|
class TestAsyncPanZoomController : public AsyncPanZoomController {
|
|
|
|
public:
|
2015-06-01 21:36:12 +03:00
|
|
|
TestAsyncPanZoomController(uint64_t aLayersId, MockContentControllerDelayed* aMcc,
|
2014-10-24 21:29:34 +04:00
|
|
|
TestAPZCTreeManager* aTreeManager,
|
2013-12-11 21:19:33 +04:00
|
|
|
GestureBehavior aBehavior = DEFAULT_GESTURES)
|
2014-10-24 21:29:34 +04:00
|
|
|
: AsyncPanZoomController(aLayersId, aTreeManager, aTreeManager->GetInputQueue(), aMcc, aBehavior)
|
2014-12-15 05:37:51 +03:00
|
|
|
, mWaitForMainThread(false)
|
2015-06-01 21:36:12 +03:00
|
|
|
, mcc(aMcc)
|
2013-07-30 22:03:40 +04:00
|
|
|
{}
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
nsEventStatus ReceiveInputEvent(const InputData& aEvent, ScrollableLayerGuid* aDummy, uint64_t* aOutInputBlockId) {
|
|
|
|
// This is a function whose signature matches exactly the ReceiveInputEvent
|
|
|
|
// on APZCTreeManager. This allows us to templates for functions like
|
|
|
|
// TouchDown, TouchUp, etc so that we can reuse the code for dispatching
|
|
|
|
// events into both APZC and APZCTM.
|
|
|
|
return ReceiveInputEvent(aEvent, aOutInputBlockId);
|
|
|
|
}
|
|
|
|
|
2014-10-24 21:29:35 +04:00
|
|
|
nsEventStatus ReceiveInputEvent(const InputData& aEvent, uint64_t* aOutInputBlockId) {
|
2014-12-15 05:37:51 +03:00
|
|
|
return GetInputQueue()->ReceiveInputEvent(this, !mWaitForMainThread, aEvent, aOutInputBlockId);
|
2014-10-24 21:29:35 +04:00
|
|
|
}
|
|
|
|
|
2014-12-09 13:35:12 +03:00
|
|
|
void ContentReceivedInputBlock(uint64_t aInputBlockId, bool aPreventDefault) {
|
|
|
|
GetInputQueue()->ContentReceivedInputBlock(aInputBlockId, aPreventDefault);
|
2014-10-24 21:29:35 +04:00
|
|
|
}
|
2014-12-15 05:37:51 +03:00
|
|
|
|
|
|
|
void ConfirmTarget(uint64_t aInputBlockId) {
|
|
|
|
nsRefPtr<AsyncPanZoomController> target = this;
|
|
|
|
GetInputQueue()->SetConfirmedTargetApzc(aInputBlockId, target);
|
|
|
|
}
|
|
|
|
|
2014-10-24 21:29:35 +04:00
|
|
|
void SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aBehaviors) {
|
|
|
|
GetInputQueue()->SetAllowedTouchBehavior(aInputBlockId, aBehaviors);
|
|
|
|
}
|
|
|
|
|
2013-07-30 22:03:40 +04:00
|
|
|
void SetFrameMetrics(const FrameMetrics& metrics) {
|
2013-07-31 16:53:16 +04:00
|
|
|
ReentrantMonitorAutoEnter lock(mMonitor);
|
2013-07-30 22:03:40 +04:00
|
|
|
mFrameMetrics = metrics;
|
|
|
|
}
|
2013-10-10 20:21:50 +04:00
|
|
|
|
2014-07-16 16:33:50 +04:00
|
|
|
FrameMetrics& GetFrameMetrics() {
|
|
|
|
ReentrantMonitorAutoEnter lock(mMonitor);
|
|
|
|
return mFrameMetrics;
|
|
|
|
}
|
|
|
|
|
|
|
|
const FrameMetrics& GetFrameMetrics() const {
|
2013-10-10 20:21:50 +04:00
|
|
|
ReentrantMonitorAutoEnter lock(mMonitor);
|
|
|
|
return mFrameMetrics;
|
|
|
|
}
|
2014-05-30 10:00:31 +04:00
|
|
|
|
2015-06-04 02:38:50 +03:00
|
|
|
using AsyncPanZoomController::GetVelocityVector;
|
|
|
|
|
2014-08-20 03:57:22 +04:00
|
|
|
void AssertStateIsReset() const {
|
2014-05-30 10:00:31 +04:00
|
|
|
ReentrantMonitorAutoEnter lock(mMonitor);
|
|
|
|
EXPECT_EQ(NOTHING, mState);
|
|
|
|
}
|
2014-08-20 05:17:10 +04:00
|
|
|
|
2014-08-20 03:57:22 +04:00
|
|
|
void AssertStateIsFling() const {
|
|
|
|
ReentrantMonitorAutoEnter lock(mMonitor);
|
|
|
|
EXPECT_EQ(FLING, mState);
|
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
void AdvanceAnimationsUntilEnd(const TimeDuration& aIncrement = TimeDuration::FromMilliseconds(10)) {
|
|
|
|
while (AdvanceAnimations(mcc->Time())) {
|
|
|
|
mcc->AdvanceBy(aIncrement);
|
2014-08-20 03:57:22 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
bool SampleContentTransformForFrame(ViewTransform* aOutTransform,
|
|
|
|
ParentLayerPoint& aScrollOffset,
|
|
|
|
const TimeDuration& aIncrement = TimeDuration::FromMilliseconds(0)) {
|
|
|
|
mcc->AdvanceBy(aIncrement);
|
|
|
|
bool ret = AdvanceAnimations(mcc->Time());
|
2014-08-20 05:17:10 +04:00
|
|
|
AsyncPanZoomController::SampleContentTransformForFrame(
|
2014-10-02 01:49:31 +04:00
|
|
|
aOutTransform, aScrollOffset);
|
2014-08-20 05:17:10 +04:00
|
|
|
return ret;
|
|
|
|
}
|
2014-12-15 05:37:51 +03:00
|
|
|
|
|
|
|
void SetWaitForMainThread() {
|
|
|
|
mWaitForMainThread = true;
|
|
|
|
}
|
|
|
|
|
2015-05-15 19:45:27 +03:00
|
|
|
TimeStamp GetFrameTime() const {
|
2015-06-01 21:36:12 +03:00
|
|
|
return mcc->Time();
|
2015-05-15 19:45:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static TimeStamp GetStartupTime() {
|
|
|
|
static TimeStamp sStartupTime = TimeStamp::Now();
|
|
|
|
return sStartupTime;
|
|
|
|
}
|
|
|
|
|
2014-12-15 05:37:51 +03:00
|
|
|
private:
|
|
|
|
bool mWaitForMainThread;
|
2015-06-01 21:36:12 +03:00
|
|
|
MockContentControllerDelayed* mcc;
|
2013-07-30 22:03:40 +04:00
|
|
|
};
|
|
|
|
|
2014-12-11 18:39:19 +03:00
|
|
|
AsyncPanZoomController*
|
|
|
|
TestAPZCTreeManager::MakeAPZCInstance(uint64_t aLayersId, GeckoContentController* aController)
|
|
|
|
{
|
2015-06-01 21:36:12 +03:00
|
|
|
MockContentControllerDelayed* mcc = static_cast<MockContentControllerDelayed*>(aController);
|
|
|
|
return new TestAsyncPanZoomController(aLayersId, mcc, this,
|
|
|
|
AsyncPanZoomController::USE_GESTURE_DETECTOR);
|
2014-12-11 18:39:19 +03:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:53 +04:00
|
|
|
static FrameMetrics
|
|
|
|
TestFrameMetrics()
|
|
|
|
{
|
2013-06-24 23:24:42 +04:00
|
|
|
FrameMetrics fm;
|
|
|
|
|
2014-12-23 18:35:58 +03:00
|
|
|
fm.SetDisplayPort(CSSRect(0, 0, 10, 10));
|
2015-05-07 21:44:03 +03:00
|
|
|
fm.SetCompositionBounds(ParentLayerRect(0, 0, 10, 10));
|
2014-12-30 22:07:57 +03:00
|
|
|
fm.SetCriticalDisplayPort(CSSRect(0, 0, 10, 10));
|
2014-12-27 20:48:27 +03:00
|
|
|
fm.SetScrollableRect(CSSRect(0, 0, 100, 100));
|
2013-06-24 23:24:42 +04:00
|
|
|
|
|
|
|
return fm;
|
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
class APZCBasicTester : public ::testing::Test {
|
2014-07-15 03:07:54 +04:00
|
|
|
public:
|
2014-09-01 07:31:20 +04:00
|
|
|
explicit APZCBasicTester(AsyncPanZoomController::GestureBehavior aGestureBehavior = AsyncPanZoomController::DEFAULT_GESTURES)
|
2014-07-15 03:07:54 +04:00
|
|
|
: mGestureBehavior(aGestureBehavior)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void SetUp()
|
|
|
|
{
|
2014-07-15 03:07:54 +04:00
|
|
|
gfxPrefs::GetSingleton();
|
2015-02-10 16:24:23 +03:00
|
|
|
APZThreadUtils::SetThreadAssertionsEnabled(false);
|
2015-04-29 14:22:27 +03:00
|
|
|
APZThreadUtils::SetControllerThread(MessageLoop::current());
|
2014-07-15 03:07:54 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
mcc = new NiceMock<MockContentControllerDelayed>();
|
2015-06-01 21:36:12 +03:00
|
|
|
tm = new TestAPZCTreeManager();
|
|
|
|
apzc = new TestAsyncPanZoomController(0, mcc, tm, mGestureBehavior);
|
2014-07-15 03:07:54 +04:00
|
|
|
apzc->SetFrameMetrics(TestFrameMetrics());
|
|
|
|
}
|
|
|
|
|
2015-04-30 02:38:02 +03:00
|
|
|
/**
|
|
|
|
* Get the APZC's scroll range in CSS pixels.
|
|
|
|
*/
|
|
|
|
CSSRect GetScrollRange() const
|
|
|
|
{
|
|
|
|
const FrameMetrics& metrics = apzc->GetFrameMetrics();
|
|
|
|
return CSSRect(
|
|
|
|
metrics.GetScrollableRect().TopLeft(),
|
|
|
|
metrics.GetScrollableRect().Size() - metrics.CalculateCompositedSizeInCssPixels());
|
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
virtual void TearDown()
|
|
|
|
{
|
2015-06-01 21:36:12 +03:00
|
|
|
while (mcc->RunThroughDelayedTasks());
|
2014-07-15 03:07:54 +04:00
|
|
|
apzc->Destroy();
|
|
|
|
}
|
|
|
|
|
2015-03-10 16:29:25 +03:00
|
|
|
void MakeApzcWaitForMainThread()
|
2014-07-15 03:07:54 +04:00
|
|
|
{
|
2014-12-15 05:37:51 +03:00
|
|
|
apzc->SetWaitForMainThread();
|
2014-07-15 03:07:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void MakeApzcZoomable()
|
|
|
|
{
|
2014-11-10 22:35:11 +03:00
|
|
|
apzc->UpdateZoomConstraints(ZoomConstraints(true, true, CSSToParentLayerScale(0.25f), CSSToParentLayerScale(4.0f)));
|
2014-07-15 03:07:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void MakeApzcUnzoomable()
|
|
|
|
{
|
2014-11-10 22:35:11 +03:00
|
|
|
apzc->UpdateZoomConstraints(ZoomConstraints(false, false, CSSToParentLayerScale(1.0f), CSSToParentLayerScale(1.0f)));
|
2014-07-15 03:07:54 +04:00
|
|
|
}
|
|
|
|
|
2015-05-15 19:45:27 +03:00
|
|
|
void PanIntoOverscroll();
|
2015-04-30 02:38:02 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Sample animations once, 1 ms later than the last sample.
|
|
|
|
*/
|
|
|
|
void SampleAnimationOnce()
|
|
|
|
{
|
|
|
|
const TimeDuration increment = TimeDuration::FromMilliseconds(1);
|
|
|
|
ParentLayerPoint pointOut;
|
|
|
|
ViewTransform viewTransformOut;
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->AdvanceBy(increment);
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2015-04-30 02:38:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sample animations until we recover from overscroll.
|
|
|
|
* @param aExpectedScrollOffset the expected reported scroll offset
|
|
|
|
* throughout the animation
|
|
|
|
*/
|
|
|
|
void SampleAnimationUntilRecoveredFromOverscroll(const ParentLayerPoint& aExpectedScrollOffset)
|
|
|
|
{
|
|
|
|
const TimeDuration increment = TimeDuration::FromMilliseconds(1);
|
|
|
|
bool recoveredFromOverscroll = false;
|
|
|
|
ParentLayerPoint pointOut;
|
|
|
|
ViewTransform viewTransformOut;
|
2015-06-01 21:36:12 +03:00
|
|
|
while (apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut)) {
|
2015-04-30 02:38:02 +03:00
|
|
|
// The reported scroll offset should be the same throughout.
|
|
|
|
EXPECT_EQ(aExpectedScrollOffset, pointOut);
|
|
|
|
|
|
|
|
// Trigger computation of the overscroll tranform, to make sure
|
|
|
|
// no assetions fire during the calculation.
|
|
|
|
apzc->GetOverscrollTransform();
|
|
|
|
|
|
|
|
if (!apzc->IsOverscrolled()) {
|
|
|
|
recoveredFromOverscroll = true;
|
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->AdvanceBy(increment);
|
2015-04-30 02:38:02 +03:00
|
|
|
}
|
|
|
|
EXPECT_TRUE(recoveredFromOverscroll);
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
|
2015-04-09 02:59:14 +03:00
|
|
|
void TestOverscroll();
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
AsyncPanZoomController::GestureBehavior mGestureBehavior;
|
|
|
|
nsRefPtr<MockContentControllerDelayed> mcc;
|
|
|
|
nsRefPtr<TestAPZCTreeManager> tm;
|
|
|
|
nsRefPtr<TestAsyncPanZoomController> apzc;
|
|
|
|
};
|
|
|
|
|
|
|
|
class APZCGestureDetectorTester : public APZCBasicTester {
|
|
|
|
public:
|
|
|
|
APZCGestureDetectorTester()
|
|
|
|
: APZCBasicTester(AsyncPanZoomController::USE_GESTURE_DETECTOR)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
/* The InputReceiver template parameter used in the helper functions below needs
|
2015-03-02 19:51:45 +03:00
|
|
|
* to be a class that implements functions with the signatures:
|
2014-10-31 22:31:35 +03:00
|
|
|
* nsEventStatus ReceiveInputEvent(const InputData& aEvent,
|
|
|
|
* ScrollableLayerGuid* aGuid,
|
|
|
|
* uint64_t* aOutInputBlockId);
|
2015-03-02 19:51:45 +03:00
|
|
|
* void SetAllowedTouchBehavior(uint64_t aInputBlockId,
|
|
|
|
* const nsTArray<uint32_t>& aBehaviours);
|
|
|
|
* The classes that currently implement these are APZCTreeManager and
|
2014-10-31 22:31:35 +03:00
|
|
|
* TestAsyncPanZoomController. Using this template allows us to test individual
|
|
|
|
* APZC instances in isolation and also an entire APZ tree, while using the same
|
|
|
|
* code to dispatch input events.
|
|
|
|
*/
|
|
|
|
|
2014-11-10 22:35:11 +03:00
|
|
|
// Some helper functions for constructing input event objects suitable to be
|
|
|
|
// passed either to an APZC (which expects an transformed point), or to an APZTM
|
|
|
|
// (which expects an untransformed point). We handle both cases by setting both
|
|
|
|
// the transformed and untransformed fields to the same value.
|
|
|
|
static SingleTouchData
|
|
|
|
CreateSingleTouchData(int32_t aIdentifier, int aX, int aY)
|
|
|
|
{
|
|
|
|
SingleTouchData touch(aIdentifier, ScreenIntPoint(aX, aY), ScreenSize(0, 0), 0, 0);
|
|
|
|
touch.mLocalScreenPoint = ParentLayerPoint(aX, aY);
|
|
|
|
return touch;
|
|
|
|
}
|
|
|
|
static PinchGestureInput
|
|
|
|
CreatePinchGestureInput(PinchGestureInput::PinchGestureType aType,
|
|
|
|
int aFocusX, int aFocusY,
|
|
|
|
float aCurrentSpan, float aPreviousSpan)
|
|
|
|
{
|
|
|
|
PinchGestureInput result(aType, 0, TimeStamp(), ScreenPoint(aFocusX, aFocusY),
|
|
|
|
aCurrentSpan, aPreviousSpan, 0);
|
|
|
|
result.mLocalFocusPoint = ParentLayerPoint(aFocusX, aFocusY);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-03-02 19:51:45 +03:00
|
|
|
template<class InputReceiver> static void
|
|
|
|
SetDefaultAllowedTouchBehavior(const nsRefPtr<InputReceiver>& aTarget,
|
|
|
|
uint64_t aInputBlockId,
|
|
|
|
int touchPoints = 1)
|
|
|
|
{
|
|
|
|
nsTArray<uint32_t> defaultBehaviors;
|
|
|
|
// use the default value where everything is allowed
|
|
|
|
for (int i = 0; i < touchPoints; i++) {
|
|
|
|
defaultBehaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
|
|
|
|
| mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN
|
|
|
|
| mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM
|
|
|
|
| mozilla::layers::AllowedTouchBehavior::DOUBLE_TAP_ZOOM);
|
|
|
|
}
|
|
|
|
aTarget->SetAllowedTouchBehavior(aInputBlockId, defaultBehaviors);
|
|
|
|
}
|
|
|
|
|
2015-05-15 19:45:27 +03:00
|
|
|
static uint32_t
|
|
|
|
MillisecondsSinceStartup(TimeStamp aTime)
|
|
|
|
{
|
|
|
|
return (aTime - TestAsyncPanZoomController::GetStartupTime()).ToMilliseconds();
|
|
|
|
}
|
|
|
|
|
|
|
|
static MultiTouchInput
|
|
|
|
CreateMultiTouchInput(MultiTouchInput::MultiTouchType aType, TimeStamp aTime)
|
|
|
|
{
|
|
|
|
return MultiTouchInput(aType, MillisecondsSinceStartup(aTime), aTime, 0);
|
|
|
|
}
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static nsEventStatus
|
2015-05-15 19:45:27 +03:00
|
|
|
TouchDown(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY, TimeStamp aTime, uint64_t* aOutInputBlockId = nullptr)
|
2014-07-15 03:07:53 +04:00
|
|
|
{
|
2015-05-15 19:45:27 +03:00
|
|
|
MultiTouchInput mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, aTime);
|
2014-11-10 22:35:11 +03:00
|
|
|
mti.mTouches.AppendElement(CreateSingleTouchData(0, aX, aY));
|
2014-10-31 22:31:35 +03:00
|
|
|
return aTarget->ReceiveInputEvent(mti, nullptr, aOutInputBlockId);
|
2014-07-15 03:07:53 +04:00
|
|
|
}
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static nsEventStatus
|
2015-05-15 19:45:27 +03:00
|
|
|
TouchMove(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY, TimeStamp aTime)
|
2014-10-31 22:31:35 +03:00
|
|
|
{
|
2015-05-15 19:45:27 +03:00
|
|
|
MultiTouchInput mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime);
|
2014-11-10 22:35:11 +03:00
|
|
|
mti.mTouches.AppendElement(CreateSingleTouchData(0, aX, aY));
|
2014-10-31 22:31:35 +03:00
|
|
|
return aTarget->ReceiveInputEvent(mti, nullptr, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class InputReceiver> static nsEventStatus
|
2015-05-15 19:45:27 +03:00
|
|
|
TouchUp(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY, TimeStamp aTime)
|
2014-07-15 03:07:53 +04:00
|
|
|
{
|
2015-05-15 19:45:27 +03:00
|
|
|
MultiTouchInput mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_END, aTime);
|
2014-11-10 22:35:11 +03:00
|
|
|
mti.mTouches.AppendElement(CreateSingleTouchData(0, aX, aY));
|
2014-10-31 22:31:35 +03:00
|
|
|
return aTarget->ReceiveInputEvent(mti, nullptr, nullptr);
|
2014-07-15 03:07:53 +04:00
|
|
|
}
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static void
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY, MockContentControllerDelayed* aMcc,
|
2015-05-15 19:45:27 +03:00
|
|
|
TimeDuration aTapLength,
|
2014-11-14 15:40:15 +03:00
|
|
|
nsEventStatus (*aOutEventStatuses)[2] = nullptr,
|
|
|
|
uint64_t* aOutInputBlockId = nullptr)
|
2014-07-15 03:07:53 +04:00
|
|
|
{
|
2015-03-02 19:51:45 +03:00
|
|
|
// Even if the caller doesn't care about the block id, we need it to set the
|
|
|
|
// allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
|
|
|
|
uint64_t blockId;
|
|
|
|
if (!aOutInputBlockId) {
|
|
|
|
aOutInputBlockId = &blockId;
|
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
nsEventStatus status = TouchDown(aTarget, aX, aY, aMcc->Time(), aOutInputBlockId);
|
2014-07-17 21:41:53 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[0] = status;
|
2014-07-15 03:07:53 +04:00
|
|
|
}
|
2015-06-01 21:36:12 +03:00
|
|
|
aMcc->AdvanceBy(aTapLength);
|
2015-03-02 19:51:45 +03:00
|
|
|
|
|
|
|
// If touch-action is enabled then simulate the allowed touch behaviour
|
|
|
|
// notification that the main thread is supposed to deliver.
|
2015-03-19 13:33:32 +03:00
|
|
|
if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
|
2015-03-02 19:51:45 +03:00
|
|
|
SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId);
|
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
status = TouchUp(aTarget, aX, aY, aMcc->Time());
|
2014-07-17 21:41:53 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[1] = status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static void
|
2015-05-15 19:45:27 +03:00
|
|
|
TapAndCheckStatus(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY,
|
2015-06-01 21:36:12 +03:00
|
|
|
MockContentControllerDelayed* aMcc, TimeDuration aTapLength)
|
2014-07-17 21:41:53 +04:00
|
|
|
{
|
|
|
|
nsEventStatus statuses[2];
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(aTarget, aX, aY, aMcc, aTapLength, &statuses);
|
2014-08-02 00:24:50 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
|
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[1]);
|
2014-07-15 03:07:53 +04:00
|
|
|
}
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static void
|
|
|
|
Pan(const nsRefPtr<InputReceiver>& aTarget,
|
2015-06-01 21:36:12 +03:00
|
|
|
MockContentControllerDelayed* aMcc,
|
2015-05-12 05:06:03 +03:00
|
|
|
const ScreenPoint& aTouchStart,
|
|
|
|
const ScreenPoint& aTouchEnd,
|
2014-10-31 22:31:35 +03:00
|
|
|
bool aKeepFingerDown = false,
|
|
|
|
nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
|
|
|
|
nsEventStatus (*aOutEventStatuses)[4] = nullptr,
|
|
|
|
uint64_t* aOutInputBlockId = nullptr)
|
2014-07-15 03:07:53 +04:00
|
|
|
{
|
2014-10-31 22:31:35 +03:00
|
|
|
// Reduce the touch start tolerance to a tiny value.
|
|
|
|
// We can't use a scoped pref because this value might be read at some later
|
|
|
|
// time when the events are actually processed, rather than when we deliver
|
|
|
|
// them.
|
|
|
|
gfxPrefs::SetAPZTouchStartTolerance(1.0f / 1000.0f);
|
|
|
|
const int OVERCOME_TOUCH_TOLERANCE = 1;
|
|
|
|
|
2015-06-01 16:51:16 +03:00
|
|
|
const TimeDuration TIME_BETWEEN_TOUCH_EVENT = TimeDuration::FromMilliseconds(50);
|
2013-06-24 23:24:42 +04:00
|
|
|
|
2014-10-24 21:29:30 +04:00
|
|
|
// Even if the caller doesn't care about the block id, we need it to set the
|
|
|
|
// allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
|
|
|
|
uint64_t blockId;
|
|
|
|
if (!aOutInputBlockId) {
|
|
|
|
aOutInputBlockId = &blockId;
|
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:53 +04:00
|
|
|
// Make sure the move is large enough to not be handled as a tap
|
2015-06-01 21:36:12 +03:00
|
|
|
nsEventStatus status = TouchDown(aTarget, aTouchStart.x, aTouchStart.y + OVERCOME_TOUCH_TOLERANCE, aMcc->Time(), aOutInputBlockId);
|
2014-07-15 03:07:53 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[0] = status;
|
2014-02-13 20:24:53 +04:00
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
aMcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
2013-06-24 23:24:42 +04:00
|
|
|
|
2014-04-14 22:59:20 +04:00
|
|
|
// Allowed touch behaviours must be set after sending touch-start.
|
2015-03-19 13:33:32 +03:00
|
|
|
if (status != nsEventStatus_eConsumeNoDefault) {
|
|
|
|
if (aAllowedTouchBehaviors) {
|
|
|
|
EXPECT_EQ(1UL, aAllowedTouchBehaviors->Length());
|
|
|
|
aTarget->SetAllowedTouchBehavior(*aOutInputBlockId, *aAllowedTouchBehaviors);
|
|
|
|
} else if (gfxPrefs::TouchActionEnabled()) {
|
|
|
|
SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId);
|
|
|
|
}
|
2014-04-14 22:59:20 +04:00
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
status = TouchMove(aTarget, aTouchStart.x, aTouchStart.y, aMcc->Time());
|
2014-07-15 03:07:53 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[1] = status;
|
2014-01-15 19:03:16 +04:00
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
aMcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
2013-06-24 23:24:42 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
status = TouchMove(aTarget, aTouchEnd.x, aTouchEnd.y, aMcc->Time());
|
2014-07-15 03:07:53 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[2] = status;
|
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
aMcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
|
2013-06-24 23:24:42 +04:00
|
|
|
|
2014-07-14 20:54:41 +04:00
|
|
|
if (!aKeepFingerDown) {
|
2015-06-01 21:36:12 +03:00
|
|
|
status = TouchUp(aTarget, aTouchEnd.x, aTouchEnd.y, aMcc->Time());
|
2014-07-15 03:07:53 +04:00
|
|
|
} else {
|
2014-08-02 00:24:50 +04:00
|
|
|
status = nsEventStatus_eIgnore;
|
2014-07-15 03:07:53 +04:00
|
|
|
}
|
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[3] = status;
|
2014-07-14 20:54:41 +04:00
|
|
|
}
|
2014-07-15 03:07:53 +04:00
|
|
|
|
2015-05-15 19:45:27 +03:00
|
|
|
// Don't increment the time here. Animations started on touch-up, such as
|
|
|
|
// flings, are affected by elapsed time, and we want to be able to sample
|
|
|
|
// them immediately after they start, without time having elapsed.
|
2013-06-24 23:24:42 +04:00
|
|
|
}
|
|
|
|
|
2015-05-12 05:06:03 +03:00
|
|
|
// A version of Pan() that only takes y coordinates rather than (x, y) points
|
|
|
|
// for the touch start and end points, and uses 10 for the x coordinates.
|
|
|
|
// This is for convenience, as most tests only need to pan in one direction.
|
|
|
|
template<class InputReceiver> static void
|
|
|
|
Pan(const nsRefPtr<InputReceiver>& aTarget,
|
2015-06-01 21:36:12 +03:00
|
|
|
MockContentControllerDelayed* aMcc,
|
2015-05-12 05:06:03 +03:00
|
|
|
int aTouchStartY,
|
|
|
|
int aTouchEndY,
|
|
|
|
bool aKeepFingerDown = false,
|
|
|
|
nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
|
|
|
|
nsEventStatus (*aOutEventStatuses)[4] = nullptr,
|
|
|
|
uint64_t* aOutInputBlockId = nullptr)
|
|
|
|
{
|
2015-06-01 21:36:12 +03:00
|
|
|
::Pan(aTarget, aMcc, ScreenPoint(10, aTouchStartY), ScreenPoint(10, aTouchEndY),
|
2015-05-12 05:06:03 +03:00
|
|
|
aKeepFingerDown, aAllowedTouchBehaviors, aOutEventStatuses, aOutInputBlockId);
|
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:53 +04:00
|
|
|
/*
|
|
|
|
* Dispatches mock touch events to the apzc and checks whether apzc properly
|
|
|
|
* consumed them and triggered scrolling behavior.
|
|
|
|
*/
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static void
|
|
|
|
PanAndCheckStatus(const nsRefPtr<InputReceiver>& aTarget,
|
2015-06-01 21:36:12 +03:00
|
|
|
MockContentControllerDelayed* aMcc,
|
2014-10-31 22:31:35 +03:00
|
|
|
int aTouchStartY,
|
|
|
|
int aTouchEndY,
|
|
|
|
bool aExpectConsumed,
|
|
|
|
nsTArray<uint32_t>* aAllowedTouchBehaviors,
|
|
|
|
uint64_t* aOutInputBlockId = nullptr)
|
2014-07-15 03:07:53 +04:00
|
|
|
{
|
|
|
|
nsEventStatus statuses[4]; // down, move, move, up
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(aTarget, aMcc, aTouchStartY, aTouchEndY, false, aAllowedTouchBehaviors, &statuses, aOutInputBlockId);
|
2014-07-15 03:07:53 +04:00
|
|
|
|
2014-08-02 00:24:50 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
|
2014-07-15 03:07:53 +04:00
|
|
|
|
|
|
|
nsEventStatus touchMoveStatus;
|
2014-08-02 00:24:50 +04:00
|
|
|
if (aExpectConsumed) {
|
2014-07-16 16:33:50 +04:00
|
|
|
touchMoveStatus = nsEventStatus_eConsumeDoDefault;
|
2014-07-15 03:07:53 +04:00
|
|
|
} else {
|
2014-08-02 00:24:50 +04:00
|
|
|
touchMoveStatus = nsEventStatus_eIgnore;
|
2014-07-15 03:07:53 +04:00
|
|
|
}
|
|
|
|
EXPECT_EQ(touchMoveStatus, statuses[1]);
|
|
|
|
EXPECT_EQ(touchMoveStatus, statuses[2]);
|
|
|
|
}
|
|
|
|
|
2014-07-17 21:41:54 +04:00
|
|
|
static void
|
2014-10-31 22:31:35 +03:00
|
|
|
ApzcPanNoFling(const nsRefPtr<TestAsyncPanZoomController>& aApzc,
|
2015-06-01 21:36:12 +03:00
|
|
|
MockContentControllerDelayed* aMcc,
|
2014-07-17 21:41:54 +04:00
|
|
|
int aTouchStartY,
|
2014-10-24 21:29:30 +04:00
|
|
|
int aTouchEndY,
|
|
|
|
uint64_t* aOutInputBlockId = nullptr)
|
2014-07-17 21:41:54 +04:00
|
|
|
{
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(aApzc, aMcc, aTouchStartY, aTouchEndY, false, nullptr, nullptr, aOutInputBlockId);
|
2014-07-17 21:41:54 +04:00
|
|
|
aApzc->CancelAnimation();
|
|
|
|
}
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static void
|
|
|
|
PinchWithPinchInput(const nsRefPtr<InputReceiver>& aTarget,
|
|
|
|
int aFocusX, int aFocusY, float aScale,
|
|
|
|
nsEventStatus (*aOutEventStatuses)[3] = nullptr)
|
2014-07-15 03:07:54 +04:00
|
|
|
{
|
2014-10-31 22:31:35 +03:00
|
|
|
nsEventStatus actualStatus = aTarget->ReceiveInputEvent(
|
2014-11-10 22:35:11 +03:00
|
|
|
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
|
|
|
|
aFocusX, aFocusY, 10.0, 10.0),
|
|
|
|
nullptr);
|
2014-07-15 03:07:54 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[0] = actualStatus;
|
2014-05-05 19:23:00 +04:00
|
|
|
}
|
2014-10-31 22:31:35 +03:00
|
|
|
actualStatus = aTarget->ReceiveInputEvent(
|
2014-11-10 22:35:11 +03:00
|
|
|
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
|
|
|
|
aFocusX, aFocusY, 10.0 * aScale, 10.0),
|
|
|
|
nullptr);
|
2014-07-15 03:07:54 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[1] = actualStatus;
|
|
|
|
}
|
2014-10-31 22:31:35 +03:00
|
|
|
actualStatus = aTarget->ReceiveInputEvent(
|
2014-11-10 22:35:11 +03:00
|
|
|
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
|
|
|
|
// note: negative values here tell APZC
|
|
|
|
// not to turn the pinch into a pan
|
|
|
|
aFocusX, aFocusY, -1.0, -1.0),
|
|
|
|
nullptr);
|
2014-07-15 03:07:54 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[2] = actualStatus;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static void
|
|
|
|
PinchWithPinchInputAndCheckStatus(const nsRefPtr<InputReceiver>& aTarget,
|
|
|
|
int aFocusX, int aFocusY, float aScale,
|
|
|
|
bool aShouldTriggerPinch)
|
2014-07-15 03:07:54 +04:00
|
|
|
{
|
|
|
|
nsEventStatus statuses[3]; // scalebegin, scale, scaleend
|
2014-10-31 22:31:35 +03:00
|
|
|
PinchWithPinchInput(aTarget, aFocusX, aFocusY, aScale, &statuses);
|
2014-05-05 19:23:00 +04:00
|
|
|
|
|
|
|
nsEventStatus expectedStatus = aShouldTriggerPinch
|
2014-07-15 03:07:54 +04:00
|
|
|
? nsEventStatus_eConsumeNoDefault
|
|
|
|
: nsEventStatus_eIgnore;
|
|
|
|
EXPECT_EQ(expectedStatus, statuses[0]);
|
|
|
|
EXPECT_EQ(expectedStatus, statuses[1]);
|
2014-05-05 19:23:00 +04:00
|
|
|
}
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static void
|
|
|
|
PinchWithTouchInput(const nsRefPtr<InputReceiver>& aTarget,
|
|
|
|
int aFocusX, int aFocusY, float aScale,
|
|
|
|
int& inputId,
|
|
|
|
nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
|
|
|
|
nsEventStatus (*aOutEventStatuses)[4] = nullptr,
|
|
|
|
uint64_t* aOutInputBlockId = nullptr)
|
2014-07-15 03:07:54 +04:00
|
|
|
{
|
2014-05-05 19:23:00 +04:00
|
|
|
// Having pinch coordinates in float type may cause problems with high-precision scale values
|
|
|
|
// since SingleTouchData accepts integer value. But for trivial tests it should be ok.
|
|
|
|
float pinchLength = 100.0;
|
|
|
|
float pinchLengthScaled = pinchLength * aScale;
|
|
|
|
|
2014-10-24 21:29:30 +04:00
|
|
|
// Even if the caller doesn't care about the block id, we need it to set the
|
|
|
|
// allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
|
|
|
|
uint64_t blockId;
|
|
|
|
if (!aOutInputBlockId) {
|
|
|
|
aOutInputBlockId = &blockId;
|
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
MultiTouchInput mtiStart = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
|
2014-11-10 22:35:11 +03:00
|
|
|
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocusX, aFocusY));
|
|
|
|
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocusX, aFocusY));
|
2014-10-31 22:31:35 +03:00
|
|
|
nsEventStatus status = aTarget->ReceiveInputEvent(mtiStart, aOutInputBlockId);
|
2014-07-15 03:07:54 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[0] = status;
|
|
|
|
}
|
2014-05-05 19:23:00 +04:00
|
|
|
|
2015-03-02 19:51:45 +03:00
|
|
|
if (aAllowedTouchBehaviors) {
|
|
|
|
EXPECT_EQ(2UL, aAllowedTouchBehaviors->Length());
|
2014-10-31 22:31:35 +03:00
|
|
|
aTarget->SetAllowedTouchBehavior(*aOutInputBlockId, *aAllowedTouchBehaviors);
|
2015-03-02 19:51:45 +03:00
|
|
|
} else if (gfxPrefs::TouchActionEnabled()) {
|
|
|
|
SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId, 2);
|
2014-05-05 19:23:00 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
MultiTouchInput mtiMove1 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
|
2014-11-10 22:35:11 +03:00
|
|
|
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocusX - pinchLength, aFocusY));
|
|
|
|
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocusX + pinchLength, aFocusY));
|
2014-10-31 22:31:35 +03:00
|
|
|
status = aTarget->ReceiveInputEvent(mtiMove1, nullptr);
|
2014-07-15 03:07:54 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[1] = status;
|
|
|
|
}
|
2014-05-05 19:23:00 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
MultiTouchInput mtiMove2 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
|
2014-11-10 22:35:11 +03:00
|
|
|
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocusX - pinchLengthScaled, aFocusY));
|
|
|
|
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocusX + pinchLengthScaled, aFocusY));
|
2014-10-31 22:31:35 +03:00
|
|
|
status = aTarget->ReceiveInputEvent(mtiMove2, nullptr);
|
2014-07-15 03:07:54 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[2] = status;
|
|
|
|
}
|
2014-05-05 19:23:00 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
MultiTouchInput mtiEnd = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, TimeStamp(), 0);
|
2014-11-10 22:35:11 +03:00
|
|
|
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocusX - pinchLengthScaled, aFocusY));
|
|
|
|
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocusX + pinchLengthScaled, aFocusY));
|
2014-10-31 22:31:35 +03:00
|
|
|
status = aTarget->ReceiveInputEvent(mtiEnd, nullptr);
|
2014-07-15 03:07:54 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[3] = status;
|
|
|
|
}
|
|
|
|
|
2014-05-05 19:23:00 +04:00
|
|
|
inputId += 2;
|
|
|
|
}
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static void
|
|
|
|
PinchWithTouchInputAndCheckStatus(const nsRefPtr<InputReceiver>& aTarget,
|
|
|
|
int aFocusX, int aFocusY, float aScale,
|
|
|
|
int& inputId, bool aShouldTriggerPinch,
|
|
|
|
nsTArray<uint32_t>* aAllowedTouchBehaviors)
|
2014-07-15 03:07:54 +04:00
|
|
|
{
|
|
|
|
nsEventStatus statuses[4]; // down, move, move, up
|
2014-10-31 22:31:35 +03:00
|
|
|
PinchWithTouchInput(aTarget, aFocusX, aFocusY, aScale, inputId, aAllowedTouchBehaviors, &statuses);
|
2014-07-15 03:07:54 +04:00
|
|
|
|
2014-08-02 00:24:50 +04:00
|
|
|
nsEventStatus expectedMoveStatus = aShouldTriggerPinch
|
|
|
|
? nsEventStatus_eConsumeDoDefault
|
2014-07-15 03:07:54 +04:00
|
|
|
: nsEventStatus_eIgnore;
|
2014-08-02 00:24:50 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
|
|
|
|
EXPECT_EQ(expectedMoveStatus, statuses[1]);
|
|
|
|
EXPECT_EQ(expectedMoveStatus, statuses[2]);
|
2014-07-15 03:07:54 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
class APZCPinchTester : public APZCBasicTester {
|
|
|
|
public:
|
2014-09-01 07:31:20 +04:00
|
|
|
explicit APZCPinchTester(AsyncPanZoomController::GestureBehavior aGestureBehavior = AsyncPanZoomController::DEFAULT_GESTURES)
|
2014-07-15 03:07:54 +04:00
|
|
|
: APZCBasicTester(aGestureBehavior)
|
|
|
|
{
|
2014-05-05 19:23:00 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
protected:
|
2014-07-16 16:33:50 +04:00
|
|
|
FrameMetrics GetPinchableFrameMetrics()
|
2014-07-15 03:07:54 +04:00
|
|
|
{
|
|
|
|
FrameMetrics fm;
|
2015-05-07 21:44:03 +03:00
|
|
|
fm.SetCompositionBounds(ParentLayerRect(200, 200, 100, 200));
|
2014-12-27 20:48:27 +03:00
|
|
|
fm.SetScrollableRect(CSSRect(0, 0, 980, 1000));
|
2014-07-15 03:07:54 +04:00
|
|
|
fm.SetScrollOffset(CSSPoint(300, 300));
|
2015-03-06 21:54:10 +03:00
|
|
|
fm.SetZoom(CSSToParentLayerScale2D(2.0, 2.0));
|
|
|
|
// APZC only allows zooming on the root scrollable frame.
|
2015-06-08 23:01:26 +03:00
|
|
|
fm.SetIsRootContent(true);
|
2014-07-15 03:07:54 +04:00
|
|
|
// the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100
|
2014-07-16 16:33:50 +04:00
|
|
|
return fm;
|
|
|
|
}
|
2014-07-15 03:07:54 +04:00
|
|
|
|
2014-07-16 16:33:50 +04:00
|
|
|
void DoPinchTest(bool aShouldTriggerPinch,
|
|
|
|
nsTArray<uint32_t> *aAllowedTouchBehaviors = nullptr)
|
|
|
|
{
|
|
|
|
apzc->SetFrameMetrics(GetPinchableFrameMetrics());
|
2014-07-15 03:07:54 +04:00
|
|
|
MakeApzcZoomable();
|
|
|
|
|
|
|
|
if (aShouldTriggerPinch) {
|
|
|
|
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
|
|
|
|
} else {
|
|
|
|
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtMost(2));
|
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
|
|
|
|
}
|
2014-05-05 19:23:00 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
int touchInputId = 0;
|
|
|
|
if (mGestureBehavior == AsyncPanZoomController::USE_GESTURE_DETECTOR) {
|
2014-10-31 22:31:35 +03:00
|
|
|
PinchWithTouchInputAndCheckStatus(apzc, 250, 300, 1.25, touchInputId, aShouldTriggerPinch, aAllowedTouchBehaviors);
|
2014-07-15 03:07:54 +04:00
|
|
|
} else {
|
2014-10-31 22:31:35 +03:00
|
|
|
PinchWithPinchInputAndCheckStatus(apzc, 250, 300, 1.25, aShouldTriggerPinch);
|
2014-07-15 03:07:54 +04:00
|
|
|
}
|
2014-05-05 19:23:00 +04:00
|
|
|
|
2014-07-16 16:33:50 +04:00
|
|
|
FrameMetrics fm = apzc->GetFrameMetrics();
|
2014-07-15 03:07:54 +04:00
|
|
|
|
|
|
|
if (aShouldTriggerPinch) {
|
|
|
|
// the visible area of the document in CSS pixels is now x=305 y=310 w=40 h=80
|
2015-03-06 21:54:10 +03:00
|
|
|
EXPECT_EQ(2.5f, fm.GetZoom().ToScaleFactor().scale);
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_EQ(305, fm.GetScrollOffset().x);
|
|
|
|
EXPECT_EQ(310, fm.GetScrollOffset().y);
|
|
|
|
} else {
|
|
|
|
// The frame metrics should stay the same since touch-action:none makes
|
|
|
|
// apzc ignore pinch gestures.
|
2015-03-06 21:54:10 +03:00
|
|
|
EXPECT_EQ(2.0f, fm.GetZoom().ToScaleFactor().scale);
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_EQ(300, fm.GetScrollOffset().x);
|
|
|
|
EXPECT_EQ(300, fm.GetScrollOffset().y);
|
|
|
|
}
|
2014-05-05 19:23:00 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
// part 2 of the test, move to the top-right corner of the page and pinch and
|
|
|
|
// make sure we stay in the correct spot
|
2015-03-06 21:54:10 +03:00
|
|
|
fm.SetZoom(CSSToParentLayerScale2D(2.0, 2.0));
|
2014-07-15 03:07:54 +04:00
|
|
|
fm.SetScrollOffset(CSSPoint(930, 5));
|
|
|
|
apzc->SetFrameMetrics(fm);
|
|
|
|
// the visible area of the document in CSS pixels is x=930 y=5 w=50 h=100
|
|
|
|
|
|
|
|
if (mGestureBehavior == AsyncPanZoomController::USE_GESTURE_DETECTOR) {
|
2014-10-31 22:31:35 +03:00
|
|
|
PinchWithTouchInputAndCheckStatus(apzc, 250, 300, 0.5, touchInputId, aShouldTriggerPinch, aAllowedTouchBehaviors);
|
2014-07-15 03:07:54 +04:00
|
|
|
} else {
|
2014-10-31 22:31:35 +03:00
|
|
|
PinchWithPinchInputAndCheckStatus(apzc, 250, 300, 0.5, aShouldTriggerPinch);
|
2014-07-15 03:07:54 +04:00
|
|
|
}
|
2014-05-05 19:23:00 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
fm = apzc->GetFrameMetrics();
|
|
|
|
|
|
|
|
if (aShouldTriggerPinch) {
|
|
|
|
// the visible area of the document in CSS pixels is now x=880 y=0 w=100 h=200
|
2015-03-06 21:54:10 +03:00
|
|
|
EXPECT_EQ(1.0f, fm.GetZoom().ToScaleFactor().scale);
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_EQ(880, fm.GetScrollOffset().x);
|
|
|
|
EXPECT_EQ(0, fm.GetScrollOffset().y);
|
|
|
|
} else {
|
2015-03-06 21:54:10 +03:00
|
|
|
EXPECT_EQ(2.0f, fm.GetZoom().ToScaleFactor().scale);
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_EQ(930, fm.GetScrollOffset().x);
|
|
|
|
EXPECT_EQ(5, fm.GetScrollOffset().y);
|
|
|
|
}
|
2014-05-05 19:23:00 +04:00
|
|
|
}
|
2014-07-15 03:07:54 +04:00
|
|
|
};
|
2014-05-05 19:23:00 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
class APZCPinchGestureDetectorTester : public APZCPinchTester {
|
|
|
|
public:
|
|
|
|
APZCPinchGestureDetectorTester()
|
|
|
|
: APZCPinchTester(AsyncPanZoomController::USE_GESTURE_DETECTOR)
|
|
|
|
{
|
2014-05-05 19:23:00 +04:00
|
|
|
}
|
2014-07-15 03:07:54 +04:00
|
|
|
};
|
2013-11-10 18:48:12 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCPinchTester, Pinch_DefaultGestures_NoTouchAction) {
|
2015-03-02 19:50:38 +03:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
|
2014-07-15 03:07:54 +04:00
|
|
|
DoPinchTest(true);
|
2014-05-05 19:23:00 +04:00
|
|
|
}
|
2014-01-22 22:37:30 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCPinchGestureDetectorTester, Pinch_UseGestureDetector_NoTouchAction) {
|
2015-03-02 19:50:38 +03:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
|
2014-07-15 03:07:54 +04:00
|
|
|
DoPinchTest(true);
|
2014-05-05 19:23:00 +04:00
|
|
|
}
|
2014-01-15 19:03:16 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCPinchGestureDetectorTester, Pinch_UseGestureDetector_TouchActionNone) {
|
2014-07-15 03:07:53 +04:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
|
2014-05-05 19:23:00 +04:00
|
|
|
nsTArray<uint32_t> behaviors;
|
|
|
|
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::NONE);
|
|
|
|
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::NONE);
|
2014-07-15 03:07:54 +04:00
|
|
|
DoPinchTest(false, &behaviors);
|
2014-05-05 19:23:00 +04:00
|
|
|
}
|
2014-01-15 19:03:16 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCPinchGestureDetectorTester, Pinch_UseGestureDetector_TouchActionZoom) {
|
2014-07-15 03:07:53 +04:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
|
2014-05-05 19:23:00 +04:00
|
|
|
nsTArray<uint32_t> behaviors;
|
|
|
|
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
|
|
|
|
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
|
2014-07-15 03:07:54 +04:00
|
|
|
DoPinchTest(true, &behaviors);
|
2014-05-05 19:23:00 +04:00
|
|
|
}
|
2014-01-15 19:03:16 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCPinchGestureDetectorTester, Pinch_UseGestureDetector_TouchActionNotAllowZoom) {
|
2014-07-15 03:07:53 +04:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
|
2014-05-05 19:23:00 +04:00
|
|
|
nsTArray<uint32_t> behaviors;
|
|
|
|
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
|
|
|
|
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
|
2014-07-15 03:07:54 +04:00
|
|
|
DoPinchTest(false, &behaviors);
|
2014-01-15 19:03:16 +04:00
|
|
|
}
|
|
|
|
|
2014-07-16 16:33:50 +04:00
|
|
|
TEST_F(APZCPinchGestureDetectorTester, Pinch_PreventDefault) {
|
|
|
|
FrameMetrics originalMetrics = GetPinchableFrameMetrics();
|
|
|
|
apzc->SetFrameMetrics(originalMetrics);
|
|
|
|
|
2015-03-10 16:29:25 +03:00
|
|
|
MakeApzcWaitForMainThread();
|
2014-07-16 16:33:50 +04:00
|
|
|
MakeApzcZoomable();
|
|
|
|
|
|
|
|
int touchInputId = 0;
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockId = 0;
|
2014-10-31 22:31:35 +03:00
|
|
|
PinchWithTouchInput(apzc, 250, 300, 1.25, touchInputId, nullptr, nullptr, &blockId);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
// Send the prevent-default notification for the touch block
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockId, true);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
// verify the metrics didn't change (i.e. the pinch was ignored)
|
|
|
|
FrameMetrics fm = apzc->GetFrameMetrics();
|
2015-03-06 21:54:10 +03:00
|
|
|
EXPECT_EQ(originalMetrics.GetZoom(), fm.GetZoom());
|
2014-07-16 16:33:50 +04:00
|
|
|
EXPECT_EQ(originalMetrics.GetScrollOffset().x, fm.GetScrollOffset().x);
|
|
|
|
EXPECT_EQ(originalMetrics.GetScrollOffset().y, fm.GetScrollOffset().y);
|
|
|
|
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCBasicTester, Overzoom) {
|
|
|
|
// the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100
|
2013-10-11 01:00:29 +04:00
|
|
|
FrameMetrics fm;
|
2015-05-07 21:44:03 +03:00
|
|
|
fm.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
2014-12-27 20:48:27 +03:00
|
|
|
fm.SetScrollableRect(CSSRect(0, 0, 125, 150));
|
2014-03-13 10:34:34 +04:00
|
|
|
fm.SetScrollOffset(CSSPoint(10, 0));
|
2015-03-06 21:54:10 +03:00
|
|
|
fm.SetZoom(CSSToParentLayerScale2D(1.0, 1.0));
|
2015-06-08 23:01:26 +03:00
|
|
|
fm.SetIsRootContent(true);
|
2013-10-11 01:00:29 +04:00
|
|
|
apzc->SetFrameMetrics(fm);
|
2014-07-15 03:07:54 +04:00
|
|
|
|
|
|
|
MakeApzcZoomable();
|
2013-10-11 01:00:29 +04:00
|
|
|
|
2013-12-07 21:45:19 +04:00
|
|
|
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
|
2013-10-11 01:00:29 +04:00
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
PinchWithPinchInputAndCheckStatus(apzc, 50, 50, 0.5, true);
|
2013-10-11 01:00:29 +04:00
|
|
|
|
|
|
|
fm = apzc->GetFrameMetrics();
|
2015-03-06 21:54:10 +03:00
|
|
|
EXPECT_EQ(0.8f, fm.GetZoom().ToScaleFactor().scale);
|
2013-11-10 18:47:27 +04:00
|
|
|
// bug 936721 - PGO builds introduce rounding error so
|
|
|
|
// use a fuzzy match instead
|
2014-03-13 10:34:34 +04:00
|
|
|
EXPECT_LT(abs(fm.GetScrollOffset().x), 1e-5);
|
|
|
|
EXPECT_LT(abs(fm.GetScrollOffset().y), 1e-5);
|
2013-10-11 01:00:29 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCBasicTester, SimpleTransform) {
|
2014-11-10 22:35:11 +03:00
|
|
|
ParentLayerPoint pointOut;
|
2013-06-24 23:24:42 +04:00
|
|
|
ViewTransform viewTransformOut;
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2013-06-24 23:24:42 +04:00
|
|
|
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(), pointOut);
|
2014-04-16 01:56:05 +04:00
|
|
|
EXPECT_EQ(ViewTransform(), viewTransformOut);
|
2013-06-24 23:24:42 +04:00
|
|
|
}
|
|
|
|
|
2013-07-08 23:53:51 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCBasicTester, ComplexTransform) {
|
2013-07-08 23:53:51 +04:00
|
|
|
// This test assumes there is a page that gets rendered to
|
|
|
|
// two layers. In CSS pixels, the first layer is 50x50 and
|
|
|
|
// the second layer is 25x50. The widget scale factor is 3.0
|
|
|
|
// and the presShell resolution is 2.0. Therefore, these layers
|
|
|
|
// end up being 300x300 and 150x300 in layer pixels.
|
|
|
|
//
|
|
|
|
// The second (child) layer has an additional CSS transform that
|
|
|
|
// stretches it by 2.0 on the x-axis. Therefore, after applying
|
|
|
|
// CSS transforms, the two layers are the same size in screen
|
|
|
|
// pixels.
|
|
|
|
//
|
|
|
|
// The screen itself is 24x24 in screen pixels (therefore 4x4 in
|
|
|
|
// CSS pixels). The displayport is 1 extra CSS pixel on all
|
|
|
|
// sides.
|
|
|
|
|
2015-05-15 19:45:27 +03:00
|
|
|
nsRefPtr<TestAsyncPanZoomController> childApzc =
|
2015-06-01 21:36:12 +03:00
|
|
|
new TestAsyncPanZoomController(0, mcc, tm);
|
2013-07-08 23:53:51 +04:00
|
|
|
|
|
|
|
const char* layerTreeSyntax = "c(c)";
|
|
|
|
// LayerID 0 1
|
|
|
|
nsIntRegion layerVisibleRegion[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0, 0, 300, 300)),
|
|
|
|
nsIntRegion(IntRect(0, 0, 150, 300)),
|
2013-07-08 23:53:51 +04:00
|
|
|
};
|
2014-08-01 16:31:48 +04:00
|
|
|
Matrix4x4 transforms[] = {
|
|
|
|
Matrix4x4(),
|
|
|
|
Matrix4x4(),
|
2013-07-08 23:53:51 +04:00
|
|
|
};
|
2014-10-16 13:51:12 +04:00
|
|
|
transforms[0].PostScale(0.5f, 0.5f, 1.0f); // this results from the 2.0 resolution on the root layer
|
|
|
|
transforms[1].PostScale(2.0f, 1.0f, 1.0f); // this is the 2.0 x-axis CSS transform on the child layer
|
2013-07-08 23:53:51 +04:00
|
|
|
|
|
|
|
nsTArray<nsRefPtr<Layer> > layers;
|
|
|
|
nsRefPtr<LayerManager> lm;
|
|
|
|
nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
|
|
|
|
|
|
|
|
FrameMetrics metrics;
|
2015-05-07 21:44:03 +03:00
|
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 24, 24));
|
2014-12-23 18:35:58 +03:00
|
|
|
metrics.SetDisplayPort(CSSRect(-1, -1, 6, 6));
|
2014-03-13 10:34:34 +04:00
|
|
|
metrics.SetScrollOffset(CSSPoint(10, 10));
|
2014-12-27 20:48:27 +03:00
|
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 50, 50));
|
2015-03-06 21:54:10 +03:00
|
|
|
metrics.SetCumulativeResolution(LayoutDeviceToLayerScale2D(2, 2));
|
2015-01-17 00:15:52 +03:00
|
|
|
metrics.SetPresShellResolution(2.0f);
|
2015-03-06 21:54:10 +03:00
|
|
|
metrics.SetZoom(CSSToParentLayerScale2D(6, 6));
|
2014-12-18 01:14:05 +03:00
|
|
|
metrics.SetDevPixelsPerCSSPixel(CSSToLayoutDeviceScale(3));
|
2014-03-22 01:48:08 +04:00
|
|
|
metrics.SetScrollId(FrameMetrics::START_SCROLL_ID);
|
2013-07-08 23:53:51 +04:00
|
|
|
|
|
|
|
FrameMetrics childMetrics = metrics;
|
2014-03-22 01:48:08 +04:00
|
|
|
childMetrics.SetScrollId(FrameMetrics::START_SCROLL_ID + 1);
|
2013-07-08 23:53:51 +04:00
|
|
|
|
2014-08-12 04:00:36 +04:00
|
|
|
layers[0]->SetFrameMetrics(metrics);
|
|
|
|
layers[1]->SetFrameMetrics(childMetrics);
|
2013-07-08 23:53:51 +04:00
|
|
|
|
2014-11-10 22:35:11 +03:00
|
|
|
ParentLayerPoint pointOut;
|
2013-07-08 23:53:51 +04:00
|
|
|
ViewTransform viewTransformOut;
|
|
|
|
|
|
|
|
// Both the parent and child layer should behave exactly the same here, because
|
|
|
|
// the CSS transform on the child layer does not affect the SampleContentTransformForFrame code
|
|
|
|
|
|
|
|
// initial transform
|
2013-07-30 22:03:40 +04:00
|
|
|
apzc->SetFrameMetrics(metrics);
|
2013-07-08 23:53:51 +04:00
|
|
|
apzc->NotifyLayersUpdated(metrics, true);
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2014-12-20 02:53:05 +03:00
|
|
|
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut);
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(60, 60), pointOut);
|
2013-07-08 23:53:51 +04:00
|
|
|
|
2013-07-30 22:03:40 +04:00
|
|
|
childApzc->SetFrameMetrics(childMetrics);
|
|
|
|
childApzc->NotifyLayersUpdated(childMetrics, true);
|
2015-06-01 21:36:12 +03:00
|
|
|
childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2014-12-20 02:53:05 +03:00
|
|
|
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut);
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(60, 60), pointOut);
|
2013-07-08 23:53:51 +04:00
|
|
|
|
|
|
|
// do an async scroll by 5 pixels and check the transform
|
2014-03-13 10:34:34 +04:00
|
|
|
metrics.ScrollBy(CSSPoint(5, 0));
|
2013-07-30 22:03:40 +04:00
|
|
|
apzc->SetFrameMetrics(metrics);
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2014-12-20 02:53:05 +03:00
|
|
|
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)), viewTransformOut);
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(90, 60), pointOut);
|
2013-07-08 23:53:51 +04:00
|
|
|
|
2014-03-13 10:34:34 +04:00
|
|
|
childMetrics.ScrollBy(CSSPoint(5, 0));
|
2013-07-30 22:03:40 +04:00
|
|
|
childApzc->SetFrameMetrics(childMetrics);
|
2015-06-01 21:36:12 +03:00
|
|
|
childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2014-12-20 02:53:05 +03:00
|
|
|
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)), viewTransformOut);
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(90, 60), pointOut);
|
2013-07-08 23:53:51 +04:00
|
|
|
|
|
|
|
// do an async zoom of 1.5x and check the transform
|
2014-03-12 20:46:57 +04:00
|
|
|
metrics.ZoomBy(1.5f);
|
2013-07-30 22:03:40 +04:00
|
|
|
apzc->SetFrameMetrics(metrics);
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2014-12-20 02:53:05 +03:00
|
|
|
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)), viewTransformOut);
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(135, 90), pointOut);
|
2013-07-08 23:53:51 +04:00
|
|
|
|
2014-03-12 20:46:57 +04:00
|
|
|
childMetrics.ZoomBy(1.5f);
|
2013-07-30 22:03:40 +04:00
|
|
|
childApzc->SetFrameMetrics(childMetrics);
|
2015-06-01 21:36:12 +03:00
|
|
|
childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2014-12-20 02:53:05 +03:00
|
|
|
EXPECT_EQ(ViewTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)), viewTransformOut);
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(135, 90), pointOut);
|
2015-01-08 17:40:01 +03:00
|
|
|
|
|
|
|
childApzc->Destroy();
|
2013-07-08 23:53:51 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
class APZCPanningTester : public APZCBasicTester {
|
|
|
|
protected:
|
2014-08-02 00:24:50 +04:00
|
|
|
void DoPanTest(bool aShouldTriggerScroll, bool aShouldBeConsumed, uint32_t aBehavior)
|
2014-07-15 03:07:54 +04:00
|
|
|
{
|
|
|
|
if (aShouldTriggerScroll) {
|
|
|
|
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
|
|
|
|
} else {
|
|
|
|
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(0);
|
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
|
|
|
|
}
|
2014-07-15 03:07:54 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
int touchStart = 50;
|
|
|
|
int touchEnd = 10;
|
2014-11-10 22:35:11 +03:00
|
|
|
ParentLayerPoint pointOut;
|
2014-07-15 03:07:54 +04:00
|
|
|
ViewTransform viewTransformOut;
|
|
|
|
|
|
|
|
nsTArray<uint32_t> allowedTouchBehaviors;
|
|
|
|
allowedTouchBehaviors.AppendElement(aBehavior);
|
|
|
|
|
|
|
|
// Pan down
|
2015-06-01 21:36:12 +03:00
|
|
|
PanAndCheckStatus(apzc, mcc, touchStart, touchEnd, aShouldBeConsumed, &allowedTouchBehaviors);
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2014-07-15 03:07:54 +04:00
|
|
|
|
|
|
|
if (aShouldTriggerScroll) {
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(0, -(touchEnd-touchStart)), pointOut);
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_NE(ViewTransform(), viewTransformOut);
|
|
|
|
} else {
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(), pointOut);
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_EQ(ViewTransform(), viewTransformOut);
|
|
|
|
}
|
2014-07-15 03:07:54 +04:00
|
|
|
|
2014-07-17 21:41:54 +04:00
|
|
|
// Clear the fling from the previous pan, or stopping it will
|
|
|
|
// consume the next touchstart
|
|
|
|
apzc->CancelAnimation();
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
// Pan back
|
2015-06-01 21:36:12 +03:00
|
|
|
PanAndCheckStatus(apzc, mcc, touchEnd, touchStart, aShouldBeConsumed, &allowedTouchBehaviors);
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2014-07-15 03:07:54 +04:00
|
|
|
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(), pointOut);
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_EQ(ViewTransform(), viewTransformOut);
|
|
|
|
}
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
void DoPanWithPreventDefaultTest()
|
|
|
|
{
|
2015-03-10 16:29:25 +03:00
|
|
|
MakeApzcWaitForMainThread();
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
int touchStart = 50;
|
|
|
|
int touchEnd = 10;
|
2014-11-10 22:35:11 +03:00
|
|
|
ParentLayerPoint pointOut;
|
2014-07-16 16:33:50 +04:00
|
|
|
ViewTransform viewTransformOut;
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockId = 0;
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
// Pan down
|
|
|
|
nsTArray<uint32_t> allowedTouchBehaviors;
|
|
|
|
allowedTouchBehaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
|
2015-06-01 21:36:12 +03:00
|
|
|
PanAndCheckStatus(apzc, mcc, touchStart, touchEnd, true, &allowedTouchBehaviors, &blockId);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
// Send the signal that content has handled and preventDefaulted the touch
|
|
|
|
// events. This flushes the event queue.
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockId, true);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(), pointOut);
|
2014-07-16 16:33:50 +04:00
|
|
|
EXPECT_EQ(ViewTransform(), viewTransformOut);
|
|
|
|
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
2014-07-15 03:07:54 +04:00
|
|
|
};
|
2014-07-15 03:07:54 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCPanningTester, Pan) {
|
2015-03-02 19:50:38 +03:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
|
2014-08-02 00:24:50 +04:00
|
|
|
DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::NONE);
|
2014-01-15 19:03:16 +04:00
|
|
|
}
|
2013-06-24 23:24:42 +04:00
|
|
|
|
2014-01-15 19:03:16 +04:00
|
|
|
// In the each of the following 4 pan tests we are performing two pan gestures: vertical pan from top
|
|
|
|
// to bottom and back - from bottom to top.
|
|
|
|
// According to the pointer-events/touch-action spec AUTO and PAN_Y touch-action values allow vertical
|
|
|
|
// scrolling while NONE and PAN_X forbid it. The first parameter of DoPanTest method specifies this
|
|
|
|
// behavior.
|
2014-08-02 00:24:50 +04:00
|
|
|
// However, the events will be marked as consumed even if the behavior in PAN_X, because the user could
|
|
|
|
// move their finger horizontally too - APZ has no way of knowing beforehand and so must consume the
|
|
|
|
// events.
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCPanningTester, PanWithTouchActionAuto) {
|
2014-07-15 03:07:53 +04:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
|
2014-08-02 00:24:50 +04:00
|
|
|
DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
|
|
|
|
| mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
|
2014-01-15 19:03:16 +04:00
|
|
|
}
|
2013-06-24 23:24:42 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCPanningTester, PanWithTouchActionNone) {
|
2014-07-15 03:07:53 +04:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
|
2014-08-02 00:24:50 +04:00
|
|
|
DoPanTest(false, false, 0);
|
2014-01-15 19:03:16 +04:00
|
|
|
}
|
2013-06-24 23:24:42 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCPanningTester, PanWithTouchActionPanX) {
|
2014-07-15 03:07:53 +04:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
|
2014-08-02 00:24:50 +04:00
|
|
|
DoPanTest(false, true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN);
|
2014-01-15 19:03:16 +04:00
|
|
|
}
|
2013-06-24 23:24:42 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCPanningTester, PanWithTouchActionPanY) {
|
2014-07-15 03:07:53 +04:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
|
2014-08-02 00:24:50 +04:00
|
|
|
DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN);
|
2013-06-24 23:24:42 +04:00
|
|
|
}
|
|
|
|
|
2014-07-16 16:33:50 +04:00
|
|
|
TEST_F(APZCPanningTester, PanWithPreventDefaultAndTouchAction) {
|
2014-07-15 03:07:53 +04:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
|
2014-07-16 16:33:50 +04:00
|
|
|
DoPanWithPreventDefaultTest();
|
|
|
|
}
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-16 16:33:50 +04:00
|
|
|
TEST_F(APZCPanningTester, PanWithPreventDefault) {
|
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
|
|
|
|
DoPanWithPreventDefaultTest();
|
2014-02-13 20:24:53 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCBasicTester, Fling) {
|
2013-12-07 21:45:19 +04:00
|
|
|
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
|
2013-06-24 23:24:42 +04:00
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
|
|
|
|
|
|
|
|
int touchStart = 50;
|
|
|
|
int touchEnd = 10;
|
2014-11-10 22:35:11 +03:00
|
|
|
ParentLayerPoint pointOut;
|
2013-06-24 23:24:42 +04:00
|
|
|
ViewTransform viewTransformOut;
|
|
|
|
|
|
|
|
// Fling down. Each step scroll further down
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(apzc, mcc, touchStart, touchEnd);
|
2014-11-10 22:35:11 +03:00
|
|
|
ParentLayerPoint lastPoint;
|
2013-06-24 23:24:42 +04:00
|
|
|
for (int i = 1; i < 50; i+=1) {
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut, TimeDuration::FromMilliseconds(1));
|
2013-06-24 23:24:42 +04:00
|
|
|
EXPECT_GT(pointOut.y, lastPoint.y);
|
|
|
|
lastPoint = pointOut;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-20 22:28:41 +04:00
|
|
|
TEST_F(APZCBasicTester, FlingIntoOverscroll) {
|
|
|
|
// Enable overscrolling.
|
|
|
|
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
|
|
|
|
|
|
|
|
// Scroll down by 25 px. Don't fling for simplicity.
|
2015-06-01 21:36:12 +03:00
|
|
|
ApzcPanNoFling(apzc, mcc, 50, 25);
|
2014-08-20 22:28:41 +04:00
|
|
|
|
|
|
|
// Now scroll back up by 20px, this time flinging after.
|
|
|
|
// The fling should cover the remaining 5 px of room to scroll, then
|
|
|
|
// go into overscroll, and finally snap-back to recover from overscroll.
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(apzc, mcc, 25, 45);
|
2014-08-20 22:28:41 +04:00
|
|
|
const TimeDuration increment = TimeDuration::FromMilliseconds(1);
|
|
|
|
bool reachedOverscroll = false;
|
|
|
|
bool recoveredFromOverscroll = false;
|
2015-06-01 21:36:12 +03:00
|
|
|
while (apzc->AdvanceAnimations(mcc->Time())) {
|
2014-08-20 22:28:41 +04:00
|
|
|
if (!reachedOverscroll && apzc->IsOverscrolled()) {
|
|
|
|
reachedOverscroll = true;
|
|
|
|
}
|
|
|
|
if (reachedOverscroll && !apzc->IsOverscrolled()) {
|
|
|
|
recoveredFromOverscroll = true;
|
|
|
|
}
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->AdvanceBy(increment);
|
2014-08-20 22:28:41 +04:00
|
|
|
}
|
|
|
|
EXPECT_TRUE(reachedOverscroll);
|
|
|
|
EXPECT_TRUE(recoveredFromOverscroll);
|
|
|
|
}
|
|
|
|
|
2014-09-12 19:41:28 +04:00
|
|
|
TEST_F(APZCBasicTester, PanningTransformNotifications) {
|
|
|
|
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
|
|
|
|
|
|
|
|
// Scroll down by 25 px. Ensure we only get one set of
|
|
|
|
// state change notifications.
|
|
|
|
//
|
|
|
|
// Then, scroll back up by 20px, this time flinging after.
|
|
|
|
// The fling should cover the remaining 5 px of room to scroll, then
|
|
|
|
// go into overscroll, and finally snap-back to recover from overscroll.
|
|
|
|
// Again, ensure we only get one set of state change notifications for
|
|
|
|
// this entire procedure.
|
|
|
|
|
|
|
|
MockFunction<void(std::string checkPointName)> check;
|
|
|
|
{
|
|
|
|
InSequence s;
|
|
|
|
EXPECT_CALL(check, Call("Simple pan"));
|
|
|
|
EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::StartTouch,_)).Times(1);
|
|
|
|
EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::TransformBegin,_)).Times(1);
|
|
|
|
EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::StartPanning,_)).Times(1);
|
|
|
|
EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::EndTouch,_)).Times(1);
|
|
|
|
EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::TransformEnd,_)).Times(1);
|
|
|
|
EXPECT_CALL(check, Call("Complex pan"));
|
|
|
|
EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::StartTouch,_)).Times(1);
|
|
|
|
EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::TransformBegin,_)).Times(1);
|
|
|
|
EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::StartPanning,_)).Times(1);
|
|
|
|
EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::EndTouch,_)).Times(1);
|
|
|
|
EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::TransformEnd,_)).Times(1);
|
|
|
|
EXPECT_CALL(check, Call("Done"));
|
|
|
|
}
|
|
|
|
|
|
|
|
check.Call("Simple pan");
|
2015-06-01 21:36:12 +03:00
|
|
|
ApzcPanNoFling(apzc, mcc, 50, 25);
|
2014-09-12 19:41:28 +04:00
|
|
|
check.Call("Complex pan");
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(apzc, mcc, 25, 45);
|
|
|
|
apzc->AdvanceAnimationsUntilEnd();
|
2014-09-12 19:41:28 +04:00
|
|
|
check.Call("Done");
|
|
|
|
}
|
|
|
|
|
2015-05-15 19:45:27 +03:00
|
|
|
void APZCBasicTester::PanIntoOverscroll()
|
2015-04-09 02:59:14 +03:00
|
|
|
{
|
2014-09-03 04:39:40 +04:00
|
|
|
int touchStart = 500;
|
|
|
|
int touchEnd = 10;
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(apzc, mcc, touchStart, touchEnd);
|
2014-09-03 04:39:40 +04:00
|
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
2015-04-30 02:38:02 +03:00
|
|
|
}
|
2014-09-03 04:39:40 +04:00
|
|
|
|
2015-04-30 02:38:02 +03:00
|
|
|
void APZCBasicTester::TestOverscroll()
|
|
|
|
{
|
|
|
|
// Pan sufficiently to hit overscroll behavior
|
2015-05-15 19:45:27 +03:00
|
|
|
PanIntoOverscroll();
|
2014-09-03 04:39:40 +04:00
|
|
|
|
2015-04-30 02:38:02 +03:00
|
|
|
// Check that we recover from overscroll via an animation.
|
|
|
|
ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost());
|
|
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
2014-09-03 04:39:40 +04:00
|
|
|
}
|
|
|
|
|
2015-04-09 02:59:14 +03:00
|
|
|
|
|
|
|
TEST_F(APZCBasicTester, OverScrollPanning) {
|
|
|
|
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
|
|
|
|
|
|
|
|
TestOverscroll();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that an overscroll animation doesn't trigger an assertion failure
|
|
|
|
// in the case where a sample has a velocity of zero.
|
2015-04-30 02:38:02 +03:00
|
|
|
TEST_F(APZCBasicTester, OverScroll_Bug1152051a) {
|
2015-04-09 02:59:14 +03:00
|
|
|
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
|
|
|
|
|
|
|
|
// Doctor the prefs to make the velocity zero at the end of the first sample.
|
|
|
|
|
|
|
|
// This ensures our incoming velocity to the overscroll animation is
|
|
|
|
// a round(ish) number, 4.9 (that being the distance of the pan before
|
|
|
|
// overscroll, which is 500 - 10 = 490 pixels, divided by the duration of
|
|
|
|
// the pan, which is 100 ms).
|
|
|
|
SCOPED_GFX_PREF(APZFlingFriction, float, 0);
|
|
|
|
|
|
|
|
// To ensure the velocity after the first sample is 0, set the spring
|
|
|
|
// stiffness to the incoming velocity (4.9) divided by the overscroll
|
|
|
|
// (400 pixels) times the step duration (1 ms).
|
|
|
|
SCOPED_GFX_PREF(APZOverscrollSpringStiffness, float, 0.01225f);
|
|
|
|
|
|
|
|
TestOverscroll();
|
|
|
|
}
|
|
|
|
|
2015-04-30 02:38:02 +03:00
|
|
|
// Tests that ending an overscroll animation doesn't leave around state that
|
|
|
|
// confuses the next overscroll animation.
|
|
|
|
TEST_F(APZCBasicTester, OverScroll_Bug1152051b) {
|
|
|
|
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
|
|
|
|
|
|
|
|
SCOPED_GFX_PREF(APZOverscrollStopDistanceThreshold, float, 0.1f);
|
|
|
|
|
|
|
|
// Pan sufficiently to hit overscroll behavior
|
2015-05-15 19:45:27 +03:00
|
|
|
PanIntoOverscroll();
|
2015-04-30 02:38:02 +03:00
|
|
|
|
|
|
|
// Sample animations once, to give the fling animation started on touch-up
|
|
|
|
// a chance to realize it's overscrolled, and schedule a call to
|
|
|
|
// HandleFlingOverscroll().
|
|
|
|
SampleAnimationOnce();
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
// This advances the time and runs the HandleFlingOverscroll task scheduled in
|
|
|
|
// the previous call, which starts an overscroll animation. It then samples
|
|
|
|
// the overscroll animation once, to get it to initialize the first overscroll
|
|
|
|
// sample.
|
2015-04-30 02:38:02 +03:00
|
|
|
SampleAnimationOnce();
|
|
|
|
|
|
|
|
// Do a touch-down to cancel the overscroll animation, and then a touch-up
|
|
|
|
// to schedule a new one since we're still overscrolled. We don't pan because
|
|
|
|
// panning can trigger functions that clear the overscroll animation state
|
|
|
|
// in other ways.
|
2015-06-01 21:36:12 +03:00
|
|
|
TouchDown(apzc, 10, 10, mcc->Time(), nullptr);
|
|
|
|
TouchUp(apzc, 10, 10, mcc->Time());
|
2015-04-30 02:38:02 +03:00
|
|
|
|
|
|
|
// Sample the second overscroll animation to its end.
|
|
|
|
// If the ending of the first overscroll animation fails to clear state
|
|
|
|
// properly, this will assert.
|
|
|
|
ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost());
|
|
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
|
|
}
|
|
|
|
|
2014-09-03 04:39:40 +04:00
|
|
|
TEST_F(APZCBasicTester, OverScrollAbort) {
|
|
|
|
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
|
|
|
|
|
|
|
|
// Pan sufficiently to hit overscroll behavior
|
|
|
|
int touchStart = 500;
|
|
|
|
int touchEnd = 10;
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(apzc, mcc, touchStart, touchEnd);
|
2014-09-03 04:39:40 +04:00
|
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
|
2014-11-10 22:35:11 +03:00
|
|
|
ParentLayerPoint pointOut;
|
2014-09-03 04:39:40 +04:00
|
|
|
ViewTransform viewTransformOut;
|
|
|
|
|
2014-10-31 19:05:29 +03:00
|
|
|
// This sample call will run to the end of the fling animation
|
|
|
|
// and will schedule the overscroll animation.
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut, TimeDuration::FromMilliseconds(10000));
|
2014-09-03 04:39:40 +04:00
|
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
|
2014-10-31 19:05:29 +03:00
|
|
|
// At this point, we have an active overscroll animation.
|
2014-09-03 04:39:40 +04:00
|
|
|
// Check that cancelling the animation clears the overscroll.
|
|
|
|
apzc->CancelAnimation();
|
|
|
|
EXPECT_FALSE(apzc->IsOverscrolled());
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(APZCBasicTester, OverScrollPanningAbort) {
|
|
|
|
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
|
|
|
|
|
|
|
|
// Pan sufficiently to hit overscroll behaviour. Keep the finger down so
|
|
|
|
// the pan does not end.
|
|
|
|
int touchStart = 500;
|
|
|
|
int touchEnd = 10;
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(apzc, mcc, touchStart, touchEnd, true); // keep finger down
|
2014-09-03 04:39:40 +04:00
|
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
|
|
|
|
// Check that calling CancelAnimation() while the user is still panning
|
|
|
|
// (and thus no fling or snap-back animation has had a chance to start)
|
|
|
|
// clears the overscroll.
|
|
|
|
apzc->CancelAnimation();
|
|
|
|
EXPECT_FALSE(apzc->IsOverscrolled());
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
class APZCFlingStopTester : public APZCGestureDetectorTester {
|
|
|
|
protected:
|
|
|
|
// Start a fling, and then tap while the fling is ongoing. When
|
|
|
|
// aSlow is false, the tap will happen while the fling is at a
|
|
|
|
// high velocity, and we check that the tap doesn't trigger sending a tap
|
|
|
|
// to content. If aSlow is true, the tap will happen while the fling
|
|
|
|
// is at a slow velocity, and we check that the tap does trigger sending
|
|
|
|
// a tap to content. See bug 1022956.
|
|
|
|
void DoFlingStopTest(bool aSlow) {
|
|
|
|
int touchStart = 50;
|
|
|
|
int touchEnd = 10;
|
|
|
|
|
|
|
|
// Start the fling down.
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(apzc, mcc, touchStart, touchEnd);
|
2014-07-15 03:07:54 +04:00
|
|
|
// The touchstart from the pan will leave some cancelled tasks in the queue, clear them out
|
|
|
|
|
|
|
|
// If we want to tap while the fling is fast, let the fling advance for 10ms only. If we want
|
|
|
|
// the fling to slow down more, advance to 2000ms. These numbers may need adjusting if our
|
|
|
|
// friction and threshold values change, but they should be deterministic at least.
|
|
|
|
int timeDelta = aSlow ? 2000 : 10;
|
2015-03-19 13:33:32 +03:00
|
|
|
int tapCallsExpected = aSlow ? 2 : 1;
|
2014-07-15 03:07:54 +04:00
|
|
|
|
|
|
|
// Advance the fling animation by timeDelta milliseconds.
|
2014-11-10 22:35:11 +03:00
|
|
|
ParentLayerPoint pointOut;
|
2014-07-15 03:07:54 +04:00
|
|
|
ViewTransform viewTransformOut;
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut, TimeDuration::FromMilliseconds(timeDelta));
|
2014-07-15 03:07:54 +04:00
|
|
|
|
|
|
|
// Deliver a tap to abort the fling. Ensure that we get a HandleSingleTap
|
|
|
|
// call out of it if and only if the fling is slow.
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(_, 0, apzc->GetGuid())).Times(tapCallsExpected);
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(apzc, 10, 10, mcc, 0);
|
2014-07-17 21:41:53 +04:00
|
|
|
while (mcc->RunThroughDelayedTasks());
|
2014-07-15 03:07:54 +04:00
|
|
|
|
2015-03-19 13:33:32 +03:00
|
|
|
// Deliver another tap, to make sure that taps are flowing properly once
|
|
|
|
// the fling is aborted.
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(apzc, 100, 100, mcc, 0);
|
2015-03-19 13:33:32 +03:00
|
|
|
while (mcc->RunThroughDelayedTasks());
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
// Verify that we didn't advance any further after the fling was aborted, in either case.
|
2014-11-10 22:35:11 +03:00
|
|
|
ParentLayerPoint finalPointOut;
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, finalPointOut);
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_EQ(pointOut.x, finalPointOut.x);
|
|
|
|
EXPECT_EQ(pointOut.y, finalPointOut.y);
|
|
|
|
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
2014-07-17 21:41:53 +04:00
|
|
|
|
|
|
|
void DoFlingStopWithSlowListener(bool aPreventDefault) {
|
2015-03-10 16:29:25 +03:00
|
|
|
MakeApzcWaitForMainThread();
|
2014-07-17 21:41:53 +04:00
|
|
|
|
|
|
|
int touchStart = 50;
|
|
|
|
int touchEnd = 10;
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockId = 0;
|
2014-07-17 21:41:53 +04:00
|
|
|
|
|
|
|
// Start the fling down.
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(apzc, mcc, touchStart, touchEnd, false, nullptr, nullptr, &blockId);
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->ConfirmTarget(blockId);
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockId, false);
|
2014-07-17 21:41:53 +04:00
|
|
|
|
|
|
|
// Sample the fling a couple of times to ensure it's going.
|
2014-11-10 22:35:11 +03:00
|
|
|
ParentLayerPoint point, finalPoint;
|
2014-07-17 21:41:53 +04:00
|
|
|
ViewTransform viewTransform;
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransform, point, TimeDuration::FromMilliseconds(10));
|
|
|
|
apzc->SampleContentTransformForFrame(&viewTransform, finalPoint, TimeDuration::FromMilliseconds(10));
|
2014-07-17 21:41:53 +04:00
|
|
|
EXPECT_GT(finalPoint.y, point.y);
|
|
|
|
|
|
|
|
// Now we put our finger down to stop the fling
|
2015-06-01 21:36:12 +03:00
|
|
|
TouchDown(apzc, 10, 10, mcc->Time(), &blockId);
|
2014-07-17 21:41:53 +04:00
|
|
|
|
|
|
|
// Re-sample to make sure it hasn't moved
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransform, point, TimeDuration::FromMilliseconds(10));
|
2014-07-17 21:41:53 +04:00
|
|
|
EXPECT_EQ(finalPoint.x, point.x);
|
|
|
|
EXPECT_EQ(finalPoint.y, point.y);
|
|
|
|
|
|
|
|
// respond to the touchdown that stopped the fling.
|
|
|
|
// even if we do a prevent-default on it, the animation should remain stopped.
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockId, aPreventDefault);
|
2014-07-17 21:41:53 +04:00
|
|
|
|
|
|
|
// Verify the page hasn't moved
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransform, point, TimeDuration::FromMilliseconds(70));
|
2014-07-17 21:41:53 +04:00
|
|
|
EXPECT_EQ(finalPoint.x, point.x);
|
|
|
|
EXPECT_EQ(finalPoint.y, point.y);
|
|
|
|
|
|
|
|
// clean up
|
2015-06-01 21:36:12 +03:00
|
|
|
TouchUp(apzc, 10, 10, mcc->Time());
|
2014-07-17 21:41:53 +04:00
|
|
|
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
2014-07-15 03:07:54 +04:00
|
|
|
};
|
2014-06-27 02:37:44 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCFlingStopTester, FlingStop) {
|
2014-06-27 02:37:44 +04:00
|
|
|
DoFlingStopTest(false);
|
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCFlingStopTester, FlingStopTap) {
|
2014-06-27 02:37:44 +04:00
|
|
|
DoFlingStopTest(true);
|
|
|
|
}
|
|
|
|
|
2014-07-17 21:41:53 +04:00
|
|
|
TEST_F(APZCFlingStopTester, FlingStopSlowListener) {
|
|
|
|
DoFlingStopWithSlowListener(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(APZCFlingStopTester, FlingStopPreventDefault) {
|
|
|
|
DoFlingStopWithSlowListener(true);
|
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCGestureDetectorTester, ShortPress) {
|
|
|
|
MakeApzcUnzoomable();
|
2013-12-11 21:19:33 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
MockFunction<void(std::string checkPointName)> check;
|
|
|
|
{
|
|
|
|
InSequence s;
|
|
|
|
// This verifies that the single tap notification is sent after the
|
|
|
|
// touchup is fully processed. The ordering here is important.
|
|
|
|
EXPECT_CALL(check, Call("pre-tap"));
|
|
|
|
EXPECT_CALL(check, Call("post-tap"));
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
|
|
|
}
|
2014-02-11 19:42:42 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
check.Call("pre-tap");
|
|
|
|
TapAndCheckStatus(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(100));
|
|
|
|
check.Call("post-tap");
|
2014-02-11 19:42:42 +04:00
|
|
|
|
2014-05-30 10:00:31 +04:00
|
|
|
apzc->AssertStateIsReset();
|
2013-12-11 21:19:33 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCGestureDetectorTester, MediumPress) {
|
|
|
|
MakeApzcUnzoomable();
|
2013-12-11 21:19:33 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
MockFunction<void(std::string checkPointName)> check;
|
|
|
|
{
|
|
|
|
InSequence s;
|
|
|
|
// This verifies that the single tap notification is sent after the
|
|
|
|
// touchup is fully processed. The ordering here is important.
|
|
|
|
EXPECT_CALL(check, Call("pre-tap"));
|
|
|
|
EXPECT_CALL(check, Call("post-tap"));
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
|
|
|
}
|
2014-02-11 19:42:42 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
check.Call("pre-tap");
|
|
|
|
TapAndCheckStatus(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(400));
|
|
|
|
check.Call("post-tap");
|
2014-02-11 19:42:42 +04:00
|
|
|
|
2014-05-30 10:00:31 +04:00
|
|
|
apzc->AssertStateIsReset();
|
2013-12-11 21:19:33 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
class APZCLongPressTester : public APZCGestureDetectorTester {
|
|
|
|
protected:
|
|
|
|
void DoLongPressTest(uint32_t aBehavior) {
|
|
|
|
MakeApzcUnzoomable();
|
2013-12-12 04:39:06 +04:00
|
|
|
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockId = 0;
|
2013-12-12 04:39:06 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
nsEventStatus status = TouchDown(apzc, 10, 10, mcc->Time(), &blockId);
|
2014-08-02 00:24:50 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
|
2014-04-14 22:59:20 +04:00
|
|
|
|
2015-03-19 13:33:32 +03:00
|
|
|
if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
|
2014-07-16 16:33:50 +04:00
|
|
|
// SetAllowedTouchBehavior() must be called after sending touch-start.
|
|
|
|
nsTArray<uint32_t> allowedTouchBehaviors;
|
|
|
|
allowedTouchBehaviors.AppendElement(aBehavior);
|
2014-10-24 21:29:30 +04:00
|
|
|
apzc->SetAllowedTouchBehavior(blockId, allowedTouchBehaviors);
|
2014-07-16 16:33:50 +04:00
|
|
|
}
|
|
|
|
// Have content "respond" to the touchstart
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockId, false);
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
MockFunction<void(std::string checkPointName)> check;
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
{
|
|
|
|
InSequence s;
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_CALL(check, Call("preHandleLongTap"));
|
2014-10-24 21:29:30 +04:00
|
|
|
blockId++;
|
|
|
|
EXPECT_CALL(*mcc, HandleLongTap(CSSPoint(10, 10), 0, apzc->GetGuid(), blockId)).Times(1);
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_CALL(check, Call("postHandleLongTap"));
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2015-03-20 21:26:52 +03:00
|
|
|
EXPECT_CALL(check, Call("preHandleSingleTap"));
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
|
|
|
EXPECT_CALL(check, Call("postHandleSingleTap"));
|
2014-07-15 03:07:54 +04:00
|
|
|
}
|
2013-12-12 04:39:06 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
// Manually invoke the longpress while the touch is currently down.
|
|
|
|
check.Call("preHandleLongTap");
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->RunThroughDelayedTasks();
|
2014-07-15 03:07:54 +04:00
|
|
|
check.Call("postHandleLongTap");
|
|
|
|
|
2014-07-16 16:33:50 +04:00
|
|
|
// Dispatching the longpress event starts a new touch block, which
|
|
|
|
// needs a new content response and also has a pending timeout task
|
|
|
|
// in the queue. Deal with those here. We do the content response first
|
|
|
|
// with preventDefault=false, and then we run the timeout task which
|
|
|
|
// "loses the race" and does nothing.
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockId, false);
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->AdvanceByMillis(1000);
|
2013-12-12 04:39:06 +04:00
|
|
|
|
2014-07-16 16:33:50 +04:00
|
|
|
// Finally, simulate lifting the finger. Since the long-press wasn't
|
|
|
|
// prevent-defaulted, we should get a long-tap-up event.
|
2015-03-20 21:26:52 +03:00
|
|
|
check.Call("preHandleSingleTap");
|
2015-06-01 21:36:12 +03:00
|
|
|
status = TouchUp(apzc, 10, 10, mcc->Time());
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->RunThroughDelayedTasks();
|
2014-08-02 00:24:50 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
|
2015-03-20 21:26:52 +03:00
|
|
|
check.Call("postHandleSingleTap");
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
void DoLongPressPreventDefaultTest(uint32_t aBehavior) {
|
|
|
|
MakeApzcUnzoomable();
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(0);
|
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
int touchX = 10,
|
|
|
|
touchStartY = 10,
|
|
|
|
touchEndY = 50;
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockId = 0;
|
2015-06-01 21:36:12 +03:00
|
|
|
nsEventStatus status = TouchDown(apzc, touchX, touchStartY, mcc->Time(), &blockId);
|
2014-08-02 00:24:50 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2015-03-19 13:33:32 +03:00
|
|
|
if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
|
2014-07-16 16:33:50 +04:00
|
|
|
// SetAllowedTouchBehavior() must be called after sending touch-start.
|
|
|
|
nsTArray<uint32_t> allowedTouchBehaviors;
|
|
|
|
allowedTouchBehaviors.AppendElement(aBehavior);
|
2014-10-24 21:29:30 +04:00
|
|
|
apzc->SetAllowedTouchBehavior(blockId, allowedTouchBehaviors);
|
2014-07-16 16:33:50 +04:00
|
|
|
}
|
|
|
|
// Have content "respond" to the touchstart
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockId, false);
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
MockFunction<void(std::string checkPointName)> check;
|
2014-04-21 19:30:15 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
{
|
|
|
|
InSequence s;
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_CALL(check, Call("preHandleLongTap"));
|
2014-10-24 21:29:30 +04:00
|
|
|
blockId++;
|
|
|
|
EXPECT_CALL(*mcc, HandleLongTap(CSSPoint(touchX, touchStartY), 0, apzc->GetGuid(), blockId)).Times(1);
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_CALL(check, Call("postHandleLongTap"));
|
|
|
|
}
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
// Manually invoke the longpress while the touch is currently down.
|
|
|
|
check.Call("preHandleLongTap");
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->RunThroughDelayedTasks();
|
2014-07-15 03:07:54 +04:00
|
|
|
check.Call("postHandleLongTap");
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-16 16:33:50 +04:00
|
|
|
// There should be a TimeoutContentResponse task in the queue still,
|
|
|
|
// waiting for the response from the longtap event dispatched above.
|
|
|
|
// Send the signal that content has handled the long-tap, and then run
|
|
|
|
// the timeout task (it will be a no-op because the content "wins" the
|
|
|
|
// race. This takes the place of the "contextmenu" event.
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockId, true);
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->AdvanceByMillis(1000);
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
MultiTouchInput mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time());
|
2014-11-10 22:35:11 +03:00
|
|
|
mti.mTouches.AppendElement(SingleTouchData(0, ParentLayerPoint(touchX, touchEndY), ScreenSize(0, 0), 0, 0));
|
2014-10-24 21:29:30 +04:00
|
|
|
status = apzc->ReceiveInputEvent(mti, nullptr);
|
2014-08-02 00:24:50 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2015-03-20 21:26:52 +03:00
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(touchX, touchEndY), 0, apzc->GetGuid())).Times(0);
|
2015-06-01 21:36:12 +03:00
|
|
|
status = TouchUp(apzc, touchX, touchEndY, mcc->Time());
|
2014-08-02 00:24:50 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-11-10 22:35:11 +03:00
|
|
|
ParentLayerPoint pointOut;
|
2014-07-15 03:07:54 +04:00
|
|
|
ViewTransform viewTransformOut;
|
2015-06-01 21:36:12 +03:00
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-11-10 22:35:11 +03:00
|
|
|
EXPECT_EQ(ParentLayerPoint(), pointOut);
|
2014-07-15 03:07:54 +04:00
|
|
|
EXPECT_EQ(ViewTransform(), viewTransformOut);
|
2014-02-13 20:24:53 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
};
|
2013-12-12 04:39:06 +04:00
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCLongPressTester, LongPress) {
|
2015-03-02 19:50:38 +03:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
|
2014-07-11 16:25:13 +04:00
|
|
|
DoLongPressTest(mozilla::layers::AllowedTouchBehavior::NONE);
|
2014-02-24 10:31:18 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCLongPressTester, LongPressWithTouchAction) {
|
2014-07-15 03:07:53 +04:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
|
2014-07-11 16:25:13 +04:00
|
|
|
DoLongPressTest(mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
|
|
|
|
| mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN
|
|
|
|
| mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
|
2014-02-24 10:31:18 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCLongPressTester, LongPressPreventDefault) {
|
2015-03-02 19:50:38 +03:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
|
2014-07-11 16:25:13 +04:00
|
|
|
DoLongPressPreventDefaultTest(mozilla::layers::AllowedTouchBehavior::NONE);
|
2014-04-21 19:30:15 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 03:07:54 +04:00
|
|
|
TEST_F(APZCLongPressTester, LongPressPreventDefaultWithTouchAction) {
|
2014-07-15 03:07:53 +04:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, true);
|
2014-07-11 16:25:13 +04:00
|
|
|
DoLongPressPreventDefaultTest(mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
|
|
|
|
| mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN
|
|
|
|
| mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
|
2014-04-21 19:30:15 +04:00
|
|
|
}
|
2014-02-24 10:31:18 +04:00
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static void
|
2015-06-01 21:36:12 +03:00
|
|
|
DoubleTap(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY, MockContentControllerDelayed* aMcc,
|
2014-10-31 22:31:35 +03:00
|
|
|
nsEventStatus (*aOutEventStatuses)[4] = nullptr,
|
|
|
|
uint64_t (*aOutInputBlockIds)[2] = nullptr)
|
2014-07-16 16:33:50 +04:00
|
|
|
{
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockId;
|
2015-06-01 21:36:12 +03:00
|
|
|
nsEventStatus status = TouchDown(aTarget, aX, aY, aMcc->Time(), &blockId);
|
2014-07-16 16:33:50 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[0] = status;
|
|
|
|
}
|
2014-10-24 21:29:30 +04:00
|
|
|
if (aOutInputBlockIds) {
|
|
|
|
(*aOutInputBlockIds)[0] = blockId;
|
|
|
|
}
|
2015-06-01 21:36:12 +03:00
|
|
|
aMcc->AdvanceByMillis(10);
|
2015-03-02 19:51:45 +03:00
|
|
|
|
|
|
|
// If touch-action is enabled then simulate the allowed touch behaviour
|
|
|
|
// notification that the main thread is supposed to deliver.
|
2015-03-19 13:33:32 +03:00
|
|
|
if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
|
2015-03-02 19:51:45 +03:00
|
|
|
SetDefaultAllowedTouchBehavior(aTarget, blockId);
|
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
status = TouchUp(aTarget, aX, aY, aMcc->Time());
|
2014-07-16 16:33:50 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[1] = status;
|
|
|
|
}
|
2015-06-01 21:36:12 +03:00
|
|
|
aMcc->AdvanceByMillis(10);
|
|
|
|
status = TouchDown(aTarget, aX, aY, aMcc->Time(), &blockId);
|
2014-07-16 16:33:50 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[2] = status;
|
|
|
|
}
|
2014-10-24 21:29:30 +04:00
|
|
|
if (aOutInputBlockIds) {
|
|
|
|
(*aOutInputBlockIds)[1] = blockId;
|
|
|
|
}
|
2015-06-01 21:36:12 +03:00
|
|
|
aMcc->AdvanceByMillis(10);
|
2015-03-02 19:51:45 +03:00
|
|
|
|
2015-03-19 13:33:32 +03:00
|
|
|
if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) {
|
2015-03-02 19:51:45 +03:00
|
|
|
SetDefaultAllowedTouchBehavior(aTarget, blockId);
|
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
status = TouchUp(aTarget, aX, aY, aMcc->Time());
|
2014-07-16 16:33:50 +04:00
|
|
|
if (aOutEventStatuses) {
|
|
|
|
(*aOutEventStatuses)[3] = status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
template<class InputReceiver> static void
|
2015-05-15 19:45:27 +03:00
|
|
|
DoubleTapAndCheckStatus(const nsRefPtr<InputReceiver>& aTarget, int aX, int aY,
|
2015-06-01 21:36:12 +03:00
|
|
|
MockContentControllerDelayed* aMcc, uint64_t (*aOutInputBlockIds)[2] = nullptr)
|
2014-07-16 16:33:50 +04:00
|
|
|
{
|
|
|
|
nsEventStatus statuses[4];
|
2015-06-01 21:36:12 +03:00
|
|
|
DoubleTap(aTarget, aX, aY, aMcc, &statuses, aOutInputBlockIds);
|
2014-07-16 16:33:50 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
|
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[1]);
|
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[2]);
|
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(APZCGestureDetectorTester, DoubleTap) {
|
2015-03-10 16:29:25 +03:00
|
|
|
MakeApzcWaitForMainThread();
|
2014-07-16 16:33:50 +04:00
|
|
|
MakeApzcZoomable();
|
|
|
|
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0);
|
|
|
|
EXPECT_CALL(*mcc, HandleDoubleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
|
|
|
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockIds[2];
|
2015-06-01 21:36:12 +03:00
|
|
|
DoubleTapAndCheckStatus(apzc, 10, 10, mcc, &blockIds);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
// responses to the two touchstarts
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockIds[0], false);
|
|
|
|
apzc->ContentReceivedInputBlock(blockIds[1], false);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(APZCGestureDetectorTester, DoubleTapNotZoomable) {
|
2015-03-10 16:29:25 +03:00
|
|
|
MakeApzcWaitForMainThread();
|
2014-07-16 16:33:50 +04:00
|
|
|
MakeApzcUnzoomable();
|
|
|
|
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(2);
|
|
|
|
EXPECT_CALL(*mcc, HandleDoubleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0);
|
|
|
|
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockIds[2];
|
2015-06-01 21:36:12 +03:00
|
|
|
DoubleTapAndCheckStatus(apzc, 10, 10, mcc, &blockIds);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
// responses to the two touchstarts
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockIds[0], false);
|
|
|
|
apzc->ContentReceivedInputBlock(blockIds[1], false);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(APZCGestureDetectorTester, DoubleTapPreventDefaultFirstOnly) {
|
2015-03-10 16:29:25 +03:00
|
|
|
MakeApzcWaitForMainThread();
|
2014-07-16 16:33:50 +04:00
|
|
|
MakeApzcZoomable();
|
|
|
|
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
|
|
|
EXPECT_CALL(*mcc, HandleDoubleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0);
|
|
|
|
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockIds[2];
|
2015-06-01 21:36:12 +03:00
|
|
|
DoubleTapAndCheckStatus(apzc, 10, 10, mcc, &blockIds);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
// responses to the two touchstarts
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockIds[0], true);
|
|
|
|
apzc->ContentReceivedInputBlock(blockIds[1], false);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(APZCGestureDetectorTester, DoubleTapPreventDefaultBoth) {
|
2015-03-10 16:29:25 +03:00
|
|
|
MakeApzcWaitForMainThread();
|
2014-07-16 16:33:50 +04:00
|
|
|
MakeApzcZoomable();
|
|
|
|
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0);
|
|
|
|
EXPECT_CALL(*mcc, HandleDoubleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0);
|
|
|
|
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockIds[2];
|
2015-06-01 21:36:12 +03:00
|
|
|
DoubleTapAndCheckStatus(apzc, 10, 10, mcc, &blockIds);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
// responses to the two touchstarts
|
2014-12-09 13:35:12 +03:00
|
|
|
apzc->ContentReceivedInputBlock(blockIds[0], true);
|
|
|
|
apzc->ContentReceivedInputBlock(blockIds[1], true);
|
2014-07-16 16:33:50 +04:00
|
|
|
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
|
2014-10-03 17:24:56 +04:00
|
|
|
// Test for bug 947892
|
|
|
|
// We test whether we dispatch tap event when the tap is followed by pinch.
|
|
|
|
TEST_F(APZCGestureDetectorTester, TapFollowedByPinch) {
|
|
|
|
MakeApzcZoomable();
|
|
|
|
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(100));
|
2014-10-03 17:24:56 +04:00
|
|
|
|
|
|
|
int inputId = 0;
|
|
|
|
MultiTouchInput mti;
|
2015-06-01 21:36:12 +03:00
|
|
|
mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time());
|
2014-11-10 22:35:11 +03:00
|
|
|
mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20), ScreenSize(0, 0), 0, 0));
|
|
|
|
mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ParentLayerPoint(10, 10), ScreenSize(0, 0), 0, 0));
|
2014-10-24 21:29:30 +04:00
|
|
|
apzc->ReceiveInputEvent(mti, nullptr);
|
2014-10-03 17:24:56 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_END, mcc->Time());
|
2014-11-10 22:35:11 +03:00
|
|
|
mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20), ScreenSize(0, 0), 0, 0));
|
|
|
|
mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ParentLayerPoint(10, 10), ScreenSize(0, 0), 0, 0));
|
2014-10-24 21:29:30 +04:00
|
|
|
apzc->ReceiveInputEvent(mti, nullptr);
|
2014-10-03 17:24:56 +04:00
|
|
|
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(APZCGestureDetectorTester, TapFollowedByMultipleTouches) {
|
|
|
|
MakeApzcZoomable();
|
|
|
|
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(100));
|
2014-10-03 17:24:56 +04:00
|
|
|
|
|
|
|
int inputId = 0;
|
|
|
|
MultiTouchInput mti;
|
2015-06-01 21:36:12 +03:00
|
|
|
mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time());
|
2014-11-10 22:35:11 +03:00
|
|
|
mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20), ScreenSize(0, 0), 0, 0));
|
2014-10-24 21:29:30 +04:00
|
|
|
apzc->ReceiveInputEvent(mti, nullptr);
|
2014-10-03 17:24:56 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time());
|
2014-11-10 22:35:11 +03:00
|
|
|
mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20), ScreenSize(0, 0), 0, 0));
|
|
|
|
mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ParentLayerPoint(10, 10), ScreenSize(0, 0), 0, 0));
|
2014-10-24 21:29:30 +04:00
|
|
|
apzc->ReceiveInputEvent(mti, nullptr);
|
2014-10-03 17:24:56 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_END, mcc->Time());
|
2014-11-10 22:35:11 +03:00
|
|
|
mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20), ScreenSize(0, 0), 0, 0));
|
|
|
|
mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ParentLayerPoint(10, 10), ScreenSize(0, 0), 0, 0));
|
2014-10-24 21:29:30 +04:00
|
|
|
apzc->ReceiveInputEvent(mti, nullptr);
|
2014-10-03 17:24:56 +04:00
|
|
|
|
|
|
|
apzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
|
2014-08-20 05:17:10 +04:00
|
|
|
class APZCTreeManagerTester : public ::testing::Test {
|
|
|
|
protected:
|
|
|
|
virtual void SetUp() {
|
|
|
|
gfxPrefs::GetSingleton();
|
2015-02-10 16:24:23 +03:00
|
|
|
APZThreadUtils::SetThreadAssertionsEnabled(false);
|
2015-04-29 14:22:27 +03:00
|
|
|
APZThreadUtils::SetControllerThread(MessageLoop::current());
|
2013-10-30 23:58:25 +04:00
|
|
|
|
2014-09-25 21:46:34 +04:00
|
|
|
mcc = new NiceMock<MockContentControllerDelayed>();
|
2015-06-01 21:36:12 +03:00
|
|
|
manager = new TestAPZCTreeManager();
|
2014-08-20 05:17:10 +04:00
|
|
|
}
|
2013-07-30 22:03:41 +04:00
|
|
|
|
2014-08-20 05:17:10 +04:00
|
|
|
virtual void TearDown() {
|
2015-06-01 21:36:12 +03:00
|
|
|
while (mcc->RunThroughDelayedTasks());
|
2014-08-20 05:17:10 +04:00
|
|
|
manager->ClearTree();
|
2013-08-21 20:03:03 +04:00
|
|
|
}
|
|
|
|
|
2015-06-04 02:38:50 +03:00
|
|
|
/**
|
|
|
|
* Sample animations once for all APZCs, 1 ms later than the last sample.
|
|
|
|
*/
|
|
|
|
void SampleAnimationsOnce() {
|
|
|
|
const TimeDuration increment = TimeDuration::FromMilliseconds(1);
|
|
|
|
ParentLayerPoint pointOut;
|
|
|
|
ViewTransform viewTransformOut;
|
|
|
|
mcc->AdvanceBy(increment);
|
|
|
|
|
|
|
|
for (const nsRefPtr<Layer>& layer : layers) {
|
|
|
|
if (TestAsyncPanZoomController* apzc = ApzcOf(layer)) {
|
|
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-25 21:46:34 +04:00
|
|
|
nsRefPtr<MockContentControllerDelayed> mcc;
|
2014-08-20 05:17:10 +04:00
|
|
|
|
2013-07-30 22:03:41 +04:00
|
|
|
nsTArray<nsRefPtr<Layer> > layers;
|
|
|
|
nsRefPtr<LayerManager> lm;
|
2014-08-20 05:17:10 +04:00
|
|
|
nsRefPtr<Layer> root;
|
2013-07-30 22:03:41 +04:00
|
|
|
|
2014-08-20 05:17:10 +04:00
|
|
|
nsRefPtr<TestAPZCTreeManager> manager;
|
2013-07-30 22:03:41 +04:00
|
|
|
|
2014-08-20 05:17:10 +04:00
|
|
|
protected:
|
|
|
|
static void SetScrollableFrameMetrics(Layer* aLayer, FrameMetrics::ViewID aScrollId,
|
|
|
|
CSSRect aScrollableRect = CSSRect(-1, -1, -1, -1)) {
|
|
|
|
FrameMetrics metrics;
|
|
|
|
metrics.SetScrollId(aScrollId);
|
2015-05-31 22:44:41 +03:00
|
|
|
// By convention in this test file, START_SCROLL_ID is the root, so mark it as such.
|
|
|
|
if (aScrollId == FrameMetrics::START_SCROLL_ID) {
|
|
|
|
metrics.SetIsLayersIdRoot(true);
|
|
|
|
}
|
2015-05-07 12:08:01 +03:00
|
|
|
IntRect layerBound = aLayer->GetVisibleRegion().GetBounds();
|
2015-05-07 21:44:03 +03:00
|
|
|
metrics.SetCompositionBounds(ParentLayerRect(layerBound.x, layerBound.y,
|
|
|
|
layerBound.width, layerBound.height));
|
2014-12-27 20:48:27 +03:00
|
|
|
metrics.SetScrollableRect(aScrollableRect);
|
2014-08-20 05:17:10 +04:00
|
|
|
metrics.SetScrollOffset(CSSPoint(0, 0));
|
2015-05-29 18:04:22 +03:00
|
|
|
metrics.SetPageScrollAmount(LayoutDeviceIntSize(50, 100));
|
|
|
|
metrics.SetAllowVerticalScrollWithWheel();
|
2014-08-20 05:17:10 +04:00
|
|
|
aLayer->SetFrameMetrics(metrics);
|
2015-04-12 05:03:00 +03:00
|
|
|
aLayer->SetClipRect(Some(ViewAs<ParentLayerPixel>(layerBound)));
|
2014-12-15 05:37:52 +03:00
|
|
|
if (!aScrollableRect.IsEqualEdges(CSSRect(-1, -1, -1, -1))) {
|
|
|
|
// The purpose of this is to roughly mimic what layout would do in the
|
|
|
|
// case of a scrollable frame with the event regions and clip. This lets
|
|
|
|
// us exercise the hit-testing code in APZCTreeManager
|
|
|
|
EventRegions er = aLayer->GetEventRegions();
|
2015-05-07 12:08:01 +03:00
|
|
|
IntRect scrollRect = LayerIntRect::ToUntyped(RoundedToInt(aScrollableRect * metrics.LayersPixelsPerCSSPixel()));
|
|
|
|
er.mHitRegion = nsIntRegion(IntRect(layerBound.TopLeft(), scrollRect.Size()));
|
2014-12-15 05:37:52 +03:00
|
|
|
aLayer->SetEventRegions(er);
|
|
|
|
}
|
2014-08-20 05:17:10 +04:00
|
|
|
}
|
2014-08-20 05:17:10 +04:00
|
|
|
|
2014-11-14 15:40:15 +03:00
|
|
|
void SetScrollHandoff(Layer* aChild, Layer* aParent) {
|
|
|
|
FrameMetrics metrics = aChild->GetFrameMetrics(0);
|
|
|
|
metrics.SetScrollParentId(aParent->GetFrameMetrics(0).GetScrollId());
|
|
|
|
aChild->SetFrameMetrics(metrics);
|
|
|
|
}
|
|
|
|
|
2014-09-04 21:55:05 +04:00
|
|
|
static TestAsyncPanZoomController* ApzcOf(Layer* aLayer) {
|
2014-09-06 04:13:04 +04:00
|
|
|
EXPECT_EQ(1u, aLayer->GetFrameMetricsCount());
|
2014-09-04 21:55:05 +04:00
|
|
|
return (TestAsyncPanZoomController*)aLayer->GetAsyncPanZoomController(0);
|
|
|
|
}
|
|
|
|
|
2014-09-25 21:46:34 +04:00
|
|
|
void CreateSimpleScrollingLayer() {
|
|
|
|
const char* layerTreeSyntax = "t";
|
|
|
|
nsIntRegion layerVisibleRegion[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0,0,200,200)),
|
2014-09-25 21:46:34 +04:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
|
|
|
|
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 500, 500));
|
|
|
|
}
|
|
|
|
|
2014-08-20 05:17:10 +04:00
|
|
|
void CreateSimpleMultiLayerTree() {
|
|
|
|
const char* layerTreeSyntax = "c(tt)";
|
|
|
|
// LayerID 0 12
|
|
|
|
nsIntRegion layerVisibleRegion[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0,0,100,100)),
|
|
|
|
nsIntRegion(IntRect(0,0,100,50)),
|
|
|
|
nsIntRegion(IntRect(0,50,100,50)),
|
2014-08-20 05:17:10 +04:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
|
|
|
|
}
|
2014-09-21 06:27:16 +04:00
|
|
|
|
|
|
|
void CreatePotentiallyLeakingTree() {
|
2014-12-15 05:37:51 +03:00
|
|
|
const char* layerTreeSyntax = "c(c(c(t))c(c(t)))";
|
2014-09-21 06:27:16 +04:00
|
|
|
// LayerID 0 1 2 3 4 5 6
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, nullptr, nullptr, lm, layers);
|
|
|
|
SetScrollableFrameMetrics(layers[0], FrameMetrics::START_SCROLL_ID);
|
|
|
|
SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 1);
|
|
|
|
SetScrollableFrameMetrics(layers[5], FrameMetrics::START_SCROLL_ID + 1);
|
|
|
|
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 2);
|
|
|
|
SetScrollableFrameMetrics(layers[6], FrameMetrics::START_SCROLL_ID + 3);
|
|
|
|
}
|
2014-08-20 05:17:10 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
class APZHitTestingTester : public APZCTreeManagerTester {
|
|
|
|
protected:
|
2014-08-01 16:31:49 +04:00
|
|
|
Matrix4x4 transformToApzc;
|
|
|
|
Matrix4x4 transformToGecko;
|
2013-07-30 22:03:41 +04:00
|
|
|
|
2014-08-20 05:17:10 +04:00
|
|
|
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint) {
|
|
|
|
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(aPoint, nullptr);
|
|
|
|
if (hit) {
|
2014-09-09 02:04:01 +04:00
|
|
|
transformToApzc = manager->GetScreenToApzcTransform(hit.get());
|
|
|
|
transformToGecko = manager->GetApzcToGeckoTransform(hit.get());
|
2014-08-20 05:17:10 +04:00
|
|
|
}
|
|
|
|
return hit.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void CreateHitTesting1LayerTree() {
|
2014-12-15 05:37:51 +03:00
|
|
|
const char* layerTreeSyntax = "c(tttt)";
|
2014-08-20 05:17:10 +04:00
|
|
|
// LayerID 0 1234
|
|
|
|
nsIntRegion layerVisibleRegion[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0,0,100,100)),
|
|
|
|
nsIntRegion(IntRect(0,0,100,100)),
|
|
|
|
nsIntRegion(IntRect(10,10,20,20)),
|
|
|
|
nsIntRegion(IntRect(10,10,20,20)),
|
|
|
|
nsIntRegion(IntRect(5,5,20,20)),
|
2014-08-20 05:17:10 +04:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CreateHitTesting2LayerTree() {
|
2014-12-15 05:37:51 +03:00
|
|
|
const char* layerTreeSyntax = "c(tc(t))";
|
2014-08-20 05:17:10 +04:00
|
|
|
// LayerID 0 12 3
|
|
|
|
nsIntRegion layerVisibleRegion[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0,0,100,100)),
|
|
|
|
nsIntRegion(IntRect(10,10,40,40)),
|
|
|
|
nsIntRegion(IntRect(10,60,40,40)),
|
|
|
|
nsIntRegion(IntRect(10,60,40,40)),
|
2014-08-20 05:17:10 +04:00
|
|
|
};
|
|
|
|
Matrix4x4 transforms[] = {
|
|
|
|
Matrix4x4(),
|
|
|
|
Matrix4x4(),
|
2014-10-08 07:43:00 +04:00
|
|
|
Matrix4x4::Scaling(2, 1, 1),
|
2014-08-20 05:17:10 +04:00
|
|
|
Matrix4x4(),
|
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
|
|
|
|
|
|
|
|
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
|
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 80, 80));
|
|
|
|
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 2, CSSRect(0, 0, 80, 80));
|
|
|
|
}
|
2014-08-20 05:17:10 +04:00
|
|
|
|
|
|
|
void CreateComplexMultiLayerTree() {
|
2014-09-04 22:43:31 +04:00
|
|
|
const char* layerTreeSyntax = "c(tc(t)tc(c(t)tt))";
|
|
|
|
// LayerID 0 12 3 45 6 7 89
|
2014-08-20 05:17:10 +04:00
|
|
|
nsIntRegion layerVisibleRegion[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0,0,300,400)), // root(0)
|
|
|
|
nsIntRegion(IntRect(0,0,100,100)), // thebes(1) in top-left
|
|
|
|
nsIntRegion(IntRect(50,50,200,300)), // container(2) centered in root(0)
|
|
|
|
nsIntRegion(IntRect(50,50,200,300)), // thebes(3) fully occupying parent container(2)
|
|
|
|
nsIntRegion(IntRect(0,200,100,100)), // thebes(4) in bottom-left
|
|
|
|
nsIntRegion(IntRect(200,0,100,400)), // container(5) along the right 100px of root(0)
|
|
|
|
nsIntRegion(IntRect(200,0,100,200)), // container(6) taking up the top half of parent container(5)
|
|
|
|
nsIntRegion(IntRect(200,0,100,200)), // thebes(7) fully occupying parent container(6)
|
|
|
|
nsIntRegion(IntRect(200,200,100,100)), // thebes(8) in bottom-right (below (6))
|
|
|
|
nsIntRegion(IntRect(200,300,100,100)), // thebes(9) in bottom-right (below (8))
|
2014-08-20 05:17:10 +04:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
|
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID);
|
|
|
|
SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID);
|
|
|
|
SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 1);
|
|
|
|
SetScrollableFrameMetrics(layers[6], FrameMetrics::START_SCROLL_ID + 1);
|
|
|
|
SetScrollableFrameMetrics(layers[7], FrameMetrics::START_SCROLL_ID + 2);
|
2014-09-04 22:43:31 +04:00
|
|
|
SetScrollableFrameMetrics(layers[8], FrameMetrics::START_SCROLL_ID + 1);
|
|
|
|
SetScrollableFrameMetrics(layers[9], FrameMetrics::START_SCROLL_ID + 3);
|
2014-08-20 05:17:10 +04:00
|
|
|
}
|
2015-04-30 21:30:38 +03:00
|
|
|
|
|
|
|
void CreateBug1148350LayerTree() {
|
|
|
|
const char* layerTreeSyntax = "c(t)";
|
|
|
|
// LayerID 0 1
|
|
|
|
nsIntRegion layerVisibleRegion[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0,0,200,200)),
|
|
|
|
nsIntRegion(IntRect(0,0,200,200)),
|
2015-04-30 21:30:38 +03:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
|
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID);
|
|
|
|
}
|
2014-08-20 05:17:10 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
// A simple hit testing test that doesn't involve any transforms on layers.
|
|
|
|
TEST_F(APZHitTestingTester, HitTesting1) {
|
|
|
|
CreateHitTesting1LayerTree();
|
|
|
|
ScopedLayerTreeRegistration registration(0, root, mcc);
|
|
|
|
|
2013-07-30 22:03:41 +04:00
|
|
|
// No APZC attached so hit testing will return no APZC at (20,20)
|
2014-08-20 05:17:10 +04:00
|
|
|
nsRefPtr<AsyncPanZoomController> hit = GetTargetAPZC(ScreenPoint(20, 20));
|
2014-10-24 21:29:35 +04:00
|
|
|
TestAsyncPanZoomController* nullAPZC = nullptr;
|
2013-07-30 22:03:41 +04:00
|
|
|
EXPECT_EQ(nullAPZC, hit.get());
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Matrix4x4(), transformToApzc);
|
|
|
|
EXPECT_EQ(Matrix4x4(), transformToGecko);
|
2013-07-30 22:03:41 +04:00
|
|
|
|
2014-05-07 01:26:13 +04:00
|
|
|
uint32_t paintSequenceNumber = 0;
|
|
|
|
|
2013-07-30 22:03:41 +04:00
|
|
|
// Now we have a root APZC that will match the page
|
2013-11-09 04:07:00 +04:00
|
|
|
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, paintSequenceNumber++);
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(15, 15));
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_EQ(ApzcOf(root), hit.get());
|
2013-07-30 22:03:41 +04:00
|
|
|
// expect hit point at LayerIntPoint(15, 15)
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(15, 15), transformToApzc * Point(15, 15));
|
|
|
|
EXPECT_EQ(Point(15, 15), transformToGecko * Point(15, 15));
|
2013-07-30 22:03:41 +04:00
|
|
|
|
|
|
|
// Now we have a sub APZC with a better fit
|
2013-11-09 04:07:00 +04:00
|
|
|
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 1);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, paintSequenceNumber++);
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_NE(ApzcOf(root), ApzcOf(layers[3]));
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(25, 25));
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_EQ(ApzcOf(layers[3]), hit.get());
|
2014-07-25 16:27:43 +04:00
|
|
|
// expect hit point at LayerIntPoint(25, 25)
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(25, 25), transformToApzc * Point(25, 25));
|
|
|
|
EXPECT_EQ(Point(25, 25), transformToGecko * Point(25, 25));
|
2014-07-25 16:27:43 +04:00
|
|
|
|
2014-07-25 16:27:43 +04:00
|
|
|
// At this point, layers[4] obscures layers[3] at the point (15, 15) so
|
|
|
|
// hitting there should hit the root APZC
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(15, 15));
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_EQ(ApzcOf(root), hit.get());
|
2014-07-25 16:27:43 +04:00
|
|
|
|
|
|
|
// Now test hit testing when we have two scrollable layers
|
2013-11-09 04:07:00 +04:00
|
|
|
SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 2);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, paintSequenceNumber++);
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(15, 15));
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_EQ(ApzcOf(layers[4]), hit.get());
|
2013-07-30 22:03:41 +04:00
|
|
|
// expect hit point at LayerIntPoint(15, 15)
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(15, 15), transformToApzc * Point(15, 15));
|
|
|
|
EXPECT_EQ(Point(15, 15), transformToGecko * Point(15, 15));
|
2013-07-30 22:03:41 +04:00
|
|
|
|
|
|
|
// Hit test ouside the reach of layer[3,4] but inside root
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(90, 90));
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_EQ(ApzcOf(root), hit.get());
|
2013-07-30 22:03:41 +04:00
|
|
|
// expect hit point at LayerIntPoint(90, 90)
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(90, 90), transformToApzc * Point(90, 90));
|
|
|
|
EXPECT_EQ(Point(90, 90), transformToGecko * Point(90, 90));
|
2013-07-30 22:03:41 +04:00
|
|
|
|
|
|
|
// Hit test ouside the reach of any layer
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(1000, 10));
|
2013-07-30 22:03:41 +04:00
|
|
|
EXPECT_EQ(nullAPZC, hit.get());
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Matrix4x4(), transformToApzc);
|
|
|
|
EXPECT_EQ(Matrix4x4(), transformToGecko);
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(-1000, 10));
|
2013-07-30 22:03:41 +04:00
|
|
|
EXPECT_EQ(nullAPZC, hit.get());
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Matrix4x4(), transformToApzc);
|
|
|
|
EXPECT_EQ(Matrix4x4(), transformToGecko);
|
2013-10-30 23:58:25 +04:00
|
|
|
}
|
2013-07-30 22:03:41 +04:00
|
|
|
|
2013-10-30 23:58:25 +04:00
|
|
|
// A more involved hit testing test that involves css and async transforms.
|
2014-08-20 05:17:10 +04:00
|
|
|
TEST_F(APZHitTestingTester, HitTesting2) {
|
|
|
|
CreateHitTesting2LayerTree();
|
|
|
|
ScopedLayerTreeRegistration registration(0, root, mcc);
|
2013-10-30 23:58:25 +04:00
|
|
|
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2013-10-30 23:58:25 +04:00
|
|
|
|
|
|
|
// At this point, the following holds (all coordinates in screen pixels):
|
|
|
|
// layers[0] has content from (0,0)-(200,200), clipped by composition bounds (0,0)-(100,100)
|
|
|
|
// layers[1] has content from (10,10)-(90,90), clipped by composition bounds (10,10)-(50,50)
|
|
|
|
// layers[2] has content from (20,60)-(100,100). no clipping as it's not a scrollable layer
|
|
|
|
// layers[3] has content from (20,60)-(180,140), clipped by composition bounds (20,60)-(100,100)
|
|
|
|
|
2014-10-24 21:29:35 +04:00
|
|
|
TestAsyncPanZoomController* apzcroot = ApzcOf(root);
|
|
|
|
TestAsyncPanZoomController* apzc1 = ApzcOf(layers[1]);
|
|
|
|
TestAsyncPanZoomController* apzc3 = ApzcOf(layers[3]);
|
2013-10-30 23:58:25 +04:00
|
|
|
|
|
|
|
// Hit an area that's clearly on the root layer but not any of the child layers.
|
2014-08-20 05:17:10 +04:00
|
|
|
nsRefPtr<AsyncPanZoomController> hit = GetTargetAPZC(ScreenPoint(75, 25));
|
2013-10-30 23:58:25 +04:00
|
|
|
EXPECT_EQ(apzcroot, hit.get());
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(75, 25), transformToApzc * Point(75, 25));
|
|
|
|
EXPECT_EQ(Point(75, 25), transformToGecko * Point(75, 25));
|
2013-10-30 23:58:25 +04:00
|
|
|
|
|
|
|
// Hit an area on the root that would be on layers[3] if layers[2]
|
|
|
|
// weren't transformed.
|
|
|
|
// Note that if layers[2] were scrollable, then this would hit layers[2]
|
|
|
|
// because its composition bounds would be at (10,60)-(50,100) (and the
|
|
|
|
// scale-only transform that we set on layers[2] would be invalid because
|
|
|
|
// it would place the layer into overscroll, as its composition bounds
|
|
|
|
// start at x=10 but its content at x=20).
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(15, 75));
|
2013-10-30 23:58:25 +04:00
|
|
|
EXPECT_EQ(apzcroot, hit.get());
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(15, 75), transformToApzc * Point(15, 75));
|
|
|
|
EXPECT_EQ(Point(15, 75), transformToGecko * Point(15, 75));
|
2013-10-30 23:58:25 +04:00
|
|
|
|
|
|
|
// Hit an area on layers[1].
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(25, 25));
|
2013-10-30 23:58:25 +04:00
|
|
|
EXPECT_EQ(apzc1, hit.get());
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(25, 25), transformToApzc * Point(25, 25));
|
|
|
|
EXPECT_EQ(Point(25, 25), transformToGecko * Point(25, 25));
|
2013-10-30 23:58:25 +04:00
|
|
|
|
|
|
|
// Hit an area on layers[3].
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(25, 75));
|
2013-10-30 23:58:25 +04:00
|
|
|
EXPECT_EQ(apzc3, hit.get());
|
|
|
|
// transformToApzc should unapply layers[2]'s transform
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(12.5, 75), transformToApzc * Point(25, 75));
|
2013-10-31 22:44:33 +04:00
|
|
|
// and transformToGecko should reapply it
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(25, 75), transformToGecko * Point(12.5, 75));
|
2013-10-30 23:58:25 +04:00
|
|
|
|
|
|
|
// Hit an area on layers[3] that would be on the root if layers[2]
|
|
|
|
// weren't transformed.
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(75, 75));
|
2013-10-30 23:58:25 +04:00
|
|
|
EXPECT_EQ(apzc3, hit.get());
|
|
|
|
// transformToApzc should unapply layers[2]'s transform
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(37.5, 75), transformToApzc * Point(75, 75));
|
2013-10-31 22:44:33 +04:00
|
|
|
// and transformToGecko should reapply it
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(75, 75), transformToGecko * Point(37.5, 75));
|
2013-10-30 23:58:25 +04:00
|
|
|
|
|
|
|
// Pan the root layer upward by 50 pixels.
|
|
|
|
// This causes layers[1] to scroll out of view, and an async transform
|
|
|
|
// of -50 to be set on the root layer.
|
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
|
2014-01-22 22:37:30 +04:00
|
|
|
|
|
|
|
// This first pan will move the APZC by 50 pixels, and dispatch a paint request.
|
|
|
|
// Since this paint request is in the queue to Gecko, transformToGecko will
|
|
|
|
// take it into account.
|
2015-06-01 21:36:12 +03:00
|
|
|
ApzcPanNoFling(apzcroot, mcc, 100, 50);
|
2013-10-30 23:58:25 +04:00
|
|
|
|
|
|
|
// Hit where layers[3] used to be. It should now hit the root.
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(75, 75));
|
2013-10-30 23:58:25 +04:00
|
|
|
EXPECT_EQ(apzcroot, hit.get());
|
|
|
|
// transformToApzc doesn't unapply the root's own async transform
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(75, 75), transformToApzc * Point(75, 75));
|
2014-01-22 22:37:30 +04:00
|
|
|
// and transformToGecko unapplies it and then reapplies it, because by the
|
|
|
|
// time the event being transformed reaches Gecko the new paint request will
|
|
|
|
// have been handled.
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(75, 75), transformToGecko * Point(75, 75));
|
2013-10-30 23:58:25 +04:00
|
|
|
|
|
|
|
// Hit where layers[1] used to be and where layers[3] should now be.
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(25, 25));
|
2013-10-30 23:58:25 +04:00
|
|
|
EXPECT_EQ(apzc3, hit.get());
|
|
|
|
// transformToApzc unapplies both layers[2]'s css transform and the root's
|
2014-01-22 22:37:30 +04:00
|
|
|
// async transform
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(12.5, 75), transformToApzc * Point(25, 25));
|
2014-01-22 22:37:30 +04:00
|
|
|
// transformToGecko reapplies both the css transform and the async transform
|
|
|
|
// because we have already issued a paint request with it.
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(25, 25), transformToGecko * Point(12.5, 75));
|
2014-01-22 22:37:30 +04:00
|
|
|
|
|
|
|
// This second pan will move the APZC by another 50 pixels but since the paint
|
|
|
|
// request dispatched above has not "completed", we will not dispatch another
|
|
|
|
// one yet. Now we have an async transform on top of the pending paint request
|
|
|
|
// transform.
|
2015-06-01 21:36:12 +03:00
|
|
|
ApzcPanNoFling(apzcroot, mcc, 100, 50);
|
2014-01-22 22:37:30 +04:00
|
|
|
|
|
|
|
// Hit where layers[3] used to be. It should now hit the root.
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(75, 75));
|
2014-01-22 22:37:30 +04:00
|
|
|
EXPECT_EQ(apzcroot, hit.get());
|
|
|
|
// transformToApzc doesn't unapply the root's own async transform
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(75, 75), transformToApzc * Point(75, 75));
|
2014-01-22 22:37:30 +04:00
|
|
|
// transformToGecko unapplies the full async transform of -100 pixels, and then
|
|
|
|
// reapplies the "D" transform of -50 leading to an overall adjustment of +50
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(75, 125), transformToGecko * Point(75, 75));
|
2014-01-22 22:37:30 +04:00
|
|
|
|
|
|
|
// Hit where layers[1] used to be. It should now hit the root.
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(25, 25));
|
2014-01-22 22:37:30 +04:00
|
|
|
EXPECT_EQ(apzcroot, hit.get());
|
|
|
|
// transformToApzc doesn't unapply the root's own async transform
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(25, 25), transformToApzc * Point(25, 25));
|
2014-01-22 22:37:30 +04:00
|
|
|
// transformToGecko unapplies the full async transform of -100 pixels, and then
|
|
|
|
// reapplies the "D" transform of -50 leading to an overall adjustment of +50
|
2014-08-01 16:31:49 +04:00
|
|
|
EXPECT_EQ(Point(25, 75), transformToGecko * Point(25, 25));
|
2013-10-31 22:44:33 +04:00
|
|
|
}
|
2014-07-31 17:04:34 +04:00
|
|
|
|
2014-09-26 21:06:08 +04:00
|
|
|
TEST_F(APZCTreeManagerTester, ScrollablePaintedLayers) {
|
2014-08-20 05:17:10 +04:00
|
|
|
CreateSimpleMultiLayerTree();
|
|
|
|
ScopedLayerTreeRegistration registration(0, root, mcc);
|
|
|
|
|
|
|
|
// both layers have the same scrollId
|
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID);
|
|
|
|
SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2014-08-20 05:17:10 +04:00
|
|
|
|
2014-10-24 21:29:35 +04:00
|
|
|
TestAsyncPanZoomController* nullAPZC = nullptr;
|
2014-08-20 05:17:10 +04:00
|
|
|
// so they should have the same APZC
|
2014-08-28 06:13:43 +04:00
|
|
|
EXPECT_FALSE(layers[0]->HasScrollableFrameMetrics());
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_NE(nullAPZC, ApzcOf(layers[1]));
|
|
|
|
EXPECT_NE(nullAPZC, ApzcOf(layers[2]));
|
|
|
|
EXPECT_EQ(ApzcOf(layers[1]), ApzcOf(layers[2]));
|
2014-08-20 05:17:10 +04:00
|
|
|
|
|
|
|
// Change the scrollId of layers[1], and verify the APZC changes
|
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_NE(ApzcOf(layers[1]), ApzcOf(layers[2]));
|
2014-08-20 05:17:10 +04:00
|
|
|
|
|
|
|
// Change the scrollId of layers[2] to match that of layers[1], ensure we get the same
|
|
|
|
// APZC for both again
|
|
|
|
SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 1);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_EQ(ApzcOf(layers[1]), ApzcOf(layers[2]));
|
2014-08-20 05:17:10 +04:00
|
|
|
}
|
|
|
|
|
2014-09-21 06:27:16 +04:00
|
|
|
TEST_F(APZCTreeManagerTester, Bug1068268) {
|
|
|
|
CreatePotentiallyLeakingTree();
|
|
|
|
ScopedLayerTreeRegistration registration(0, root, mcc);
|
|
|
|
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2015-01-08 17:40:01 +03:00
|
|
|
nsRefPtr<HitTestingTreeNode> root = manager->GetRootNode();
|
2015-01-08 17:40:01 +03:00
|
|
|
nsRefPtr<HitTestingTreeNode> node2 = root->GetFirstChild()->GetFirstChild();
|
|
|
|
nsRefPtr<HitTestingTreeNode> node5 = root->GetLastChild()->GetLastChild();
|
2015-01-08 17:40:01 +03:00
|
|
|
|
2015-01-08 17:40:01 +03:00
|
|
|
EXPECT_EQ(ApzcOf(layers[2]), node5->GetApzc());
|
|
|
|
EXPECT_EQ(ApzcOf(layers[2]), node2->GetApzc());
|
2014-09-21 06:27:16 +04:00
|
|
|
EXPECT_EQ(ApzcOf(layers[0]), ApzcOf(layers[2])->GetParent());
|
|
|
|
EXPECT_EQ(ApzcOf(layers[2]), ApzcOf(layers[5]));
|
|
|
|
|
2015-01-08 17:40:01 +03:00
|
|
|
EXPECT_EQ(node2->GetFirstChild(), node2->GetLastChild());
|
2015-01-08 17:40:01 +03:00
|
|
|
EXPECT_EQ(ApzcOf(layers[3]), node2->GetLastChild()->GetApzc());
|
2015-01-08 17:40:01 +03:00
|
|
|
EXPECT_EQ(node5->GetFirstChild(), node5->GetLastChild());
|
2015-01-08 17:40:01 +03:00
|
|
|
EXPECT_EQ(ApzcOf(layers[6]), node5->GetLastChild()->GetApzc());
|
2014-09-21 06:27:16 +04:00
|
|
|
EXPECT_EQ(ApzcOf(layers[2]), ApzcOf(layers[3])->GetParent());
|
2015-01-08 17:40:01 +03:00
|
|
|
EXPECT_EQ(ApzcOf(layers[5]), ApzcOf(layers[6])->GetParent());
|
2014-09-21 06:27:16 +04:00
|
|
|
}
|
|
|
|
|
2014-08-20 05:17:10 +04:00
|
|
|
TEST_F(APZHitTestingTester, ComplexMultiLayerTree) {
|
|
|
|
CreateComplexMultiLayerTree();
|
|
|
|
ScopedLayerTreeRegistration registration(0, root, mcc);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2014-08-20 05:17:10 +04:00
|
|
|
|
2015-01-08 17:40:01 +03:00
|
|
|
/* The layer tree looks like this:
|
|
|
|
|
|
|
|
0
|
|
|
|
|----|--+--|----|
|
|
|
|
1 2 4 5
|
|
|
|
| /|\
|
|
|
|
3 6 8 9
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
|
Layers 1,2 have the same APZC
|
|
|
|
Layers 4,6,8 have the same APZC
|
|
|
|
Layer 7 has an APZC
|
|
|
|
Layer 9 has an APZC
|
|
|
|
*/
|
|
|
|
|
2014-10-24 21:29:35 +04:00
|
|
|
TestAsyncPanZoomController* nullAPZC = nullptr;
|
2014-08-20 05:17:10 +04:00
|
|
|
// Ensure all the scrollable layers have an APZC
|
2014-08-28 06:13:43 +04:00
|
|
|
EXPECT_FALSE(layers[0]->HasScrollableFrameMetrics());
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_NE(nullAPZC, ApzcOf(layers[1]));
|
|
|
|
EXPECT_NE(nullAPZC, ApzcOf(layers[2]));
|
2014-08-28 06:13:43 +04:00
|
|
|
EXPECT_FALSE(layers[3]->HasScrollableFrameMetrics());
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_NE(nullAPZC, ApzcOf(layers[4]));
|
2014-08-28 06:13:43 +04:00
|
|
|
EXPECT_FALSE(layers[5]->HasScrollableFrameMetrics());
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_NE(nullAPZC, ApzcOf(layers[6]));
|
|
|
|
EXPECT_NE(nullAPZC, ApzcOf(layers[7]));
|
|
|
|
EXPECT_NE(nullAPZC, ApzcOf(layers[8]));
|
2014-09-04 22:43:31 +04:00
|
|
|
EXPECT_NE(nullAPZC, ApzcOf(layers[9]));
|
2014-08-20 05:17:10 +04:00
|
|
|
// Ensure those that scroll together have the same APZCs
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_EQ(ApzcOf(layers[1]), ApzcOf(layers[2]));
|
|
|
|
EXPECT_EQ(ApzcOf(layers[4]), ApzcOf(layers[6]));
|
2014-09-04 22:43:31 +04:00
|
|
|
EXPECT_EQ(ApzcOf(layers[8]), ApzcOf(layers[6]));
|
2014-08-20 05:17:10 +04:00
|
|
|
// Ensure those that don't scroll together have different APZCs
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_NE(ApzcOf(layers[1]), ApzcOf(layers[4]));
|
|
|
|
EXPECT_NE(ApzcOf(layers[1]), ApzcOf(layers[7]));
|
2014-09-04 22:43:31 +04:00
|
|
|
EXPECT_NE(ApzcOf(layers[1]), ApzcOf(layers[9]));
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_NE(ApzcOf(layers[4]), ApzcOf(layers[7]));
|
2014-09-04 22:43:31 +04:00
|
|
|
EXPECT_NE(ApzcOf(layers[4]), ApzcOf(layers[9]));
|
|
|
|
EXPECT_NE(ApzcOf(layers[7]), ApzcOf(layers[9]));
|
2015-01-08 17:40:01 +03:00
|
|
|
// Ensure the APZC parent chains are set up correctly
|
2014-10-24 21:29:35 +04:00
|
|
|
TestAsyncPanZoomController* layers1_2 = ApzcOf(layers[1]);
|
|
|
|
TestAsyncPanZoomController* layers4_6_8 = ApzcOf(layers[4]);
|
|
|
|
TestAsyncPanZoomController* layer7 = ApzcOf(layers[7]);
|
|
|
|
TestAsyncPanZoomController* layer9 = ApzcOf(layers[9]);
|
2014-09-04 22:43:31 +04:00
|
|
|
EXPECT_EQ(nullptr, layers1_2->GetParent());
|
|
|
|
EXPECT_EQ(nullptr, layers4_6_8->GetParent());
|
|
|
|
EXPECT_EQ(layers4_6_8, layer7->GetParent());
|
|
|
|
EXPECT_EQ(nullptr, layer9->GetParent());
|
2015-01-08 17:40:01 +03:00
|
|
|
// Ensure the hit-testing tree looks like the layer tree
|
|
|
|
nsRefPtr<HitTestingTreeNode> root = manager->GetRootNode();
|
|
|
|
nsRefPtr<HitTestingTreeNode> node5 = root->GetLastChild();
|
|
|
|
nsRefPtr<HitTestingTreeNode> node4 = node5->GetPrevSibling();
|
|
|
|
nsRefPtr<HitTestingTreeNode> node2 = node4->GetPrevSibling();
|
|
|
|
nsRefPtr<HitTestingTreeNode> node1 = node2->GetPrevSibling();
|
|
|
|
nsRefPtr<HitTestingTreeNode> node3 = node2->GetLastChild();
|
|
|
|
nsRefPtr<HitTestingTreeNode> node9 = node5->GetLastChild();
|
|
|
|
nsRefPtr<HitTestingTreeNode> node8 = node9->GetPrevSibling();
|
|
|
|
nsRefPtr<HitTestingTreeNode> node6 = node8->GetPrevSibling();
|
|
|
|
nsRefPtr<HitTestingTreeNode> node7 = node6->GetLastChild();
|
|
|
|
EXPECT_EQ(nullptr, node1->GetPrevSibling());
|
|
|
|
EXPECT_EQ(nullptr, node3->GetPrevSibling());
|
|
|
|
EXPECT_EQ(nullptr, node6->GetPrevSibling());
|
|
|
|
EXPECT_EQ(nullptr, node7->GetPrevSibling());
|
|
|
|
EXPECT_EQ(nullptr, node1->GetLastChild());
|
|
|
|
EXPECT_EQ(nullptr, node3->GetLastChild());
|
|
|
|
EXPECT_EQ(nullptr, node4->GetLastChild());
|
|
|
|
EXPECT_EQ(nullptr, node7->GetLastChild());
|
|
|
|
EXPECT_EQ(nullptr, node8->GetLastChild());
|
|
|
|
EXPECT_EQ(nullptr, node9->GetLastChild());
|
2014-08-20 05:17:10 +04:00
|
|
|
|
|
|
|
nsRefPtr<AsyncPanZoomController> hit = GetTargetAPZC(ScreenPoint(25, 25));
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_EQ(ApzcOf(layers[1]), hit.get());
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(275, 375));
|
2014-09-04 22:43:31 +04:00
|
|
|
EXPECT_EQ(ApzcOf(layers[9]), hit.get());
|
2014-08-20 05:17:10 +04:00
|
|
|
hit = GetTargetAPZC(ScreenPoint(250, 100));
|
2014-09-04 21:55:05 +04:00
|
|
|
EXPECT_EQ(ApzcOf(layers[7]), hit.get());
|
2014-08-20 05:17:10 +04:00
|
|
|
}
|
|
|
|
|
2014-09-25 21:46:34 +04:00
|
|
|
TEST_F(APZHitTestingTester, TestRepaintFlushOnNewInputBlock) {
|
2015-03-02 19:50:38 +03:00
|
|
|
SCOPED_GFX_PREF(TouchActionEnabled, bool, false);
|
|
|
|
|
2014-09-25 21:46:34 +04:00
|
|
|
// The main purpose of this test is to verify that touch-start events (or anything
|
|
|
|
// that starts a new input block) don't ever get untransformed. This should always
|
|
|
|
// hold because the APZ code should flush repaints when we start a new input block
|
|
|
|
// and the transform to gecko space should be empty.
|
|
|
|
|
|
|
|
CreateSimpleScrollingLayer();
|
|
|
|
ScopedLayerTreeRegistration registration(0, root, mcc);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2014-10-24 21:29:35 +04:00
|
|
|
TestAsyncPanZoomController* apzcroot = ApzcOf(root);
|
2014-09-25 21:46:34 +04:00
|
|
|
|
|
|
|
// At this point, the following holds (all coordinates in screen pixels):
|
|
|
|
// layers[0] has content from (0,0)-(500,500), clipped by composition bounds (0,0)-(200,200)
|
|
|
|
|
|
|
|
MockFunction<void(std::string checkPointName)> check;
|
|
|
|
|
|
|
|
{
|
|
|
|
InSequence s;
|
|
|
|
|
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(check, Call("post-first-touch-start"));
|
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(check, Call("post-second-fling"));
|
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtLeast(1));
|
|
|
|
EXPECT_CALL(check, Call("post-second-touch-start"));
|
|
|
|
}
|
|
|
|
|
|
|
|
// This first pan will move the APZC by 50 pixels, and dispatch a paint request.
|
2015-06-01 21:36:12 +03:00
|
|
|
ApzcPanNoFling(apzcroot, mcc, 100, 50);
|
2014-09-25 21:46:34 +04:00
|
|
|
|
|
|
|
// Verify that a touch start doesn't get untransformed
|
|
|
|
ScreenIntPoint touchPoint(50, 50);
|
2015-06-01 21:36:12 +03:00
|
|
|
MultiTouchInput mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time());
|
2014-09-25 21:46:34 +04:00
|
|
|
mti.mTouches.AppendElement(SingleTouchData(0, touchPoint, ScreenSize(0, 0), 0, 0));
|
|
|
|
|
2014-10-24 21:29:30 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(mti, nullptr, nullptr));
|
2014-09-25 21:46:34 +04:00
|
|
|
EXPECT_EQ(touchPoint, mti.mTouches[0].mScreenPoint);
|
|
|
|
check.Call("post-first-touch-start");
|
|
|
|
|
|
|
|
// Send a touchend to clear state
|
|
|
|
mti.mType = MultiTouchInput::MULTITOUCH_END;
|
2014-10-24 21:29:30 +04:00
|
|
|
manager->ReceiveInputEvent(mti, nullptr, nullptr);
|
2014-09-25 21:46:34 +04:00
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->AdvanceByMillis(1000);
|
2014-09-25 21:46:34 +04:00
|
|
|
|
|
|
|
// Now do two pans. The first of these will dispatch a repaint request, as above.
|
|
|
|
// The second will get stuck in the paint throttler because the first one doesn't
|
|
|
|
// get marked as "completed", so this will result in a non-empty LD transform.
|
|
|
|
// (Note that any outstanding repaint requests from the first half of this test
|
|
|
|
// don't impact this half because we advance the time by 1 second, which will trigger
|
|
|
|
// the max-wait-exceeded codepath in the paint throttler).
|
2015-06-01 21:36:12 +03:00
|
|
|
ApzcPanNoFling(apzcroot, mcc, 100, 50);
|
2014-09-25 21:46:34 +04:00
|
|
|
check.Call("post-second-fling");
|
2015-06-01 21:36:12 +03:00
|
|
|
ApzcPanNoFling(apzcroot, mcc, 100, 50);
|
2014-09-25 21:46:34 +04:00
|
|
|
|
|
|
|
// Ensure that a touch start again doesn't get untransformed by flushing
|
|
|
|
// a repaint
|
|
|
|
mti.mType = MultiTouchInput::MULTITOUCH_START;
|
2014-10-24 21:29:30 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(mti, nullptr, nullptr));
|
2014-09-25 21:46:34 +04:00
|
|
|
EXPECT_EQ(touchPoint, mti.mTouches[0].mScreenPoint);
|
|
|
|
check.Call("post-second-touch-start");
|
|
|
|
|
|
|
|
mti.mType = MultiTouchInput::MULTITOUCH_END;
|
2014-10-24 21:29:30 +04:00
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(mti, nullptr, nullptr));
|
2014-09-25 21:46:34 +04:00
|
|
|
EXPECT_EQ(touchPoint, mti.mTouches[0].mScreenPoint);
|
|
|
|
}
|
|
|
|
|
2015-05-29 18:04:22 +03:00
|
|
|
TEST_F(APZHitTestingTester, TestRepaintFlushOnWheelEvents) {
|
|
|
|
// The purpose of this test is to ensure that wheel events trigger a repaint
|
|
|
|
// flush as per bug 1166871, and that the wheel event untransform is a no-op.
|
|
|
|
|
|
|
|
CreateSimpleScrollingLayer();
|
|
|
|
ScopedLayerTreeRegistration registration(0, root, mcc);
|
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
|
|
|
TestAsyncPanZoomController* apzcroot = ApzcOf(root);
|
|
|
|
|
|
|
|
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtLeast(3));
|
|
|
|
ScreenPoint origin(100, 50);
|
|
|
|
for (int i = 0; i < 3; i++) {
|
2015-06-01 21:36:12 +03:00
|
|
|
ScrollWheelInput swi(MillisecondsSinceStartup(mcc->Time()), mcc->Time(), 0,
|
2015-05-29 18:04:22 +03:00
|
|
|
ScrollWheelInput::SCROLLMODE_INSTANT, ScrollWheelInput::SCROLLDELTA_PIXEL,
|
|
|
|
origin, 0, 10);
|
|
|
|
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(swi, nullptr, nullptr));
|
|
|
|
EXPECT_EQ(origin, swi.mOrigin);
|
|
|
|
|
|
|
|
ViewTransform viewTransform;
|
|
|
|
ParentLayerPoint point;
|
2015-06-01 21:36:12 +03:00
|
|
|
apzcroot->SampleContentTransformForFrame(&viewTransform, point);
|
2015-05-29 18:04:22 +03:00
|
|
|
EXPECT_EQ(0, point.x);
|
|
|
|
EXPECT_EQ((i + 1) * 10, point.y);
|
|
|
|
EXPECT_EQ(0, viewTransform.mTranslation.x);
|
|
|
|
EXPECT_EQ((i + 1) * -10, viewTransform.mTranslation.y);
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->AdvanceByMillis(5);
|
2015-05-29 18:04:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-30 21:30:38 +03:00
|
|
|
TEST_F(APZHitTestingTester, Bug1148350) {
|
|
|
|
CreateBug1148350LayerTree();
|
|
|
|
ScopedLayerTreeRegistration registration(0, root, mcc);
|
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
|
|
|
|
|
|
|
MockFunction<void(std::string checkPointName)> check;
|
|
|
|
{
|
|
|
|
InSequence s;
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(100, 100), 0, ApzcOf(layers[1])->GetGuid())).Times(1);
|
|
|
|
EXPECT_CALL(check, Call("Tapped without transform"));
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(100, 100), 0, ApzcOf(layers[1])->GetGuid())).Times(1);
|
|
|
|
EXPECT_CALL(check, Call("Tapped with interleaved transform"));
|
|
|
|
}
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(manager, 100, 100, mcc, TimeDuration::FromMilliseconds(100));
|
2015-04-30 21:30:38 +03:00
|
|
|
mcc->RunThroughDelayedTasks();
|
|
|
|
check.Call("Tapped without transform");
|
|
|
|
|
|
|
|
uint64_t blockId;
|
2015-06-01 21:36:12 +03:00
|
|
|
TouchDown(manager, 100, 100, mcc->Time(), &blockId);
|
2015-04-30 21:30:38 +03:00
|
|
|
if (gfxPrefs::TouchActionEnabled()) {
|
|
|
|
SetDefaultAllowedTouchBehavior(manager, blockId);
|
|
|
|
}
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->AdvanceByMillis(100);
|
2015-04-30 21:30:38 +03:00
|
|
|
|
2015-05-07 12:08:01 +03:00
|
|
|
layers[0]->SetVisibleRegion(nsIntRegion(IntRect(0,50,200,150)));
|
2015-04-30 21:30:38 +03:00
|
|
|
layers[0]->SetBaseTransform(Matrix4x4::Translation(0, 50, 0));
|
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
TouchUp(manager, 100, 100, mcc->Time());
|
2015-04-30 21:30:38 +03:00
|
|
|
mcc->RunThroughDelayedTasks();
|
|
|
|
check.Call("Tapped with interleaved transform");
|
|
|
|
}
|
|
|
|
|
2014-08-20 03:57:22 +04:00
|
|
|
class APZOverscrollHandoffTester : public APZCTreeManagerTester {
|
|
|
|
protected:
|
2014-08-20 21:22:36 +04:00
|
|
|
UniquePtr<ScopedLayerTreeRegistration> registration;
|
|
|
|
TestAsyncPanZoomController* rootApzc;
|
|
|
|
|
2014-08-20 03:57:22 +04:00
|
|
|
void CreateOverscrollHandoffLayerTree1() {
|
2014-12-15 05:37:51 +03:00
|
|
|
const char* layerTreeSyntax = "c(t)";
|
2014-08-20 03:57:22 +04:00
|
|
|
nsIntRegion layerVisibleRegion[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0, 0, 100, 100)),
|
|
|
|
nsIntRegion(IntRect(0, 50, 100, 50))
|
2014-08-20 03:57:22 +04:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
|
|
|
|
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
|
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 100, 100));
|
2014-08-21 21:47:42 +04:00
|
|
|
SetScrollHandoff(layers[1], root);
|
2014-08-20 21:22:36 +04:00
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(0, root, mcc);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2014-09-04 21:55:05 +04:00
|
|
|
rootApzc = ApzcOf(root);
|
2014-08-20 03:57:22 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void CreateOverscrollHandoffLayerTree2() {
|
2014-12-15 05:37:51 +03:00
|
|
|
const char* layerTreeSyntax = "c(c(t))";
|
2014-08-20 03:57:22 +04:00
|
|
|
nsIntRegion layerVisibleRegion[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0, 0, 100, 100)),
|
|
|
|
nsIntRegion(IntRect(0, 0, 100, 100)),
|
|
|
|
nsIntRegion(IntRect(0, 50, 100, 50))
|
2014-08-20 03:57:22 +04:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
|
|
|
|
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
|
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 2, CSSRect(-100, -100, 200, 200));
|
|
|
|
SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 100, 100));
|
2014-08-21 21:47:42 +04:00
|
|
|
SetScrollHandoff(layers[1], root);
|
|
|
|
SetScrollHandoff(layers[2], layers[1]);
|
2014-08-20 21:22:36 +04:00
|
|
|
// No ScopedLayerTreeRegistration as that just needs to be done once per test
|
|
|
|
// and this is the second layer tree for a particular test.
|
|
|
|
MOZ_ASSERT(registration);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2014-09-04 21:55:05 +04:00
|
|
|
rootApzc = ApzcOf(root);
|
2014-08-20 03:57:22 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void CreateOverscrollHandoffLayerTree3() {
|
2014-12-15 05:37:51 +03:00
|
|
|
const char* layerTreeSyntax = "c(c(t)c(t))";
|
2014-08-20 03:57:22 +04:00
|
|
|
nsIntRegion layerVisibleRegion[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0, 0, 100, 100)), // root
|
|
|
|
nsIntRegion(IntRect(0, 0, 100, 50)), // scrolling parent 1
|
|
|
|
nsIntRegion(IntRect(0, 0, 100, 50)), // scrolling child 1
|
|
|
|
nsIntRegion(IntRect(0, 50, 100, 50)), // scrolling parent 2
|
|
|
|
nsIntRegion(IntRect(0, 50, 100, 50)) // scrolling child 2
|
2014-08-20 03:57:22 +04:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
|
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 100, 100));
|
|
|
|
SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 100, 100));
|
|
|
|
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 2, CSSRect(0, 50, 100, 100));
|
|
|
|
SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 3, CSSRect(0, 50, 100, 100));
|
2014-08-21 21:47:42 +04:00
|
|
|
SetScrollHandoff(layers[2], layers[1]);
|
|
|
|
SetScrollHandoff(layers[4], layers[3]);
|
2014-08-20 21:22:36 +04:00
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(0, root, mcc);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2014-08-20 21:22:36 +04:00
|
|
|
}
|
|
|
|
|
2015-06-04 02:38:50 +03:00
|
|
|
void CreateScrollgrabLayerTree(bool makeParentScrollable = true) {
|
2014-12-15 05:37:51 +03:00
|
|
|
const char* layerTreeSyntax = "c(t)";
|
2014-08-20 21:22:36 +04:00
|
|
|
nsIntRegion layerVisibleRegion[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0, 0, 100, 100)), // scroll-grabbing parent
|
|
|
|
nsIntRegion(IntRect(0, 20, 100, 80)) // child
|
2014-08-20 21:22:36 +04:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
|
2015-06-04 02:38:50 +03:00
|
|
|
float parentHeight = makeParentScrollable ? 120 : 100;
|
|
|
|
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 100, parentHeight));
|
2014-08-20 21:22:36 +04:00
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 100, 200));
|
2014-08-21 21:47:42 +04:00
|
|
|
SetScrollHandoff(layers[1], root);
|
2014-08-20 21:22:36 +04:00
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(0, root, mcc);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2014-09-04 21:55:05 +04:00
|
|
|
rootApzc = ApzcOf(root);
|
2014-08-20 21:22:36 +04:00
|
|
|
rootApzc->GetFrameMetrics().SetHasScrollgrab(true);
|
2014-08-20 03:57:22 +04:00
|
|
|
}
|
2015-06-04 02:38:50 +03:00
|
|
|
|
|
|
|
void TestFlingAcceleration() {
|
|
|
|
// Jack up the fling acceleration multiplier so we can easily determine
|
|
|
|
// whether acceleration occured.
|
|
|
|
const float kAcceleration = 100.0f;
|
|
|
|
SCOPED_GFX_PREF(APZFlingAccelBaseMultiplier, float, kAcceleration);
|
|
|
|
|
|
|
|
nsRefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
|
|
|
|
|
|
|
|
// Pan once, enough to fully scroll the scrollgrab parent and then scroll
|
|
|
|
// and fling the child.
|
|
|
|
Pan(manager, mcc, 70, 40);
|
|
|
|
|
|
|
|
// Give the fling animation a chance to start.
|
|
|
|
SampleAnimationsOnce();
|
|
|
|
|
|
|
|
float childVelocityAfterFling1 = childApzc->GetVelocityVector().y;
|
|
|
|
|
|
|
|
// Pan again.
|
|
|
|
Pan(manager, mcc, 70, 40);
|
|
|
|
|
|
|
|
// Give the fling animation a chance to start.
|
|
|
|
// This time it should be accelerated.
|
|
|
|
SampleAnimationsOnce();
|
|
|
|
|
|
|
|
float childVelocityAfterFling2 = childApzc->GetVelocityVector().y;
|
|
|
|
|
|
|
|
// We should have accelerated once.
|
|
|
|
// The division by 2 is to account for friction.
|
|
|
|
EXPECT_GT(childVelocityAfterFling2,
|
|
|
|
childVelocityAfterFling1 * kAcceleration / 2);
|
|
|
|
|
|
|
|
// We should not have accelerated twice.
|
|
|
|
// The division by 4 is to account for friction.
|
|
|
|
EXPECT_LE(childVelocityAfterFling2,
|
|
|
|
childVelocityAfterFling1 * kAcceleration * kAcceleration / 4);
|
|
|
|
}
|
2014-08-20 03:57:22 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Here we test that if the processing of a touch block is deferred while we
|
|
|
|
// wait for content to send a prevent-default message, overscroll is still
|
|
|
|
// handed off correctly when the block is processed.
|
|
|
|
TEST_F(APZOverscrollHandoffTester, DeferredInputEventProcessing) {
|
|
|
|
// Set up the APZC tree.
|
|
|
|
CreateOverscrollHandoffLayerTree1();
|
|
|
|
|
2014-09-04 21:55:05 +04:00
|
|
|
TestAsyncPanZoomController* childApzc = ApzcOf(layers[1]);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Enable touch-listeners so that we can separate the queueing of input
|
|
|
|
// events from them being processed.
|
2014-12-15 05:37:51 +03:00
|
|
|
childApzc->SetWaitForMainThread();
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Queue input events for a pan.
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockId = 0;
|
2015-06-01 21:36:12 +03:00
|
|
|
ApzcPanNoFling(childApzc, mcc, 90, 30, &blockId);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Allow the pan to be processed.
|
2014-12-09 13:35:12 +03:00
|
|
|
childApzc->ContentReceivedInputBlock(blockId, false);
|
2014-12-15 05:37:51 +03:00
|
|
|
childApzc->ConfirmTarget(blockId);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Make sure overscroll was handed off correctly.
|
|
|
|
EXPECT_EQ(50, childApzc->GetFrameMetrics().GetScrollOffset().y);
|
|
|
|
EXPECT_EQ(10, rootApzc->GetFrameMetrics().GetScrollOffset().y);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Here we test that if the layer structure changes in between two input
|
|
|
|
// blocks being queued, and the first block is only processed after the second
|
|
|
|
// one has been queued, overscroll handoff for the first block follows
|
|
|
|
// the original layer structure while overscroll handoff for the second block
|
|
|
|
// follows the new layer structure.
|
|
|
|
TEST_F(APZOverscrollHandoffTester, LayerStructureChangesWhileEventsArePending) {
|
|
|
|
// Set up an initial APZC tree.
|
|
|
|
CreateOverscrollHandoffLayerTree1();
|
|
|
|
|
2014-09-04 21:55:05 +04:00
|
|
|
TestAsyncPanZoomController* childApzc = ApzcOf(layers[1]);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Enable touch-listeners so that we can separate the queueing of input
|
|
|
|
// events from them being processed.
|
2014-12-15 05:37:51 +03:00
|
|
|
childApzc->SetWaitForMainThread();
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Queue input events for a pan.
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t blockId = 0;
|
2015-06-01 21:36:12 +03:00
|
|
|
ApzcPanNoFling(childApzc, mcc, 90, 30, &blockId);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Modify the APZC tree to insert a new APZC 'middle' into the handoff chain
|
|
|
|
// between the child and the root.
|
|
|
|
CreateOverscrollHandoffLayerTree2();
|
|
|
|
nsRefPtr<Layer> middle = layers[1];
|
2014-12-15 05:37:51 +03:00
|
|
|
childApzc->SetWaitForMainThread();
|
2014-09-04 21:55:05 +04:00
|
|
|
TestAsyncPanZoomController* middleApzc = ApzcOf(middle);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Queue input events for another pan.
|
2014-10-24 21:29:30 +04:00
|
|
|
uint64_t secondBlockId = 0;
|
2015-06-01 21:36:12 +03:00
|
|
|
ApzcPanNoFling(childApzc, mcc, 30, 90, &secondBlockId);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Allow the first pan to be processed.
|
2014-12-09 13:35:12 +03:00
|
|
|
childApzc->ContentReceivedInputBlock(blockId, false);
|
2014-12-15 05:37:51 +03:00
|
|
|
childApzc->ConfirmTarget(blockId);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Make sure things have scrolled according to the handoff chain in
|
|
|
|
// place at the time the touch-start of the first pan was queued.
|
|
|
|
EXPECT_EQ(50, childApzc->GetFrameMetrics().GetScrollOffset().y);
|
|
|
|
EXPECT_EQ(10, rootApzc->GetFrameMetrics().GetScrollOffset().y);
|
|
|
|
EXPECT_EQ(0, middleApzc->GetFrameMetrics().GetScrollOffset().y);
|
|
|
|
|
|
|
|
// Allow the second pan to be processed.
|
2014-12-09 13:35:12 +03:00
|
|
|
childApzc->ContentReceivedInputBlock(secondBlockId, false);
|
2014-12-15 05:37:51 +03:00
|
|
|
childApzc->ConfirmTarget(secondBlockId);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Make sure things have scrolled according to the handoff chain in
|
|
|
|
// place at the time the touch-start of the second pan was queued.
|
|
|
|
EXPECT_EQ(0, childApzc->GetFrameMetrics().GetScrollOffset().y);
|
|
|
|
EXPECT_EQ(10, rootApzc->GetFrameMetrics().GetScrollOffset().y);
|
|
|
|
EXPECT_EQ(-10, middleApzc->GetFrameMetrics().GetScrollOffset().y);
|
|
|
|
}
|
|
|
|
|
2014-10-04 04:35:16 +04:00
|
|
|
// Test that putting a second finger down on an APZC while a down-chain APZC
|
|
|
|
// is overscrolled doesn't result in being stuck in overscroll.
|
|
|
|
TEST_F(APZOverscrollHandoffTester, StuckInOverscroll_Bug1073250) {
|
|
|
|
// Enable overscrolling.
|
|
|
|
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
|
|
|
|
|
|
|
|
CreateOverscrollHandoffLayerTree1();
|
|
|
|
|
|
|
|
TestAsyncPanZoomController* child = ApzcOf(layers[1]);
|
|
|
|
|
|
|
|
// Pan, causing the parent APZC to overscroll.
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(manager, mcc, 10, 40, true /* keep finger down */);
|
2014-10-04 04:35:16 +04:00
|
|
|
EXPECT_FALSE(child->IsOverscrolled());
|
|
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
|
|
|
|
|
|
// Put a second finger down.
|
|
|
|
MultiTouchInput secondFingerDown(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
|
2014-10-31 22:31:35 +03:00
|
|
|
// Use the same touch identifier for the first touch (0) as Pan(). (A bit hacky.)
|
2014-10-04 04:35:16 +04:00
|
|
|
secondFingerDown.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, 40), ScreenSize(0, 0), 0, 0));
|
|
|
|
secondFingerDown.mTouches.AppendElement(SingleTouchData(1, ScreenIntPoint(30, 20), ScreenSize(0, 0), 0, 0));
|
2014-10-24 21:29:30 +04:00
|
|
|
manager->ReceiveInputEvent(secondFingerDown, nullptr, nullptr);
|
2014-10-04 04:35:16 +04:00
|
|
|
|
|
|
|
// Release the fingers.
|
|
|
|
MultiTouchInput fingersUp = secondFingerDown;
|
|
|
|
fingersUp.mType = MultiTouchInput::MULTITOUCH_END;
|
2014-10-24 21:29:30 +04:00
|
|
|
manager->ReceiveInputEvent(fingersUp, nullptr, nullptr);
|
2014-10-04 04:35:16 +04:00
|
|
|
|
|
|
|
// Allow any animations to run their course.
|
2015-06-01 21:36:12 +03:00
|
|
|
child->AdvanceAnimationsUntilEnd();
|
|
|
|
rootApzc->AdvanceAnimationsUntilEnd();
|
2014-10-04 04:35:16 +04:00
|
|
|
|
|
|
|
// Make sure nothing is overscrolled.
|
|
|
|
EXPECT_FALSE(child->IsOverscrolled());
|
|
|
|
EXPECT_FALSE(rootApzc->IsOverscrolled());
|
|
|
|
}
|
|
|
|
|
2015-05-12 05:25:34 +03:00
|
|
|
// Test that flinging in a direction where one component of the fling goes into
|
|
|
|
// overscroll but the other doesn't, results in just the one component being
|
|
|
|
// handed off to the parent, while the original APZC continues flinging in the
|
|
|
|
// other direction.
|
|
|
|
TEST_F(APZOverscrollHandoffTester, PartialFlingHandoff) {
|
|
|
|
CreateOverscrollHandoffLayerTree1();
|
|
|
|
|
|
|
|
// Fling up and to the left. The child APZC has room to scroll up, but not
|
|
|
|
// to the left, so the horizontal component of the fling should be handed
|
|
|
|
// off to the parent APZC.
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(manager, mcc, ScreenPoint(90, 90), ScreenPoint(55, 55));
|
2015-05-12 05:25:34 +03:00
|
|
|
|
|
|
|
nsRefPtr<TestAsyncPanZoomController> parent = ApzcOf(root);
|
|
|
|
nsRefPtr<TestAsyncPanZoomController> child = ApzcOf(layers[1]);
|
|
|
|
|
|
|
|
// Advance the child's fling animation once to give the partial handoff
|
|
|
|
// a chance to occur.
|
2015-06-01 21:36:12 +03:00
|
|
|
mcc->AdvanceByMillis(10);
|
|
|
|
child->AdvanceAnimations(mcc->Time());
|
2015-05-12 05:25:34 +03:00
|
|
|
|
|
|
|
// Assert that partial handoff has occurred.
|
|
|
|
child->AssertStateIsFling();
|
|
|
|
parent->AssertStateIsFling();
|
|
|
|
}
|
|
|
|
|
2014-08-20 03:57:22 +04:00
|
|
|
// Here we test that if two flings are happening simultaneously, overscroll
|
|
|
|
// is handed off correctly for each.
|
|
|
|
TEST_F(APZOverscrollHandoffTester, SimultaneousFlings) {
|
|
|
|
// Set up an initial APZC tree.
|
|
|
|
CreateOverscrollHandoffLayerTree3();
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
nsRefPtr<TestAsyncPanZoomController> parent1 = ApzcOf(layers[1]);
|
|
|
|
nsRefPtr<TestAsyncPanZoomController> child1 = ApzcOf(layers[2]);
|
|
|
|
nsRefPtr<TestAsyncPanZoomController> parent2 = ApzcOf(layers[3]);
|
|
|
|
nsRefPtr<TestAsyncPanZoomController> child2 = ApzcOf(layers[4]);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Pan on the lower child.
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(child2, mcc, 45, 5);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Pan on the upper child.
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(child1, mcc, 95, 55);
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Check that child1 and child2 are in a FLING state.
|
|
|
|
child1->AssertStateIsFling();
|
|
|
|
child2->AssertStateIsFling();
|
|
|
|
|
|
|
|
// Advance the animations on child1 and child2 until their end.
|
2015-06-01 21:36:12 +03:00
|
|
|
child1->AdvanceAnimationsUntilEnd();
|
|
|
|
child2->AdvanceAnimationsUntilEnd();
|
2014-08-20 03:57:22 +04:00
|
|
|
|
|
|
|
// Check that the flings have been handed off to the parents.
|
|
|
|
child1->AssertStateIsReset();
|
|
|
|
parent1->AssertStateIsFling();
|
|
|
|
child2->AssertStateIsReset();
|
|
|
|
parent2->AssertStateIsFling();
|
|
|
|
}
|
|
|
|
|
2014-08-20 21:22:36 +04:00
|
|
|
TEST_F(APZOverscrollHandoffTester, Scrollgrab) {
|
|
|
|
// Set up the layer tree
|
|
|
|
CreateScrollgrabLayerTree();
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
nsRefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
|
2014-08-20 21:22:36 +04:00
|
|
|
|
|
|
|
// Pan on the child, enough to fully scroll the scrollgrab parent (20 px)
|
|
|
|
// and leave some more (another 15 px) for the child.
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(childApzc, mcc, 80, 45);
|
2014-08-20 21:22:36 +04:00
|
|
|
|
|
|
|
// Check that the parent and child have scrolled as much as we expect.
|
|
|
|
EXPECT_EQ(20, rootApzc->GetFrameMetrics().GetScrollOffset().y);
|
|
|
|
EXPECT_EQ(15, childApzc->GetFrameMetrics().GetScrollOffset().y);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(APZOverscrollHandoffTester, ScrollgrabFling) {
|
|
|
|
// Set up the layer tree
|
|
|
|
CreateScrollgrabLayerTree();
|
|
|
|
|
2014-10-31 22:31:35 +03:00
|
|
|
nsRefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
|
2014-08-20 21:22:36 +04:00
|
|
|
|
|
|
|
// Pan on the child, not enough to fully scroll the scrollgrab parent.
|
2015-06-01 21:36:12 +03:00
|
|
|
Pan(childApzc, mcc, 80, 70);
|
2014-08-20 21:22:36 +04:00
|
|
|
|
|
|
|
// Check that it is the scrollgrab parent that's in a fling, not the child.
|
|
|
|
rootApzc->AssertStateIsFling();
|
|
|
|
childApzc->AssertStateIsReset();
|
|
|
|
}
|
|
|
|
|
2015-06-04 02:38:50 +03:00
|
|
|
TEST_F(APZOverscrollHandoffTester, ScrollgrabFlingAcceleration1) {
|
|
|
|
CreateScrollgrabLayerTree(true /* make parent scrollable */);
|
|
|
|
TestFlingAcceleration();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(APZOverscrollHandoffTester, ScrollgrabFlingAcceleration2) {
|
|
|
|
CreateScrollgrabLayerTree(false /* do not make parent scrollable */);
|
|
|
|
TestFlingAcceleration();
|
|
|
|
}
|
|
|
|
|
2014-11-14 15:40:15 +03:00
|
|
|
class APZEventRegionsTester : public APZCTreeManagerTester {
|
|
|
|
protected:
|
|
|
|
UniquePtr<ScopedLayerTreeRegistration> registration;
|
|
|
|
TestAsyncPanZoomController* rootApzc;
|
|
|
|
|
|
|
|
void CreateEventRegionsLayerTree1() {
|
|
|
|
const char* layerTreeSyntax = "c(tt)";
|
2015-01-08 17:40:01 +03:00
|
|
|
nsIntRegion layerVisibleRegions[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0, 0, 200, 200)), // root
|
|
|
|
nsIntRegion(IntRect(0, 0, 100, 200)), // left half
|
|
|
|
nsIntRegion(IntRect(0, 100, 200, 100)), // bottom half
|
2015-01-08 17:40:01 +03:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, nullptr, lm, layers);
|
2014-11-14 15:40:15 +03:00
|
|
|
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
|
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1);
|
|
|
|
SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 2);
|
|
|
|
SetScrollHandoff(layers[1], root);
|
|
|
|
SetScrollHandoff(layers[2], root);
|
|
|
|
|
|
|
|
// Set up the event regions over a 200x200 area. The root layer has the
|
|
|
|
// whole 200x200 as the hit region; layers[1] has the left half and
|
|
|
|
// layers[2] has the bottom half. The bottom-left 100x100 area is also
|
|
|
|
// in the d-t-c region for both layers[1] and layers[2] (but layers[2] is
|
|
|
|
// on top so it gets the events by default if the main thread doesn't
|
|
|
|
// respond).
|
2015-05-07 12:08:01 +03:00
|
|
|
EventRegions regions(nsIntRegion(IntRect(0, 0, 200, 200)));
|
2014-11-14 15:40:15 +03:00
|
|
|
root->SetEventRegions(regions);
|
2015-05-07 12:08:01 +03:00
|
|
|
regions.mDispatchToContentHitRegion = nsIntRegion(IntRect(0, 100, 100, 100));
|
|
|
|
regions.mHitRegion = nsIntRegion(IntRect(0, 0, 100, 200));
|
2014-11-14 15:40:15 +03:00
|
|
|
layers[1]->SetEventRegions(regions);
|
2015-05-07 12:08:01 +03:00
|
|
|
regions.mHitRegion = nsIntRegion(IntRect(0, 100, 200, 100));
|
2014-11-14 15:40:15 +03:00
|
|
|
layers[2]->SetEventRegions(regions);
|
|
|
|
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(0, root, mcc);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2014-11-14 15:40:15 +03:00
|
|
|
rootApzc = ApzcOf(root);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CreateEventRegionsLayerTree2() {
|
|
|
|
const char* layerTreeSyntax = "c(t)";
|
2015-01-08 17:40:01 +03:00
|
|
|
nsIntRegion layerVisibleRegions[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0, 0, 100, 500)),
|
|
|
|
nsIntRegion(IntRect(0, 150, 100, 100)),
|
2015-01-08 17:40:01 +03:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, nullptr, lm, layers);
|
2014-11-14 15:40:15 +03:00
|
|
|
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
|
|
|
|
|
|
|
|
// Set up the event regions so that the child thebes layer is positioned far
|
|
|
|
// away from the scrolling container layer.
|
2015-05-07 12:08:01 +03:00
|
|
|
EventRegions regions(nsIntRegion(IntRect(0, 0, 100, 100)));
|
2014-11-14 15:40:15 +03:00
|
|
|
root->SetEventRegions(regions);
|
2015-05-07 12:08:01 +03:00
|
|
|
regions.mHitRegion = nsIntRegion(IntRect(0, 150, 100, 100));
|
2014-11-14 15:40:15 +03:00
|
|
|
layers[1]->SetEventRegions(regions);
|
|
|
|
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(0, root, mcc);
|
2015-01-08 17:40:01 +03:00
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
2014-11-14 15:40:15 +03:00
|
|
|
rootApzc = ApzcOf(root);
|
|
|
|
}
|
2015-01-08 17:40:01 +03:00
|
|
|
|
|
|
|
void CreateObscuringLayerTree() {
|
|
|
|
const char* layerTreeSyntax = "c(c(t)t)";
|
|
|
|
// LayerID 0 1 2 3
|
|
|
|
// 0 is the root.
|
|
|
|
// 1 is a parent scrollable layer.
|
|
|
|
// 2 is a child scrollable layer.
|
|
|
|
// 3 is the Obscurer, who ruins everything.
|
|
|
|
nsIntRegion layerVisibleRegions[] = {
|
|
|
|
// x coordinates are uninteresting
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0, 0, 200, 200)), // [0, 200]
|
|
|
|
nsIntRegion(IntRect(0, 0, 200, 200)), // [0, 200]
|
|
|
|
nsIntRegion(IntRect(0, 100, 200, 50)), // [100, 150]
|
|
|
|
nsIntRegion(IntRect(0, 100, 200, 100)) // [100, 200]
|
2015-01-08 17:40:01 +03:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, nullptr, lm, layers);
|
|
|
|
|
|
|
|
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
|
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 200, 300));
|
|
|
|
SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 2, CSSRect(0, 0, 200, 100));
|
|
|
|
SetScrollHandoff(layers[2], layers[1]);
|
|
|
|
SetScrollHandoff(layers[1], root);
|
|
|
|
|
2015-05-07 12:08:01 +03:00
|
|
|
EventRegions regions(nsIntRegion(IntRect(0, 0, 200, 200)));
|
2015-01-08 17:40:01 +03:00
|
|
|
root->SetEventRegions(regions);
|
2015-05-07 12:08:01 +03:00
|
|
|
regions.mHitRegion = nsIntRegion(IntRect(0, 0, 200, 300));
|
2015-01-08 17:40:01 +03:00
|
|
|
layers[1]->SetEventRegions(regions);
|
2015-05-07 12:08:01 +03:00
|
|
|
regions.mHitRegion = nsIntRegion(IntRect(0, 100, 200, 100));
|
2015-01-08 17:40:01 +03:00
|
|
|
layers[2]->SetEventRegions(regions);
|
|
|
|
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(0, root, mcc);
|
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
|
|
|
rootApzc = ApzcOf(root);
|
|
|
|
}
|
2015-01-14 18:41:38 +03:00
|
|
|
|
2015-01-15 18:37:54 +03:00
|
|
|
void CreateBug1119497LayerTree() {
|
|
|
|
const char* layerTreeSyntax = "c(tt)";
|
|
|
|
// LayerID 0 12
|
2015-05-31 22:44:41 +03:00
|
|
|
// 0 is the root and has an APZC
|
|
|
|
// 1 is behind 2 and has an APZC
|
|
|
|
// 2 entirely covers 1 and should take all the input events, but has no APZC
|
|
|
|
// so hits to 2 should go to to the root APZC
|
2015-01-15 18:37:54 +03:00
|
|
|
nsIntRegion layerVisibleRegions[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0, 0, 100, 100)),
|
|
|
|
nsIntRegion(IntRect(0, 0, 100, 100)),
|
|
|
|
nsIntRegion(IntRect(0, 0, 100, 100)),
|
2015-01-15 18:37:54 +03:00
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, nullptr, lm, layers);
|
|
|
|
|
2015-05-31 22:44:41 +03:00
|
|
|
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
|
2015-01-15 18:37:54 +03:00
|
|
|
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1);
|
|
|
|
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(0, root, mcc);
|
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
|
|
|
}
|
|
|
|
|
2015-01-14 18:41:38 +03:00
|
|
|
void CreateBug1117712LayerTree() {
|
|
|
|
const char* layerTreeSyntax = "c(c(t)t)";
|
|
|
|
// LayerID 0 1 2 3
|
|
|
|
// 0 is the root
|
|
|
|
// 1 is a container layer whose sole purpose to make a non-empty ancestor
|
|
|
|
// transform for 2, so that 2's screen-to-apzc and apzc-to-gecko
|
|
|
|
// transforms are different from 3's.
|
|
|
|
// 2 is a small layer that is the actual target
|
|
|
|
// 3 is a big layer obscuring 2 with a dispatch-to-content region
|
|
|
|
nsIntRegion layerVisibleRegions[] = {
|
2015-05-07 12:08:01 +03:00
|
|
|
nsIntRegion(IntRect(0, 0, 100, 100)),
|
|
|
|
nsIntRegion(IntRect(0, 0, 0, 0)),
|
|
|
|
nsIntRegion(IntRect(0, 0, 10, 10)),
|
|
|
|
nsIntRegion(IntRect(0, 0, 100, 100)),
|
2015-01-14 18:41:38 +03:00
|
|
|
};
|
|
|
|
Matrix4x4 layerTransforms[] = {
|
|
|
|
Matrix4x4(),
|
|
|
|
Matrix4x4::Translation(50, 0, 0),
|
|
|
|
Matrix4x4(),
|
|
|
|
Matrix4x4(),
|
|
|
|
};
|
|
|
|
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, layerTransforms, lm, layers);
|
|
|
|
|
|
|
|
SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 10, 10));
|
|
|
|
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 2, CSSRect(0, 0, 100, 100));
|
|
|
|
|
2015-05-07 12:08:01 +03:00
|
|
|
EventRegions regions(nsIntRegion(IntRect(0, 0, 10, 10)));
|
2015-01-14 18:41:38 +03:00
|
|
|
layers[2]->SetEventRegions(regions);
|
2015-05-07 12:08:01 +03:00
|
|
|
regions.mHitRegion = nsIntRegion(IntRect(0, 0, 100, 100));
|
|
|
|
regions.mDispatchToContentHitRegion = nsIntRegion(IntRect(0, 0, 100, 100));
|
2015-01-14 18:41:38 +03:00
|
|
|
layers[3]->SetEventRegions(regions);
|
|
|
|
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(0, root, mcc);
|
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
|
|
|
}
|
2014-11-14 15:40:15 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
TEST_F(APZEventRegionsTester, HitRegionImmediateResponse) {
|
|
|
|
CreateEventRegionsLayerTree1();
|
|
|
|
|
|
|
|
TestAsyncPanZoomController* root = ApzcOf(layers[0]);
|
|
|
|
TestAsyncPanZoomController* left = ApzcOf(layers[1]);
|
|
|
|
TestAsyncPanZoomController* bottom = ApzcOf(layers[2]);
|
|
|
|
|
|
|
|
MockFunction<void(std::string checkPointName)> check;
|
|
|
|
{
|
|
|
|
InSequence s;
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(_, _, left->GetGuid())).Times(1);
|
|
|
|
EXPECT_CALL(check, Call("Tapped on left"));
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(_, _, bottom->GetGuid())).Times(1);
|
|
|
|
EXPECT_CALL(check, Call("Tapped on bottom"));
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(_, _, root->GetGuid())).Times(1);
|
|
|
|
EXPECT_CALL(check, Call("Tapped on root"));
|
|
|
|
EXPECT_CALL(check, Call("Tap pending on d-t-c region"));
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(_, _, bottom->GetGuid())).Times(1);
|
|
|
|
EXPECT_CALL(check, Call("Tapped on bottom again"));
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(_, _, left->GetGuid())).Times(1);
|
|
|
|
EXPECT_CALL(check, Call("Tapped on left this time"));
|
|
|
|
}
|
|
|
|
|
2015-05-15 19:45:27 +03:00
|
|
|
TimeDuration tapDuration = TimeDuration::FromMilliseconds(100);
|
|
|
|
|
2014-11-14 15:40:15 +03:00
|
|
|
// Tap in the exposed hit regions of each of the layers once and ensure
|
|
|
|
// the clicks are dispatched right away
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(manager, 10, 10, mcc, tapDuration);
|
2014-11-14 15:40:15 +03:00
|
|
|
mcc->RunThroughDelayedTasks(); // this runs the tap event
|
|
|
|
check.Call("Tapped on left");
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(manager, 110, 110, mcc, tapDuration);
|
2014-11-14 15:40:15 +03:00
|
|
|
mcc->RunThroughDelayedTasks(); // this runs the tap event
|
|
|
|
check.Call("Tapped on bottom");
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(manager, 110, 10, mcc, tapDuration);
|
2014-11-14 15:40:15 +03:00
|
|
|
mcc->RunThroughDelayedTasks(); // this runs the tap event
|
|
|
|
check.Call("Tapped on root");
|
|
|
|
|
|
|
|
// Now tap on the dispatch-to-content region where the layers overlap
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(manager, 10, 110, mcc, tapDuration);
|
2014-11-14 15:40:15 +03:00
|
|
|
mcc->RunThroughDelayedTasks(); // this runs the main-thread timeout
|
|
|
|
check.Call("Tap pending on d-t-c region");
|
|
|
|
mcc->RunThroughDelayedTasks(); // this runs the tap event
|
|
|
|
check.Call("Tapped on bottom again");
|
|
|
|
|
|
|
|
// Now let's do that again, but simulate a main-thread response
|
|
|
|
uint64_t inputBlockId = 0;
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(manager, 10, 110, mcc, tapDuration, nullptr, &inputBlockId);
|
2014-11-22 05:36:25 +03:00
|
|
|
nsTArray<ScrollableLayerGuid> targets;
|
|
|
|
targets.AppendElement(left->GetGuid());
|
|
|
|
manager->SetTargetAPZC(inputBlockId, targets);
|
2014-11-14 15:40:15 +03:00
|
|
|
while (mcc->RunThroughDelayedTasks()); // this runs the tap event
|
|
|
|
check.Call("Tapped on left this time");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(APZEventRegionsTester, HitRegionAccumulatesChildren) {
|
|
|
|
CreateEventRegionsLayerTree2();
|
|
|
|
|
|
|
|
// Tap in the area of the child layer that's not directly included in the
|
|
|
|
// parent layer's hit region. Verify that it comes out of the APZC's
|
|
|
|
// content controller, which indicates the input events got routed correctly
|
|
|
|
// to the APZC.
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(_, _, rootApzc->GetGuid())).Times(1);
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(manager, 10, 160, mcc, TimeDuration::FromMilliseconds(100));
|
2014-11-14 15:40:15 +03:00
|
|
|
}
|
2014-08-20 03:57:22 +04:00
|
|
|
|
2015-01-08 17:40:01 +03:00
|
|
|
TEST_F(APZEventRegionsTester, Obscuration) {
|
|
|
|
CreateObscuringLayerTree();
|
|
|
|
ScopedLayerTreeRegistration registration(0, root, mcc);
|
|
|
|
|
|
|
|
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
|
|
|
|
|
|
|
|
TestAsyncPanZoomController* parent = ApzcOf(layers[1]);
|
|
|
|
TestAsyncPanZoomController* child = ApzcOf(layers[2]);
|
|
|
|
|
2015-06-01 21:36:12 +03:00
|
|
|
ApzcPanNoFling(parent, mcc, 75, 25);
|
2015-01-08 17:40:01 +03:00
|
|
|
|
|
|
|
HitTestResult result;
|
|
|
|
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(50, 75), &result);
|
|
|
|
EXPECT_EQ(child, hit.get());
|
2015-01-15 18:37:54 +03:00
|
|
|
EXPECT_EQ(HitTestResult::HitLayer, result);
|
2015-01-10 18:55:47 +03:00
|
|
|
}
|
|
|
|
|
2015-01-15 18:37:54 +03:00
|
|
|
TEST_F(APZEventRegionsTester, Bug1119497) {
|
|
|
|
CreateBug1119497LayerTree();
|
|
|
|
|
|
|
|
HitTestResult result;
|
|
|
|
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(50, 50), &result);
|
2015-01-15 18:37:54 +03:00
|
|
|
// We should hit layers[2], so |result| will be HitLayer but there's no
|
2015-05-31 22:44:41 +03:00
|
|
|
// actual APZC on layers[2], so it will be the APZC of the root layer.
|
|
|
|
EXPECT_EQ(ApzcOf(layers[0]), hit.get());
|
2015-01-15 18:37:54 +03:00
|
|
|
EXPECT_EQ(HitTestResult::HitLayer, result);
|
2015-01-15 18:37:54 +03:00
|
|
|
}
|
|
|
|
|
2015-01-14 18:41:38 +03:00
|
|
|
TEST_F(APZEventRegionsTester, Bug1117712) {
|
|
|
|
CreateBug1117712LayerTree();
|
|
|
|
|
|
|
|
TestAsyncPanZoomController* apzc2 = ApzcOf(layers[2]);
|
|
|
|
|
|
|
|
// These touch events should hit the dispatch-to-content region of layers[3]
|
|
|
|
// and so get queued with that APZC as the tentative target.
|
|
|
|
uint64_t inputBlockId = 0;
|
2015-06-01 21:36:12 +03:00
|
|
|
Tap(manager, 55, 5, mcc, TimeDuration::FromMilliseconds(100), nullptr, &inputBlockId);
|
2015-01-14 18:41:38 +03:00
|
|
|
// But now we tell the APZ that really it hit layers[2], and expect the tap
|
|
|
|
// to be delivered at the correct coordinates.
|
|
|
|
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(55, 5), 0, apzc2->GetGuid())).Times(1);
|
|
|
|
|
|
|
|
nsTArray<ScrollableLayerGuid> targets;
|
|
|
|
targets.AppendElement(apzc2->GetGuid());
|
|
|
|
manager->SetTargetAPZC(inputBlockId, targets);
|
|
|
|
}
|
|
|
|
|
2014-07-31 17:04:34 +04:00
|
|
|
class TaskRunMetrics {
|
|
|
|
public:
|
|
|
|
TaskRunMetrics()
|
|
|
|
: mRunCount(0)
|
|
|
|
, mCancelCount(0)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void IncrementRunCount() {
|
|
|
|
mRunCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IncrementCancelCount() {
|
|
|
|
mCancelCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetAndClearRunCount() {
|
|
|
|
int runCount = mRunCount;
|
|
|
|
mRunCount = 0;
|
|
|
|
return runCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetAndClearCancelCount() {
|
|
|
|
int cancelCount = mCancelCount;
|
|
|
|
mCancelCount = 0;
|
|
|
|
return cancelCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
int mRunCount;
|
|
|
|
int mCancelCount;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MockTask : public CancelableTask {
|
|
|
|
public:
|
2014-09-01 07:31:20 +04:00
|
|
|
explicit MockTask(TaskRunMetrics& aMetrics)
|
2014-07-31 17:04:34 +04:00
|
|
|
: mMetrics(aMetrics)
|
|
|
|
{}
|
|
|
|
|
|
|
|
virtual void Run() {
|
|
|
|
mMetrics.IncrementRunCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void Cancel() {
|
|
|
|
mMetrics.IncrementCancelCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2014-07-31 17:23:34 +04:00
|
|
|
TaskRunMetrics& mMetrics;
|
2014-07-31 17:04:34 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
class APZTaskThrottlerTester : public ::testing::Test {
|
|
|
|
public:
|
|
|
|
APZTaskThrottlerTester()
|
|
|
|
{
|
|
|
|
now = TimeStamp::Now();
|
|
|
|
throttler = MakeUnique<TaskThrottler>(now, TimeDuration::FromMilliseconds(100));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
TimeStamp Advance(int aMillis = 5)
|
|
|
|
{
|
|
|
|
now = now + TimeDuration::FromMilliseconds(aMillis);
|
|
|
|
return now;
|
|
|
|
}
|
|
|
|
|
|
|
|
UniquePtr<CancelableTask> NewTask()
|
|
|
|
{
|
2014-07-31 17:23:34 +04:00
|
|
|
return MakeUnique<MockTask>(metrics);
|
2014-07-31 17:04:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
TimeStamp now;
|
|
|
|
UniquePtr<TaskThrottler> throttler;
|
|
|
|
TaskRunMetrics metrics;
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_F(APZTaskThrottlerTester, BasicTest) {
|
|
|
|
// Check that posting the first task runs right away
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 1
|
|
|
|
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
|
|
|
|
|
|
|
// Check that posting the second task doesn't run until the first one is done
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 2
|
|
|
|
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
|
|
|
throttler->TaskComplete(Advance()); // for task 1
|
|
|
|
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
|
|
|
EXPECT_EQ(0, metrics.GetAndClearCancelCount());
|
|
|
|
|
|
|
|
// Check that tasks are coalesced: dispatch 5 tasks
|
|
|
|
// while there is still one outstanding, and ensure
|
|
|
|
// that only one of the 5 runs
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 3
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 4
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 5
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 6
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 7
|
|
|
|
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
|
|
|
EXPECT_EQ(4, metrics.GetAndClearCancelCount());
|
|
|
|
|
|
|
|
throttler->TaskComplete(Advance()); // for task 2
|
|
|
|
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
|
|
|
throttler->TaskComplete(Advance()); // for task 7 (tasks 3..6 were cancelled)
|
|
|
|
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
|
|
|
EXPECT_EQ(0, metrics.GetAndClearCancelCount());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(APZTaskThrottlerTester, TimeoutTest) {
|
|
|
|
// Check that posting the first task runs right away
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 1
|
|
|
|
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
|
|
|
|
|
|
|
// Because we let 100ms pass, the second task should
|
|
|
|
// run immediately even though the first one isn't
|
|
|
|
// done yet
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance(100)); // task 2; task 1 is assumed lost
|
|
|
|
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
|
|
|
throttler->TaskComplete(Advance()); // for task 1, but TaskThrottler thinks it's for task 2
|
|
|
|
throttler->TaskComplete(Advance()); // for task 2, TaskThrottler ignores it
|
|
|
|
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
|
|
|
EXPECT_EQ(0, metrics.GetAndClearCancelCount());
|
|
|
|
|
|
|
|
// This time queue up a few tasks before the timeout expires
|
|
|
|
// and ensure cancellation still works as expected
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 3
|
|
|
|
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 4
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 5
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance()); // task 6
|
|
|
|
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
|
|
|
throttler->PostTask(FROM_HERE, NewTask(), Advance(100)); // task 7; task 3 is assumed lost
|
|
|
|
EXPECT_EQ(1, metrics.GetAndClearRunCount());
|
|
|
|
EXPECT_EQ(3, metrics.GetAndClearCancelCount()); // tasks 4..6 should have been cancelled
|
|
|
|
throttler->TaskComplete(Advance()); // for task 7
|
|
|
|
EXPECT_EQ(0, metrics.GetAndClearRunCount());
|
|
|
|
EXPECT_EQ(0, metrics.GetAndClearCancelCount());
|
|
|
|
}
|