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" |
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 Loading... |
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_scrollbarManager(*this), | 186 m_scrollbarManager(*this), |
191 m_needsScrollbarsUpdate(false), | 187 m_needsScrollbarsUpdate(false), |
192 m_suppressAdjustViewSize(false), | 188 m_suppressAdjustViewSize(false), |
193 m_allowsLayoutInvalidationAfterLayoutClean(true) { | 189 m_allowsLayoutInvalidationAfterLayoutClean(true) { |
194 ASSERT(m_frame); | 190 ASSERT(m_frame); |
195 init(); | 191 init(); |
(...skipping 19 matching lines...) Expand all Loading... |
215 } | 211 } |
216 | 212 |
217 DEFINE_TRACE(FrameView) { | 213 DEFINE_TRACE(FrameView) { |
218 visitor->trace(m_frame); | 214 visitor->trace(m_frame); |
219 visitor->trace(m_fragmentAnchor); | 215 visitor->trace(m_fragmentAnchor); |
220 visitor->trace(m_scrollableAreas); | 216 visitor->trace(m_scrollableAreas); |
221 visitor->trace(m_animatingScrollableAreas); | 217 visitor->trace(m_animatingScrollableAreas); |
222 visitor->trace(m_autoSizeInfo); | 218 visitor->trace(m_autoSizeInfo); |
223 visitor->trace(m_children); | 219 visitor->trace(m_children); |
224 visitor->trace(m_viewportScrollableArea); | 220 visitor->trace(m_viewportScrollableArea); |
| 221 visitor->trace(m_visibilityObserver); |
225 visitor->trace(m_scrollAnchor); | 222 visitor->trace(m_scrollAnchor); |
226 visitor->trace(m_scrollbarManager); | 223 visitor->trace(m_scrollbarManager); |
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; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 3069 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3394 } | 3411 } |
3395 | 3412 |
3396 void FrameView::setParent(Widget* parentView) { | 3413 void FrameView::setParent(Widget* parentView) { |
3397 if (parentView == parent()) | 3414 if (parentView == parent()) |
3398 return; | 3415 return; |
3399 | 3416 |
3400 Widget::setParent(parentView); | 3417 Widget::setParent(parentView); |
3401 | 3418 |
3402 updateScrollableAreaSet(); | 3419 updateScrollableAreaSet(); |
3403 setNeedsUpdateViewportIntersection(); | 3420 setNeedsUpdateViewportIntersection(); |
| 3421 setupRenderThrottling(); |
| 3422 |
| 3423 if (parentFrameView()) |
| 3424 m_subtreeThrottled = parentFrameView()->canThrottleRendering(); |
3404 } | 3425 } |
3405 | 3426 |
3406 void FrameView::removeChild(Widget* child) { | 3427 void FrameView::removeChild(Widget* child) { |
3407 ASSERT(child->parent() == this); | 3428 ASSERT(child->parent() == this); |
3408 | 3429 |
3409 if (child->isFrameView()) | 3430 if (child->isFrameView()) |
3410 removeScrollableArea(toFrameView(child)); | 3431 removeScrollableArea(toFrameView(child)); |
3411 | 3432 |
3412 child->setParent(0); | 3433 child->setParent(0); |
3413 m_children.remove(child); | 3434 m_children.remove(child); |
(...skipping 897 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4311 if (layoutObject.isText()) | 4332 if (layoutObject.isText()) |
4312 return; | 4333 return; |
4313 | 4334 |
4314 layoutObject.addAnnotatedRegions(regions); | 4335 layoutObject.addAnnotatedRegions(regions); |
4315 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; | 4336 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; |
4316 curr = curr->nextSibling()) | 4337 curr = curr->nextSibling()) |
4317 collectAnnotatedRegions(*curr, regions); | 4338 collectAnnotatedRegions(*curr, regions); |
4318 } | 4339 } |
4319 | 4340 |
4320 void FrameView::setNeedsUpdateViewportIntersection() { | 4341 void FrameView::setNeedsUpdateViewportIntersection() { |
4321 m_needsUpdateViewportIntersection = true; | |
4322 for (FrameView* parent = parentFrameView(); parent; | 4342 for (FrameView* parent = parentFrameView(); parent; |
4323 parent = parent->parentFrameView()) | 4343 parent = parent->parentFrameView()) |
4324 parent->m_needsUpdateViewportIntersectionInSubtree = true; | 4344 parent->m_needsUpdateViewportIntersectionInSubtree = true; |
4325 } | 4345 } |
4326 | 4346 |
4327 void FrameView::updateViewportIntersectionIfNeeded() { | |
4328 if (!m_needsUpdateViewportIntersection) | |
4329 return; | |
4330 m_needsUpdateViewportIntersection = false; | |
4331 m_viewportIntersectionValid = true; | |
4332 FrameView* parent = parentFrameView(); | |
4333 if (!parent) { | |
4334 HTMLFrameOwnerElement* element = frame().deprecatedLocalOwner(); | |
4335 if (!element) | |
4336 frame().document()->maybeRecordLoadReason(WouldLoadOutOfProcess); | |
4337 // Having no layout object means the frame is not drawn. | |
4338 else if (!element->layoutObject()) | |
4339 frame().document()->maybeRecordLoadReason(WouldLoadDisplayNone); | |
4340 m_viewportIntersection = frameRect(); | |
4341 return; | |
4342 } | |
4343 ASSERT(!parent->m_needsUpdateViewportIntersection); | |
4344 | |
4345 bool parentLoaded = parent->frame().document()->wouldLoadReason() > Created; | |
4346 // If the parent wasn't loaded, the children won't be either. | |
4347 if (parentLoaded) { | |
4348 if (frameRect().isEmpty()) | |
4349 frame().document()->maybeRecordLoadReason(WouldLoadZeroByZero); | |
4350 else if (frameRect().maxY() < 0) | |
4351 frame().document()->maybeRecordLoadReason(WouldLoadAbove); | |
4352 else if (frameRect().maxX() < 0) | |
4353 frame().document()->maybeRecordLoadReason(WouldLoadLeft); | |
4354 } | |
4355 | |
4356 // If our parent is hidden, then we are too. | |
4357 if (parent->m_viewportIntersection.isEmpty()) { | |
4358 m_viewportIntersection = parent->m_viewportIntersection; | |
4359 return; | |
4360 } | |
4361 | |
4362 // Transform our bounds into the root frame's content coordinate space, | |
4363 // making sure we have valid layout data in our parent document. If our | |
4364 // parent is throttled, we'll use possible stale layout information and | |
4365 // rely on the fact that another lifecycle update will be scheduled once | |
4366 // our parent becomes unthrottled. | |
4367 ASSERT(parent->lifecycle().state() >= DocumentLifecycle::LayoutClean || | |
4368 parent->shouldThrottleRendering()); | |
4369 m_viewportIntersection = parent->contentsToRootFrame(frameRect()); | |
4370 | |
4371 // TODO(skyostil): Expand the viewport to make it less likely to see stale | |
4372 // content while scrolling. | |
4373 IntRect viewport = parent->m_viewportIntersection; | |
4374 m_viewportIntersection.intersect(viewport); | |
4375 | |
4376 if (parentLoaded && !m_viewportIntersection.isEmpty()) | |
4377 frame().document()->maybeRecordLoadReason(WouldLoadVisible); | |
4378 } | |
4379 | |
4380 void FrameView::updateViewportIntersectionsForSubtree( | 4347 void FrameView::updateViewportIntersectionsForSubtree( |
4381 DocumentLifecycle::LifecycleState targetState) { | 4348 DocumentLifecycle::LifecycleState targetState) { |
4382 bool hadValidIntersection = m_viewportIntersectionValid; | |
4383 bool hadEmptyIntersection = m_viewportIntersection.isEmpty(); | |
4384 updateViewportIntersectionIfNeeded(); | |
4385 | |
4386 // Notify javascript IntersectionObservers | 4349 // Notify javascript IntersectionObservers |
4387 if (targetState == DocumentLifecycle::PaintClean && | 4350 if (targetState == DocumentLifecycle::PaintClean && |
4388 frame().document()->intersectionObserverController()) | 4351 frame().document()->intersectionObserverController()) |
4389 frame() | 4352 frame() |
4390 .document() | 4353 .document() |
4391 ->intersectionObserverController() | 4354 ->intersectionObserverController() |
4392 ->computeTrackedIntersectionObservations(); | 4355 ->computeTrackedIntersectionObservations(); |
4393 | 4356 |
4394 // Adjust render throttling for iframes based on visibility | |
4395 bool shouldNotify = !hadValidIntersection || | |
4396 hadEmptyIntersection != m_viewportIntersection.isEmpty(); | |
4397 if (shouldNotify && | |
4398 !m_renderThrottlingObserverNotificationFactory->isPending()) | |
4399 m_frame->frameScheduler()->unthrottledTaskRunner()->postTask( | |
4400 BLINK_FROM_HERE, | |
4401 m_renderThrottlingObserverNotificationFactory->cancelAndCreate()); | |
4402 | |
4403 if (!m_needsUpdateViewportIntersectionInSubtree) | 4357 if (!m_needsUpdateViewportIntersectionInSubtree) |
4404 return; | 4358 return; |
4405 m_needsUpdateViewportIntersectionInSubtree = false; | 4359 m_needsUpdateViewportIntersectionInSubtree = false; |
4406 | 4360 |
4407 for (Frame* child = m_frame->tree().firstChild(); child; | 4361 for (Frame* child = m_frame->tree().firstChild(); child; |
4408 child = child->tree().nextSibling()) { | 4362 child = child->tree().nextSibling()) { |
4409 if (!child->isLocalFrame()) | 4363 if (!child->isLocalFrame()) |
4410 continue; | 4364 continue; |
4411 if (FrameView* view = toLocalFrame(child)->view()) | 4365 if (FrameView* view = toLocalFrame(child)->view()) |
4412 view->updateViewportIntersectionsForSubtree(targetState); | 4366 view->updateViewportIntersectionsForSubtree(targetState); |
4413 } | 4367 } |
4414 } | 4368 } |
4415 | 4369 |
4416 void FrameView::updateThrottlingStatus() { | 4370 void FrameView::updateRenderThrottlingStatusForTesting() { |
4417 // Only offscreen frames can be throttled. Note that we disallow throttling | 4371 m_visibilityObserver->deliverObservationsForTesting(); |
4418 // of 0x0 frames because some sites use them to drive UI logic. | |
4419 DCHECK(m_viewportIntersectionValid); | |
4420 m_hiddenForThrottling = | |
4421 m_viewportIntersection.isEmpty() && !frameRect().isEmpty(); | |
4422 | |
4423 // We only throttle the rendering pipeline in cross-origin frames. This is | |
4424 // to avoid a situation where an ancestor frame directly depends on the | |
4425 // pipeline timing of a descendant and breaks as a result of throttling. | |
4426 // The rationale is that cross-origin frames must already communicate with | |
4427 // asynchronous messages, so they should be able to tolerate some delay in | |
4428 // receiving replies from a throttled peer. | |
4429 // | |
4430 // Check if we can access our parent's security origin. | |
4431 m_crossOriginForThrottling = false; | |
4432 // If any of our parents are throttled, we must be too. | |
4433 m_subtreeThrottled = false; | |
4434 const SecurityOrigin* origin = frame().securityContext()->getSecurityOrigin(); | |
4435 for (Frame* parentFrame = m_frame->tree().parent(); parentFrame; | |
4436 parentFrame = parentFrame->tree().parent()) { | |
4437 const SecurityOrigin* parentOrigin = | |
4438 parentFrame->securityContext()->getSecurityOrigin(); | |
4439 if (!origin->canAccess(parentOrigin)) | |
4440 m_crossOriginForThrottling = true; | |
4441 if (parentFrame->isLocalFrame() && toLocalFrame(parentFrame)->view() && | |
4442 toLocalFrame(parentFrame)->view()->canThrottleRendering()) | |
4443 m_subtreeThrottled = true; | |
4444 } | |
4445 m_frame->frameScheduler()->setFrameVisible(!m_hiddenForThrottling); | |
4446 m_frame->frameScheduler()->setCrossOrigin(m_crossOriginForThrottling); | |
4447 } | 4372 } |
4448 | 4373 |
4449 void FrameView::notifyRenderThrottlingObserversForTesting() { | 4374 void FrameView::updateRenderThrottlingStatus(bool hidden, |
4450 DCHECK(m_renderThrottlingObserverNotificationFactory->isPending()); | 4375 bool subtreeThrottled) { |
4451 notifyRenderThrottlingObservers(); | 4376 TRACE_EVENT0("blink", "FrameView::updateRenderThrottlingStatus"); |
4452 } | |
4453 | |
4454 void FrameView::notifyRenderThrottlingObservers() { | |
4455 TRACE_EVENT0("blink", "FrameView::notifyRenderThrottlingObservers"); | |
4456 DCHECK(!isInPerformLayout()); | 4377 DCHECK(!isInPerformLayout()); |
4457 DCHECK(frame().document()); | 4378 DCHECK(!m_frame->document() || !m_frame->document()->inStyleRecalc()); |
4458 DCHECK(!frame().document()->inStyleRecalc()); | |
4459 bool wasThrottled = canThrottleRendering(); | 4379 bool wasThrottled = canThrottleRendering(); |
4460 | 4380 |
4461 updateThrottlingStatus(); | 4381 // Note that we disallow throttling of 0x0 frames because some sites use |
| 4382 // them to drive UI logic. |
| 4383 m_hiddenForThrottling = hidden && !frameRect().isEmpty(); |
| 4384 m_subtreeThrottled = subtreeThrottled; |
4462 | 4385 |
4463 bool becameThrottled = !wasThrottled && canThrottleRendering(); | 4386 bool isThrottled = canThrottleRendering(); |
4464 bool becameUnthrottled = wasThrottled && !canThrottleRendering(); | 4387 bool becameUnthrottled = wasThrottled && !isThrottled; |
| 4388 |
| 4389 // If this FrameView became unthrottled or throttled, we must make sure all |
| 4390 // its children are notified synchronously. Otherwise we 1) might attempt to |
| 4391 // paint one of the children with an out-of-date layout before |
| 4392 // |updateRenderThrottlingStatus| has made it throttled or 2) fail to |
| 4393 // unthrottle a child whose parent is unthrottled by a later notification. |
| 4394 if (wasThrottled != isThrottled) { |
| 4395 for (const Member<Widget>& child : *children()) { |
| 4396 if (child->isFrameView()) { |
| 4397 FrameView* childView = toFrameView(child); |
| 4398 childView->updateRenderThrottlingStatus( |
| 4399 childView->m_hiddenForThrottling, isThrottled); |
| 4400 } |
| 4401 } |
| 4402 } |
| 4403 |
4465 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); | 4404 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); |
4466 if (becameThrottled) { | |
4467 // If this FrameView became throttled, we must make sure all of its | |
4468 // children become throttled at the same time. Otherwise we might | |
4469 // attempt to paint one of the children with an out-of-date layout | |
4470 // before |notifyRenderThrottlingObservers| has made it throttled. | |
4471 forAllNonThrottledFrameViews([](FrameView& frameView) { | |
4472 frameView.m_subtreeThrottled = true; | |
4473 DCHECK(frameView.canThrottleRendering()); | |
4474 }); | |
4475 } | |
4476 if (becameUnthrottled) { | 4405 if (becameUnthrottled) { |
4477 // ScrollingCoordinator needs to update according to the new throttling | 4406 // ScrollingCoordinator needs to update according to the new throttling |
4478 // status. | 4407 // status. |
4479 if (scrollingCoordinator) | 4408 if (scrollingCoordinator) |
4480 scrollingCoordinator->notifyGeometryChanged(); | 4409 scrollingCoordinator->notifyGeometryChanged(); |
4481 // Start ticking animation frames again if necessary. | 4410 // Start ticking animation frames again if necessary. |
4482 if (page()) | 4411 if (page()) |
4483 page()->animator().scheduleVisualUpdate(m_frame.get()); | 4412 page()->animator().scheduleVisualUpdate(m_frame.get()); |
4484 // Force a full repaint of this frame to ensure we are not left with a | 4413 // Force a full repaint of this frame to ensure we are not left with a |
4485 // partially painted version of this frame's contents if we skipped | 4414 // partially painted version of this frame's contents if we skipped |
4486 // painting them while the frame was throttled. | 4415 // painting them while the frame was throttled. |
4487 LayoutViewItem layoutViewItem = this->layoutViewItem(); | 4416 LayoutViewItem layoutViewItem = this->layoutViewItem(); |
4488 if (!layoutViewItem.isNull()) | 4417 if (!layoutViewItem.isNull()) |
4489 layoutViewItem.invalidatePaintForViewAndCompositedLayers(); | 4418 layoutViewItem.invalidatePaintForViewAndCompositedLayers(); |
4490 } | 4419 } |
4491 | 4420 |
4492 bool hasHandlers = m_frame->host() && | 4421 bool hasHandlers = m_frame->host() && |
4493 m_frame->host()->eventHandlerRegistry().hasEventHandlers( | 4422 m_frame->host()->eventHandlerRegistry().hasEventHandlers( |
4494 EventHandlerRegistry::TouchStartOrMoveEventBlocking); | 4423 EventHandlerRegistry::TouchStartOrMoveEventBlocking); |
4495 if (wasThrottled != canThrottleRendering() && scrollingCoordinator && | 4424 if (wasThrottled != canThrottleRendering() && scrollingCoordinator && |
4496 hasHandlers) | 4425 hasHandlers) |
4497 scrollingCoordinator->touchEventTargetRectsDidChange(); | 4426 scrollingCoordinator->touchEventTargetRectsDidChange(); |
4498 | 4427 |
| 4428 FrameView* parent = parentFrameView(); |
| 4429 if (frame().document()->frame()) { |
| 4430 if (!parent) { |
| 4431 HTMLFrameOwnerElement* element = frame().deprecatedLocalOwner(); |
| 4432 if (!element) |
| 4433 frame().document()->maybeRecordLoadReason(WouldLoadOutOfProcess); |
| 4434 // Having no layout object means the frame is not drawn. |
| 4435 else if (!element->layoutObject()) |
| 4436 frame().document()->maybeRecordLoadReason(WouldLoadDisplayNone); |
| 4437 } else { |
| 4438 // Assume the main frame has always loaded since we don't track its |
| 4439 // visibility. |
| 4440 bool parentLoaded = |
| 4441 !parent->parentFrameView() || |
| 4442 parent->frame().document()->wouldLoadReason() > Created; |
| 4443 // If the parent wasn't loaded, the children won't be either. |
| 4444 if (parentLoaded) { |
| 4445 if (frameRect().isEmpty()) |
| 4446 frame().document()->maybeRecordLoadReason(WouldLoadZeroByZero); |
| 4447 else if (frameRect().maxY() < 0) |
| 4448 frame().document()->maybeRecordLoadReason(WouldLoadAbove); |
| 4449 else if (frameRect().maxX() < 0) |
| 4450 frame().document()->maybeRecordLoadReason(WouldLoadLeft); |
| 4451 else if (!m_hiddenForThrottling) |
| 4452 frame().document()->maybeRecordLoadReason(WouldLoadVisible); |
| 4453 } |
| 4454 } |
| 4455 } |
| 4456 |
4499 #if DCHECK_IS_ON() | 4457 #if DCHECK_IS_ON() |
4500 // Make sure we never have an unthrottled frame inside a throttled one. | 4458 // Make sure we never have an unthrottled frame inside a throttled one. |
4501 FrameView* parent = parentFrameView(); | |
4502 while (parent) { | 4459 while (parent) { |
4503 DCHECK(canThrottleRendering() || !parent->canThrottleRendering()); | 4460 DCHECK(canThrottleRendering() || !parent->canThrottleRendering()); |
4504 parent = parent->parentFrameView(); | 4461 parent = parent->parentFrameView(); |
4505 } | 4462 } |
4506 #endif | 4463 #endif |
4507 } | 4464 } |
4508 | 4465 |
4509 bool FrameView::shouldThrottleRendering() const { | 4466 bool FrameView::shouldThrottleRendering() const { |
4510 return canThrottleRendering() && lifecycle().throttlingAllowed(); | 4467 return canThrottleRendering() && lifecycle().throttlingAllowed(); |
4511 } | 4468 } |
4512 | 4469 |
4513 bool FrameView::canThrottleRendering() const { | 4470 bool FrameView::canThrottleRendering() const { |
4514 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled()) | 4471 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled()) |
4515 return false; | 4472 return false; |
| 4473 // We only throttle the rendering pipeline in cross-origin frames. This is |
| 4474 // to avoid a situation where an ancestor frame directly depends on the |
| 4475 // pipeline timing of a descendant and breaks as a result of throttling. |
| 4476 // The rationale is that cross-origin frames must already communicate with |
| 4477 // asynchronous messages, so they should be able to tolerate some delay in |
| 4478 // receiving replies from a throttled peer. |
4516 return m_subtreeThrottled || | 4479 return m_subtreeThrottled || |
4517 (m_hiddenForThrottling && m_crossOriginForThrottling); | 4480 (m_hiddenForThrottling && m_frame->isCrossOriginSubframe()); |
4518 } | 4481 } |
4519 | 4482 |
4520 void FrameView::setInitialViewportSize(const IntSize& viewportSize) { | 4483 void FrameView::setInitialViewportSize(const IntSize& viewportSize) { |
4521 if (viewportSize == m_initialViewportSize) | 4484 if (viewportSize == m_initialViewportSize) |
4522 return; | 4485 return; |
4523 | 4486 |
4524 m_initialViewportSize = viewportSize; | 4487 m_initialViewportSize = viewportSize; |
4525 if (Document* document = m_frame->document()) | 4488 if (Document* document = m_frame->document()) |
4526 document->styleEngine().initialViewportChanged(); | 4489 document->styleEngine().initialViewportChanged(); |
4527 } | 4490 } |
4528 | 4491 |
4529 int FrameView::initialViewportWidth() const { | 4492 int FrameView::initialViewportWidth() const { |
4530 DCHECK(m_frame->isMainFrame()); | 4493 DCHECK(m_frame->isMainFrame()); |
4531 return m_initialViewportSize.width(); | 4494 return m_initialViewportSize.width(); |
4532 } | 4495 } |
4533 | 4496 |
4534 int FrameView::initialViewportHeight() const { | 4497 int FrameView::initialViewportHeight() const { |
4535 DCHECK(m_frame->isMainFrame()); | 4498 DCHECK(m_frame->isMainFrame()); |
4536 return m_initialViewportSize.height(); | 4499 return m_initialViewportSize.height(); |
4537 } | 4500 } |
4538 | 4501 |
4539 } // namespace blink | 4502 } // namespace blink |
OLD | NEW |