ScrollOffset maximumScrollOffset() const override { ScrollOffset visibleViewport(viewportSize()); visibleViewport.scale(1 / m_scale); ScrollOffset maxOffset = ScrollOffset(contentsSize()) - visibleViewport; return ScrollOffset(maxOffset); }
//----------------------------------------------------------------------------- //! //----------------------------------------------------------------------------- void tAbstractSideBar::timerEvent( QTimerEvent* pEvent ) { if( m_State == eMS_ManuallyScrolling ) { m_CurrentSpeed = ScrollOffset() - m_DragPosition; m_DragPosition = ScrollOffset(); } QObject::timerEvent( pEvent ); }
LayoutRect RootFrameViewport::scrollIntoView(const LayoutRect& rectInContent, const ScrollAlignment& alignX, const ScrollAlignment& alignY, ScrollType scrollType) { // We want to move the rect into the viewport that excludes the scrollbars so // we intersect the visual viewport with the scrollbar-excluded frameView // content rect. However, we don't use visibleContentRect directly since it // floors the scroll offset. Instead, we use ScrollAnimatorBase::currentOffset // and construct a LayoutRect from that. LayoutRect frameRectInContent = LayoutRect(FloatPoint(layoutViewport().scrollAnimator().currentOffset()), FloatSize(layoutViewport().visibleContentRect().size())); LayoutRect visualRectInContent = LayoutRect(FloatPoint(scrollOffsetFromScrollAnimators()), FloatSize(visualViewport().visibleContentRect().size())); // Intersect layout and visual rects to exclude the scrollbar from the view // rect. LayoutRect viewRectInContent = intersection(visualRectInContent, frameRectInContent); LayoutRect targetViewport = ScrollAlignment::getRectToExpose( viewRectInContent, rectInContent, alignX, alignY); if (targetViewport != viewRectInContent) { setScrollOffset(ScrollOffset(targetViewport.x(), targetViewport.y()), scrollType); } // RootFrameViewport only changes the viewport relative to the document so we // can't change the input rect's location relative to the document origin. return rectInContent; }
void RootFrameViewport::restoreToAnchor(const ScrollOffset& targetOffset) { // Clamp the scroll offset of each viewport now so that we force any invalid // offsets to become valid so we can compute the correct deltas. visualViewport().setScrollOffset(visualViewport().getScrollOffset(), ProgrammaticScroll); layoutViewport().setScrollOffset(layoutViewport().getScrollOffset(), ProgrammaticScroll); ScrollOffset delta = targetOffset - getScrollOffset(); visualViewport().setScrollOffset(visualViewport().getScrollOffset() + delta, ProgrammaticScroll); delta = targetOffset - getScrollOffset(); // Since the main thread FrameView has integer scroll offsets, scroll it to // the next pixel and then we'll scroll the visual viewport again to // compensate for the sub-pixel offset. We need this "overscroll" to ensure // the pixel of which we want to be partially in appears fully inside the // FrameView since the VisualViewport is bounded by the FrameView. IntSize layoutDelta = IntSize( delta.width() < 0 ? floor(delta.width()) : ceil(delta.width()), delta.height() < 0 ? floor(delta.height()) : ceil(delta.height())); layoutViewport().setScrollOffset( ScrollOffset(layoutViewport().scrollOffsetInt() + layoutDelta), ProgrammaticScroll); delta = targetOffset - getScrollOffset(); visualViewport().setScrollOffset(visualViewport().getScrollOffset() + delta, ProgrammaticScroll); }
ScrollOffset clampedScrollOffset(const ScrollOffset& offset) { ScrollOffset minOffset = minimumScrollOffset(); ScrollOffset maxOffset = maximumScrollOffset(); float width = std::min(std::max(offset.width(), minOffset.width()), maxOffset.width()); float height = std::min(std::max(offset.height(), minOffset.height()), maxOffset.height()); return ScrollOffset(width, height); }
TEST_F(EventHandlerTest, dragSelectionAfterScroll) { setHtmlInnerHTML( "<style> body { margin: 0px; } .upper { width: 300px; height: 400px; }" ".lower { margin: 0px; width: 300px; height: 400px; } .line { display: " "block; width: 300px; height: 30px; } </style>" "<div class='upper'></div>" "<div class='lower'>" "<span class='line'>Line 1</span><span class='line'>Line 2</span><span " "class='line'>Line 3</span><span class='line'>Line 4</span><span " "class='line'>Line 5</span>" "<span class='line'>Line 6</span><span class='line'>Line 7</span><span " "class='line'>Line 8</span><span class='line'>Line 9</span><span " "class='line'>Line 10</span>" "</div>"); FrameView* frameView = document().view(); frameView->layoutViewportScrollableArea()->setScrollOffset( ScrollOffset(0, 400), ProgrammaticScroll); PlatformMouseEvent mouseDownEvent( IntPoint(0, 0), IntPoint(100, 200), WebPointerProperties::Button::Left, PlatformEvent::MousePressed, 1, PlatformEvent::Modifiers::LeftButtonDown, WTF::monotonicallyIncreasingTime()); document().frame()->eventHandler().handleMousePressEvent(mouseDownEvent); PlatformMouseEvent mouseMoveEvent( IntPoint(100, 50), IntPoint(200, 250), WebPointerProperties::Button::Left, PlatformEvent::MouseMoved, 1, PlatformEvent::Modifiers::LeftButtonDown, WTF::monotonicallyIncreasingTime()); document().frame()->eventHandler().handleMouseMoveEvent( mouseMoveEvent, Vector<PlatformMouseEvent>()); page().autoscrollController().animate(WTF::monotonicallyIncreasingTime()); page().animator().serviceScriptedAnimations( WTF::monotonicallyIncreasingTime()); PlatformMouseEvent mouseUpEvent( IntPoint(100, 50), IntPoint(200, 250), WebPointerProperties::Button::Left, PlatformEvent::MouseReleased, 1, static_cast<PlatformEvent::Modifiers>(0), WTF::monotonicallyIncreasingTime()); document().frame()->eventHandler().handleMouseReleaseEvent(mouseUpEvent); FrameSelection& selection = document().frame()->selection(); ASSERT_TRUE(selection.isRange()); Range* range = createRange(selection.selection().toNormalizedEphemeralRange()); ASSERT_TRUE(range); EXPECT_EQ("Line 1\nLine 2", range->text()); }
ScrollOffset VisualViewport::maximumScrollOffset() const { if (!mainFrame()) return ScrollOffset(); // TODO(bokan): We probably shouldn't be storing the bounds in a float. // crbug.com/470718. FloatSize frameViewSize(contentsSize()); if (m_browserControlsAdjustment) { float minScale = frameHost().pageScaleConstraintsSet().finalConstraints().minimumScale; frameViewSize.expand(0, m_browserControlsAdjustment / minScale); } frameViewSize.scale(m_scale); frameViewSize = FloatSize(flooredIntSize(frameViewSize)); FloatSize viewportSize(m_size); viewportSize.expand(0, ceilf(m_browserControlsAdjustment)); FloatSize maxPosition = frameViewSize - viewportSize; maxPosition.scale(1 / m_scale); return ScrollOffset(maxPosition); }
// Tests that the visible rect (i.e. visual viewport rect) is correctly // calculated, taking into account both viewports and page scale. TEST_F(RootFrameViewportTest, VisibleContentRect) { IntSize viewportSize(500, 401); RootFrameViewStub* layoutViewport = RootFrameViewStub::create(viewportSize, IntSize(1000, 2000)); VisualViewportStub* visualViewport = VisualViewportStub::create(viewportSize, viewportSize); ScrollableArea* rootFrameViewport = RootFrameViewport::create(*visualViewport, *layoutViewport); rootFrameViewport->setScrollOffset(ScrollOffset(100, 75), ProgrammaticScroll); EXPECT_POINT_EQ(IntPoint(100, 75), rootFrameViewport->visibleContentRect().location()); EXPECT_SIZE_EQ(ScrollOffset(500, 401), rootFrameViewport->visibleContentRect().size()); visualViewport->setScale(2); EXPECT_POINT_EQ(IntPoint(100, 75), rootFrameViewport->visibleContentRect().location()); EXPECT_SIZE_EQ(ScrollOffset(250, 201), rootFrameViewport->visibleContentRect().size()); }
void ScrollAnimator::adjustAnimationAndSetScrollOffset( const ScrollOffset& offset, ScrollType scrollType) { IntSize adjustment = roundedIntSize(offset) - roundedIntSize(m_scrollableArea->scrollOffset()); scrollOffsetChanged(offset, scrollType); if (m_runState == RunState::Idle) { adjustImplOnlyScrollOffsetAnimation(adjustment); } else if (hasRunningAnimation()) { m_targetOffset += ScrollOffset(adjustment); if (m_animationCurve) { m_animationCurve->applyAdjustment(adjustment); if (m_runState != RunState::RunningOnMainThread && registerAndScheduleAnimation()) m_runState = RunState::RunningOnCompositorButNeedsAdjustment; } } }
WebView* TouchActionTest::setupTest(std::string file, TouchActionTrackingWebViewClient& client) { URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL), WebString::fromUTF8(file)); // Note that JavaScript must be enabled for shadow DOM tests. WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + file, true, 0, &client); // Set size to enable hit testing, and avoid line wrapping for consistency // with browser. webView->resize(WebSize(800, 1200)); // Scroll to verify the code properly transforms windows to client co-ords. const int kScrollOffset = 100; Document* document = static_cast<Document*>(webView->mainFrame()->document()); document->frame()->view()->layoutViewportScrollableArea()->setScrollOffset( ScrollOffset(0, kScrollOffset), ProgrammaticScroll); return webView; }
TEST_P(CompositedLayerMappingTest, VerticalRightLeftWritingModeDocument) { setBodyInnerHTML( "<style>html,body { margin: 0px } html { -webkit-writing-mode: " "vertical-rl}</style> <div id='target' style='width: 10000px; height: " "200px;'></div>"); document().view()->updateAllLifecyclePhases(); document().view()->layoutViewportScrollableArea()->setScrollOffset( ScrollOffset(-5000, 0), ProgrammaticScroll); document().view()->updateAllLifecyclePhases(); PaintLayer* paintLayer = document().layoutViewItem().layer(); ASSERT_TRUE(paintLayer->graphicsLayerBacking()); ASSERT_TRUE(paintLayer->compositedLayerMapping()); // A scroll by -5000px is equivalent to a scroll by (10000 - 5000 - 800)px = // 4200px in non-RTL mode. Expanding the resulting rect by 4000px in each // direction yields this result. EXPECT_RECT_EQ( IntRect(200, 0, 8800, 600), recomputeInterestRect(paintLayer->graphicsLayerBackingForScrolling())); }
TEST_F(VisualRectMappingTest, LayoutView) { document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com")); setBodyInnerHTML( "<style>body { margin: 0; }</style>" "<div id=frameContainer>" " <iframe src='http://test.com' width='50' height='50' " "frameBorder='0'></iframe>" "</div>"); setChildFrameHTML( "<style>body { margin: 0; }</style><span><img style='width: 20px; " "height: 100px'></span>text text text"); document().view()->updateAllLifecyclePhases(); LayoutBlock* frameContainer = toLayoutBlock(getLayoutObjectByElementId("frameContainer")); LayoutBlock* frameBody = toLayoutBlock(childDocument().body()->layoutObject()); LayoutText* frameText = toLayoutText(frameBody->lastChild()); // This case involves clipping: frame height is 50, y-coordinate of result // rect is 13, so height should be clipped to (50 - 13) == 37. childDocument().view()->setScrollOffset(ScrollOffset(0, 47), ProgrammaticScroll); LayoutRect originalRect(4, 60, 20, 80); LayoutRect rect = originalRect; EXPECT_TRUE(frameText->mapToVisualRectInAncestorSpace(frameContainer, rect)); EXPECT_EQ(rect, LayoutRect(4, 13, 20, 37)); rect = originalRect; EXPECT_TRUE(frameText->mapToVisualRectInAncestorSpace(&layoutView(), rect)); EXPECT_EQ(rect, LayoutRect(4, 13, 20, 37)); checkPaintInvalidationStateRectMapping(rect, originalRect, *frameText, layoutView(), layoutView()); rect = LayoutRect(4, 60, 0, 80); EXPECT_TRUE(frameText->mapToVisualRectInAncestorSpace(frameContainer, rect, EdgeInclusive)); EXPECT_EQ(rect, LayoutRect(4, 13, 0, 37)); }
TEST_F(VisualRectMappingTest, LayoutViewDisplayNone) { document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com")); setBodyInnerHTML( "<style>body { margin: 0; }</style>" "<div id=frameContainer>" " <iframe id='frame' src='http://test.com' width='50' height='50' " "frameBorder='0'></iframe>" "</div>"); setChildFrameHTML( "<style>body { margin: 0; }</style><div " "style='width:100px;height:100px;'></div>"); document().view()->updateAllLifecyclePhases(); LayoutBlock* frameContainer = toLayoutBlock(getLayoutObjectByElementId("frameContainer")); LayoutBlock* frameBody = toLayoutBlock(childDocument().body()->layoutObject()); LayoutBlock* frameDiv = toLayoutBlock(frameBody->lastChild()); // This part is copied from the LayoutView test, just to ensure that the // mapped rect is valid before display:none is set on the iframe. childDocument().view()->setScrollOffset(ScrollOffset(0, 47), ProgrammaticScroll); LayoutRect originalRect(4, 60, 20, 80); LayoutRect rect = originalRect; EXPECT_TRUE(frameDiv->mapToVisualRectInAncestorSpace(frameContainer, rect)); EXPECT_EQ(rect, LayoutRect(4, 13, 20, 37)); Element* frameElement = document().getElementById("frame"); frameElement->setInlineStyleProperty(CSSPropertyDisplay, "none"); document().view()->updateAllLifecyclePhases(); rect = originalRect; EXPECT_FALSE(frameDiv->mapToVisualRectInAncestorSpace(&layoutView(), rect)); EXPECT_EQ(rect, LayoutRect()); }
// Tests that scrolls on the root frame scroll the visual viewport before // trying to scroll the layout viewport. TEST_F(RootFrameViewportTest, ViewportScrollOrder) { IntSize viewportSize(100, 100); RootFrameViewStub* layoutViewport = RootFrameViewStub::create(viewportSize, IntSize(200, 300)); VisualViewportStub* visualViewport = VisualViewportStub::create(viewportSize, viewportSize); ScrollableArea* rootFrameViewport = RootFrameViewport::create(*visualViewport, *layoutViewport); visualViewport->setScale(2); rootFrameViewport->setScrollOffset(ScrollOffset(40, 40), UserScroll); EXPECT_SIZE_EQ(ScrollOffset(40, 40), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 0), layoutViewport->getScrollOffset()); rootFrameViewport->setScrollOffset(ScrollOffset(60, 60), ProgrammaticScroll); EXPECT_SIZE_EQ(ScrollOffset(50, 50), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(10, 10), layoutViewport->getScrollOffset()); }
void WebHistoryItem::setScrollOffset(const WebPoint& scrollOffset) { m_private->setScrollOffset(ScrollOffset(scrollOffset.x, scrollOffset.y)); }
ScrollOffset maximumScrollOffset() const override { return ScrollOffset(contentsSize() - viewportSize()); }
ScrollOffset ScrollableArea::maximumScrollOffset() const { return ScrollOffset(totalContentsSize() - visibleSize()); }
// Tests that scrolling the viewport when the layout viewport is // !userInputScrollable (as happens when overflow:hidden is set) works // correctly, that is, the visual viewport can scroll, but not the layout. TEST_F(RootFrameViewportTest, UserInputScrollable) { IntSize viewportSize(100, 150); RootFrameViewStub* layoutViewport = RootFrameViewStub::create(viewportSize, IntSize(200, 300)); VisualViewportStub* visualViewport = VisualViewportStub::create(viewportSize, viewportSize); ScrollableArea* rootFrameViewport = RootFrameViewport::create(*visualViewport, *layoutViewport); visualViewport->setScale(2); // Disable just the layout viewport's horizontal scrolling, the // RootFrameViewport should remain scrollable overall. layoutViewport->setUserInputScrollable(false, true); visualViewport->setUserInputScrollable(true, true); EXPECT_TRUE(rootFrameViewport->userInputScrollable(HorizontalScrollbar)); EXPECT_TRUE(rootFrameViewport->userInputScrollable(VerticalScrollbar)); // Layout viewport shouldn't scroll since it's not horizontally scrollable, // but visual viewport should. rootFrameViewport->userScroll(ScrollByPixel, FloatSize(300, 0)); EXPECT_SIZE_EQ(ScrollOffset(0, 0), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(50, 0), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(50, 0), rootFrameViewport->getScrollOffset()); // Vertical scrolling should be unaffected. rootFrameViewport->userScroll(ScrollByPixel, FloatSize(0, 300)); EXPECT_SIZE_EQ(ScrollOffset(0, 150), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(50, 75), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(50, 225), rootFrameViewport->getScrollOffset()); // Try the same checks as above but for the vertical direction. // =============================================== rootFrameViewport->setScrollOffset(ScrollOffset(), ProgrammaticScroll); // Disable just the layout viewport's vertical scrolling, the // RootFrameViewport should remain scrollable overall. layoutViewport->setUserInputScrollable(true, false); visualViewport->setUserInputScrollable(true, true); EXPECT_TRUE(rootFrameViewport->userInputScrollable(HorizontalScrollbar)); EXPECT_TRUE(rootFrameViewport->userInputScrollable(VerticalScrollbar)); // Layout viewport shouldn't scroll since it's not vertically scrollable, // but visual viewport should. rootFrameViewport->userScroll(ScrollByPixel, FloatSize(0, 300)); EXPECT_SIZE_EQ(ScrollOffset(0, 0), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 75), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 75), rootFrameViewport->getScrollOffset()); // Horizontal scrolling should be unaffected. rootFrameViewport->userScroll(ScrollByPixel, FloatSize(300, 0)); EXPECT_SIZE_EQ(ScrollOffset(100, 0), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(50, 75), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(150, 75), rootFrameViewport->getScrollOffset()); }
// Make sure scrolls using the scroll animator (scroll(), setScrollOffset()) // work correctly when one of the subviewports is explicitly scrolled without // using the // RootFrameViewport interface. TEST_F(RootFrameViewportTest, TestScrollAnimatorUpdatedBeforeScroll) { IntSize viewportSize(100, 150); RootFrameViewStub* layoutViewport = RootFrameViewStub::create(viewportSize, IntSize(200, 300)); VisualViewportStub* visualViewport = VisualViewportStub::create(viewportSize, viewportSize); ScrollableArea* rootFrameViewport = RootFrameViewport::create(*visualViewport, *layoutViewport); visualViewport->setScale(2); visualViewport->setScrollOffset(ScrollOffset(50, 75), ProgrammaticScroll); EXPECT_SIZE_EQ(ScrollOffset(50, 75), rootFrameViewport->getScrollOffset()); // If the scroll animator doesn't update, it will still think it's at (0, 0) // and so it may early exit. rootFrameViewport->setScrollOffset(ScrollOffset(0, 0), ProgrammaticScroll); EXPECT_SIZE_EQ(ScrollOffset(0, 0), rootFrameViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 0), visualViewport->getScrollOffset()); // Try again for userScroll() visualViewport->setScrollOffset(ScrollOffset(50, 75), ProgrammaticScroll); EXPECT_SIZE_EQ(ScrollOffset(50, 75), rootFrameViewport->getScrollOffset()); rootFrameViewport->userScroll(ScrollByPixel, FloatSize(-50, 0)); EXPECT_SIZE_EQ(ScrollOffset(0, 75), rootFrameViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 75), visualViewport->getScrollOffset()); // Make sure the layout viewport is also accounted for. rootFrameViewport->setScrollOffset(ScrollOffset(0, 0), ProgrammaticScroll); layoutViewport->setScrollOffset(ScrollOffset(100, 150), ProgrammaticScroll); EXPECT_SIZE_EQ(ScrollOffset(100, 150), rootFrameViewport->getScrollOffset()); rootFrameViewport->userScroll(ScrollByPixel, FloatSize(-100, 0)); EXPECT_SIZE_EQ(ScrollOffset(0, 150), rootFrameViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 150), layoutViewport->getScrollOffset()); }
EXPORT_C void CHuiLayout::SetScrollOffsetInBaseUnits(const THuiRealPoint& aOffset, TInt aTransitionTime) { // Pass information directly to the scroll offset ScrollOffset().Set(aOffset, aTransitionTime); }
// SetTo void PropertyListView::SetTo(PropertyObject* object) { // try to do without rebuilding the list // it should in fact be pretty unlikely that this does not // work, but we keep being defensive if (fPropertyObject && object && fPropertyObject->ContainsSameProperties(*object)) { // iterate over view items and update their value views bool error = false; for (int32 i = 0; PropertyItemView* item = _ItemAt(i); i++) { Property* property = object->PropertyAt(i); if (!item->AdoptProperty(property)) { // the reason for this can be that the property is // unkown to the PropertyEditorFactory and therefor // there is no editor view at this item fprintf(stderr, "PropertyListView::_SetTo() - " "property mismatch at %ld\n", i); error = true; break; } if (property) item->SetEnabled(property->IsEditable()); } // we didn't need to make empty, but transfer ownership // of the object if (!error) { // if the "adopt" process went only halfway, // some properties of the original object // are still referenced, so we can only // delete the original object if the process // was successful and leak Properties otherwise, // but this case is only theoretical anyways... delete fPropertyObject; } fPropertyObject = object; } else { // remember scroll pos, selection and focused item BPoint scrollOffset = ScrollOffset(); BList selection(20); int32 focused = -1; for (int32 i = 0; PropertyItemView* item = _ItemAt(i); i++) { if (item->IsSelected()) selection.AddItem((void*)i); if (item->IsFocused()) focused = i; } if (Window()) Window()->BeginViewTransaction(); fSuspendUpdates = true; // rebuild list _MakeEmpty(); fPropertyObject = object; if (fPropertyObject) { // fill with content for (int32 i = 0; Property* property = fPropertyObject->PropertyAt(i); i++) { PropertyItemView* item = new PropertyItemView(property); item->SetEnabled(property->IsEditable()); _AddItem(item); } _LayoutItems(); // restore scroll pos, selection and focus SetScrollOffset(scrollOffset); for (int32 i = 0; PropertyItemView* item = _ItemAt(i); i++) { if (selection.HasItem((void*)i)) item->SetSelected(true); if (i == focused) item->MakeFocus(true); } } if (Window()) Window()->EndViewTransaction(); fSuspendUpdates = false; SetDataRect(_ItemsRect()); } _UpdateSavedProperties(); _CheckMenuStatus(); Invalidate(); }
// Test that the scrollIntoView correctly scrolls the main frame // and visual viewport such that the given rect is centered in the viewport. TEST_F(RootFrameViewportTest, ScrollIntoView) { IntSize viewportSize(100, 150); RootFrameViewStub* layoutViewport = RootFrameViewStub::create(viewportSize, IntSize(200, 300)); VisualViewportStub* visualViewport = VisualViewportStub::create(viewportSize, viewportSize); ScrollableArea* rootFrameViewport = RootFrameViewport::create(*visualViewport, *layoutViewport); // Test that the visual viewport is scrolled if the viewport has been // resized (as is the case when the ChromeOS keyboard comes up) but not // scaled. visualViewport->setViewportSize(IntSize(100, 100)); rootFrameViewport->scrollIntoView(LayoutRect(100, 250, 50, 50), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); EXPECT_SIZE_EQ(ScrollOffset(50, 150), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 50), visualViewport->getScrollOffset()); rootFrameViewport->scrollIntoView(LayoutRect(25, 75, 50, 50), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); EXPECT_SIZE_EQ(ScrollOffset(25, 75), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 0), visualViewport->getScrollOffset()); // Reset the visual viewport's size, scale the page, and repeat the test visualViewport->setViewportSize(IntSize(100, 150)); visualViewport->setScale(2); rootFrameViewport->setScrollOffset(ScrollOffset(), ProgrammaticScroll); rootFrameViewport->scrollIntoView(LayoutRect(50, 75, 50, 75), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); EXPECT_SIZE_EQ(ScrollOffset(0, 0), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(50, 75), visualViewport->getScrollOffset()); rootFrameViewport->scrollIntoView(LayoutRect(190, 290, 10, 10), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); EXPECT_SIZE_EQ(ScrollOffset(100, 150), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(50, 75), visualViewport->getScrollOffset()); // Scrolling into view the viewport rect itself should be a no-op. visualViewport->setViewportSize(IntSize(100, 100)); visualViewport->setScale(1.5f); visualViewport->setScrollOffset(ScrollOffset(0, 10), ProgrammaticScroll); layoutViewport->setScrollOffset(ScrollOffset(50, 50), ProgrammaticScroll); rootFrameViewport->setScrollOffset(rootFrameViewport->getScrollOffset(), ProgrammaticScroll); rootFrameViewport->scrollIntoView( LayoutRect(rootFrameViewport->visibleContentRect(ExcludeScrollbars)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); EXPECT_SIZE_EQ(ScrollOffset(50, 50), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 10), visualViewport->getScrollOffset()); rootFrameViewport->scrollIntoView( LayoutRect(rootFrameViewport->visibleContentRect(ExcludeScrollbars)), ScrollAlignment::alignCenterAlways, ScrollAlignment::alignCenterAlways); EXPECT_SIZE_EQ(ScrollOffset(50, 50), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 10), visualViewport->getScrollOffset()); rootFrameViewport->scrollIntoView( LayoutRect(rootFrameViewport->visibleContentRect(ExcludeScrollbars)), ScrollAlignment::alignTopAlways, ScrollAlignment::alignTopAlways); EXPECT_SIZE_EQ(ScrollOffset(50, 50), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 10), visualViewport->getScrollOffset()); }
// Tests that the setScrollOffset method works correctly with both viewports. TEST_F(RootFrameViewportTest, SetScrollOffset) { IntSize viewportSize(500, 500); RootFrameViewStub* layoutViewport = RootFrameViewStub::create(viewportSize, IntSize(1000, 2000)); VisualViewportStub* visualViewport = VisualViewportStub::create(viewportSize, viewportSize); ScrollableArea* rootFrameViewport = RootFrameViewport::create(*visualViewport, *layoutViewport); visualViewport->setScale(2); // Ensure that the visual viewport scrolls first. rootFrameViewport->setScrollOffset(ScrollOffset(100, 100), ProgrammaticScroll); EXPECT_SIZE_EQ(ScrollOffset(100, 100), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 0), layoutViewport->getScrollOffset()); // Scroll to the visual viewport's extent, the layout viewport should scroll // the remainder. rootFrameViewport->setScrollOffset(ScrollOffset(300, 400), ProgrammaticScroll); EXPECT_SIZE_EQ(ScrollOffset(250, 250), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(50, 150), layoutViewport->getScrollOffset()); // Only the layout viewport should scroll further. Make sure it doesn't scroll // out of bounds. rootFrameViewport->setScrollOffset(ScrollOffset(780, 1780), ProgrammaticScroll); EXPECT_SIZE_EQ(ScrollOffset(250, 250), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(500, 1500), layoutViewport->getScrollOffset()); // Scroll all the way back. rootFrameViewport->setScrollOffset(ScrollOffset(0, 0), ProgrammaticScroll); EXPECT_SIZE_EQ(ScrollOffset(0, 0), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 0), layoutViewport->getScrollOffset()); }
ScrollOffset minimumScrollOffset() const override { return ScrollOffset(); }
// Tests that setting an alternate layout viewport scrolls the alternate // instead of the original. TEST_F(RootFrameViewportTest, SetAlternateLayoutViewport) { IntSize viewportSize(100, 100); RootFrameViewStub* layoutViewport = RootFrameViewStub::create(viewportSize, IntSize(200, 300)); VisualViewportStub* visualViewport = VisualViewportStub::create(viewportSize, viewportSize); RootFrameViewStub* alternateScroller = RootFrameViewStub::create(viewportSize, IntSize(600, 500)); RootFrameViewport* rootFrameViewport = RootFrameViewport::create(*visualViewport, *layoutViewport); visualViewport->setScale(2); rootFrameViewport->setScrollOffset(ScrollOffset(100, 100), UserScroll); EXPECT_SIZE_EQ(ScrollOffset(50, 50), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(50, 50), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(100, 100), rootFrameViewport->getScrollOffset()); rootFrameViewport->setLayoutViewport(*alternateScroller); EXPECT_SIZE_EQ(ScrollOffset(50, 50), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(0, 0), alternateScroller->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(50, 50), rootFrameViewport->getScrollOffset()); rootFrameViewport->setScrollOffset(ScrollOffset(200, 200), UserScroll); EXPECT_SIZE_EQ(ScrollOffset(50, 50), visualViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(150, 150), alternateScroller->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(200, 200), rootFrameViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(50, 50), layoutViewport->getScrollOffset()); EXPECT_SIZE_EQ(ScrollOffset(550, 450), rootFrameViewport->maximumScrollOffset()); }