| Index: Source/core/rendering/RenderLayerScrollableArea.cpp
|
| diff --git a/Source/core/rendering/RenderLayerScrollableArea.cpp b/Source/core/rendering/RenderLayerScrollableArea.cpp
|
| deleted file mode 100644
|
| index ecc547911e31ff486302f2f6ff840a6a21838367..0000000000000000000000000000000000000000
|
| --- a/Source/core/rendering/RenderLayerScrollableArea.cpp
|
| +++ /dev/null
|
| @@ -1,1385 +0,0 @@
|
| -/*
|
| - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
|
| - *
|
| - * Portions are Copyright (C) 1998 Netscape Communications Corporation.
|
| - *
|
| - * Other contributors:
|
| - * Robert O'Callahan <roc+@cs.cmu.edu>
|
| - * David Baron <dbaron@fas.harvard.edu>
|
| - * Christian Biesinger <cbiesinger@web.de>
|
| - * Randall Jesup <rjesup@wgate.com>
|
| - * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
|
| - * Josh Soref <timeless@mac.com>
|
| - * Boris Zbarsky <bzbarsky@mit.edu>
|
| - *
|
| - * This library is free software; you can redistribute it and/or
|
| - * modify it under the terms of the GNU Lesser General Public
|
| - * License as published by the Free Software Foundation; either
|
| - * version 2.1 of the License, or (at your option) any later version.
|
| - *
|
| - * This library is distributed in the hope that it will be useful,
|
| - * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| - * Lesser General Public License for more details.
|
| - *
|
| - * You should have received a copy of the GNU Lesser General Public
|
| - * License along with this library; if not, write to the Free Software
|
| - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| - *
|
| - * Alternatively, the contents of this file may be used under the terms
|
| - * of either the Mozilla Public License Version 1.1, found at
|
| - * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
|
| - * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
|
| - * (the "GPL"), in which case the provisions of the MPL or the GPL are
|
| - * applicable instead of those above. If you wish to allow use of your
|
| - * version of this file only under the terms of one of those two
|
| - * licenses (the MPL or the GPL) and not to allow others to use your
|
| - * version of this file under the LGPL, indicate your decision by
|
| - * deletingthe provisions above and replace them with the notice and
|
| - * other provisions required by the MPL or the GPL, as the case may be.
|
| - * If you do not delete the provisions above, a recipient may use your
|
| - * version of this file under any of the LGPL, the MPL or the GPL.
|
| - */
|
| -
|
| -#include "config.h"
|
| -#include "core/rendering/RenderLayer.h"
|
| -
|
| -#include "core/css/PseudoStyleRequest.h"
|
| -#include "core/dom/AXObjectCache.h"
|
| -#include "core/dom/Node.h"
|
| -#include "core/dom/shadow/ShadowRoot.h"
|
| -#include "core/editing/FrameSelection.h"
|
| -#include "core/frame/FrameView.h"
|
| -#include "core/frame/LocalFrame.h"
|
| -#include "core/frame/Settings.h"
|
| -#include "core/html/HTMLFrameOwnerElement.h"
|
| -#include "core/inspector/InspectorInstrumentation.h"
|
| -#include "core/layout/LayoutTheme.h"
|
| -#include "core/layout/compositing/CompositedLayerMapping.h"
|
| -#include "core/layout/compositing/RenderLayerCompositor.h"
|
| -#include "core/page/Chrome.h"
|
| -#include "core/page/EventHandler.h"
|
| -#include "core/page/FocusController.h"
|
| -#include "core/page/Page.h"
|
| -#include "core/page/scrolling/ScrollingCoordinator.h"
|
| -#include "core/rendering/RenderGeometryMap.h"
|
| -#include "core/rendering/RenderScrollbar.h"
|
| -#include "core/rendering/RenderScrollbarPart.h"
|
| -#include "core/rendering/RenderView.h"
|
| -#include "platform/PlatformGestureEvent.h"
|
| -#include "platform/PlatformMouseEvent.h"
|
| -#include "platform/graphics/GraphicsContextStateSaver.h"
|
| -#include "platform/graphics/GraphicsLayer.h"
|
| -#include "platform/graphics/paint/DrawingRecorder.h"
|
| -#include "platform/scroll/ScrollAnimator.h"
|
| -#include "platform/scroll/ScrollbarTheme.h"
|
| -#include "public/platform/Platform.h"
|
| -
|
| -namespace blink {
|
| -
|
| -const int ResizerControlExpandRatioForTouch = 2;
|
| -
|
| -RenderLayerScrollableArea::RenderLayerScrollableArea(RenderLayer& layer)
|
| - : m_layer(layer)
|
| - , m_inResizeMode(false)
|
| - , m_scrollsOverflow(false)
|
| - , m_scrollDimensionsDirty(true)
|
| - , m_inOverflowRelayout(false)
|
| - , m_nextTopmostScrollChild(0)
|
| - , m_topmostScrollChild(0)
|
| - , m_needsCompositedScrolling(false)
|
| - , m_scrollCorner(nullptr)
|
| - , m_resizer(nullptr)
|
| -{
|
| - ScrollableArea::setConstrainsScrollingToContentEdge(false);
|
| -
|
| - Node* node = box().node();
|
| - if (node && node->isElementNode()) {
|
| - // We save and restore only the scrollOffset as the other scroll values are recalculated.
|
| - Element* element = toElement(node);
|
| - m_scrollOffset = element->savedLayerScrollOffset();
|
| - if (!m_scrollOffset.isZero())
|
| - scrollAnimator()->setCurrentPosition(FloatPoint(m_scrollOffset.width(), m_scrollOffset.height()));
|
| - element->setSavedLayerScrollOffset(IntSize());
|
| - }
|
| -
|
| - updateResizerAreaSet();
|
| -}
|
| -
|
| -RenderLayerScrollableArea::~RenderLayerScrollableArea()
|
| -{
|
| - if (inResizeMode() && !box().documentBeingDestroyed()) {
|
| - if (LocalFrame* frame = box().frame())
|
| - frame->eventHandler().resizeScrollableAreaDestroyed();
|
| - }
|
| -
|
| - if (LocalFrame* frame = box().frame()) {
|
| - if (FrameView* frameView = frame->view()) {
|
| - frameView->removeScrollableArea(this);
|
| - frameView->removeAnimatingScrollableArea(this);
|
| - }
|
| - }
|
| -
|
| - if (box().frame() && box().frame()->page()) {
|
| - if (ScrollingCoordinator* scrollingCoordinator = box().frame()->page()->scrollingCoordinator())
|
| - scrollingCoordinator->willDestroyScrollableArea(this);
|
| - }
|
| -
|
| - if (!box().documentBeingDestroyed()) {
|
| - Node* node = box().node();
|
| - // FIXME: Make setSavedLayerScrollOffset take DoubleSize. crbug.com/414283.
|
| - if (node && node->isElementNode())
|
| - toElement(node)->setSavedLayerScrollOffset(flooredIntSize(m_scrollOffset));
|
| - }
|
| -
|
| - if (LocalFrame* frame = box().frame()) {
|
| - if (FrameView* frameView = frame->view())
|
| - frameView->removeResizerArea(box());
|
| - }
|
| -
|
| - destroyScrollbar(HorizontalScrollbar);
|
| - destroyScrollbar(VerticalScrollbar);
|
| -
|
| - if (m_scrollCorner)
|
| - m_scrollCorner->destroy();
|
| - if (m_resizer)
|
| - m_resizer->destroy();
|
| -}
|
| -
|
| -HostWindow* RenderLayerScrollableArea::hostWindow() const
|
| -{
|
| - if (Page* page = box().frame()->page())
|
| - return &page->chrome();
|
| - return nullptr;
|
| -}
|
| -
|
| -GraphicsLayer* RenderLayerScrollableArea::layerForScrolling() const
|
| -{
|
| - return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMapping()->scrollingContentsLayer() : 0;
|
| -}
|
| -
|
| -GraphicsLayer* RenderLayerScrollableArea::layerForHorizontalScrollbar() const
|
| -{
|
| - // See crbug.com/343132.
|
| - DisableCompositingQueryAsserts disabler;
|
| -
|
| - return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMapping()->layerForHorizontalScrollbar() : 0;
|
| -}
|
| -
|
| -GraphicsLayer* RenderLayerScrollableArea::layerForVerticalScrollbar() const
|
| -{
|
| - // See crbug.com/343132.
|
| - DisableCompositingQueryAsserts disabler;
|
| -
|
| - return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMapping()->layerForVerticalScrollbar() : 0;
|
| -}
|
| -
|
| -GraphicsLayer* RenderLayerScrollableArea::layerForScrollCorner() const
|
| -{
|
| - // See crbug.com/343132.
|
| - DisableCompositingQueryAsserts disabler;
|
| -
|
| - return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMapping()->layerForScrollCorner() : 0;
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
|
| -{
|
| - // See crbug.com/343132.
|
| - DisableCompositingQueryAsserts disabler;
|
| -
|
| - if (scrollbar == m_vBar.get()) {
|
| - if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
|
| - layer->setNeedsDisplayInRect(rect, PaintInvalidationScroll);
|
| - return;
|
| - }
|
| - } else {
|
| - if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
|
| - layer->setNeedsDisplayInRect(rect, PaintInvalidationScroll);
|
| - return;
|
| - }
|
| - }
|
| -
|
| - IntRect scrollRect = rect;
|
| - // If we are not yet inserted into the tree, there is no need to issue paint invaldiations.
|
| - if (!box().isRenderView() && !box().parent())
|
| - return;
|
| -
|
| - if (scrollbar == m_vBar.get())
|
| - scrollRect.move(verticalScrollbarStart(0, box().size().width()), box().borderTop());
|
| - else
|
| - scrollRect.move(horizontalScrollbarStart(0), box().size().height() - box().borderBottom() - scrollbar->height());
|
| -
|
| - if (scrollRect.isEmpty())
|
| - return;
|
| -
|
| - LayoutRect paintInvalidationRect = scrollRect;
|
| - box().flipForWritingMode(paintInvalidationRect);
|
| -
|
| - IntRect intRect = pixelSnappedIntRect(paintInvalidationRect);
|
| -
|
| - if (box().frameView()->isInPerformLayout())
|
| - addScrollbarDamage(scrollbar, intRect);
|
| - else
|
| - box().invalidatePaintRectangle(intRect);
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::invalidateScrollCornerRect(const IntRect& rect)
|
| -{
|
| - if (GraphicsLayer* layer = layerForScrollCorner()) {
|
| - layer->setNeedsDisplayInRect(rect, PaintInvalidationScroll);
|
| - return;
|
| - }
|
| -
|
| - if (m_scrollCorner)
|
| - m_scrollCorner->invalidatePaintRectangle(rect);
|
| - if (m_resizer)
|
| - m_resizer->invalidatePaintRectangle(rect);
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::shouldUseIntegerScrollOffset() const
|
| -{
|
| - Frame* frame = box().frame();
|
| - if (frame->settings() && !frame->settings()->preferCompositingToLCDTextEnabled())
|
| - return true;
|
| - return false;
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::isActive() const
|
| -{
|
| - Page* page = box().frame()->page();
|
| - return page && page->focusController().isActive();
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::isScrollCornerVisible() const
|
| -{
|
| - return !scrollCornerRect().isEmpty();
|
| -}
|
| -
|
| -static int cornerStart(const RenderStyle* style, int minX, int maxX, int thickness)
|
| -{
|
| - if (style->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
|
| - return minX + style->borderLeftWidth();
|
| - return maxX - thickness - style->borderRightWidth();
|
| -}
|
| -
|
| -static IntRect cornerRect(const RenderStyle* style, const Scrollbar* horizontalScrollbar, const Scrollbar* verticalScrollbar, const IntRect& bounds)
|
| -{
|
| - int horizontalThickness;
|
| - int verticalThickness;
|
| - if (!verticalScrollbar && !horizontalScrollbar) {
|
| - // FIXME: This isn't right. We need to know the thickness of custom scrollbars
|
| - // even when they don't exist in order to set the resizer square size properly.
|
| - horizontalThickness = ScrollbarTheme::theme()->scrollbarThickness();
|
| - verticalThickness = horizontalThickness;
|
| - } else if (verticalScrollbar && !horizontalScrollbar) {
|
| - horizontalThickness = verticalScrollbar->width();
|
| - verticalThickness = horizontalThickness;
|
| - } else if (horizontalScrollbar && !verticalScrollbar) {
|
| - verticalThickness = horizontalScrollbar->height();
|
| - horizontalThickness = verticalThickness;
|
| - } else {
|
| - horizontalThickness = verticalScrollbar->width();
|
| - verticalThickness = horizontalScrollbar->height();
|
| - }
|
| - return IntRect(cornerStart(style, bounds.x(), bounds.maxX(), horizontalThickness),
|
| - bounds.maxY() - verticalThickness - style->borderBottomWidth(),
|
| - horizontalThickness, verticalThickness);
|
| -}
|
| -
|
| -
|
| -IntRect RenderLayerScrollableArea::scrollCornerRect() const
|
| -{
|
| - // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box.
|
| - // This happens when:
|
| - // (a) A resizer is present and at least one scrollbar is present
|
| - // (b) Both scrollbars are present.
|
| - bool hasHorizontalBar = horizontalScrollbar();
|
| - bool hasVerticalBar = verticalScrollbar();
|
| - bool hasResizer = box().style()->resize() != RESIZE_NONE;
|
| - if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
|
| - return cornerRect(box().style(), horizontalScrollbar(), verticalScrollbar(), box().pixelSnappedBorderBoxRect());
|
| - return IntRect();
|
| -}
|
| -
|
| -IntRect RenderLayerScrollableArea::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
|
| -{
|
| - RenderView* view = box().view();
|
| - if (!view)
|
| - return scrollbarRect;
|
| -
|
| - IntRect rect = scrollbarRect;
|
| - rect.move(scrollbarOffset(scrollbar));
|
| -
|
| - return view->frameView()->convertFromRenderer(box(), rect);
|
| -}
|
| -
|
| -IntRect RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
|
| -{
|
| - RenderView* view = box().view();
|
| - if (!view)
|
| - return parentRect;
|
| -
|
| - IntRect rect = view->frameView()->convertToRenderer(box(), parentRect);
|
| - rect.move(-scrollbarOffset(scrollbar));
|
| - return rect;
|
| -}
|
| -
|
| -IntPoint RenderLayerScrollableArea::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
|
| -{
|
| - RenderView* view = box().view();
|
| - if (!view)
|
| - return scrollbarPoint;
|
| -
|
| - IntPoint point = scrollbarPoint;
|
| - point.move(scrollbarOffset(scrollbar));
|
| - return view->frameView()->convertFromRenderer(box(), point);
|
| -}
|
| -
|
| -IntPoint RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
|
| -{
|
| - RenderView* view = box().view();
|
| - if (!view)
|
| - return parentPoint;
|
| -
|
| - IntPoint point = view->frameView()->convertToRenderer(box(), parentPoint);
|
| -
|
| - point.move(-scrollbarOffset(scrollbar));
|
| - return point;
|
| -}
|
| -
|
| -int RenderLayerScrollableArea::scrollSize(ScrollbarOrientation orientation) const
|
| -{
|
| - IntSize scrollDimensions = maximumScrollPosition() - minimumScrollPosition();
|
| - return (orientation == HorizontalScrollbar) ? scrollDimensions.width() : scrollDimensions.height();
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset)
|
| -{
|
| - setScrollOffset(DoublePoint(newScrollOffset));
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::setScrollOffset(const DoublePoint& newScrollOffset)
|
| -{
|
| - // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
|
| - if (m_scrollDimensionsDirty)
|
| - computeScrollDimensions();
|
| -
|
| - if (scrollOffset() == toDoubleSize(newScrollOffset))
|
| - return;
|
| -
|
| - m_scrollOffset = toDoubleSize(newScrollOffset);
|
| -
|
| - LocalFrame* frame = box().frame();
|
| - ASSERT(frame);
|
| -
|
| - RefPtrWillBeRawPtr<FrameView> frameView = box().frameView();
|
| -
|
| - TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ScrollLayer", "data", InspectorScrollLayerEvent::data(&box()));
|
| - // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
|
| - InspectorInstrumentation::willScrollLayer(&box());
|
| -
|
| - // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
|
| - // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
|
| - if (!frameView->isInPerformLayout()) {
|
| - // If we're in the middle of layout, we'll just update layers once layout has finished.
|
| - layer()->updateLayerPositionsAfterOverflowScroll();
|
| - // Update regions, scrolling may change the clip of a particular region.
|
| - frameView->updateAnnotatedRegions();
|
| - frameView->setNeedsUpdateWidgetPositions();
|
| - updateCompositingLayersAfterScroll();
|
| - }
|
| -
|
| - const RenderLayerModelObject* paintInvalidationContainer = box().containerForPaintInvalidation();
|
| - // The caret rect needs to be invalidated after scrolling
|
| - frame->selection().setCaretRectNeedsUpdate();
|
| -
|
| - FloatQuad quadForFakeMouseMoveEvent = FloatQuad(layer()->renderer()->previousPaintInvalidationRect());
|
| -
|
| - quadForFakeMouseMoveEvent = paintInvalidationContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
|
| - frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
|
| -
|
| - bool requiresPaintInvalidation = true;
|
| -
|
| - {
|
| - // FIXME(420741): Since scrolling depends on compositing state, the scroll should be
|
| - // deferred until after the compositing update.
|
| - DisableCompositingQueryAsserts disabler;
|
| - if (box().view()->compositor()->inCompositingMode()) {
|
| - bool onlyScrolledCompositedLayers = scrollsOverflow()
|
| - && !layer()->hasVisibleNonLayerContent()
|
| - && !layer()->hasNonCompositedChild()
|
| - && !layer()->hasBlockSelectionGapBounds()
|
| - && box().style()->backgroundLayers().attachment() != LocalBackgroundAttachment;
|
| -
|
| - if (usesCompositedScrolling() || onlyScrolledCompositedLayers)
|
| - requiresPaintInvalidation = false;
|
| - }
|
| - }
|
| -
|
| - // Just schedule a full paint invalidation of our object.
|
| - if (requiresPaintInvalidation)
|
| - box().setShouldDoFullPaintInvalidation();
|
| -
|
| - // Schedule the scroll DOM event.
|
| - if (box().node())
|
| - box().node()->document().enqueueScrollEventForNode(box().node());
|
| -
|
| - if (AXObjectCache* cache = box().document().existingAXObjectCache())
|
| - cache->handleScrollPositionChanged(&box());
|
| -
|
| - InspectorInstrumentation::didScrollLayer(&box());
|
| -}
|
| -
|
| -IntPoint RenderLayerScrollableArea::scrollPosition() const
|
| -{
|
| - return IntPoint(flooredIntSize(m_scrollOffset));
|
| -}
|
| -
|
| -DoublePoint RenderLayerScrollableArea::scrollPositionDouble() const
|
| -{
|
| - return DoublePoint(m_scrollOffset);
|
| -}
|
| -
|
| -IntPoint RenderLayerScrollableArea::minimumScrollPosition() const
|
| -{
|
| - return -scrollOrigin();
|
| -}
|
| -
|
| -IntPoint RenderLayerScrollableArea::maximumScrollPosition() const
|
| -{
|
| - if (!box().hasOverflowClip())
|
| - return -scrollOrigin();
|
| - return -scrollOrigin() + IntPoint(pixelSnappedScrollWidth(), pixelSnappedScrollHeight()) - enclosingIntRect(box().clientBoxRect()).size();
|
| -}
|
| -
|
| -IntRect RenderLayerScrollableArea::visibleContentRect(IncludeScrollbarsInRect scrollbarInclusion) const
|
| -{
|
| - int verticalScrollbarWidth = 0;
|
| - int horizontalScrollbarHeight = 0;
|
| - if (scrollbarInclusion == IncludeScrollbars) {
|
| - verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()) ? verticalScrollbar()->width() : 0;
|
| - horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0;
|
| - }
|
| -
|
| - return IntRect(IntPoint(scrollXOffset(), scrollYOffset()),
|
| - IntSize(max(0, layer()->size().width() - verticalScrollbarWidth), max(0, layer()->size().height() - horizontalScrollbarHeight)));
|
| -}
|
| -
|
| -int RenderLayerScrollableArea::visibleHeight() const
|
| -{
|
| - return layer()->size().height();
|
| -}
|
| -
|
| -int RenderLayerScrollableArea::visibleWidth() const
|
| -{
|
| - return layer()->size().width();
|
| -}
|
| -
|
| -IntSize RenderLayerScrollableArea::contentsSize() const
|
| -{
|
| - return IntSize(scrollWidth(), scrollHeight());
|
| -}
|
| -
|
| -IntSize RenderLayerScrollableArea::overhangAmount() const
|
| -{
|
| - return IntSize();
|
| -}
|
| -
|
| -IntPoint RenderLayerScrollableArea::lastKnownMousePosition() const
|
| -{
|
| - return box().frame() ? box().frame()->eventHandler().lastKnownMousePosition() : IntPoint();
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::shouldSuspendScrollAnimations() const
|
| -{
|
| - RenderView* view = box().view();
|
| - if (!view)
|
| - return true;
|
| - return view->frameView()->shouldSuspendScrollAnimations();
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::scrollbarsCanBeActive() const
|
| -{
|
| - RenderView* view = box().view();
|
| - if (!view)
|
| - return false;
|
| - return view->frameView()->scrollbarsCanBeActive();
|
| -}
|
| -
|
| -IntRect RenderLayerScrollableArea::scrollableAreaBoundingBox() const
|
| -{
|
| - return box().absoluteBoundingBoxRect();
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::registerForAnimation()
|
| -{
|
| - if (LocalFrame* frame = box().frame()) {
|
| - if (FrameView* frameView = frame->view())
|
| - frameView->addAnimatingScrollableArea(this);
|
| - }
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::deregisterForAnimation()
|
| -{
|
| - if (LocalFrame* frame = box().frame()) {
|
| - if (FrameView* frameView = frame->view())
|
| - frameView->removeAnimatingScrollableArea(this);
|
| - }
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::userInputScrollable(ScrollbarOrientation orientation) const
|
| -{
|
| - if (box().isIntristicallyScrollable(orientation))
|
| - return true;
|
| -
|
| - EOverflow overflowStyle = (orientation == HorizontalScrollbar) ?
|
| - box().style()->overflowX() : box().style()->overflowY();
|
| - return (overflowStyle == OSCROLL || overflowStyle == OAUTO || overflowStyle == OOVERLAY);
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::shouldPlaceVerticalScrollbarOnLeft() const
|
| -{
|
| - return box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft();
|
| -}
|
| -
|
| -int RenderLayerScrollableArea::pageStep(ScrollbarOrientation orientation) const
|
| -{
|
| - int length = (orientation == HorizontalScrollbar) ?
|
| - box().pixelSnappedClientWidth() : box().pixelSnappedClientHeight();
|
| - int minPageStep = static_cast<float>(length) * ScrollableArea::minFractionToStepWhenPaging();
|
| - int pageStep = max(minPageStep, length - ScrollableArea::maxOverlapBetweenPages());
|
| -
|
| - return max(pageStep, 1);
|
| -}
|
| -
|
| -RenderBox& RenderLayerScrollableArea::box() const
|
| -{
|
| - return *m_layer.renderBox();
|
| -}
|
| -
|
| -RenderLayer* RenderLayerScrollableArea::layer() const
|
| -{
|
| - return &m_layer;
|
| -}
|
| -
|
| -LayoutUnit RenderLayerScrollableArea::scrollWidth() const
|
| -{
|
| - if (m_scrollDimensionsDirty)
|
| - const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions();
|
| - return m_overflowRect.width();
|
| -}
|
| -
|
| -LayoutUnit RenderLayerScrollableArea::scrollHeight() const
|
| -{
|
| - if (m_scrollDimensionsDirty)
|
| - const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions();
|
| - return m_overflowRect.height();
|
| -}
|
| -
|
| -int RenderLayerScrollableArea::pixelSnappedScrollWidth() const
|
| -{
|
| - return snapSizeToPixel(scrollWidth(), box().clientLeft() + box().location().x());
|
| -}
|
| -
|
| -int RenderLayerScrollableArea::pixelSnappedScrollHeight() const
|
| -{
|
| - return snapSizeToPixel(scrollHeight(), box().clientTop() + box().location().y());
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::computeScrollDimensions()
|
| -{
|
| - m_scrollDimensionsDirty = false;
|
| -
|
| - m_overflowRect = box().layoutOverflowRect();
|
| - box().flipForWritingMode(m_overflowRect);
|
| -
|
| - int scrollableLeftOverflow = m_overflowRect.x() - box().borderLeft() - (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? box().verticalScrollbarWidth() : 0);
|
| - int scrollableTopOverflow = m_overflowRect.y() - box().borderTop();
|
| - setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow));
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::scrollToOffset(const DoubleSize& scrollOffset, ScrollOffsetClamping clamp, ScrollBehavior scrollBehavior)
|
| -{
|
| - cancelProgrammaticScrollAnimation();
|
| - DoubleSize newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset;
|
| - if (newScrollOffset != adjustedScrollOffset()) {
|
| - if (scrollBehavior == ScrollBehaviorAuto)
|
| - scrollBehavior = box().style()->scrollBehavior();
|
| - DoublePoint origin(scrollOrigin());
|
| - if (scrollBehavior == ScrollBehaviorSmooth) {
|
| - // FIXME: Make programmaticallyScrollSmoothlyToOffset take DoublePoint. crbug.com/243871.
|
| - programmaticallyScrollSmoothlyToOffset(toFloatPoint(-origin + newScrollOffset));
|
| - } else {
|
| - // FIXME: Make scrollToOffsetWithoutAnimation take DoublePoint. crbug.com/414283.
|
| - scrollToOffsetWithoutAnimation(toFloatPoint(-origin + newScrollOffset));
|
| - }
|
| - }
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::updateAfterLayout()
|
| -{
|
| - m_scrollDimensionsDirty = true;
|
| - DoubleSize 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).
|
| - DoubleSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset());
|
| - if (clampedScrollOffset != adjustedScrollOffset())
|
| - scrollToOffset(clampedScrollOffset);
|
| -
|
| - if (originalScrollOffset != adjustedScrollOffset()) {
|
| - DoublePoint origin(scrollOrigin());
|
| - scrollToOffsetWithoutAnimation(toFloatPoint(-origin + 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())
|
| - horizontalScrollbar()->setEnabled(hasHorizontalOverflow);
|
| - if (box().style()->overflowY() == OSCROLL && verticalScrollbar())
|
| - verticalScrollbar()->setEnabled(hasVerticalOverflow);
|
| - }
|
| - if (hasOverlayScrollbars()) {
|
| - if (!scrollSize(HorizontalScrollbar))
|
| - setHasHorizontalScrollbar(false);
|
| - if (!scrollSize(VerticalScrollbar))
|
| - setHasVerticalScrollbar(false);
|
| - }
|
| - // 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);
|
| -
|
| - if (hasVerticalOverflow || hasHorizontalOverflow)
|
| - updateScrollCornerStyle();
|
| -
|
| - layer()->updateSelfPaintingLayer();
|
| -
|
| - // Force an update since we know the scrollbars have changed things.
|
| - if (box().document().hasAnnotatedRegions())
|
| - box().document().setAnnotatedRegionsDirty(true);
|
| -
|
| - 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());
|
| - }
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::hasHorizontalOverflow() const
|
| -{
|
| - ASSERT(!m_scrollDimensionsDirty);
|
| -
|
| - return pixelSnappedScrollWidth() > box().pixelSnappedClientWidth();
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::hasVerticalOverflow() const
|
| -{
|
| - ASSERT(!m_scrollDimensionsDirty);
|
| -
|
| - return pixelSnappedScrollHeight() > box().pixelSnappedClientHeight();
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::hasScrollableHorizontalOverflow() const
|
| -{
|
| - return hasHorizontalOverflow() && box().scrollsOverflowX();
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::hasScrollableVerticalOverflow() const
|
| -{
|
| - return hasVerticalOverflow() && box().scrollsOverflowY();
|
| -}
|
| -
|
| -static bool overflowRequiresScrollbar(EOverflow overflow)
|
| -{
|
| - return overflow == OSCROLL;
|
| -}
|
| -
|
| -static bool overflowDefinesAutomaticScrollbar(EOverflow overflow)
|
| -{
|
| - return overflow == OAUTO || overflow == OOVERLAY;
|
| -}
|
| -
|
| -// This function returns true if the given box requires overflow scrollbars (as
|
| -// opposed to the 'viewport' scrollbars managed by the RenderLayerCompositor).
|
| -// FIXME: we should use the same scrolling machinery for both the viewport and
|
| -// overflow. Currently, we need to avoid producing scrollbars here if they'll be
|
| -// handled externally in the RLC.
|
| -static bool canHaveOverflowScrollbars(const RenderBox& box)
|
| -{
|
| - bool rootLayerScrolls = box.document().settings() && box.document().settings()->rootLayerScrolls();
|
| - return (rootLayerScrolls || !box.isRenderView()) && box.document().viewportDefiningElement() != box.node();
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::updateAfterStyleChange(const RenderStyle* oldStyle)
|
| -{
|
| - if (!m_scrollDimensionsDirty)
|
| - updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
|
| -
|
| - if (!canHaveOverflowScrollbars(box()))
|
| - return;
|
| -
|
| - EOverflow overflowX = box().style()->overflowX();
|
| - EOverflow overflowY = box().style()->overflowY();
|
| -
|
| - // To avoid doing a relayout in updateScrollbarsAfterLayout, we try to keep any automatic scrollbar that was already present.
|
| - bool needsHorizontalScrollbar = (hasHorizontalScrollbar() && overflowDefinesAutomaticScrollbar(overflowX)) || overflowRequiresScrollbar(overflowX);
|
| - bool needsVerticalScrollbar = (hasVerticalScrollbar() && overflowDefinesAutomaticScrollbar(overflowY)) || overflowRequiresScrollbar(overflowY);
|
| - setHasHorizontalScrollbar(needsHorizontalScrollbar);
|
| - setHasVerticalScrollbar(needsVerticalScrollbar);
|
| -
|
| - // With overflow: scroll, scrollbars are always visible but may be disabled.
|
| - // When switching to another value, we need to re-enable them (see bug 11985).
|
| - if (needsHorizontalScrollbar && oldStyle && oldStyle->overflowX() == OSCROLL && overflowX != OSCROLL) {
|
| - ASSERT(hasHorizontalScrollbar());
|
| - m_hBar->setEnabled(true);
|
| - }
|
| -
|
| - if (needsVerticalScrollbar && oldStyle && oldStyle->overflowY() == OSCROLL && overflowY != OSCROLL) {
|
| - ASSERT(hasVerticalScrollbar());
|
| - m_vBar->setEnabled(true);
|
| - }
|
| -
|
| - // FIXME: Need to detect a swap from custom to native scrollbars (and vice versa).
|
| - if (m_hBar)
|
| - m_hBar->styleChanged();
|
| - if (m_vBar)
|
| - m_vBar->styleChanged();
|
| -
|
| - updateScrollCornerStyle();
|
| - updateResizerAreaSet();
|
| - updateResizerStyle();
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::updateAfterCompositingChange()
|
| -{
|
| - layer()->updateScrollingStateAfterCompositingChange();
|
| - const bool layersChanged = m_topmostScrollChild != m_nextTopmostScrollChild;
|
| - m_topmostScrollChild = m_nextTopmostScrollChild;
|
| - m_nextTopmostScrollChild = nullptr;
|
| - return layersChanged;
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::updateAfterOverflowRecalc()
|
| -{
|
| - computeScrollDimensions();
|
| - 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 hasHorizontalOverflow = this->hasHorizontalOverflow();
|
| - bool hasVerticalOverflow = this->hasVerticalOverflow();
|
| - bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
|
| - bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow);
|
| - if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged)
|
| - box().setNeedsLayoutAndFullPaintInvalidation();
|
| -}
|
| -
|
| -DoubleSize RenderLayerScrollableArea::clampScrollOffset(const DoubleSize& scrollOffset) const
|
| -{
|
| - int maxX = scrollWidth() - box().pixelSnappedClientWidth();
|
| - int maxY = scrollHeight() - box().pixelSnappedClientHeight();
|
| -
|
| - double x = std::max(std::min(scrollOffset.width(), static_cast<double>(maxX)), 0.0);
|
| - double y = std::max(std::min(scrollOffset.height(), static_cast<double>(maxY)), 0.0);
|
| - return DoubleSize(x, y);
|
| -}
|
| -
|
| -IntRect RenderLayerScrollableArea::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const
|
| -{
|
| - if (!m_hBar)
|
| - return IntRect();
|
| -
|
| - const IntRect& scrollCorner = scrollCornerRect();
|
| -
|
| - return IntRect(horizontalScrollbarStart(borderBoxRect.x()),
|
| - borderBoxRect.maxY() - box().borderBottom() - m_hBar->height(),
|
| - borderBoxRect.width() - (box().borderLeft() + box().borderRight()) - scrollCorner.width(),
|
| - m_hBar->height());
|
| -}
|
| -
|
| -IntRect RenderLayerScrollableArea::rectForVerticalScrollbar(const IntRect& borderBoxRect) const
|
| -{
|
| - if (!m_vBar)
|
| - return IntRect();
|
| -
|
| - const IntRect& scrollCorner = scrollCornerRect();
|
| -
|
| - return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()),
|
| - borderBoxRect.y() + box().borderTop(),
|
| - m_vBar->width(),
|
| - borderBoxRect.height() - (box().borderTop() + box().borderBottom()) - scrollCorner.height());
|
| -}
|
| -
|
| -LayoutUnit RenderLayerScrollableArea::verticalScrollbarStart(int minX, int maxX) const
|
| -{
|
| - if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
|
| - return minX + box().borderLeft();
|
| - return maxX - box().borderRight() - m_vBar->width();
|
| -}
|
| -
|
| -LayoutUnit RenderLayerScrollableArea::horizontalScrollbarStart(int minX) const
|
| -{
|
| - int x = minX + box().borderLeft();
|
| - if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
|
| - x += m_vBar ? m_vBar->width() : resizerCornerRect(box().pixelSnappedBorderBoxRect(), ResizerForPointer).width();
|
| - return x;
|
| -}
|
| -
|
| -IntSize RenderLayerScrollableArea::scrollbarOffset(const Scrollbar* scrollbar) const
|
| -{
|
| - if (scrollbar == m_vBar.get())
|
| - return IntSize(verticalScrollbarStart(0, box().size().width()), box().borderTop());
|
| -
|
| - if (scrollbar == m_hBar.get())
|
| - return IntSize(horizontalScrollbarStart(0), box().size().height() - box().borderBottom() - scrollbar->height());
|
| -
|
| - ASSERT_NOT_REACHED();
|
| - return IntSize();
|
| -}
|
| -
|
| -static inline RenderObject* rendererForScrollbar(RenderObject& renderer)
|
| -{
|
| - if (Node* node = renderer.node()) {
|
| - if (ShadowRoot* shadowRoot = node->containingShadowRoot()) {
|
| - if (shadowRoot->type() == ShadowRoot::UserAgentShadowRoot)
|
| - return shadowRoot->host()->renderer();
|
| - }
|
| - }
|
| -
|
| - return &renderer;
|
| -}
|
| -
|
| -PassRefPtrWillBeRawPtr<Scrollbar> RenderLayerScrollableArea::createScrollbar(ScrollbarOrientation orientation)
|
| -{
|
| - RefPtrWillBeRawPtr<Scrollbar> widget = nullptr;
|
| - RenderObject* actualRenderer = rendererForScrollbar(box());
|
| - bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR);
|
| - if (hasCustomScrollbarStyle) {
|
| - widget = RenderScrollbar::createCustomScrollbar(this, orientation, actualRenderer->node());
|
| - } else {
|
| - ScrollbarControlSize scrollbarSize = RegularScrollbar;
|
| - if (actualRenderer->style()->hasAppearance())
|
| - scrollbarSize = LayoutTheme::theme().scrollbarControlSizeForPart(actualRenderer->style()->appearance());
|
| - widget = Scrollbar::create(this, orientation, scrollbarSize);
|
| - if (orientation == HorizontalScrollbar)
|
| - didAddScrollbar(widget.get(), HorizontalScrollbar);
|
| - else
|
| - didAddScrollbar(widget.get(), VerticalScrollbar);
|
| - }
|
| - box().document().view()->addChild(widget.get());
|
| - return widget.release();
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::destroyScrollbar(ScrollbarOrientation orientation)
|
| -{
|
| - RefPtrWillBePersistent<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
|
| - if (!scrollbar)
|
| - return;
|
| -
|
| - if (!scrollbar->isCustomScrollbar())
|
| - willRemoveScrollbar(scrollbar.get(), orientation);
|
| -
|
| - toFrameView(scrollbar->parent())->removeChild(scrollbar.get());
|
| - scrollbar->disconnectFromScrollableArea();
|
| - scrollbar = nullptr;
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar)
|
| -{
|
| - if (hasScrollbar == hasHorizontalScrollbar())
|
| - return;
|
| -
|
| - if (hasScrollbar) {
|
| - // This doesn't hit in any tests, but since the equivalent code in setHasVerticalScrollbar
|
| - // does, presumably this code does as well.
|
| - DisableCompositingQueryAsserts disabler;
|
| - m_hBar = createScrollbar(HorizontalScrollbar);
|
| - } else {
|
| - if (!layerForHorizontalScrollbar())
|
| - m_hBar->invalidate();
|
| - // Otherwise we will remove the layer and just need recompositing.
|
| -
|
| - destroyScrollbar(HorizontalScrollbar);
|
| - }
|
| -
|
| - // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
|
| - if (m_hBar)
|
| - m_hBar->styleChanged();
|
| - if (m_vBar)
|
| - m_vBar->styleChanged();
|
| -
|
| - // Force an update since we know the scrollbars have changed things.
|
| - if (box().document().hasAnnotatedRegions())
|
| - box().document().setAnnotatedRegionsDirty(true);
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::setHasVerticalScrollbar(bool hasScrollbar)
|
| -{
|
| - if (hasScrollbar == hasVerticalScrollbar())
|
| - return;
|
| -
|
| - if (hasScrollbar) {
|
| - // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html
|
| - DisableCompositingQueryAsserts disabler;
|
| - m_vBar = createScrollbar(VerticalScrollbar);
|
| - } else {
|
| - if (!layerForVerticalScrollbar())
|
| - m_vBar->invalidate();
|
| - // Otherwise we will remove the layer and just need recompositing.
|
| -
|
| - destroyScrollbar(VerticalScrollbar);
|
| - }
|
| -
|
| - // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
|
| - if (m_hBar)
|
| - m_hBar->styleChanged();
|
| - if (m_vBar)
|
| - m_vBar->styleChanged();
|
| -
|
| - // Force an update since we know the scrollbars have changed things.
|
| - if (box().document().hasAnnotatedRegions())
|
| - box().document().setAnnotatedRegionsDirty(true);
|
| -}
|
| -
|
| -int RenderLayerScrollableArea::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
|
| -{
|
| - if (!m_vBar || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_vBar->shouldParticipateInHitTesting())))
|
| - return 0;
|
| - return m_vBar->width();
|
| -}
|
| -
|
| -int RenderLayerScrollableArea::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
|
| -{
|
| - if (!m_hBar || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_hBar->shouldParticipateInHitTesting())))
|
| - return 0;
|
| - return m_hBar->height();
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::positionOverflowControls(const IntSize& offsetFromRoot)
|
| -{
|
| - if (!hasScrollbar() && !box().canResize())
|
| - return;
|
| -
|
| - const IntRect borderBox = box().pixelSnappedBorderBoxRect();
|
| - if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) {
|
| - IntRect vBarRect = rectForVerticalScrollbar(borderBox);
|
| - vBarRect.move(offsetFromRoot);
|
| - verticalScrollbar->setFrameRect(vBarRect);
|
| - }
|
| -
|
| - if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) {
|
| - IntRect hBarRect = rectForHorizontalScrollbar(borderBox);
|
| - hBarRect.move(offsetFromRoot);
|
| - horizontalScrollbar->setFrameRect(hBarRect);
|
| - }
|
| -
|
| - const IntRect& scrollCorner = scrollCornerRect();
|
| - if (m_scrollCorner)
|
| - m_scrollCorner->setFrameRect(scrollCorner);
|
| -
|
| - if (m_resizer)
|
| - m_resizer->setFrameRect(resizerCornerRect(borderBox, ResizerForPointer));
|
| -
|
| - // FIXME, this should eventually be removed, once we are certain that composited
|
| - // controls get correctly positioned on a compositor update. For now, conservatively
|
| - // leaving this unchanged.
|
| - if (layer()->hasCompositedLayerMapping())
|
| - layer()->compositedLayerMapping()->positionOverflowControlsLayers(offsetFromRoot);
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::updateScrollCornerStyle()
|
| -{
|
| - if (!m_scrollCorner && !hasScrollbar())
|
| - return;
|
| - if (!m_scrollCorner && hasOverlayScrollbars())
|
| - return;
|
| -
|
| - RenderObject* actualRenderer = rendererForScrollbar(box());
|
| - RefPtr<RenderStyle> corner = box().hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), actualRenderer->style()) : PassRefPtr<RenderStyle>(nullptr);
|
| - if (corner) {
|
| - if (!m_scrollCorner) {
|
| - m_scrollCorner = RenderScrollbarPart::createAnonymous(&box().document());
|
| - m_scrollCorner->setParent(&box());
|
| - }
|
| - m_scrollCorner->setStyle(corner.release());
|
| - } else if (m_scrollCorner) {
|
| - m_scrollCorner->destroy();
|
| - m_scrollCorner = nullptr;
|
| - }
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint)
|
| -{
|
| - if (!hasScrollbar() && !box().canResize())
|
| - return false;
|
| -
|
| - IntRect resizeControlRect;
|
| - if (box().style()->resize() != RESIZE_NONE) {
|
| - resizeControlRect = resizerCornerRect(box().pixelSnappedBorderBoxRect(), ResizerForPointer);
|
| - if (resizeControlRect.contains(localPoint))
|
| - return true;
|
| - }
|
| -
|
| - int resizeControlSize = max(resizeControlRect.height(), 0);
|
| - if (m_vBar && m_vBar->shouldParticipateInHitTesting()) {
|
| - LayoutRect vBarRect(verticalScrollbarStart(0, box().size().width()),
|
| - box().borderTop(),
|
| - m_vBar->width(),
|
| - box().size().height() - (box().borderTop() + box().borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
|
| - if (vBarRect.contains(localPoint)) {
|
| - result.setScrollbar(m_vBar.get());
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - resizeControlSize = max(resizeControlRect.width(), 0);
|
| - if (m_hBar && m_hBar->shouldParticipateInHitTesting()) {
|
| - LayoutRect hBarRect(horizontalScrollbarStart(0),
|
| - box().size().height() - box().borderBottom() - m_hBar->height(),
|
| - box().size().width() - (box().borderLeft() + box().borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
|
| - m_hBar->height());
|
| - if (hBarRect.contains(localPoint)) {
|
| - result.setScrollbar(m_hBar.get());
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - // FIXME: We should hit test the m_scrollCorner and pass it back through the result.
|
| -
|
| - return false;
|
| -}
|
| -
|
| -IntRect RenderLayerScrollableArea::resizerCornerRect(const IntRect& bounds, ResizerHitTestType resizerHitTestType) const
|
| -{
|
| - if (box().style()->resize() == RESIZE_NONE)
|
| - return IntRect();
|
| - IntRect corner = cornerRect(box().style(), horizontalScrollbar(), verticalScrollbar(), bounds);
|
| -
|
| - if (resizerHitTestType == ResizerForTouch) {
|
| - // We make the resizer virtually larger for touch hit testing. With the
|
| - // expanding ratio k = ResizerControlExpandRatioForTouch, we first move
|
| - // the resizer rect (of width w & height h), by (-w * (k-1), -h * (k-1)),
|
| - // then expand the rect by new_w/h = w/h * k.
|
| - int expandRatio = ResizerControlExpandRatioForTouch - 1;
|
| - corner.move(-corner.width() * expandRatio, -corner.height() * expandRatio);
|
| - corner.expand(corner.width() * expandRatio, corner.height() * expandRatio);
|
| - }
|
| -
|
| - return corner;
|
| -}
|
| -
|
| -IntRect RenderLayerScrollableArea::scrollCornerAndResizerRect() const
|
| -{
|
| - IntRect scrollCornerAndResizer = scrollCornerRect();
|
| - if (scrollCornerAndResizer.isEmpty())
|
| - scrollCornerAndResizer = resizerCornerRect(box().pixelSnappedBorderBoxRect(), ResizerForPointer);
|
| - return scrollCornerAndResizer;
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::isPointInResizeControl(const IntPoint& absolutePoint, ResizerHitTestType resizerHitTestType) const
|
| -{
|
| - if (!box().canResize())
|
| - return false;
|
| -
|
| - IntPoint localPoint = roundedIntPoint(box().absoluteToLocal(absolutePoint, UseTransforms));
|
| - IntRect localBounds(0, 0, box().pixelSnappedWidth(), box().pixelSnappedHeight());
|
| - return resizerCornerRect(localBounds, resizerHitTestType).contains(localPoint);
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::hitTestResizerInFragments(const LayerFragments& layerFragments, const HitTestLocation& hitTestLocation) const
|
| -{
|
| - if (!box().canResize())
|
| - return false;
|
| -
|
| - if (layerFragments.isEmpty())
|
| - return false;
|
| -
|
| - for (int i = layerFragments.size() - 1; i >= 0; --i) {
|
| - const LayerFragment& fragment = layerFragments.at(i);
|
| - if (fragment.backgroundRect.intersects(hitTestLocation) && resizerCornerRect(pixelSnappedIntRect(fragment.layerBounds), ResizerForPointer).contains(hitTestLocation.roundedPoint()))
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::updateResizerAreaSet()
|
| -{
|
| - LocalFrame* frame = box().frame();
|
| - if (!frame)
|
| - return;
|
| - FrameView* frameView = frame->view();
|
| - if (!frameView)
|
| - return;
|
| - if (box().canResize())
|
| - frameView->addResizerArea(box());
|
| - else
|
| - frameView->removeResizerArea(box());
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::updateResizerStyle()
|
| -{
|
| - if (!m_resizer && !box().canResize())
|
| - return;
|
| -
|
| - RenderObject* actualRenderer = rendererForScrollbar(box());
|
| - RefPtr<RenderStyle> resizer = box().hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(RESIZER), actualRenderer->style()) : PassRefPtr<RenderStyle>(nullptr);
|
| - if (resizer) {
|
| - if (!m_resizer) {
|
| - m_resizer = RenderScrollbarPart::createAnonymous(&box().document());
|
| - m_resizer->setParent(&box());
|
| - }
|
| - m_resizer->setStyle(resizer.release());
|
| - } else if (m_resizer) {
|
| - m_resizer->destroy();
|
| - m_resizer = nullptr;
|
| - }
|
| -}
|
| -
|
| -IntSize RenderLayerScrollableArea::offsetFromResizeCorner(const IntPoint& absolutePoint) const
|
| -{
|
| - // Currently the resize corner is either the bottom right corner or the bottom left corner.
|
| - // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
|
| - IntSize elementSize = layer()->size();
|
| - if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
|
| - elementSize.setWidth(0);
|
| - IntPoint resizerPoint = IntPoint(elementSize);
|
| - IntPoint localPoint = roundedIntPoint(box().absoluteToLocal(absolutePoint, UseTransforms));
|
| - return localPoint - resizerPoint;
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::resize(const PlatformEvent& evt, const LayoutSize& oldOffset)
|
| -{
|
| - // FIXME: This should be possible on generated content but is not right now.
|
| - if (!inResizeMode() || !box().canResize() || !box().node())
|
| - return;
|
| -
|
| - ASSERT(box().node()->isElementNode());
|
| - Element* element = toElement(box().node());
|
| -
|
| - Document& document = element->document();
|
| -
|
| - IntPoint pos;
|
| - const PlatformGestureEvent* gevt = 0;
|
| -
|
| - switch (evt.type()) {
|
| - case PlatformEvent::MouseMoved:
|
| - if (!document.frame()->eventHandler().mousePressed())
|
| - return;
|
| - pos = static_cast<const PlatformMouseEvent*>(&evt)->position();
|
| - break;
|
| - case PlatformEvent::GestureScrollUpdate:
|
| - pos = static_cast<const PlatformGestureEvent*>(&evt)->position();
|
| - gevt = static_cast<const PlatformGestureEvent*>(&evt);
|
| - pos = gevt->position();
|
| - pos.move(gevt->deltaX(), gevt->deltaY());
|
| - break;
|
| - default:
|
| - ASSERT_NOT_REACHED();
|
| - }
|
| -
|
| - float zoomFactor = box().style()->effectiveZoom();
|
| -
|
| - IntSize newOffset = offsetFromResizeCorner(document.view()->windowToContents(pos));
|
| - newOffset.setWidth(newOffset.width() / zoomFactor);
|
| - newOffset.setHeight(newOffset.height() / zoomFactor);
|
| -
|
| - LayoutSize currentSize = box().size();
|
| - currentSize.scale(1 / zoomFactor);
|
| - LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
|
| - element->setMinimumSizeForResizing(minimumSize);
|
| -
|
| - LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
|
| - if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
|
| - newOffset.setWidth(-newOffset.width());
|
| - adjustedOldOffset.setWidth(-adjustedOldOffset.width());
|
| - }
|
| -
|
| - LayoutSize difference((currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize);
|
| -
|
| - bool isBoxSizingBorder = box().style()->boxSizing() == BORDER_BOX;
|
| -
|
| - EResize resize = box().style()->resize();
|
| - if (resize != RESIZE_VERTICAL && difference.width()) {
|
| - if (element->isFormControlElement()) {
|
| - // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
|
| - element->setInlineStyleProperty(CSSPropertyMarginLeft, box().marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX);
|
| - element->setInlineStyleProperty(CSSPropertyMarginRight, box().marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX);
|
| - }
|
| - LayoutUnit baseWidth = box().size().width() - (isBoxSizingBorder ? LayoutUnit() : box().borderAndPaddingWidth());
|
| - baseWidth = baseWidth / zoomFactor;
|
| - element->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX);
|
| - }
|
| -
|
| - if (resize != RESIZE_HORIZONTAL && difference.height()) {
|
| - if (element->isFormControlElement()) {
|
| - // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
|
| - element->setInlineStyleProperty(CSSPropertyMarginTop, box().marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX);
|
| - element->setInlineStyleProperty(CSSPropertyMarginBottom, box().marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX);
|
| - }
|
| - LayoutUnit baseHeight = box().size().height() - (isBoxSizingBorder ? LayoutUnit() : box().borderAndPaddingHeight());
|
| - baseHeight = baseHeight / zoomFactor;
|
| - element->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX);
|
| - }
|
| -
|
| - document.updateLayout();
|
| -
|
| - // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
|
| -}
|
| -
|
| -LayoutRect RenderLayerScrollableArea::exposeRect(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
|
| -{
|
| - LayoutRect localExposeRect(box().absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox());
|
| - localExposeRect.move(-box().borderLeft(), -box().borderTop());
|
| - LayoutRect layerBounds(0, 0, box().clientWidth(), box().clientHeight());
|
| - LayoutRect r = ScrollAlignment::getRectToExpose(layerBounds, localExposeRect, alignX, alignY);
|
| -
|
| - DoubleSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset() + roundedIntSize(r.location()));
|
| - if (clampedScrollOffset == adjustedScrollOffset())
|
| - return rect;
|
| -
|
| - DoubleSize oldScrollOffset = adjustedScrollOffset();
|
| - scrollToOffset(clampedScrollOffset);
|
| - DoubleSize scrollOffsetDifference = adjustedScrollOffset() - oldScrollOffset;
|
| - localExposeRect.move(-LayoutSize(scrollOffsetDifference));
|
| - return LayoutRect(box().localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox());
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::updateScrollableAreaSet(bool hasOverflow)
|
| -{
|
| - LocalFrame* frame = box().frame();
|
| - if (!frame)
|
| - return;
|
| -
|
| - FrameView* frameView = frame->view();
|
| - if (!frameView)
|
| - return;
|
| -
|
| - // FIXME: Does this need to be fixed later for OOPI?
|
| - bool isVisibleToHitTest = box().visibleToHitTesting();
|
| - if (HTMLFrameOwnerElement* owner = frame->deprecatedLocalOwner())
|
| - isVisibleToHitTest &= owner->renderer() && owner->renderer()->visibleToHitTesting();
|
| -
|
| - bool didScrollOverflow = m_scrollsOverflow;
|
| -
|
| - m_scrollsOverflow = hasOverflow && isVisibleToHitTest;
|
| - if (didScrollOverflow == scrollsOverflow())
|
| - return;
|
| -
|
| - if (m_scrollsOverflow) {
|
| - ASSERT(canHaveOverflowScrollbars(box()));
|
| - frameView->addScrollableArea(this);
|
| - } else
|
| - frameView->removeScrollableArea(this);
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::updateCompositingLayersAfterScroll()
|
| -{
|
| - DisableCompositingQueryAsserts disabler;
|
| - RenderLayerCompositor* compositor = box().view()->compositor();
|
| - if (compositor->inCompositingMode()) {
|
| - if (usesCompositedScrolling()) {
|
| - ASSERT(layer()->hasCompositedLayerMapping());
|
| - layer()->compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
|
| - compositor->setNeedsCompositingUpdate(CompositingUpdateAfterGeometryChange);
|
| - } else {
|
| - layer()->setNeedsCompositingInputsUpdate();
|
| - }
|
| - }
|
| -}
|
| -
|
| -bool RenderLayerScrollableArea::usesCompositedScrolling() const
|
| -{
|
| - // Scroll form controls on the main thread so they exhibit correct touch scroll event bubbling
|
| - if (box().isIntristicallyScrollable(VerticalScrollbar) || box().isIntristicallyScrollable(HorizontalScrollbar))
|
| - return false;
|
| -
|
| - // See https://codereview.chromium.org/176633003/ for the tests that fail without this disabler.
|
| - DisableCompositingQueryAsserts disabler;
|
| - return layer()->hasCompositedLayerMapping() && layer()->compositedLayerMapping()->scrollingLayer();
|
| -}
|
| -
|
| -static bool layerNeedsCompositedScrolling(RenderLayerScrollableArea::LCDTextMode mode, const RenderLayer* layer)
|
| -{
|
| - if (mode == RenderLayerScrollableArea::ConsiderLCDText && !layer->compositor()->preferCompositingToLCDTextEnabled())
|
| - return false;
|
| -
|
| - return layer->scrollsOverflow()
|
| - && !layer->hasDescendantWithClipPath()
|
| - && !layer->hasAncestorWithClipPath()
|
| - && !layer->renderer()->style()->hasBorderRadius();
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::updateNeedsCompositedScrolling(LCDTextMode mode)
|
| -{
|
| - const bool needsCompositedScrolling = layerNeedsCompositedScrolling(mode, layer());
|
| - if (static_cast<bool>(m_needsCompositedScrolling) != needsCompositedScrolling) {
|
| - m_needsCompositedScrolling = needsCompositedScrolling;
|
| - layer()->didUpdateNeedsCompositedScrolling();
|
| - }
|
| -}
|
| -
|
| -void RenderLayerScrollableArea::setTopmostScrollChild(RenderLayer* scrollChild)
|
| -{
|
| - // We only want to track the topmost scroll child for scrollable areas with
|
| - // overlay scrollbars.
|
| - if (!hasOverlayScrollbars())
|
| - return;
|
| - m_nextTopmostScrollChild = scrollChild;
|
| -}
|
| -
|
| -} // namespace blink
|
|
|