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 | |
szager1
2016/08/30 23:57:12
if (frame().isLocalRoot())
return;
Sami
2016/08/31 11:08:56
Any particular reason why? That would mean we don'
szager1
2016/08/31 20:54:26
OK; that's a weird scenario, but if that's the beh
| |
287 IntersectionObserverInit observerInit; | |
288 // Intersection observer does not currently support remote frames. As a | |
szager1
2016/08/30 23:57:12
Is there a nice way to combine this with the stati
Sami
2016/08/31 11:08:55
I gave this a try but couldn't find a good way to
| |
289 // workaround we monitor visibility up to the local root (crbug.com/615156). | |
290 Frame* mainFrame = frame().tree().top(); | |
291 if (!mainFrame || !mainFrame->isLocalFrame()) | |
292 observerInit.setRoot(frame().localFrameRoot()->document()->documentEleme nt()); | |
293 | |
294 IntersectionObserverCallback* callback = new IntersectionObserverCallback(th is); | |
295 m_intersectionObserver = IntersectionObserver::create(observerInit, *callbac k, ASSERT_NO_EXCEPTION); | |
296 m_intersectionObserver->setLowLatency(true); | |
297 m_intersectionObserver->observe(frame().document()->documentElement()); | |
298 | |
299 // Initially the intersection observer assumes the target is hidden. If it | |
300 // actually is, no notification about this will be delivered. To work around | |
301 // this, we set the observer into an undefined state so the first | |
302 // notification will always get delivered. | |
303 for (auto& observation : m_intersectionObserver->observations()) | |
304 observation->setLastThresholdIndex(std::numeric_limits<unsigned>::max()) ; | |
305 } | |
306 | |
283 void FrameView::dispose() | 307 void FrameView::dispose() |
284 { | 308 { |
285 RELEASE_ASSERT(!isInPerformLayout()); | 309 RELEASE_ASSERT(!isInPerformLayout()); |
286 | 310 |
287 if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) | 311 if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) |
288 scrollAnimator->cancelAnimation(); | 312 scrollAnimator->cancelAnimation(); |
289 cancelProgrammaticScrollAnimation(); | 313 cancelProgrammaticScrollAnimation(); |
290 | 314 |
291 detachScrollbars(); | 315 detachScrollbars(); |
292 | 316 |
(...skipping 10 matching lines...) Expand all Loading... | |
303 | 327 |
304 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing | 328 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing |
305 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|. | 329 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|. |
306 m_autoSizeInfo.clear(); | 330 m_autoSizeInfo.clear(); |
307 | 331 |
308 if (m_postLayoutTasksTimer.isActive()) | 332 if (m_postLayoutTasksTimer.isActive()) |
309 m_postLayoutTasksTimer.stop(); | 333 m_postLayoutTasksTimer.stop(); |
310 | 334 |
311 if (m_didScrollTimer.isActive()) | 335 if (m_didScrollTimer.isActive()) |
312 m_didScrollTimer.stop(); | 336 m_didScrollTimer.stop(); |
313 m_renderThrottlingObserverNotificationFactory->cancel(); | |
314 | 337 |
315 // FIXME: Do we need to do something here for OOPI? | 338 // FIXME: Do we need to do something here for OOPI? |
316 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); | 339 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); |
317 // TODO(dcheng): It seems buggy that we can have an owner element that | 340 // TODO(dcheng): It seems buggy that we can have an owner element that |
318 // points to another Widget. | 341 // points to another Widget. |
319 if (ownerElement && ownerElement->ownedWidget() == this) | 342 if (ownerElement && ownerElement->ownedWidget() == this) |
320 ownerElement->setWidget(nullptr); | 343 ownerElement->setWidget(nullptr); |
321 | 344 |
322 #if ENABLE(ASSERT) | 345 #if ENABLE(ASSERT) |
323 m_hasBeenDisposed = true; | 346 m_hasBeenDisposed = true; |
(...skipping 2859 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3183 if (m_scrollbarsAvoidingResizer && parent()) | 3206 if (m_scrollbarsAvoidingResizer && parent()) |
3184 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(-m_scrollbar sAvoidingResizer); | 3207 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(-m_scrollbar sAvoidingResizer); |
3185 | 3208 |
3186 Widget::setParent(parentView); | 3209 Widget::setParent(parentView); |
3187 | 3210 |
3188 if (m_scrollbarsAvoidingResizer && parent()) | 3211 if (m_scrollbarsAvoidingResizer && parent()) |
3189 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(m_scrollbars AvoidingResizer); | 3212 toFrameView(parent())->adjustScrollbarsAvoidingResizerCount(m_scrollbars AvoidingResizer); |
3190 | 3213 |
3191 updateScrollableAreaSet(); | 3214 updateScrollableAreaSet(); |
3192 setNeedsUpdateViewportIntersection(); | 3215 setNeedsUpdateViewportIntersection(); |
3216 | |
3217 setupRenderThrottling(); | |
3193 } | 3218 } |
3194 | 3219 |
3195 void FrameView::removeChild(Widget* child) | 3220 void FrameView::removeChild(Widget* child) |
3196 { | 3221 { |
3197 ASSERT(child->parent() == this); | 3222 ASSERT(child->parent() == this); |
3198 | 3223 |
3199 if (child->isFrameView()) | 3224 if (child->isFrameView()) |
3200 removeScrollableArea(toFrameView(child)); | 3225 removeScrollableArea(toFrameView(child)); |
3201 | 3226 |
3202 child->setParent(0); | 3227 child->setParent(0); |
(...skipping 958 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4161 if (layoutObject.isText()) | 4186 if (layoutObject.isText()) |
4162 return; | 4187 return; |
4163 | 4188 |
4164 layoutObject.addAnnotatedRegions(regions); | 4189 layoutObject.addAnnotatedRegions(regions); |
4165 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; curr = curr-> nextSibling()) | 4190 for (LayoutObject* curr = layoutObject.slowFirstChild(); curr; curr = curr-> nextSibling()) |
4166 collectAnnotatedRegions(*curr, regions); | 4191 collectAnnotatedRegions(*curr, regions); |
4167 } | 4192 } |
4168 | 4193 |
4169 void FrameView::setNeedsUpdateViewportIntersection() | 4194 void FrameView::setNeedsUpdateViewportIntersection() |
4170 { | 4195 { |
4171 m_needsUpdateViewportIntersection = true; | |
4172 for (FrameView* parent = parentFrameView(); parent; parent = parent->parentF rameView()) | 4196 for (FrameView* parent = parentFrameView(); parent; parent = parent->parentF rameView()) |
4173 parent->m_needsUpdateViewportIntersectionInSubtree = true; | 4197 parent->m_needsUpdateViewportIntersectionInSubtree = true; |
4174 } | 4198 } |
4175 | 4199 |
4176 void FrameView::updateViewportIntersectionIfNeeded() | |
4177 { | |
4178 if (!m_needsUpdateViewportIntersection) | |
4179 return; | |
4180 m_needsUpdateViewportIntersection = false; | |
4181 m_viewportIntersectionValid = true; | |
4182 FrameView* parent = parentFrameView(); | |
4183 if (!parent) { | |
4184 m_viewportIntersection = frameRect(); | |
4185 return; | |
4186 } | |
4187 ASSERT(!parent->m_needsUpdateViewportIntersection); | |
4188 | |
4189 // If our parent is hidden, then we are too. | |
4190 if (parent->m_viewportIntersection.isEmpty()) { | |
4191 m_viewportIntersection = parent->m_viewportIntersection; | |
4192 return; | |
4193 } | |
4194 | |
4195 // Transform our bounds into the root frame's content coordinate space, | |
4196 // making sure we have valid layout data in our parent document. If our | |
4197 // parent is throttled, we'll use possible stale layout information and | |
4198 // rely on the fact that another lifecycle update will be scheduled once | |
4199 // our parent becomes unthrottled. | |
4200 ASSERT(parent->lifecycle().state() >= DocumentLifecycle::LayoutClean || pare nt->shouldThrottleRendering()); | |
4201 m_viewportIntersection = parent->contentsToRootFrame(frameRect()); | |
4202 | |
4203 // TODO(skyostil): Expand the viewport to make it less likely to see stale c ontent while scrolling. | |
4204 IntRect viewport = parent->m_viewportIntersection; | |
4205 m_viewportIntersection.intersect(viewport); | |
4206 } | |
4207 | |
4208 void FrameView::updateViewportIntersectionsForSubtree(DocumentLifecycle::Lifecyc leState targetState) | 4200 void FrameView::updateViewportIntersectionsForSubtree(DocumentLifecycle::Lifecyc leState targetState) |
4209 { | 4201 { |
4210 bool hadValidIntersection = m_viewportIntersectionValid; | |
4211 bool hadEmptyIntersection = m_viewportIntersection.isEmpty(); | |
4212 updateViewportIntersectionIfNeeded(); | |
4213 | |
4214 // Notify javascript IntersectionObservers | 4202 // Notify javascript IntersectionObservers |
4215 if (targetState == DocumentLifecycle::PaintClean && frame().document()->inte rsectionObserverController()) | 4203 if (targetState == DocumentLifecycle::PaintClean && frame().document()->inte rsectionObserverController()) |
4216 frame().document()->intersectionObserverController()->computeTrackedInte rsectionObservations(); | 4204 frame().document()->intersectionObserverController()->computeTrackedInte rsectionObservations(); |
4217 | 4205 |
4218 // Adjust render throttling for iframes based on visibility | |
4219 bool shouldNotify = !hadValidIntersection || hadEmptyIntersection != m_viewp ortIntersection.isEmpty(); | |
4220 if (shouldNotify && !m_renderThrottlingObserverNotificationFactory->isPendin g()) | |
4221 m_frame->frameScheduler()->unthrottledTaskRunner()->postTask(BLINK_FROM_ HERE, m_renderThrottlingObserverNotificationFactory->cancelAndCreate()); | |
4222 | |
4223 if (!m_needsUpdateViewportIntersectionInSubtree) | 4206 if (!m_needsUpdateViewportIntersectionInSubtree) |
4224 return; | 4207 return; |
4225 m_needsUpdateViewportIntersectionInSubtree = false; | 4208 m_needsUpdateViewportIntersectionInSubtree = false; |
4226 | 4209 |
4227 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree ().nextSibling()) { | 4210 for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree ().nextSibling()) { |
4228 if (!child->isLocalFrame()) | 4211 if (!child->isLocalFrame()) |
4229 continue; | 4212 continue; |
4230 if (FrameView* view = toLocalFrame(child)->view()) | 4213 if (FrameView* view = toLocalFrame(child)->view()) |
4231 view->updateViewportIntersectionsForSubtree(targetState); | 4214 view->updateViewportIntersectionsForSubtree(targetState); |
4232 } | 4215 } |
4233 } | 4216 } |
4234 | 4217 |
4235 void FrameView::updateThrottlingStatus() | 4218 void FrameView::updateRenderThrottlingStatusForTesting() |
4236 { | 4219 { |
4237 // Only offscreen frames can be throttled. | 4220 m_intersectionObserver->deliver(); |
4238 DCHECK(m_viewportIntersectionValid); | |
4239 m_hiddenForThrottling = m_viewportIntersection.isEmpty(); | |
4240 | |
4241 // We only throttle the rendering pipeline in cross-origin frames. This is | |
4242 // to avoid a situation where an ancestor frame directly depends on the | |
4243 // pipeline timing of a descendant and breaks as a result of throttling. | |
4244 // The rationale is that cross-origin frames must already communicate with | |
4245 // asynchronous messages, so they should be able to tolerate some delay in | |
4246 // receiving replies from a throttled peer. | |
4247 // | |
4248 // Check if we can access our parent's security origin. | |
4249 m_crossOriginForThrottling = false; | |
4250 // If any of our parents are throttled, we must be too. | |
4251 m_subtreeThrottled = false; | |
4252 const SecurityOrigin* origin = frame().securityContext()->getSecurityOrigin( ); | |
4253 for (Frame* parentFrame = m_frame->tree().parent(); parentFrame; parentFrame = parentFrame->tree().parent()) { | |
4254 const SecurityOrigin* parentOrigin = parentFrame->securityContext()->get SecurityOrigin(); | |
4255 if (!origin->canAccess(parentOrigin)) | |
4256 m_crossOriginForThrottling = true; | |
4257 if (parentFrame->isLocalFrame() && toLocalFrame(parentFrame)->view() && toLocalFrame(parentFrame)->view()->canThrottleRendering()) | |
4258 m_subtreeThrottled = true; | |
4259 } | |
4260 m_frame->frameScheduler()->setFrameVisible(!m_hiddenForThrottling); | |
4261 m_frame->frameScheduler()->setCrossOrigin(m_crossOriginForThrottling); | |
4262 } | 4221 } |
4263 | 4222 |
4264 void FrameView::notifyRenderThrottlingObserversForTesting() | 4223 void FrameView::updateRenderThrottlingStatus(bool hidden, bool subtreeThrottled) |
4265 { | |
4266 DCHECK(m_renderThrottlingObserverNotificationFactory->isPending()); | |
4267 notifyRenderThrottlingObservers(); | |
4268 } | |
4269 | |
4270 void FrameView::notifyRenderThrottlingObservers() | |
4271 { | 4224 { |
4272 TRACE_EVENT0("blink", "FrameView::notifyRenderThrottlingObservers"); | 4225 TRACE_EVENT0("blink", "FrameView::notifyRenderThrottlingObservers"); |
4273 DCHECK(!isInPerformLayout()); | 4226 DCHECK(!isInPerformLayout()); |
4274 DCHECK(!m_frame->document() || !m_frame->document()->inStyleRecalc()); | 4227 DCHECK(!m_frame->document() || !m_frame->document()->inStyleRecalc()); |
4275 bool wasThrottled = canThrottleRendering(); | 4228 bool wasThrottled = canThrottleRendering(); |
4276 | 4229 |
4277 updateThrottlingStatus(); | 4230 m_hiddenForThrottling = hidden; |
4231 m_subtreeThrottled = subtreeThrottled; | |
4278 | 4232 |
4279 bool becameThrottled = !wasThrottled && canThrottleRendering(); | 4233 bool isThrottled = canThrottleRendering(); |
4280 bool becameUnthrottled = wasThrottled && !canThrottleRendering(); | 4234 bool becameUnthrottled = wasThrottled && !isThrottled; |
4235 | |
4236 // If this FrameView became unthrottled or throttled, we must make sure all | |
4237 // its children are notified synchronously. Otherwise we 1) might attempt to | |
4238 // paint one of the children with an out-of-date layout before | |
4239 // |updateRenderThrottlingStatus| has made it throttled or 2) fail to | |
4240 // unthrottle a child whose parent is unthrottled by a later notification. | |
4241 if (wasThrottled != isThrottled) { | |
4242 for (const Member<Widget>& child : *children()) { | |
4243 if (child->isFrameView()) { | |
4244 FrameView* childView = toFrameView(child); | |
4245 childView->updateRenderThrottlingStatus(childView->m_hiddenForTh rottling, isThrottled); | |
4246 } | |
4247 } | |
4248 } | |
4249 | |
4281 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); | 4250 ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator(); |
4282 if (becameThrottled) { | |
4283 // If this FrameView became throttled, we must make sure all of its | |
4284 // children become throttled at the same time. Otherwise we might | |
4285 // attempt to paint one of the children with an out-of-date layout | |
4286 // before |notifyRenderThrottlingObservers| has made it throttled. | |
4287 forAllNonThrottledFrameViews([](FrameView& frameView) { | |
4288 frameView.m_subtreeThrottled = true; | |
4289 DCHECK(frameView.canThrottleRendering()); | |
4290 }); | |
4291 } | |
4292 if (becameUnthrottled) { | 4251 if (becameUnthrottled) { |
4293 // ScrollingCoordinator needs to update according to the new throttling status. | 4252 // ScrollingCoordinator needs to update according to the new throttling status. |
4294 if (scrollingCoordinator) | 4253 if (scrollingCoordinator) |
4295 scrollingCoordinator->notifyGeometryChanged(); | 4254 scrollingCoordinator->notifyGeometryChanged(); |
4296 // Start ticking animation frames again if necessary. | 4255 // Start ticking animation frames again if necessary. |
4297 if (page()) | 4256 if (page()) |
4298 page()->animator().scheduleVisualUpdate(m_frame.get()); | 4257 page()->animator().scheduleVisualUpdate(m_frame.get()); |
4299 // Force a full repaint of this frame to ensure we are not left with a | 4258 // Force a full repaint of this frame to ensure we are not left with a |
4300 // partially painted version of this frame's contents if we skipped | 4259 // partially painted version of this frame's contents if we skipped |
4301 // painting them while the frame was throttled. | 4260 // painting them while the frame was throttled. |
(...skipping 18 matching lines...) Expand all Loading... | |
4320 | 4279 |
4321 bool FrameView::shouldThrottleRendering() const | 4280 bool FrameView::shouldThrottleRendering() const |
4322 { | 4281 { |
4323 return canThrottleRendering() && lifecycle().throttlingAllowed(); | 4282 return canThrottleRendering() && lifecycle().throttlingAllowed(); |
4324 } | 4283 } |
4325 | 4284 |
4326 bool FrameView::canThrottleRendering() const | 4285 bool FrameView::canThrottleRendering() const |
4327 { | 4286 { |
4328 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled()) | 4287 if (!RuntimeEnabledFeatures::renderingPipelineThrottlingEnabled()) |
4329 return false; | 4288 return false; |
4330 return m_subtreeThrottled || (m_hiddenForThrottling && m_crossOriginForThrot tling); | 4289 // We only throttle the rendering pipeline in cross-origin frames. This is |
4290 // to avoid a situation where an ancestor frame directly depends on the | |
4291 // pipeline timing of a descendant and breaks as a result of throttling. | |
4292 // The rationale is that cross-origin frames must already communicate with | |
4293 // asynchronous messages, so they should be able to tolerate some delay in | |
4294 // receiving replies from a throttled peer. | |
4295 return m_subtreeThrottled || (m_hiddenForThrottling && m_frame->isCrossOrigi nSubframe()); | |
4296 } | |
4297 | |
4298 FrameView::IntersectionObserverCallback::IntersectionObserverCallback(FrameView* frameView) | |
4299 : m_frameView(std::move(frameView)) | |
szager1
2016/08/30 23:57:12
Why std::move?
Sami
2016/08/31 11:08:55
Oops, looks like I'm typing it out of habit alread
| |
4300 { | |
4301 } | |
4302 | |
4303 void FrameView::IntersectionObserverCallback::handleEvent(const HeapVector<Membe r<IntersectionObserverEntry>>& entries, IntersectionObserver&) | |
4304 { | |
4305 bool wasHidden = m_frameView->m_hiddenForThrottling; | |
4306 bool isHidden = wasHidden; | |
4307 for (const auto& entry : entries) | |
szager1
2016/08/30 23:57:11
if (entries.length())
isHidden = !entries.last()
Sami
2016/08/31 11:08:56
Neat, thanks!
| |
4308 isHidden = !entry->intersectionRatio(); | |
4309 if (wasHidden != isHidden) | |
4310 m_frameView->updateRenderThrottlingStatus(isHidden, m_frameView->m_subtr eeThrottled); | |
szager1
2016/08/30 23:57:12
I would expect that you need a friend declaration
Sami
2016/08/31 11:08:55
This is an inner class and since C++11 it's automa
| |
4311 } | |
4312 | |
4313 ExecutionContext* FrameView::IntersectionObserverCallback::getExecutionContext() const | |
4314 { | |
4315 return m_frameView->frame().document(); | |
szager1
2016/08/30 23:57:12
I'm not sure it matters, which ExecutionContext is
Sami
2016/08/31 11:08:56
I wasn't sure about that either. I've now made it
| |
4316 } | |
4317 | |
4318 DEFINE_TRACE(FrameView::IntersectionObserverCallback) | |
4319 { | |
4320 blink::IntersectionObserverCallback::trace(visitor); | |
4321 visitor->trace(m_frameView); | |
4331 } | 4322 } |
4332 | 4323 |
4333 } // namespace blink | 4324 } // namespace blink |
OLD | NEW |