void RootFrameViewport::setScrollOffset(const ScrollOffset& offset, ScrollType scrollType, ScrollBehavior scrollBehavior) { updateScrollAnimator(); if (scrollBehavior == ScrollBehaviorAuto) scrollBehavior = scrollBehaviorStyle(); if (scrollType == ProgrammaticScroll && !layoutViewport().isProgrammaticallyScrollable()) return; if (scrollType == AnchoringScroll) { distributeScrollBetweenViewports(offset, scrollType, scrollBehavior, LayoutViewport); return; } if (scrollBehavior == ScrollBehaviorSmooth) { distributeScrollBetweenViewports(offset, scrollType, scrollBehavior, VisualViewport); return; } ScrollOffset clampedOffset = clampScrollOffset(offset); ScrollableArea::setScrollOffset(clampedOffset, scrollType, scrollBehavior); }
void VisualViewport::setScrollOffset(const ScrollOffset& offset, ScrollType scrollType, ScrollBehavior scrollBehavior) { // We clamp the offset here, because the ScrollAnimator may otherwise be // set to a non-clamped offset by ScrollableArea::setScrollOffset, // which may lead to incorrect scrolling behavior in RootFrameViewport down // the line. // TODO(eseckler): Solve this instead by ensuring that ScrollableArea and // ScrollAnimator are kept in sync. This requires that ScrollableArea always // stores fractional offsets and that truncation happens elsewhere, see // crbug.com/626315. ScrollOffset newScrollOffset = clampScrollOffset(offset); ScrollableArea::setScrollOffset(newScrollOffset, scrollType, scrollBehavior); }
LayoutRect RenderLayerScrollableArea::exposeRect(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) { LayoutRect localExposeRect(box().absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox()); LayoutRect layerBounds(0, 0, box().clientWidth(), box().clientHeight()); LayoutRect r = ScrollAlignment::getRectToExpose(layerBounds, localExposeRect, alignX, alignY); IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset() + toIntSize(roundedIntRect(r).location())); if (clampedScrollOffset == adjustedScrollOffset()) return rect; IntSize oldScrollOffset = adjustedScrollOffset(); scrollToOffset(clampedScrollOffset); IntSize scrollOffsetDifference = adjustedScrollOffset() - oldScrollOffset; localExposeRect.move(-scrollOffsetDifference); return LayoutRect(box().localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox()); }
bool VisualViewport::didSetScaleOrLocation(float scale, const FloatPoint& location) { if (!mainFrame()) return false; bool valuesChanged = false; if (scale != m_scale) { m_scale = scale; valuesChanged = true; frameHost().chromeClient().pageScaleFactorChanged(); enqueueResizeEvent(); } ScrollOffset clampedOffset = clampScrollOffset(toScrollOffset(location)); if (clampedOffset != m_offset) { m_offset = clampedOffset; scrollAnimator().setCurrentOffset(m_offset); // SVG runs with accelerated compositing disabled so no // ScrollingCoordinator. if (ScrollingCoordinator* coordinator = frameHost().page().scrollingCoordinator()) coordinator->scrollableAreaScrollLayerDidChange(this); if (!frameHost().settings().inertVisualViewport()) { if (Document* document = mainFrame()->document()) document->enqueueScrollEventForNode(document); } enqueueScrollEvent(); mainFrame()->view()->didChangeScrollOffset(); valuesChanged = true; } if (!valuesChanged) return false; InspectorInstrumentation::didUpdateLayout(mainFrame()); mainFrame()->loader().saveScrollState(); clampToBoundaries(); return true; }
void RenderLayerScrollableArea::updateAfterLayout() { m_scrollDimensionsDirty = true; IntSize originalScrollOffset = adjustedScrollOffset(); computeScrollDimensions(); // Layout may cause us to be at an invalid scroll position. In this case we need // to pull our scroll offsets back to the max (or push them up to the min). IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset()); if (clampedScrollOffset != adjustedScrollOffset()) scrollToOffset(clampedScrollOffset); if (originalScrollOffset != adjustedScrollOffset()) scrollToOffsetWithoutAnimation(-scrollOrigin() + adjustedScrollOffset()); bool hasHorizontalOverflow = this->hasHorizontalOverflow(); bool hasVerticalOverflow = this->hasVerticalOverflow(); { // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html. DisableCompositingQueryAsserts disabler; // overflow:scroll should just enable/disable. if (box().style()->overflowX() == OSCROLL) horizontalScrollbar()->setEnabled(hasHorizontalOverflow); if (box().style()->overflowY() == OSCROLL) verticalScrollbar()->setEnabled(hasVerticalOverflow); } // overflow:auto may need to lay out again if scrollbars got added/removed. bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow); bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow); if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) { if (box().hasAutoHorizontalScrollbar()) setHasHorizontalScrollbar(hasHorizontalOverflow); if (box().hasAutoVerticalScrollbar()) setHasVerticalScrollbar(hasVerticalOverflow); layer()->updateSelfPaintingLayer(); if (box().style()->overflowX() == OAUTO || box().style()->overflowY() == OAUTO) { if (!m_inOverflowRelayout) { // Our proprietary overflow: overlay value doesn't trigger a layout. m_inOverflowRelayout = true; SubtreeLayoutScope layoutScope(box()); layoutScope.setNeedsLayout(&box()); if (box().isRenderBlock()) { RenderBlock& block = toRenderBlock(box()); block.scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged); block.layoutBlock(true); } else { box().layout(); } m_inOverflowRelayout = false; } } } { // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html. DisableCompositingQueryAsserts disabler; // Set up the range (and page step/line step). if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { int clientWidth = box().pixelSnappedClientWidth(); horizontalScrollbar->setProportion(clientWidth, overflowRect().width()); } if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { int clientHeight = box().pixelSnappedClientHeight(); verticalScrollbar->setProportion(clientHeight, overflowRect().height()); } } bool hasOverflow = hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow(); updateScrollableAreaSet(hasOverflow); if (hasOverflow) { DisableCompositingQueryAsserts disabler; positionOverflowControls(IntSize()); } }
void RenderLayerScrollableArea::scrollToOffset(const IntSize& scrollOffset, ScrollOffsetClamping clamp) { IntSize newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset; if (newScrollOffset != adjustedScrollOffset()) scrollToOffsetWithoutAnimation(-scrollOrigin() + newScrollOffset); }