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 16 matching lines...) Expand all Loading... | |
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/Fullscreen.h" | 36 #include "core/dom/Fullscreen.h" |
37 #include "core/dom/IntersectionObserverCallback.h" | |
37 #include "core/dom/IntersectionObserverController.h" | 38 #include "core/dom/IntersectionObserverController.h" |
39 #include "core/dom/IntersectionObserverInit.h" | |
38 #include "core/editing/EditingUtilities.h" | 40 #include "core/editing/EditingUtilities.h" |
39 #include "core/editing/FrameSelection.h" | 41 #include "core/editing/FrameSelection.h" |
40 #include "core/editing/RenderedPosition.h" | 42 #include "core/editing/RenderedPosition.h" |
41 #include "core/editing/markers/DocumentMarkerController.h" | 43 #include "core/editing/markers/DocumentMarkerController.h" |
42 #include "core/events/ErrorEvent.h" | 44 #include "core/events/ErrorEvent.h" |
43 #include "core/fetch/ResourceFetcher.h" | 45 #include "core/fetch/ResourceFetcher.h" |
44 #include "core/frame/EventHandlerRegistry.h" | 46 #include "core/frame/EventHandlerRegistry.h" |
45 #include "core/frame/FrameHost.h" | 47 #include "core/frame/FrameHost.h" |
46 #include "core/frame/LocalFrame.h" | 48 #include "core/frame/LocalFrame.h" |
47 #include "core/frame/Location.h" | 49 #include "core/frame/Location.h" |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
146 static bool s_initialTrackAllPaintInvalidations = false; | 148 static bool s_initialTrackAllPaintInvalidations = false; |
147 | 149 |
148 FrameView::FrameView(LocalFrame* frame) | 150 FrameView::FrameView(LocalFrame* frame) |
149 : m_frame(frame), | 151 : m_frame(frame), |
150 m_displayMode(WebDisplayModeBrowser), | 152 m_displayMode(WebDisplayModeBrowser), |
151 m_canHaveScrollbars(true), | 153 m_canHaveScrollbars(true), |
152 m_hasPendingLayout(false), | 154 m_hasPendingLayout(false), |
153 m_inSynchronousPostLayout(false), | 155 m_inSynchronousPostLayout(false), |
154 m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired), | 156 m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired), |
155 m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired), | 157 m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired), |
156 m_renderThrottlingObserverNotificationFactory( | |
157 CancellableTaskFactory::create( | |
158 this, | |
159 &FrameView::notifyRenderThrottlingObservers)), | |
160 m_isTransparent(false), | 158 m_isTransparent(false), |
161 m_baseBackgroundColor(Color::white), | 159 m_baseBackgroundColor(Color::white), |
162 m_mediaType(MediaTypeNames::screen), | 160 m_mediaType(MediaTypeNames::screen), |
163 m_safeToPropagateScrollToParent(true), | 161 m_safeToPropagateScrollToParent(true), |
164 m_scrollCorner(nullptr), | 162 m_scrollCorner(nullptr), |
165 m_stickyPositionObjectCount(0), | 163 m_stickyPositionObjectCount(0), |
166 m_inputEventsScaleFactorForEmulation(1), | 164 m_inputEventsScaleFactorForEmulation(1), |
167 m_layoutSizeFixedToFrameSize(true), | 165 m_layoutSizeFixedToFrameSize(true), |
168 m_didScrollTimer(this, &FrameView::didScrollTimerFired), | 166 m_didScrollTimer(this, &FrameView::didScrollTimerFired), |
169 m_topControlsViewportAdjustment(0), | 167 m_topControlsViewportAdjustment(0), |
170 m_needsUpdateWidgetGeometries(false), | 168 m_needsUpdateWidgetGeometries(false), |
171 m_needsUpdateViewportIntersection(true), | 169 m_needsUpdateViewportIntersection(true), |
172 m_needsUpdateViewportIntersectionInSubtree(true), | |
173 #if ENABLE(ASSERT) | 170 #if ENABLE(ASSERT) |
174 m_hasBeenDisposed(false), | 171 m_hasBeenDisposed(false), |
175 #endif | 172 #endif |
176 m_horizontalScrollbarMode(ScrollbarAuto), | 173 m_horizontalScrollbarMode(ScrollbarAuto), |
177 m_verticalScrollbarMode(ScrollbarAuto), | 174 m_verticalScrollbarMode(ScrollbarAuto), |
178 m_horizontalScrollbarLock(false), | 175 m_horizontalScrollbarLock(false), |
179 m_verticalScrollbarLock(false), | 176 m_verticalScrollbarLock(false), |
180 m_scrollbarsSuppressed(false), | 177 m_scrollbarsSuppressed(false), |
181 m_inUpdateScrollbars(false), | 178 m_inUpdateScrollbars(false), |
182 m_frameTimingRequestsDirty(true), | 179 m_frameTimingRequestsDirty(true), |
183 m_viewportIntersectionValid(false), | |
184 m_hiddenForThrottling(false), | 180 m_hiddenForThrottling(false), |
185 m_crossOriginForThrottling(false), | |
186 m_subtreeThrottled(false), | 181 m_subtreeThrottled(false), |
187 m_currentUpdateLifecyclePhasesTargetState( | 182 m_currentUpdateLifecyclePhasesTargetState( |
188 DocumentLifecycle::Uninitialized), | 183 DocumentLifecycle::Uninitialized), |
189 m_scrollAnchor(this), | 184 m_scrollAnchor(this), |
190 m_needsScrollbarsUpdate(false), | 185 m_needsScrollbarsUpdate(false), |
191 m_suppressAdjustViewSize(false), | 186 m_suppressAdjustViewSize(false), |
192 m_allowsLayoutInvalidationAfterLayoutClean(true) { | 187 m_allowsLayoutInvalidationAfterLayoutClean(true) { |
193 ASSERT(m_frame); | 188 ASSERT(m_frame); |
194 init(); | 189 init(); |
195 } | 190 } |
(...skipping 20 matching lines...) Expand all Loading... | |
216 DEFINE_TRACE(FrameView) { | 211 DEFINE_TRACE(FrameView) { |
217 visitor->trace(m_frame); | 212 visitor->trace(m_frame); |
218 visitor->trace(m_fragmentAnchor); | 213 visitor->trace(m_fragmentAnchor); |
219 visitor->trace(m_scrollableAreas); | 214 visitor->trace(m_scrollableAreas); |
220 visitor->trace(m_animatingScrollableAreas); | 215 visitor->trace(m_animatingScrollableAreas); |
221 visitor->trace(m_autoSizeInfo); | 216 visitor->trace(m_autoSizeInfo); |
222 visitor->trace(m_horizontalScrollbar); | 217 visitor->trace(m_horizontalScrollbar); |
223 visitor->trace(m_verticalScrollbar); | 218 visitor->trace(m_verticalScrollbar); |
224 visitor->trace(m_children); | 219 visitor->trace(m_children); |
225 visitor->trace(m_viewportScrollableArea); | 220 visitor->trace(m_viewportScrollableArea); |
221 visitor->trace(m_intersectionObserver); | |
226 visitor->trace(m_scrollAnchor); | 222 visitor->trace(m_scrollAnchor); |
227 Widget::trace(visitor); | 223 Widget::trace(visitor); |
228 ScrollableArea::trace(visitor); | 224 ScrollableArea::trace(visitor); |
229 } | 225 } |
230 | 226 |
231 void FrameView::reset() { | 227 void FrameView::reset() { |
232 m_hasPendingLayout = false; | 228 m_hasPendingLayout = false; |
233 m_layoutSchedulingEnabled = true; | 229 m_layoutSchedulingEnabled = true; |
234 m_inSynchronousPostLayout = false; | 230 m_inSynchronousPostLayout = false; |
235 m_layoutCount = 0; | 231 m_layoutCount = 0; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
276 reset(); | 272 reset(); |
277 | 273 |
278 m_size = LayoutSize(); | 274 m_size = LayoutSize(); |
279 | 275 |
280 // Propagate the marginwidth/height and scrolling modes to the view. | 276 // Propagate the marginwidth/height and scrolling modes to the view. |
281 if (m_frame->owner() && | 277 if (m_frame->owner() && |
282 m_frame->owner()->scrollingMode() == ScrollbarAlwaysOff) | 278 m_frame->owner()->scrollingMode() == ScrollbarAlwaysOff) |
283 setCanHaveScrollbars(false); | 279 setCanHaveScrollbars(false); |
284 } | 280 } |
285 | 281 |
282 void FrameView::setupRenderThrottling() { | |
283 if (m_intersectionObserver || !frame().document() || | |
284 !frame().document()->frame() || !frame().document()->documentElement() || | |
285 !frame().document()->documentElement()->isConnected()) { | |
286 return; | |
287 } | |
288 | |
289 ExecutionContext* context; | |
290 IntersectionObserverInit observerInit; | |
291 // Intersection observer does not currently support remote frames. As a | |
292 // workaround we monitor visibility up to the local root (crbug.com/615156). | |
293 Frame* mainFrame = frame().tree().top(); | |
294 if (!mainFrame || !mainFrame->isLocalFrame()) { | |
295 observerInit.setRoot( | |
296 frame().localFrameRoot()->document()->documentElement()); | |
297 context = &observerInit.root()->document(); | |
298 } else { | |
299 context = toLocalFrame(mainFrame)->document(); | |
300 } | |
301 | |
302 IntersectionObserverCallback* callback = | |
303 new IntersectionObserverCallback(this, context); | |
304 m_intersectionObserver = IntersectionObserver::create(observerInit, *callback, | |
305 ASSERT_NO_EXCEPTION); | |
306 m_intersectionObserver->observe(frame().document()->documentElement()); | |
307 | |
308 // Initially the intersection observer assumes the target is hidden. If it | |
309 // actually is, no notification about this will be delivered. To work around | |
310 // this, we set the observer into an undefined state so the first | |
311 // notification will always get delivered. | |
312 for (auto& observation : m_intersectionObserver->observations()) | |
313 observation->setLastThresholdIndex(std::numeric_limits<unsigned>::max()); | |
ojan
2016/10/14 02:25:47
This is digging into the guts of IntersectionObser
Sami
2016/10/25 17:47:12
Yeah, sounds good. I've added an explicit method f
| |
314 } | |
315 | |
286 void FrameView::dispose() { | 316 void FrameView::dispose() { |
287 RELEASE_ASSERT(!isInPerformLayout()); | 317 RELEASE_ASSERT(!isInPerformLayout()); |
288 | 318 |
289 if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) | 319 if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) |
290 scrollAnimator->cancelAnimation(); | 320 scrollAnimator->cancelAnimation(); |
291 cancelProgrammaticScrollAnimation(); | 321 cancelProgrammaticScrollAnimation(); |
292 | 322 |
293 detachScrollbars(); | 323 detachScrollbars(); |
294 | 324 |
295 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) | 325 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) |
296 scrollingCoordinator->willDestroyScrollableArea(this); | 326 scrollingCoordinator->willDestroyScrollableArea(this); |
297 | 327 |
298 // We need to clear the RootFrameViewport's animator since it gets called | 328 // 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 | 329 // from non-GC'd objects and RootFrameViewport will still have a pointer to |
300 // this class. | 330 // this class. |
301 if (m_viewportScrollableArea) | 331 if (m_viewportScrollableArea) |
302 m_viewportScrollableArea->clearScrollAnimators(); | 332 m_viewportScrollableArea->clearScrollAnimators(); |
303 | 333 |
304 clearScrollAnimators(); | 334 clearScrollAnimators(); |
305 | 335 |
306 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing | 336 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing |
307 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|. | 337 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|. |
308 m_autoSizeInfo.clear(); | 338 m_autoSizeInfo.clear(); |
309 | 339 |
310 m_postLayoutTasksTimer.stop(); | 340 m_postLayoutTasksTimer.stop(); |
311 m_didScrollTimer.stop(); | 341 m_didScrollTimer.stop(); |
312 | 342 |
313 m_renderThrottlingObserverNotificationFactory->cancel(); | |
314 | |
315 // FIXME: Do we need to do something here for OOPI? | 343 // FIXME: Do we need to do something here for OOPI? |
316 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); | 344 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); |
317 // TODO(dcheng): It seems buggy that we can have an owner element that | 345 // TODO(dcheng): It seems buggy that we can have an owner element that |
318 // points to another Widget. | 346 // points to another Widget. |
319 if (ownerElement && ownerElement->ownedWidget() == this) | 347 if (ownerElement && ownerElement->ownedWidget() == this) |
320 ownerElement->setWidget(nullptr); | 348 ownerElement->setWidget(nullptr); |
321 | 349 |
322 #if ENABLE(ASSERT) | 350 #if ENABLE(ASSERT) |
323 m_hasBeenDisposed = true; | 351 m_hasBeenDisposed = true; |
324 #endif | 352 #endif |
(...skipping 3010 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3335 } | 3363 } |
3336 | 3364 |
3337 void FrameView::setParent(Widget* parentView) { | 3365 void FrameView::setParent(Widget* parentView) { |
3338 if (parentView == parent()) | 3366 if (parentView == parent()) |
3339 return; | 3367 return; |
3340 | 3368 |
3341 Widget::setParent(parentView); | 3369 Widget::setParent(parentView); |
3342 | 3370 |
3343 updateScrollableAreaSet(); | 3371 updateScrollableAreaSet(); |
3344 setNeedsUpdateViewportIntersection(); | 3372 setNeedsUpdateViewportIntersection(); |
3373 setupRenderThrottling(); | |
3374 | |
3375 if (parentFrameView()) | |
3376 m_subtreeThrottled = parentFrameView()->canThrottleRendering(); | |
3345 } | 3377 } |
3346 | 3378 |
3347 void FrameView::removeChild(Widget* child) { | 3379 void FrameView::removeChild(Widget* child) { |
3348 ASSERT(child->parent() == this); | 3380 ASSERT(child->parent() == this); |
3349 | 3381 |
3350 if (child->isFrameView()) | 3382 if (child->isFrameView()) |
3351 removeScrollableArea(toFrameView(child)); | 3383 removeScrollableArea(toFrameView(child)); |
3352 | 3384 |
3353 child->setParent(0); | 3385 child->setParent(0); |
3354 m_children.remove(child); | 3386 m_children.remove(child); |
(...skipping 936 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4291 if (layoutObject.isText()) | 4323 if (layoutObject.isText()) |
4292 return; | 4324 return; |
4293 | 4325 |
4294 layoutObject.addAnnotatedRegions(regions); | 4326 layoutObject.addAnnotatedRegions(regions); |
4295 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; | 4327 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; |
4296 curr = curr->nextSibling()) | 4328 curr = curr->nextSibling()) |
4297 collectAnnotatedRegions(*curr, regions); | 4329 collectAnnotatedRegions(*curr, regions); |
4298 } | 4330 } |
4299 | 4331 |
4300 void FrameView::setNeedsUpdateViewportIntersection() { | 4332 void FrameView::setNeedsUpdateViewportIntersection() { |
4301 m_needsUpdateViewportIntersection = true; | |
4302 for (FrameView* parent = parentFrameView(); parent; | 4333 for (FrameView* parent = parentFrameView(); parent; |
4303 parent = parent->parentFrameView()) | 4334 parent = parent->parentFrameView()) |
4304 parent->m_needsUpdateViewportIntersectionInSubtree = true; | 4335 parent->m_needsUpdateViewportIntersectionInSubtree = true; |
4305 } | 4336 } |
4306 | 4337 |
4307 void FrameView::updateViewportIntersectionIfNeeded() { | |
4308 if (!m_needsUpdateViewportIntersection) | |
4309 return; | |
4310 m_needsUpdateViewportIntersection = false; | |
4311 m_viewportIntersectionValid = true; | |
4312 FrameView* parent = parentFrameView(); | |
4313 if (!parent) { | |
4314 m_viewportIntersection = frameRect(); | |
4315 return; | |
4316 } | |
4317 ASSERT(!parent->m_needsUpdateViewportIntersection); | |
4318 | |
4319 // If our parent is hidden, then we are too. | |
4320 if (parent->m_viewportIntersection.isEmpty()) { | |
4321 m_viewportIntersection = parent->m_viewportIntersection; | |
4322 return; | |
4323 } | |
4324 | |
4325 // Transform our bounds into the root frame's content coordinate space, | |
4326 // making sure we have valid layout data in our parent document. If our | |
4327 // parent is throttled, we'll use possible stale layout information and | |
4328 // rely on the fact that another lifecycle update will be scheduled once | |
4329 // our parent becomes unthrottled. | |
4330 ASSERT(parent->lifecycle().state() >= DocumentLifecycle::LayoutClean || | |
4331 parent->shouldThrottleRendering()); | |
4332 m_viewportIntersection = parent->contentsToRootFrame(frameRect()); | |
4333 | |
4334 // TODO(skyostil): Expand the viewport to make it less likely to see stale | |
4335 // content while scrolling. | |
4336 IntRect viewport = parent->m_viewportIntersection; | |
4337 m_viewportIntersection.intersect(viewport); | |
4338 } | |
4339 | |
4340 void FrameView::updateViewportIntersectionsForSubtree( | 4338 void FrameView::updateViewportIntersectionsForSubtree( |
4341 DocumentLifecycle::LifecycleState targetState) { | 4339 DocumentLifecycle::LifecycleState targetState) { |
4342 bool hadValidIntersection = m_viewportIntersectionValid; | |
4343 bool hadEmptyIntersection = m_viewportIntersection.isEmpty(); | |
4344 updateViewportIntersectionIfNeeded(); | |
4345 | |
4346 // Notify javascript IntersectionObservers | 4340 // Notify javascript IntersectionObservers |
4347 if (targetState == DocumentLifecycle::PaintClean && | 4341 if (targetState == DocumentLifecycle::PaintClean && |
4348 frame().document()->intersectionObserverController()) | 4342 frame().document()->intersectionObserverController()) |
4349 frame() | 4343 frame() |
4350 .document() | 4344 .document() |
4351 ->intersectionObserverController() | 4345 ->intersectionObserverController() |
4352 ->computeTrackedIntersectionObservations(); | 4346 ->computeTrackedIntersectionObservations(); |
4353 | 4347 |
4354 // Adjust render throttling for iframes based on visibility | |
4355 bool shouldNotify = !hadValidIntersection || | |
4356 hadEmptyIntersection != m_viewportIntersection.isEmpty(); | |
4357 if (shouldNotify && | |
4358 !m_renderThrottlingObserverNotificationFactory->isPending()) | |
4359 m_frame->frameScheduler()->unthrottledTaskRunner()->postTask( | |
4360 BLINK_FROM_HERE, | |
4361 m_renderThrottlingObserverNotificationFactory->cancelAndCreate()); | |
4362 | |
4363 if (!m_needsUpdateViewportIntersectionInSubtree) | 4348 if (!m_needsUpdateViewportIntersectionInSubtree) |
4364 return; | 4349 return; |
4365 m_needsUpdateViewportIntersectionInSubtree = false; | 4350 m_needsUpdateViewportIntersectionInSubtree = false; |
4366 | 4351 |
4367 for (Frame* child = m_frame->tree().firstChild(); child; | 4352 for (Frame* child = m_frame->tree().firstChild(); child; |
4368 child = child->tree().nextSibling()) { | 4353 child = child->tree().nextSibling()) { |
4369 if (!child->isLocalFrame()) | 4354 if (!child->isLocalFrame()) |
4370 continue; | 4355 continue; |
4371 if (FrameView* view = toLocalFrame(child)->view()) | 4356 if (FrameView* view = toLocalFrame(child)->view()) |
4372 view->updateViewportIntersectionsForSubtree(targetState); | 4357 view->updateViewportIntersectionsForSubtree(targetState); |
4373 } | 4358 } |
4374 } | 4359 } |
4375 | 4360 |
4376 void FrameView::updateThrottlingStatus() { | 4361 void FrameView::updateRenderThrottlingStatusForTesting() { |
4377 // Only offscreen frames can be throttled. Note that we disallow throttling | 4362 m_intersectionObserver->deliver(); |
4378 // of 0x0 frames because some sites use them to drive UI logic. | |
4379 DCHECK(m_viewportIntersectionValid); | |
4380 m_hiddenForThrottling = | |
4381 m_viewportIntersection.isEmpty() && !frameRect().isEmpty(); | |
4382 | |
4383 // We only throttle the rendering pipeline in cross-origin frames. This is | |
4384 // to avoid a situation where an ancestor frame directly depends on the | |
4385 // pipeline timing of a descendant and breaks as a result of throttling. | |
4386 // The rationale is that cross-origin frames must already communicate with | |
4387 // asynchronous messages, so they should be able to tolerate some delay in | |
4388 // receiving replies from a throttled peer. | |
4389 // | |
4390 // Check if we can access our parent's security origin. | |
4391 m_crossOriginForThrottling = false; | |
4392 // If any of our parents are throttled, we must be too. | |
4393 m_subtreeThrottled = false; | |
4394 const SecurityOrigin* origin = frame().securityContext()->getSecurityOrigin(); | |
4395 for (Frame* parentFrame = m_frame->tree().parent(); parentFrame; | |
4396 parentFrame = parentFrame->tree().parent()) { | |
4397 const SecurityOrigin* parentOrigin = | |
4398 parentFrame->securityContext()->getSecurityOrigin(); | |
4399 if (!origin->canAccess(parentOrigin)) | |
4400 m_crossOriginForThrottling = true; | |
4401 if (parentFrame->isLocalFrame() && toLocalFrame(parentFrame)->view() && | |
4402 toLocalFrame(parentFrame)->view()->canThrottleRendering()) | |
4403 m_subtreeThrottled = true; | |
4404 } | |
4405 m_frame->frameScheduler()->setFrameVisible(!m_hiddenForThrottling); | |
4406 m_frame->frameScheduler()->setCrossOrigin(m_crossOriginForThrottling); | |
4407 } | 4363 } |
4408 | 4364 |
4409 void FrameView::notifyRenderThrottlingObserversForTesting() { | 4365 void FrameView::updateRenderThrottlingStatus(bool hidden, |
4410 DCHECK(m_renderThrottlingObserverNotificationFactory->isPending()); | 4366 bool subtreeThrottled) { |
4411 notifyRenderThrottlingObservers(); | 4367 TRACE_EVENT0("blink", "FrameView::updateRenderThrottlingStatus"); |
4412 } | |
4413 | |
4414 void FrameView::notifyRenderThrottlingObservers() { | |
4415 TRACE_EVENT0("blink", "FrameView::notifyRenderThrottlingObservers"); | |
4416 DCHECK(!isInPerformLayout()); | 4368 DCHECK(!isInPerformLayout()); |
4417 DCHECK(frame().document()); | 4369 DCHECK(!m_frame->document() || !m_frame->document()->inStyleRecalc()); |
4418 DCHECK(!frame().document()->inStyleRecalc()); | |
4419 bool wasThrottled = canThrottleRendering(); | 4370 bool wasThrottled = canThrottleRendering(); |
4420 | 4371 |
4421 updateThrottlingStatus(); | 4372 // Note that we disallow throttling of 0x0 frames because some sites use |
4373 // them to drive UI logic. | |
4374 m_hiddenForThrottling = hidden && !frameRect().isEmpty(); | |
4375 m_subtreeThrottled = subtreeThrottled; | |
4422 | 4376 |
4423 frame().document()->onVisibilityMaybeChanged(!m_hiddenForThrottling); | 4377 bool isThrottled = canThrottleRendering(); |
4378 bool becameUnthrottled = wasThrottled && !isThrottled; | |
4424 | 4379 |
4425 bool becameThrottled = !wasThrottled && canThrottleRendering(); | 4380 // If this FrameView became unthrottled or throttled, we must make sure all |
4426 bool becameUnthrottled = wasThrottled && !canThrottleRendering(); | 4381 // its children are notified synchronously. Otherwise we 1) might attempt to |
4382 // paint one of the children with an out-of-date layout before | |
4383 // |updateRenderThrottlingStatus| has made it throttled or 2) fail to | |
4384 // unthrottle a child whose parent is unthrottled by a later notification. | |
4385 if (wasThrottled != isThrottled) { | |
4386 for (const Member<Widget>& child : *children()) { | |
4387 if (child->isFrameView()) { | |
4388 FrameView* childView = toFrameView(child); | |
4389 childView->updateRenderThrottlingStatus( | |
4390 childView->m_hiddenForThrottling, isThrottled); | |
4391 } | |
4392 } | |
4393 } | |
4394 | |
4427 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); | 4395 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); |
4428 if (becameThrottled) { | |
4429 // If this FrameView became throttled, we must make sure all of its | |
4430 // children become throttled at the same time. Otherwise we might | |
4431 // attempt to paint one of the children with an out-of-date layout | |
4432 // before |notifyRenderThrottlingObservers| has made it throttled. | |
4433 forAllNonThrottledFrameViews([](FrameView& frameView) { | |
4434 frameView.m_subtreeThrottled = true; | |
4435 DCHECK(frameView.canThrottleRendering()); | |
4436 }); | |
4437 } | |
4438 if (becameUnthrottled) { | 4396 if (becameUnthrottled) { |
4439 // ScrollingCoordinator needs to update according to the new throttling | 4397 // ScrollingCoordinator needs to update according to the new throttling |
4440 // status. | 4398 // status. |
4441 if (scrollingCoordinator) | 4399 if (scrollingCoordinator) |
4442 scrollingCoordinator->notifyGeometryChanged(); | 4400 scrollingCoordinator->notifyGeometryChanged(); |
4443 // Start ticking animation frames again if necessary. | 4401 // Start ticking animation frames again if necessary. |
4444 if (page()) | 4402 if (page()) |
4445 page()->animator().scheduleVisualUpdate(m_frame.get()); | 4403 page()->animator().scheduleVisualUpdate(m_frame.get()); |
4446 // Force a full repaint of this frame to ensure we are not left with a | 4404 // Force a full repaint of this frame to ensure we are not left with a |
4447 // partially painted version of this frame's contents if we skipped | 4405 // partially painted version of this frame's contents if we skipped |
(...skipping 11 matching lines...) Expand all Loading... | |
4459 scrollingCoordinator->touchEventTargetRectsDidChange(); | 4417 scrollingCoordinator->touchEventTargetRectsDidChange(); |
4460 | 4418 |
4461 #if DCHECK_IS_ON() | 4419 #if DCHECK_IS_ON() |
4462 // Make sure we never have an unthrottled frame inside a throttled one. | 4420 // Make sure we never have an unthrottled frame inside a throttled one. |
4463 FrameView* parent = parentFrameView(); | 4421 FrameView* parent = parentFrameView(); |
4464 while (parent) { | 4422 while (parent) { |
4465 DCHECK(canThrottleRendering() || !parent->canThrottleRendering()); | 4423 DCHECK(canThrottleRendering() || !parent->canThrottleRendering()); |
4466 parent = parent->parentFrameView(); | 4424 parent = parent->parentFrameView(); |
4467 } | 4425 } |
4468 #endif | 4426 #endif |
4427 | |
4428 if (frame().document()->frame()) | |
4429 frame().document()->onVisibilityMaybeChanged(!hidden); | |
4469 } | 4430 } |
4470 | 4431 |
4471 bool FrameView::shouldThrottleRendering() const { | 4432 bool FrameView::shouldThrottleRendering() const { |
4472 return canThrottleRendering() && lifecycle().throttlingAllowed(); | 4433 return canThrottleRendering() && lifecycle().throttlingAllowed(); |
4473 } | 4434 } |
4474 | 4435 |
4475 bool FrameView::canThrottleRendering() const { | 4436 bool FrameView::canThrottleRendering() const { |
4476 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled()) | 4437 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled()) |
4477 return false; | 4438 return false; |
4439 // We only throttle the rendering pipeline in cross-origin frames. This is | |
4440 // to avoid a situation where an ancestor frame directly depends on the | |
4441 // pipeline timing of a descendant and breaks as a result of throttling. | |
4442 // The rationale is that cross-origin frames must already communicate with | |
4443 // asynchronous messages, so they should be able to tolerate some delay in | |
4444 // receiving replies from a throttled peer. | |
4478 return m_subtreeThrottled || | 4445 return m_subtreeThrottled || |
4479 (m_hiddenForThrottling && m_crossOriginForThrottling); | 4446 (m_hiddenForThrottling && m_frame->isCrossOriginSubframe()); |
4447 } | |
4448 | |
4449 FrameView::IntersectionObserverCallback::IntersectionObserverCallback( | |
4450 FrameView* frameView, | |
4451 ExecutionContext* context) | |
4452 : m_frameView(frameView), m_context(context) {} | |
4453 | |
4454 void FrameView::IntersectionObserverCallback::handleEvent( | |
4455 const HeapVector<Member<IntersectionObserverEntry>>& entries, | |
4456 IntersectionObserver&) { | |
4457 if (!m_frameView) | |
4458 return; | |
4459 bool wasHidden = m_frameView->m_hiddenForThrottling; | |
4460 bool isHidden = wasHidden; | |
4461 if (!entries.isEmpty()) | |
4462 isHidden = !entries.last()->intersectionRatio(); | |
4463 if (wasHidden != isHidden) { | |
4464 m_frameView->updateRenderThrottlingStatus(isHidden, | |
4465 m_frameView->m_subtreeThrottled); | |
4466 } | |
4467 } | |
4468 | |
4469 ExecutionContext* FrameView::IntersectionObserverCallback::getExecutionContext() | |
4470 const { | |
4471 return m_context.get(); | |
4472 } | |
4473 | |
4474 DEFINE_TRACE(FrameView::IntersectionObserverCallback) { | |
4475 blink::IntersectionObserverCallback::trace(visitor); | |
4476 visitor->trace(m_frameView); | |
4477 visitor->trace(m_context); | |
4480 } | 4478 } |
4481 | 4479 |
4482 } // namespace blink | 4480 } // namespace blink |
OLD | NEW |