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 2f0ec93decdc0740e811af964dae9a4796203954..86ed70af0e21e8d0d265f3c1b60b413b343acde9 100644 |
| --- a/third_party/WebKit/Source/core/frame/FrameView.cpp |
| +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp |
| @@ -125,6 +125,7 @@ |
| #include "wtf/CurrentTime.h" |
| #include "wtf/PtrUtil.h" |
| #include "wtf/StdLibExtras.h" |
| +#include <algorithm> |
| #include <memory> |
| // Used to check for dirty layouts violating document lifecycle rules. |
| @@ -173,7 +174,6 @@ FrameView::FrameView(LocalFrame& frame) |
| m_didScrollTimer(this, &FrameView::didScrollTimerFired), |
| m_browserControlsViewportAdjustment(0), |
| m_needsUpdateWidgetGeometries(false), |
| - m_needsUpdateViewportIntersection(true), |
| #if ENABLE(ASSERT) |
| m_hasBeenDisposed(false), |
| #endif |
| @@ -311,7 +311,7 @@ void FrameView::setupRenderThrottling() { |
| [](FrameView* frameView, bool isVisible) { |
| frameView->updateRenderThrottlingStatus( |
| !isVisible, frameView->m_subtreeThrottled); |
| - frameView->maybeRecordLoadReason(); |
| + frameView->recordDeferredLoadingStats(); |
| }, |
| wrapWeakPersistent(this))); |
| m_visibilityObserver->start(); |
| @@ -4475,13 +4475,16 @@ void FrameView::setNeedsUpdateViewportIntersection() { |
| void FrameView::updateViewportIntersectionsForSubtree( |
| DocumentLifecycle::LifecycleState targetState) { |
| - // Notify javascript IntersectionObservers |
| - if (targetState == DocumentLifecycle::PaintClean && |
| - frame().document()->intersectionObserverController()) |
| - frame() |
| - .document() |
| - ->intersectionObserverController() |
| - ->computeTrackedIntersectionObservations(); |
| + if (targetState == DocumentLifecycle::PaintClean) { |
| + recordDeferredLoadingStats(); |
| + // Notify javascript IntersectionObservers |
| + if (frame().document()->intersectionObserverController()) { |
| + frame() |
| + .document() |
| + ->intersectionObserverController() |
| + ->computeTrackedIntersectionObservations(); |
| + } |
| + } |
| if (!m_needsUpdateViewportIntersectionInSubtree) |
| return; |
| @@ -4564,37 +4567,45 @@ void FrameView::updateRenderThrottlingStatus(bool hidden, |
| #endif |
| } |
| -// TODO(esprehn): Rename this and the method on Document to |
| -// recordDeferredLoadReason(). |
| -void FrameView::maybeRecordLoadReason() { |
| +void FrameView::recordDeferredLoadingStats() { |
| + if (!frame().document()->frame() || !frame().isCrossOriginSubframe()) |
| + return; |
| FrameView* parent = parentFrameView(); |
| - if (frame().document()->frame()) { |
| - if (!parent) { |
| - HTMLFrameOwnerElement* element = frame().deprecatedLocalOwner(); |
| - if (!element) |
| - frame().document()->maybeRecordLoadReason(WouldLoadOutOfProcess); |
| - // Having no layout object means the frame is not drawn. |
| - else if (!element->layoutObject()) |
| - frame().document()->maybeRecordLoadReason(WouldLoadDisplayNone); |
| - } else { |
| - // Assume the main frame has always loaded since we don't track its |
| - // visibility. |
| - bool parentLoaded = |
| - !parent->parentFrameView() || |
| - parent->frame().document()->wouldLoadReason() > Created; |
| - // If the parent wasn't loaded, the children won't be either. |
| - if (parentLoaded) { |
| - if (frameRect().isEmpty()) |
| - frame().document()->maybeRecordLoadReason(WouldLoadZeroByZero); |
| - else if (frameRect().maxY() < 0 && frameRect().maxX() < 0) |
| - frame().document()->maybeRecordLoadReason(WouldLoadAboveAndLeft); |
| - else if (frameRect().maxY() < 0) |
| - frame().document()->maybeRecordLoadReason(WouldLoadAbove); |
| - else if (frameRect().maxX() < 0) |
| - frame().document()->maybeRecordLoadReason(WouldLoadLeft); |
| - else if (!m_hiddenForThrottling) |
| - frame().document()->maybeRecordLoadReason(WouldLoadVisible); |
| - } |
| + if (!parent) { |
| + HTMLFrameOwnerElement* element = frame().deprecatedLocalOwner(); |
| + // We would fall into an else block on some teardowns and other weird cases. |
| + if (!element || !element->layoutObject()) |
| + frame().document()->recordDeferredLoadReason(WouldLoadNoParent); |
| + return; |
| + } |
| + // Small inaccuracy: frames with origins that match the top level might be |
| + // nested in a cross-origin frame. To keep code simpler, count such frames as |
| + // WouldLoadVisible, even when their parent is offscreen. |
| + WouldLoadReason whyParentLoaded = WouldLoadVisible; |
| + if (parent->parentFrameView() && parent->frame().isCrossOriginSubframe()) |
| + whyParentLoaded = parent->frame().document()->deferredLoadReason(); |
| + |
| + // If the parent wasn't loaded, the children won't be either. |
| + if (whyParentLoaded == Created) |
| + return; |
| + if (frameRect().isEmpty() || frameRect().maxY() < 0 || |
| + frameRect().maxX() < 0) { |
| + frame().document()->recordDeferredLoadReason(whyParentLoaded); |
| + return; |
| + } |
| + IntRect parentRect = parent->frameRect(); |
| + if (FrameView* grandParent = parent->parentFrameView()) |
| + parentRect = grandParent->contentsToRootFrame(parentRect); |
|
Z_DONOTUSE
2016/12/11 03:39:44
Unfortunately, I think this is n^2 in the frame tr
dgrogan
2016/12/20 22:27:08
I think it's nlgn in the common case but n^2 in th
|
| + const IntRect childRect = parent->contentsToRootFrame(frameRect()); |
| + // Optimization opportunity: Do some arithmetic instead of looping over each |
| + // of the repositioned viewports. |
| + for (int i = 0; i <= 3; ++i) { |
| + IntRect expandedParentRect(parentRect); |
| + expandedParentRect.expand(0, i * parentRect.height()); |
| + if (expandedParentRect.intersects(childRect)) { |
| + frame().document()->recordDeferredLoadReason(static_cast<WouldLoadReason>( |
| + std::min(static_cast<int>(whyParentLoaded), WouldLoadVisible - i))); |
| + return; |
| } |
| } |
| } |