OLD | NEW |
| (Empty) |
1 // Copyright 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "config.h" | |
6 | |
7 #include "CCLayerTreeHostImpl.h" | |
8 | |
9 #include "base/basictypes.h" | |
10 #include "CCAppendQuadsData.h" | |
11 #include "CCDamageTracker.h" | |
12 #include "CCDebugRectHistory.h" | |
13 #include "CCDelayBasedTimeSource.h" | |
14 #include "CCFontAtlas.h" | |
15 #include "CCFrameRateCounter.h" | |
16 #include "CCHeadsUpDisplayLayerImpl.h" | |
17 #include "CCLayerIterator.h" | |
18 #include "CCLayerTreeHost.h" | |
19 #include "CCLayerTreeHostCommon.h" | |
20 #include "CCMathUtil.h" | |
21 #include "CCOverdrawMetrics.h" | |
22 #include "CCPageScaleAnimation.h" | |
23 #include "CCPrioritizedTextureManager.h" | |
24 #include "CCRenderPassDrawQuad.h" | |
25 #include "CCRendererGL.h" | |
26 #include "CCRendererSoftware.h" | |
27 #include "CCRenderingStats.h" | |
28 #include "CCScrollbarAnimationController.h" | |
29 #include "CCScrollbarLayerImpl.h" | |
30 #include "CCSettings.h" | |
31 #include "CCSingleThreadProxy.h" | |
32 #include "TextureUploader.h" | |
33 #include "TraceEvent.h" | |
34 #include <wtf/CurrentTime.h> | |
35 #include <algorithm> | |
36 | |
37 using WebKit::WebTransformationMatrix; | |
38 | |
39 namespace { | |
40 | |
41 void didVisibilityChange(cc::CCLayerTreeHostImpl* id, bool visible) | |
42 { | |
43 if (visible) { | |
44 TRACE_EVENT_ASYNC_BEGIN1("webkit", "CCLayerTreeHostImpl::setVisible", id
, "CCLayerTreeHostImpl", id); | |
45 return; | |
46 } | |
47 | |
48 TRACE_EVENT_ASYNC_END0("webkit", "CCLayerTreeHostImpl::setVisible", id); | |
49 } | |
50 | |
51 } // namespace | |
52 | |
53 namespace cc { | |
54 | |
55 CCPinchZoomViewport::CCPinchZoomViewport() | |
56 : m_pageScaleFactor(1) | |
57 , m_pageScaleDelta(1) | |
58 , m_sentPageScaleDelta(1) | |
59 , m_minPageScaleFactor(0) | |
60 , m_maxPageScaleFactor(0) | |
61 { | |
62 } | |
63 | |
64 float CCPinchZoomViewport::totalPageScaleFactor() const | |
65 { | |
66 return m_pageScaleFactor * m_pageScaleDelta; | |
67 } | |
68 | |
69 void CCPinchZoomViewport::setPageScaleDelta(float delta) | |
70 { | |
71 // Clamp to the current min/max limits. | |
72 float totalPageScaleFactor = m_pageScaleFactor * delta; | |
73 if (m_minPageScaleFactor && totalPageScaleFactor < m_minPageScaleFactor) | |
74 delta = m_minPageScaleFactor / m_pageScaleFactor; | |
75 else if (m_maxPageScaleFactor && totalPageScaleFactor > m_maxPageScaleFactor
) | |
76 delta = m_maxPageScaleFactor / m_pageScaleFactor; | |
77 | |
78 if (delta == m_pageScaleDelta) | |
79 return; | |
80 | |
81 m_pageScaleDelta = delta; | |
82 } | |
83 | |
84 bool CCPinchZoomViewport::setPageScaleFactorAndLimits(float pageScaleFactor, flo
at minPageScaleFactor, float maxPageScaleFactor) | |
85 { | |
86 ASSERT(pageScaleFactor); | |
87 | |
88 if (m_sentPageScaleDelta == 1 && pageScaleFactor == m_pageScaleFactor && min
PageScaleFactor == m_minPageScaleFactor && maxPageScaleFactor == m_maxPageScaleF
actor) | |
89 return false; | |
90 | |
91 m_minPageScaleFactor = minPageScaleFactor; | |
92 m_maxPageScaleFactor = maxPageScaleFactor; | |
93 | |
94 m_pageScaleFactor = pageScaleFactor; | |
95 return true; | |
96 } | |
97 | |
98 FloatRect CCPinchZoomViewport::bounds() const | |
99 { | |
100 FloatSize scaledViewportSize = m_layoutViewportSize; | |
101 scaledViewportSize.scale(1 / totalPageScaleFactor()); | |
102 | |
103 FloatRect bounds(FloatPoint(0, 0), scaledViewportSize); | |
104 bounds.setLocation(m_pinchViewportScrollDelta); | |
105 | |
106 return bounds; | |
107 } | |
108 | |
109 FloatSize CCPinchZoomViewport::applyScroll(FloatSize& delta) | |
110 { | |
111 FloatSize overflow; | |
112 FloatRect pinchedBounds = bounds(); | |
113 | |
114 pinchedBounds.move(delta); | |
115 if (pinchedBounds.x() < 0) { | |
116 overflow.setWidth(pinchedBounds.x()); | |
117 pinchedBounds.setX(0); | |
118 } | |
119 | |
120 if (pinchedBounds.y() < 0) { | |
121 overflow.setHeight(pinchedBounds.y()); | |
122 pinchedBounds.setY(0); | |
123 } | |
124 | |
125 if (pinchedBounds.maxX() > m_layoutViewportSize.width()) { | |
126 overflow.setWidth( | |
127 pinchedBounds.maxX() - m_layoutViewportSize.width()); | |
128 pinchedBounds.move( | |
129 m_layoutViewportSize.width() - pinchedBounds.maxX(), 0); | |
130 } | |
131 | |
132 if (pinchedBounds.maxY() > m_layoutViewportSize.height()) { | |
133 overflow.setHeight( | |
134 pinchedBounds.maxY() - m_layoutViewportSize.height()); | |
135 pinchedBounds.move( | |
136 0, m_layoutViewportSize.height() - pinchedBounds.maxY()); | |
137 } | |
138 m_pinchViewportScrollDelta = pinchedBounds.location(); | |
139 | |
140 return overflow; | |
141 } | |
142 | |
143 WebTransformationMatrix CCPinchZoomViewport::implTransform() const | |
144 { | |
145 WebTransformationMatrix transform; | |
146 transform.scale(m_pageScaleDelta); | |
147 | |
148 // If the pinch state is applied in the impl, then push it to the | |
149 // impl transform, otherwise the scale is handled by WebCore. | |
150 if (CCSettings::pageScalePinchZoomEnabled()) { | |
151 transform.scale(m_pageScaleFactor); | |
152 transform.translate(-m_pinchViewportScrollDelta.x(), | |
153 -m_pinchViewportScrollDelta.y()); | |
154 } | |
155 | |
156 return transform; | |
157 } | |
158 | |
159 class CCLayerTreeHostImplTimeSourceAdapter : public CCTimeSourceClient { | |
160 public: | |
161 static PassOwnPtr<CCLayerTreeHostImplTimeSourceAdapter> create(CCLayerTreeHo
stImpl* layerTreeHostImpl, PassRefPtr<CCDelayBasedTimeSource> timeSource) | |
162 { | |
163 return adoptPtr(new CCLayerTreeHostImplTimeSourceAdapter(layerTreeHostIm
pl, timeSource)); | |
164 } | |
165 virtual ~CCLayerTreeHostImplTimeSourceAdapter() | |
166 { | |
167 m_timeSource->setClient(0); | |
168 m_timeSource->setActive(false); | |
169 } | |
170 | |
171 virtual void onTimerTick() OVERRIDE | |
172 { | |
173 // FIXME: We require that animate be called on the impl thread. This | |
174 // avoids asserts in single threaded mode. Ideally background ticking | |
175 // would be handled by the proxy/scheduler and this could be removed. | |
176 DebugScopedSetImplThread impl; | |
177 | |
178 m_layerTreeHostImpl->animate(monotonicallyIncreasingTime(), currentTime(
)); | |
179 } | |
180 | |
181 void setActive(bool active) | |
182 { | |
183 if (active != m_timeSource->active()) | |
184 m_timeSource->setActive(active); | |
185 } | |
186 | |
187 private: | |
188 CCLayerTreeHostImplTimeSourceAdapter(CCLayerTreeHostImpl* layerTreeHostImpl,
PassRefPtr<CCDelayBasedTimeSource> timeSource) | |
189 : m_layerTreeHostImpl(layerTreeHostImpl) | |
190 , m_timeSource(timeSource) | |
191 { | |
192 m_timeSource->setClient(this); | |
193 } | |
194 | |
195 CCLayerTreeHostImpl* m_layerTreeHostImpl; | |
196 RefPtr<CCDelayBasedTimeSource> m_timeSource; | |
197 | |
198 DISALLOW_COPY_AND_ASSIGN(CCLayerTreeHostImplTimeSourceAdapter); | |
199 }; | |
200 | |
201 CCLayerTreeHostImpl::FrameData::FrameData() | |
202 { | |
203 } | |
204 | |
205 CCLayerTreeHostImpl::FrameData::~FrameData() | |
206 { | |
207 } | |
208 | |
209 scoped_ptr<CCLayerTreeHostImpl> CCLayerTreeHostImpl::create(const CCLayerTreeSet
tings& settings, CCLayerTreeHostImplClient* client) | |
210 { | |
211 return make_scoped_ptr(new CCLayerTreeHostImpl(settings, client)); | |
212 } | |
213 | |
214 CCLayerTreeHostImpl::CCLayerTreeHostImpl(const CCLayerTreeSettings& settings, CC
LayerTreeHostImplClient* client) | |
215 : m_client(client) | |
216 , m_sourceFrameNumber(-1) | |
217 , m_rootScrollLayerImpl(0) | |
218 , m_currentlyScrollingLayerImpl(0) | |
219 , m_hudLayerImpl(0) | |
220 , m_scrollingLayerIdFromPreviousTree(-1) | |
221 , m_scrollDeltaIsInScreenSpace(false) | |
222 , m_settings(settings) | |
223 , m_deviceScaleFactor(1) | |
224 , m_visible(true) | |
225 , m_contentsTexturesPurged(false) | |
226 , m_memoryAllocationLimitBytes(CCPrioritizedTextureManager::defaultMemoryAll
ocationLimit()) | |
227 , m_backgroundColor(0) | |
228 , m_hasTransparentBackground(false) | |
229 , m_needsAnimateLayers(false) | |
230 , m_pinchGestureActive(false) | |
231 , m_fpsCounter(CCFrameRateCounter::create()) | |
232 , m_debugRectHistory(CCDebugRectHistory::create()) | |
233 , m_numImplThreadScrolls(0) | |
234 , m_numMainThreadScrolls(0) | |
235 { | |
236 ASSERT(CCProxy::isImplThread()); | |
237 didVisibilityChange(this, m_visible); | |
238 } | |
239 | |
240 CCLayerTreeHostImpl::~CCLayerTreeHostImpl() | |
241 { | |
242 ASSERT(CCProxy::isImplThread()); | |
243 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::~CCLayerTreeHostImpl()"); | |
244 | |
245 if (m_rootLayerImpl) | |
246 clearRenderSurfaces(); | |
247 } | |
248 | |
249 void CCLayerTreeHostImpl::beginCommit() | |
250 { | |
251 } | |
252 | |
253 void CCLayerTreeHostImpl::commitComplete() | |
254 { | |
255 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::commitComplete"); | |
256 // Recompute max scroll position; must be after layer content bounds are | |
257 // updated. | |
258 updateMaxScrollPosition(); | |
259 } | |
260 | |
261 bool CCLayerTreeHostImpl::canDraw() | |
262 { | |
263 // Note: If you are changing this function or any other function that might | |
264 // affect the result of canDraw, make sure to call m_client->onCanDrawStateC
hanged | |
265 // in the proper places and update the notifyIfCanDrawChanged test. | |
266 | |
267 if (!m_rootLayerImpl) { | |
268 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw no root layer")
; | |
269 return false; | |
270 } | |
271 if (deviceViewportSize().isEmpty()) { | |
272 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw empty viewport"
); | |
273 return false; | |
274 } | |
275 if (!m_renderer) { | |
276 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw no renderer"); | |
277 return false; | |
278 } | |
279 if (m_contentsTexturesPurged) { | |
280 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw contents textur
es purged"); | |
281 return false; | |
282 } | |
283 return true; | |
284 } | |
285 | |
286 CCGraphicsContext* CCLayerTreeHostImpl::context() const | |
287 { | |
288 return m_context.get(); | |
289 } | |
290 | |
291 void CCLayerTreeHostImpl::animate(double monotonicTime, double wallClockTime) | |
292 { | |
293 animatePageScale(monotonicTime); | |
294 animateLayers(monotonicTime, wallClockTime); | |
295 animateScrollbars(monotonicTime); | |
296 } | |
297 | |
298 void CCLayerTreeHostImpl::startPageScaleAnimation(const IntSize& targetPosition,
bool anchorPoint, float pageScale, double startTime, double duration) | |
299 { | |
300 if (!m_rootScrollLayerImpl) | |
301 return; | |
302 | |
303 IntSize scrollTotal = flooredIntSize(m_rootScrollLayerImpl->scrollPosition()
+ m_rootScrollLayerImpl->scrollDelta()); | |
304 scrollTotal.scale(m_pinchZoomViewport.pageScaleDelta()); | |
305 float scaleTotal = m_pinchZoomViewport.totalPageScaleFactor(); | |
306 IntSize scaledContentSize = contentSize(); | |
307 scaledContentSize.scale(m_pinchZoomViewport.pageScaleDelta()); | |
308 | |
309 m_pageScaleAnimation = CCPageScaleAnimation::create(scrollTotal, scaleTotal,
m_deviceViewportSize, scaledContentSize, startTime); | |
310 | |
311 if (anchorPoint) { | |
312 IntSize windowAnchor(targetPosition); | |
313 windowAnchor.scale(scaleTotal / pageScale); | |
314 windowAnchor -= scrollTotal; | |
315 m_pageScaleAnimation->zoomWithAnchor(windowAnchor, pageScale, duration); | |
316 } else | |
317 m_pageScaleAnimation->zoomTo(targetPosition, pageScale, duration); | |
318 | |
319 m_client->setNeedsRedrawOnImplThread(); | |
320 m_client->setNeedsCommitOnImplThread(); | |
321 } | |
322 | |
323 void CCLayerTreeHostImpl::scheduleAnimation() | |
324 { | |
325 m_client->setNeedsRedrawOnImplThread(); | |
326 } | |
327 | |
328 void CCLayerTreeHostImpl::trackDamageForAllSurfaces(CCLayerImpl* rootDrawLayer,
const CCLayerList& renderSurfaceLayerList) | |
329 { | |
330 // For now, we use damage tracking to compute a global scissor. To do this,
we must | |
331 // compute all damage tracking before drawing anything, so that we know the
root | |
332 // damage rect. The root damage rect is then used to scissor each surface. | |
333 | |
334 for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0
; --surfaceIndex) { | |
335 CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex]; | |
336 CCRenderSurface* renderSurface = renderSurfaceLayer->renderSurface(); | |
337 ASSERT(renderSurface); | |
338 renderSurface->damageTracker()->updateDamageTrackingState(renderSurface-
>layerList(), renderSurfaceLayer->id(), renderSurface->surfacePropertyChangedOnl
yFromDescendant(), renderSurface->contentRect(), renderSurfaceLayer->maskLayer()
, renderSurfaceLayer->filters()); | |
339 } | |
340 } | |
341 | |
342 void CCLayerTreeHostImpl::updateRootScrollLayerImplTransform() | |
343 { | |
344 if (m_rootScrollLayerImpl) { | |
345 m_rootScrollLayerImpl->setImplTransform(implTransform()); | |
346 } | |
347 } | |
348 | |
349 void CCLayerTreeHostImpl::calculateRenderSurfaceLayerList(CCLayerList& renderSur
faceLayerList) | |
350 { | |
351 ASSERT(renderSurfaceLayerList.empty()); | |
352 ASSERT(m_rootLayerImpl); | |
353 ASSERT(m_renderer); // For maxTextureSize. | |
354 | |
355 { | |
356 updateRootScrollLayerImplTransform(); | |
357 | |
358 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::calcDrawEtc"); | |
359 CCLayerTreeHostCommon::calculateDrawTransforms(m_rootLayerImpl.get(), de
viceViewportSize(), m_deviceScaleFactor, &m_layerSorter, rendererCapabilities().
maxTextureSize, renderSurfaceLayerList); | |
360 | |
361 trackDamageForAllSurfaces(m_rootLayerImpl.get(), renderSurfaceLayerList)
; | |
362 } | |
363 } | |
364 | |
365 void CCLayerTreeHostImpl::FrameData::appendRenderPass(scoped_ptr<CCRenderPass> r
enderPass) | |
366 { | |
367 CCRenderPass* pass = renderPass.get(); | |
368 renderPasses.push_back(pass); | |
369 renderPassesById.set(pass->id(), renderPass.Pass()); | |
370 } | |
371 | |
372 bool CCLayerTreeHostImpl::calculateRenderPasses(FrameData& frame) | |
373 { | |
374 ASSERT(frame.renderPasses.empty()); | |
375 | |
376 calculateRenderSurfaceLayerList(*frame.renderSurfaceLayerList); | |
377 | |
378 TRACE_EVENT1("cc", "CCLayerTreeHostImpl::calculateRenderPasses", "renderSurf
aceLayerList.size()", static_cast<long long unsigned>(frame.renderSurfaceLayerLi
st->size())); | |
379 | |
380 // Create the render passes in dependency order. | |
381 for (int surfaceIndex = frame.renderSurfaceLayerList->size() - 1; surfaceInd
ex >= 0 ; --surfaceIndex) { | |
382 CCLayerImpl* renderSurfaceLayer = (*frame.renderSurfaceLayerList)[surfac
eIndex]; | |
383 renderSurfaceLayer->renderSurface()->appendRenderPasses(frame); | |
384 } | |
385 | |
386 bool recordMetricsForFrame = true; // FIXME: In the future, disable this whe
n about:tracing is off. | |
387 CCOcclusionTrackerImpl occlusionTracker(m_rootLayerImpl->renderSurface()->co
ntentRect(), recordMetricsForFrame); | |
388 occlusionTracker.setMinimumTrackingSize(m_settings.minimumOcclusionTrackingS
ize); | |
389 | |
390 if (settings().showOccludingRects) | |
391 occlusionTracker.setOccludingScreenSpaceRectsContainer(&frame.occludingS
creenSpaceRects); | |
392 | |
393 // Add quads to the Render passes in FrontToBack order to allow for testing
occlusion and performing culling during the tree walk. | |
394 typedef CCLayerIterator<CCLayerImpl, std::vector<CCLayerImpl*>, CCRenderSurf
ace, CCLayerIteratorActions::FrontToBack> CCLayerIteratorType; | |
395 | |
396 // Typically when we are missing a texture and use a checkerboard quad, we s
till draw the frame. However when the layer being | |
397 // checkerboarded is moving due to an impl-animation, we drop the frame to a
void flashing due to the texture suddenly appearing | |
398 // in the future. | |
399 bool drawFrame = true; | |
400 | |
401 CCLayerIteratorType end = CCLayerIteratorType::end(frame.renderSurfaceLayerL
ist); | |
402 for (CCLayerIteratorType it = CCLayerIteratorType::begin(frame.renderSurface
LayerList); it != end; ++it) { | |
403 CCRenderPass::Id targetRenderPassId = it.targetRenderSurfaceLayer()->ren
derSurface()->renderPassId(); | |
404 CCRenderPass* targetRenderPass = frame.renderPassesById.get(targetRender
PassId); | |
405 | |
406 occlusionTracker.enterLayer(it); | |
407 | |
408 CCAppendQuadsData appendQuadsData(targetRenderPass->id()); | |
409 | |
410 if (it.representsContributingRenderSurface()) { | |
411 CCRenderPass::Id contributingRenderPassId = it->renderSurface()->ren
derPassId(); | |
412 CCRenderPass* contributingRenderPass = frame.renderPassesById.get(co
ntributingRenderPassId); | |
413 targetRenderPass->appendQuadsForRenderSurfaceLayer(*it, contributing
RenderPass, &occlusionTracker, appendQuadsData); | |
414 } else if (it.representsItself() && !it->visibleContentRect().isEmpty())
{ | |
415 bool hasOcclusionFromOutsideTargetSurface; | |
416 if (occlusionTracker.occluded(*it, it->visibleContentRect(), &hasOcc
lusionFromOutsideTargetSurface)) | |
417 appendQuadsData.hadOcclusionFromOutsideTargetSurface |= hasOcclu
sionFromOutsideTargetSurface; | |
418 else { | |
419 it->willDraw(m_resourceProvider.get()); | |
420 frame.willDrawLayers.push_back(*it); | |
421 | |
422 if (it->hasContributingDelegatedRenderPasses()) { | |
423 CCRenderPass::Id contributingRenderPassId = it->firstContrib
utingRenderPassId(); | |
424 while (frame.renderPassesById.contains(contributingRenderPas
sId)) { | |
425 CCRenderPass* renderPass = frame.renderPassesById.get(co
ntributingRenderPassId); | |
426 | |
427 CCAppendQuadsData appendQuadsData(renderPass->id()); | |
428 renderPass->appendQuadsForLayer(*it, &occlusionTracker,
appendQuadsData); | |
429 | |
430 contributingRenderPassId = it->nextContributingRenderPas
sId(contributingRenderPassId); | |
431 } | |
432 } | |
433 | |
434 targetRenderPass->appendQuadsForLayer(*it, &occlusionTracker, ap
pendQuadsData); | |
435 } | |
436 } | |
437 | |
438 if (appendQuadsData.hadOcclusionFromOutsideTargetSurface) | |
439 targetRenderPass->setHasOcclusionFromOutsideTargetSurface(true); | |
440 | |
441 if (appendQuadsData.hadMissingTiles) { | |
442 bool layerHasAnimatingTransform = it->screenSpaceTransformIsAnimatin
g() || it->drawTransformIsAnimating(); | |
443 if (layerHasAnimatingTransform || CCSettings::jankInsteadOfCheckerbo
ard()) | |
444 drawFrame = false; | |
445 } | |
446 | |
447 occlusionTracker.leaveLayer(it); | |
448 } | |
449 | |
450 #if !ASSERT_DISABLED | |
451 for (size_t i = 0; i < frame.renderPasses.size(); ++i) { | |
452 for (size_t j = 0; j < frame.renderPasses[i]->quadList().size(); ++j) | |
453 ASSERT(frame.renderPasses[i]->quadList()[j]->sharedQuadStateId() >=
0); | |
454 ASSERT(frame.renderPassesById.contains(frame.renderPasses[i]->id())); | |
455 } | |
456 #endif | |
457 | |
458 if (!m_hasTransparentBackground) { | |
459 frame.renderPasses.back()->setHasTransparentBackground(false); | |
460 frame.renderPasses.back()->appendQuadsToFillScreen(m_rootLayerImpl.get()
, m_backgroundColor, occlusionTracker); | |
461 } | |
462 | |
463 if (drawFrame) | |
464 occlusionTracker.overdrawMetrics().recordMetrics(this); | |
465 | |
466 removeRenderPasses(CullRenderPassesWithNoQuads(), frame); | |
467 m_renderer->decideRenderPassAllocationsForFrame(frame.renderPasses); | |
468 removeRenderPasses(CullRenderPassesWithCachedTextures(*m_renderer), frame); | |
469 | |
470 return drawFrame; | |
471 } | |
472 | |
473 void CCLayerTreeHostImpl::animateLayersRecursive(CCLayerImpl* current, double mo
notonicTime, double wallClockTime, CCAnimationEventsVector* events, bool& didAni
mate, bool& needsAnimateLayers) | |
474 { | |
475 bool subtreeNeedsAnimateLayers = false; | |
476 | |
477 CCLayerAnimationController* currentController = current->layerAnimationContr
oller(); | |
478 | |
479 bool hadActiveAnimation = currentController->hasActiveAnimation(); | |
480 currentController->animate(monotonicTime, events); | |
481 bool startedAnimation = events->size() > 0; | |
482 | |
483 // We animated if we either ticked a running animation, or started a new ani
mation. | |
484 if (hadActiveAnimation || startedAnimation) | |
485 didAnimate = true; | |
486 | |
487 // If the current controller still has an active animation, we must continue
animating layers. | |
488 if (currentController->hasActiveAnimation()) | |
489 subtreeNeedsAnimateLayers = true; | |
490 | |
491 for (size_t i = 0; i < current->children().size(); ++i) { | |
492 bool childNeedsAnimateLayers = false; | |
493 animateLayersRecursive(current->children()[i], monotonicTime, wallClockT
ime, events, didAnimate, childNeedsAnimateLayers); | |
494 if (childNeedsAnimateLayers) | |
495 subtreeNeedsAnimateLayers = true; | |
496 } | |
497 | |
498 needsAnimateLayers = subtreeNeedsAnimateLayers; | |
499 } | |
500 | |
501 void CCLayerTreeHostImpl::setBackgroundTickingEnabled(bool enabled) | |
502 { | |
503 // Lazily create the timeSource adapter so that we can vary the interval for
testing. | |
504 if (!m_timeSourceClientAdapter) | |
505 m_timeSourceClientAdapter = CCLayerTreeHostImplTimeSourceAdapter::create
(this, CCDelayBasedTimeSource::create(lowFrequencyAnimationInterval(), CCProxy::
currentThread())); | |
506 | |
507 m_timeSourceClientAdapter->setActive(enabled); | |
508 } | |
509 | |
510 IntSize CCLayerTreeHostImpl::contentSize() const | |
511 { | |
512 // TODO(aelias): Hardcoding the first child here is weird. Think of | |
513 // a cleaner way to get the contentBounds on the Impl side. | |
514 if (!m_rootScrollLayerImpl || m_rootScrollLayerImpl->children().isEmpty()) | |
515 return IntSize(); | |
516 return m_rootScrollLayerImpl->children()[0]->contentBounds(); | |
517 } | |
518 | |
519 static inline CCRenderPass* findRenderPassById(CCRenderPass::Id renderPassId, co
nst CCLayerTreeHostImpl::FrameData& frame) | |
520 { | |
521 CCRenderPassIdHashMap::const_iterator it = frame.renderPassesById.find(rende
rPassId); | |
522 ASSERT(it != frame.renderPassesById.end()); | |
523 return it->second; | |
524 } | |
525 | |
526 static void removeRenderPassesRecursive(CCRenderPass::Id removeRenderPassId, CCL
ayerTreeHostImpl::FrameData& frame) | |
527 { | |
528 CCRenderPass* removeRenderPass = findRenderPassById(removeRenderPassId, fram
e); | |
529 CCRenderPassList& renderPasses = frame.renderPasses; | |
530 CCRenderPassList::iterator toRemove = std::find(renderPasses.begin(), render
Passes.end(), removeRenderPass); | |
531 | |
532 // The pass was already removed by another quad - probably the original, and
we are the replica. | |
533 if (toRemove == renderPasses.end()) | |
534 return; | |
535 | |
536 const CCRenderPass* removedPass = *toRemove; | |
537 frame.renderPasses.erase(toRemove); | |
538 | |
539 // Now follow up for all RenderPass quads and remove their RenderPasses recu
rsively. | |
540 const CCQuadList& quadList = removedPass->quadList(); | |
541 CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToFront
Begin(); | |
542 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) { | |
543 CCDrawQuad* currentQuad = (*quadListIterator); | |
544 if (currentQuad->material() != CCDrawQuad::RenderPass) | |
545 continue; | |
546 | |
547 CCRenderPass::Id nextRemoveRenderPassId = CCRenderPassDrawQuad::material
Cast(currentQuad)->renderPassId(); | |
548 removeRenderPassesRecursive(nextRemoveRenderPassId, frame); | |
549 } | |
550 } | |
551 | |
552 bool CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures::shouldRemoveRender
Pass(const CCRenderPassDrawQuad& quad, const FrameData&) const | |
553 { | |
554 return quad.contentsChangedSinceLastFrame().isEmpty() && m_renderer.haveCach
edResourcesForRenderPassId(quad.renderPassId()); | |
555 } | |
556 | |
557 bool CCLayerTreeHostImpl::CullRenderPassesWithNoQuads::shouldRemoveRenderPass(co
nst CCRenderPassDrawQuad& quad, const FrameData& frame) const | |
558 { | |
559 const CCRenderPass* renderPass = findRenderPassById(quad.renderPassId(), fra
me); | |
560 const CCRenderPassList& renderPasses = frame.renderPasses; | |
561 CCRenderPassList::const_iterator foundPass = std::find(renderPasses.begin(),
renderPasses.end(), renderPass); | |
562 | |
563 bool renderPassAlreadyRemoved = foundPass == renderPasses.end(); | |
564 if (renderPassAlreadyRemoved) | |
565 return false; | |
566 | |
567 // If any quad or RenderPass draws into this RenderPass, then keep it. | |
568 const CCQuadList& quadList = (*foundPass)->quadList(); | |
569 for (CCQuadList::constBackToFrontIterator quadListIterator = quadList.backTo
FrontBegin(); quadListIterator != quadList.backToFrontEnd(); ++quadListIterator)
{ | |
570 CCDrawQuad* currentQuad = *quadListIterator; | |
571 | |
572 if (currentQuad->material() != CCDrawQuad::RenderPass) | |
573 return false; | |
574 | |
575 const CCRenderPass* contributingPass = findRenderPassById(CCRenderPassDr
awQuad::materialCast(currentQuad)->renderPassId(), frame); | |
576 CCRenderPassList::const_iterator foundContributingPass = std::find(rende
rPasses.begin(), renderPasses.end(), contributingPass); | |
577 if (foundContributingPass != renderPasses.end()) | |
578 return false; | |
579 } | |
580 return true; | |
581 } | |
582 | |
583 // Defined for linking tests. | |
584 template void CCLayerTreeHostImpl::removeRenderPasses<CCLayerTreeHostImpl::CullR
enderPassesWithCachedTextures>(CullRenderPassesWithCachedTextures, FrameData&); | |
585 template void CCLayerTreeHostImpl::removeRenderPasses<CCLayerTreeHostImpl::CullR
enderPassesWithNoQuads>(CullRenderPassesWithNoQuads, FrameData&); | |
586 | |
587 // static | |
588 template<typename RenderPassCuller> | |
589 void CCLayerTreeHostImpl::removeRenderPasses(RenderPassCuller culler, FrameData&
frame) | |
590 { | |
591 for (size_t it = culler.renderPassListBegin(frame.renderPasses); it != culle
r.renderPassListEnd(frame.renderPasses); it = culler.renderPassListNext(it)) { | |
592 const CCRenderPass* currentPass = frame.renderPasses[it]; | |
593 const CCQuadList& quadList = currentPass->quadList(); | |
594 CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToF
rontBegin(); | |
595 | |
596 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator
) { | |
597 CCDrawQuad* currentQuad = *quadListIterator; | |
598 | |
599 if (currentQuad->material() != CCDrawQuad::RenderPass) | |
600 continue; | |
601 | |
602 CCRenderPassDrawQuad* renderPassQuad = static_cast<CCRenderPassDrawQ
uad*>(currentQuad); | |
603 if (!culler.shouldRemoveRenderPass(*renderPassQuad, frame)) | |
604 continue; | |
605 | |
606 // We are changing the vector in the middle of iteration. Because we | |
607 // delete render passes that draw into the current pass, we are | |
608 // guaranteed that any data from the iterator to the end will not | |
609 // change. So, capture the iterator position from the end of the | |
610 // list, and restore it after the change. | |
611 int positionFromEnd = frame.renderPasses.size() - it; | |
612 removeRenderPassesRecursive(renderPassQuad->renderPassId(), frame); | |
613 it = frame.renderPasses.size() - positionFromEnd; | |
614 ASSERT(it >= 0); | |
615 } | |
616 } | |
617 } | |
618 | |
619 bool CCLayerTreeHostImpl::prepareToDraw(FrameData& frame) | |
620 { | |
621 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::prepareToDraw"); | |
622 ASSERT(canDraw()); | |
623 | |
624 frame.renderSurfaceLayerList = &m_renderSurfaceLayerList; | |
625 frame.renderPasses.clear(); | |
626 frame.renderPassesById.clear(); | |
627 frame.renderSurfaceLayerList->clear(); | |
628 frame.willDrawLayers.clear(); | |
629 | |
630 if (!calculateRenderPasses(frame)) | |
631 return false; | |
632 | |
633 // If we return true, then we expect drawLayers() to be called before this f
unction is called again. | |
634 return true; | |
635 } | |
636 | |
637 void CCLayerTreeHostImpl::releaseContentsTextures() | |
638 { | |
639 if (m_contentsTexturesPurged) | |
640 return; | |
641 m_client->releaseContentsTexturesOnImplThread(); | |
642 setContentsTexturesPurged(); | |
643 m_client->setNeedsCommitOnImplThread(); | |
644 m_client->onCanDrawStateChanged(canDraw()); | |
645 } | |
646 | |
647 void CCLayerTreeHostImpl::setMemoryAllocationLimitBytes(size_t bytes) | |
648 { | |
649 if (m_memoryAllocationLimitBytes == bytes) | |
650 return; | |
651 m_memoryAllocationLimitBytes = bytes; | |
652 | |
653 ASSERT(bytes); | |
654 m_client->setNeedsCommitOnImplThread(); | |
655 } | |
656 | |
657 void CCLayerTreeHostImpl::onVSyncParametersChanged(double monotonicTimebase, dou
ble intervalInSeconds) | |
658 { | |
659 m_client->onVSyncParametersChanged(monotonicTimebase, intervalInSeconds); | |
660 } | |
661 | |
662 void CCLayerTreeHostImpl::drawLayers(const FrameData& frame) | |
663 { | |
664 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::drawLayers"); | |
665 ASSERT(canDraw()); | |
666 ASSERT(!frame.renderPasses.empty()); | |
667 | |
668 // FIXME: use the frame begin time from the overall compositor scheduler. | |
669 // This value is currently inaccessible because it is up in Chromium's | |
670 // RenderWidget. | |
671 m_fpsCounter->markBeginningOfFrame(currentTime()); | |
672 | |
673 if (m_settings.showDebugRects()) | |
674 m_debugRectHistory->saveDebugRectsForCurrentFrame(m_rootLayerImpl.get(),
*frame.renderSurfaceLayerList, frame.occludingScreenSpaceRects, settings()); | |
675 | |
676 // Because the contents of the HUD depend on everything else in the frame, t
he contents | |
677 // of its texture are updated as the last thing before the frame is drawn. | |
678 if (m_hudLayerImpl) | |
679 m_hudLayerImpl->updateHudTexture(m_resourceProvider.get()); | |
680 | |
681 m_renderer->drawFrame(frame.renderPasses, frame.renderPassesById); | |
682 | |
683 // Once a RenderPass has been drawn, its damage should be cleared in | |
684 // case the RenderPass will be reused next frame. | |
685 for (unsigned int i = 0; i < frame.renderPasses.size(); i++) | |
686 frame.renderPasses[i]->setDamageRect(FloatRect()); | |
687 | |
688 // The next frame should start by assuming nothing has changed, and changes
are noted as they occur. | |
689 for (unsigned int i = 0; i < frame.renderSurfaceLayerList->size(); i++) | |
690 (*frame.renderSurfaceLayerList)[i]->renderSurface()->damageTracker()->di
dDrawDamagedArea(); | |
691 m_rootLayerImpl->resetAllChangeTrackingForSubtree(); | |
692 } | |
693 | |
694 void CCLayerTreeHostImpl::didDrawAllLayers(const FrameData& frame) | |
695 { | |
696 for (size_t i = 0; i < frame.willDrawLayers.size(); ++i) | |
697 frame.willDrawLayers[i]->didDraw(m_resourceProvider.get()); | |
698 | |
699 // Once all layers have been drawn, pending texture uploads should no | |
700 // longer block future uploads. | |
701 m_resourceProvider->textureUploader()->markPendingUploadsAsNonBlocking(); | |
702 } | |
703 | |
704 void CCLayerTreeHostImpl::finishAllRendering() | |
705 { | |
706 if (m_renderer) | |
707 m_renderer->finish(); | |
708 } | |
709 | |
710 bool CCLayerTreeHostImpl::isContextLost() | |
711 { | |
712 return m_renderer && m_renderer->isContextLost(); | |
713 } | |
714 | |
715 const RendererCapabilities& CCLayerTreeHostImpl::rendererCapabilities() const | |
716 { | |
717 return m_renderer->capabilities(); | |
718 } | |
719 | |
720 bool CCLayerTreeHostImpl::swapBuffers() | |
721 { | |
722 ASSERT(m_renderer); | |
723 | |
724 m_fpsCounter->markEndOfFrame(); | |
725 return m_renderer->swapBuffers(); | |
726 } | |
727 | |
728 const IntSize& CCLayerTreeHostImpl::deviceViewportSize() const | |
729 { | |
730 return m_deviceViewportSize; | |
731 } | |
732 | |
733 const CCLayerTreeSettings& CCLayerTreeHostImpl::settings() const | |
734 { | |
735 return m_settings; | |
736 } | |
737 | |
738 void CCLayerTreeHostImpl::didLoseContext() | |
739 { | |
740 m_client->didLoseContextOnImplThread(); | |
741 } | |
742 | |
743 void CCLayerTreeHostImpl::onSwapBuffersComplete() | |
744 { | |
745 m_client->onSwapBuffersCompleteOnImplThread(); | |
746 } | |
747 | |
748 void CCLayerTreeHostImpl::readback(void* pixels, const IntRect& rect) | |
749 { | |
750 ASSERT(m_renderer); | |
751 m_renderer->getFramebufferPixels(pixels, rect); | |
752 } | |
753 | |
754 static CCLayerImpl* findRootScrollLayer(CCLayerImpl* layer) | |
755 { | |
756 if (!layer) | |
757 return 0; | |
758 | |
759 if (layer->scrollable()) | |
760 return layer; | |
761 | |
762 for (size_t i = 0; i < layer->children().size(); ++i) { | |
763 CCLayerImpl* found = findRootScrollLayer(layer->children()[i]); | |
764 if (found) | |
765 return found; | |
766 } | |
767 | |
768 return 0; | |
769 } | |
770 | |
771 // Content layers can be either directly scrollable or contained in an outer | |
772 // scrolling layer which applies the scroll transform. Given a content layer, | |
773 // this function returns the associated scroll layer if any. | |
774 static CCLayerImpl* findScrollLayerForContentLayer(CCLayerImpl* layerImpl) | |
775 { | |
776 if (!layerImpl) | |
777 return 0; | |
778 | |
779 if (layerImpl->scrollable()) | |
780 return layerImpl; | |
781 | |
782 if (layerImpl->drawsContent() && layerImpl->parent() && layerImpl->parent()-
>scrollable()) | |
783 return layerImpl->parent(); | |
784 | |
785 return 0; | |
786 } | |
787 | |
788 void CCLayerTreeHostImpl::setRootLayer(scoped_ptr<CCLayerImpl> layer) | |
789 { | |
790 m_rootLayerImpl = layer.Pass(); | |
791 m_rootScrollLayerImpl = findRootScrollLayer(m_rootLayerImpl.get()); | |
792 m_currentlyScrollingLayerImpl = 0; | |
793 | |
794 if (m_rootLayerImpl && m_scrollingLayerIdFromPreviousTree != -1) | |
795 m_currentlyScrollingLayerImpl = CCLayerTreeHostCommon::findLayerInSubtre
e(m_rootLayerImpl.get(), m_scrollingLayerIdFromPreviousTree); | |
796 | |
797 m_scrollingLayerIdFromPreviousTree = -1; | |
798 | |
799 m_client->onCanDrawStateChanged(canDraw()); | |
800 } | |
801 | |
802 scoped_ptr<CCLayerImpl> CCLayerTreeHostImpl::detachLayerTree() | |
803 { | |
804 // Clear all data structures that have direct references to the layer tree. | |
805 m_scrollingLayerIdFromPreviousTree = m_currentlyScrollingLayerImpl ? m_curre
ntlyScrollingLayerImpl->id() : -1; | |
806 m_currentlyScrollingLayerImpl = 0; | |
807 m_renderSurfaceLayerList.clear(); | |
808 | |
809 return m_rootLayerImpl.Pass(); | |
810 } | |
811 | |
812 void CCLayerTreeHostImpl::setVisible(bool visible) | |
813 { | |
814 ASSERT(CCProxy::isImplThread()); | |
815 | |
816 if (m_visible == visible) | |
817 return; | |
818 m_visible = visible; | |
819 didVisibilityChange(this, m_visible); | |
820 | |
821 if (!m_renderer) | |
822 return; | |
823 | |
824 m_renderer->setVisible(visible); | |
825 | |
826 setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers); | |
827 } | |
828 | |
829 bool CCLayerTreeHostImpl::initializeRenderer(scoped_ptr<CCGraphicsContext> conte
xt) | |
830 { | |
831 // Since we will create a new resource provider, we cannot continue to use | |
832 // the old resources (i.e. renderSurfaces and texture IDs). Clear them | |
833 // before we destroy the old resource provider. | |
834 if (m_rootLayerImpl) { | |
835 clearRenderSurfaces(); | |
836 sendDidLoseContextRecursive(m_rootLayerImpl.get()); | |
837 } | |
838 // Note: order is important here. | |
839 m_renderer.clear(); | |
840 m_resourceProvider.clear(); | |
841 m_context.reset(); | |
842 | |
843 if (!context->bindToClient(this)) | |
844 return false; | |
845 | |
846 OwnPtr<CCResourceProvider> resourceProvider = CCResourceProvider::create(con
text.get()); | |
847 if (!resourceProvider) | |
848 return false; | |
849 | |
850 if (context->context3D()) | |
851 m_renderer = CCRendererGL::create(this, resourceProvider.get()); | |
852 else if (context->softwareDevice()) | |
853 m_renderer = CCRendererSoftware::create(this, resourceProvider.get(), co
ntext->softwareDevice()); | |
854 if (!m_renderer) | |
855 return false; | |
856 | |
857 m_resourceProvider = resourceProvider.release(); | |
858 m_context = context.Pass(); | |
859 | |
860 if (!m_visible) | |
861 m_renderer->setVisible(m_visible); | |
862 | |
863 m_client->onCanDrawStateChanged(canDraw()); | |
864 | |
865 return true; | |
866 } | |
867 | |
868 void CCLayerTreeHostImpl::setContentsTexturesPurged() | |
869 { | |
870 m_contentsTexturesPurged = true; | |
871 m_client->onCanDrawStateChanged(canDraw()); | |
872 } | |
873 | |
874 void CCLayerTreeHostImpl::resetContentsTexturesPurged() | |
875 { | |
876 m_contentsTexturesPurged = false; | |
877 m_client->onCanDrawStateChanged(canDraw()); | |
878 } | |
879 | |
880 void CCLayerTreeHostImpl::setViewportSize(const IntSize& layoutViewportSize, con
st IntSize& deviceViewportSize) | |
881 { | |
882 if (layoutViewportSize == m_layoutViewportSize && deviceViewportSize == m_de
viceViewportSize) | |
883 return; | |
884 | |
885 m_layoutViewportSize = layoutViewportSize; | |
886 m_deviceViewportSize = deviceViewportSize; | |
887 | |
888 m_pinchZoomViewport.setLayoutViewportSize(FloatSize(layoutViewportSize)); | |
889 | |
890 updateMaxScrollPosition(); | |
891 | |
892 if (m_renderer) | |
893 m_renderer->viewportChanged(); | |
894 | |
895 m_client->onCanDrawStateChanged(canDraw()); | |
896 } | |
897 | |
898 static void adjustScrollsForPageScaleChange(CCLayerImpl* layerImpl, float pageSc
aleChange) | |
899 { | |
900 if (!layerImpl) | |
901 return; | |
902 | |
903 if (layerImpl->scrollable()) { | |
904 // We need to convert impl-side scroll deltas to pageScale space. | |
905 FloatSize scrollDelta = layerImpl->scrollDelta(); | |
906 scrollDelta.scale(pageScaleChange); | |
907 layerImpl->setScrollDelta(scrollDelta); | |
908 } | |
909 | |
910 for (size_t i = 0; i < layerImpl->children().size(); ++i) | |
911 adjustScrollsForPageScaleChange(layerImpl->children()[i], pageScaleChang
e); | |
912 } | |
913 | |
914 void CCLayerTreeHostImpl::setDeviceScaleFactor(float deviceScaleFactor) | |
915 { | |
916 if (deviceScaleFactor == m_deviceScaleFactor) | |
917 return; | |
918 m_deviceScaleFactor = deviceScaleFactor; | |
919 | |
920 updateMaxScrollPosition(); | |
921 } | |
922 | |
923 float CCLayerTreeHostImpl::pageScaleFactor() const | |
924 { | |
925 return m_pinchZoomViewport.pageScaleFactor(); | |
926 } | |
927 | |
928 void CCLayerTreeHostImpl::setPageScaleFactorAndLimits(float pageScaleFactor, flo
at minPageScaleFactor, float maxPageScaleFactor) | |
929 { | |
930 if (!pageScaleFactor) | |
931 return; | |
932 | |
933 float pageScaleChange = pageScaleFactor / m_pinchZoomViewport.pageScaleFacto
r(); | |
934 m_pinchZoomViewport.setPageScaleFactorAndLimits(pageScaleFactor, minPageScal
eFactor, maxPageScaleFactor); | |
935 | |
936 if (!CCSettings::pageScalePinchZoomEnabled()) { | |
937 if (pageScaleChange != 1) | |
938 adjustScrollsForPageScaleChange(m_rootScrollLayerImpl, pageScaleChan
ge); | |
939 } | |
940 | |
941 // Clamp delta to limits and refresh display matrix. | |
942 setPageScaleDelta(m_pinchZoomViewport.pageScaleDelta() / m_pinchZoomViewport
.sentPageScaleDelta()); | |
943 m_pinchZoomViewport.setSentPageScaleDelta(1); | |
944 } | |
945 | |
946 void CCLayerTreeHostImpl::setPageScaleDelta(float delta) | |
947 { | |
948 m_pinchZoomViewport.setPageScaleDelta(delta); | |
949 | |
950 updateMaxScrollPosition(); | |
951 } | |
952 | |
953 void CCLayerTreeHostImpl::updateMaxScrollPosition() | |
954 { | |
955 if (!m_rootScrollLayerImpl || !m_rootScrollLayerImpl->children().size()) | |
956 return; | |
957 | |
958 FloatSize viewBounds = m_deviceViewportSize; | |
959 if (CCLayerImpl* clipLayer = m_rootScrollLayerImpl->parent()) { | |
960 // Compensate for non-overlay scrollbars. | |
961 if (clipLayer->masksToBounds()) { | |
962 viewBounds = clipLayer->bounds(); | |
963 viewBounds.scale(m_deviceScaleFactor); | |
964 } | |
965 } | |
966 | |
967 IntSize contentBounds = contentSize(); | |
968 if (CCSettings::pageScalePinchZoomEnabled()) { | |
969 // Pinch with pageScale scrolls entirely in layout space. contentSize | |
970 // returns the bounds including the page scale factor, so calculate the | |
971 // pre page-scale layout size here. | |
972 float pageScaleFactor = m_pinchZoomViewport.pageScaleFactor(); | |
973 contentBounds.setWidth(contentBounds.width() / pageScaleFactor); | |
974 contentBounds.setHeight(contentBounds.height() / pageScaleFactor); | |
975 } else { | |
976 viewBounds.scale(1 / m_pinchZoomViewport.pageScaleDelta()); | |
977 } | |
978 | |
979 IntSize maxScroll = contentBounds - expandedIntSize(viewBounds); | |
980 maxScroll.scale(1 / m_deviceScaleFactor); | |
981 | |
982 // The viewport may be larger than the contents in some cases, such as | |
983 // having a vertical scrollbar but no horizontal overflow. | |
984 maxScroll.clampNegativeToZero(); | |
985 | |
986 m_rootScrollLayerImpl->setMaxScrollPosition(maxScroll); | |
987 } | |
988 | |
989 void CCLayerTreeHostImpl::setNeedsRedraw() | |
990 { | |
991 m_client->setNeedsRedrawOnImplThread(); | |
992 } | |
993 | |
994 bool CCLayerTreeHostImpl::ensureRenderSurfaceLayerList() | |
995 { | |
996 if (!m_rootLayerImpl) | |
997 return false; | |
998 if (!m_renderer) | |
999 return false; | |
1000 | |
1001 // We need both a non-empty render surface layer list and a root render | |
1002 // surface to be able to iterate over the visible layers. | |
1003 if (m_renderSurfaceLayerList.size() && m_rootLayerImpl->renderSurface()) | |
1004 return true; | |
1005 | |
1006 // If we are called after setRootLayer() but before prepareToDraw(), we need | |
1007 // to recalculate the visible layers. This prevents being unable to scroll | |
1008 // during part of a commit. | |
1009 m_renderSurfaceLayerList.clear(); | |
1010 calculateRenderSurfaceLayerList(m_renderSurfaceLayerList); | |
1011 | |
1012 return m_renderSurfaceLayerList.size(); | |
1013 } | |
1014 | |
1015 CCInputHandlerClient::ScrollStatus CCLayerTreeHostImpl::scrollBegin(const IntPoi
nt& viewportPoint, CCInputHandlerClient::ScrollInputType type) | |
1016 { | |
1017 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::scrollBegin"); | |
1018 | |
1019 ASSERT(!m_currentlyScrollingLayerImpl); | |
1020 clearCurrentlyScrollingLayer(); | |
1021 | |
1022 if (!ensureRenderSurfaceLayerList()) | |
1023 return ScrollIgnored; | |
1024 | |
1025 IntPoint deviceViewportPoint = viewportPoint; | |
1026 deviceViewportPoint.scale(m_deviceScaleFactor, m_deviceScaleFactor); | |
1027 | |
1028 // First find out which layer was hit from the saved list of visible layers | |
1029 // in the most recent frame. | |
1030 CCLayerImpl* layerImpl = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(vi
ewportPoint, m_renderSurfaceLayerList); | |
1031 | |
1032 // Walk up the hierarchy and look for a scrollable layer. | |
1033 CCLayerImpl* potentiallyScrollingLayerImpl = 0; | |
1034 for (; layerImpl; layerImpl = layerImpl->parent()) { | |
1035 // The content layer can also block attempts to scroll outside the main
thread. | |
1036 if (layerImpl->tryScroll(deviceViewportPoint, type) == ScrollOnMainThrea
d) { | |
1037 m_numMainThreadScrolls++; | |
1038 return ScrollOnMainThread; | |
1039 } | |
1040 | |
1041 CCLayerImpl* scrollLayerImpl = findScrollLayerForContentLayer(layerImpl)
; | |
1042 if (!scrollLayerImpl) | |
1043 continue; | |
1044 | |
1045 ScrollStatus status = scrollLayerImpl->tryScroll(viewportPoint, type); | |
1046 | |
1047 // If any layer wants to divert the scroll event to the main thread, abo
rt. | |
1048 if (status == ScrollOnMainThread) { | |
1049 m_numMainThreadScrolls++; | |
1050 return ScrollOnMainThread; | |
1051 } | |
1052 | |
1053 if (status == ScrollStarted && !potentiallyScrollingLayerImpl) | |
1054 potentiallyScrollingLayerImpl = scrollLayerImpl; | |
1055 } | |
1056 | |
1057 if (potentiallyScrollingLayerImpl) { | |
1058 m_currentlyScrollingLayerImpl = potentiallyScrollingLayerImpl; | |
1059 // Gesture events need to be transformed from screen coordinates to loca
l layer coordinates | |
1060 // so that the scrolling contents exactly follow the user's finger. In c
ontrast, wheel | |
1061 // events are already in local layer coordinates so we can just apply th
em directly. | |
1062 m_scrollDeltaIsInScreenSpace = (type == Gesture); | |
1063 m_numImplThreadScrolls++; | |
1064 return ScrollStarted; | |
1065 } | |
1066 return ScrollIgnored; | |
1067 } | |
1068 | |
1069 static FloatSize scrollLayerWithScreenSpaceDelta(CCPinchZoomViewport* viewport,
CCLayerImpl& layerImpl, const FloatPoint& screenSpacePoint, const FloatSize& scr
eenSpaceDelta) | |
1070 { | |
1071 // Layers with non-invertible screen space transforms should not have passed
the scroll hit | |
1072 // test in the first place. | |
1073 ASSERT(layerImpl.screenSpaceTransform().isInvertible()); | |
1074 WebTransformationMatrix inverseScreenSpaceTransform = layerImpl.screenSpaceT
ransform().inverse(); | |
1075 | |
1076 // First project the scroll start and end points to local layer space to fin
d the scroll delta | |
1077 // in layer coordinates. | |
1078 bool startClipped, endClipped; | |
1079 FloatPoint screenSpaceEndPoint = screenSpacePoint + screenSpaceDelta; | |
1080 FloatPoint localStartPoint = CCMathUtil::projectPoint(inverseScreenSpaceTran
sform, screenSpacePoint, startClipped); | |
1081 FloatPoint localEndPoint = CCMathUtil::projectPoint(inverseScreenSpaceTransf
orm, screenSpaceEndPoint, endClipped); | |
1082 | |
1083 // In general scroll point coordinates should not get clipped. | |
1084 ASSERT(!startClipped); | |
1085 ASSERT(!endClipped); | |
1086 if (startClipped || endClipped) | |
1087 return FloatSize(); | |
1088 | |
1089 // Apply the scroll delta. | |
1090 FloatSize previousDelta(layerImpl.scrollDelta()); | |
1091 FloatSize unscrolled = layerImpl.scrollBy(localEndPoint - localStartPoint); | |
1092 | |
1093 if (viewport) | |
1094 viewport->applyScroll(unscrolled); | |
1095 | |
1096 // Calculate the applied scroll delta in screen space coordinates. | |
1097 FloatPoint actualLocalEndPoint = localStartPoint + layerImpl.scrollDelta() -
previousDelta; | |
1098 FloatPoint actualScreenSpaceEndPoint = CCMathUtil::mapPoint(layerImpl.screen
SpaceTransform(), actualLocalEndPoint, endClipped); | |
1099 ASSERT(!endClipped); | |
1100 if (endClipped) | |
1101 return FloatSize(); | |
1102 return actualScreenSpaceEndPoint - screenSpacePoint; | |
1103 } | |
1104 | |
1105 static FloatSize scrollLayerWithLocalDelta(CCLayerImpl& layerImpl, const FloatSi
ze& localDelta) | |
1106 { | |
1107 FloatSize previousDelta(layerImpl.scrollDelta()); | |
1108 layerImpl.scrollBy(localDelta); | |
1109 return layerImpl.scrollDelta() - previousDelta; | |
1110 } | |
1111 | |
1112 void CCLayerTreeHostImpl::scrollBy(const IntPoint& viewportPoint, const IntSize&
scrollDelta) | |
1113 { | |
1114 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::scrollBy"); | |
1115 if (!m_currentlyScrollingLayerImpl) | |
1116 return; | |
1117 | |
1118 FloatSize pendingDelta(scrollDelta); | |
1119 | |
1120 pendingDelta.scale(m_deviceScaleFactor); | |
1121 | |
1122 for (CCLayerImpl* layerImpl = m_currentlyScrollingLayerImpl; layerImpl; laye
rImpl = layerImpl->parent()) { | |
1123 if (!layerImpl->scrollable()) | |
1124 continue; | |
1125 | |
1126 CCPinchZoomViewport* viewport = layerImpl == m_rootScrollLayerImpl ? &m_
pinchZoomViewport : 0; | |
1127 FloatSize appliedDelta; | |
1128 if (m_scrollDeltaIsInScreenSpace) | |
1129 appliedDelta = scrollLayerWithScreenSpaceDelta(viewport, *layerImpl,
viewportPoint, pendingDelta); | |
1130 else | |
1131 appliedDelta = scrollLayerWithLocalDelta(*layerImpl, pendingDelta); | |
1132 | |
1133 // If the layer wasn't able to move, try the next one in the hierarchy. | |
1134 float moveThresholdSquared = 0.1f * 0.1f; | |
1135 if (appliedDelta.diagonalLengthSquared() < moveThresholdSquared) | |
1136 continue; | |
1137 | |
1138 // If the applied delta is within 45 degrees of the input delta, bail ou
t to make it easier | |
1139 // to scroll just one layer in one direction without affecting any of it
s parents. | |
1140 float angleThreshold = 45; | |
1141 if (CCMathUtil::smallestAngleBetweenVectors(appliedDelta, pendingDelta)
< angleThreshold) { | |
1142 pendingDelta = FloatSize(); | |
1143 break; | |
1144 } | |
1145 | |
1146 // Allow further movement only on an axis perpendicular to the direction
in which the layer | |
1147 // moved. | |
1148 FloatSize perpendicularAxis(-appliedDelta.height(), appliedDelta.width()
); | |
1149 pendingDelta = CCMathUtil::projectVector(pendingDelta, perpendicularAxis
); | |
1150 | |
1151 if (flooredIntSize(pendingDelta).isZero()) | |
1152 break; | |
1153 } | |
1154 | |
1155 if (!scrollDelta.isZero() && flooredIntSize(pendingDelta).isEmpty()) { | |
1156 m_client->setNeedsCommitOnImplThread(); | |
1157 m_client->setNeedsRedrawOnImplThread(); | |
1158 } | |
1159 } | |
1160 | |
1161 void CCLayerTreeHostImpl::clearCurrentlyScrollingLayer() | |
1162 { | |
1163 m_currentlyScrollingLayerImpl = 0; | |
1164 m_scrollingLayerIdFromPreviousTree = -1; | |
1165 } | |
1166 | |
1167 void CCLayerTreeHostImpl::scrollEnd() | |
1168 { | |
1169 clearCurrentlyScrollingLayer(); | |
1170 } | |
1171 | |
1172 void CCLayerTreeHostImpl::pinchGestureBegin() | |
1173 { | |
1174 m_pinchGestureActive = true; | |
1175 m_previousPinchAnchor = IntPoint(); | |
1176 | |
1177 if (m_rootScrollLayerImpl && m_rootScrollLayerImpl->scrollbarAnimationContro
ller()) | |
1178 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureBe
gin(); | |
1179 } | |
1180 | |
1181 void CCLayerTreeHostImpl::pinchGestureUpdate(float magnifyDelta, | |
1182 const IntPoint& anchor) | |
1183 { | |
1184 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::pinchGestureUpdate"); | |
1185 | |
1186 if (!m_rootScrollLayerImpl) | |
1187 return; | |
1188 | |
1189 if (m_previousPinchAnchor == IntPoint::zero()) | |
1190 m_previousPinchAnchor = anchor; | |
1191 | |
1192 // Keep the center-of-pinch anchor specified by (x, y) in a stable | |
1193 // position over the course of the magnify. | |
1194 float pageScaleDelta = m_pinchZoomViewport.pageScaleDelta(); | |
1195 FloatPoint previousScaleAnchor(m_previousPinchAnchor.x() / pageScaleDelta, | |
1196 m_previousPinchAnchor.y() / pageScaleDelta); | |
1197 setPageScaleDelta(pageScaleDelta * magnifyDelta); | |
1198 pageScaleDelta = m_pinchZoomViewport.pageScaleDelta(); | |
1199 FloatPoint newScaleAnchor(anchor.x() / pageScaleDelta, anchor.y() / pageScal
eDelta); | |
1200 FloatSize move = previousScaleAnchor - newScaleAnchor; | |
1201 | |
1202 m_previousPinchAnchor = anchor; | |
1203 | |
1204 if (CCSettings::pageScalePinchZoomEnabled()) { | |
1205 // Compute the application of the delta with respect to the current page
zoom of the page. | |
1206 move.scale(1 / (m_pinchZoomViewport.pageScaleFactor() * m_deviceScaleFac
tor)); | |
1207 } | |
1208 | |
1209 FloatSize scrollOverflow = CCSettings::pageScalePinchZoomEnabled() ? m_pinch
ZoomViewport.applyScroll(move) : move; | |
1210 m_rootScrollLayerImpl->scrollBy(roundedIntSize(scrollOverflow)); | |
1211 | |
1212 if (m_rootScrollLayerImpl->scrollbarAnimationController()) | |
1213 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureUp
date(); | |
1214 | |
1215 m_client->setNeedsCommitOnImplThread(); | |
1216 m_client->setNeedsRedrawOnImplThread(); | |
1217 } | |
1218 | |
1219 void CCLayerTreeHostImpl::pinchGestureEnd() | |
1220 { | |
1221 m_pinchGestureActive = false; | |
1222 | |
1223 if (m_rootScrollLayerImpl && m_rootScrollLayerImpl->scrollbarAnimationContro
ller()) | |
1224 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureEn
d(); | |
1225 | |
1226 m_client->setNeedsCommitOnImplThread(); | |
1227 } | |
1228 | |
1229 void CCLayerTreeHostImpl::computeDoubleTapZoomDeltas(CCScrollAndScaleSet* scroll
Info) | |
1230 { | |
1231 float pageScale = m_pageScaleAnimation->finalPageScale(); | |
1232 IntSize scrollOffset = m_pageScaleAnimation->finalScrollOffset(); | |
1233 scrollOffset.scale(m_pinchZoomViewport.pageScaleFactor() / pageScale); | |
1234 makeScrollAndScaleSet(scrollInfo, scrollOffset, pageScale); | |
1235 } | |
1236 | |
1237 void CCLayerTreeHostImpl::computePinchZoomDeltas(CCScrollAndScaleSet* scrollInfo
) | |
1238 { | |
1239 if (!m_rootScrollLayerImpl) | |
1240 return; | |
1241 | |
1242 // Only send fake scroll/zoom deltas if we're pinch zooming out by a | |
1243 // significant amount. This also ensures only one fake delta set will be | |
1244 // sent. | |
1245 const float pinchZoomOutSensitivity = 0.95f; | |
1246 if (m_pinchZoomViewport.pageScaleDelta() > pinchZoomOutSensitivity) | |
1247 return; | |
1248 | |
1249 // Compute where the scroll offset/page scale would be if fully pinch-zoomed | |
1250 // out from the anchor point. | |
1251 IntSize scrollBegin = flooredIntSize(m_rootScrollLayerImpl->scrollPosition()
+ m_rootScrollLayerImpl->scrollDelta()); | |
1252 scrollBegin.scale(m_pinchZoomViewport.pageScaleDelta()); | |
1253 float scaleBegin = m_pinchZoomViewport.totalPageScaleFactor(); | |
1254 float pageScaleDeltaToSend = m_pinchZoomViewport.minPageScaleFactor() / m_pi
nchZoomViewport.pageScaleFactor(); | |
1255 FloatSize scaledContentsSize = contentSize(); | |
1256 scaledContentsSize.scale(pageScaleDeltaToSend); | |
1257 | |
1258 FloatSize anchor = toSize(m_previousPinchAnchor); | |
1259 FloatSize scrollEnd = scrollBegin + anchor; | |
1260 scrollEnd.scale(m_pinchZoomViewport.minPageScaleFactor() / scaleBegin); | |
1261 scrollEnd -= anchor; | |
1262 scrollEnd = scrollEnd.shrunkTo(roundedIntSize(scaledContentsSize - m_deviceV
iewportSize)).expandedTo(FloatSize(0, 0)); | |
1263 scrollEnd.scale(1 / pageScaleDeltaToSend); | |
1264 scrollEnd.scale(m_deviceScaleFactor); | |
1265 | |
1266 makeScrollAndScaleSet(scrollInfo, roundedIntSize(scrollEnd), m_pinchZoomView
port.minPageScaleFactor()); | |
1267 } | |
1268 | |
1269 void CCLayerTreeHostImpl::makeScrollAndScaleSet(CCScrollAndScaleSet* scrollInfo,
const IntSize& scrollOffset, float pageScale) | |
1270 { | |
1271 if (!m_rootScrollLayerImpl) | |
1272 return; | |
1273 | |
1274 CCLayerTreeHostCommon::ScrollUpdateInfo scroll; | |
1275 scroll.layerId = m_rootScrollLayerImpl->id(); | |
1276 scroll.scrollDelta = scrollOffset - toSize(m_rootScrollLayerImpl->scrollPosi
tion()); | |
1277 scrollInfo->scrolls.append(scroll); | |
1278 m_rootScrollLayerImpl->setSentScrollDelta(scroll.scrollDelta); | |
1279 scrollInfo->pageScaleDelta = pageScale / m_pinchZoomViewport.pageScaleFactor
(); | |
1280 m_pinchZoomViewport.setSentPageScaleDelta(scrollInfo->pageScaleDelta); | |
1281 } | |
1282 | |
1283 static void collectScrollDeltas(CCScrollAndScaleSet* scrollInfo, CCLayerImpl* la
yerImpl) | |
1284 { | |
1285 if (!layerImpl) | |
1286 return; | |
1287 | |
1288 if (!layerImpl->scrollDelta().isZero()) { | |
1289 IntSize scrollDelta = flooredIntSize(layerImpl->scrollDelta()); | |
1290 CCLayerTreeHostCommon::ScrollUpdateInfo scroll; | |
1291 scroll.layerId = layerImpl->id(); | |
1292 scroll.scrollDelta = scrollDelta; | |
1293 scrollInfo->scrolls.append(scroll); | |
1294 layerImpl->setSentScrollDelta(scrollDelta); | |
1295 } | |
1296 | |
1297 for (size_t i = 0; i < layerImpl->children().size(); ++i) | |
1298 collectScrollDeltas(scrollInfo, layerImpl->children()[i]); | |
1299 } | |
1300 | |
1301 scoped_ptr<CCScrollAndScaleSet> CCLayerTreeHostImpl::processScrollDeltas() | |
1302 { | |
1303 scoped_ptr<CCScrollAndScaleSet> scrollInfo(new CCScrollAndScaleSet()); | |
1304 | |
1305 if (m_pinchGestureActive || m_pageScaleAnimation) { | |
1306 scrollInfo->pageScaleDelta = 1; | |
1307 m_pinchZoomViewport.setSentPageScaleDelta(1); | |
1308 // FIXME(aelias): Make these painting optimizations compatible with | |
1309 // compositor-side scaling. | |
1310 if (!CCSettings::pageScalePinchZoomEnabled()) { | |
1311 if (m_pinchGestureActive) | |
1312 computePinchZoomDeltas(scrollInfo.get()); | |
1313 else if (m_pageScaleAnimation.get()) | |
1314 computeDoubleTapZoomDeltas(scrollInfo.get()); | |
1315 } | |
1316 return scrollInfo.Pass(); | |
1317 } | |
1318 | |
1319 collectScrollDeltas(scrollInfo.get(), m_rootLayerImpl.get()); | |
1320 scrollInfo->pageScaleDelta = m_pinchZoomViewport.pageScaleDelta(); | |
1321 m_pinchZoomViewport.setSentPageScaleDelta(scrollInfo->pageScaleDelta); | |
1322 | |
1323 return scrollInfo.Pass(); | |
1324 } | |
1325 | |
1326 WebTransformationMatrix CCLayerTreeHostImpl::implTransform() const | |
1327 { | |
1328 return m_pinchZoomViewport.implTransform(); | |
1329 } | |
1330 | |
1331 void CCLayerTreeHostImpl::setFullRootLayerDamage() | |
1332 { | |
1333 if (m_rootLayerImpl) { | |
1334 CCRenderSurface* renderSurface = m_rootLayerImpl->renderSurface(); | |
1335 if (renderSurface) | |
1336 renderSurface->damageTracker()->forceFullDamageNextUpdate(); | |
1337 } | |
1338 } | |
1339 | |
1340 void CCLayerTreeHostImpl::animatePageScale(double monotonicTime) | |
1341 { | |
1342 if (!m_pageScaleAnimation || !m_rootScrollLayerImpl) | |
1343 return; | |
1344 | |
1345 IntSize scrollTotal = flooredIntSize(m_rootScrollLayerImpl->scrollPosition()
+ m_rootScrollLayerImpl->scrollDelta()); | |
1346 | |
1347 setPageScaleDelta(m_pageScaleAnimation->pageScaleAtTime(monotonicTime) / m_p
inchZoomViewport.pageScaleFactor()); | |
1348 IntSize nextScroll = m_pageScaleAnimation->scrollOffsetAtTime(monotonicTime)
; | |
1349 nextScroll.scale(1 / m_pinchZoomViewport.pageScaleDelta()); | |
1350 m_rootScrollLayerImpl->scrollBy(nextScroll - scrollTotal); | |
1351 m_client->setNeedsRedrawOnImplThread(); | |
1352 | |
1353 if (m_pageScaleAnimation->isAnimationCompleteAtTime(monotonicTime)) { | |
1354 m_pageScaleAnimation.clear(); | |
1355 m_client->setNeedsCommitOnImplThread(); | |
1356 } | |
1357 } | |
1358 | |
1359 void CCLayerTreeHostImpl::animateLayers(double monotonicTime, double wallClockTi
me) | |
1360 { | |
1361 if (!CCSettings::acceleratedAnimationEnabled() || !m_needsAnimateLayers || !
m_rootLayerImpl) | |
1362 return; | |
1363 | |
1364 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::animateLayers"); | |
1365 | |
1366 scoped_ptr<CCAnimationEventsVector> events(make_scoped_ptr(new CCAnimationEv
entsVector)); | |
1367 | |
1368 bool didAnimate = false; | |
1369 animateLayersRecursive(m_rootLayerImpl.get(), monotonicTime, wallClockTime,
events.get(), didAnimate, m_needsAnimateLayers); | |
1370 | |
1371 if (!events->empty()) | |
1372 m_client->postAnimationEventsToMainThreadOnImplThread(events.Pass(), wal
lClockTime); | |
1373 | |
1374 if (didAnimate) | |
1375 m_client->setNeedsRedrawOnImplThread(); | |
1376 | |
1377 setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers); | |
1378 } | |
1379 | |
1380 base::TimeDelta CCLayerTreeHostImpl::lowFrequencyAnimationInterval() const | |
1381 { | |
1382 return base::TimeDelta::FromSeconds(1); | |
1383 } | |
1384 | |
1385 void CCLayerTreeHostImpl::sendDidLoseContextRecursive(CCLayerImpl* current) | |
1386 { | |
1387 ASSERT(current); | |
1388 current->didLoseContext(); | |
1389 if (current->maskLayer()) | |
1390 sendDidLoseContextRecursive(current->maskLayer()); | |
1391 if (current->replicaLayer()) | |
1392 sendDidLoseContextRecursive(current->replicaLayer()); | |
1393 for (size_t i = 0; i < current->children().size(); ++i) | |
1394 sendDidLoseContextRecursive(current->children()[i]); | |
1395 } | |
1396 | |
1397 static void clearRenderSurfacesOnCCLayerImplRecursive(CCLayerImpl* current) | |
1398 { | |
1399 ASSERT(current); | |
1400 for (size_t i = 0; i < current->children().size(); ++i) | |
1401 clearRenderSurfacesOnCCLayerImplRecursive(current->children()[i]); | |
1402 current->clearRenderSurface(); | |
1403 } | |
1404 | |
1405 void CCLayerTreeHostImpl::clearRenderSurfaces() | |
1406 { | |
1407 clearRenderSurfacesOnCCLayerImplRecursive(m_rootLayerImpl.get()); | |
1408 m_renderSurfaceLayerList.clear(); | |
1409 } | |
1410 | |
1411 std::string CCLayerTreeHostImpl::layerTreeAsText() const | |
1412 { | |
1413 std::string str; | |
1414 if (m_rootLayerImpl) { | |
1415 str = m_rootLayerImpl->layerTreeAsText(); | |
1416 str += "RenderSurfaces:\n"; | |
1417 dumpRenderSurfaces(&str, 1, m_rootLayerImpl.get()); | |
1418 } | |
1419 return str; | |
1420 } | |
1421 | |
1422 void CCLayerTreeHostImpl::dumpRenderSurfaces(std::string* str, int indent, const
CCLayerImpl* layer) const | |
1423 { | |
1424 if (layer->renderSurface()) | |
1425 layer->renderSurface()->dumpSurface(str, indent); | |
1426 | |
1427 for (size_t i = 0; i < layer->children().size(); ++i) | |
1428 dumpRenderSurfaces(str, indent, layer->children()[i]); | |
1429 } | |
1430 | |
1431 int CCLayerTreeHostImpl::sourceAnimationFrameNumber() const | |
1432 { | |
1433 return fpsCounter()->currentFrameNumber(); | |
1434 } | |
1435 | |
1436 void CCLayerTreeHostImpl::renderingStats(CCRenderingStats* stats) const | |
1437 { | |
1438 stats->numFramesSentToScreen = fpsCounter()->currentFrameNumber(); | |
1439 stats->droppedFrameCount = fpsCounter()->droppedFrameCount(); | |
1440 stats->numImplThreadScrolls = m_numImplThreadScrolls; | |
1441 stats->numMainThreadScrolls = m_numMainThreadScrolls; | |
1442 } | |
1443 | |
1444 void CCLayerTreeHostImpl::animateScrollbars(double monotonicTime) | |
1445 { | |
1446 animateScrollbarsRecursive(m_rootLayerImpl.get(), monotonicTime); | |
1447 } | |
1448 | |
1449 void CCLayerTreeHostImpl::animateScrollbarsRecursive(CCLayerImpl* layer, double
monotonicTime) | |
1450 { | |
1451 if (!layer) | |
1452 return; | |
1453 | |
1454 CCScrollbarAnimationController* scrollbarController = layer->scrollbarAnimat
ionController(); | |
1455 if (scrollbarController && scrollbarController->animate(monotonicTime)) | |
1456 m_client->setNeedsRedrawOnImplThread(); | |
1457 | |
1458 for (size_t i = 0; i < layer->children().size(); ++i) | |
1459 animateScrollbarsRecursive(layer->children()[i], monotonicTime); | |
1460 } | |
1461 | |
1462 } // namespace cc | |
OLD | NEW |