diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.cpp')
-rw-r--r-- | chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.cpp | 715 |
1 files changed, 350 insertions, 365 deletions
diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.cpp index 0486111467d..b9512464833 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.cpp @@ -47,20 +47,21 @@ #include "core/css/PseudoStyleRequest.h" #include "core/dom/shadow/ShadowRoot.h" #include "core/editing/FrameSelection.h" +#include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/html/HTMLFrameOwnerElement.h" #include "core/inspector/InspectorInstrumentation.h" +#include "core/inspector/InspectorTraceEvents.h" #include "core/page/EventHandler.h" #include "core/page/FocusController.h" -#include "core/frame/Frame.h" -#include "core/frame/FrameView.h" #include "core/page/Page.h" #include "core/page/scrolling/ScrollingCoordinator.h" -#include "core/rendering/CompositedLayerMapping.h" #include "core/rendering/RenderGeometryMap.h" -#include "core/rendering/RenderLayerCompositor.h" #include "core/rendering/RenderScrollbar.h" #include "core/rendering/RenderScrollbarPart.h" #include "core/rendering/RenderView.h" +#include "core/rendering/compositing/CompositedLayerMapping.h" +#include "core/rendering/compositing/RenderLayerCompositor.h" #include "platform/PlatformGestureEvent.h" #include "platform/PlatformMouseEvent.h" #include "platform/graphics/GraphicsContextStateSaver.h" @@ -73,21 +74,18 @@ namespace WebCore { const int ResizerControlExpandRatioForTouch = 2; -RenderLayerScrollableArea::RenderLayerScrollableArea(RenderBox* box) - : m_box(box) +RenderLayerScrollableArea::RenderLayerScrollableArea(RenderLayer& layer) + : m_layer(layer) , m_inResizeMode(false) + , m_scrollsOverflow(false) , m_scrollDimensionsDirty(true) , m_inOverflowRelayout(false) - , m_needsCompositedScrolling(false) - , m_willUseCompositedScrollingHasBeenRecorded(false) - , m_isScrollableAreaHasBeenRecorded(false) - , m_forceNeedsCompositedScrolling(DoNotForceCompositedScrolling) , m_scrollCorner(0) , m_resizer(0) { ScrollableArea::setConstrainsScrollingToContentEdge(false); - Node* node = m_box->node(); + 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); @@ -102,31 +100,31 @@ RenderLayerScrollableArea::RenderLayerScrollableArea(RenderBox* box) RenderLayerScrollableArea::~RenderLayerScrollableArea() { - if (inResizeMode() && !m_box->documentBeingDestroyed()) { - if (Frame* frame = m_box->frame()) + if (inResizeMode() && !box().documentBeingDestroyed()) { + if (LocalFrame* frame = box().frame()) frame->eventHandler().resizeScrollableAreaDestroyed(); } - if (Frame* frame = m_box->frame()) { + if (LocalFrame* frame = box().frame()) { if (FrameView* frameView = frame->view()) { frameView->removeScrollableArea(this); } } - if (m_box->frame() && m_box->frame()->page()) { - if (ScrollingCoordinator* scrollingCoordinator = m_box->frame()->page()->scrollingCoordinator()) + if (box().frame() && box().frame()->page()) { + if (ScrollingCoordinator* scrollingCoordinator = box().frame()->page()->scrollingCoordinator()) scrollingCoordinator->willDestroyScrollableArea(this); } - if (!m_box->documentBeingDestroyed()) { - Node* node = m_box->node(); + if (!box().documentBeingDestroyed()) { + Node* node = box().node(); if (node && node->isElementNode()) toElement(node)->setSavedLayerScrollOffset(m_scrollOffset); } - if (Frame* frame = m_box->frame()) { + if (LocalFrame* frame = box().frame()) { if (FrameView* frameView = frame->view()) - frameView->removeResizerArea(m_box); + frameView->removeResizerArea(box()); } destroyScrollbar(HorizontalScrollbar); @@ -138,38 +136,40 @@ RenderLayerScrollableArea::~RenderLayerScrollableArea() m_resizer->destroy(); } -ScrollableArea* RenderLayerScrollableArea::enclosingScrollableArea() const -{ - if (RenderBox* enclosingScrollableBox = m_box->enclosingScrollableBox()) - return enclosingScrollableBox->layer()->scrollableArea(); - - // FIXME: We should return the frame view here (or possibly an ancestor frame view, - // if the frame view isn't scrollable. - return 0; -} - GraphicsLayer* RenderLayerScrollableArea::layerForScrolling() const { - return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->scrollingContentsLayer() : 0; + return box().hasCompositedLayerMapping() ? box().compositedLayerMapping()->scrollingContentsLayer() : 0; } GraphicsLayer* RenderLayerScrollableArea::layerForHorizontalScrollbar() const { - return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->layerForHorizontalScrollbar() : 0; + // See crbug.com/343132. + DisableCompositingQueryAsserts disabler; + + return box().hasCompositedLayerMapping() ? box().compositedLayerMapping()->layerForHorizontalScrollbar() : 0; } GraphicsLayer* RenderLayerScrollableArea::layerForVerticalScrollbar() const { - return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->layerForVerticalScrollbar() : 0; + // See crbug.com/343132. + DisableCompositingQueryAsserts disabler; + + return box().hasCompositedLayerMapping() ? box().compositedLayerMapping()->layerForVerticalScrollbar() : 0; } GraphicsLayer* RenderLayerScrollableArea::layerForScrollCorner() const { - return m_box->hasCompositedLayerMapping() ? m_box->compositedLayerMapping()->layerForScrollCorner() : 0; + // See crbug.com/343132. + DisableCompositingQueryAsserts disabler; + + return box().hasCompositedLayerMapping() ? box().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); @@ -184,14 +184,34 @@ void RenderLayerScrollableArea::invalidateScrollbarRect(Scrollbar* scrollbar, co IntRect scrollRect = rect; // If we are not yet inserted into the tree, there is no need to repaint. - if (!m_box->parent()) + if (!box().parent()) return; if (scrollbar == m_vBar.get()) - scrollRect.move(verticalScrollbarStart(0, m_box->width()), m_box->borderTop()); + scrollRect.move(verticalScrollbarStart(0, box().width()), box().borderTop()); else - scrollRect.move(horizontalScrollbarStart(0), m_box->height() - m_box->borderBottom() - scrollbar->height()); - m_box->repaintRectangle(scrollRect); + scrollRect.move(horizontalScrollbarStart(0), box().height() - box().borderBottom() - scrollbar->height()); + + if (scrollRect.isEmpty()) + return; + + LayoutRect repaintRect = scrollRect; + box().flipForWritingMode(repaintRect); + + IntRect intRect = pixelSnappedIntRect(repaintRect); + + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && box().frameView()->isInPerformLayout()) { + if (scrollbar == m_vBar.get()) { + m_verticalBarDamage = intRect; + m_hasVerticalBarDamage = true; + } else { + m_horizontalBarDamage = intRect; + m_hasHorizontalBarDamage = true; + } + + } else { + box().invalidatePaintRectangle(intRect); + } } void RenderLayerScrollableArea::invalidateScrollCornerRect(const IntRect& rect) @@ -202,14 +222,14 @@ void RenderLayerScrollableArea::invalidateScrollCornerRect(const IntRect& rect) } if (m_scrollCorner) - m_scrollCorner->repaintRectangle(rect); + m_scrollCorner->invalidatePaintRectangle(rect); if (m_resizer) - m_resizer->repaintRectangle(rect); + m_resizer->invalidatePaintRectangle(rect); } bool RenderLayerScrollableArea::isActive() const { - Page* page = m_box->frame()->page(); + Page* page = box().frame()->page(); return page && page->focusController().isActive(); } @@ -258,53 +278,53 @@ IntRect RenderLayerScrollableArea::scrollCornerRect() const // (b) Both scrollbars are present. bool hasHorizontalBar = horizontalScrollbar(); bool hasVerticalBar = verticalScrollbar(); - bool hasResizer = m_box->style()->resize() != RESIZE_NONE; + bool hasResizer = box().style()->resize() != RESIZE_NONE; if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar))) - return cornerRect(m_box->style(), horizontalScrollbar(), verticalScrollbar(), m_box->pixelSnappedBorderBoxRect()); + return cornerRect(box().style(), horizontalScrollbar(), verticalScrollbar(), box().pixelSnappedBorderBoxRect()); return IntRect(); } IntRect RenderLayerScrollableArea::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const { - RenderView* view = m_box->view(); + RenderView* view = box().view(); if (!view) return scrollbarRect; IntRect rect = scrollbarRect; rect.move(scrollbarOffset(scrollbar)); - return view->frameView()->convertFromRenderer(m_box, rect); + return view->frameView()->convertFromRenderer(box(), rect); } IntRect RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const { - RenderView* view = m_box->view(); + RenderView* view = box().view(); if (!view) return parentRect; - IntRect rect = view->frameView()->convertToRenderer(m_box, 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 = m_box->view(); + RenderView* view = box().view(); if (!view) return scrollbarPoint; IntPoint point = scrollbarPoint; point.move(scrollbarOffset(scrollbar)); - return view->frameView()->convertFromRenderer(m_box, point); + return view->frameView()->convertFromRenderer(box(), point); } IntPoint RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const { - RenderView* view = m_box->view(); + RenderView* view = box().view(); if (!view) return parentPoint; - IntPoint point = view->frameView()->convertToRenderer(m_box, parentPoint); + IntPoint point = view->frameView()->convertToRenderer(box(), parentPoint); point.move(-scrollbarOffset(scrollbar)); return point; @@ -318,7 +338,7 @@ int RenderLayerScrollableArea::scrollSize(ScrollbarOrientation orientation) cons void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset) { - if (!m_box->isMarquee()) { + if (!box().isMarquee()) { // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks). if (m_scrollDimensionsDirty) computeScrollDimensions(); @@ -329,62 +349,77 @@ void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset) setScrollOffset(toIntSize(newScrollOffset)); - Frame* frame = m_box->frame(); - InspectorInstrumentation::willScrollLayer(m_box); + LocalFrame* frame = box().frame(); + ASSERT(frame); - RenderView* view = m_box->view(); + RefPtr<FrameView> frameView = box().frameView(); - // We should have a RenderView if we're trying to scroll. - ASSERT(view); + 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. - bool inLayout = view ? view->frameView()->isInLayout() : false; - if (!inLayout) { + if (!frameView->isInPerformLayout()) { // If we're in the middle of layout, we'll just update layers once layout has finished. layer()->updateLayerPositionsAfterOverflowScroll(); - if (view) { - // Update regions, scrolling may change the clip of a particular region. - view->frameView()->updateAnnotatedRegions(); - view->updateWidgetPositions(); - } - + // Update regions, scrolling may change the clip of a particular region. + frameView->updateAnnotatedRegions(); + // FIXME: We shouldn't call updateWidgetPositions() here since it might tear down the render tree, + // for now we just crash to avoid allowing an attacker to use after free. + frameView->updateWidgetPositions(); + RELEASE_ASSERT(frameView->renderView()); updateCompositingLayersAfterScroll(); } - RenderLayerModelObject* repaintContainer = m_box->containerForRepaint(); - if (frame) { - // The caret rect needs to be invalidated after scrolling - frame->selection().setCaretRectNeedsUpdate(); + const RenderLayerModelObject* repaintContainer = box().containerForPaintInvalidation(); + // The caret rect needs to be invalidated after scrolling + frame->selection().setCaretRectNeedsUpdate(); - FloatQuad quadForFakeMouseMoveEvent = FloatQuad(layer()->repainter().repaintRect()); - if (repaintContainer) - quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent); - frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent); - } + FloatQuad quadForFakeMouseMoveEvent; + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + quadForFakeMouseMoveEvent = FloatQuad(layer()->renderer()->previousPaintInvalidationRect()); + else + quadForFakeMouseMoveEvent = FloatQuad(layer()->repainter().repaintRect()); + + quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent); + frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent); bool requiresRepaint = true; - if (m_box->view()->compositor()->inCompositingMode()) { + if (box().view()->compositor()->inCompositingMode()) { + // Hits in virtual/gpu/fast/canvas/canvas-scroll-path-into-view.html. + DisableCompositingQueryAsserts disabler; bool onlyScrolledCompositedLayers = scrollsOverflow() && !layer()->hasVisibleNonLayerContent() && !layer()->hasNonCompositedChild() && !layer()->hasBlockSelectionGapBounds() - && !m_box->isMarquee(); + && !box().isMarquee(); if (usesCompositedScrolling() || onlyScrolledCompositedLayers) requiresRepaint = false; } // Just schedule a full repaint of our object. - if (view && requiresRepaint) - m_box->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(layer()->repainter().repaintRect())); + if (requiresRepaint) { + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { + if (box().frameView()->isInPerformLayout()) + box().setShouldDoFullPaintInvalidationAfterLayout(true); + else + box().invalidatePaintUsingContainer(repaintContainer, pixelSnappedIntRect(layer()->renderer()->previousPaintInvalidationRect()), InvalidationScroll); + } else { + box().invalidatePaintUsingContainer(repaintContainer, pixelSnappedIntRect(layer()->repainter().repaintRect()), InvalidationScroll); + } + } // Schedule the scroll DOM event. - if (m_box->node()) - m_box->node()->document().enqueueScrollEventForNode(m_box->node()); + if (box().node()) + box().node()->document().enqueueScrollEventForNode(box().node()); - InspectorInstrumentation::didScrollLayer(m_box); + if (AXObjectCache* cache = box().document().existingAXObjectCache()) + cache->handleScrollPositionChanged(&box()); + + InspectorInstrumentation::didScrollLayer(&box()); } IntPoint RenderLayerScrollableArea::scrollPosition() const @@ -399,10 +434,10 @@ IntPoint RenderLayerScrollableArea::minimumScrollPosition() const IntPoint RenderLayerScrollableArea::maximumScrollPosition() const { - if (!m_box->hasOverflowClip()) + if (!box().hasOverflowClip()) return -scrollOrigin(); - return -scrollOrigin() + enclosingIntRect(m_overflowRect).size() - enclosingIntRect(m_box->clientBoxRect()).size(); + return -scrollOrigin() + enclosingIntRect(m_overflowRect).size() - enclosingIntRect(box().clientBoxRect()).size(); } IntRect RenderLayerScrollableArea::visibleContentRect(IncludeScrollbarsInRect scrollbarInclusion) const @@ -440,12 +475,12 @@ IntSize RenderLayerScrollableArea::overhangAmount() const IntPoint RenderLayerScrollableArea::lastKnownMousePosition() const { - return m_box->frame() ? m_box->frame()->eventHandler().lastKnownMousePosition() : IntPoint(); + return box().frame() ? box().frame()->eventHandler().lastKnownMousePosition() : IntPoint(); } bool RenderLayerScrollableArea::shouldSuspendScrollAnimations() const { - RenderView* view = m_box->view(); + RenderView* view = box().view(); if (!view) return true; return view->frameView()->shouldSuspendScrollAnimations(); @@ -453,7 +488,7 @@ bool RenderLayerScrollableArea::shouldSuspendScrollAnimations() const bool RenderLayerScrollableArea::scrollbarsCanBeActive() const { - RenderView* view = m_box->view(); + RenderView* view = box().view(); if (!view) return false; return view->frameView()->scrollbarsCanBeActive(); @@ -461,62 +496,67 @@ bool RenderLayerScrollableArea::scrollbarsCanBeActive() const IntRect RenderLayerScrollableArea::scrollableAreaBoundingBox() const { - return m_box->absoluteBoundingBoxRect(); + return box().absoluteBoundingBoxRect(); } bool RenderLayerScrollableArea::userInputScrollable(ScrollbarOrientation orientation) const { - if (m_box->isIntristicallyScrollable(orientation)) + if (box().isIntristicallyScrollable(orientation)) return true; EOverflow overflowStyle = (orientation == HorizontalScrollbar) ? - m_box->style()->overflowX() : m_box->style()->overflowY(); + box().style()->overflowX() : box().style()->overflowY(); return (overflowStyle == OSCROLL || overflowStyle == OAUTO || overflowStyle == OOVERLAY); } bool RenderLayerScrollableArea::shouldPlaceVerticalScrollbarOnLeft() const { - return m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft(); + return box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft(); } int RenderLayerScrollableArea::pageStep(ScrollbarOrientation orientation) const { int length = (orientation == HorizontalScrollbar) ? - m_box->pixelSnappedClientWidth() : m_box->pixelSnappedClientHeight(); + 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_box->layer(); + return &m_layer; } -int RenderLayerScrollableArea::scrollWidth() const +LayoutUnit RenderLayerScrollableArea::scrollWidth() const { if (m_scrollDimensionsDirty) const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions(); - return snapSizeToPixel(m_overflowRect.width(), m_box->clientLeft() + m_box->x()); + return m_overflowRect.width(); } -int RenderLayerScrollableArea::scrollHeight() const +LayoutUnit RenderLayerScrollableArea::scrollHeight() const { if (m_scrollDimensionsDirty) const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions(); - return snapSizeToPixel(m_overflowRect.height(), m_box->clientTop() + m_box->y()); + return m_overflowRect.height(); } void RenderLayerScrollableArea::computeScrollDimensions() { m_scrollDimensionsDirty = false; - m_overflowRect = m_box->layoutOverflowRect(); - m_box->flipForWritingMode(m_overflowRect); + m_overflowRect = box().layoutOverflowRect(); + box().flipForWritingMode(m_overflowRect); - int scrollableLeftOverflow = m_overflowRect.x() - m_box->borderLeft() - (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? m_box->verticalScrollbarWidth() : 0); - int scrollableTopOverflow = m_overflowRect.y() - m_box->borderTop(); + int scrollableLeftOverflow = m_overflowRect.x() - box().borderLeft() - (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? box().verticalScrollbarWidth() : 0); + int scrollableTopOverflow = m_overflowRect.y() - box().borderTop(); setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow)); } @@ -530,7 +570,7 @@ void RenderLayerScrollableArea::scrollToOffset(const IntSize& scrollOffset, Scro void RenderLayerScrollableArea::updateAfterLayout() { // List box parts handle the scrollbars by themselves so we have nothing to do. - if (m_box->style()->appearance() == ListboxPart) + if (box().style()->appearance() == ListboxPart) return; m_scrollDimensionsDirty = true; @@ -538,7 +578,7 @@ void RenderLayerScrollableArea::updateAfterLayout() computeScrollDimensions(); - if (!m_box->isMarquee()) { + if (!box().isMarquee()) { // 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()); @@ -552,87 +592,97 @@ void RenderLayerScrollableArea::updateAfterLayout() bool hasHorizontalOverflow = this->hasHorizontalOverflow(); bool hasVerticalOverflow = this->hasVerticalOverflow(); - // overflow:scroll should just enable/disable. - if (m_box->style()->overflowX() == OSCROLL) - horizontalScrollbar()->setEnabled(hasHorizontalOverflow); - if (m_box->style()->overflowY() == OSCROLL) - verticalScrollbar()->setEnabled(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 = m_box->hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow); - bool autoVerticalScrollBarChanged = m_box->hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow); + bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow); + bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow); if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) { - if (m_box->hasAutoHorizontalScrollbar()) + if (box().hasAutoHorizontalScrollbar()) setHasHorizontalScrollbar(hasHorizontalOverflow); - if (m_box->hasAutoVerticalScrollbar()) + if (box().hasAutoVerticalScrollbar()) setHasVerticalScrollbar(hasVerticalOverflow); + if (hasVerticalOverflow || hasHorizontalOverflow) + updateScrollCornerStyle(); + layer()->updateSelfPaintingLayer(); // Force an update since we know the scrollbars have changed things. - if (m_box->document().hasAnnotatedRegions()) - m_box->document().setAnnotatedRegionsDirty(true); + if (box().document().hasAnnotatedRegions()) + box().document().setAnnotatedRegionsDirty(true); - m_box->repaint(); + if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) + box().paintInvalidationForWholeRenderer(); - if (m_box->style()->overflowX() == OAUTO || m_box->style()->overflowY() == OAUTO) { + 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(m_box); - layoutScope.setNeedsLayout(m_box); - if (m_box->isRenderBlock()) { - RenderBlock* block = toRenderBlock(m_box); - block->scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged); - block->layoutBlock(true); + SubtreeLayoutScope layoutScope(box()); + layoutScope.setNeedsLayout(&box()); + if (box().isRenderBlock()) { + RenderBlock& block = toRenderBlock(box()); + block.scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged); + block.layoutBlock(true); } else { - m_box->layout(); + box().layout(); } m_inOverflowRelayout = false; } } } - // Set up the range (and page step/line step). - if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { - int clientWidth = m_box->pixelSnappedClientWidth(); - horizontalScrollbar->setProportion(clientWidth, overflowRect().width()); - } - if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { - int clientHeight = m_box->pixelSnappedClientHeight(); - verticalScrollbar->setProportion(clientHeight, overflowRect().height()); + { + // 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()); + } } updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow()); - - // Composited scrolling may need to be enabled or disabled if the amount of overflow changed. - if (m_box->view() && m_box->view()->compositor()->updateLayerCompositingState(m_box->layer())) - m_box->view()->compositor()->setCompositingLayersNeedRebuild(); } bool RenderLayerScrollableArea::hasHorizontalOverflow() const { ASSERT(!m_scrollDimensionsDirty); - return scrollWidth() > m_box->pixelSnappedClientWidth(); + return scrollWidth() > box().clientWidth(); } bool RenderLayerScrollableArea::hasVerticalOverflow() const { ASSERT(!m_scrollDimensionsDirty); - return scrollHeight() > m_box->pixelSnappedClientHeight(); + return scrollHeight() > box().clientHeight(); } bool RenderLayerScrollableArea::hasScrollableHorizontalOverflow() const { - return hasHorizontalOverflow() && m_box->scrollsOverflowX(); + return hasHorizontalOverflow() && box().scrollsOverflowX(); } bool RenderLayerScrollableArea::hasScrollableVerticalOverflow() const { - return hasVerticalOverflow() && m_box->scrollsOverflowY(); + return hasVerticalOverflow() && box().scrollsOverflowY(); } static bool overflowRequiresScrollbar(EOverflow overflow) @@ -648,14 +698,18 @@ static bool overflowDefinesAutomaticScrollbar(EOverflow overflow) void RenderLayerScrollableArea::updateAfterStyleChange(const RenderStyle* oldStyle) { // List box parts handle the scrollbars by themselves so we have nothing to do. - if (m_box->style()->appearance() == ListboxPart) + if (box().style()->appearance() == ListboxPart) + return; + + // RenderView shouldn't provide scrollbars on its own. + if (box().isRenderView()) return; if (!m_scrollDimensionsDirty) updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow()); - EOverflow overflowX = m_box->style()->overflowX(); - EOverflow overflowY = m_box->style()->overflowY(); + 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); @@ -686,10 +740,35 @@ void RenderLayerScrollableArea::updateAfterStyleChange(const RenderStyle* oldSty updateResizerStyle(); } +void RenderLayerScrollableArea::updateAfterCompositingChange() +{ + layer()->updateScrollingStateAfterCompositingChange(); +} + +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(); +} + IntSize RenderLayerScrollableArea::clampScrollOffset(const IntSize& scrollOffset) const { - int maxX = scrollWidth() - m_box->pixelSnappedClientWidth(); - int maxY = scrollHeight() - m_box->pixelSnappedClientHeight(); + int maxX = scrollWidth() - box().pixelSnappedClientWidth(); + int maxY = scrollHeight() - box().pixelSnappedClientHeight(); int x = std::max(std::min(scrollOffset.width(), maxX), 0); int y = std::max(std::min(scrollOffset.height(), maxY), 0); @@ -704,8 +783,8 @@ IntRect RenderLayerScrollableArea::rectForHorizontalScrollbar(const IntRect& bor const IntRect& scrollCorner = scrollCornerRect(); return IntRect(horizontalScrollbarStart(borderBoxRect.x()), - borderBoxRect.maxY() - m_box->borderBottom() - m_hBar->height(), - borderBoxRect.width() - (m_box->borderLeft() + m_box->borderRight()) - scrollCorner.width(), + borderBoxRect.maxY() - box().borderBottom() - m_hBar->height(), + borderBoxRect.width() - (box().borderLeft() + box().borderRight()) - scrollCorner.width(), m_hBar->height()); } @@ -717,54 +796,54 @@ IntRect RenderLayerScrollableArea::rectForVerticalScrollbar(const IntRect& borde const IntRect& scrollCorner = scrollCornerRect(); return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()), - borderBoxRect.y() + m_box->borderTop(), + borderBoxRect.y() + box().borderTop(), m_vBar->width(), - borderBoxRect.height() - (m_box->borderTop() + m_box->borderBottom()) - scrollCorner.height()); + borderBoxRect.height() - (box().borderTop() + box().borderBottom()) - scrollCorner.height()); } LayoutUnit RenderLayerScrollableArea::verticalScrollbarStart(int minX, int maxX) const { - if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) - return minX + m_box->borderLeft(); - return maxX - m_box->borderRight() - m_vBar->width(); + if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) + return minX + box().borderLeft(); + return maxX - box().borderRight() - m_vBar->width(); } LayoutUnit RenderLayerScrollableArea::horizontalScrollbarStart(int minX) const { - int x = minX + m_box->borderLeft(); - if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) - x += m_vBar ? m_vBar->width() : resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer).width(); + 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, m_box->width()), m_box->borderTop()); + return IntSize(verticalScrollbarStart(0, box().width()), box().borderTop()); if (scrollbar == m_hBar.get()) - return IntSize(horizontalScrollbarStart(0), m_box->height() - m_box->borderBottom() - scrollbar->height()); + return IntSize(horizontalScrollbarStart(0), box().height() - box().borderBottom() - scrollbar->height()); ASSERT_NOT_REACHED(); return IntSize(); } -static inline RenderObject* rendererForScrollbar(RenderObject* renderer) +static inline RenderObject* rendererForScrollbar(RenderObject& renderer) { - if (Node* node = renderer->node()) { + if (Node* node = renderer.node()) { if (ShadowRoot* shadowRoot = node->containingShadowRoot()) { if (shadowRoot->type() == ShadowRoot::UserAgentShadowRoot) return shadowRoot->host()->renderer(); } } - return renderer; + return &renderer; } PassRefPtr<Scrollbar> RenderLayerScrollableArea::createScrollbar(ScrollbarOrientation orientation) { RefPtr<Scrollbar> widget; - RenderObject* actualRenderer = rendererForScrollbar(m_box); + RenderObject* actualRenderer = rendererForScrollbar(box()); bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR); if (hasCustomScrollbarStyle) { widget = RenderScrollbar::createCustomScrollbar(this, orientation, actualRenderer->node()); @@ -775,7 +854,7 @@ PassRefPtr<Scrollbar> RenderLayerScrollableArea::createScrollbar(ScrollbarOrient else didAddScrollbar(widget.get(), VerticalScrollbar); } - m_box->document().view()->addChild(widget.get()); + box().document().view()->addChild(widget.get()); return widget.release(); } @@ -790,7 +869,7 @@ void RenderLayerScrollableArea::destroyScrollbar(ScrollbarOrientation orientatio scrollbar->removeFromParent(); scrollbar->disconnectFromScrollableArea(); - scrollbar = 0; + scrollbar = nullptr; } void RenderLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar) @@ -798,10 +877,14 @@ void RenderLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar) if (hasScrollbar == hasHorizontalScrollbar()) return; - if (hasScrollbar) + 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 + } else { 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) @@ -810,8 +893,8 @@ void RenderLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar) m_vBar->styleChanged(); // Force an update since we know the scrollbars have changed things. - if (m_box->document().hasAnnotatedRegions()) - m_box->document().setAnnotatedRegionsDirty(true); + if (box().document().hasAnnotatedRegions()) + box().document().setAnnotatedRegionsDirty(true); } void RenderLayerScrollableArea::setHasVerticalScrollbar(bool hasScrollbar) @@ -819,10 +902,13 @@ void RenderLayerScrollableArea::setHasVerticalScrollbar(bool hasScrollbar) if (hasScrollbar == hasVerticalScrollbar()) return; - if (hasScrollbar) + if (hasScrollbar) { + // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html + DisableCompositingQueryAsserts disabler; m_vBar = createScrollbar(VerticalScrollbar); - else + } else { 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) @@ -831,8 +917,8 @@ void RenderLayerScrollableArea::setHasVerticalScrollbar(bool hasScrollbar) m_vBar->styleChanged(); // Force an update since we know the scrollbars have changed things. - if (m_box->document().hasAnnotatedRegions()) - m_box->document().setAnnotatedRegionsDirty(true); + if (box().document().hasAnnotatedRegions()) + box().document().setAnnotatedRegionsDirty(true); } int RenderLayerScrollableArea::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const @@ -849,23 +935,12 @@ int RenderLayerScrollableArea::horizontalScrollbarHeight(OverlayScrollbarSizeRel return m_hBar->height(); } -void RenderLayerScrollableArea::positionOverflowControls() -{ - RenderGeometryMap geometryMap(UseTransforms); - RenderView* view = m_box->view(); - if (m_box->layer() != view->layer() && m_box->layer()->parent()) - geometryMap.pushMappingsToAncestor(m_box->layer()->parent(), 0); - - LayoutPoint offsetFromRoot = LayoutPoint(geometryMap.absolutePoint(FloatPoint())); - positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot))); -} - void RenderLayerScrollableArea::positionOverflowControls(const IntSize& offsetFromRoot) { - if (!hasScrollbar() && !m_box->canResize()) + if (!hasScrollbar() && !box().canResize()) return; - const IntRect borderBox = m_box->pixelSnappedBorderBoxRect(); + const IntRect borderBox = box().pixelSnappedBorderBoxRect(); if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { IntRect vBarRect = rectForVerticalScrollbar(borderBox); vBarRect.move(offsetFromRoot); @@ -888,26 +963,23 @@ void RenderLayerScrollableArea::positionOverflowControls(const IntSize& offsetFr // 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 (m_box->hasCompositedLayerMapping()) - m_box->compositedLayerMapping()->positionOverflowControlsLayers(offsetFromRoot); -} - -bool RenderLayerScrollableArea::scrollsOverflow() const -{ - if (FrameView* frameView = m_box->view()->frameView()) - return frameView->containsScrollableArea(this); - - return false; + if (box().hasCompositedLayerMapping()) + box().compositedLayerMapping()->positionOverflowControlsLayers(offsetFromRoot); } void RenderLayerScrollableArea::updateScrollCornerStyle() { - RenderObject* actualRenderer = rendererForScrollbar(m_box); - RefPtr<RenderStyle> corner = m_box->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), actualRenderer->style()) : PassRefPtr<RenderStyle>(0); + 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(&m_box->document()); - m_scrollCorner->setParent(m_box); + m_scrollCorner = RenderScrollbarPart::createAnonymous(&box().document()); + m_scrollCorner->setParent(&box()); } m_scrollCorner->setStyle(corner.release()); } else if (m_scrollCorner) { @@ -919,7 +991,7 @@ void RenderLayerScrollableArea::updateScrollCornerStyle() void RenderLayerScrollableArea::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls) { // Don't do anything if we have no overflow. - if (!m_box->hasOverflowClip()) + if (!box().hasOverflowClip()) return; IntPoint adjustedPaintOffset = paintOffset; @@ -947,7 +1019,7 @@ void RenderLayerScrollableArea::paintOverflowControls(GraphicsContext* context, if (!overflowControlsIntersectRect(localDamgeRect)) return; - RenderView* renderView = m_box->view(); + RenderView* renderView = box().view(); RenderLayer* paintingRoot = layer()->enclosingCompositingLayer(); if (!paintingRoot) @@ -1003,22 +1075,22 @@ void RenderLayerScrollableArea::paintScrollCorner(GraphicsContext* context, cons bool RenderLayerScrollableArea::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint) { - if (!hasScrollbar() && !m_box->canResize()) + if (!hasScrollbar() && !box().canResize()) return false; IntRect resizeControlRect; - if (m_box->style()->resize() != RESIZE_NONE) { - resizeControlRect = resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer); + 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, m_box->width()), - m_box->borderTop(), + LayoutRect vBarRect(verticalScrollbarStart(0, box().width()), + box().borderTop(), m_vBar->width(), - m_box->height() - (m_box->borderTop() + m_box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize)); + box().height() - (box().borderTop() + box().borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize)); if (vBarRect.contains(localPoint)) { result.setScrollbar(m_vBar.get()); return true; @@ -1028,8 +1100,8 @@ bool RenderLayerScrollableArea::hitTestOverflowControls(HitTestResult& result, c resizeControlSize = max(resizeControlRect.width(), 0); if (m_hBar && m_hBar->shouldParticipateInHitTesting()) { LayoutRect hBarRect(horizontalScrollbarStart(0), - m_box->height() - m_box->borderBottom() - m_hBar->height(), - m_box->width() - (m_box->borderLeft() + m_box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), + box().height() - box().borderBottom() - m_hBar->height(), + box().width() - (box().borderLeft() + box().borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), m_hBar->height()); if (hBarRect.contains(localPoint)) { result.setScrollbar(m_hBar.get()); @@ -1044,9 +1116,9 @@ bool RenderLayerScrollableArea::hitTestOverflowControls(HitTestResult& result, c IntRect RenderLayerScrollableArea::resizerCornerRect(const IntRect& bounds, ResizerHitTestType resizerHitTestType) const { - if (m_box->style()->resize() == RESIZE_NONE) + if (box().style()->resize() == RESIZE_NONE) return IntRect(); - IntRect corner = cornerRect(m_box->style(), horizontalScrollbar(), verticalScrollbar(), bounds); + IntRect corner = cornerRect(box().style(), horizontalScrollbar(), verticalScrollbar(), bounds); if (resizerHitTestType == ResizerForTouch) { // We make the resizer virtually larger for touch hit testing. With the @@ -1065,13 +1137,13 @@ IntRect RenderLayerScrollableArea::scrollCornerAndResizerRect() const { IntRect scrollCornerAndResizer = scrollCornerRect(); if (scrollCornerAndResizer.isEmpty()) - scrollCornerAndResizer = resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer); + scrollCornerAndResizer = resizerCornerRect(box().pixelSnappedBorderBoxRect(), ResizerForPointer); return scrollCornerAndResizer; } bool RenderLayerScrollableArea::overflowControlsIntersectRect(const IntRect& localRect) const { - const IntRect borderBox = m_box->pixelSnappedBorderBoxRect(); + const IntRect borderBox = box().pixelSnappedBorderBoxRect(); if (rectForHorizontalScrollbar(borderBox).intersects(localRect)) return true; @@ -1090,10 +1162,10 @@ bool RenderLayerScrollableArea::overflowControlsIntersectRect(const IntRect& loc void RenderLayerScrollableArea::paintResizer(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect) { - if (m_box->style()->resize() == RESIZE_NONE) + if (box().style()->resize() == RESIZE_NONE) return; - IntRect absRect = resizerCornerRect(m_box->pixelSnappedBorderBoxRect(), ResizerForPointer); + IntRect absRect = resizerCornerRect(box().pixelSnappedBorderBoxRect(), ResizerForPointer); absRect.moveBy(paintOffset); if (!absRect.intersects(damageRect)) return; @@ -1126,17 +1198,17 @@ void RenderLayerScrollableArea::paintResizer(GraphicsContext* context, const Int bool RenderLayerScrollableArea::isPointInResizeControl(const IntPoint& absolutePoint, ResizerHitTestType resizerHitTestType) const { - if (!m_box->canResize()) + if (!box().canResize()) return false; - IntPoint localPoint = roundedIntPoint(m_box->absoluteToLocal(absolutePoint, UseTransforms)); - IntRect localBounds(0, 0, m_box->pixelSnappedWidth(), m_box->pixelSnappedHeight()); + 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 (!m_box->canResize()) + if (!box().canResize()) return false; if (layerFragments.isEmpty()) @@ -1153,26 +1225,29 @@ bool RenderLayerScrollableArea::hitTestResizerInFragments(const LayerFragments& void RenderLayerScrollableArea::updateResizerAreaSet() { - Frame* frame = m_box->frame(); + LocalFrame* frame = box().frame(); if (!frame) return; FrameView* frameView = frame->view(); if (!frameView) return; - if (m_box->canResize()) - frameView->addResizerArea(m_box); + if (box().canResize()) + frameView->addResizerArea(box()); else - frameView->removeResizerArea(m_box); + frameView->removeResizerArea(box()); } void RenderLayerScrollableArea::updateResizerStyle() { - RenderObject* actualRenderer = rendererForScrollbar(m_box); - RefPtr<RenderStyle> resizer = m_box->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(RESIZER), actualRenderer->style()) : PassRefPtr<RenderStyle>(0); + 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(&m_box->document()); - m_resizer->setParent(m_box); + m_resizer = RenderScrollbarPart::createAnonymous(&box().document()); + m_resizer->setParent(&box()); } m_resizer->setStyle(resizer.release()); } else if (m_resizer) { @@ -1183,7 +1258,7 @@ void RenderLayerScrollableArea::updateResizerStyle() void RenderLayerScrollableArea::drawPlatformResizerImage(GraphicsContext* context, IntRect resizerCornerRect) { - float deviceScaleFactor = WebCore::deviceScaleFactor(m_box->frame()); + float deviceScaleFactor = WebCore::deviceScaleFactor(box().frame()); RefPtr<Image> resizeCornerImage; IntSize cornerResizerSize; @@ -1198,10 +1273,10 @@ void RenderLayerScrollableArea::drawPlatformResizerImage(GraphicsContext* contex cornerResizerSize = resizeCornerImage->size(); } - if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { + if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { context->save(); context->translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height()); - context->scale(FloatSize(-1.0, 1.0)); + context->scale(-1.0, 1.0); context->drawImage(resizeCornerImage.get(), IntRect(IntPoint(), cornerResizerSize)); context->restore(); return; @@ -1215,21 +1290,21 @@ IntSize RenderLayerScrollableArea::offsetFromResizeCorner(const IntPoint& absolu // 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 (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) + if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) elementSize.setWidth(0); IntPoint resizerPoint = IntPoint(elementSize); - IntPoint localPoint = roundedIntPoint(m_box->absoluteToLocal(absolutePoint, UseTransforms)); + 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() || !m_box->canResize() || !m_box->node()) + if (!inResizeMode() || !box().canResize() || !box().node()) return; - ASSERT(m_box->node()->isElementNode()); - Element* element = toElement(m_box->node()); + ASSERT(box().node()->isElementNode()); + Element* element = toElement(box().node()); Document& document = element->document(); @@ -1253,34 +1328,34 @@ void RenderLayerScrollableArea::resize(const PlatformEvent& evt, const LayoutSiz ASSERT_NOT_REACHED(); } - float zoomFactor = m_box->style()->effectiveZoom(); + float zoomFactor = box().style()->effectiveZoom(); LayoutSize newOffset = offsetFromResizeCorner(document.view()->windowToContents(pos)); newOffset.setWidth(newOffset.width() / zoomFactor); newOffset.setHeight(newOffset.height() / zoomFactor); - LayoutSize currentSize = LayoutSize(m_box->width() / zoomFactor, m_box->height() / zoomFactor); + LayoutSize currentSize = LayoutSize(box().width() / zoomFactor, box().height() / zoomFactor); LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize); element->setMinimumSizeForResizing(minimumSize); LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor); - if (m_box->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { + if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { newOffset.setWidth(-newOffset.width()); adjustedOldOffset.setWidth(-adjustedOldOffset.width()); } LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize; - bool isBoxSizingBorder = m_box->style()->boxSizing() == BORDER_BOX; + bool isBoxSizingBorder = box().style()->boxSizing() == BORDER_BOX; - EResize resize = m_box->style()->resize(); + 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, m_box->marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX); - element->setInlineStyleProperty(CSSPropertyMarginRight, m_box->marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX); + element->setInlineStyleProperty(CSSPropertyMarginLeft, box().marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX); + element->setInlineStyleProperty(CSSPropertyMarginRight, box().marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX); } - LayoutUnit baseWidth = m_box->width() - (isBoxSizingBorder ? LayoutUnit() : m_box->borderAndPaddingWidth()); + LayoutUnit baseWidth = box().width() - (isBoxSizingBorder ? LayoutUnit() : box().borderAndPaddingWidth()); baseWidth = baseWidth / zoomFactor; element->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX); } @@ -1288,10 +1363,10 @@ void RenderLayerScrollableArea::resize(const PlatformEvent& evt, const LayoutSiz 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, m_box->marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX); - element->setInlineStyleProperty(CSSPropertyMarginBottom, m_box->marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX); + element->setInlineStyleProperty(CSSPropertyMarginTop, box().marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX); + element->setInlineStyleProperty(CSSPropertyMarginBottom, box().marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX); } - LayoutUnit baseHeight = m_box->height() - (isBoxSizingBorder ? LayoutUnit() : m_box->borderAndPaddingHeight()); + LayoutUnit baseHeight = box().height() - (isBoxSizingBorder ? LayoutUnit() : box().borderAndPaddingHeight()); baseHeight = baseHeight / zoomFactor; element->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX); } @@ -1303,8 +1378,8 @@ void RenderLayerScrollableArea::resize(const PlatformEvent& evt, const LayoutSiz LayoutRect RenderLayerScrollableArea::exposeRect(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) { - LayoutRect localExposeRect(m_box->absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox()); - LayoutRect layerBounds(0, 0, m_box->clientWidth(), m_box->clientHeight()); + 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())); @@ -1315,12 +1390,12 @@ LayoutRect RenderLayerScrollableArea::exposeRect(const LayoutRect& rect, const S scrollToOffset(clampedScrollOffset); IntSize scrollOffsetDifference = adjustedScrollOffset() - oldScrollOffset; localExposeRect.move(-scrollOffsetDifference); - return LayoutRect(m_box->localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox()); + return LayoutRect(box().localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox()); } void RenderLayerScrollableArea::updateScrollableAreaSet(bool hasOverflow) { - Frame* frame = m_box->frame(); + LocalFrame* frame = box().frame(); if (!frame) return; @@ -1328,148 +1403,58 @@ void RenderLayerScrollableArea::updateScrollableAreaSet(bool hasOverflow) if (!frameView) return; - bool isVisibleToHitTest = m_box->visibleToHitTesting(); - if (HTMLFrameOwnerElement* owner = frame->ownerElement()) + // 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 requiresScrollableArea = hasOverflow && isVisibleToHitTest; - bool updatedScrollableAreaSet = false; - if (requiresScrollableArea) { - if (frameView->addScrollableArea(this)) - updatedScrollableAreaSet = true; - } else { - if (frameView->removeScrollableArea(this)) - updatedScrollableAreaSet = true; - } - - if (updatedScrollableAreaSet) { - // Count the total number of RenderLayers that are scrollable areas for - // any period. We only want to record this at most once per RenderLayer. - if (requiresScrollableArea && !m_isScrollableAreaHasBeenRecorded) { - blink::Platform::current()->histogramEnumeration("Renderer.CompositedScrolling", RenderLayer::IsScrollableAreaBucket, RenderLayer::CompositedScrollingHistogramMax); - m_isScrollableAreaHasBeenRecorded = true; - } - - // We always want composited scrolling if compositor driven accelerated - // scrolling is enabled. Since we will not update needs composited scrolling - // in this case, we must force our state to update. - if (layer()->compositorDrivenAcceleratedScrollingEnabled()) - layer()->didUpdateNeedsCompositedScrolling(); - else if (requiresScrollableArea) - m_box->view()->compositor()->setNeedsUpdateCompositingRequirementsState(); - else - setNeedsCompositedScrolling(false); - } -} - -void RenderLayerScrollableArea::updateNeedsCompositedScrolling() -{ - TRACE_EVENT0("comp-scroll", "RenderLayer::updateNeedsCompositedScrolling"); - - layer()->stackingNode()->updateDescendantsAreContiguousInStackingOrder(); - layer()->updateDescendantDependentFlags(); - - ASSERT(scrollsOverflow()); - const bool needsToBeStackingContainer = layer()->acceleratedCompositingForOverflowScrollEnabled() - && layer()->stackingNode()->descendantsAreContiguousInStackingOrder() - && !layer()->hasUnclippedDescendant(); + bool didNeedCompositedScrolling = needsCompositedScrolling(); - const bool needsToBeStackingContainerDidChange = layer()->stackingNode()->setNeedsToBeStackingContainer(needsToBeStackingContainer); + bool didScrollOverflow = m_scrollsOverflow; - const bool needsCompositedScrolling = needsToBeStackingContainer - || layer()->compositorDrivenAcceleratedScrollingEnabled(); - - // We gather a boolean value for use with Google UMA histograms to - // quantify the actual effects of a set of patches attempting to - // relax composited scrolling requirements, thereby increasing the - // number of composited overflow divs. - if (layer()->acceleratedCompositingForOverflowScrollEnabled()) - blink::Platform::current()->histogramEnumeration("Renderer.NeedsCompositedScrolling", needsCompositedScrolling, 2); + m_scrollsOverflow = hasOverflow && isVisibleToHitTest; + if (didScrollOverflow == scrollsOverflow()) + return; - const bool needsCompositedScrollingDidChange = setNeedsCompositedScrolling(needsCompositedScrolling); + if (m_scrollsOverflow) + frameView->addScrollableArea(this); + else + frameView->removeScrollableArea(this); - if (needsToBeStackingContainerDidChange || needsCompositedScrollingDidChange) { - // Note, the z-order lists may need to be rebuilt, but our code guarantees - // that we have not affected stacking, so we will not dirty - // m_descendantsAreContiguousInStackingOrder for either us or our stacking - // context or container. + if (didNeedCompositedScrolling != needsCompositedScrolling()) layer()->didUpdateNeedsCompositedScrolling(); - } -} - -bool RenderLayerScrollableArea::setNeedsCompositedScrolling(bool needsCompositedScrolling) -{ - if (this->needsCompositedScrolling() == needsCompositedScrolling) - return false; - - // Count the total number of RenderLayers which need composited scrolling at - // some point. This should be recorded at most once per RenderLayer, so we - // check m_willUseCompositedScrollingHasBeenRecorded. - if (layer()->acceleratedCompositingForOverflowScrollEnabled() && !m_willUseCompositedScrollingHasBeenRecorded) { - blink::Platform::current()->histogramEnumeration("Renderer.CompositedScrolling", RenderLayer::WillUseCompositedScrollingBucket, RenderLayer::CompositedScrollingHistogramMax); - m_willUseCompositedScrollingHasBeenRecorded = true; - } - - m_needsCompositedScrolling = needsCompositedScrolling; - - return true; -} - -void RenderLayerScrollableArea::updateHasVisibleNonLayerContent() -{ - layer()->updateHasVisibleNonLayerContent(); } void RenderLayerScrollableArea::updateCompositingLayersAfterScroll() { - RenderLayerCompositor* compositor = m_box->view()->compositor(); + RenderLayerCompositor* compositor = box().view()->compositor(); if (compositor->inCompositingMode()) { - // FIXME: Our stacking container is guaranteed to contain all of our descendants that may need - // repositioning, so we should be able to enqueue a partial update compositing layers from there. - // this feature was overridden for now by deferred compositing updates. - if (usesCompositedScrolling()) - compositor->updateCompositingLayers(CompositingUpdateOnCompositedScroll); - else - compositor->updateCompositingLayers(CompositingUpdateOnScroll); + if (usesCompositedScrolling()) { + DisableCompositingQueryAsserts disabler; + ASSERT(box().hasCompositedLayerMapping()); + box().compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree); + compositor->setNeedsCompositingUpdate(CompositingUpdateAfterGeometryChange); + } else { + layer()->setNeedsCompositingInputsUpdate(); + compositor->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange); + } } } bool RenderLayerScrollableArea::usesCompositedScrolling() const { // Scroll form controls on the main thread so they exhibit correct touch scroll event bubbling - if (m_box && (m_box->isIntristicallyScrollable(VerticalScrollbar) || m_box->isIntristicallyScrollable(HorizontalScrollbar))) + if (box().isIntristicallyScrollable(VerticalScrollbar) || box().isIntristicallyScrollable(HorizontalScrollbar)) return false; - return m_box->hasCompositedLayerMapping() && m_box->compositedLayerMapping()->scrollingLayer(); -} - -bool RenderLayerScrollableArea::adjustForForceCompositedScrollingMode(bool value) const -{ - switch (m_forceNeedsCompositedScrolling) { - case DoNotForceCompositedScrolling: - return value; - case CompositedScrollingAlwaysOn: - return true; - case CompositedScrollingAlwaysOff: - return false; - } - - ASSERT_NOT_REACHED(); - return value; + // See https://codereview.chromium.org/176633003/ for the tests that fail without this disabler. + DisableCompositingQueryAsserts disabler; + return box().hasCompositedLayerMapping() && box().compositedLayerMapping()->scrollingLayer(); } bool RenderLayerScrollableArea::needsCompositedScrolling() const { - return adjustForForceCompositedScrollingMode(m_needsCompositedScrolling); -} - -void RenderLayerScrollableArea::setForceNeedsCompositedScrolling(ForceNeedsCompositedScrollingMode mode) -{ - if (m_forceNeedsCompositedScrolling == mode) - return; - - m_forceNeedsCompositedScrolling = mode; - layer()->didUpdateNeedsCompositedScrolling(); + return scrollsOverflow() && box().view()->compositor()->acceleratedCompositingForOverflowScrollEnabled(); } } // Namespace WebCore |