blob: 1d67042f4999d85e52c034a8a6f0a5b443bfa79e [file] [log] [blame]
[email protected]94f206c12012-08-25 00:09:141// 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 "CCActiveGestureAnimation.h"
[email protected]89228202012-08-29 03:20:3010#include "CCAppendQuadsData.h"
[email protected]94f206c12012-08-25 00:09:1411#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 "CCRenderingStats.h"
27#include "CCScrollbarAnimationController.h"
28#include "CCScrollbarLayerImpl.h"
29#include "CCSettings.h"
30#include "CCSingleThreadProxy.h"
31#include "TextStream.h"
32#include "TraceEvent.h"
33#include <wtf/CurrentTime.h>
34
35using WebKit::WebTransformationMatrix;
36
37namespace {
38
39void didVisibilityChange(WebCore::CCLayerTreeHostImpl* id, bool visible)
40{
41 if (visible) {
42 TRACE_EVENT_ASYNC_BEGIN1("webkit", "CCLayerTreeHostImpl::setVisible", id, "CCLayerTreeHostImpl", id);
43 return;
44 }
45
46 TRACE_EVENT_ASYNC_END0("webkit", "CCLayerTreeHostImpl::setVisible", id);
47}
48
49} // namespace
50
51namespace WebCore {
52
53class CCLayerTreeHostImplTimeSourceAdapter : public CCTimeSourceClient {
54 WTF_MAKE_NONCOPYABLE(CCLayerTreeHostImplTimeSourceAdapter);
55public:
56 static PassOwnPtr<CCLayerTreeHostImplTimeSourceAdapter> create(CCLayerTreeHostImpl* layerTreeHostImpl, PassRefPtr<CCDelayBasedTimeSource> timeSource)
57 {
58 return adoptPtr(new CCLayerTreeHostImplTimeSourceAdapter(layerTreeHostImpl, timeSource));
59 }
60 virtual ~CCLayerTreeHostImplTimeSourceAdapter()
61 {
62 m_timeSource->setClient(0);
63 m_timeSource->setActive(false);
64 }
65
66 virtual void onTimerTick() OVERRIDE
67 {
68 // FIXME: We require that animate be called on the impl thread. This
69 // avoids asserts in single threaded mode. Ideally background ticking
70 // would be handled by the proxy/scheduler and this could be removed.
71 DebugScopedSetImplThread impl;
72
73 m_layerTreeHostImpl->animate(monotonicallyIncreasingTime(), currentTime());
74 }
75
76 void setActive(bool active)
77 {
78 if (active != m_timeSource->active())
79 m_timeSource->setActive(active);
80 }
81
82private:
83 CCLayerTreeHostImplTimeSourceAdapter(CCLayerTreeHostImpl* layerTreeHostImpl, PassRefPtr<CCDelayBasedTimeSource> timeSource)
84 : m_layerTreeHostImpl(layerTreeHostImpl)
85 , m_timeSource(timeSource)
86 {
87 m_timeSource->setClient(this);
88 }
89
90 CCLayerTreeHostImpl* m_layerTreeHostImpl;
91 RefPtr<CCDelayBasedTimeSource> m_timeSource;
92};
93
94PassOwnPtr<CCLayerTreeHostImpl> CCLayerTreeHostImpl::create(const CCLayerTreeSettings& settings, CCLayerTreeHostImplClient* client)
95{
96 return adoptPtr(new CCLayerTreeHostImpl(settings, client));
97}
98
99CCLayerTreeHostImpl::CCLayerTreeHostImpl(const CCLayerTreeSettings& settings, CCLayerTreeHostImplClient* client)
100 : m_client(client)
101 , m_sourceFrameNumber(-1)
102 , m_rootScrollLayerImpl(0)
103 , m_currentlyScrollingLayerImpl(0)
104 , m_hudLayerImpl(0)
105 , m_scrollingLayerIdFromPreviousTree(-1)
106 , m_scrollDeltaIsInScreenSpace(false)
107 , m_settings(settings)
108 , m_deviceScaleFactor(1)
109 , m_visible(true)
110 , m_contentsTexturesPurged(false)
111 , m_memoryAllocationLimitBytes(CCPrioritizedTextureManager::defaultMemoryAllocationLimit())
112 , m_pageScale(1)
113 , m_pageScaleDelta(1)
114 , m_sentPageScaleDelta(1)
115 , m_minPageScale(0)
116 , m_maxPageScale(0)
117 , m_backgroundColor(0)
118 , m_hasTransparentBackground(false)
119 , m_needsAnimateLayers(false)
120 , m_pinchGestureActive(false)
121 , m_fpsCounter(CCFrameRateCounter::create())
122 , m_debugRectHistory(CCDebugRectHistory::create())
123{
124 ASSERT(CCProxy::isImplThread());
125 didVisibilityChange(this, m_visible);
126}
127
128CCLayerTreeHostImpl::~CCLayerTreeHostImpl()
129{
130 ASSERT(CCProxy::isImplThread());
131 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::~CCLayerTreeHostImpl()");
132
133 if (m_rootLayerImpl)
134 clearRenderSurfaces();
135}
136
137void CCLayerTreeHostImpl::beginCommit()
138{
139}
140
141void CCLayerTreeHostImpl::commitComplete()
142{
143 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::commitComplete");
144 // Recompute max scroll position; must be after layer content bounds are
145 // updated.
146 updateMaxScrollPosition();
147}
148
149bool CCLayerTreeHostImpl::canDraw()
150{
151 if (!m_rootLayerImpl) {
152 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw no root layer");
153 return false;
154 }
155 if (deviceViewportSize().isEmpty()) {
156 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw empty viewport");
157 return false;
158 }
159 if (!m_renderer) {
160 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw no renderer");
161 return false;
162 }
163 if (m_contentsTexturesPurged) {
164 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw contents textures purged");
165 return false;
166 }
167 return true;
168}
169
170CCGraphicsContext* CCLayerTreeHostImpl::context() const
171{
172 return m_context.get();
173}
174
175void CCLayerTreeHostImpl::animate(double monotonicTime, double wallClockTime)
176{
177 animatePageScale(monotonicTime);
178 animateLayers(monotonicTime, wallClockTime);
179 animateGestures(monotonicTime);
180 animateScrollbars(monotonicTime);
181}
182
183void CCLayerTreeHostImpl::startPageScaleAnimation(const IntSize& targetPosition, bool anchorPoint, float pageScale, double startTime, double duration)
184{
185 if (!m_rootScrollLayerImpl)
186 return;
187
188 IntSize scrollTotal = flooredIntSize(m_rootScrollLayerImpl->scrollPosition() + m_rootScrollLayerImpl->scrollDelta());
189 scrollTotal.scale(m_pageScaleDelta);
190 float scaleTotal = m_pageScale * m_pageScaleDelta;
191 IntSize scaledContentSize = contentSize();
192 scaledContentSize.scale(m_pageScaleDelta);
193
194 m_pageScaleAnimation = CCPageScaleAnimation::create(scrollTotal, scaleTotal, m_deviceViewportSize, scaledContentSize, startTime);
195
196 if (anchorPoint) {
197 IntSize windowAnchor(targetPosition);
198 windowAnchor.scale(scaleTotal / pageScale);
199 windowAnchor -= scrollTotal;
200 m_pageScaleAnimation->zoomWithAnchor(windowAnchor, pageScale, duration);
201 } else
202 m_pageScaleAnimation->zoomTo(targetPosition, pageScale, duration);
203
204 m_client->setNeedsRedrawOnImplThread();
205 m_client->setNeedsCommitOnImplThread();
206}
207
208void CCLayerTreeHostImpl::setActiveGestureAnimation(PassOwnPtr<CCActiveGestureAnimation> gestureAnimation)
209{
210 m_activeGestureAnimation = gestureAnimation;
211
212 if (m_activeGestureAnimation)
213 m_client->setNeedsRedrawOnImplThread();
214}
215
216void CCLayerTreeHostImpl::scheduleAnimation()
217{
218 m_client->setNeedsRedrawOnImplThread();
219}
220
221void CCLayerTreeHostImpl::trackDamageForAllSurfaces(CCLayerImpl* rootDrawLayer, const CCLayerList& renderSurfaceLayerList)
222{
223 // For now, we use damage tracking to compute a global scissor. To do this, we must
224 // compute all damage tracking before drawing anything, so that we know the root
225 // damage rect. The root damage rect is then used to scissor each surface.
226
227 for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
228 CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex];
229 CCRenderSurface* renderSurface = renderSurfaceLayer->renderSurface();
230 ASSERT(renderSurface);
231 renderSurface->damageTracker()->updateDamageTrackingState(renderSurface->layerList(), renderSurfaceLayer->id(), renderSurface->surfacePropertyChangedOnlyFromDescendant(), renderSurface->contentRect(), renderSurfaceLayer->maskLayer(), renderSurfaceLayer->filters());
232 }
233}
234
235void CCLayerTreeHostImpl::calculateRenderSurfaceLayerList(CCLayerList& renderSurfaceLayerList)
236{
237 ASSERT(renderSurfaceLayerList.isEmpty());
238 ASSERT(m_rootLayerImpl);
239 ASSERT(m_renderer); // For maxTextureSize.
240
241 {
242 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::calcDrawEtc");
243 CCLayerTreeHostCommon::calculateDrawTransforms(m_rootLayerImpl.get(), deviceViewportSize(), m_deviceScaleFactor, &m_layerSorter, rendererCapabilities().maxTextureSize, renderSurfaceLayerList);
244 CCLayerTreeHostCommon::calculateVisibleRects(renderSurfaceLayerList);
245
246 trackDamageForAllSurfaces(m_rootLayerImpl.get(), renderSurfaceLayerList);
247 }
248}
249
[email protected]467b3612012-08-28 07:41:16250void CCLayerTreeHostImpl::FrameData::appendRenderPass(PassOwnPtr<CCRenderPass> renderPass)
251{
252 CCRenderPass* pass = renderPass.get();
253 renderPasses.append(pass);
254 renderPassesById.set(pass->id(), renderPass);
255}
256
[email protected]94f206c12012-08-25 00:09:14257bool CCLayerTreeHostImpl::calculateRenderPasses(FrameData& frame)
258{
259 ASSERT(frame.renderPasses.isEmpty());
260
261 calculateRenderSurfaceLayerList(*frame.renderSurfaceLayerList);
262
263 TRACE_EVENT1("cc", "CCLayerTreeHostImpl::calculateRenderPasses", "renderSurfaceLayerList.size()", static_cast<long long unsigned>(frame.renderSurfaceLayerList->size()));
264
265 // Create the render passes in dependency order.
[email protected]94f206c12012-08-25 00:09:14266 for (int surfaceIndex = frame.renderSurfaceLayerList->size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
267 CCLayerImpl* renderSurfaceLayer = (*frame.renderSurfaceLayerList)[surfaceIndex];
[email protected]467b3612012-08-28 07:41:16268 renderSurfaceLayer->renderSurface()->appendRenderPasses(frame);
[email protected]94f206c12012-08-25 00:09:14269 }
270
271 bool recordMetricsForFrame = true; // FIXME: In the future, disable this when about:tracing is off.
272 CCOcclusionTrackerImpl occlusionTracker(m_rootLayerImpl->renderSurface()->contentRect(), recordMetricsForFrame);
273 occlusionTracker.setMinimumTrackingSize(m_settings.minimumOcclusionTrackingSize);
274
275 if (settings().showOccludingRects)
276 occlusionTracker.setOccludingScreenSpaceRectsContainer(&frame.occludingScreenSpaceRects);
277
278 // Add quads to the Render passes in FrontToBack order to allow for testing occlusion and performing culling during the tree walk.
279 typedef CCLayerIterator<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface, CCLayerIteratorActions::FrontToBack> CCLayerIteratorType;
280
281 // Typically when we are missing a texture and use a checkerboard quad, we still draw the frame. However when the layer being
282 // checkerboarded is moving due to an impl-animation, we drop the frame to avoid flashing due to the texture suddenly appearing
283 // in the future.
284 bool drawFrame = true;
285
286 CCLayerIteratorType end = CCLayerIteratorType::end(frame.renderSurfaceLayerList);
287 for (CCLayerIteratorType it = CCLayerIteratorType::begin(frame.renderSurfaceLayerList); it != end; ++it) {
[email protected]467b3612012-08-28 07:41:16288 int targetRenderPassId = it.targetRenderSurfaceLayer()->id();
289 CCRenderPass* targetRenderPass = frame.renderPassesById.get(targetRenderPassId);
[email protected]94f206c12012-08-25 00:09:14290
291 occlusionTracker.enterLayer(it);
292
[email protected]89228202012-08-29 03:20:30293 CCAppendQuadsData appendQuadsData;
294
[email protected]94f206c12012-08-25 00:09:14295 if (it.representsContributingRenderSurface()) {
[email protected]467b3612012-08-28 07:41:16296 int contributingRenderPassId = it->id();
297 CCRenderPass* contributingRenderPass = frame.renderPassesById.get(contributingRenderPassId);
[email protected]89228202012-08-29 03:20:30298 targetRenderPass->appendQuadsForRenderSurfaceLayer(*it, contributingRenderPass, &occlusionTracker, appendQuadsData);
[email protected]94f206c12012-08-25 00:09:14299 } else if (it.representsItself() && !it->visibleContentRect().isEmpty()) {
300 bool hasOcclusionFromOutsideTargetSurface;
[email protected]89228202012-08-29 03:20:30301 if (occlusionTracker.occluded(*it, it->visibleContentRect(), &hasOcclusionFromOutsideTargetSurface))
302 appendQuadsData.hadOcclusionFromOutsideTargetSurface |= hasOcclusionFromOutsideTargetSurface;
303 else {
[email protected]94f206c12012-08-25 00:09:14304 it->willDraw(m_resourceProvider.get());
305 frame.willDrawLayers.append(*it);
[email protected]89228202012-08-29 03:20:30306 targetRenderPass->appendQuadsForLayer(*it, &occlusionTracker, appendQuadsData);
[email protected]94f206c12012-08-25 00:09:14307 }
308 }
309
[email protected]89228202012-08-29 03:20:30310 if (appendQuadsData.hadOcclusionFromOutsideTargetSurface)
311 targetRenderPass->setHasOcclusionFromOutsideTargetSurface(true);
312
313 if (appendQuadsData.hadMissingTiles) {
[email protected]94f206c12012-08-25 00:09:14314 bool layerHasAnimatingTransform = it->screenSpaceTransformIsAnimating() || it->drawTransformIsAnimating();
315 if (layerHasAnimatingTransform)
316 drawFrame = false;
317 }
318
319 occlusionTracker.leaveLayer(it);
320 }
321
322#if !ASSERT_DISABLED
323 for (size_t i = 0; i < frame.renderPasses.size(); ++i) {
324 for (size_t j = 0; j < frame.renderPasses[i]->quadList().size(); ++j)
325 ASSERT(frame.renderPasses[i]->quadList()[j]->sharedQuadStateId() >= 0);
[email protected]467b3612012-08-28 07:41:16326 ASSERT(frame.renderPassesById.contains(frame.renderPasses[i]->id()));
[email protected]94f206c12012-08-25 00:09:14327 }
328#endif
329
330 if (!m_hasTransparentBackground) {
331 frame.renderPasses.last()->setHasTransparentBackground(false);
332 frame.renderPasses.last()->appendQuadsToFillScreen(m_rootLayerImpl.get(), m_backgroundColor, occlusionTracker);
333 }
334
335 if (drawFrame)
336 occlusionTracker.overdrawMetrics().recordMetrics(this);
337
338 removeRenderPasses(CullRenderPassesWithNoQuads(), frame);
339 m_renderer->decideRenderPassAllocationsForFrame(frame.renderPasses);
340 removeRenderPasses(CullRenderPassesWithCachedTextures(*m_renderer), frame);
341
342 return drawFrame;
343}
344
345void CCLayerTreeHostImpl::animateLayersRecursive(CCLayerImpl* current, double monotonicTime, double wallClockTime, CCAnimationEventsVector* events, bool& didAnimate, bool& needsAnimateLayers)
346{
347 bool subtreeNeedsAnimateLayers = false;
348
349 CCLayerAnimationController* currentController = current->layerAnimationController();
350
351 bool hadActiveAnimation = currentController->hasActiveAnimation();
352 currentController->animate(monotonicTime, events);
353 bool startedAnimation = events->size() > 0;
354
355 // We animated if we either ticked a running animation, or started a new animation.
356 if (hadActiveAnimation || startedAnimation)
357 didAnimate = true;
358
359 // If the current controller still has an active animation, we must continue animating layers.
360 if (currentController->hasActiveAnimation())
361 subtreeNeedsAnimateLayers = true;
362
363 for (size_t i = 0; i < current->children().size(); ++i) {
364 bool childNeedsAnimateLayers = false;
365 animateLayersRecursive(current->children()[i].get(), monotonicTime, wallClockTime, events, didAnimate, childNeedsAnimateLayers);
366 if (childNeedsAnimateLayers)
367 subtreeNeedsAnimateLayers = true;
368 }
369
370 needsAnimateLayers = subtreeNeedsAnimateLayers;
371}
372
373void CCLayerTreeHostImpl::setBackgroundTickingEnabled(bool enabled)
374{
375 // Lazily create the timeSource adapter so that we can vary the interval for testing.
376 if (!m_timeSourceClientAdapter)
377 m_timeSourceClientAdapter = CCLayerTreeHostImplTimeSourceAdapter::create(this, CCDelayBasedTimeSource::create(lowFrequencyAnimationInterval(), CCProxy::currentThread()));
378
379 m_timeSourceClientAdapter->setActive(enabled);
380}
381
382IntSize CCLayerTreeHostImpl::contentSize() const
383{
384 // TODO(aelias): Hardcoding the first child here is weird. Think of
385 // a cleaner way to get the contentBounds on the Impl side.
386 if (!m_rootScrollLayerImpl || m_rootScrollLayerImpl->children().isEmpty())
387 return IntSize();
388 return m_rootScrollLayerImpl->children()[0]->contentBounds();
389}
390
391static inline CCRenderPass* findRenderPassById(int renderPassId, const CCLayerTreeHostImpl::FrameData& frame)
392{
393 CCRenderPassIdHashMap::const_iterator it = frame.renderPassesById.find(renderPassId);
394 ASSERT(it != frame.renderPassesById.end());
395 return it->second.get();
396}
397
398static void removeRenderPassesRecursive(int removeRenderPassId, CCLayerTreeHostImpl::FrameData& frame)
399{
400 CCRenderPass* removeRenderPass = findRenderPassById(removeRenderPassId, frame);
401 size_t removeIndex = frame.renderPasses.find(removeRenderPass);
402
403 // The pass was already removed by another quad - probably the original, and we are the replica.
404 if (removeIndex == notFound)
405 return;
406
407 const CCRenderPass* removedPass = frame.renderPasses[removeIndex];
408 frame.renderPasses.remove(removeIndex);
409
410 // Now follow up for all RenderPass quads and remove their RenderPasses recursively.
411 const CCQuadList& quadList = removedPass->quadList();
412 CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin();
413 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) {
414 CCDrawQuad* currentQuad = (*quadListIterator).get();
415 if (currentQuad->material() != CCDrawQuad::RenderPass)
416 continue;
417
418 int nextRemoveRenderPassId = CCRenderPassDrawQuad::materialCast(currentQuad)->renderPassId();
419 removeRenderPassesRecursive(nextRemoveRenderPassId, frame);
420 }
421}
422
423bool CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures::shouldRemoveRenderPass(const CCRenderPassDrawQuad& quad, const FrameData&) const
424{
425 return quad.contentsChangedSinceLastFrame().isEmpty() && m_renderer.haveCachedResourcesForRenderPassId(quad.renderPassId());
426}
427
428bool CCLayerTreeHostImpl::CullRenderPassesWithNoQuads::shouldRemoveRenderPass(const CCRenderPassDrawQuad& quad, const FrameData& frame) const
429{
430 const CCRenderPass* renderPass = findRenderPassById(quad.renderPassId(), frame);
431 size_t passIndex = frame.renderPasses.find(renderPass);
432
433 bool renderPassAlreadyRemoved = passIndex == notFound;
434 if (renderPassAlreadyRemoved)
435 return false;
436
437 // If any quad or RenderPass draws into this RenderPass, then keep it.
438 const CCQuadList& quadList = frame.renderPasses[passIndex]->quadList();
439 for (CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin(); quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) {
440 CCDrawQuad* currentQuad = quadListIterator->get();
441
442 if (currentQuad->material() != CCDrawQuad::RenderPass)
443 return false;
444
445 const CCRenderPass* contributingPass = findRenderPassById(CCRenderPassDrawQuad::materialCast(currentQuad)->renderPassId(), frame);
446 if (frame.renderPasses.contains(contributingPass))
447 return false;
448 }
449 return true;
450}
451
452// Defined for linking tests.
453template void CCLayerTreeHostImpl::removeRenderPasses<CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures>(CullRenderPassesWithCachedTextures, FrameData&);
454template void CCLayerTreeHostImpl::removeRenderPasses<CCLayerTreeHostImpl::CullRenderPassesWithNoQuads>(CullRenderPassesWithNoQuads, FrameData&);
455
456// static
457template<typename RenderPassCuller>
458void CCLayerTreeHostImpl::removeRenderPasses(RenderPassCuller culler, FrameData& frame)
459{
460 for (size_t it = culler.renderPassListBegin(frame.renderPasses); it != culler.renderPassListEnd(frame.renderPasses); it = culler.renderPassListNext(it)) {
461 const CCRenderPass* currentPass = frame.renderPasses[it];
462 const CCQuadList& quadList = currentPass->quadList();
463 CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin();
464
465 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) {
466 CCDrawQuad* currentQuad = quadListIterator->get();
467
468 if (currentQuad->material() != CCDrawQuad::RenderPass)
469 continue;
470
471 CCRenderPassDrawQuad* renderPassQuad = static_cast<CCRenderPassDrawQuad*>(currentQuad);
472 if (!culler.shouldRemoveRenderPass(*renderPassQuad, frame))
473 continue;
474
475 // We are changing the vector in the middle of iteration. Because we
476 // delete render passes that draw into the current pass, we are
477 // guaranteed that any data from the iterator to the end will not
478 // change. So, capture the iterator position from the end of the
479 // list, and restore it after the change.
480 int positionFromEnd = frame.renderPasses.size() - it;
481 removeRenderPassesRecursive(renderPassQuad->renderPassId(), frame);
482 it = frame.renderPasses.size() - positionFromEnd;
483 ASSERT(it >= 0);
484 }
485 }
486}
487
488bool CCLayerTreeHostImpl::prepareToDraw(FrameData& frame)
489{
490 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::prepareToDraw");
491 ASSERT(canDraw());
492
493 frame.renderSurfaceLayerList = &m_renderSurfaceLayerList;
494 frame.renderPasses.clear();
495 frame.renderPassesById.clear();
496 frame.renderSurfaceLayerList->clear();
497 frame.willDrawLayers.clear();
498
499 if (!calculateRenderPasses(frame))
500 return false;
501
502 // If we return true, then we expect drawLayers() to be called before this function is called again.
503 return true;
504}
505
506void CCLayerTreeHostImpl::releaseContentsTextures()
507{
508 if (m_contentsTexturesPurged)
509 return;
510 m_resourceProvider->deleteOwnedResources(CCRenderer::ContentPool);
511 m_contentsTexturesPurged = true;
512 m_client->setNeedsCommitOnImplThread();
513}
514
515void CCLayerTreeHostImpl::setMemoryAllocationLimitBytes(size_t bytes)
516{
517 if (m_memoryAllocationLimitBytes == bytes)
518 return;
519 m_memoryAllocationLimitBytes = bytes;
520
521 ASSERT(bytes);
522 m_client->setNeedsCommitOnImplThread();
523}
524
525void CCLayerTreeHostImpl::onVSyncParametersChanged(double monotonicTimebase, double intervalInSeconds)
526{
527 m_client->onVSyncParametersChanged(monotonicTimebase, intervalInSeconds);
528}
529
530void CCLayerTreeHostImpl::drawLayers(const FrameData& frame)
531{
532 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::drawLayers");
533 ASSERT(canDraw());
534 ASSERT(!frame.renderPasses.isEmpty());
535
536 // FIXME: use the frame begin time from the overall compositor scheduler.
537 // This value is currently inaccessible because it is up in Chromium's
538 // RenderWidget.
539 m_fpsCounter->markBeginningOfFrame(currentTime());
540
541 if (m_settings.showDebugRects())
542 m_debugRectHistory->saveDebugRectsForCurrentFrame(m_rootLayerImpl.get(), *frame.renderSurfaceLayerList, frame.occludingScreenSpaceRects, settings());
543
544 // Because the contents of the HUD depend on everything else in the frame, the contents
545 // of its texture are updated as the last thing before the frame is drawn.
546 if (m_hudLayerImpl)
547 m_hudLayerImpl->updateHudTexture(m_resourceProvider.get());
548
549 m_renderer->drawFrame(frame.renderPasses, frame.renderPassesById);
550
551 // Once a RenderPass has been drawn, its damage should be cleared in
552 // case the RenderPass will be reused next frame.
553 for (unsigned int i = 0; i < frame.renderPasses.size(); i++)
554 frame.renderPasses[i]->setDamageRect(FloatRect());
555
556 // The next frame should start by assuming nothing has changed, and changes are noted as they occur.
557 for (unsigned int i = 0; i < frame.renderSurfaceLayerList->size(); i++)
558 (*frame.renderSurfaceLayerList)[i]->renderSurface()->damageTracker()->didDrawDamagedArea();
559 m_rootLayerImpl->resetAllChangeTrackingForSubtree();
560}
561
562void CCLayerTreeHostImpl::didDrawAllLayers(const FrameData& frame)
563{
564 for (size_t i = 0; i < frame.willDrawLayers.size(); ++i)
565 frame.willDrawLayers[i]->didDraw(m_resourceProvider.get());
566}
567
568void CCLayerTreeHostImpl::finishAllRendering()
569{
570 if (m_renderer)
571 m_renderer->finish();
572}
573
574bool CCLayerTreeHostImpl::isContextLost()
575{
576 return m_renderer && m_renderer->isContextLost();
577}
578
579const RendererCapabilities& CCLayerTreeHostImpl::rendererCapabilities() const
580{
581 return m_renderer->capabilities();
582}
583
584bool CCLayerTreeHostImpl::swapBuffers()
585{
586 ASSERT(m_renderer);
587
588 m_fpsCounter->markEndOfFrame();
589 return m_renderer->swapBuffers();
590}
591
592void CCLayerTreeHostImpl::didLoseContext()
593{
594 m_client->didLoseContextOnImplThread();
595}
596
597void CCLayerTreeHostImpl::onSwapBuffersComplete()
598{
599 m_client->onSwapBuffersCompleteOnImplThread();
600}
601
602void CCLayerTreeHostImpl::readback(void* pixels, const IntRect& rect)
603{
604 ASSERT(m_renderer);
605 m_renderer->getFramebufferPixels(pixels, rect);
606}
607
608static CCLayerImpl* findRootScrollLayer(CCLayerImpl* layer)
609{
610 if (!layer)
611 return 0;
612
613 if (layer->scrollable())
614 return layer;
615
616 for (size_t i = 0; i < layer->children().size(); ++i) {
617 CCLayerImpl* found = findRootScrollLayer(layer->children()[i].get());
618 if (found)
619 return found;
620 }
621
622 return 0;
623}
624
625// Content layers can be either directly scrollable or contained in an outer
626// scrolling layer which applies the scroll transform. Given a content layer,
627// this function returns the associated scroll layer if any.
628static CCLayerImpl* findScrollLayerForContentLayer(CCLayerImpl* layerImpl)
629{
630 if (!layerImpl)
631 return 0;
632
633 if (layerImpl->scrollable())
634 return layerImpl;
635
636 if (layerImpl->drawsContent() && layerImpl->parent() && layerImpl->parent()->scrollable())
637 return layerImpl->parent();
638
639 return 0;
640}
641
642void CCLayerTreeHostImpl::setRootLayer(PassOwnPtr<CCLayerImpl> layer)
643{
644 m_rootLayerImpl = layer;
645 m_rootScrollLayerImpl = findRootScrollLayer(m_rootLayerImpl.get());
646 m_currentlyScrollingLayerImpl = 0;
647
648 if (m_rootLayerImpl && m_scrollingLayerIdFromPreviousTree != -1)
649 m_currentlyScrollingLayerImpl = CCLayerTreeHostCommon::findLayerInSubtree(m_rootLayerImpl.get(), m_scrollingLayerIdFromPreviousTree);
650
651 m_scrollingLayerIdFromPreviousTree = -1;
652}
653
654PassOwnPtr<CCLayerImpl> CCLayerTreeHostImpl::detachLayerTree()
655{
656 // Clear all data structures that have direct references to the layer tree.
657 m_scrollingLayerIdFromPreviousTree = m_currentlyScrollingLayerImpl ? m_currentlyScrollingLayerImpl->id() : -1;
658 m_currentlyScrollingLayerImpl = 0;
659 m_renderSurfaceLayerList.clear();
660
661 return m_rootLayerImpl.release();
662}
663
664void CCLayerTreeHostImpl::setVisible(bool visible)
665{
666 ASSERT(CCProxy::isImplThread());
667
668 if (m_visible == visible)
669 return;
670 m_visible = visible;
671 didVisibilityChange(this, m_visible);
672
673 if (!m_renderer)
674 return;
675
676 m_renderer->setVisible(visible);
677
678 setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers);
679}
680
681bool CCLayerTreeHostImpl::initializeRenderer(PassOwnPtr<CCGraphicsContext> context, TextureUploaderOption textureUploader)
682{
683 if (!context->bindToClient(this))
684 return false;
685
686 WebKit::WebGraphicsContext3D* context3d = context->context3D();
687
688 if (!context3d) {
689 // FIXME: Implement this path for software compositing.
690 return false;
691 }
692
693 OwnPtr<CCGraphicsContext> contextRef(context);
694 OwnPtr<CCResourceProvider> resourceProvider = CCResourceProvider::create(contextRef.get());
695 OwnPtr<CCRendererGL> renderer;
696 if (resourceProvider.get())
697 renderer = CCRendererGL::create(this, resourceProvider.get(), textureUploader);
698
699 // Since we now have a new context/renderer, we cannot continue to use the old
700 // resources (i.e. renderSurfaces and texture IDs).
701 if (m_rootLayerImpl) {
702 clearRenderSurfaces();
703 sendDidLoseContextRecursive(m_rootLayerImpl.get());
704 }
705
706 m_renderer = renderer.release();
707 m_resourceProvider = resourceProvider.release();
708 if (m_renderer)
709 m_context = contextRef.release();
710
711 if (!m_visible && m_renderer)
712 m_renderer->setVisible(m_visible);
713
714 return m_renderer;
715}
716
717void CCLayerTreeHostImpl::setViewportSize(const IntSize& layoutViewportSize, const IntSize& deviceViewportSize)
718{
719 if (layoutViewportSize == m_layoutViewportSize && deviceViewportSize == m_deviceViewportSize)
720 return;
721
722 m_layoutViewportSize = layoutViewportSize;
723 m_deviceViewportSize = deviceViewportSize;
724
725 updateMaxScrollPosition();
726
727 if (m_renderer)
728 m_renderer->viewportChanged();
729}
730
731static void adjustScrollsForPageScaleChange(CCLayerImpl* layerImpl, float pageScaleChange)
732{
733 if (!layerImpl)
734 return;
735
736 if (layerImpl->scrollable()) {
737 // We need to convert impl-side scroll deltas to pageScale space.
738 FloatSize scrollDelta = layerImpl->scrollDelta();
739 scrollDelta.scale(pageScaleChange);
740 layerImpl->setScrollDelta(scrollDelta);
741 }
742
743 for (size_t i = 0; i < layerImpl->children().size(); ++i)
744 adjustScrollsForPageScaleChange(layerImpl->children()[i].get(), pageScaleChange);
745}
746
747void CCLayerTreeHostImpl::setDeviceScaleFactor(float deviceScaleFactor)
748{
749 if (deviceScaleFactor == m_deviceScaleFactor)
750 return;
751 m_deviceScaleFactor = deviceScaleFactor;
752}
753
754
755void CCLayerTreeHostImpl::setPageScaleFactorAndLimits(float pageScale, float minPageScale, float maxPageScale)
756{
757 if (!pageScale)
758 return;
759
760 if (m_sentPageScaleDelta == 1 && pageScale == m_pageScale && minPageScale == m_minPageScale && maxPageScale == m_maxPageScale)
761 return;
762
763 m_minPageScale = minPageScale;
764 m_maxPageScale = maxPageScale;
765
766 float pageScaleChange = pageScale / m_pageScale;
767 m_pageScale = pageScale;
768
769 if (pageScaleChange != 1)
770 adjustScrollsForPageScaleChange(m_rootScrollLayerImpl, pageScaleChange);
771
772 // Clamp delta to limits and refresh display matrix.
773 setPageScaleDelta(m_pageScaleDelta / m_sentPageScaleDelta);
774 m_sentPageScaleDelta = 1;
775 if (m_rootScrollLayerImpl)
776 m_rootScrollLayerImpl->setPageScaleDelta(m_pageScaleDelta);
777}
778
779void CCLayerTreeHostImpl::setPageScaleDelta(float delta)
780{
781 // Clamp to the current min/max limits.
782 float finalMagnifyScale = m_pageScale * delta;
783 if (m_minPageScale && finalMagnifyScale < m_minPageScale)
784 delta = m_minPageScale / m_pageScale;
785 else if (m_maxPageScale && finalMagnifyScale > m_maxPageScale)
786 delta = m_maxPageScale / m_pageScale;
787
788 if (delta == m_pageScaleDelta)
789 return;
790
791 m_pageScaleDelta = delta;
792
793 updateMaxScrollPosition();
794 if (m_rootScrollLayerImpl)
795 m_rootScrollLayerImpl->setPageScaleDelta(m_pageScaleDelta);
796}
797
798void CCLayerTreeHostImpl::updateMaxScrollPosition()
799{
800 if (!m_rootScrollLayerImpl || !m_rootScrollLayerImpl->children().size())
801 return;
802
803 FloatSize viewBounds = m_deviceViewportSize;
804 if (CCLayerImpl* clipLayer = m_rootScrollLayerImpl->parent()) {
805 // Compensate for non-overlay scrollbars.
806 if (clipLayer->masksToBounds()) {
807 viewBounds = clipLayer->bounds();
808 viewBounds.scale(m_deviceScaleFactor);
809 }
810 }
811 viewBounds.scale(1 / m_pageScaleDelta);
812
813 // maxScroll is computed in physical pixels, but scroll positions are in layout pixels.
814 IntSize maxScroll = contentSize() - expandedIntSize(viewBounds);
815 maxScroll.scale(1 / m_deviceScaleFactor);
816 // The viewport may be larger than the contents in some cases, such as
817 // having a vertical scrollbar but no horizontal overflow.
818 maxScroll.clampNegativeToZero();
819
820 m_rootScrollLayerImpl->setMaxScrollPosition(maxScroll);
821}
822
823void CCLayerTreeHostImpl::setNeedsRedraw()
824{
825 m_client->setNeedsRedrawOnImplThread();
826}
827
828bool CCLayerTreeHostImpl::ensureRenderSurfaceLayerList()
829{
830 if (!m_rootLayerImpl)
831 return false;
832 if (!m_renderer)
833 return false;
834
835 // We need both a non-empty render surface layer list and a root render
836 // surface to be able to iterate over the visible layers.
837 if (m_renderSurfaceLayerList.size() && m_rootLayerImpl->renderSurface())
838 return true;
839
840 // If we are called after setRootLayer() but before prepareToDraw(), we need
841 // to recalculate the visible layers. This prevents being unable to scroll
842 // during part of a commit.
843 m_renderSurfaceLayerList.clear();
844 calculateRenderSurfaceLayerList(m_renderSurfaceLayerList);
845
846 return m_renderSurfaceLayerList.size();
847}
848
849CCInputHandlerClient::ScrollStatus CCLayerTreeHostImpl::scrollBegin(const IntPoint& viewportPoint, CCInputHandlerClient::ScrollInputType type)
850{
851 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::scrollBegin");
852
853 ASSERT(!m_currentlyScrollingLayerImpl);
854 clearCurrentlyScrollingLayer();
855
856 if (!ensureRenderSurfaceLayerList())
857 return ScrollIgnored;
858
859 IntPoint deviceViewportPoint = viewportPoint;
860 deviceViewportPoint.scale(m_deviceScaleFactor, m_deviceScaleFactor);
861
862 // First find out which layer was hit from the saved list of visible layers
863 // in the most recent frame.
864 CCLayerImpl* layerImpl = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(viewportPoint, m_renderSurfaceLayerList);
865
866 // Walk up the hierarchy and look for a scrollable layer.
867 CCLayerImpl* potentiallyScrollingLayerImpl = 0;
868 for (; layerImpl; layerImpl = layerImpl->parent()) {
869 // The content layer can also block attempts to scroll outside the main thread.
870 if (layerImpl->tryScroll(deviceViewportPoint, type) == ScrollOnMainThread)
871 return ScrollOnMainThread;
872
873 CCLayerImpl* scrollLayerImpl = findScrollLayerForContentLayer(layerImpl);
874 if (!scrollLayerImpl)
875 continue;
876
877 ScrollStatus status = scrollLayerImpl->tryScroll(viewportPoint, type);
878
879 // If any layer wants to divert the scroll event to the main thread, abort.
880 if (status == ScrollOnMainThread)
881 return ScrollOnMainThread;
882
883 if (status == ScrollStarted && !potentiallyScrollingLayerImpl)
884 potentiallyScrollingLayerImpl = scrollLayerImpl;
885 }
886
887 if (potentiallyScrollingLayerImpl) {
888 m_currentlyScrollingLayerImpl = potentiallyScrollingLayerImpl;
889 // Gesture events need to be transformed from screen coordinates to local layer coordinates
890 // so that the scrolling contents exactly follow the user's finger. In contrast, wheel
891 // events are already in local layer coordinates so we can just apply them directly.
892 m_scrollDeltaIsInScreenSpace = (type == Gesture);
893 return ScrollStarted;
894 }
895 return ScrollIgnored;
896}
897
898static FloatSize scrollLayerWithScreenSpaceDelta(CCLayerImpl& layerImpl, const FloatPoint& screenSpacePoint, const FloatSize& screenSpaceDelta)
899{
900 // Layers with non-invertible screen space transforms should not have passed the scroll hit
901 // test in the first place.
902 ASSERT(layerImpl.screenSpaceTransform().isInvertible());
903 WebTransformationMatrix inverseScreenSpaceTransform = layerImpl.screenSpaceTransform().inverse();
904
905 // First project the scroll start and end points to local layer space to find the scroll delta
906 // in layer coordinates.
907 bool startClipped, endClipped;
908 FloatPoint screenSpaceEndPoint = screenSpacePoint + screenSpaceDelta;
909 FloatPoint localStartPoint = CCMathUtil::projectPoint(inverseScreenSpaceTransform, screenSpacePoint, startClipped);
910 FloatPoint localEndPoint = CCMathUtil::projectPoint(inverseScreenSpaceTransform, screenSpaceEndPoint, endClipped);
911
912 // In general scroll point coordinates should not get clipped.
913 ASSERT(!startClipped);
914 ASSERT(!endClipped);
915 if (startClipped || endClipped)
916 return FloatSize();
917
918 // Apply the scroll delta.
919 FloatSize previousDelta(layerImpl.scrollDelta());
920 layerImpl.scrollBy(localEndPoint - localStartPoint);
921
922 // Calculate the applied scroll delta in screen space coordinates.
923 FloatPoint actualLocalEndPoint = localStartPoint + layerImpl.scrollDelta() - previousDelta;
924 FloatPoint actualScreenSpaceEndPoint = CCMathUtil::mapPoint(layerImpl.screenSpaceTransform(), actualLocalEndPoint, endClipped);
925 ASSERT(!endClipped);
926 if (endClipped)
927 return FloatSize();
928 return actualScreenSpaceEndPoint - screenSpacePoint;
929}
930
931static FloatSize scrollLayerWithLocalDelta(CCLayerImpl& layerImpl, const FloatSize& localDelta)
932{
933 FloatSize previousDelta(layerImpl.scrollDelta());
934 layerImpl.scrollBy(localDelta);
935 return layerImpl.scrollDelta() - previousDelta;
936}
937
938void CCLayerTreeHostImpl::scrollBy(const IntPoint& viewportPoint, const IntSize& scrollDelta)
939{
940 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::scrollBy");
941 if (!m_currentlyScrollingLayerImpl)
942 return;
943
944 FloatSize pendingDelta(scrollDelta);
945
946 pendingDelta.scale(m_deviceScaleFactor);
947
948 for (CCLayerImpl* layerImpl = m_currentlyScrollingLayerImpl; layerImpl; layerImpl = layerImpl->parent()) {
949 if (!layerImpl->scrollable())
950 continue;
951
952 FloatSize appliedDelta;
953 if (m_scrollDeltaIsInScreenSpace)
954 appliedDelta = scrollLayerWithScreenSpaceDelta(*layerImpl, viewportPoint, pendingDelta);
955 else
956 appliedDelta = scrollLayerWithLocalDelta(*layerImpl, pendingDelta);
957
958 // If the layer wasn't able to move, try the next one in the hierarchy.
959 float moveThresholdSquared = 0.1 * 0.1;
960 if (appliedDelta.diagonalLengthSquared() < moveThresholdSquared)
961 continue;
962
963 // If the applied delta is within 45 degrees of the input delta, bail out to make it easier
964 // to scroll just one layer in one direction without affecting any of its parents.
965 float angleThreshold = 45;
966 if (CCMathUtil::smallestAngleBetweenVectors(appliedDelta, pendingDelta) < angleThreshold) {
967 pendingDelta = FloatSize();
968 break;
969 }
970
971 // Allow further movement only on an axis perpendicular to the direction in which the layer
972 // moved.
973 FloatSize perpendicularAxis(-appliedDelta.height(), appliedDelta.width());
974 pendingDelta = CCMathUtil::projectVector(pendingDelta, perpendicularAxis);
975
976 if (flooredIntSize(pendingDelta).isZero())
977 break;
978 }
979
980 if (!scrollDelta.isZero() && flooredIntSize(pendingDelta).isEmpty()) {
981 m_client->setNeedsCommitOnImplThread();
982 m_client->setNeedsRedrawOnImplThread();
983 }
984}
985
986void CCLayerTreeHostImpl::clearCurrentlyScrollingLayer()
987{
988 m_currentlyScrollingLayerImpl = 0;
989 m_scrollingLayerIdFromPreviousTree = -1;
990}
991
992void CCLayerTreeHostImpl::scrollEnd()
993{
994 clearCurrentlyScrollingLayer();
995}
996
997void CCLayerTreeHostImpl::pinchGestureBegin()
998{
999 m_pinchGestureActive = true;
1000 m_previousPinchAnchor = IntPoint();
1001
1002 if (m_rootScrollLayerImpl && m_rootScrollLayerImpl->scrollbarAnimationController())
1003 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureBegin();
1004}
1005
1006void CCLayerTreeHostImpl::pinchGestureUpdate(float magnifyDelta,
1007 const IntPoint& anchor)
1008{
1009 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::pinchGestureUpdate");
1010
1011 if (!m_rootScrollLayerImpl)
1012 return;
1013
1014 if (m_previousPinchAnchor == IntPoint::zero())
1015 m_previousPinchAnchor = anchor;
1016
1017 // Keep the center-of-pinch anchor specified by (x, y) in a stable
1018 // position over the course of the magnify.
1019 FloatPoint previousScaleAnchor(m_previousPinchAnchor.x() / m_pageScaleDelta, m_previousPinchAnchor.y() / m_pageScaleDelta);
1020 setPageScaleDelta(m_pageScaleDelta * magnifyDelta);
1021 FloatPoint newScaleAnchor(anchor.x() / m_pageScaleDelta, anchor.y() / m_pageScaleDelta);
1022 FloatSize move = previousScaleAnchor - newScaleAnchor;
1023
1024 m_previousPinchAnchor = anchor;
1025
1026 m_rootScrollLayerImpl->scrollBy(roundedIntSize(move));
1027
1028 if (m_rootScrollLayerImpl->scrollbarAnimationController())
1029 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureUpdate();
1030
1031 m_client->setNeedsCommitOnImplThread();
1032 m_client->setNeedsRedrawOnImplThread();
1033}
1034
1035void CCLayerTreeHostImpl::pinchGestureEnd()
1036{
1037 m_pinchGestureActive = false;
1038
1039 if (m_rootScrollLayerImpl && m_rootScrollLayerImpl->scrollbarAnimationController())
1040 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureEnd();
1041
1042 m_client->setNeedsCommitOnImplThread();
1043}
1044
1045void CCLayerTreeHostImpl::computeDoubleTapZoomDeltas(CCScrollAndScaleSet* scrollInfo)
1046{
1047 float pageScale = m_pageScaleAnimation->finalPageScale();
1048 IntSize scrollOffset = m_pageScaleAnimation->finalScrollOffset();
1049 scrollOffset.scale(m_pageScale / pageScale);
1050 makeScrollAndScaleSet(scrollInfo, scrollOffset, pageScale);
1051}
1052
1053void CCLayerTreeHostImpl::computePinchZoomDeltas(CCScrollAndScaleSet* scrollInfo)
1054{
1055 if (!m_rootScrollLayerImpl)
1056 return;
1057
1058 // Only send fake scroll/zoom deltas if we're pinch zooming out by a
1059 // significant amount. This also ensures only one fake delta set will be
1060 // sent.
1061 const float pinchZoomOutSensitivity = 0.95;
1062 if (m_pageScaleDelta > pinchZoomOutSensitivity)
1063 return;
1064
1065 // Compute where the scroll offset/page scale would be if fully pinch-zoomed
1066 // out from the anchor point.
1067 IntSize scrollBegin = flooredIntSize(m_rootScrollLayerImpl->scrollPosition() + m_rootScrollLayerImpl->scrollDelta());
1068 scrollBegin.scale(m_pageScaleDelta);
1069 float scaleBegin = m_pageScale * m_pageScaleDelta;
1070 float pageScaleDeltaToSend = m_minPageScale / m_pageScale;
1071 FloatSize scaledContentsSize = contentSize();
1072 scaledContentsSize.scale(pageScaleDeltaToSend);
1073
1074 FloatSize anchor = toSize(m_previousPinchAnchor);
1075 FloatSize scrollEnd = scrollBegin + anchor;
1076 scrollEnd.scale(m_minPageScale / scaleBegin);
1077 scrollEnd -= anchor;
1078 scrollEnd = scrollEnd.shrunkTo(roundedIntSize(scaledContentsSize - m_deviceViewportSize)).expandedTo(FloatSize(0, 0));
1079 scrollEnd.scale(1 / pageScaleDeltaToSend);
1080 scrollEnd.scale(m_deviceScaleFactor);
1081
1082 makeScrollAndScaleSet(scrollInfo, roundedIntSize(scrollEnd), m_minPageScale);
1083}
1084
1085void CCLayerTreeHostImpl::makeScrollAndScaleSet(CCScrollAndScaleSet* scrollInfo, const IntSize& scrollOffset, float pageScale)
1086{
1087 if (!m_rootScrollLayerImpl)
1088 return;
1089
1090 CCLayerTreeHostCommon::ScrollUpdateInfo scroll;
1091 scroll.layerId = m_rootScrollLayerImpl->id();
1092 scroll.scrollDelta = scrollOffset - toSize(m_rootScrollLayerImpl->scrollPosition());
1093 scrollInfo->scrolls.append(scroll);
1094 m_rootScrollLayerImpl->setSentScrollDelta(scroll.scrollDelta);
1095 m_sentPageScaleDelta = scrollInfo->pageScaleDelta = pageScale / m_pageScale;
1096}
1097
1098static void collectScrollDeltas(CCScrollAndScaleSet* scrollInfo, CCLayerImpl* layerImpl)
1099{
1100 if (!layerImpl)
1101 return;
1102
1103 if (!layerImpl->scrollDelta().isZero()) {
1104 IntSize scrollDelta = flooredIntSize(layerImpl->scrollDelta());
1105 CCLayerTreeHostCommon::ScrollUpdateInfo scroll;
1106 scroll.layerId = layerImpl->id();
1107 scroll.scrollDelta = scrollDelta;
1108 scrollInfo->scrolls.append(scroll);
1109 layerImpl->setSentScrollDelta(scrollDelta);
1110 }
1111
1112 for (size_t i = 0; i < layerImpl->children().size(); ++i)
1113 collectScrollDeltas(scrollInfo, layerImpl->children()[i].get());
1114}
1115
1116PassOwnPtr<CCScrollAndScaleSet> CCLayerTreeHostImpl::processScrollDeltas()
1117{
1118 OwnPtr<CCScrollAndScaleSet> scrollInfo = adoptPtr(new CCScrollAndScaleSet());
1119
1120 if (m_pinchGestureActive || m_pageScaleAnimation) {
1121 m_sentPageScaleDelta = scrollInfo->pageScaleDelta = 1;
1122 if (m_pinchGestureActive)
1123 computePinchZoomDeltas(scrollInfo.get());
1124 else if (m_pageScaleAnimation.get())
1125 computeDoubleTapZoomDeltas(scrollInfo.get());
1126 return scrollInfo.release();
1127 }
1128
1129 collectScrollDeltas(scrollInfo.get(), m_rootLayerImpl.get());
1130 m_sentPageScaleDelta = scrollInfo->pageScaleDelta = m_pageScaleDelta;
1131
1132 return scrollInfo.release();
1133}
1134
1135void CCLayerTreeHostImpl::setFullRootLayerDamage()
1136{
1137 if (m_rootLayerImpl) {
1138 CCRenderSurface* renderSurface = m_rootLayerImpl->renderSurface();
1139 if (renderSurface)
1140 renderSurface->damageTracker()->forceFullDamageNextUpdate();
1141 }
1142}
1143
1144void CCLayerTreeHostImpl::animatePageScale(double monotonicTime)
1145{
1146 if (!m_pageScaleAnimation || !m_rootScrollLayerImpl)
1147 return;
1148
1149 IntSize scrollTotal = flooredIntSize(m_rootScrollLayerImpl->scrollPosition() + m_rootScrollLayerImpl->scrollDelta());
1150
1151 setPageScaleDelta(m_pageScaleAnimation->pageScaleAtTime(monotonicTime) / m_pageScale);
1152 IntSize nextScroll = m_pageScaleAnimation->scrollOffsetAtTime(monotonicTime);
1153 nextScroll.scale(1 / m_pageScaleDelta);
1154 m_rootScrollLayerImpl->scrollBy(nextScroll - scrollTotal);
1155 m_client->setNeedsRedrawOnImplThread();
1156
1157 if (m_pageScaleAnimation->isAnimationCompleteAtTime(monotonicTime)) {
1158 m_pageScaleAnimation.clear();
1159 m_client->setNeedsCommitOnImplThread();
1160 }
1161}
1162
1163void CCLayerTreeHostImpl::animateLayers(double monotonicTime, double wallClockTime)
1164{
1165 if (!CCSettings::acceleratedAnimationEnabled() || !m_needsAnimateLayers || !m_rootLayerImpl)
1166 return;
1167
1168 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::animateLayers");
1169
1170 OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector));
1171
1172 bool didAnimate = false;
1173 animateLayersRecursive(m_rootLayerImpl.get(), monotonicTime, wallClockTime, events.get(), didAnimate, m_needsAnimateLayers);
1174
1175 if (!events->isEmpty())
1176 m_client->postAnimationEventsToMainThreadOnImplThread(events.release(), wallClockTime);
1177
1178 if (didAnimate)
1179 m_client->setNeedsRedrawOnImplThread();
1180
1181 setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers);
1182}
1183
1184double CCLayerTreeHostImpl::lowFrequencyAnimationInterval() const
1185{
1186 return 1;
1187}
1188
1189void CCLayerTreeHostImpl::sendDidLoseContextRecursive(CCLayerImpl* current)
1190{
1191 ASSERT(current);
1192 current->didLoseContext();
1193 if (current->maskLayer())
1194 sendDidLoseContextRecursive(current->maskLayer());
1195 if (current->replicaLayer())
1196 sendDidLoseContextRecursive(current->replicaLayer());
1197 for (size_t i = 0; i < current->children().size(); ++i)
1198 sendDidLoseContextRecursive(current->children()[i].get());
1199}
1200
1201static void clearRenderSurfacesOnCCLayerImplRecursive(CCLayerImpl* current)
1202{
1203 ASSERT(current);
1204 for (size_t i = 0; i < current->children().size(); ++i)
1205 clearRenderSurfacesOnCCLayerImplRecursive(current->children()[i].get());
1206 current->clearRenderSurface();
1207}
1208
1209void CCLayerTreeHostImpl::clearRenderSurfaces()
1210{
1211 clearRenderSurfacesOnCCLayerImplRecursive(m_rootLayerImpl.get());
1212 m_renderSurfaceLayerList.clear();
1213}
1214
1215String CCLayerTreeHostImpl::layerTreeAsText() const
1216{
1217 TextStream ts;
1218 if (m_rootLayerImpl) {
1219 ts << m_rootLayerImpl->layerTreeAsText();
1220 ts << "RenderSurfaces:\n";
1221 dumpRenderSurfaces(ts, 1, m_rootLayerImpl.get());
1222 }
1223 return ts.release();
1224}
1225
1226void CCLayerTreeHostImpl::dumpRenderSurfaces(TextStream& ts, int indent, const CCLayerImpl* layer) const
1227{
1228 if (layer->renderSurface())
1229 layer->renderSurface()->dumpSurface(ts, indent);
1230
1231 for (size_t i = 0; i < layer->children().size(); ++i)
1232 dumpRenderSurfaces(ts, indent, layer->children()[i].get());
1233}
1234
1235
1236void CCLayerTreeHostImpl::animateGestures(double monotonicTime)
1237{
1238 if (!m_activeGestureAnimation)
1239 return;
1240
1241 bool isContinuing = m_activeGestureAnimation->animate(monotonicTime);
1242 if (isContinuing)
1243 m_client->setNeedsRedrawOnImplThread();
1244 else
1245 m_activeGestureAnimation.clear();
1246}
1247
1248int CCLayerTreeHostImpl::sourceAnimationFrameNumber() const
1249{
1250 return fpsCounter()->currentFrameNumber();
1251}
1252
1253void CCLayerTreeHostImpl::renderingStats(CCRenderingStats& stats) const
1254{
1255 stats.numFramesSentToScreen = fpsCounter()->currentFrameNumber();
1256 stats.droppedFrameCount = fpsCounter()->droppedFrameCount();
1257}
1258
1259void CCLayerTreeHostImpl::animateScrollbars(double monotonicTime)
1260{
1261 animateScrollbarsRecursive(m_rootLayerImpl.get(), monotonicTime);
1262}
1263
1264void CCLayerTreeHostImpl::animateScrollbarsRecursive(CCLayerImpl* layer, double monotonicTime)
1265{
1266 if (!layer)
1267 return;
1268
1269 CCScrollbarAnimationController* scrollbarController = layer->scrollbarAnimationController();
1270 if (scrollbarController && scrollbarController->animate(monotonicTime))
1271 m_client->setNeedsRedrawOnImplThread();
1272
1273 for (size_t i = 0; i < layer->children().size(); ++i)
1274 animateScrollbarsRecursive(layer->children()[i].get(), monotonicTime);
1275}
1276
1277} // namespace WebCore