Chromium Code Reviews| Index: third_party/WebKit/Source/core/frame/FrameView.cpp |
| diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp |
| index 42d01f256c5a85a3e908a1d9ac81bc219c6f3fcd..6391864fcc6be09670020a7b9517af6bb22e1832 100644 |
| --- a/third_party/WebKit/Source/core/frame/FrameView.cpp |
| +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp |
| @@ -194,7 +194,8 @@ FrameView::FrameView(LocalFrame& frame) |
| m_scrollbarManager(*this), |
| m_needsScrollbarsUpdate(false), |
| m_suppressAdjustViewSize(false), |
| - m_allowsLayoutInvalidationAfterLayoutClean(true) { |
| + m_allowsLayoutInvalidationAfterLayoutClean(true), |
| + m_lastMainThreadScrollingReasons(0) { |
| init(); |
| } |
| @@ -257,6 +258,7 @@ void FrameView::reset() { |
| m_visuallyNonEmptyCharacterCount = 0; |
| m_visuallyNonEmptyPixelCount = 0; |
| m_isVisuallyNonEmpty = false; |
| + m_lastMainThreadScrollingReasons = 0; |
| m_layoutObjectCounter.reset(); |
| clearFragmentAnchor(); |
| m_viewportConstrainedObjects.reset(); |
| @@ -824,10 +826,8 @@ bool FrameView::usesCompositedScrolling() const { |
| } |
| bool FrameView::shouldScrollOnMainThread() const { |
| - if (ScrollingCoordinator* sc = scrollingCoordinator()) { |
| - if (sc->shouldUpdateScrollLayerPositionOnMainThread()) |
| - return true; |
| - } |
| + if (mainThreadScrollingReasons()) |
| + return true; |
| return ScrollableArea::shouldScrollOnMainThread(); |
| } |
| @@ -4679,4 +4679,150 @@ int FrameView::initialViewportHeight() const { |
| return m_initialViewportSize.height(); |
| } |
| +bool FrameView::hasVisibleSlowRepaintViewportConstrainedObjects( |
|
pdr.
2016/12/17 05:50:16
Nit: I don't think you need to pass in frameView h
yigu
2016/12/18 17:57:11
Done.
|
| + const FrameView& frameView) const { |
| + const ViewportConstrainedObjectSet* viewportConstrainedObjects = |
| + frameView.viewportConstrainedObjects(); |
| + if (!viewportConstrainedObjects) |
| + return false; |
| + |
| + for (const LayoutObject* layoutObject : *viewportConstrainedObjects) { |
| + DCHECK(layoutObject->isBoxModelObject() && layoutObject->hasLayer()); |
| + DCHECK(layoutObject->style()->position() == FixedPosition || |
| + layoutObject->style()->position() == StickyPosition); |
| + PaintLayer* layer = toLayoutBoxModelObject(layoutObject)->layer(); |
| + |
| + // Whether the Layer sticks to the viewport is a tree-depenent |
| + // property and our viewportConstrainedObjects collection is maintained |
| + // with only LayoutObject-level information. |
| + if (!layer->sticksToViewport()) |
| + continue; |
| + |
| + // If the whole subtree is invisible, there's no reason to scroll on |
| + // the main thread because we don't need to generate invalidations |
| + // for invisible content. |
| + if (layer->subtreeIsInvisible()) |
| + continue; |
| + |
| + // We're only smart enough to scroll viewport-constrainted objects |
| + // in the compositor if they have their own backing or they paint |
| + // into a grouped back (which necessarily all have the same viewport |
| + // constraints). |
| + CompositingState compositingState = layer->compositingState(); |
| + if (compositingState != PaintsIntoOwnBacking && |
| + compositingState != PaintsIntoGroupedBacking) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +void FrameView::updateSubFrameScrollOnMainReason( |
| + const Frame& frame, |
| + MainThreadScrollingReasons parentReason) { |
| + MainThreadScrollingReasons reasons = parentReason; |
| + |
| + if (!page()->settings().threadedScrollingEnabled()) |
| + reasons |= MainThreadScrollingReason::kThreadedScrollingDisabled; |
| + |
| + if (!frame.isLocalFrame()) |
| + return; |
| + |
| + if (!toLocalFrame(frame).view()->layerForScrolling()) |
| + return; |
| + |
| + reasons |= mainThreadScrollingReasonsPerFrame(*toLocalFrame(&frame)); |
| + if (WebLayer* scrollLayer = |
| + toLocalFrame(frame).view()->layerForScrolling()->platformLayer()) { |
| + if (reasons) { |
| + scrollLayer->addMainThreadScrollingReasons(reasons); |
| + } else { |
| + scrollLayer->clearMainThreadScrollingReasons( |
| + ~0 & ~MainThreadScrollingReason::kHandlingScrollFromMainThread); |
|
pdr.
2016/12/17 05:50:16
What is ~0 for?
yigu
2016/12/18 17:57:11
That was silly..
|
| + } |
| + } |
| + |
| + Frame* child = frame.tree().firstChild(); |
| + while (child) { |
| + updateSubFrameScrollOnMainReason(*child, reasons); |
| + child = child->tree().nextSibling(); |
| + } |
| + |
| + if (frame.isMainFrame()) |
| + m_lastMainThreadScrollingReasons = reasons; |
| +} |
| + |
| +MainThreadScrollingReasons FrameView::mainThreadScrollingReasonsPerFrame( |
|
pdr.
2016/12/17 05:50:16
Is "const LocalFrame& frame" needed? Similar to ha
yigu
2016/12/18 17:57:11
Done.
|
| + const LocalFrame& frame) const { |
| + MainThreadScrollingReasons reasons = |
| + static_cast<MainThreadScrollingReasons>(0); |
| + |
| + FrameView* frameView = frame.view(); |
| + if (!frameView || frameView->shouldThrottleRendering()) |
| + return reasons; |
| + |
| + if (frameView->hasBackgroundAttachmentFixedObjects()) |
| + reasons |= MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects; |
| + ScrollingReasons scrollingReasons = frameView->getScrollingReasons(); |
| + const bool mayBeScrolledByInput = (scrollingReasons == Scrollable); |
| + const bool mayBeScrolledByScript = |
| + mayBeScrolledByInput || |
| + (scrollingReasons == NotScrollableExplicitlyDisabled); |
| + |
| + // TODO(awoloszyn) Currently crbug.com/304810 will let certain |
| + // overflow:hidden elements scroll on the compositor thread, so we should |
| + // not let this move there path as an optimization, when we have |
| + // slow-repaint elements. |
| + if (mayBeScrolledByScript && |
| + hasVisibleSlowRepaintViewportConstrainedObjects(*frameView)) { |
| + reasons |= |
| + MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects; |
| + } |
| + return reasons; |
| +} |
| + |
| +MainThreadScrollingReasons FrameView::mainThreadScrollingReasons() const { |
| + MainThreadScrollingReasons reasons = |
| + static_cast<MainThreadScrollingReasons>(0); |
| + |
| + if (!page()->settings().threadedScrollingEnabled()) |
| + reasons |= MainThreadScrollingReason::kThreadedScrollingDisabled; |
| + |
| + if (!page()->mainFrame()->isLocalFrame()) |
| + return reasons; |
| + |
| + // TODO(alexmos,kenrb): For OOPIF, local roots that are different from |
| + // the main frame can't be used in the calculation, since they use |
| + // different compositors with unrelated state, which breaks some of the |
| + // calculations below. |
| + if (m_frame->localFrameRoot() != page()->mainFrame()) |
| + return reasons; |
| + |
| + // Walk through the subtree from the target frame to root. Use the gathered |
|
pdr.
2016/12/17 05:50:16
Nit: Update this to reflect that the function is n
yigu
2016/12/18 17:57:11
Done.
|
| + // reasons to determine whether the target frame should be scrolled on main |
| + // thread regardless other subframes on the same page. |
| + for (Frame* frame = m_frame; frame; frame = frame->tree().parent()) { |
| + if (!frame->isLocalFrame()) |
| + continue; |
| + reasons |= mainThreadScrollingReasonsPerFrame(*toLocalFrame(frame)); |
| + } |
| + |
| + return reasons; |
| +} |
| + |
| +String FrameView::mainThreadScrollingReasonsAsText() const { |
| + DCHECK(lifecycle().state() >= DocumentLifecycle::CompositingClean); |
| + if (layerForScrolling() && layerForScrolling()->platformLayer()) { |
| + String result( |
| + MainThreadScrollingReason::mainThreadScrollingReasonsAsText( |
| + layerForScrolling()->platformLayer()->mainThreadScrollingReasons()) |
| + .c_str()); |
| + return result; |
| + } |
| + |
| + String result(MainThreadScrollingReason::mainThreadScrollingReasonsAsText( |
| + m_lastMainThreadScrollingReasons) |
| + .c_str()); |
| + return result; |
| +} |
| + |
| } // namespace blink |