/* -*- 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" class APZScrollbarDraggingTester : public APZCTreeManagerTester { public: APZScrollbarDraggingTester() { CreateMockHitTester(); } protected: UniquePtr registration; ScrollableLayerGuid::ViewID scrollId = ScrollableLayerGuid::START_SCROLL_ID; TestAsyncPanZoomController* apzc = nullptr; ParentLayerCoord ScrollY() const { return apzc ->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForEventHandling) .y; } void QueueHitOnVerticalScrollbar() { mMockHitTester->QueueScrollbarThumbHitResult(scrollId, ScrollDirection::eVertical); } void CreateLayerTreeWithVerticalScrollbar() { // The first child is the scrollable node, the second child is the // scrollbar. const char* treeShape = "x(xx)"; LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100), LayerIntRect(0, 0, 50, 100), LayerIntRect(50, 0, 50, 10)}; CreateScrollData(treeShape, layerVisibleRect); SetScrollableFrameMetrics(layers[1], scrollId, CSSRect(0, 0, 50, 1000)); registration = MakeUnique(LayersId{0}, mcc); layers[2]->SetScrollbarData(ScrollbarData::CreateForThumb( ScrollDirection::eVertical, 0.1, 0, 10, 10, true, 0, 100, scrollId)); UpdateHitTestingTree(); apzc = ApzcOf(layers[1]); } }; // Test that the scrollable rect shrinking during dragging does not result // in scrolling out of bounds. TEST_F(APZScrollbarDraggingTester, ScrollableRectShrinksDuringDragging) { // Explicitly enable scrollbar dragging. This allows the test to run on // Android as well. SCOPED_GFX_PREF_BOOL("apz.drag.enabled", true); CreateLayerTreeWithVerticalScrollbar(); EXPECT_EQ(ScrollY(), 0); // Start a scrollbar drag at y=5. QueueHitOnVerticalScrollbar(); auto dragBlockId = MouseDown(manager, ScreenIntPoint(75, 5), mcc->Time()).mInputBlockId; manager->StartScrollbarDrag(apzc->GetGuid(), AsyncDragMetrics(scrollId, 0, dragBlockId, 5, ScrollDirection::eVertical)); // Drag the scrollbar down to y=75. (The total height is 100.) for (int mouseY = 10; mouseY <= 75; mouseY += 5) { mcc->AdvanceByMillis(10); // We do a hit test for every mouse event, including mousemoves. QueueHitOnVerticalScrollbar(); MouseMove(manager, ScreenIntPoint(75, mouseY), mcc->Time()); } // We should have scrolled past y>500 at least (total scrollable rect height // is 1000). EXPECT_GT(ScrollY(), 500); // Shrink the scrollable rect height to 500. ModifyFrameMetrics(layers[1], [](ScrollMetadata&, FrameMetrics& aMetrics) { aMetrics.SetScrollableRect(CSSRect(0, 0, 50, 500)); }); UpdateHitTestingTree(); // Continue the drag to near the bottom, y=95. // Check that the scroll position never gets out of bounds. (With the // scrollable rect height now 500, the max vertical scroll position is 400.) for (int mouseY = 80; mouseY <= 95; mouseY += 5) { mcc->AdvanceByMillis(10); QueueHitOnVerticalScrollbar(); MouseMove(manager, ScreenIntPoint(75, mouseY), mcc->Time()); EXPECT_LE(ScrollY(), 400); } // End the drag. mcc->AdvanceByMillis(10); QueueHitOnVerticalScrollbar(); MouseUp(manager, ScreenIntPoint(75, 95), mcc->Time()); // We should end up at the bottom of the new scroll range (and not out of // bounds). EXPECT_EQ(ScrollY(), 400); }