Source code
Revision control
Copy as Markdown
Other Tools
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
#include "APZCTreeManagerTester.h"
#include "APZTestCommon.h"
#include "InputUtils.h"
#include "mozilla/layers/LayersTypes.h"
class APZEventRegionsTester : public APZCTreeManagerTester {
protected:
UniquePtr<ScopedLayerTreeRegistration> registration;
TestAsyncPanZoomController* rootApzc;
void CreateEventRegionsLayerTree1() {
const char* treeShape = "x(xx)";
LayerIntRect layerVisibleRects[] = {
LayerIntRect(0, 0, 200, 200), // root
LayerIntRect(0, 0, 100, 200), // left half
LayerIntRect(0, 100, 200, 100), // bottom half
};
CreateScrollData(treeShape, layerVisibleRects);
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID);
SetScrollableFrameMetrics(layers[1],
ScrollableLayerGuid::START_SCROLL_ID + 1);
SetScrollableFrameMetrics(layers[2],
ScrollableLayerGuid::START_SCROLL_ID + 2);
SetScrollHandoff(layers[1], root);
SetScrollHandoff(layers[2], root);
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
UpdateHitTestingTree();
rootApzc = ApzcOf(root);
}
void CreateEventRegionsLayerTree2() {
const char* treeShape = "x(x)";
LayerIntRect layerVisibleRects[] = {
LayerIntRect(0, 0, 100, 500),
LayerIntRect(0, 150, 100, 100),
};
CreateScrollData(treeShape, layerVisibleRects);
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID);
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
UpdateHitTestingTree();
rootApzc = ApzcOf(root);
}
void CreateBug1117712LayerTree() {
const char* treeShape = "x(x(x)x)";
// 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
LayerIntRect layerVisibleRects[] = {
LayerIntRect(0, 0, 100, 100),
LayerIntRect(0, 0, 0, 0),
LayerIntRect(0, 0, 10, 10),
LayerIntRect(0, 0, 100, 100),
};
Matrix4x4 layerTransforms[] = {
Matrix4x4(),
Matrix4x4::Translation(50, 0, 0),
Matrix4x4(),
Matrix4x4(),
};
CreateScrollData(treeShape, layerVisibleRects, layerTransforms);
SetScrollableFrameMetrics(layers[2], ScrollableLayerGuid::START_SCROLL_ID,
CSSRect(0, 0, 10, 10));
SetScrollableFrameMetrics(layers[3],
ScrollableLayerGuid::START_SCROLL_ID + 1,
CSSRect(0, 0, 100, 100));
SetScrollHandoff(layers[3], layers[2]);
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
UpdateHitTestingTree();
}
};
class APZEventRegionsTesterMock : public APZEventRegionsTester {
public:
APZEventRegionsTesterMock() { CreateMockHitTester(); }
};
TEST_F(APZEventRegionsTesterMock, 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,
HandleTap(TapType::eSingleTap, _, _, left->GetGuid(), _, _))
.Times(1);
EXPECT_CALL(check, Call("Tapped on left"));
EXPECT_CALL(*mcc,
HandleTap(TapType::eSingleTap, _, _, bottom->GetGuid(), _, _))
.Times(1);
EXPECT_CALL(check, Call("Tapped on bottom"));
EXPECT_CALL(*mcc,
HandleTap(TapType::eSingleTap, _, _, 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,
HandleTap(TapType::eSingleTap, _, _, bottom->GetGuid(), _, _))
.Times(1);
EXPECT_CALL(check, Call("Tapped on bottom again"));
EXPECT_CALL(*mcc,
HandleTap(TapType::eSingleTap, _, _, left->GetGuid(), _, _))
.Times(1);
EXPECT_CALL(check, Call("Tapped on left this time"));
}
TimeDuration tapDuration = TimeDuration::FromMilliseconds(100);
// Tap in the exposed hit regions of each of the layers once and ensure
// the clicks are dispatched right away
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
Tap(manager, ScreenIntPoint(10, 10), tapDuration);
mcc->RunThroughDelayedTasks(); // this runs the tap event
check.Call("Tapped on left");
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 2);
Tap(manager, ScreenIntPoint(110, 110), tapDuration);
mcc->RunThroughDelayedTasks(); // this runs the tap event
check.Call("Tapped on bottom");
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
Tap(manager, ScreenIntPoint(110, 10), tapDuration);
mcc->RunThroughDelayedTasks(); // this runs the tap event
check.Call("Tapped on root");
// Now tap on the dispatch-to-content region where the layers overlap
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 2,
{CompositorHitTestFlags::eVisibleToHitTest,
CompositorHitTestFlags::eIrregularArea});
Tap(manager, ScreenIntPoint(10, 110), tapDuration);
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
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 2,
{CompositorHitTestFlags::eVisibleToHitTest,
CompositorHitTestFlags::eIrregularArea});
APZEventResult result =
Tap(manager, ScreenIntPoint(10, 110), tapDuration, nullptr);
nsTArray<ScrollableLayerGuid> targets;
targets.AppendElement(left->GetGuid());
manager->SetTargetAPZC(result.mInputBlockId, targets);
while (mcc->RunThroughDelayedTasks()); // this runs the tap event
check.Call("Tapped on left this time");
}
TEST_F(APZEventRegionsTesterMock, 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,
HandleTap(TapType::eSingleTap, _, _, rootApzc->GetGuid(), _, _))
.Times(1);
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
Tap(manager, ScreenIntPoint(10, 160), TimeDuration::FromMilliseconds(100));
}
TEST_F(APZEventRegionsTesterMock, 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.
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1,
{CompositorHitTestFlags::eVisibleToHitTest,
CompositorHitTestFlags::eIrregularArea});
APZEventResult result = Tap(manager, ScreenIntPoint(55, 5),
TimeDuration::FromMilliseconds(100), nullptr);
// 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, HandleTap(TapType::eSingleTap, LayoutDevicePoint(55, 5), 0,
apzc2->GetGuid(), _, _))
.Times(1);
nsTArray<ScrollableLayerGuid> targets;
targets.AppendElement(apzc2->GetGuid());
manager->SetTargetAPZC(result.mInputBlockId, targets);
}