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/css/FontFaceSet.h" | 31 #include "core/css/FontFaceSet.h" |
32 #include "core/css/resolver/StyleResolver.h" | 32 #include "core/css/resolver/StyleResolver.h" |
33 #include "core/dom/AXObjectCache.h" | 33 #include "core/dom/AXObjectCache.h" |
34 #include "core/dom/DOMNodeIds.h" | 34 #include "core/dom/DOMNodeIds.h" |
35 #include "core/dom/Fullscreen.h" | 35 #include "core/dom/Fullscreen.h" |
36 #include "core/dom/IntersectionObserverCallback.h" | |
36 #include "core/dom/IntersectionObserverController.h" | 37 #include "core/dom/IntersectionObserverController.h" |
38 #include "core/dom/IntersectionObserverInit.h" | |
37 #include "core/editing/EditingUtilities.h" | 39 #include "core/editing/EditingUtilities.h" |
38 #include "core/editing/FrameSelection.h" | 40 #include "core/editing/FrameSelection.h" |
39 #include "core/editing/RenderedPosition.h" | 41 #include "core/editing/RenderedPosition.h" |
40 #include "core/editing/markers/DocumentMarkerController.h" | 42 #include "core/editing/markers/DocumentMarkerController.h" |
41 #include "core/events/ErrorEvent.h" | 43 #include "core/events/ErrorEvent.h" |
42 #include "core/fetch/ResourceFetcher.h" | 44 #include "core/fetch/ResourceFetcher.h" |
43 #include "core/frame/EventHandlerRegistry.h" | 45 #include "core/frame/EventHandlerRegistry.h" |
44 #include "core/frame/FrameHost.h" | 46 #include "core/frame/FrameHost.h" |
45 #include "core/frame/LocalFrame.h" | 47 #include "core/frame/LocalFrame.h" |
46 #include "core/frame/Location.h" | 48 #include "core/frame/Location.h" |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
144 static bool s_initialTrackAllPaintInvalidations = false; | 146 static bool s_initialTrackAllPaintInvalidations = false; |
145 | 147 |
146 FrameView::FrameView(LocalFrame* frame) | 148 FrameView::FrameView(LocalFrame* frame) |
147 : m_frame(frame) | 149 : m_frame(frame) |
148 , m_displayMode(WebDisplayModeBrowser) | 150 , m_displayMode(WebDisplayModeBrowser) |
149 , m_canHaveScrollbars(true) | 151 , m_canHaveScrollbars(true) |
150 , m_hasPendingLayout(false) | 152 , m_hasPendingLayout(false) |
151 , m_inSynchronousPostLayout(false) | 153 , m_inSynchronousPostLayout(false) |
152 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired) | 154 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired) |
153 , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired) | 155 , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired) |
154 , m_renderThrottlingObserverNotificationFactory(CancellableTaskFactory::crea te(this, &FrameView::notifyRenderThrottlingObservers)) | |
155 , m_isTransparent(false) | 156 , m_isTransparent(false) |
156 , m_baseBackgroundColor(Color::white) | 157 , m_baseBackgroundColor(Color::white) |
157 , m_mediaType(MediaTypeNames::screen) | 158 , m_mediaType(MediaTypeNames::screen) |
158 , m_safeToPropagateScrollToParent(true) | 159 , m_safeToPropagateScrollToParent(true) |
159 , m_scrollCorner(nullptr) | 160 , m_scrollCorner(nullptr) |
160 , m_stickyPositionObjectCount(0) | 161 , m_stickyPositionObjectCount(0) |
161 , m_inputEventsScaleFactorForEmulation(1) | 162 , m_inputEventsScaleFactorForEmulation(1) |
162 , m_layoutSizeFixedToFrameSize(true) | 163 , m_layoutSizeFixedToFrameSize(true) |
163 , m_didScrollTimer(this, &FrameView::didScrollTimerFired) | 164 , m_didScrollTimer(this, &FrameView::didScrollTimerFired) |
164 , m_topControlsViewportAdjustment(0) | 165 , m_topControlsViewportAdjustment(0) |
165 , m_needsUpdateWidgetGeometries(false) | 166 , m_needsUpdateWidgetGeometries(false) |
166 , m_needsUpdateViewportIntersection(true) | |
167 , m_needsUpdateViewportIntersectionInSubtree(true) | 167 , m_needsUpdateViewportIntersectionInSubtree(true) |
168 #if ENABLE(ASSERT) | 168 #if ENABLE(ASSERT) |
169 , m_hasBeenDisposed(false) | 169 , m_hasBeenDisposed(false) |
170 #endif | 170 #endif |
171 , m_horizontalScrollbarMode(ScrollbarAuto) | 171 , m_horizontalScrollbarMode(ScrollbarAuto) |
172 , m_verticalScrollbarMode(ScrollbarAuto) | 172 , m_verticalScrollbarMode(ScrollbarAuto) |
173 , m_horizontalScrollbarLock(false) | 173 , m_horizontalScrollbarLock(false) |
174 , m_verticalScrollbarLock(false) | 174 , m_verticalScrollbarLock(false) |
175 , m_scrollbarsAvoidingResizer(0) | 175 , m_scrollbarsAvoidingResizer(0) |
176 , m_scrollbarsSuppressed(false) | 176 , m_scrollbarsSuppressed(false) |
177 , m_inUpdateScrollbars(false) | 177 , m_inUpdateScrollbars(false) |
178 , m_frameTimingRequestsDirty(true) | 178 , m_frameTimingRequestsDirty(true) |
179 , m_viewportIntersectionValid(false) | |
180 , m_hiddenForThrottling(false) | 179 , m_hiddenForThrottling(false) |
181 , m_crossOriginForThrottling(false) | |
182 , m_subtreeThrottled(false) | 180 , m_subtreeThrottled(false) |
183 , m_currentUpdateLifecyclePhasesTargetState(DocumentLifecycle::Uninitialized ) | 181 , m_currentUpdateLifecyclePhasesTargetState(DocumentLifecycle::Uninitialized ) |
184 , m_needsScrollbarsUpdate(false) | 182 , m_needsScrollbarsUpdate(false) |
185 , m_suppressAdjustViewSize(false) | 183 , m_suppressAdjustViewSize(false) |
186 , m_allowsLayoutInvalidationAfterLayoutClean(true) | 184 , m_allowsLayoutInvalidationAfterLayoutClean(true) |
187 { | 185 { |
188 ASSERT(m_frame); | 186 ASSERT(m_frame); |
189 init(); | 187 init(); |
190 } | 188 } |
191 | 189 |
(...skipping 24 matching lines...) Expand all Loading... | |
216 visitor->trace(m_frame); | 214 visitor->trace(m_frame); |
217 visitor->trace(m_fragmentAnchor); | 215 visitor->trace(m_fragmentAnchor); |
218 visitor->trace(m_scrollableAreas); | 216 visitor->trace(m_scrollableAreas); |
219 visitor->trace(m_animatingScrollableAreas); | 217 visitor->trace(m_animatingScrollableAreas); |
220 visitor->trace(m_autoSizeInfo); | 218 visitor->trace(m_autoSizeInfo); |
221 visitor->trace(m_horizontalScrollbar); | 219 visitor->trace(m_horizontalScrollbar); |
222 visitor->trace(m_verticalScrollbar); | 220 visitor->trace(m_verticalScrollbar); |
223 visitor->trace(m_children); | 221 visitor->trace(m_children); |
224 visitor->trace(m_viewportScrollableArea); | 222 visitor->trace(m_viewportScrollableArea); |
225 visitor->trace(m_scrollAnchor); | 223 visitor->trace(m_scrollAnchor); |
224 visitor->trace(m_intersectionObserver); | |
226 Widget::trace(visitor); | 225 Widget::trace(visitor); |
227 ScrollableArea::trace(visitor); | 226 ScrollableArea::trace(visitor); |
228 } | 227 } |
229 | 228 |
230 void FrameView::reset() | 229 void FrameView::reset() |
231 { | 230 { |
232 m_hasPendingLayout = false; | 231 m_hasPendingLayout = false; |
233 m_layoutSchedulingEnabled = true; | 232 m_layoutSchedulingEnabled = true; |
234 m_inSynchronousPostLayout = false; | 233 m_inSynchronousPostLayout = false; |
235 m_layoutCount = 0; | 234 m_layoutCount = 0; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
273 { | 272 { |
274 reset(); | 273 reset(); |
275 | 274 |
276 m_size = LayoutSize(); | 275 m_size = LayoutSize(); |
277 | 276 |
278 // Propagate the marginwidth/height and scrolling modes to the view. | 277 // Propagate the marginwidth/height and scrolling modes to the view. |
279 if (m_frame->owner() && m_frame->owner()->scrollingMode() == ScrollbarAlways Off) | 278 if (m_frame->owner() && m_frame->owner()->scrollingMode() == ScrollbarAlways Off) |
280 setCanHaveScrollbars(false); | 279 setCanHaveScrollbars(false); |
281 } | 280 } |
282 | 281 |
282 void FrameView::setupRenderThrottling() | |
283 { | |
284 if (m_intersectionObserver || !frame().document() || !frame().document()->fr ame() || !frame().document()->documentElement()) | |
285 return; | |
286 | |
287 ExecutionContext* context; | |
288 IntersectionObserverInit observerInit; | |
289 // Intersection observer does not currently support remote frames. As a | |
290 // workaround we monitor visibility up to the local root (crbug.com/615156). | |
291 Frame* mainFrame = frame().tree().top(); | |
292 if (!mainFrame || !mainFrame->isLocalFrame()) { | |
293 observerInit.setRoot(frame().localFrameRoot()->document()->documentEleme nt()); | |
haraken
2016/09/12 00:46:32
This looks a bit too weird to me. Maybe can we jus
| |
294 context = &observerInit.root()->document(); | |
295 } else { | |
296 context = toLocalFrame(mainFrame)->document(); | |
297 } | |
298 | |
299 IntersectionObserverCallback* callback = new IntersectionObserverCallback(th is, context); | |
300 m_intersectionObserver = IntersectionObserver::create(observerInit, *callbac k, ASSERT_NO_EXCEPTION); | |
301 m_intersectionObserver->setLowLatency(true); | |
302 m_intersectionObserver->observe(frame().document()->documentElement()); | |
303 | |
304 // Initially the intersection observer assumes the target is hidden. If it | |
305 // actually is, no notification about this will be delivered. To work around | |
306 // this, we set the observer into an undefined state so the first | |
307 // notification will always get delivered. | |
308 for (auto& observation : m_intersectionObserver->observations()) | |
309 observation->setLastThresholdIndex(std::numeric_limits<unsigned>::max()) ; | |
310 } | |
311 | |
283 void FrameView::dispose() | 312 void FrameView::dispose() |
284 { | 313 { |
285 RELEASE_ASSERT(!isInPerformLayout()); | 314 RELEASE_ASSERT(!isInPerformLayout()); |
286 | 315 |
287 if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) | 316 if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) |
288 scrollAnimator->cancelAnimation(); | 317 scrollAnimator->cancelAnimation(); |
289 cancelProgrammaticScrollAnimation(); | 318 cancelProgrammaticScrollAnimation(); |
290 | 319 |
291 detachScrollbars(); | 320 detachScrollbars(); |
292 | 321 |
(...skipping 10 matching lines...) Expand all Loading... | |
303 | 332 |
304 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing | 333 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing |
305 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|. | 334 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|. |
306 m_autoSizeInfo.clear(); | 335 m_autoSizeInfo.clear(); |
307 | 336 |
308 if (m_postLayoutTasksTimer.isActive()) | 337 if (m_postLayoutTasksTimer.isActive()) |
309 m_postLayoutTasksTimer.stop(); | 338 m_postLayoutTasksTimer.stop(); |
310 | 339 |
311 if (m_didScrollTimer.isActive()) | 340 if (m_didScrollTimer.isActive()) |
312 m_didScrollTimer.stop(); | 341 m_didScrollTimer.stop(); |
313 m_renderThrottlingObserverNotificationFactory->cancel(); | |
314 | 342 |
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; |
(...skipping 2878 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3202 if (m_scrollbarsAvoidingResizer && parent()) | 3230 if (m_scrollbarsAvoidingResizer && parent()) |
3203 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(-m_scrollbar sAvoidingResizer); | 3231 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(-m_scrollbar sAvoidingResizer); |
3204 | 3232 |
3205 Widget::setParent(parentView); | 3233 Widget::setParent(parentView); |
3206 | 3234 |
3207 if (m_scrollbarsAvoidingResizer && parent()) | 3235 if (m_scrollbarsAvoidingResizer && parent()) |
3208 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(m_scrollbars AvoidingResizer); | 3236 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(m_scrollbars AvoidingResizer); |
3209 | 3237 |
3210 updateScrollableAreaSet(); | 3238 updateScrollableAreaSet(); |
3211 setNeedsUpdateViewportIntersection(); | 3239 setNeedsUpdateViewportIntersection(); |
3240 | |
3241 setupRenderThrottling(); | |
3212 } | 3242 } |
3213 | 3243 |
3214 void FrameView::removeChild(Widget* child) | 3244 void FrameView::removeChild(Widget* child) |
3215 { | 3245 { |
3216 ASSERT(child->parent() == this); | 3246 ASSERT(child->parent() == this); |
3217 | 3247 |
3218 if (child->isFrameView()) | 3248 if (child->isFrameView()) |
3219 removeScrollableArea(toFrameView(child)); | 3249 removeScrollableArea(toFrameView(child)); |
3220 | 3250 |
3221 child->setParent(0); | 3251 child->setParent(0); |
(...skipping 958 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4180 if (layoutObject.isText()) | 4210 if (layoutObject.isText()) |
4181 return; | 4211 return; |
4182 | 4212 |
4183 layoutObject.addAnnotatedRegions(regions); | 4213 layoutObject.addAnnotatedRegions(regions); |
4184 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; curr = curr-> nextSibling()) | 4214 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; curr = curr-> nextSibling()) |
4185 collectAnnotatedRegions(*curr, regions); | 4215 collectAnnotatedRegions(*curr, regions); |
4186 } | 4216 } |
4187 | 4217 |
4188 void FrameView::setNeedsUpdateViewportIntersection() | 4218 void FrameView::setNeedsUpdateViewportIntersection() |
4189 { | 4219 { |
4190 m_needsUpdateViewportIntersection = true; | |
4191 for (FrameView* parent = parentFrameView(); parent; parent = parent->parentF rameView()) | 4220 for (FrameView* parent = parentFrameView(); parent; parent = parent->parentF rameView()) |
4192 parent->m_needsUpdateViewportIntersectionInSubtree = true; | 4221 parent->m_needsUpdateViewportIntersectionInSubtree = true; |
4193 } | 4222 } |
4194 | 4223 |
4195 void FrameView::updateViewportIntersectionIfNeeded() | |
4196 { | |
4197 if (!m_needsUpdateViewportIntersection) | |
4198 return; | |
4199 m_needsUpdateViewportIntersection = false; | |
4200 m_viewportIntersectionValid = true; | |
4201 FrameView* parent = parentFrameView(); | |
4202 if (!parent) { | |
4203 m_viewportIntersection = frameRect(); | |
4204 return; | |
4205 } | |
4206 ASSERT(!parent->m_needsUpdateViewportIntersection); | |
4207 | |
4208 // If our parent is hidden, then we are too. | |
4209 if (parent->m_viewportIntersection.isEmpty()) { | |
4210 m_viewportIntersection = parent->m_viewportIntersection; | |
4211 return; | |
4212 } | |
4213 | |
4214 // Transform our bounds into the root frame's content coordinate space, | |
4215 // making sure we have valid layout data in our parent document. If our | |
4216 // parent is throttled, we'll use possible stale layout information and | |
4217 // rely on the fact that another lifecycle update will be scheduled once | |
4218 // our parent becomes unthrottled. | |
4219 ASSERT(parent->lifecycle().state() >= DocumentLifecycle::LayoutClean || pare nt->shouldThrottleRendering()); | |
4220 m_viewportIntersection = parent->contentsToRootFrame(frameRect()); | |
4221 | |
4222 // TODO(skyostil): Expand the viewport to make it less likely to see stale c ontent while scrolling. | |
4223 IntRect viewport = parent->m_viewportIntersection; | |
4224 m_viewportIntersection.intersect(viewport); | |
4225 } | |
4226 | |
4227 void FrameView::updateViewportIntersectionsForSubtree(DocumentLifecycle::Lifecyc leState targetState) | 4224 void FrameView::updateViewportIntersectionsForSubtree(DocumentLifecycle::Lifecyc leState targetState) |
4228 { | 4225 { |
4229 bool hadValidIntersection = m_viewportIntersectionValid; | |
4230 bool hadEmptyIntersection = m_viewportIntersection.isEmpty(); | |
4231 updateViewportIntersectionIfNeeded(); | |
4232 | |
4233 // Notify javascript IntersectionObservers | 4226 // Notify javascript IntersectionObservers |
4234 if (targetState == DocumentLifecycle::PaintClean && frame().document()->inte rsectionObserverController()) | 4227 if (targetState == DocumentLifecycle::PaintClean && frame().document()->inte rsectionObserverController()) |
4235 frame().document()->intersectionObserverController()->computeTrackedInte rsectionObservations(); | 4228 frame().document()->intersectionObserverController()->computeTrackedInte rsectionObservations(); |
4236 | 4229 |
4237 // Adjust render throttling for iframes based on visibility | |
4238 bool shouldNotify = !hadValidIntersection || hadEmptyIntersection != m_viewp ortIntersection.isEmpty(); | |
4239 if (shouldNotify && !m_renderThrottlingObserverNotificationFactory->isPendin g()) | |
4240 m_frame->frameScheduler()->unthrottledTaskRunner()->postTask(BLINK_FROM_ HERE, m_renderThrottlingObserverNotificationFactory->cancelAndCreate()); | |
4241 | |
4242 if (!m_needsUpdateViewportIntersectionInSubtree) | 4230 if (!m_needsUpdateViewportIntersectionInSubtree) |
4243 return; | 4231 return; |
4244 m_needsUpdateViewportIntersectionInSubtree = false; | 4232 m_needsUpdateViewportIntersectionInSubtree = false; |
4245 | 4233 |
4246 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree ().nextSibling()) { | 4234 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree ().nextSibling()) { |
4247 if (!child->isLocalFrame()) | 4235 if (!child->isLocalFrame()) |
4248 continue; | 4236 continue; |
4249 if (FrameView* view = toLocalFrame(child)->view()) | 4237 if (FrameView* view = toLocalFrame(child)->view()) |
4250 view->updateViewportIntersectionsForSubtree(targetState); | 4238 view->updateViewportIntersectionsForSubtree(targetState); |
4251 } | 4239 } |
4252 } | 4240 } |
4253 | 4241 |
4254 void FrameView::updateThrottlingStatus() | 4242 void FrameView::updateRenderThrottlingStatusForTesting() |
4255 { | 4243 { |
4256 // Only offscreen frames can be throttled. | 4244 m_intersectionObserver->deliver(); |
4257 DCHECK(m_viewportIntersectionValid); | |
4258 m_hiddenForThrottling = m_viewportIntersection.isEmpty(); | |
4259 | |
4260 // We only throttle the rendering pipeline in cross-origin frames. This is | |
4261 // to avoid a situation where an ancestor frame directly depends on the | |
4262 // pipeline timing of a descendant and breaks as a result of throttling. | |
4263 // The rationale is that cross-origin frames must already communicate with | |
4264 // asynchronous messages, so they should be able to tolerate some delay in | |
4265 // receiving replies from a throttled peer. | |
4266 // | |
4267 // Check if we can access our parent's security origin. | |
4268 m_crossOriginForThrottling = false; | |
4269 // If any of our parents are throttled, we must be too. | |
4270 m_subtreeThrottled = false; | |
4271 const SecurityOrigin* origin = frame().securityContext()->getSecurityOrigin( ); | |
4272 for (Frame* parentFrame = m_frame->tree().parent(); parentFrame; parentFrame = parentFrame->tree().parent()) { | |
4273 const SecurityOrigin* parentOrigin = parentFrame->securityContext()->get SecurityOrigin(); | |
4274 if (!origin->canAccess(parentOrigin)) | |
4275 m_crossOriginForThrottling = true; | |
4276 if (parentFrame->isLocalFrame() && toLocalFrame(parentFrame)->view() && toLocalFrame(parentFrame)->view()->canThrottleRendering()) | |
4277 m_subtreeThrottled = true; | |
4278 } | |
4279 m_frame->frameScheduler()->setFrameVisible(!m_hiddenForThrottling); | |
4280 m_frame->frameScheduler()->setCrossOrigin(m_crossOriginForThrottling); | |
4281 } | 4245 } |
4282 | 4246 |
4283 void FrameView::notifyRenderThrottlingObserversForTesting() | 4247 void FrameView::updateRenderThrottlingStatus(bool hidden, bool subtreeThrottled) |
4284 { | |
4285 DCHECK(m_renderThrottlingObserverNotificationFactory->isPending()); | |
4286 notifyRenderThrottlingObservers(); | |
4287 } | |
4288 | |
4289 void FrameView::notifyRenderThrottlingObservers() | |
4290 { | 4248 { |
4291 TRACE_EVENT0("blink", "FrameView::notifyRenderThrottlingObservers"); | 4249 TRACE_EVENT0("blink", "FrameView::notifyRenderThrottlingObservers"); |
4292 DCHECK(!isInPerformLayout()); | 4250 DCHECK(!isInPerformLayout()); |
4293 DCHECK(frame().document()); | 4251 DCHECK(!m_frame->document() || !m_frame->document()->inStyleRecalc()); |
4294 DCHECK(!frame().document()->inStyleRecalc()); | |
4295 bool wasThrottled = canThrottleRendering(); | 4252 bool wasThrottled = canThrottleRendering(); |
4296 | 4253 |
4297 updateThrottlingStatus(); | 4254 m_hiddenForThrottling = hidden; |
4255 m_subtreeThrottled = subtreeThrottled; | |
4298 | 4256 |
4299 frame().document()->onVisibilityMaybeChanged(!m_hiddenForThrottling); | 4257 bool isThrottled = canThrottleRendering(); |
dgrogan
2016/09/15 23:47:07
If this was unintentionally dropped in the new cod
| |
4258 bool becameUnthrottled = wasThrottled && !isThrottled; | |
4300 | 4259 |
4301 bool becameThrottled = !wasThrottled && canThrottleRendering(); | 4260 // If this FrameView became unthrottled or throttled, we must make sure all |
4302 bool becameUnthrottled = wasThrottled && !canThrottleRendering(); | 4261 // its children are notified synchronously. Otherwise we 1) might attempt to |
4262 // paint one of the children with an out-of-date layout before | |
4263 // |updateRenderThrottlingStatus| has made it throttled or 2) fail to | |
4264 // unthrottle a child whose parent is unthrottled by a later notification. | |
4265 if (wasThrottled != isThrottled) { | |
4266 for (const Member<Widget>& child : *children()) { | |
4267 if (child->isFrameView()) { | |
4268 FrameView* childView = toFrameView(child); | |
4269 childView->updateRenderThrottlingStatus(childView->m_hiddenForTh rottling, isThrottled); | |
4270 } | |
4271 } | |
4272 } | |
4273 | |
4303 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); | 4274 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); |
4304 if (becameThrottled) { | |
4305 // If this FrameView became throttled, we must make sure all of its | |
4306 // children become throttled at the same time. Otherwise we might | |
4307 // attempt to paint one of the children with an out-of-date layout | |
4308 // before |notifyRenderThrottlingObservers| has made it throttled. | |
4309 forAllNonThrottledFrameViews([](FrameView& frameView) { | |
4310 frameView.m_subtreeThrottled = true; | |
4311 DCHECK(frameView.canThrottleRendering()); | |
4312 }); | |
4313 } | |
4314 if (becameUnthrottled) { | 4275 if (becameUnthrottled) { |
4315 // ScrollingCoordinator needs to update according to the new throttling status. | 4276 // ScrollingCoordinator needs to update according to the new throttling status. |
4316 if (scrollingCoordinator) | 4277 if (scrollingCoordinator) |
4317 scrollingCoordinator->notifyGeometryChanged(); | 4278 scrollingCoordinator->notifyGeometryChanged(); |
4318 // Start ticking animation frames again if necessary. | 4279 // Start ticking animation frames again if necessary. |
4319 if (page()) | 4280 if (page()) |
4320 page()->animator().scheduleVisualUpdate(m_frame.get()); | 4281 page()->animator().scheduleVisualUpdate(m_frame.get()); |
4321 // Force a full repaint of this frame to ensure we are not left with a | 4282 // Force a full repaint of this frame to ensure we are not left with a |
4322 // partially painted version of this frame's contents if we skipped | 4283 // partially painted version of this frame's contents if we skipped |
4323 // painting them while the frame was throttled. | 4284 // painting them while the frame was throttled. |
(...skipping 18 matching lines...) Expand all Loading... | |
4342 | 4303 |
4343 bool FrameView::shouldThrottleRendering() const | 4304 bool FrameView::shouldThrottleRendering() const |
4344 { | 4305 { |
4345 return canThrottleRendering() && lifecycle().throttlingAllowed(); | 4306 return canThrottleRendering() && lifecycle().throttlingAllowed(); |
4346 } | 4307 } |
4347 | 4308 |
4348 bool FrameView::canThrottleRendering() const | 4309 bool FrameView::canThrottleRendering() const |
4349 { | 4310 { |
4350 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled()) | 4311 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled()) |
4351 return false; | 4312 return false; |
4352 return m_subtreeThrottled || (m_hiddenForThrottling && m_crossOriginForThrot tling); | 4313 // We only throttle the rendering pipeline in cross-origin frames. This is |
4314 // to avoid a situation where an ancestor frame directly depends on the | |
4315 // pipeline timing of a descendant and breaks as a result of throttling. | |
4316 // The rationale is that cross-origin frames must already communicate with | |
4317 // asynchronous messages, so they should be able to tolerate some delay in | |
4318 // receiving replies from a throttled peer. | |
4319 return m_subtreeThrottled || (m_hiddenForThrottling && m_frame->isCrossOrigi nSubframe()); | |
4320 } | |
4321 | |
4322 FrameView::IntersectionObserverCallback::IntersectionObserverCallback(FrameView* frameView, ExecutionContext* context) | |
4323 : m_frameView(frameView) | |
4324 , m_context(context) | |
4325 { | |
4326 } | |
4327 | |
4328 void FrameView::IntersectionObserverCallback::handleEvent(const HeapVector<Membe r<IntersectionObserverEntry>>& entries, IntersectionObserver&) | |
4329 { | |
4330 if (!m_frameView) | |
4331 return; | |
4332 bool wasHidden = m_frameView->m_hiddenForThrottling; | |
4333 bool isHidden = wasHidden; | |
4334 if (!entries.isEmpty()) | |
4335 isHidden = !entries.last()->intersectionRatio(); | |
4336 if (wasHidden != isHidden) | |
4337 m_frameView->updateRenderThrottlingStatus(isHidden, m_frameView->m_subtr eeThrottled); | |
4338 } | |
4339 | |
4340 ExecutionContext* FrameView::IntersectionObserverCallback::getExecutionContext() const | |
4341 { | |
4342 return m_context.get(); | |
4343 } | |
4344 | |
4345 DEFINE_TRACE(FrameView::IntersectionObserverCallback) | |
4346 { | |
4347 blink::IntersectionObserverCallback::trace(visitor); | |
4348 visitor->trace(m_frameView); | |
4349 visitor->trace(m_context); | |
4353 } | 4350 } |
4354 | 4351 |
4355 } // namespace blink | 4352 } // namespace blink |
OLD | NEW |