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 88bfd295adafbfa2a186dd6f3f0695d5961b2976..70dea6b62cb0a40ce685023b571b17b194d213e8 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_mainThreadScrollingReasons(0) { |
init(); |
} |
@@ -257,6 +258,7 @@ void FrameView::reset() { |
m_visuallyNonEmptyCharacterCount = 0; |
m_visuallyNonEmptyPixelCount = 0; |
m_isVisuallyNonEmpty = false; |
+ m_mainThreadScrollingReasons = 0; |
m_layoutObjectCounter.reset(); |
clearFragmentAnchor(); |
m_viewportConstrainedObjects.reset(); |
@@ -703,7 +705,7 @@ void FrameView::adjustViewSizeAndLayout() { |
void FrameView::calculateScrollbarModesFromOverflowStyle( |
const ComputedStyle* style, |
ScrollbarMode& hMode, |
- ScrollbarMode& vMode) { |
+ ScrollbarMode& vMode) const { |
hMode = vMode = ScrollbarAuto; |
EOverflow overflowX = style->overflowX(); |
@@ -725,7 +727,7 @@ void FrameView::calculateScrollbarModesFromOverflowStyle( |
void FrameView::calculateScrollbarModes( |
ScrollbarMode& hMode, |
ScrollbarMode& vMode, |
- ScrollbarModesCalculationStrategy strategy) { |
+ ScrollbarModesCalculationStrategy strategy) const { |
#define RETURN_SCROLLBAR_MODE(mode) \ |
{ \ |
hMode = vMode = mode; \ |
@@ -832,10 +834,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(); |
} |
@@ -2541,7 +2541,7 @@ bool FrameView::isProgrammaticallyScrollable() { |
return !m_inUpdateScrollbars; |
} |
-FrameView::ScrollingReasons FrameView::getScrollingReasons() { |
+FrameView::ScrollingReasons FrameView::getScrollingReasons() const { |
// Check for: |
// 1) If there an actual overflow. |
// 2) display:none or visibility:hidden set to self or inherited. |
@@ -4704,4 +4704,149 @@ int FrameView::initialViewportHeight() const { |
return m_initialViewportSize.height(); |
} |
+bool FrameView::hasVisibleSlowRepaintViewportConstrainedObjects() const { |
+ 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 |= toLocalFrame(frame).view()->mainThreadScrollingReasonsPerFrame(); |
+ if (WebLayer* scrollLayer = |
+ toLocalFrame(frame).view()->layerForScrolling()->platformLayer()) { |
+ if (reasons) { |
+ scrollLayer->addMainThreadScrollingReasons(reasons); |
+ } else { |
+ // Clear all main thread scrolling reasons except the one that's set |
+ // if there is a running scroll animation. |
+ scrollLayer->clearMainThreadScrollingReasons( |
+ ~MainThreadScrollingReason::kHandlingScrollFromMainThread); |
+ } |
+ } |
+ |
+ Frame* child = frame.tree().firstChild(); |
+ while (child) { |
+ updateSubFrameScrollOnMainReason(*child, reasons); |
+ child = child->tree().nextSibling(); |
+ } |
+ |
+ if (frame.isMainFrame()) |
+ m_mainThreadScrollingReasons = reasons; |
+} |
+ |
+MainThreadScrollingReasons FrameView::mainThreadScrollingReasonsPerFrame() |
+ const { |
+ MainThreadScrollingReasons reasons = |
+ static_cast<MainThreadScrollingReasons>(0); |
+ |
+ if (shouldThrottleRendering()) |
+ return reasons; |
+ |
+ if (hasBackgroundAttachmentFixedObjects()) |
+ reasons |= MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects; |
+ ScrollingReasons scrollingReasons = 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()) { |
+ 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 the tree to the root. Use the gathered 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 |= |
+ toLocalFrame(frame)->view()->mainThreadScrollingReasonsPerFrame(); |
+ } |
+ |
+ 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_mainThreadScrollingReasons) |
+ .c_str()); |
+ return result; |
+} |
+ |
} // namespace blink |