Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Unified Diff: third_party/WebKit/Source/core/frame/FrameView.cpp

Issue 1364063007: Throttle rendering pipeline for invisible frames (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix layout test by not dumping throttled FrameViews. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/frame/FrameView.h ('k') | third_party/WebKit/Source/core/frame/LocalFrame.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 3e42f1a057e32f54b6ed44d2ecc6917706fd40b9..2a2aca87637e3503197e368b09b84cc1d854a62b 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -93,9 +93,11 @@
#include "platform/graphics/GraphicsLayer.h"
#include "platform/graphics/GraphicsLayerDebugInfo.h"
#include "platform/graphics/paint/PaintController.h"
+#include "platform/scheduler/CancellableTaskFactory.h"
#include "platform/scroll/ScrollAnimator.h"
#include "platform/text/TextStream.h"
#include "public/platform/WebDisplayItemList.h"
+#include "public/platform/WebFrameScheduler.h"
#include "wtf/CurrentTime.h"
#include "wtf/StdLibExtras.h"
#include "wtf/TemporaryChange.h"
@@ -119,6 +121,7 @@ FrameView::FrameView(LocalFrame* frame)
, m_inSynchronousPostLayout(false)
, m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
, m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired)
+ , m_intersectionObserverNotificationFactory(CancellableTaskFactory::create(this, &FrameView::notifyIntersectionObservers))
, m_isTransparent(false)
, m_baseBackgroundColor(Color::white)
, m_mediaType(MediaTypeNames::screen)
@@ -130,6 +133,8 @@ FrameView::FrameView(LocalFrame* frame)
, m_didScrollTimer(this, &FrameView::didScrollTimerFired)
, m_topControlsViewportAdjustment(0)
, m_needsUpdateWidgetPositions(false)
+ , m_needsUpdateViewportIntersection(true)
+ , m_needsUpdateViewportIntersectionInSubtree(true)
#if ENABLE(ASSERT)
, m_hasBeenDisposed(false)
#endif
@@ -141,7 +146,9 @@ FrameView::FrameView(LocalFrame* frame)
, m_scrollbarsSuppressed(false)
, m_inUpdateScrollbars(false)
, m_frameTimingRequestsDirty(true)
-
+ , m_viewportIntersectionValid(false)
+ , m_hiddenForThrottling(false)
+ , m_crossOriginForThrottling(false)
{
ASSERT(m_frame);
init();
@@ -278,6 +285,7 @@ void FrameView::dispose()
if (m_didScrollTimer.isActive())
m_didScrollTimer.stop();
+ m_intersectionObserverNotificationFactory->cancel();
// FIXME: Do we need to do something here for OOPI?
HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
@@ -888,7 +896,7 @@ void FrameView::layout()
ScriptForbiddenScope forbidScript;
- if (isInPerformLayout() || !m_frame->document()->isActive())
+ if (isInPerformLayout() || !m_frame->document()->isActive() || shouldThrottleRendering())
return;
TRACE_EVENT0("blink,benchmark", "FrameView::layout");
@@ -1072,6 +1080,9 @@ void FrameView::layout()
// See http://crbug.com/306706
void FrameView::invalidateTreeIfNeeded(PaintInvalidationState& paintInvalidationState)
{
+ if (shouldThrottleRendering())
+ return;
+
lifecycle().advanceTo(DocumentLifecycle::InPaintInvalidation);
ASSERT(layoutView());
@@ -1282,6 +1293,8 @@ bool FrameView::shouldSetCursor() const
void FrameView::scrollContentsIfNeededRecursive()
{
forAllFrameViews([](FrameView& frameView) {
+ if (frameView.shouldThrottleRendering())
+ return;
frameView.scrollContentsIfNeeded();
});
}
@@ -1696,7 +1709,8 @@ void FrameView::scheduleRelayout()
return;
m_hasPendingLayout = true;
- page()->animator().scheduleVisualUpdate(m_frame.get());
+ if (!shouldThrottleRendering())
+ page()->animator().scheduleVisualUpdate(m_frame.get());
lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
}
@@ -2410,8 +2424,10 @@ void FrameView::updateLifecyclePhasesInternal(LifeCycleUpdateOption phases, cons
updateStyleAndLayoutIfNeededRecursive();
ASSERT(lifecycle().state() >= DocumentLifecycle::LayoutClean);
alogvinov 2015/10/21 13:02:44 Shouldn't this assert be removed or amended now th
Sami 2015/10/21 13:15:16 Right now I think this works since we never thrott
- if (phases == OnlyUpToLayoutClean)
+ if (phases == OnlyUpToLayoutClean) {
+ updateViewportIntersectionsForSubtree();
return;
+ }
if (LayoutView* view = layoutView()) {
TRACE_EVENT1("devtools.timeline", "UpdateLayerTree", "data", InspectorUpdateLayerTreeEvent::data(m_frame.get()));
@@ -2449,6 +2465,8 @@ void FrameView::updateLifecyclePhasesInternal(LifeCycleUpdateOption phases, cons
|| (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled() && lifecycle().state() == DocumentLifecycle::PaintClean));
}
}
+
+ updateViewportIntersectionsForSubtree();
}
void FrameView::updatePaintProperties()
@@ -2534,6 +2552,9 @@ void FrameView::updateFrameTimingRequestsIfNeeded()
void FrameView::updateStyleAndLayoutIfNeededRecursive()
{
+ if (shouldThrottleRendering())
+ return;
+
// We have to crawl our entire subtree looking for any FrameViews that need
// layout and make sure they are up to date.
// Mac actually tests for intersection with the dirty region and tries not to
@@ -2588,6 +2609,11 @@ void FrameView::updateStyleAndLayoutIfNeededRecursive()
void FrameView::invalidateTreeIfNeededRecursive()
{
ASSERT(layoutView());
+
+ // We need to stop recursing here since a child frame view might not be throttled
+ // even though we are (e.g., it didn't compute its visibility yet).
+ if (shouldThrottleRendering())
+ return;
TRACE_EVENT1("blink", "FrameView::invalidateTreeIfNeededRecursive", "root", layoutView()->debugName().ascii());
Vector<LayoutObject*> pendingDelayedPaintInvalidations;
@@ -2906,6 +2932,7 @@ void FrameView::setParent(Widget* parentView)
toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
updateScrollableAreaSet();
+ setNeedsUpdateViewportIntersection();
}
void FrameView::removeChild(Widget* child)
@@ -2963,6 +2990,7 @@ void FrameView::frameRectsChanged()
if (layoutSizeFixedToFrameSize())
setLayoutSizeInternal(frameRect().size());
+ setNeedsUpdateViewportIntersection();
for (const auto& child : m_children)
child->frameRectsChanged();
}
@@ -3739,11 +3767,16 @@ void FrameView::paint(GraphicsContext* context, const IntRect& rect) const
void FrameView::paint(GraphicsContext* context, const GlobalPaintFlags globalPaintFlags, const IntRect& rect) const
{
+ // TODO(skyostil): Remove this early-out in favor of painting cached scrollbars.
+ if (shouldThrottleRendering())
+ return;
FramePainter(*this).paint(context, globalPaintFlags, rect);
}
void FrameView::paintContents(GraphicsContext* context, const GlobalPaintFlags globalPaintFlags, const IntRect& damageRect) const
{
+ if (shouldThrottleRendering())
+ return;
FramePainter(*this).paintContents(context, globalPaintFlags, damageRect);
}
@@ -3931,6 +3964,9 @@ void FrameView::collectFrameTimingRequests(GraphicsLayerFrameTimingRequests& gra
LocalFrame* localFrame = toLocalFrame(frame);
LayoutRect viewRect = localFrame->contentLayoutObject()->viewRect();
const LayoutBoxModelObject* paintInvalidationContainer = localFrame->contentLayoutObject()->containerForPaintInvalidation();
+ // If the frame is being throttled, its compositing state may not be up to date.
+ if (!paintInvalidationContainer->enclosingLayer()->isAllowedToQueryCompositingState())
+ return;
const GraphicsLayer* graphicsLayer = paintInvalidationContainer->enclosingLayer()->graphicsLayerBacking();
if (!graphicsLayer)
@@ -3941,4 +3977,111 @@ void FrameView::collectFrameTimingRequests(GraphicsLayerFrameTimingRequests& gra
graphicsLayerTimingRequests.add(graphicsLayer, Vector<std::pair<int64_t, WebRect>>()).storedValue->value.append(std::make_pair(m_frame->frameID(), enclosingIntRect(viewRect)));
}
+void FrameView::setNeedsUpdateViewportIntersection()
+{
+ m_needsUpdateViewportIntersection = true;
+ for (FrameView* parent = parentFrameView(); parent; parent = parent->parentFrameView())
+ parent->m_needsUpdateViewportIntersectionInSubtree = true;
+}
+
+void FrameView::updateViewportIntersectionIfNeeded()
+{
+ // TODO(skyostil): Replace this with a real intersection observer.
+ if (!m_needsUpdateViewportIntersection)
+ return;
+ m_needsUpdateViewportIntersection = false;
+ m_viewportIntersectionValid = true;
+
+ FrameView* parent = parentFrameView();
+ if (!parent) {
+ m_viewportIntersection = frameRect();
+ return;
+ }
+ ASSERT(!parent->m_needsUpdateViewportIntersection);
+
+ // If our parent is hidden, then we are too.
+ if (parent->m_viewportIntersection.isEmpty()) {
+ m_viewportIntersection = parent->m_viewportIntersection;
+ return;
+ }
+
+ // Transform our bounds into the root frame's content coordinate space,
+ // making sure we have valid layout data in our parent document. If our
+ // parent is throttled, we'll use possible stale layout information and
+ // rely on the fact that another lifecycle update will be scheduled once
+ // our parent becomes unthrottled.
+ ASSERT(parent->lifecycle().state() >= DocumentLifecycle::LayoutClean || parent->shouldThrottleRendering());
+ m_viewportIntersection = parent->contentsToRootFrame(frameRect());
+
+ // TODO(skyostil): Expand the viewport to make it less likely to see stale content while scrolling.
+ IntRect viewport = parent->m_viewportIntersection;
+ m_viewportIntersection.intersect(viewport);
+}
+
+void FrameView::updateViewportIntersectionsForSubtree()
+{
+ bool hadValidIntersection = m_viewportIntersectionValid;
+ bool hadEmptyIntersection = m_viewportIntersection.isEmpty();
+ updateViewportIntersectionIfNeeded();
+ bool shouldNotify = !hadValidIntersection || hadEmptyIntersection != m_viewportIntersection.isEmpty();
+ if (shouldNotify && !m_intersectionObserverNotificationFactory->isPending())
+ m_frame->frameScheduler()->timerTaskRunner()->postTask(BLINK_FROM_HERE, m_intersectionObserverNotificationFactory->cancelAndCreate());
+
+ if (!m_needsUpdateViewportIntersectionInSubtree)
+ return;
+ m_needsUpdateViewportIntersectionInSubtree = false;
+
+ for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
+ if (!child->isLocalFrame())
+ continue;
+ if (FrameView* view = toLocalFrame(child)->view())
+ view->updateViewportIntersectionsForSubtree();
+ }
+}
+
+void FrameView::notifyIntersectionObservers()
+{
+ TRACE_EVENT0("blink", "FrameView::notifyIntersectionObservers");
+ ASSERT(!isInPerformLayout());
+ ASSERT(!m_frame->document()->inStyleRecalc());
+ bool wasThrottled = canThrottleRendering();
+
+ // Only offscreen frames can be throttled.
+ m_hiddenForThrottling = m_viewportIntersectionValid && m_viewportIntersection.isEmpty();
+
+ // We only throttle the rendering pipeline in cross-origin frames. This is
+ // to avoid a situation where an ancestor frame directly depends on the
+ // pipeline timing of a descendant and breaks as a result of throttling.
+ // The rationale is that cross-origin frames must already communicate with
+ // asynchronous messages, so they should be able to tolerate some delay in
+ // receiving replies from a throttled peer.
+ //
+ // Check if we can access our parent's security origin.
+ m_crossOriginForThrottling = false;
+ const SecurityOrigin* origin = frame().securityContext()->securityOrigin();
+ for (Frame* parentFrame = m_frame->tree().parent(); parentFrame; parentFrame = parentFrame->tree().parent()) {
+ const SecurityOrigin* parentOrigin = parentFrame->securityContext()->securityOrigin();
+ if (!origin->canAccess(parentOrigin)) {
+ m_crossOriginForThrottling = true;
+ break;
+ }
+ }
+
+ bool becameUnthrottled = wasThrottled && !canThrottleRendering();
+ if (becameUnthrottled)
+ page()->animator().scheduleVisualUpdate(m_frame.get());
+}
+
+bool FrameView::shouldThrottleRendering() const
+{
+ return canThrottleRendering() && lifecycle().throttlingAllowed();
+}
+
+bool FrameView::canThrottleRendering() const
+{
+ if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled())
+ return false;
+ return m_hiddenForThrottling && m_crossOriginForThrottling;
+}
+
} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/frame/FrameView.h ('k') | third_party/WebKit/Source/core/frame/LocalFrame.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698