489 lines
22 KiB
C++
489 lines
22 KiB
C++
/* -*- 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
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "APZCTreeManagerTester.h"
|
|
#include "APZTestCommon.h"
|
|
#include "InputUtils.h"
|
|
#include "Units.h"
|
|
#include "mozilla/BasicEvents.h"
|
|
#include "mozilla/StaticPrefs_apz.h"
|
|
|
|
class APZCTreeManagerGenericTester : public APZCTreeManagerTester {
|
|
protected:
|
|
void CreateSimpleScrollingLayer() {
|
|
const char* treeShape = "x";
|
|
LayerIntRect layerVisibleRect[] = {
|
|
LayerIntRect(0, 0, 200, 200),
|
|
};
|
|
CreateScrollData(treeShape, layerVisibleRect);
|
|
SetScrollableFrameMetrics(layers[0], ScrollableLayerGuid::START_SCROLL_ID,
|
|
CSSRect(0, 0, 500, 500));
|
|
}
|
|
|
|
void CreateSimpleMultiLayerTree() {
|
|
const char* treeShape = "x(xx)";
|
|
// LayerID 0 12
|
|
LayerIntRect layerVisibleRect[] = {
|
|
LayerIntRect(0, 0, 100, 100),
|
|
LayerIntRect(0, 0, 100, 50),
|
|
LayerIntRect(0, 50, 100, 50),
|
|
};
|
|
CreateScrollData(treeShape, layerVisibleRect);
|
|
}
|
|
|
|
void CreatePotentiallyLeakingTree() {
|
|
const char* treeShape = "x(x(x(x))x(x(x)))";
|
|
// LayerID 0 1 2 3 4 5 6
|
|
CreateScrollData(treeShape);
|
|
SetScrollableFrameMetrics(layers[0], ScrollableLayerGuid::START_SCROLL_ID);
|
|
SetScrollableFrameMetrics(layers[2],
|
|
ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
SetScrollableFrameMetrics(layers[5],
|
|
ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
SetScrollableFrameMetrics(layers[3],
|
|
ScrollableLayerGuid::START_SCROLL_ID + 2);
|
|
SetScrollableFrameMetrics(layers[6],
|
|
ScrollableLayerGuid::START_SCROLL_ID + 3);
|
|
}
|
|
|
|
void CreateTwoLayerTree(int32_t aRootContentLayerIndex) {
|
|
const char* treeShape = "x(x)";
|
|
// LayerID 0 1
|
|
LayerIntRect layerVisibleRect[] = {
|
|
LayerIntRect(0, 0, 100, 100),
|
|
LayerIntRect(0, 0, 100, 100),
|
|
};
|
|
CreateScrollData(treeShape, layerVisibleRect);
|
|
SetScrollableFrameMetrics(layers[0], ScrollableLayerGuid::START_SCROLL_ID);
|
|
SetScrollableFrameMetrics(layers[1],
|
|
ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
SetScrollHandoff(layers[1], layers[0]);
|
|
|
|
// Make layers[aRootContentLayerIndex] the root content
|
|
ModifyFrameMetrics(layers[aRootContentLayerIndex],
|
|
[](ScrollMetadata& sm, FrameMetrics& fm) {
|
|
fm.SetIsRootContent(true);
|
|
});
|
|
}
|
|
};
|
|
|
|
TEST_F(APZCTreeManagerGenericTester, ScrollablePaintedLayers) {
|
|
CreateSimpleMultiLayerTree();
|
|
ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
|
|
|
|
// both layers have the same scrollId
|
|
SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID);
|
|
SetScrollableFrameMetrics(layers[2], ScrollableLayerGuid::START_SCROLL_ID);
|
|
UpdateHitTestingTree();
|
|
|
|
TestAsyncPanZoomController* nullAPZC = nullptr;
|
|
// so they should have the same APZC
|
|
EXPECT_FALSE(HasScrollableFrameMetrics(layers[0]));
|
|
EXPECT_NE(nullAPZC, ApzcOf(layers[1]));
|
|
EXPECT_NE(nullAPZC, ApzcOf(layers[2]));
|
|
EXPECT_EQ(ApzcOf(layers[1]), ApzcOf(layers[2]));
|
|
}
|
|
|
|
TEST_F(APZCTreeManagerGenericTester, Bug1068268) {
|
|
CreatePotentiallyLeakingTree();
|
|
ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
|
|
|
|
UpdateHitTestingTree();
|
|
RefPtr<HitTestingTreeNode> root = manager->GetRootNode();
|
|
RefPtr<HitTestingTreeNode> node2 = root->GetFirstChild()->GetFirstChild();
|
|
RefPtr<HitTestingTreeNode> node5 = root->GetLastChild()->GetLastChild();
|
|
|
|
EXPECT_EQ(ApzcOf(layers[2]), node5->GetApzc());
|
|
EXPECT_EQ(ApzcOf(layers[2]), node2->GetApzc());
|
|
EXPECT_EQ(ApzcOf(layers[0]), ApzcOf(layers[2])->GetParent());
|
|
EXPECT_EQ(ApzcOf(layers[2]), ApzcOf(layers[5]));
|
|
|
|
EXPECT_EQ(node2->GetFirstChild(), node2->GetLastChild());
|
|
EXPECT_EQ(ApzcOf(layers[3]), node2->GetLastChild()->GetApzc());
|
|
EXPECT_EQ(node5->GetFirstChild(), node5->GetLastChild());
|
|
EXPECT_EQ(ApzcOf(layers[6]), node5->GetLastChild()->GetApzc());
|
|
EXPECT_EQ(ApzcOf(layers[2]), ApzcOf(layers[3])->GetParent());
|
|
EXPECT_EQ(ApzcOf(layers[5]), ApzcOf(layers[6])->GetParent());
|
|
}
|
|
|
|
class APZCTreeManagerGenericTesterMock : public APZCTreeManagerGenericTester {
|
|
public:
|
|
APZCTreeManagerGenericTesterMock() { CreateMockHitTester(); }
|
|
};
|
|
|
|
TEST_F(APZCTreeManagerGenericTesterMock, Bug1194876) {
|
|
// Create a layer tree with parent and child scrollable layers, with the
|
|
// child being the root content.
|
|
CreateTwoLayerTree(1);
|
|
ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
|
|
uint64_t blockId;
|
|
nsTArray<ScrollableLayerGuid> targets;
|
|
|
|
// First touch goes down, APZCTM will hit layers[1] because it is on top of
|
|
// layers[0], but we tell it the real target APZC is layers[0].
|
|
MultiTouchInput mti;
|
|
mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time());
|
|
mti.mTouches.AppendElement(
|
|
SingleTouchData(0, ScreenIntPoint(25, 50), ScreenSize(0, 0), 0, 0));
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
{CompositorHitTestFlags::eVisibleToHitTest,
|
|
CompositorHitTestFlags::eIrregularArea});
|
|
blockId = manager->ReceiveInputEvent(mti).mInputBlockId;
|
|
manager->ContentReceivedInputBlock(blockId, false);
|
|
targets.AppendElement(ApzcOf(layers[0])->GetGuid());
|
|
manager->SetTargetAPZC(blockId, targets);
|
|
|
|
// Around here, the above touch will get processed by ApzcOf(layers[0])
|
|
|
|
// Second touch goes down (first touch remains down), APZCTM will again hit
|
|
// layers[1]. Again we tell it both touches landed on layers[0], but because
|
|
// layers[1] is the RCD layer, it will end up being the multitouch target.
|
|
mti.mTouches.AppendElement(
|
|
SingleTouchData(1, ScreenIntPoint(75, 50), ScreenSize(0, 0), 0, 0));
|
|
// Each touch will get hit-tested, so queue two hit-test results.
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
{CompositorHitTestFlags::eVisibleToHitTest,
|
|
CompositorHitTestFlags::eIrregularArea});
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
{CompositorHitTestFlags::eVisibleToHitTest,
|
|
CompositorHitTestFlags::eIrregularArea});
|
|
blockId = manager->ReceiveInputEvent(mti).mInputBlockId;
|
|
manager->ContentReceivedInputBlock(blockId, false);
|
|
targets.AppendElement(ApzcOf(layers[0])->GetGuid());
|
|
manager->SetTargetAPZC(blockId, targets);
|
|
|
|
// Around here, the above multi-touch will get processed by ApzcOf(layers[1]).
|
|
// We want to ensure that ApzcOf(layers[0]) has had its state cleared, because
|
|
// otherwise it will do things like dispatch spurious long-tap events.
|
|
|
|
EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, _, _, _, _, _)).Times(0);
|
|
}
|
|
|
|
TEST_F(APZCTreeManagerGenericTesterMock, TargetChangesMidGesture_Bug1570559) {
|
|
// Create a layer tree with parent and child scrollable layers, with the
|
|
// parent being the root content.
|
|
CreateTwoLayerTree(0);
|
|
ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
|
|
uint64_t blockId;
|
|
nsTArray<ScrollableLayerGuid> targets;
|
|
|
|
// First touch goes down. APZCTM hits the child layer because it is on top
|
|
// (and we confirm this target), but do not prevent-default the event, causing
|
|
// the child APZC's gesture detector to start a long-tap timeout task.
|
|
MultiTouchInput mti =
|
|
CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time());
|
|
mti.mTouches.AppendElement(
|
|
SingleTouchData(0, ScreenIntPoint(25, 50), ScreenSize(0, 0), 0, 0));
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
{CompositorHitTestFlags::eVisibleToHitTest,
|
|
CompositorHitTestFlags::eIrregularArea});
|
|
blockId = manager->ReceiveInputEvent(mti).mInputBlockId;
|
|
manager->ContentReceivedInputBlock(blockId, /* default prevented = */ false);
|
|
targets.AppendElement(ApzcOf(layers[1])->GetGuid());
|
|
manager->SetTargetAPZC(blockId, targets);
|
|
|
|
// Second touch goes down (first touch remains down). APZCTM again hits the
|
|
// child and we confirm this, but multi-touch events are routed to the root
|
|
// content APZC which is the parent. This event is prevent-defaulted, so we
|
|
// clear the parent's gesture state. The bug is that we fail to clear the
|
|
// child's gesture state.
|
|
mti.mTouches.AppendElement(
|
|
SingleTouchData(1, ScreenIntPoint(75, 50), ScreenSize(0, 0), 0, 0));
|
|
// Each touch will get hit-tested, so queue two hit-test results.
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
{CompositorHitTestFlags::eVisibleToHitTest,
|
|
CompositorHitTestFlags::eIrregularArea});
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
{CompositorHitTestFlags::eVisibleToHitTest,
|
|
CompositorHitTestFlags::eIrregularArea});
|
|
blockId = manager->ReceiveInputEvent(mti).mInputBlockId;
|
|
manager->ContentReceivedInputBlock(blockId, /* default prevented = */ true);
|
|
targets.AppendElement(ApzcOf(layers[1])->GetGuid());
|
|
manager->SetTargetAPZC(blockId, targets);
|
|
|
|
// If we've failed to clear the child's gesture state, then the long tap
|
|
// timeout task will fire in TearDown() and a long-tap will be dispatched.
|
|
EXPECT_CALL(*mcc, HandleTap(TapType::eLongTap, _, _, _, _, _)).Times(0);
|
|
}
|
|
|
|
TEST_F(APZCTreeManagerGenericTesterMock, Bug1198900) {
|
|
// This is just a test that cancels a wheel event to make sure it doesn't
|
|
// crash.
|
|
CreateSimpleScrollingLayer();
|
|
ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
|
|
ScreenPoint origin(100, 50);
|
|
ScrollWheelInput swi(mcc->Time(), 0, ScrollWheelInput::SCROLLMODE_INSTANT,
|
|
ScrollWheelInput::SCROLLDELTA_PIXEL, origin, 0, 10,
|
|
false, WheelDeltaAdjustmentStrategy::eNone);
|
|
uint64_t blockId;
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID,
|
|
{CompositorHitTestFlags::eVisibleToHitTest,
|
|
CompositorHitTestFlags::eIrregularArea});
|
|
blockId = manager->ReceiveInputEvent(swi).mInputBlockId;
|
|
manager->ContentReceivedInputBlock(blockId, /* preventDefault= */ true);
|
|
}
|
|
|
|
// The next two tests check that APZ clamps the scroll offset it composites even
|
|
// if the main thread fails to do so. (The main thread will always clamp its
|
|
// scroll offset internally, but it may not send APZ the clamped version for
|
|
// scroll offset synchronization reasons.)
|
|
TEST_F(APZCTreeManagerTester, Bug1551582) {
|
|
// The simple layer tree has a scrollable rect of 500x500 and a composition
|
|
// bounds of 200x200, leading to a scroll range of (0,0,300,300).
|
|
CreateSimpleScrollingLayer();
|
|
ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
|
|
// Simulate the main thread scrolling to the end of the scroll range.
|
|
ModifyFrameMetrics(root, [](ScrollMetadata& aSm, FrameMetrics& aMetrics) {
|
|
aMetrics.SetLayoutScrollOffset(CSSPoint(300, 300));
|
|
nsTArray<ScrollPositionUpdate> scrollUpdates;
|
|
scrollUpdates.AppendElement(ScrollPositionUpdate::NewScroll(
|
|
ScrollOrigin::Other, CSSPoint::ToAppUnits(CSSPoint(300, 300))));
|
|
aSm.SetScrollUpdates(scrollUpdates);
|
|
aMetrics.SetScrollGeneration(scrollUpdates.LastElement().GetGeneration());
|
|
});
|
|
UpdateHitTestingTree();
|
|
|
|
// Sanity check.
|
|
RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root);
|
|
CSSPoint compositedScrollOffset = apzc->GetCompositedScrollOffset();
|
|
EXPECT_EQ(CSSPoint(300, 300), compositedScrollOffset);
|
|
|
|
// Simulate the main thread shrinking the scrollable rect to 400x400 (and
|
|
// thereby the scroll range to (0,0,200,200) without sending a new scroll
|
|
// offset update for the clamped scroll position (200,200).
|
|
ModifyFrameMetrics(root, [](ScrollMetadata& aSm, FrameMetrics& aMetrics) {
|
|
aMetrics.SetScrollableRect(CSSRect(0, 0, 400, 400));
|
|
});
|
|
UpdateHitTestingTree();
|
|
|
|
// Check that APZ has clamped the scroll offset to (200,200) for us.
|
|
compositedScrollOffset = apzc->GetCompositedScrollOffset();
|
|
EXPECT_EQ(CSSPoint(200, 200), compositedScrollOffset);
|
|
}
|
|
TEST_F(APZCTreeManagerTester, Bug1557424) {
|
|
// The simple layer tree has a scrollable rect of 500x500 and a composition
|
|
// bounds of 200x200, leading to a scroll range of (0,0,300,300).
|
|
CreateSimpleScrollingLayer();
|
|
ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
|
|
// Simulate the main thread scrolling to the end of the scroll range.
|
|
ModifyFrameMetrics(root, [](ScrollMetadata& aSm, FrameMetrics& aMetrics) {
|
|
aMetrics.SetLayoutScrollOffset(CSSPoint(300, 300));
|
|
nsTArray<ScrollPositionUpdate> scrollUpdates;
|
|
scrollUpdates.AppendElement(ScrollPositionUpdate::NewScroll(
|
|
ScrollOrigin::Other, CSSPoint::ToAppUnits(CSSPoint(300, 300))));
|
|
aSm.SetScrollUpdates(scrollUpdates);
|
|
aMetrics.SetScrollGeneration(scrollUpdates.LastElement().GetGeneration());
|
|
});
|
|
UpdateHitTestingTree();
|
|
|
|
// Sanity check.
|
|
RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root);
|
|
CSSPoint compositedScrollOffset = apzc->GetCompositedScrollOffset();
|
|
EXPECT_EQ(CSSPoint(300, 300), compositedScrollOffset);
|
|
|
|
// Simulate the main thread expanding the composition bounds to 300x300 (and
|
|
// thereby shrinking the scroll range to (0,0,200,200) without sending a new
|
|
// scroll offset update for the clamped scroll position (200,200).
|
|
ModifyFrameMetrics(root, [](ScrollMetadata& aSm, FrameMetrics& aMetrics) {
|
|
aMetrics.SetCompositionBounds(ParentLayerRect(0, 0, 300, 300));
|
|
});
|
|
UpdateHitTestingTree();
|
|
|
|
// Check that APZ has clamped the scroll offset to (200,200) for us.
|
|
compositedScrollOffset = apzc->GetCompositedScrollOffset();
|
|
EXPECT_EQ(CSSPoint(200, 200), compositedScrollOffset);
|
|
}
|
|
|
|
TEST_F(APZCTreeManagerTester, Bug1805601) {
|
|
// The simple layer tree has a scrollable rect of 500x500 and a composition
|
|
// bounds of 200x200, leading to a scroll range of (0,0,300,300) at unit zoom.
|
|
CreateSimpleScrollingLayer();
|
|
ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
RefPtr<TestAsyncPanZoomController> apzc = ApzcOf(root);
|
|
FrameMetrics& compositorMetrics = apzc->GetFrameMetrics();
|
|
EXPECT_EQ(CSSRect(0, 0, 300, 300), compositorMetrics.CalculateScrollRange());
|
|
|
|
// Zoom the page in by 2x. This needs to be reflected in each of the pres
|
|
// shell resolution, cumulative resolution, and zoom. This makes the scroll
|
|
// range (0,0,400,400).
|
|
compositorMetrics.SetZoom(CSSToParentLayerScale(2.0));
|
|
EXPECT_EQ(CSSRect(0, 0, 400, 400), compositorMetrics.CalculateScrollRange());
|
|
|
|
// Scroll to an area inside the 2x scroll range but outside the original one.
|
|
compositorMetrics.ClampAndSetVisualScrollOffset(CSSPoint(350, 350));
|
|
EXPECT_EQ(CSSPoint(350, 350), compositorMetrics.GetVisualScrollOffset());
|
|
|
|
// Simulate a main-thread update where the zoom is reset to 1x but the visual
|
|
// scroll offset is unmodified.
|
|
ModifyFrameMetrics(root, [](ScrollMetadata& aSm, FrameMetrics& aMetrics) {
|
|
// Changes to |compositorMetrics| are not reflected in |aMetrics|, which
|
|
// is the "layer tree" copy, so we don't need to explicitly set the zoom to
|
|
// 1.0 (it still has that as the initial value), but we do need to set
|
|
// the visual scroll offset to the same value the APZ copy has.
|
|
aMetrics.SetVisualScrollOffset(CSSPoint(350, 350));
|
|
|
|
// Needed to get APZ to accept the 1.0 zoom in |aMetrics|, otherwise
|
|
// it will act as though its zoom is newer (e.g. an async zoom that hasn't
|
|
// been repainted yet) and ignore ours.
|
|
aSm.SetResolutionUpdated(true);
|
|
});
|
|
UpdateHitTestingTree();
|
|
|
|
// Check that APZ clamped the scroll offset.
|
|
EXPECT_EQ(CSSRect(0, 0, 300, 300), compositorMetrics.CalculateScrollRange());
|
|
EXPECT_EQ(CSSPoint(300, 300), compositorMetrics.GetVisualScrollOffset());
|
|
}
|
|
|
|
TEST_F(APZCTreeManagerTester,
|
|
InstantKeyScrollBetweenTwoSamplingsWithSameTimeStamp) {
|
|
if (!StaticPrefs::apz_keyboard_enabled_AtStartup()) {
|
|
// On Android apz.keyboard.enabled is false by default and it's can't be
|
|
// changed here since it's `mirror: once`, so we just skip this test.
|
|
return;
|
|
}
|
|
|
|
// For instant scrolling, i.e. no async animation should not be involved.
|
|
SCOPED_GFX_PREF_BOOL("general.smoothScroll", false);
|
|
|
|
// Set up a keyboard shortcuts map to scroll page down.
|
|
AutoTArray<KeyboardShortcut, 1> shortcuts{KeyboardShortcut(
|
|
KeyboardInput::KEY_DOWN, 0, 0, 0, 0,
|
|
KeyboardScrollAction(
|
|
KeyboardScrollAction::KeyboardScrollActionType::eScrollPage, true))};
|
|
KeyboardMap keyboardMap(std::move(shortcuts));
|
|
manager->SetKeyboardMap(keyboardMap);
|
|
|
|
// Set up a scrollable layer.
|
|
CreateSimpleScrollingLayer();
|
|
ScopedLayerTreeRegistration registration(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
|
|
// Setup the scrollable layer is scrollable by key events.
|
|
FocusTarget focusTarget;
|
|
focusTarget.mSequenceNumber = 1;
|
|
focusTarget.mData = AsVariant<FocusTarget::ScrollTargets>(
|
|
{ScrollableLayerGuid::START_SCROLL_ID,
|
|
ScrollableLayerGuid::START_SCROLL_ID});
|
|
manager->UpdateFocusState(LayersId{0}, LayersId{0}, focusTarget);
|
|
|
|
// A vsync tick happens.
|
|
mcc->AdvanceByMillis(16);
|
|
|
|
// The first sampling happens, there's no change have happened, thus no need
|
|
// to composite.
|
|
EXPECT_FALSE(manager->AdvanceAnimations(mcc->GetSampleTime()));
|
|
|
|
// A key event causing scroll page down happens.
|
|
WidgetKeyboardEvent widgetEvent(true, eKeyDown, nullptr);
|
|
KeyboardInput input(widgetEvent);
|
|
Unused << manager->ReceiveInputEvent(input);
|
|
|
|
// Simulate WebRender compositing frames until APZ tells it the scroll offset
|
|
// has stopped changing.
|
|
// Important to trigger the bug: the first composite has the same time stamp
|
|
// as the earlier one above.
|
|
ParentLayerPoint compositedScrollOffset;
|
|
while (true) {
|
|
bool needMoreFrames = manager->AdvanceAnimations(mcc->GetSampleTime());
|
|
compositedScrollOffset = ApzcOf(root)->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForCompositing);
|
|
if (!needMoreFrames) {
|
|
break;
|
|
}
|
|
mcc->AdvanceBy(TimeDuration::FromMilliseconds(16));
|
|
}
|
|
|
|
// Check that the effect of the keyboard scroll has been composited.
|
|
EXPECT_GT(compositedScrollOffset.y, 0);
|
|
}
|
|
|
|
TEST_F(APZCTreeManagerGenericTesterMock,
|
|
PanGestureWithCtrlModifier_Bug1917488) {
|
|
// The outer layer represents the browser chrome, and has layers id 0.
|
|
// The inner layer represents web content, and will initally get layers id 1.
|
|
const char* treeShape = "x(x)";
|
|
LayerIntRect layerVisibleRect[] = {
|
|
LayerIntRect(0, 0, 100, 100),
|
|
LayerIntRect(0, 0, 100, 100),
|
|
};
|
|
CreateScrollData(treeShape, layerVisibleRect);
|
|
|
|
// We need one of these for every LayersId the test will use!
|
|
ScopedLayerTreeRegistration registration0(LayersId{0}, mcc);
|
|
ScopedLayerTreeRegistration registration1(LayersId{1}, mcc);
|
|
ScopedLayerTreeRegistration registration2(LayersId{2}, mcc);
|
|
|
|
// In this test, we only bother to give the inner layer an APZC.
|
|
ScrollableLayerGuid::ViewID scrollId = ScrollableLayerGuid::START_SCROLL_ID;
|
|
SetScrollableFrameMetrics(layers[1], scrollId, CSSRect(0, 0, 100, 100));
|
|
|
|
// Set the referent id of the root layer to 1.
|
|
// Note that this causes the *descendants* of the root layer
|
|
// to get a layers id of 1 during the hit-testing tree update.
|
|
LayersId tab1LayersId{1};
|
|
ScrollableLayerGuid tab1Guid(tab1LayersId, 0, scrollId);
|
|
root->SetReferentId(tab1LayersId);
|
|
UpdateHitTestingTree();
|
|
|
|
// Perform a pan gesture on the content layer.
|
|
// For the START event, do not use the PanGesture() helper, because we want to
|
|
// check the mLayersId that APZ sets on the input event object. This
|
|
// determines what content process the event will gets dispatched to.
|
|
ScreenIntPoint panPoint(50, 50);
|
|
QueueMockHitResult(tab1Guid);
|
|
PanGestureInput panStart(PanGestureInput::PANGESTURE_START, mcc->Time(),
|
|
panPoint, ScreenPoint(0, 10), MODIFIER_NONE);
|
|
manager->ReceiveInputEvent(panStart);
|
|
mcc->AdvanceByMillis(5);
|
|
QueueMockHitResult(tab1Guid);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
|
ScreenPoint(0, 10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
QueueMockHitResult(tab1Guid);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// The layers id assigned to the events of this gesture should be 1.
|
|
EXPECT_EQ(panStart.mLayersId, tab1LayersId);
|
|
|
|
// Simulate a tab switch by updating the referent id of the root layer
|
|
// to a new layers id, 2.
|
|
LayersId tab2LayersId{2};
|
|
ScrollableLayerGuid tab2Guid(tab2LayersId, 0, scrollId);
|
|
root->SetReferentId(tab2LayersId);
|
|
UpdateHitTestingTree();
|
|
|
|
// Perform another pan gesture on the content layer, but this time with
|
|
// the Control modifier held down.
|
|
QueueMockHitResult(tab2Guid);
|
|
PanGestureInput zoomStart(PanGestureInput::PANGESTURE_START, mcc->Time(),
|
|
panPoint, ScreenPoint(0, 10), MODIFIER_CONTROL);
|
|
manager->ReceiveInputEvent(zoomStart);
|
|
mcc->AdvanceByMillis(5);
|
|
QueueMockHitResult(tab2Guid);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
|
ScreenPoint(0, 10), mcc->Time(), MODIFIER_CONTROL);
|
|
mcc->AdvanceByMillis(5);
|
|
QueueMockHitResult(tab2Guid);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
|
|
ScreenPoint(0, 0), mcc->Time(), MODIFIER_CONTROL);
|
|
|
|
// The layers id assigned to the events in the zoom gesture should be 2.
|
|
// (In the buggy scenario, it's 1, meaning the events get incorrectly
|
|
// sent to the previous tab's content process.)
|
|
EXPECT_EQ(zoomStart.mLayersId, tab2LayersId);
|
|
}
|