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

Side by Side Diff: third_party/WebKit/Source/core/frame/FrameView.cpp

Issue 2272773002: Use intersection observer to control frame throttling (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add support for setting initial observer state Created 4 years, 1 month 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 unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> 2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 * 1999 Lars Knoll <knoll@kde.org> 3 * 1999 Lars Knoll <knoll@kde.org>
4 * 1999 Antti Koivisto <koivisto@kde.org> 4 * 1999 Antti Koivisto <koivisto@kde.org>
5 * 2000 Dirk Mueller <mueller@kde.org> 5 * 2000 Dirk Mueller <mueller@kde.org>
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
7 * (C) 2006 Graham Dennis (graham.dennis@gmail.com) 7 * (C) 2006 Graham Dennis (graham.dennis@gmail.com)
8 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) 8 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9 * Copyright (C) 2009 Google Inc. All rights reserved. 9 * Copyright (C) 2009 Google Inc. All rights reserved.
10 * 10 *
(...skipping 15 matching lines...) Expand all
26 26
27 #include "core/frame/FrameView.h" 27 #include "core/frame/FrameView.h"
28 28
29 #include "core/HTMLNames.h" 29 #include "core/HTMLNames.h"
30 #include "core/MediaTypeNames.h" 30 #include "core/MediaTypeNames.h"
31 #include "core/animation/DocumentAnimations.h" 31 #include "core/animation/DocumentAnimations.h"
32 #include "core/css/FontFaceSet.h" 32 #include "core/css/FontFaceSet.h"
33 #include "core/css/resolver/StyleResolver.h" 33 #include "core/css/resolver/StyleResolver.h"
34 #include "core/dom/AXObjectCache.h" 34 #include "core/dom/AXObjectCache.h"
35 #include "core/dom/DOMNodeIds.h" 35 #include "core/dom/DOMNodeIds.h"
36 #include "core/dom/ElementVisibilityObserver.h"
36 #include "core/dom/Fullscreen.h" 37 #include "core/dom/Fullscreen.h"
38 #include "core/dom/IntersectionObserverCallback.h"
37 #include "core/dom/IntersectionObserverController.h" 39 #include "core/dom/IntersectionObserverController.h"
40 #include "core/dom/IntersectionObserverInit.h"
38 #include "core/editing/EditingUtilities.h" 41 #include "core/editing/EditingUtilities.h"
39 #include "core/editing/FrameSelection.h" 42 #include "core/editing/FrameSelection.h"
40 #include "core/editing/RenderedPosition.h" 43 #include "core/editing/RenderedPosition.h"
41 #include "core/editing/markers/DocumentMarkerController.h" 44 #include "core/editing/markers/DocumentMarkerController.h"
42 #include "core/events/ErrorEvent.h" 45 #include "core/events/ErrorEvent.h"
43 #include "core/fetch/ResourceFetcher.h" 46 #include "core/fetch/ResourceFetcher.h"
44 #include "core/frame/EventHandlerRegistry.h" 47 #include "core/frame/EventHandlerRegistry.h"
45 #include "core/frame/FrameHost.h" 48 #include "core/frame/FrameHost.h"
46 #include "core/frame/LocalFrame.h" 49 #include "core/frame/LocalFrame.h"
47 #include "core/frame/Location.h" 50 #include "core/frame/Location.h"
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 static bool s_initialTrackAllPaintInvalidations = false; 149 static bool s_initialTrackAllPaintInvalidations = false;
147 150
148 FrameView::FrameView(LocalFrame* frame) 151 FrameView::FrameView(LocalFrame* frame)
149 : m_frame(frame), 152 : m_frame(frame),
150 m_displayMode(WebDisplayModeBrowser), 153 m_displayMode(WebDisplayModeBrowser),
151 m_canHaveScrollbars(true), 154 m_canHaveScrollbars(true),
152 m_hasPendingLayout(false), 155 m_hasPendingLayout(false),
153 m_inSynchronousPostLayout(false), 156 m_inSynchronousPostLayout(false),
154 m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired), 157 m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired),
155 m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired), 158 m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired),
156 m_renderThrottlingObserverNotificationFactory(
157 CancellableTaskFactory::create(
158 this,
159 &FrameView::notifyRenderThrottlingObservers)),
160 m_isTransparent(false), 159 m_isTransparent(false),
161 m_baseBackgroundColor(Color::white), 160 m_baseBackgroundColor(Color::white),
162 m_mediaType(MediaTypeNames::screen), 161 m_mediaType(MediaTypeNames::screen),
163 m_safeToPropagateScrollToParent(true), 162 m_safeToPropagateScrollToParent(true),
164 m_scrollCorner(nullptr), 163 m_scrollCorner(nullptr),
165 m_stickyPositionObjectCount(0), 164 m_stickyPositionObjectCount(0),
166 m_inputEventsScaleFactorForEmulation(1), 165 m_inputEventsScaleFactorForEmulation(1),
167 m_layoutSizeFixedToFrameSize(true), 166 m_layoutSizeFixedToFrameSize(true),
168 m_didScrollTimer(this, &FrameView::didScrollTimerFired), 167 m_didScrollTimer(this, &FrameView::didScrollTimerFired),
169 m_topControlsViewportAdjustment(0), 168 m_topControlsViewportAdjustment(0),
170 m_needsUpdateWidgetGeometries(false), 169 m_needsUpdateWidgetGeometries(false),
171 m_needsUpdateViewportIntersection(true), 170 m_needsUpdateViewportIntersection(true),
172 m_needsUpdateViewportIntersectionInSubtree(true),
173 #if ENABLE(ASSERT) 171 #if ENABLE(ASSERT)
174 m_hasBeenDisposed(false), 172 m_hasBeenDisposed(false),
175 #endif 173 #endif
176 m_horizontalScrollbarMode(ScrollbarAuto), 174 m_horizontalScrollbarMode(ScrollbarAuto),
177 m_verticalScrollbarMode(ScrollbarAuto), 175 m_verticalScrollbarMode(ScrollbarAuto),
178 m_horizontalScrollbarLock(false), 176 m_horizontalScrollbarLock(false),
179 m_verticalScrollbarLock(false), 177 m_verticalScrollbarLock(false),
180 m_scrollbarsSuppressed(false), 178 m_scrollbarsSuppressed(false),
181 m_inUpdateScrollbars(false), 179 m_inUpdateScrollbars(false),
182 m_frameTimingRequestsDirty(true), 180 m_frameTimingRequestsDirty(true),
183 m_viewportIntersectionValid(false),
184 m_hiddenForThrottling(false), 181 m_hiddenForThrottling(false),
185 m_crossOriginForThrottling(false),
186 m_subtreeThrottled(false), 182 m_subtreeThrottled(false),
187 m_currentUpdateLifecyclePhasesTargetState( 183 m_currentUpdateLifecyclePhasesTargetState(
188 DocumentLifecycle::Uninitialized), 184 DocumentLifecycle::Uninitialized),
189 m_scrollAnchor(this), 185 m_scrollAnchor(this),
190 m_needsScrollbarsUpdate(false), 186 m_needsScrollbarsUpdate(false),
191 m_suppressAdjustViewSize(false), 187 m_suppressAdjustViewSize(false),
192 m_allowsLayoutInvalidationAfterLayoutClean(true) { 188 m_allowsLayoutInvalidationAfterLayoutClean(true) {
193 ASSERT(m_frame); 189 ASSERT(m_frame);
194 init(); 190 init();
195 } 191 }
(...skipping 20 matching lines...) Expand all
216 DEFINE_TRACE(FrameView) { 212 DEFINE_TRACE(FrameView) {
217 visitor->trace(m_frame); 213 visitor->trace(m_frame);
218 visitor->trace(m_fragmentAnchor); 214 visitor->trace(m_fragmentAnchor);
219 visitor->trace(m_scrollableAreas); 215 visitor->trace(m_scrollableAreas);
220 visitor->trace(m_animatingScrollableAreas); 216 visitor->trace(m_animatingScrollableAreas);
221 visitor->trace(m_autoSizeInfo); 217 visitor->trace(m_autoSizeInfo);
222 visitor->trace(m_horizontalScrollbar); 218 visitor->trace(m_horizontalScrollbar);
223 visitor->trace(m_verticalScrollbar); 219 visitor->trace(m_verticalScrollbar);
224 visitor->trace(m_children); 220 visitor->trace(m_children);
225 visitor->trace(m_viewportScrollableArea); 221 visitor->trace(m_viewportScrollableArea);
222 visitor->trace(m_visibilityObserver);
226 visitor->trace(m_scrollAnchor); 223 visitor->trace(m_scrollAnchor);
227 Widget::trace(visitor); 224 Widget::trace(visitor);
228 ScrollableArea::trace(visitor); 225 ScrollableArea::trace(visitor);
229 } 226 }
230 227
231 void FrameView::reset() { 228 void FrameView::reset() {
232 m_hasPendingLayout = false; 229 m_hasPendingLayout = false;
233 m_layoutSchedulingEnabled = true; 230 m_layoutSchedulingEnabled = true;
234 m_inSynchronousPostLayout = false; 231 m_inSynchronousPostLayout = false;
235 m_layoutCount = 0; 232 m_layoutCount = 0;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 reset(); 273 reset();
277 274
278 m_size = LayoutSize(); 275 m_size = LayoutSize();
279 276
280 // Propagate the marginwidth/height and scrolling modes to the view. 277 // Propagate the marginwidth/height and scrolling modes to the view.
281 if (m_frame->owner() && 278 if (m_frame->owner() &&
282 m_frame->owner()->scrollingMode() == ScrollbarAlwaysOff) 279 m_frame->owner()->scrollingMode() == ScrollbarAlwaysOff)
283 setCanHaveScrollbars(false); 280 setCanHaveScrollbars(false);
284 } 281 }
285 282
283 void FrameView::setupRenderThrottling() {
284 if (m_visibilityObserver)
285 return;
286
287 // We observe the frame owner element instead of the document element, because
288 // if the document has no content we can falsely think the frame is invisible.
289 // Note that this means we cannot throttle top-level frames or (currently)
290 // frames whose owner element is remote.
291 Element* targetElement = frame().deprecatedLocalOwner();
292 if (!targetElement)
293 return;
294
295 m_visibilityObserver = new ElementVisibilityObserver(
296 targetElement, WTF::bind(
297 [](FrameView* frameView, bool isVisible) {
298 frameView->updateRenderThrottlingStatus(
299 !isVisible, frameView->m_subtreeThrottled);
300 },
301 wrapWeakPersistent(this)));
302 m_visibilityObserver->start();
303 }
304
286 void FrameView::dispose() { 305 void FrameView::dispose() {
287 RELEASE_ASSERT(!isInPerformLayout()); 306 RELEASE_ASSERT(!isInPerformLayout());
288 307
289 if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) 308 if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator())
290 scrollAnimator->cancelAnimation(); 309 scrollAnimator->cancelAnimation();
291 cancelProgrammaticScrollAnimation(); 310 cancelProgrammaticScrollAnimation();
292 311
293 detachScrollbars(); 312 detachScrollbars();
294 313
295 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) 314 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
296 scrollingCoordinator->willDestroyScrollableArea(this); 315 scrollingCoordinator->willDestroyScrollableArea(this);
297 316
298 // We need to clear the RootFrameViewport's animator since it gets called 317 // We need to clear the RootFrameViewport's animator since it gets called
299 // from non-GC'd objects and RootFrameViewport will still have a pointer to 318 // from non-GC'd objects and RootFrameViewport will still have a pointer to
300 // this class. 319 // this class.
301 if (m_viewportScrollableArea) 320 if (m_viewportScrollableArea)
302 m_viewportScrollableArea->clearScrollAnimators(); 321 m_viewportScrollableArea->clearScrollAnimators();
303 322
304 clearScrollAnimators(); 323 clearScrollAnimators();
305 324
306 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing 325 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing
307 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|. 326 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|.
308 m_autoSizeInfo.clear(); 327 m_autoSizeInfo.clear();
309 328
310 m_postLayoutTasksTimer.stop(); 329 m_postLayoutTasksTimer.stop();
311 m_didScrollTimer.stop(); 330 m_didScrollTimer.stop();
312 331
313 m_renderThrottlingObserverNotificationFactory->cancel();
314
315 // FIXME: Do we need to do something here for OOPI? 332 // FIXME: Do we need to do something here for OOPI?
316 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); 333 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
317 // TODO(dcheng): It seems buggy that we can have an owner element that 334 // TODO(dcheng): It seems buggy that we can have an owner element that
318 // points to another Widget. 335 // points to another Widget.
319 if (ownerElement && ownerElement->ownedWidget() == this) 336 if (ownerElement && ownerElement->ownedWidget() == this)
320 ownerElement->setWidget(nullptr); 337 ownerElement->setWidget(nullptr);
321 338
322 #if ENABLE(ASSERT) 339 #if ENABLE(ASSERT)
323 m_hasBeenDisposed = true; 340 m_hasBeenDisposed = true;
324 #endif 341 #endif
(...skipping 3007 matching lines...) Expand 10 before | Expand all | Expand 10 after
3332 } 3349 }
3333 3350
3334 void FrameView::setParent(Widget* parentView) { 3351 void FrameView::setParent(Widget* parentView) {
3335 if (parentView == parent()) 3352 if (parentView == parent())
3336 return; 3353 return;
3337 3354
3338 Widget::setParent(parentView); 3355 Widget::setParent(parentView);
3339 3356
3340 updateScrollableAreaSet(); 3357 updateScrollableAreaSet();
3341 setNeedsUpdateViewportIntersection(); 3358 setNeedsUpdateViewportIntersection();
3359 setupRenderThrottling();
3360
3361 if (parentFrameView())
3362 m_subtreeThrottled = parentFrameView()->canThrottleRendering();
3342 } 3363 }
3343 3364
3344 void FrameView::removeChild(Widget* child) { 3365 void FrameView::removeChild(Widget* child) {
3345 ASSERT(child->parent() == this); 3366 ASSERT(child->parent() == this);
3346 3367
3347 if (child->isFrameView()) 3368 if (child->isFrameView())
3348 removeScrollableArea(toFrameView(child)); 3369 removeScrollableArea(toFrameView(child));
3349 3370
3350 child->setParent(0); 3371 child->setParent(0);
3351 m_children.remove(child); 3372 m_children.remove(child);
(...skipping 936 matching lines...) Expand 10 before | Expand all | Expand 10 after
4288 if (layoutObject.isText()) 4309 if (layoutObject.isText())
4289 return; 4310 return;
4290 4311
4291 layoutObject.addAnnotatedRegions(regions); 4312 layoutObject.addAnnotatedRegions(regions);
4292 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; 4313 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr;
4293 curr = curr->nextSibling()) 4314 curr = curr->nextSibling())
4294 collectAnnotatedRegions(*curr, regions); 4315 collectAnnotatedRegions(*curr, regions);
4295 } 4316 }
4296 4317
4297 void FrameView::setNeedsUpdateViewportIntersection() { 4318 void FrameView::setNeedsUpdateViewportIntersection() {
4298 m_needsUpdateViewportIntersection = true;
4299 for (FrameView* parent = parentFrameView(); parent; 4319 for (FrameView* parent = parentFrameView(); parent;
4300 parent = parent->parentFrameView()) 4320 parent = parent->parentFrameView())
4301 parent->m_needsUpdateViewportIntersectionInSubtree = true; 4321 parent->m_needsUpdateViewportIntersectionInSubtree = true;
4302 } 4322 }
4303 4323
4304 void FrameView::updateViewportIntersectionIfNeeded() {
4305 if (!m_needsUpdateViewportIntersection)
4306 return;
4307 m_needsUpdateViewportIntersection = false;
4308 m_viewportIntersectionValid = true;
4309 FrameView* parent = parentFrameView();
4310 if (!parent) {
4311 HTMLFrameOwnerElement* element = frame().deprecatedLocalOwner();
4312 if (!element)
4313 frame().document()->maybeRecordLoadReason(WouldLoadOutOfProcess);
4314 // Having no layout object means the frame is not drawn.
4315 else if (!element->layoutObject())
4316 frame().document()->maybeRecordLoadReason(WouldLoadDisplayNone);
4317 m_viewportIntersection = frameRect();
4318 return;
4319 }
4320 ASSERT(!parent->m_needsUpdateViewportIntersection);
4321
4322 bool parentLoaded = parent->frame().document()->wouldLoadReason() > Created;
4323 // If the parent wasn't loaded, the children won't be either.
4324 if (parentLoaded) {
4325 if (frameRect().isEmpty())
4326 frame().document()->maybeRecordLoadReason(WouldLoadZeroByZero);
4327 else if (frameRect().maxY() < 0)
4328 frame().document()->maybeRecordLoadReason(WouldLoadAbove);
4329 else if (frameRect().maxX() < 0)
4330 frame().document()->maybeRecordLoadReason(WouldLoadLeft);
4331 }
4332
4333 // If our parent is hidden, then we are too.
4334 if (parent->m_viewportIntersection.isEmpty()) {
4335 m_viewportIntersection = parent->m_viewportIntersection;
4336 return;
4337 }
4338
4339 // Transform our bounds into the root frame's content coordinate space,
4340 // making sure we have valid layout data in our parent document. If our
4341 // parent is throttled, we'll use possible stale layout information and
4342 // rely on the fact that another lifecycle update will be scheduled once
4343 // our parent becomes unthrottled.
4344 ASSERT(parent->lifecycle().state() >= DocumentLifecycle::LayoutClean ||
4345 parent->shouldThrottleRendering());
4346 m_viewportIntersection = parent->contentsToRootFrame(frameRect());
4347
4348 // TODO(skyostil): Expand the viewport to make it less likely to see stale
4349 // content while scrolling.
4350 IntRect viewport = parent->m_viewportIntersection;
4351 m_viewportIntersection.intersect(viewport);
4352
4353 if (parentLoaded && !m_viewportIntersection.isEmpty())
4354 frame().document()->maybeRecordLoadReason(WouldLoadVisible);
4355 }
4356
4357 void FrameView::updateViewportIntersectionsForSubtree( 4324 void FrameView::updateViewportIntersectionsForSubtree(
4358 DocumentLifecycle::LifecycleState targetState) { 4325 DocumentLifecycle::LifecycleState targetState) {
4359 bool hadValidIntersection = m_viewportIntersectionValid;
4360 bool hadEmptyIntersection = m_viewportIntersection.isEmpty();
4361 updateViewportIntersectionIfNeeded();
4362
4363 // Notify javascript IntersectionObservers 4326 // Notify javascript IntersectionObservers
4364 if (targetState == DocumentLifecycle::PaintClean && 4327 if (targetState == DocumentLifecycle::PaintClean &&
4365 frame().document()->intersectionObserverController()) 4328 frame().document()->intersectionObserverController())
4366 frame() 4329 frame()
4367 .document() 4330 .document()
4368 ->intersectionObserverController() 4331 ->intersectionObserverController()
4369 ->computeTrackedIntersectionObservations(); 4332 ->computeTrackedIntersectionObservations();
4370 4333
4371 // Adjust render throttling for iframes based on visibility
4372 bool shouldNotify = !hadValidIntersection ||
4373 hadEmptyIntersection != m_viewportIntersection.isEmpty();
4374 if (shouldNotify &&
4375 !m_renderThrottlingObserverNotificationFactory->isPending())
4376 m_frame->frameScheduler()->unthrottledTaskRunner()->postTask(
4377 BLINK_FROM_HERE,
4378 m_renderThrottlingObserverNotificationFactory->cancelAndCreate());
4379
4380 if (!m_needsUpdateViewportIntersectionInSubtree) 4334 if (!m_needsUpdateViewportIntersectionInSubtree)
4381 return; 4335 return;
4382 m_needsUpdateViewportIntersectionInSubtree = false; 4336 m_needsUpdateViewportIntersectionInSubtree = false;
4383 4337
4384 for (Frame* child = m_frame->tree().firstChild(); child; 4338 for (Frame* child = m_frame->tree().firstChild(); child;
4385 child = child->tree().nextSibling()) { 4339 child = child->tree().nextSibling()) {
4386 if (!child->isLocalFrame()) 4340 if (!child->isLocalFrame())
4387 continue; 4341 continue;
4388 if (FrameView* view = toLocalFrame(child)->view()) 4342 if (FrameView* view = toLocalFrame(child)->view())
4389 view->updateViewportIntersectionsForSubtree(targetState); 4343 view->updateViewportIntersectionsForSubtree(targetState);
4390 } 4344 }
4391 } 4345 }
4392 4346
4393 void FrameView::updateThrottlingStatus() { 4347 void FrameView::updateRenderThrottlingStatusForTesting() {
4394 // Only offscreen frames can be throttled. Note that we disallow throttling 4348 m_visibilityObserver->deliverObservationsForTesting();
4395 // of 0x0 frames because some sites use them to drive UI logic.
4396 DCHECK(m_viewportIntersectionValid);
4397 m_hiddenForThrottling =
4398 m_viewportIntersection.isEmpty() && !frameRect().isEmpty();
4399
4400 // We only throttle the rendering pipeline in cross-origin frames. This is
4401 // to avoid a situation where an ancestor frame directly depends on the
4402 // pipeline timing of a descendant and breaks as a result of throttling.
4403 // The rationale is that cross-origin frames must already communicate with
4404 // asynchronous messages, so they should be able to tolerate some delay in
4405 // receiving replies from a throttled peer.
4406 //
4407 // Check if we can access our parent's security origin.
4408 m_crossOriginForThrottling = false;
4409 // If any of our parents are throttled, we must be too.
4410 m_subtreeThrottled = false;
4411 const SecurityOrigin* origin = frame().securityContext()->getSecurityOrigin();
4412 for (Frame* parentFrame = m_frame->tree().parent(); parentFrame;
4413 parentFrame = parentFrame->tree().parent()) {
4414 const SecurityOrigin* parentOrigin =
4415 parentFrame->securityContext()->getSecurityOrigin();
4416 if (!origin->canAccess(parentOrigin))
4417 m_crossOriginForThrottling = true;
4418 if (parentFrame->isLocalFrame() && toLocalFrame(parentFrame)->view() &&
4419 toLocalFrame(parentFrame)->view()->canThrottleRendering())
4420 m_subtreeThrottled = true;
4421 }
4422 m_frame->frameScheduler()->setFrameVisible(!m_hiddenForThrottling);
4423 m_frame->frameScheduler()->setCrossOrigin(m_crossOriginForThrottling);
4424 } 4349 }
4425 4350
4426 void FrameView::notifyRenderThrottlingObserversForTesting() { 4351 void FrameView::updateRenderThrottlingStatus(bool hidden,
4427 DCHECK(m_renderThrottlingObserverNotificationFactory->isPending()); 4352 bool subtreeThrottled) {
4428 notifyRenderThrottlingObservers(); 4353 TRACE_EVENT0("blink", "FrameView::updateRenderThrottlingStatus");
4429 }
4430
4431 void FrameView::notifyRenderThrottlingObservers() {
4432 TRACE_EVENT0("blink", "FrameView::notifyRenderThrottlingObservers");
4433 DCHECK(!isInPerformLayout()); 4354 DCHECK(!isInPerformLayout());
4434 DCHECK(frame().document()); 4355 DCHECK(!m_frame->document() || !m_frame->document()->inStyleRecalc());
4435 DCHECK(!frame().document()->inStyleRecalc());
4436 bool wasThrottled = canThrottleRendering(); 4356 bool wasThrottled = canThrottleRendering();
4437 4357
4438 updateThrottlingStatus(); 4358 // Note that we disallow throttling of 0x0 frames because some sites use
4359 // them to drive UI logic.
4360 m_hiddenForThrottling = hidden && !frameRect().isEmpty();
4361 m_subtreeThrottled = subtreeThrottled;
4439 4362
4440 bool becameThrottled = !wasThrottled && canThrottleRendering(); 4363 bool isThrottled = canThrottleRendering();
4441 bool becameUnthrottled = wasThrottled && !canThrottleRendering(); 4364 bool becameUnthrottled = wasThrottled && !isThrottled;
4365
4366 // If this FrameView became unthrottled or throttled, we must make sure all
4367 // its children are notified synchronously. Otherwise we 1) might attempt to
4368 // paint one of the children with an out-of-date layout before
4369 // |updateRenderThrottlingStatus| has made it throttled or 2) fail to
4370 // unthrottle a child whose parent is unthrottled by a later notification.
4371 if (wasThrottled != isThrottled) {
4372 for (const Member<Widget>& child : *children()) {
4373 if (child->isFrameView()) {
4374 FrameView* childView = toFrameView(child);
4375 childView->updateRenderThrottlingStatus(
4376 childView->m_hiddenForThrottling, isThrottled);
4377 }
4378 }
4379 }
4380
4442 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); 4381 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator();
4443 if (becameThrottled) {
4444 // If this FrameView became throttled, we must make sure all of its
4445 // children become throttled at the same time. Otherwise we might
4446 // attempt to paint one of the children with an out-of-date layout
4447 // before |notifyRenderThrottlingObservers| has made it throttled.
4448 forAllNonThrottledFrameViews([](FrameView& frameView) {
4449 frameView.m_subtreeThrottled = true;
4450 DCHECK(frameView.canThrottleRendering());
4451 });
4452 }
4453 if (becameUnthrottled) { 4382 if (becameUnthrottled) {
4454 // ScrollingCoordinator needs to update according to the new throttling 4383 // ScrollingCoordinator needs to update according to the new throttling
4455 // status. 4384 // status.
4456 if (scrollingCoordinator) 4385 if (scrollingCoordinator)
4457 scrollingCoordinator->notifyGeometryChanged(); 4386 scrollingCoordinator->notifyGeometryChanged();
4458 // Start ticking animation frames again if necessary. 4387 // Start ticking animation frames again if necessary.
4459 if (page()) 4388 if (page())
4460 page()->animator().scheduleVisualUpdate(m_frame.get()); 4389 page()->animator().scheduleVisualUpdate(m_frame.get());
4461 // Force a full repaint of this frame to ensure we are not left with a 4390 // Force a full repaint of this frame to ensure we are not left with a
4462 // partially painted version of this frame's contents if we skipped 4391 // partially painted version of this frame's contents if we skipped
4463 // painting them while the frame was throttled. 4392 // painting them while the frame was throttled.
4464 LayoutViewItem layoutViewItem = this->layoutViewItem(); 4393 LayoutViewItem layoutViewItem = this->layoutViewItem();
4465 if (!layoutViewItem.isNull()) 4394 if (!layoutViewItem.isNull())
4466 layoutViewItem.invalidatePaintForViewAndCompositedLayers(); 4395 layoutViewItem.invalidatePaintForViewAndCompositedLayers();
4467 } 4396 }
4468 4397
4469 bool hasHandlers = m_frame->host() && 4398 bool hasHandlers = m_frame->host() &&
4470 m_frame->host()->eventHandlerRegistry().hasEventHandlers( 4399 m_frame->host()->eventHandlerRegistry().hasEventHandlers(
4471 EventHandlerRegistry::TouchStartOrMoveEventBlocking); 4400 EventHandlerRegistry::TouchStartOrMoveEventBlocking);
4472 if (wasThrottled != canThrottleRendering() && scrollingCoordinator && 4401 if (wasThrottled != canThrottleRendering() && scrollingCoordinator &&
4473 hasHandlers) 4402 hasHandlers)
4474 scrollingCoordinator->touchEventTargetRectsDidChange(); 4403 scrollingCoordinator->touchEventTargetRectsDidChange();
4475 4404
4405 FrameView* parent = parentFrameView();
4406 if (frame().document()->frame()) {
dgrogan 2016/10/25 22:29:37 Removing this doesn't cause any of the DeferredLoa
Sami 2016/10/26 17:59:35 I think I saw some unrelated tests failing because
Sami 2016/10/27 09:11:10 Yeah, turns out we do need this -- else we get cra
4407 if (!parent) {
4408 HTMLFrameOwnerElement* element = frame().deprecatedLocalOwner();
4409 if (!element)
4410 frame().document()->maybeRecordLoadReason(WouldLoadOutOfProcess);
4411 // Having no layout object means the frame is not drawn.
4412 else if (!element->layoutObject())
4413 frame().document()->maybeRecordLoadReason(WouldLoadDisplayNone);
4414 } else {
4415 // Assume the main frame has always loaded since we don't track its
4416 // visibility.
4417 bool parentLoaded =
4418 !parent->parentFrameView() ||
4419 parent->frame().document()->wouldLoadReason() > Created;
4420 // If the parent wasn't loaded, the children won't be either.
4421 if (parentLoaded) {
4422 if (frameRect().isEmpty())
4423 frame().document()->maybeRecordLoadReason(WouldLoadZeroByZero);
4424 else if (frameRect().maxY() < 0)
4425 frame().document()->maybeRecordLoadReason(WouldLoadAbove);
4426 else if (frameRect().maxX() < 0)
4427 frame().document()->maybeRecordLoadReason(WouldLoadLeft);
4428 else if (!m_hiddenForThrottling)
4429 frame().document()->maybeRecordLoadReason(WouldLoadVisible);
4430 }
4431 }
4432 }
4433
4476 #if DCHECK_IS_ON() 4434 #if DCHECK_IS_ON()
4477 // Make sure we never have an unthrottled frame inside a throttled one. 4435 // Make sure we never have an unthrottled frame inside a throttled one.
4478 FrameView* parent = parentFrameView();
4479 while (parent) { 4436 while (parent) {
4480 DCHECK(canThrottleRendering() || !parent->canThrottleRendering()); 4437 DCHECK(canThrottleRendering() || !parent->canThrottleRendering());
4481 parent = parent->parentFrameView(); 4438 parent = parent->parentFrameView();
4482 } 4439 }
4483 #endif 4440 #endif
4484 } 4441 }
4485 4442
4486 bool FrameView::shouldThrottleRendering() const { 4443 bool FrameView::shouldThrottleRendering() const {
4487 return canThrottleRendering() && lifecycle().throttlingAllowed(); 4444 return canThrottleRendering() && lifecycle().throttlingAllowed();
4488 } 4445 }
4489 4446
4490 bool FrameView::canThrottleRendering() const { 4447 bool FrameView::canThrottleRendering() const {
4491 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled()) 4448 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled())
4492 return false; 4449 return false;
4450 // We only throttle the rendering pipeline in cross-origin frames. This is
4451 // to avoid a situation where an ancestor frame directly depends on the
4452 // pipeline timing of a descendant and breaks as a result of throttling.
4453 // The rationale is that cross-origin frames must already communicate with
4454 // asynchronous messages, so they should be able to tolerate some delay in
4455 // receiving replies from a throttled peer.
4493 return m_subtreeThrottled || 4456 return m_subtreeThrottled ||
4494 (m_hiddenForThrottling && m_crossOriginForThrottling); 4457 (m_hiddenForThrottling && m_frame->isCrossOriginSubframe());
4495 } 4458 }
4496 4459
4497 void FrameView::setInitialViewportSize(const IntSize& viewportSize) { 4460 void FrameView::setInitialViewportSize(const IntSize& viewportSize) {
4498 if (viewportSize == m_initialViewportSize) 4461 if (viewportSize == m_initialViewportSize)
4499 return; 4462 return;
4500 4463
4501 m_initialViewportSize = viewportSize; 4464 m_initialViewportSize = viewportSize;
4502 if (Document* document = m_frame->document()) 4465 if (Document* document = m_frame->document())
4503 document->styleEngine().initialViewportChanged(); 4466 document->styleEngine().initialViewportChanged();
4504 } 4467 }
4505 4468
4506 int FrameView::initialViewportWidth() const { 4469 int FrameView::initialViewportWidth() const {
4507 DCHECK(m_frame->isMainFrame()); 4470 DCHECK(m_frame->isMainFrame());
4508 return m_initialViewportSize.width(); 4471 return m_initialViewportSize.width();
4509 } 4472 }
4510 4473
4511 int FrameView::initialViewportHeight() const { 4474 int FrameView::initialViewportHeight() const {
4512 DCHECK(m_frame->isMainFrame()); 4475 DCHECK(m_frame->isMainFrame());
4513 return m_initialViewportSize.height(); 4476 return m_initialViewportSize.height();
4514 } 4477 }
4515 4478
4516 } // namespace blink 4479 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698