Chromium Code Reviews| 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_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 Loading... | |
| 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 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 3007 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |