OLD | NEW |
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 Loading... |
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" | |
37 #include "core/dom/Fullscreen.h" | 36 #include "core/dom/Fullscreen.h" |
38 #include "core/dom/IntersectionObserverCallback.h" | |
39 #include "core/dom/IntersectionObserverController.h" | 37 #include "core/dom/IntersectionObserverController.h" |
40 #include "core/dom/IntersectionObserverInit.h" | |
41 #include "core/editing/EditingUtilities.h" | 38 #include "core/editing/EditingUtilities.h" |
42 #include "core/editing/FrameSelection.h" | 39 #include "core/editing/FrameSelection.h" |
43 #include "core/editing/RenderedPosition.h" | 40 #include "core/editing/RenderedPosition.h" |
44 #include "core/editing/markers/DocumentMarkerController.h" | 41 #include "core/editing/markers/DocumentMarkerController.h" |
45 #include "core/events/ErrorEvent.h" | 42 #include "core/events/ErrorEvent.h" |
46 #include "core/fetch/ResourceFetcher.h" | 43 #include "core/fetch/ResourceFetcher.h" |
47 #include "core/frame/BrowserControls.h" | 44 #include "core/frame/BrowserControls.h" |
48 #include "core/frame/EventHandlerRegistry.h" | 45 #include "core/frame/EventHandlerRegistry.h" |
49 #include "core/frame/FrameHost.h" | 46 #include "core/frame/FrameHost.h" |
50 #include "core/frame/LocalFrame.h" | 47 #include "core/frame/LocalFrame.h" |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 static bool s_initialTrackAllPaintInvalidations = false; | 146 static bool s_initialTrackAllPaintInvalidations = false; |
150 | 147 |
151 FrameView::FrameView(LocalFrame* frame) | 148 FrameView::FrameView(LocalFrame* frame) |
152 : m_frame(frame), | 149 : m_frame(frame), |
153 m_displayMode(WebDisplayModeBrowser), | 150 m_displayMode(WebDisplayModeBrowser), |
154 m_canHaveScrollbars(true), | 151 m_canHaveScrollbars(true), |
155 m_hasPendingLayout(false), | 152 m_hasPendingLayout(false), |
156 m_inSynchronousPostLayout(false), | 153 m_inSynchronousPostLayout(false), |
157 m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired), | 154 m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired), |
158 m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired), | 155 m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired), |
| 156 m_renderThrottlingObserverNotificationFactory( |
| 157 CancellableTaskFactory::create( |
| 158 this, |
| 159 &FrameView::notifyRenderThrottlingObservers)), |
159 m_isTransparent(false), | 160 m_isTransparent(false), |
160 m_baseBackgroundColor(Color::white), | 161 m_baseBackgroundColor(Color::white), |
161 m_mediaType(MediaTypeNames::screen), | 162 m_mediaType(MediaTypeNames::screen), |
162 m_safeToPropagateScrollToParent(true), | 163 m_safeToPropagateScrollToParent(true), |
163 m_scrollCorner(nullptr), | 164 m_scrollCorner(nullptr), |
164 m_stickyPositionObjectCount(0), | 165 m_stickyPositionObjectCount(0), |
165 m_inputEventsScaleFactorForEmulation(1), | 166 m_inputEventsScaleFactorForEmulation(1), |
166 m_layoutSizeFixedToFrameSize(true), | 167 m_layoutSizeFixedToFrameSize(true), |
167 m_didScrollTimer(this, &FrameView::didScrollTimerFired), | 168 m_didScrollTimer(this, &FrameView::didScrollTimerFired), |
168 m_browserControlsViewportAdjustment(0), | 169 m_browserControlsViewportAdjustment(0), |
169 m_needsUpdateWidgetGeometries(false), | 170 m_needsUpdateWidgetGeometries(false), |
170 m_needsUpdateViewportIntersection(true), | 171 m_needsUpdateViewportIntersection(true), |
| 172 m_needsUpdateViewportIntersectionInSubtree(true), |
171 #if ENABLE(ASSERT) | 173 #if ENABLE(ASSERT) |
172 m_hasBeenDisposed(false), | 174 m_hasBeenDisposed(false), |
173 #endif | 175 #endif |
174 m_horizontalScrollbarMode(ScrollbarAuto), | 176 m_horizontalScrollbarMode(ScrollbarAuto), |
175 m_verticalScrollbarMode(ScrollbarAuto), | 177 m_verticalScrollbarMode(ScrollbarAuto), |
176 m_horizontalScrollbarLock(false), | 178 m_horizontalScrollbarLock(false), |
177 m_verticalScrollbarLock(false), | 179 m_verticalScrollbarLock(false), |
178 m_scrollbarsSuppressed(false), | 180 m_scrollbarsSuppressed(false), |
179 m_inUpdateScrollbars(false), | 181 m_inUpdateScrollbars(false), |
180 m_frameTimingRequestsDirty(true), | 182 m_frameTimingRequestsDirty(true), |
| 183 m_viewportIntersectionValid(false), |
181 m_hiddenForThrottling(false), | 184 m_hiddenForThrottling(false), |
| 185 m_crossOriginForThrottling(false), |
182 m_subtreeThrottled(false), | 186 m_subtreeThrottled(false), |
183 m_currentUpdateLifecyclePhasesTargetState( | 187 m_currentUpdateLifecyclePhasesTargetState( |
184 DocumentLifecycle::Uninitialized), | 188 DocumentLifecycle::Uninitialized), |
185 m_scrollAnchor(this), | 189 m_scrollAnchor(this), |
186 m_scrollbarManager(*this), | 190 m_scrollbarManager(*this), |
187 m_needsScrollbarsUpdate(false), | 191 m_needsScrollbarsUpdate(false), |
188 m_suppressAdjustViewSize(false), | 192 m_suppressAdjustViewSize(false), |
189 m_allowsLayoutInvalidationAfterLayoutClean(true) { | 193 m_allowsLayoutInvalidationAfterLayoutClean(true) { |
190 ASSERT(m_frame); | 194 ASSERT(m_frame); |
191 init(); | 195 init(); |
(...skipping 19 matching lines...) Expand all Loading... |
211 } | 215 } |
212 | 216 |
213 DEFINE_TRACE(FrameView) { | 217 DEFINE_TRACE(FrameView) { |
214 visitor->trace(m_frame); | 218 visitor->trace(m_frame); |
215 visitor->trace(m_fragmentAnchor); | 219 visitor->trace(m_fragmentAnchor); |
216 visitor->trace(m_scrollableAreas); | 220 visitor->trace(m_scrollableAreas); |
217 visitor->trace(m_animatingScrollableAreas); | 221 visitor->trace(m_animatingScrollableAreas); |
218 visitor->trace(m_autoSizeInfo); | 222 visitor->trace(m_autoSizeInfo); |
219 visitor->trace(m_children); | 223 visitor->trace(m_children); |
220 visitor->trace(m_viewportScrollableArea); | 224 visitor->trace(m_viewportScrollableArea); |
221 visitor->trace(m_visibilityObserver); | |
222 visitor->trace(m_scrollAnchor); | 225 visitor->trace(m_scrollAnchor); |
223 visitor->trace(m_anchoringAdjustmentQueue); | 226 visitor->trace(m_anchoringAdjustmentQueue); |
224 visitor->trace(m_scrollbarManager); | 227 visitor->trace(m_scrollbarManager); |
225 Widget::trace(visitor); | 228 Widget::trace(visitor); |
226 ScrollableArea::trace(visitor); | 229 ScrollableArea::trace(visitor); |
227 } | 230 } |
228 | 231 |
229 void FrameView::reset() { | 232 void FrameView::reset() { |
230 m_hasPendingLayout = false; | 233 m_hasPendingLayout = false; |
231 m_layoutSchedulingEnabled = true; | 234 m_layoutSchedulingEnabled = true; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 reset(); | 277 reset(); |
275 | 278 |
276 m_size = LayoutSize(); | 279 m_size = LayoutSize(); |
277 | 280 |
278 // Propagate the marginwidth/height and scrolling modes to the view. | 281 // Propagate the marginwidth/height and scrolling modes to the view. |
279 if (m_frame->owner() && | 282 if (m_frame->owner() && |
280 m_frame->owner()->scrollingMode() == ScrollbarAlwaysOff) | 283 m_frame->owner()->scrollingMode() == ScrollbarAlwaysOff) |
281 setCanHaveScrollbars(false); | 284 setCanHaveScrollbars(false); |
282 } | 285 } |
283 | 286 |
284 void FrameView::setupRenderThrottling() { | |
285 if (m_visibilityObserver) | |
286 return; | |
287 | |
288 // We observe the frame owner element instead of the document element, because | |
289 // if the document has no content we can falsely think the frame is invisible. | |
290 // Note that this means we cannot throttle top-level frames or (currently) | |
291 // frames whose owner element is remote. | |
292 Element* targetElement = frame().deprecatedLocalOwner(); | |
293 if (!targetElement) | |
294 return; | |
295 | |
296 m_visibilityObserver = new ElementVisibilityObserver( | |
297 targetElement, WTF::bind( | |
298 [](FrameView* frameView, bool isVisible) { | |
299 frameView->updateRenderThrottlingStatus( | |
300 !isVisible, frameView->m_subtreeThrottled); | |
301 }, | |
302 wrapWeakPersistent(this))); | |
303 m_visibilityObserver->start(); | |
304 } | |
305 | |
306 void FrameView::dispose() { | 287 void FrameView::dispose() { |
307 RELEASE_ASSERT(!isInPerformLayout()); | 288 RELEASE_ASSERT(!isInPerformLayout()); |
308 | 289 |
309 if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) | 290 if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) |
310 scrollAnimator->cancelAnimation(); | 291 scrollAnimator->cancelAnimation(); |
311 cancelProgrammaticScrollAnimation(); | 292 cancelProgrammaticScrollAnimation(); |
312 | 293 |
313 detachScrollbars(); | 294 detachScrollbars(); |
314 | 295 |
315 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) | 296 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) |
316 scrollingCoordinator->willDestroyScrollableArea(this); | 297 scrollingCoordinator->willDestroyScrollableArea(this); |
317 | 298 |
318 // We need to clear the RootFrameViewport's animator since it gets called | 299 // We need to clear the RootFrameViewport's animator since it gets called |
319 // from non-GC'd objects and RootFrameViewport will still have a pointer to | 300 // from non-GC'd objects and RootFrameViewport will still have a pointer to |
320 // this class. | 301 // this class. |
321 if (m_viewportScrollableArea) | 302 if (m_viewportScrollableArea) |
322 m_viewportScrollableArea->clearScrollAnimators(); | 303 m_viewportScrollableArea->clearScrollAnimators(); |
323 | 304 |
324 clearScrollAnimators(); | 305 clearScrollAnimators(); |
325 | 306 |
326 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing | 307 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing |
327 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|. | 308 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|. |
328 m_autoSizeInfo.clear(); | 309 m_autoSizeInfo.clear(); |
329 | 310 |
330 m_postLayoutTasksTimer.stop(); | 311 m_postLayoutTasksTimer.stop(); |
331 m_didScrollTimer.stop(); | 312 m_didScrollTimer.stop(); |
332 | 313 |
| 314 m_renderThrottlingObserverNotificationFactory->cancel(); |
| 315 |
333 // FIXME: Do we need to do something here for OOPI? | 316 // FIXME: Do we need to do something here for OOPI? |
334 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); | 317 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); |
335 // TODO(dcheng): It seems buggy that we can have an owner element that | 318 // TODO(dcheng): It seems buggy that we can have an owner element that |
336 // points to another Widget. | 319 // points to another Widget. |
337 if (ownerElement && ownerElement->ownedWidget() == this) | 320 if (ownerElement && ownerElement->ownedWidget() == this) |
338 ownerElement->setWidget(nullptr); | 321 ownerElement->setWidget(nullptr); |
339 | 322 |
340 #if ENABLE(ASSERT) | 323 #if ENABLE(ASSERT) |
341 m_hasBeenDisposed = true; | 324 m_hasBeenDisposed = true; |
342 #endif | 325 #endif |
(...skipping 3084 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3427 } | 3410 } |
3428 | 3411 |
3429 void FrameView::setParent(Widget* parentView) { | 3412 void FrameView::setParent(Widget* parentView) { |
3430 if (parentView == parent()) | 3413 if (parentView == parent()) |
3431 return; | 3414 return; |
3432 | 3415 |
3433 Widget::setParent(parentView); | 3416 Widget::setParent(parentView); |
3434 | 3417 |
3435 updateScrollableAreaSet(); | 3418 updateScrollableAreaSet(); |
3436 setNeedsUpdateViewportIntersection(); | 3419 setNeedsUpdateViewportIntersection(); |
3437 setupRenderThrottling(); | |
3438 | |
3439 if (parentFrameView()) | |
3440 m_subtreeThrottled = parentFrameView()->canThrottleRendering(); | |
3441 } | 3420 } |
3442 | 3421 |
3443 void FrameView::removeChild(Widget* child) { | 3422 void FrameView::removeChild(Widget* child) { |
3444 ASSERT(child->parent() == this); | 3423 ASSERT(child->parent() == this); |
3445 | 3424 |
3446 if (child->isFrameView()) | 3425 if (child->isFrameView()) |
3447 removeScrollableArea(toFrameView(child)); | 3426 removeScrollableArea(toFrameView(child)); |
3448 | 3427 |
3449 child->setParent(0); | 3428 child->setParent(0); |
3450 m_children.remove(child); | 3429 m_children.remove(child); |
(...skipping 896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4347 if (layoutObject.isText()) | 4326 if (layoutObject.isText()) |
4348 return; | 4327 return; |
4349 | 4328 |
4350 layoutObject.addAnnotatedRegions(regions); | 4329 layoutObject.addAnnotatedRegions(regions); |
4351 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; | 4330 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; |
4352 curr = curr->nextSibling()) | 4331 curr = curr->nextSibling()) |
4353 collectAnnotatedRegions(*curr, regions); | 4332 collectAnnotatedRegions(*curr, regions); |
4354 } | 4333 } |
4355 | 4334 |
4356 void FrameView::setNeedsUpdateViewportIntersection() { | 4335 void FrameView::setNeedsUpdateViewportIntersection() { |
| 4336 m_needsUpdateViewportIntersection = true; |
4357 for (FrameView* parent = parentFrameView(); parent; | 4337 for (FrameView* parent = parentFrameView(); parent; |
4358 parent = parent->parentFrameView()) | 4338 parent = parent->parentFrameView()) |
4359 parent->m_needsUpdateViewportIntersectionInSubtree = true; | 4339 parent->m_needsUpdateViewportIntersectionInSubtree = true; |
4360 } | 4340 } |
4361 | 4341 |
| 4342 void FrameView::updateViewportIntersectionIfNeeded() { |
| 4343 if (!m_needsUpdateViewportIntersection) |
| 4344 return; |
| 4345 m_needsUpdateViewportIntersection = false; |
| 4346 m_viewportIntersectionValid = true; |
| 4347 FrameView* parent = parentFrameView(); |
| 4348 if (!parent) { |
| 4349 HTMLFrameOwnerElement* element = frame().deprecatedLocalOwner(); |
| 4350 if (!element) |
| 4351 frame().document()->maybeRecordLoadReason(WouldLoadOutOfProcess); |
| 4352 // Having no layout object means the frame is not drawn. |
| 4353 else if (!element->layoutObject()) |
| 4354 frame().document()->maybeRecordLoadReason(WouldLoadDisplayNone); |
| 4355 m_viewportIntersection = frameRect(); |
| 4356 return; |
| 4357 } |
| 4358 ASSERT(!parent->m_needsUpdateViewportIntersection); |
| 4359 |
| 4360 bool parentLoaded = parent->frame().document()->wouldLoadReason() > Created; |
| 4361 // If the parent wasn't loaded, the children won't be either. |
| 4362 if (parentLoaded) { |
| 4363 if (frameRect().isEmpty()) |
| 4364 frame().document()->maybeRecordLoadReason(WouldLoadZeroByZero); |
| 4365 else if (frameRect().maxY() < 0 && frameRect().maxX() < 0) |
| 4366 frame().document()->maybeRecordLoadReason(WouldLoadAboveAndLeft); |
| 4367 else if (frameRect().maxY() < 0) |
| 4368 frame().document()->maybeRecordLoadReason(WouldLoadAbove); |
| 4369 else if (frameRect().maxX() < 0) |
| 4370 frame().document()->maybeRecordLoadReason(WouldLoadLeft); |
| 4371 } |
| 4372 |
| 4373 // If our parent is hidden, then we are too. |
| 4374 if (parent->m_viewportIntersection.isEmpty()) { |
| 4375 m_viewportIntersection = parent->m_viewportIntersection; |
| 4376 return; |
| 4377 } |
| 4378 |
| 4379 // Transform our bounds into the root frame's content coordinate space, |
| 4380 // making sure we have valid layout data in our parent document. If our |
| 4381 // parent is throttled, we'll use possible stale layout information and |
| 4382 // rely on the fact that another lifecycle update will be scheduled once |
| 4383 // our parent becomes unthrottled. |
| 4384 ASSERT(parent->lifecycle().state() >= DocumentLifecycle::LayoutClean || |
| 4385 parent->shouldThrottleRendering()); |
| 4386 m_viewportIntersection = parent->contentsToRootFrame(frameRect()); |
| 4387 |
| 4388 // TODO(skyostil): Expand the viewport to make it less likely to see stale |
| 4389 // content while scrolling. |
| 4390 IntRect viewport = parent->m_viewportIntersection; |
| 4391 m_viewportIntersection.intersect(viewport); |
| 4392 |
| 4393 if (parentLoaded && !m_viewportIntersection.isEmpty()) |
| 4394 frame().document()->maybeRecordLoadReason(WouldLoadVisible); |
| 4395 } |
| 4396 |
4362 void FrameView::updateViewportIntersectionsForSubtree( | 4397 void FrameView::updateViewportIntersectionsForSubtree( |
4363 DocumentLifecycle::LifecycleState targetState) { | 4398 DocumentLifecycle::LifecycleState targetState) { |
| 4399 bool hadValidIntersection = m_viewportIntersectionValid; |
| 4400 bool hadEmptyIntersection = m_viewportIntersection.isEmpty(); |
| 4401 updateViewportIntersectionIfNeeded(); |
| 4402 |
4364 // Notify javascript IntersectionObservers | 4403 // Notify javascript IntersectionObservers |
4365 if (targetState == DocumentLifecycle::PaintClean && | 4404 if (targetState == DocumentLifecycle::PaintClean && |
4366 frame().document()->intersectionObserverController()) | 4405 frame().document()->intersectionObserverController()) |
4367 frame() | 4406 frame() |
4368 .document() | 4407 .document() |
4369 ->intersectionObserverController() | 4408 ->intersectionObserverController() |
4370 ->computeTrackedIntersectionObservations(); | 4409 ->computeTrackedIntersectionObservations(); |
4371 | 4410 |
| 4411 // Adjust render throttling for iframes based on visibility |
| 4412 bool shouldNotify = !hadValidIntersection || |
| 4413 hadEmptyIntersection != m_viewportIntersection.isEmpty(); |
| 4414 if (shouldNotify && |
| 4415 !m_renderThrottlingObserverNotificationFactory->isPending()) |
| 4416 m_frame->frameScheduler()->unthrottledTaskRunner()->postTask( |
| 4417 BLINK_FROM_HERE, |
| 4418 m_renderThrottlingObserverNotificationFactory->cancelAndCreate()); |
| 4419 |
4372 if (!m_needsUpdateViewportIntersectionInSubtree) | 4420 if (!m_needsUpdateViewportIntersectionInSubtree) |
4373 return; | 4421 return; |
4374 m_needsUpdateViewportIntersectionInSubtree = false; | 4422 m_needsUpdateViewportIntersectionInSubtree = false; |
4375 | 4423 |
4376 for (Frame* child = m_frame->tree().firstChild(); child; | 4424 for (Frame* child = m_frame->tree().firstChild(); child; |
4377 child = child->tree().nextSibling()) { | 4425 child = child->tree().nextSibling()) { |
4378 if (!child->isLocalFrame()) | 4426 if (!child->isLocalFrame()) |
4379 continue; | 4427 continue; |
4380 if (FrameView* view = toLocalFrame(child)->view()) | 4428 if (FrameView* view = toLocalFrame(child)->view()) |
4381 view->updateViewportIntersectionsForSubtree(targetState); | 4429 view->updateViewportIntersectionsForSubtree(targetState); |
4382 } | 4430 } |
4383 } | 4431 } |
4384 | 4432 |
4385 void FrameView::updateRenderThrottlingStatusForTesting() { | 4433 void FrameView::updateThrottlingStatus() { |
4386 m_visibilityObserver->deliverObservationsForTesting(); | 4434 // Only offscreen frames can be throttled. Note that we disallow throttling |
| 4435 // of 0x0 frames because some sites use them to drive UI logic. |
| 4436 DCHECK(m_viewportIntersectionValid); |
| 4437 m_hiddenForThrottling = |
| 4438 m_viewportIntersection.isEmpty() && !frameRect().isEmpty(); |
| 4439 |
| 4440 // We only throttle the rendering pipeline in cross-origin frames. This is |
| 4441 // to avoid a situation where an ancestor frame directly depends on the |
| 4442 // pipeline timing of a descendant and breaks as a result of throttling. |
| 4443 // The rationale is that cross-origin frames must already communicate with |
| 4444 // asynchronous messages, so they should be able to tolerate some delay in |
| 4445 // receiving replies from a throttled peer. |
| 4446 // |
| 4447 // Check if we can access our parent's security origin. |
| 4448 m_crossOriginForThrottling = false; |
| 4449 // If any of our parents are throttled, we must be too. |
| 4450 m_subtreeThrottled = false; |
| 4451 const SecurityOrigin* origin = frame().securityContext()->getSecurityOrigin(); |
| 4452 for (Frame* parentFrame = m_frame->tree().parent(); parentFrame; |
| 4453 parentFrame = parentFrame->tree().parent()) { |
| 4454 const SecurityOrigin* parentOrigin = |
| 4455 parentFrame->securityContext()->getSecurityOrigin(); |
| 4456 if (!origin->canAccess(parentOrigin)) |
| 4457 m_crossOriginForThrottling = true; |
| 4458 if (parentFrame->isLocalFrame() && toLocalFrame(parentFrame)->view() && |
| 4459 toLocalFrame(parentFrame)->view()->canThrottleRendering()) |
| 4460 m_subtreeThrottled = true; |
| 4461 } |
| 4462 m_frame->frameScheduler()->setFrameVisible(!m_hiddenForThrottling); |
| 4463 m_frame->frameScheduler()->setCrossOrigin(m_crossOriginForThrottling); |
4387 } | 4464 } |
4388 | 4465 |
4389 void FrameView::updateRenderThrottlingStatus(bool hidden, | 4466 void FrameView::notifyRenderThrottlingObserversForTesting() { |
4390 bool subtreeThrottled) { | 4467 DCHECK(m_renderThrottlingObserverNotificationFactory->isPending()); |
4391 TRACE_EVENT0("blink", "FrameView::updateRenderThrottlingStatus"); | 4468 notifyRenderThrottlingObservers(); |
| 4469 } |
| 4470 |
| 4471 void FrameView::notifyRenderThrottlingObservers() { |
| 4472 TRACE_EVENT0("blink", "FrameView::notifyRenderThrottlingObservers"); |
4392 DCHECK(!isInPerformLayout()); | 4473 DCHECK(!isInPerformLayout()); |
4393 DCHECK(!m_frame->document() || !m_frame->document()->inStyleRecalc()); | 4474 DCHECK(frame().document()); |
| 4475 DCHECK(!frame().document()->inStyleRecalc()); |
4394 bool wasThrottled = canThrottleRendering(); | 4476 bool wasThrottled = canThrottleRendering(); |
4395 | 4477 |
4396 // Note that we disallow throttling of 0x0 frames because some sites use | 4478 updateThrottlingStatus(); |
4397 // them to drive UI logic. | |
4398 m_hiddenForThrottling = hidden && !frameRect().isEmpty(); | |
4399 m_subtreeThrottled = subtreeThrottled; | |
4400 | 4479 |
4401 bool isThrottled = canThrottleRendering(); | 4480 bool becameThrottled = !wasThrottled && canThrottleRendering(); |
4402 bool becameUnthrottled = wasThrottled && !isThrottled; | 4481 bool becameUnthrottled = wasThrottled && !canThrottleRendering(); |
4403 | 4482 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); |
4404 // If this FrameView became unthrottled or throttled, we must make sure all | 4483 if (becameThrottled) { |
4405 // its children are notified synchronously. Otherwise we 1) might attempt to | 4484 // If this FrameView became throttled, we must make sure all of its |
4406 // paint one of the children with an out-of-date layout before | 4485 // children become throttled at the same time. Otherwise we might |
4407 // |updateRenderThrottlingStatus| has made it throttled or 2) fail to | 4486 // attempt to paint one of the children with an out-of-date layout |
4408 // unthrottle a child whose parent is unthrottled by a later notification. | 4487 // before |notifyRenderThrottlingObservers| has made it throttled. |
4409 if (wasThrottled != isThrottled) { | 4488 forAllNonThrottledFrameViews([](FrameView& frameView) { |
4410 for (const Member<Widget>& child : *children()) { | 4489 frameView.m_subtreeThrottled = true; |
4411 if (child->isFrameView()) { | 4490 DCHECK(frameView.canThrottleRendering()); |
4412 FrameView* childView = toFrameView(child); | 4491 }); |
4413 childView->updateRenderThrottlingStatus( | |
4414 childView->m_hiddenForThrottling, isThrottled); | |
4415 } | |
4416 } | |
4417 } | 4492 } |
4418 | |
4419 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); | |
4420 if (becameUnthrottled) { | 4493 if (becameUnthrottled) { |
4421 // ScrollingCoordinator needs to update according to the new throttling | 4494 // ScrollingCoordinator needs to update according to the new throttling |
4422 // status. | 4495 // status. |
4423 if (scrollingCoordinator) | 4496 if (scrollingCoordinator) |
4424 scrollingCoordinator->notifyGeometryChanged(); | 4497 scrollingCoordinator->notifyGeometryChanged(); |
4425 // Start ticking animation frames again if necessary. | 4498 // Start ticking animation frames again if necessary. |
4426 if (page()) | 4499 if (page()) |
4427 page()->animator().scheduleVisualUpdate(m_frame.get()); | 4500 page()->animator().scheduleVisualUpdate(m_frame.get()); |
4428 // Force a full repaint of this frame to ensure we are not left with a | 4501 // Force a full repaint of this frame to ensure we are not left with a |
4429 // partially painted version of this frame's contents if we skipped | 4502 // partially painted version of this frame's contents if we skipped |
4430 // painting them while the frame was throttled. | 4503 // painting them while the frame was throttled. |
4431 LayoutViewItem layoutViewItem = this->layoutViewItem(); | 4504 LayoutViewItem layoutViewItem = this->layoutViewItem(); |
4432 if (!layoutViewItem.isNull()) | 4505 if (!layoutViewItem.isNull()) |
4433 layoutViewItem.invalidatePaintForViewAndCompositedLayers(); | 4506 layoutViewItem.invalidatePaintForViewAndCompositedLayers(); |
4434 } | 4507 } |
4435 | 4508 |
4436 bool hasHandlers = m_frame->host() && | 4509 bool hasHandlers = m_frame->host() && |
4437 m_frame->host()->eventHandlerRegistry().hasEventHandlers( | 4510 m_frame->host()->eventHandlerRegistry().hasEventHandlers( |
4438 EventHandlerRegistry::TouchStartOrMoveEventBlocking); | 4511 EventHandlerRegistry::TouchStartOrMoveEventBlocking); |
4439 if (wasThrottled != canThrottleRendering() && scrollingCoordinator && | 4512 if (wasThrottled != canThrottleRendering() && scrollingCoordinator && |
4440 hasHandlers) | 4513 hasHandlers) |
4441 scrollingCoordinator->touchEventTargetRectsDidChange(); | 4514 scrollingCoordinator->touchEventTargetRectsDidChange(); |
4442 | 4515 |
4443 FrameView* parent = parentFrameView(); | |
4444 if (frame().document()->frame()) { | |
4445 if (!parent) { | |
4446 HTMLFrameOwnerElement* element = frame().deprecatedLocalOwner(); | |
4447 if (!element) | |
4448 frame().document()->maybeRecordLoadReason(WouldLoadOutOfProcess); | |
4449 // Having no layout object means the frame is not drawn. | |
4450 else if (!element->layoutObject()) | |
4451 frame().document()->maybeRecordLoadReason(WouldLoadDisplayNone); | |
4452 } else { | |
4453 // Assume the main frame has always loaded since we don't track its | |
4454 // visibility. | |
4455 bool parentLoaded = | |
4456 !parent->parentFrameView() || | |
4457 parent->frame().document()->wouldLoadReason() > Created; | |
4458 // If the parent wasn't loaded, the children won't be either. | |
4459 if (parentLoaded) { | |
4460 if (frameRect().isEmpty()) | |
4461 frame().document()->maybeRecordLoadReason(WouldLoadZeroByZero); | |
4462 else if (frameRect().maxY() < 0 && frameRect().maxX() < 0) | |
4463 frame().document()->maybeRecordLoadReason(WouldLoadAboveAndLeft); | |
4464 else if (frameRect().maxY() < 0) | |
4465 frame().document()->maybeRecordLoadReason(WouldLoadAbove); | |
4466 else if (frameRect().maxX() < 0) | |
4467 frame().document()->maybeRecordLoadReason(WouldLoadLeft); | |
4468 else if (!m_hiddenForThrottling) | |
4469 frame().document()->maybeRecordLoadReason(WouldLoadVisible); | |
4470 } | |
4471 } | |
4472 } | |
4473 | |
4474 #if DCHECK_IS_ON() | 4516 #if DCHECK_IS_ON() |
4475 // Make sure we never have an unthrottled frame inside a throttled one. | 4517 // Make sure we never have an unthrottled frame inside a throttled one. |
| 4518 FrameView* parent = parentFrameView(); |
4476 while (parent) { | 4519 while (parent) { |
4477 DCHECK(canThrottleRendering() || !parent->canThrottleRendering()); | 4520 DCHECK(canThrottleRendering() || !parent->canThrottleRendering()); |
4478 parent = parent->parentFrameView(); | 4521 parent = parent->parentFrameView(); |
4479 } | 4522 } |
4480 #endif | 4523 #endif |
4481 } | 4524 } |
4482 | 4525 |
4483 bool FrameView::shouldThrottleRendering() const { | 4526 bool FrameView::shouldThrottleRendering() const { |
4484 return canThrottleRendering() && lifecycle().throttlingAllowed(); | 4527 return canThrottleRendering() && lifecycle().throttlingAllowed(); |
4485 } | 4528 } |
4486 | 4529 |
4487 bool FrameView::canThrottleRendering() const { | 4530 bool FrameView::canThrottleRendering() const { |
4488 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled()) | 4531 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled()) |
4489 return false; | 4532 return false; |
4490 // We only throttle the rendering pipeline in cross-origin frames. This is | |
4491 // to avoid a situation where an ancestor frame directly depends on the | |
4492 // pipeline timing of a descendant and breaks as a result of throttling. | |
4493 // The rationale is that cross-origin frames must already communicate with | |
4494 // asynchronous messages, so they should be able to tolerate some delay in | |
4495 // receiving replies from a throttled peer. | |
4496 return m_subtreeThrottled || | 4533 return m_subtreeThrottled || |
4497 (m_hiddenForThrottling && m_frame->isCrossOriginSubframe()); | 4534 (m_hiddenForThrottling && m_crossOriginForThrottling); |
4498 } | 4535 } |
4499 | 4536 |
4500 void FrameView::setInitialViewportSize(const IntSize& viewportSize) { | 4537 void FrameView::setInitialViewportSize(const IntSize& viewportSize) { |
4501 if (viewportSize == m_initialViewportSize) | 4538 if (viewportSize == m_initialViewportSize) |
4502 return; | 4539 return; |
4503 | 4540 |
4504 m_initialViewportSize = viewportSize; | 4541 m_initialViewportSize = viewportSize; |
4505 if (Document* document = m_frame->document()) | 4542 if (Document* document = m_frame->document()) |
4506 document->styleEngine().initialViewportChanged(); | 4543 document->styleEngine().initialViewportChanged(); |
4507 } | 4544 } |
4508 | 4545 |
4509 int FrameView::initialViewportWidth() const { | 4546 int FrameView::initialViewportWidth() const { |
4510 DCHECK(m_frame->isMainFrame()); | 4547 DCHECK(m_frame->isMainFrame()); |
4511 return m_initialViewportSize.width(); | 4548 return m_initialViewportSize.width(); |
4512 } | 4549 } |
4513 | 4550 |
4514 int FrameView::initialViewportHeight() const { | 4551 int FrameView::initialViewportHeight() const { |
4515 DCHECK(m_frame->isMainFrame()); | 4552 DCHECK(m_frame->isMainFrame()); |
4516 return m_initialViewportSize.height(); | 4553 return m_initialViewportSize.height(); |
4517 } | 4554 } |
4518 | 4555 |
4519 } // namespace blink | 4556 } // namespace blink |
OLD | NEW |