FileSystem mods: Changes to snapshot file creation to remove dependencies on blobs.
[chromium-blink-merge.git] / cc / layer_tree_host_impl.cc
blob7d1d1bc8225c91dd41bc52e724f002cc24634783
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.
5 #include "cc/layer_tree_host_impl.h"
7 #include <algorithm>
9 #include "base/basictypes.h"
10 #include "base/debug/trace_event.h"
11 #include "base/json/json_writer.h"
12 #include "base/metrics/histogram.h"
13 #include "base/stl_util.h"
14 #include "base/stringprintf.h"
15 #include "cc/append_quads_data.h"
16 #include "cc/compositor_frame_metadata.h"
17 #include "cc/damage_tracker.h"
18 #include "cc/debug_rect_history.h"
19 #include "cc/delay_based_time_source.h"
20 #include "cc/delegating_renderer.h"
21 #include "cc/frame_rate_counter.h"
22 #include "cc/gl_renderer.h"
23 #include "cc/heads_up_display_layer_impl.h"
24 #include "cc/layer_iterator.h"
25 #include "cc/layer_tree_host.h"
26 #include "cc/layer_tree_host_common.h"
27 #include "cc/layer_tree_impl.h"
28 #include "cc/math_util.h"
29 #include "cc/memory_history.h"
30 #include "cc/overdraw_metrics.h"
31 #include "cc/page_scale_animation.h"
32 #include "cc/paint_time_counter.h"
33 #include "cc/picture_layer_tiling.h"
34 #include "cc/prioritized_resource_manager.h"
35 #include "cc/quad_culler.h"
36 #include "cc/render_pass_draw_quad.h"
37 #include "cc/rendering_stats.h"
38 #include "cc/scrollbar_animation_controller.h"
39 #include "cc/scrollbar_layer_impl.h"
40 #include "cc/shared_quad_state.h"
41 #include "cc/single_thread_proxy.h"
42 #include "cc/software_renderer.h"
43 #include "cc/solid_color_draw_quad.h"
44 #include "cc/texture_uploader.h"
45 #include "cc/top_controls_manager.h"
46 #include "cc/tree_synchronizer.h"
47 #include "cc/util.h"
48 #include "ui/gfx/size_conversions.h"
49 #include "ui/gfx/vector2d_conversions.h"
51 namespace {
53 void didVisibilityChange(cc::LayerTreeHostImpl* id, bool visible)
55 if (visible) {
56 TRACE_EVENT_ASYNC_BEGIN1("webkit", "LayerTreeHostImpl::setVisible", id, "LayerTreeHostImpl", id);
57 return;
60 TRACE_EVENT_ASYNC_END0("webkit", "LayerTreeHostImpl::setVisible", id);
63 std::string ValueToString(scoped_ptr<base::Value> value)
65 std::string str;
66 base::JSONWriter::Write(value.get(), &str);
67 return str;
70 } // namespace
72 namespace cc {
74 class LayerTreeHostImplTimeSourceAdapter : public TimeSourceClient {
75 public:
76 static scoped_ptr<LayerTreeHostImplTimeSourceAdapter> create(LayerTreeHostImpl* layerTreeHostImpl, scoped_refptr<DelayBasedTimeSource> timeSource)
78 return make_scoped_ptr(new LayerTreeHostImplTimeSourceAdapter(layerTreeHostImpl, timeSource));
80 virtual ~LayerTreeHostImplTimeSourceAdapter()
82 m_timeSource->setClient(0);
83 m_timeSource->setActive(false);
86 virtual void onTimerTick() OVERRIDE
88 // In single threaded mode we attempt to simulate changing the current
89 // thread by maintaining a fake thread id. When we switch from one
90 // thread to another, we construct DebugScopedSetXXXThread objects that
91 // update the thread id. This lets DCHECKS that ensure we're on the
92 // right thread to work correctly in single threaded mode. The problem
93 // here is that the timer tasks are run via the message loop, and when
94 // they run, we've had no chance to construct a DebugScopedSetXXXThread
95 // object. The result is that we report that we're running on the main
96 // thread. In multi-threaded mode, this timer is run on the compositor
97 // thread, so to keep this consistent in single-threaded mode, we'll
98 // construct a DebugScopedSetImplThread object. There is no need to do
99 // this in multi-threaded mode since the real thread id's will be
100 // correct. In fact, setting fake thread id's interferes with the real
101 // thread id's and causes breakage.
102 scoped_ptr<DebugScopedSetImplThread> setImplThread;
103 if (!m_layerTreeHostImpl->proxy()->hasImplThread())
104 setImplThread.reset(new DebugScopedSetImplThread(m_layerTreeHostImpl->proxy()));
106 m_layerTreeHostImpl->activatePendingTreeIfNeeded();
107 m_layerTreeHostImpl->animate(base::TimeTicks::Now(), base::Time::Now());
108 m_layerTreeHostImpl->beginNextFrame();
111 void setActive(bool active)
113 if (active != m_timeSource->active())
114 m_timeSource->setActive(active);
117 private:
118 LayerTreeHostImplTimeSourceAdapter(LayerTreeHostImpl* layerTreeHostImpl, scoped_refptr<DelayBasedTimeSource> timeSource)
119 : m_layerTreeHostImpl(layerTreeHostImpl)
120 , m_timeSource(timeSource)
122 m_timeSource->setClient(this);
125 LayerTreeHostImpl* m_layerTreeHostImpl;
126 scoped_refptr<DelayBasedTimeSource> m_timeSource;
128 DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImplTimeSourceAdapter);
131 LayerTreeHostImpl::FrameData::FrameData()
132 : containsIncompleteTile(false)
136 LayerTreeHostImpl::FrameData::~FrameData()
140 scoped_ptr<LayerTreeHostImpl> LayerTreeHostImpl::create(const LayerTreeSettings& settings, LayerTreeHostImplClient* client, Proxy* proxy)
142 return make_scoped_ptr(new LayerTreeHostImpl(settings, client, proxy));
145 LayerTreeHostImpl::LayerTreeHostImpl(const LayerTreeSettings& settings, LayerTreeHostImplClient* client, Proxy* proxy)
146 : m_client(client)
147 , m_proxy(proxy)
148 , m_didLockScrollingLayer(false)
149 , m_shouldBubbleScrolls(false)
150 , m_wheelScrolling(false)
151 , m_settings(settings)
152 , m_deviceScaleFactor(1)
153 , m_visible(true)
154 , m_managedMemoryPolicy(PrioritizedResourceManager::defaultMemoryAllocationLimit(),
155 ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
157 ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING)
158 , m_pinchGestureActive(false)
159 , m_fpsCounter(FrameRateCounter::create(m_proxy->hasImplThread()))
160 , m_paintTimeCounter(PaintTimeCounter::create())
161 , m_memoryHistory(MemoryHistory::create())
162 , m_debugRectHistory(DebugRectHistory::create())
163 , m_numImplThreadScrolls(0)
164 , m_numMainThreadScrolls(0)
165 , m_cumulativeNumLayersDrawn(0)
166 , m_cumulativeNumMissingTiles(0)
167 , m_lastSentMemoryVisibleBytes(0)
168 , m_lastSentMemoryVisibleAndNearbyBytes(0)
169 , m_lastSentMemoryUseBytes(0)
170 , m_animationRegistrar(AnimationRegistrar::create())
172 DCHECK(m_proxy->isImplThread());
173 didVisibilityChange(this, m_visible);
175 setDebugState(settings.initialDebugState);
177 if (settings.calculateTopControlsPosition)
178 m_topControlsManager = TopControlsManager::Create(this, settings.topControlsHeight);
180 setDebugState(settings.initialDebugState);
182 // LTHI always has an active tree.
183 m_activeTree = LayerTreeImpl::create(this);
186 LayerTreeHostImpl::~LayerTreeHostImpl()
188 DCHECK(m_proxy->isImplThread());
189 TRACE_EVENT0("cc", "LayerTreeHostImpl::~LayerTreeHostImpl()");
191 if (rootLayer()) {
192 clearRenderSurfaces();
193 // The layer trees must be destroyed before the layer tree host. We've
194 // made a contract with our animation controllers that the registrar
195 // will outlive them, and we must make good.
196 m_recycleTree.reset();
197 m_pendingTree.reset();
198 m_activeTree.reset();
202 void LayerTreeHostImpl::beginCommit()
206 void LayerTreeHostImpl::commitComplete()
208 TRACE_EVENT0("cc", "LayerTreeHostImpl::commitComplete");
210 // Impl-side painting needs an update immediately post-commit to have the
211 // opportunity to create tilings. Other paths can call updateDrawProperties
212 // more lazily when needed prior to drawing.
213 if (m_settings.implSidePainting) {
214 pendingTree()->set_needs_update_draw_properties();
215 pendingTree()->UpdateDrawProperties(LayerTreeImpl::UPDATE_PENDING_TREE);
216 } else {
217 activeTree()->set_needs_update_draw_properties();
220 m_client->sendManagedMemoryStats();
223 bool LayerTreeHostImpl::canDraw()
225 // Note: If you are changing this function or any other function that might
226 // affect the result of canDraw, make sure to call m_client->onCanDrawStateChanged
227 // in the proper places and update the notifyIfCanDrawChanged test.
229 if (!rootLayer()) {
230 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw no root layer");
231 return false;
233 if (deviceViewportSize().IsEmpty()) {
234 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw empty viewport");
235 return false;
237 if (m_activeTree->ViewportSizeInvalid()) {
238 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw viewport size recently changed");
239 return false;
241 if (!m_renderer) {
242 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw no renderer");
243 return false;
245 if (m_activeTree->ContentsTexturesPurged()) {
246 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw contents textures purged");
247 return false;
249 return true;
252 OutputSurface* LayerTreeHostImpl::outputSurface() const
254 return m_outputSurface.get();
257 void LayerTreeHostImpl::animate(base::TimeTicks monotonicTime, base::Time wallClockTime)
259 animatePageScale(monotonicTime);
260 animateLayers(monotonicTime, wallClockTime);
261 animateScrollbars(monotonicTime);
262 if (m_topControlsManager)
263 m_topControlsManager->Animate(monotonicTime);
266 void LayerTreeHostImpl::manageTiles()
268 DCHECK(m_tileManager);
269 m_tileManager->ManageTiles();
271 size_t memoryRequiredBytes;
272 size_t memoryNiceToHaveBytes;
273 size_t memoryUsedBytes;
274 m_tileManager->GetMemoryStats(&memoryRequiredBytes,
275 &memoryNiceToHaveBytes,
276 &memoryUsedBytes);
277 sendManagedMemoryStats(memoryRequiredBytes,
278 memoryNiceToHaveBytes,
279 memoryUsedBytes);
282 void LayerTreeHostImpl::startPageScaleAnimation(gfx::Vector2d targetOffset, bool anchorPoint, float pageScale, base::TimeTicks startTime, base::TimeDelta duration)
284 if (!rootScrollLayer())
285 return;
287 gfx::Vector2dF scrollTotal = rootScrollLayer()->scrollOffset() + rootScrollLayer()->scrollDelta();
288 gfx::SizeF scaledScrollableSize = activeTree()->ScrollableSize();
289 if (!m_settings.pageScalePinchZoomEnabled) {
290 scrollTotal.Scale(1 / activeTree()->page_scale_factor());
291 scaledScrollableSize.Scale(1 / activeTree()->page_scale_factor());
293 gfx::SizeF viewportSize = gfx::ScaleSize(m_deviceViewportSize, 1 / m_deviceScaleFactor);
295 double startTimeSeconds = (startTime - base::TimeTicks()).InSecondsF();
296 m_pageScaleAnimation = PageScaleAnimation::create(scrollTotal, activeTree()->total_page_scale_factor(), viewportSize, scaledScrollableSize, startTimeSeconds);
298 if (anchorPoint) {
299 gfx::Vector2dF anchor(targetOffset);
300 if (!m_settings.pageScalePinchZoomEnabled)
301 anchor.Scale(1 / pageScale);
302 m_pageScaleAnimation->zoomWithAnchor(anchor, pageScale, duration.InSecondsF());
303 } else {
304 gfx::Vector2dF scaledTargetOffset = targetOffset;
305 if (!m_settings.pageScalePinchZoomEnabled)
306 scaledTargetOffset.Scale(1 / pageScale);
307 m_pageScaleAnimation->zoomTo(scaledTargetOffset, pageScale, duration.InSecondsF());
310 m_client->setNeedsRedrawOnImplThread();
311 m_client->setNeedsCommitOnImplThread();
314 void LayerTreeHostImpl::scheduleAnimation()
316 m_client->setNeedsRedrawOnImplThread();
319 bool LayerTreeHostImpl::haveTouchEventHandlersAt(const gfx::Point& viewportPoint)
321 if (!ensureRenderSurfaceLayerList())
322 return false;
324 gfx::PointF deviceViewportPoint = gfx::ScalePoint(viewportPoint, m_deviceScaleFactor);
326 // First find out which layer was hit from the saved list of visible layers
327 // in the most recent frame.
328 LayerImpl* layerImpl = LayerTreeHostCommon::findLayerThatIsHitByPoint(deviceViewportPoint, activeTree()->RenderSurfaceLayerList());
330 // Walk up the hierarchy and look for a layer with a touch event handler region that the given point hits.
331 for (; layerImpl; layerImpl = layerImpl->parent()) {
332 if (LayerTreeHostCommon::layerHasTouchEventHandlersAt(deviceViewportPoint,layerImpl))
333 return true;
336 return false;
339 void LayerTreeHostImpl::trackDamageForAllSurfaces(LayerImpl* rootDrawLayer, const LayerList& renderSurfaceLayerList)
341 // For now, we use damage tracking to compute a global scissor. To do this, we must
342 // compute all damage tracking before drawing anything, so that we know the root
343 // damage rect. The root damage rect is then used to scissor each surface.
345 for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
346 LayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex];
347 RenderSurfaceImpl* renderSurface = renderSurfaceLayer->renderSurface();
348 DCHECK(renderSurface);
349 renderSurface->damageTracker()->updateDamageTrackingState(renderSurface->layerList(), renderSurfaceLayer->id(), renderSurface->surfacePropertyChangedOnlyFromDescendant(), renderSurface->contentRect(), renderSurfaceLayer->maskLayer(), renderSurfaceLayer->filters(), renderSurfaceLayer->filter().get());
353 void LayerTreeHostImpl::FrameData::appendRenderPass(scoped_ptr<RenderPass> renderPass)
355 renderPassesById[renderPass->id] = renderPass.get();
356 renderPasses.push_back(renderPass.Pass());
359 static void appendQuadsForLayer(RenderPass* targetRenderPass, LayerImpl* layer, OcclusionTrackerImpl& occlusionTracker, AppendQuadsData& appendQuadsData)
361 bool forSurface = false;
362 QuadCuller quadCuller(targetRenderPass->quad_list,
363 targetRenderPass->shared_quad_state_list,
364 layer,
365 occlusionTracker,
366 layer->showDebugBorders(),
367 forSurface);
368 layer->appendQuads(quadCuller, appendQuadsData);
371 static void appendQuadsForRenderSurfaceLayer(RenderPass* targetRenderPass, LayerImpl* layer, const RenderPass* contributingRenderPass, OcclusionTrackerImpl& occlusionTracker, AppendQuadsData& appendQuadsData)
373 bool forSurface = true;
374 QuadCuller quadCuller(targetRenderPass->quad_list,
375 targetRenderPass->shared_quad_state_list,
376 layer,
377 occlusionTracker,
378 layer->showDebugBorders(),
379 forSurface);
381 bool isReplica = false;
382 layer->renderSurface()->appendQuads(quadCuller,
383 appendQuadsData,
384 isReplica,
385 contributingRenderPass->id);
387 // Add replica after the surface so that it appears below the surface.
388 if (layer->hasReplica()) {
389 isReplica = true;
390 layer->renderSurface()->appendQuads(quadCuller,
391 appendQuadsData,
392 isReplica,
393 contributingRenderPass->id);
397 static void appendQuadsToFillScreen(RenderPass* targetRenderPass, LayerImpl* rootLayer, SkColor screenBackgroundColor, const OcclusionTrackerImpl& occlusionTracker)
399 if (!rootLayer || !SkColorGetA(screenBackgroundColor))
400 return;
402 Region fillRegion = occlusionTracker.computeVisibleRegionInScreen();
403 if (fillRegion.IsEmpty())
404 return;
406 bool forSurface = false;
407 QuadCuller quadCuller(targetRenderPass->quad_list,
408 targetRenderPass->shared_quad_state_list,
409 rootLayer,
410 occlusionTracker,
411 rootLayer->showDebugBorders(),
412 forSurface);
414 // Manually create the quad state for the gutter quads, as the root layer
415 // doesn't have any bounds and so can't generate this itself.
416 // FIXME: Make the gutter quads generated by the solid color layer (make it smarter about generating quads to fill unoccluded areas).
418 gfx::Rect rootTargetRect = rootLayer->renderSurface()->contentRect();
419 float opacity = 1;
420 SharedQuadState* sharedQuadState = quadCuller.useSharedQuadState(SharedQuadState::Create());
421 sharedQuadState->SetAll(rootLayer->drawTransform(),
422 rootTargetRect,
423 rootTargetRect,
424 false,
425 opacity);
427 AppendQuadsData appendQuadsData;
429 gfx::Transform transformToLayerSpace(gfx::Transform::kSkipInitialization);
430 bool didInvert = rootLayer->screenSpaceTransform().GetInverse(&transformToLayerSpace);
431 DCHECK(didInvert);
432 for (Region::Iterator fillRects(fillRegion); fillRects.has_rect(); fillRects.next()) {
433 // The root layer transform is composed of translations and scales only,
434 // no perspective, so mapping is sufficient (as opposed to projecting).
435 gfx::Rect layerRect = MathUtil::mapClippedRect(transformToLayerSpace, fillRects.rect());
436 // Skip the quad culler and just append the quads directly to avoid
437 // occlusion checks.
438 scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
439 quad->SetNew(sharedQuadState, layerRect, screenBackgroundColor);
440 quadCuller.append(quad.PassAs<DrawQuad>(), appendQuadsData);
444 bool LayerTreeHostImpl::calculateRenderPasses(FrameData& frame)
446 DCHECK(frame.renderPasses.empty());
448 if (!canDraw() || !rootLayer())
449 return false;
451 trackDamageForAllSurfaces(rootLayer(), *frame.renderSurfaceLayerList);
453 TRACE_EVENT1("cc", "LayerTreeHostImpl::calculateRenderPasses", "renderSurfaceLayerList.size()", static_cast<long long unsigned>(frame.renderSurfaceLayerList->size()));
455 // Create the render passes in dependency order.
456 for (int surfaceIndex = frame.renderSurfaceLayerList->size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
457 LayerImpl* renderSurfaceLayer = (*frame.renderSurfaceLayerList)[surfaceIndex];
458 renderSurfaceLayer->renderSurface()->appendRenderPasses(frame);
461 bool recordMetricsForFrame = m_settings.showOverdrawInTracing && base::debug::TraceLog::GetInstance() && base::debug::TraceLog::GetInstance()->IsEnabled();
462 OcclusionTrackerImpl occlusionTracker(rootLayer()->renderSurface()->contentRect(), recordMetricsForFrame);
463 occlusionTracker.setMinimumTrackingSize(m_settings.minimumOcclusionTrackingSize);
465 if (m_debugState.showOccludingRects)
466 occlusionTracker.setOccludingScreenSpaceRectsContainer(&frame.occludingScreenSpaceRects);
467 if (m_debugState.showNonOccludingRects)
468 occlusionTracker.setNonOccludingScreenSpaceRectsContainer(&frame.nonOccludingScreenSpaceRects);
470 // Add quads to the Render passes in FrontToBack order to allow for testing occlusion and performing culling during the tree walk.
471 typedef LayerIterator<LayerImpl, std::vector<LayerImpl*>, RenderSurfaceImpl, LayerIteratorActions::FrontToBack> LayerIteratorType;
473 // Typically when we are missing a texture and use a checkerboard quad, we still draw the frame. However when the layer being
474 // checkerboarded is moving due to an impl-animation, we drop the frame to avoid flashing due to the texture suddenly appearing
475 // in the future.
476 bool drawFrame = true;
478 LayerIteratorType end = LayerIteratorType::end(frame.renderSurfaceLayerList);
479 for (LayerIteratorType it = LayerIteratorType::begin(frame.renderSurfaceLayerList); it != end; ++it) {
480 RenderPass::Id targetRenderPassId = it.targetRenderSurfaceLayer()->renderSurface()->renderPassId();
481 RenderPass* targetRenderPass = frame.renderPassesById[targetRenderPassId];
483 occlusionTracker.enterLayer(it);
485 AppendQuadsData appendQuadsData(targetRenderPass->id);
487 if (it.representsContributingRenderSurface()) {
488 RenderPass::Id contributingRenderPassId = it->renderSurface()->renderPassId();
489 RenderPass* contributingRenderPass = frame.renderPassesById[contributingRenderPassId];
490 appendQuadsForRenderSurfaceLayer(targetRenderPass, *it, contributingRenderPass, occlusionTracker, appendQuadsData);
491 } else if (it.representsItself() && !it->visibleContentRect().IsEmpty()) {
492 bool hasOcclusionFromOutsideTargetSurface;
493 bool implDrawTransformIsUnknown = false;
494 if (occlusionTracker.occluded(it->renderTarget(), it->visibleContentRect(), it->drawTransform(), implDrawTransformIsUnknown, it->isClipped(), it->clipRect(), &hasOcclusionFromOutsideTargetSurface))
495 appendQuadsData.hadOcclusionFromOutsideTargetSurface |= hasOcclusionFromOutsideTargetSurface;
496 else {
497 DCHECK_EQ(activeTree(), it->layerTreeImpl());
498 it->willDraw(m_resourceProvider.get());
499 frame.willDrawLayers.push_back(*it);
501 if (it->hasContributingDelegatedRenderPasses()) {
502 RenderPass::Id contributingRenderPassId = it->firstContributingRenderPassId();
503 while (frame.renderPassesById.find(contributingRenderPassId) != frame.renderPassesById.end()) {
504 RenderPass* renderPass = frame.renderPassesById[contributingRenderPassId];
506 AppendQuadsData appendQuadsData(renderPass->id);
507 appendQuadsForLayer(renderPass, *it, occlusionTracker, appendQuadsData);
509 contributingRenderPassId = it->nextContributingRenderPassId(contributingRenderPassId);
513 appendQuadsForLayer(targetRenderPass, *it, occlusionTracker, appendQuadsData);
516 ++m_cumulativeNumLayersDrawn;
519 if (appendQuadsData.hadOcclusionFromOutsideTargetSurface)
520 targetRenderPass->has_occlusion_from_outside_target_surface = true;
522 if (appendQuadsData.numMissingTiles) {
523 m_cumulativeNumMissingTiles += appendQuadsData.numMissingTiles;
524 bool layerHasAnimatingTransform = it->screenSpaceTransformIsAnimating() || it->drawTransformIsAnimating();
525 if (layerHasAnimatingTransform)
526 drawFrame = false;
529 if (appendQuadsData.hadIncompleteTile)
530 frame.containsIncompleteTile = true;
532 occlusionTracker.leaveLayer(it);
535 #ifndef NDEBUG
536 for (size_t i = 0; i < frame.renderPasses.size(); ++i) {
537 for (size_t j = 0; j < frame.renderPasses[i]->quad_list.size(); ++j)
538 DCHECK(frame.renderPasses[i]->quad_list[j]->shared_quad_state);
539 DCHECK(frame.renderPassesById.find(frame.renderPasses[i]->id)
540 != frame.renderPassesById.end());
542 #endif
543 DCHECK(frame.renderPasses.back()->output_rect.origin().IsOrigin());
545 if (!activeTree()->has_transparent_background()) {
546 frame.renderPasses.back()->has_transparent_background = false;
547 appendQuadsToFillScreen(frame.renderPasses.back(), rootLayer(), activeTree()->background_color(), occlusionTracker);
550 if (drawFrame)
551 occlusionTracker.overdrawMetrics().recordMetrics(this);
553 removeRenderPasses(CullRenderPassesWithNoQuads(), frame);
554 m_renderer->decideRenderPassAllocationsForFrame(frame.renderPasses);
555 removeRenderPasses(CullRenderPassesWithCachedTextures(*m_renderer), frame);
557 return drawFrame;
560 void LayerTreeHostImpl::setBackgroundTickingEnabled(bool enabled)
562 // Lazily create the timeSource adapter so that we can vary the interval for testing.
563 if (!m_timeSourceClientAdapter)
564 m_timeSourceClientAdapter = LayerTreeHostImplTimeSourceAdapter::create(this, DelayBasedTimeSource::create(lowFrequencyAnimationInterval(), m_proxy->currentThread()));
566 m_timeSourceClientAdapter->setActive(enabled);
569 static inline RenderPass* findRenderPassById(RenderPass::Id renderPassId, const LayerTreeHostImpl::FrameData& frame)
571 RenderPassIdHashMap::const_iterator it = frame.renderPassesById.find(renderPassId);
572 return it != frame.renderPassesById.end() ? it->second : NULL;
575 static void removeRenderPassesRecursive(RenderPass::Id removeRenderPassId, LayerTreeHostImpl::FrameData& frame)
577 RenderPass* removeRenderPass = findRenderPassById(removeRenderPassId, frame);
578 // The pass was already removed by another quad - probably the original, and we are the replica.
579 if (!removeRenderPass)
580 return;
581 RenderPassList& renderPasses = frame.renderPasses;
582 RenderPassList::iterator toRemove = std::find(renderPasses.begin(), renderPasses.end(), removeRenderPass);
584 DCHECK(toRemove != renderPasses.end());
586 scoped_ptr<RenderPass> removedPass = renderPasses.take(toRemove);
587 frame.renderPasses.erase(toRemove);
588 frame.renderPassesById.erase(removeRenderPassId);
590 // Now follow up for all RenderPass quads and remove their RenderPasses recursively.
591 const QuadList& quadList = removedPass->quad_list;
592 QuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin();
593 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) {
594 DrawQuad* currentQuad = (*quadListIterator);
595 if (currentQuad->material != DrawQuad::RENDER_PASS)
596 continue;
598 RenderPass::Id nextRemoveRenderPassId = RenderPassDrawQuad::MaterialCast(currentQuad)->render_pass_id;
599 removeRenderPassesRecursive(nextRemoveRenderPassId, frame);
603 bool LayerTreeHostImpl::CullRenderPassesWithCachedTextures::shouldRemoveRenderPass(const RenderPassDrawQuad& quad, const FrameData&) const
605 if (!quad.contents_changed_since_last_frame.IsEmpty()) {
606 TRACE_EVENT0("cc", "CullRenderPassesWithCachedTextures have damage");
607 return false;
608 } else if (!m_renderer.haveCachedResourcesForRenderPassId(quad.render_pass_id)) {
609 TRACE_EVENT0("cc", "CullRenderPassesWithCachedTextures have no texture");
610 return false;
612 TRACE_EVENT0("cc", "CullRenderPassesWithCachedTextures dropped!");
613 return true;
616 bool LayerTreeHostImpl::CullRenderPassesWithNoQuads::shouldRemoveRenderPass(const RenderPassDrawQuad& quad, const FrameData& frame) const
618 const RenderPass* renderPass = findRenderPassById(quad.render_pass_id, frame);
619 if (!renderPass)
620 return false;
622 // If any quad or RenderPass draws into this RenderPass, then keep it.
623 const QuadList& quadList = renderPass->quad_list;
624 for (QuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin(); quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) {
625 DrawQuad* currentQuad = *quadListIterator;
627 if (currentQuad->material != DrawQuad::RENDER_PASS)
628 return false;
630 const RenderPass* contributingPass = findRenderPassById(RenderPassDrawQuad::MaterialCast(currentQuad)->render_pass_id, frame);
631 if (contributingPass)
632 return false;
634 return true;
637 // Defined for linking tests.
638 template CC_EXPORT void LayerTreeHostImpl::removeRenderPasses<LayerTreeHostImpl::CullRenderPassesWithCachedTextures>(CullRenderPassesWithCachedTextures, FrameData&);
639 template CC_EXPORT void LayerTreeHostImpl::removeRenderPasses<LayerTreeHostImpl::CullRenderPassesWithNoQuads>(CullRenderPassesWithNoQuads, FrameData&);
641 // static
642 template<typename RenderPassCuller>
643 void LayerTreeHostImpl::removeRenderPasses(RenderPassCuller culler, FrameData& frame)
645 for (size_t it = culler.renderPassListBegin(frame.renderPasses); it != culler.renderPassListEnd(frame.renderPasses); it = culler.renderPassListNext(it)) {
646 const RenderPass* currentPass = frame.renderPasses[it];
647 const QuadList& quadList = currentPass->quad_list;
648 QuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin();
650 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) {
651 DrawQuad* currentQuad = *quadListIterator;
653 if (currentQuad->material != DrawQuad::RENDER_PASS)
654 continue;
656 RenderPassDrawQuad* renderPassQuad = static_cast<RenderPassDrawQuad*>(currentQuad);
657 if (!culler.shouldRemoveRenderPass(*renderPassQuad, frame))
658 continue;
660 // We are changing the vector in the middle of iteration. Because we
661 // delete render passes that draw into the current pass, we are
662 // guaranteed that any data from the iterator to the end will not
663 // change. So, capture the iterator position from the end of the
664 // list, and restore it after the change.
665 int positionFromEnd = frame.renderPasses.size() - it;
666 removeRenderPassesRecursive(renderPassQuad->render_pass_id, frame);
667 it = frame.renderPasses.size() - positionFromEnd;
668 DCHECK(it >= 0);
673 bool LayerTreeHostImpl::prepareToDraw(FrameData& frame)
675 TRACE_EVENT0("cc", "LayerTreeHostImpl::prepareToDraw");
677 activeTree()->UpdateDrawProperties(LayerTreeImpl::UPDATE_ACTIVE_TREE_FOR_DRAW);
679 frame.renderSurfaceLayerList = &activeTree()->RenderSurfaceLayerList();
680 frame.renderPasses.clear();
681 frame.renderPassesById.clear();
682 frame.willDrawLayers.clear();
684 if (!calculateRenderPasses(frame))
685 return false;
687 // If we return true, then we expect drawLayers() to be called before this function is called again.
688 return true;
691 void LayerTreeHostImpl::enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy)
693 bool evictedResources = m_client->reduceContentsTextureMemoryOnImplThread(
694 m_visible ? policy.bytesLimitWhenVisible : policy.bytesLimitWhenNotVisible,
695 ManagedMemoryPolicy::priorityCutoffToValue(
696 m_visible ? policy.priorityCutoffWhenVisible : policy.priorityCutoffWhenNotVisible));
697 if (evictedResources) {
698 activeTree()->SetContentsTexturesPurged();
699 if (pendingTree())
700 pendingTree()->SetContentsTexturesPurged();
701 m_client->setNeedsCommitOnImplThread();
702 m_client->onCanDrawStateChanged(canDraw());
703 m_client->renewTreePriority();
705 m_client->sendManagedMemoryStats();
707 if (m_tileManager) {
708 GlobalStateThatImpactsTilePriority new_state(m_tileManager->GlobalState());
709 new_state.memory_limit_in_bytes = m_visible ? policy.bytesLimitWhenVisible : policy.bytesLimitWhenNotVisible;
710 new_state.memory_limit_policy = ManagedMemoryPolicy::priorityCutoffToTileMemoryLimitPolicy(
711 m_visible ? policy.priorityCutoffWhenVisible : policy.priorityCutoffWhenNotVisible);
712 m_tileManager->SetGlobalState(new_state);
716 bool LayerTreeHostImpl::hasImplThread() const
718 return m_proxy->hasImplThread();
721 void LayerTreeHostImpl::ScheduleManageTiles()
723 if (m_client)
724 m_client->setNeedsManageTilesOnImplThread();
727 void LayerTreeHostImpl::DidUploadVisibleHighResolutionTile()
729 if (m_client)
730 m_client->didUploadVisibleHighResolutionTileOnImplThread();
733 bool LayerTreeHostImpl::shouldClearRootRenderPass() const
735 return m_settings.shouldClearRootRenderPass;
738 void LayerTreeHostImpl::setManagedMemoryPolicy(const ManagedMemoryPolicy& policy)
740 if (m_managedMemoryPolicy == policy)
741 return;
743 m_managedMemoryPolicy = policy;
744 if (!m_proxy->hasImplThread()) {
745 // FIXME: In single-thread mode, this can be called on the main thread
746 // by GLRenderer::onMemoryAllocationChanged.
747 DebugScopedSetImplThread implThread(m_proxy);
748 enforceManagedMemoryPolicy(m_managedMemoryPolicy);
749 } else {
750 DCHECK(m_proxy->isImplThread());
751 enforceManagedMemoryPolicy(m_managedMemoryPolicy);
753 // We always need to commit after changing the memory policy because the new
754 // limit can result in more or less content having texture allocated for it.
755 m_client->setNeedsCommitOnImplThread();
758 void LayerTreeHostImpl::OnVSyncParametersChanged(base::TimeTicks timebase, base::TimeDelta interval)
760 m_client->onVSyncParametersChanged(timebase, interval);
763 void LayerTreeHostImpl::OnSendFrameToParentCompositorAck(const CompositorFrameAck& ack)
765 if (!m_renderer)
766 return;
768 // TODO(piman): We may need to do some validation on this ack before processing it.
769 m_renderer->receiveCompositorFrameAck(ack);
772 void LayerTreeHostImpl::OnCanDrawStateChangedForTree(LayerTreeImpl*)
774 m_client->onCanDrawStateChanged(canDraw());
777 CompositorFrameMetadata LayerTreeHostImpl::makeCompositorFrameMetadata() const
779 CompositorFrameMetadata metadata;
780 metadata.page_scale_factor = activeTree()->total_page_scale_factor();
781 metadata.viewport_size = activeTree()->ScrollableViewportSize();
782 metadata.root_layer_size = activeTree()->ScrollableSize();
783 metadata.min_page_scale_factor = activeTree()->min_page_scale_factor();
784 metadata.max_page_scale_factor = activeTree()->max_page_scale_factor();
785 if (m_topControlsManager) {
786 metadata.location_bar_offset = gfx::Vector2dF(0.f, m_topControlsManager->controls_top_offset());
787 metadata.location_bar_content_translation = gfx::Vector2dF(0.f, m_topControlsManager->content_top_offset());
790 if (!rootScrollLayer())
791 return metadata;
793 metadata.root_scroll_offset = rootScrollLayer()->scrollOffset() + rootScrollLayer()->scrollDelta();
794 if (!m_settings.pageScalePinchZoomEnabled)
795 metadata.root_scroll_offset.Scale(1 / activeTree()->page_scale_factor());
797 return metadata;
800 void LayerTreeHostImpl::drawLayers(FrameData& frame)
802 TRACE_EVENT0("cc", "LayerTreeHostImpl::drawLayers");
803 DCHECK(canDraw());
804 DCHECK(!frame.renderPasses.empty());
806 // FIXME: use the frame begin time from the overall compositor scheduler.
807 // This value is currently inaccessible because it is up in Chromium's
808 // RenderWidget.
809 m_fpsCounter->saveTimeStamp(base::TimeTicks::Now());
811 if (m_tileManager) {
812 m_memoryHistory->SaveEntry(
813 m_tileManager->memory_stats_from_last_assign());
816 if (m_debugState.showHudRects())
817 m_debugRectHistory->saveDebugRectsForCurrentFrame(rootLayer(), *frame.renderSurfaceLayerList, frame.occludingScreenSpaceRects, frame.nonOccludingScreenSpaceRects, m_debugState);
819 if (m_debugState.traceAllRenderedFrames) {
820 TRACE_EVENT_INSTANT1("cc.debug", "Frame",
821 "frame", ValueToString(frameStateAsValue()));
824 // Because the contents of the HUD depend on everything else in the frame, the contents
825 // of its texture are updated as the last thing before the frame is drawn.
826 if (m_activeTree->hud_layer())
827 m_activeTree->hud_layer()->updateHudTexture(m_resourceProvider.get());
829 m_renderer->drawFrame(frame.renderPasses);
830 // The render passes should be consumed by the renderer.
831 DCHECK(frame.renderPasses.empty());
832 frame.renderPassesById.clear();
834 // The next frame should start by assuming nothing has changed, and changes are noted as they occur.
835 for (unsigned int i = 0; i < frame.renderSurfaceLayerList->size(); i++)
836 (*frame.renderSurfaceLayerList)[i]->renderSurface()->damageTracker()->didDrawDamagedArea();
837 rootLayer()->resetAllChangeTrackingForSubtree();
838 updateAnimationState();
841 void LayerTreeHostImpl::didDrawAllLayers(const FrameData& frame)
843 for (size_t i = 0; i < frame.willDrawLayers.size(); ++i)
844 frame.willDrawLayers[i]->didDraw(m_resourceProvider.get());
846 // Once all layers have been drawn, pending texture uploads should no
847 // longer block future uploads.
848 m_resourceProvider->markPendingUploadsAsNonBlocking();
851 void LayerTreeHostImpl::finishAllRendering()
853 if (m_renderer)
854 m_renderer->finish();
857 bool LayerTreeHostImpl::isContextLost()
859 DCHECK(m_proxy->isImplThread());
860 return m_renderer && m_renderer->isContextLost();
863 const RendererCapabilities& LayerTreeHostImpl::rendererCapabilities() const
865 return m_renderer->capabilities();
868 bool LayerTreeHostImpl::swapBuffers()
870 return m_renderer->swapBuffers();
873 const gfx::Size& LayerTreeHostImpl::deviceViewportSize() const
875 return m_deviceViewportSize;
878 const LayerTreeSettings& LayerTreeHostImpl::settings() const
880 return m_settings;
883 void LayerTreeHostImpl::didLoseOutputSurface()
885 m_client->didLoseOutputSurfaceOnImplThread();
888 void LayerTreeHostImpl::onSwapBuffersComplete()
890 m_client->onSwapBuffersCompleteOnImplThread();
893 void LayerTreeHostImpl::readback(void* pixels, const gfx::Rect& rect)
895 DCHECK(m_renderer);
896 m_renderer->getFramebufferPixels(pixels, rect);
899 bool LayerTreeHostImpl::haveRootScrollLayer() const {
900 return rootScrollLayer();
903 float LayerTreeHostImpl::rootScrollLayerTotalScrollY() const {
904 if (LayerImpl* layer = rootScrollLayer())
905 return layer->scrollOffset().y() + layer->scrollDelta().y();
906 return 0.0f;
909 LayerImpl* LayerTreeHostImpl::rootLayer() const
911 return m_activeTree->RootLayer();
914 LayerImpl* LayerTreeHostImpl::rootScrollLayer() const
916 return m_activeTree->RootScrollLayer();
919 LayerImpl* LayerTreeHostImpl::currentlyScrollingLayer() const
921 return m_activeTree->CurrentlyScrollingLayer();
924 // Content layers can be either directly scrollable or contained in an outer
925 // scrolling layer which applies the scroll transform. Given a content layer,
926 // this function returns the associated scroll layer if any.
927 static LayerImpl* findScrollLayerForContentLayer(LayerImpl* layerImpl)
929 if (!layerImpl)
930 return 0;
932 if (layerImpl->scrollable())
933 return layerImpl;
935 if (layerImpl->drawsContent() && layerImpl->parent() && layerImpl->parent()->scrollable())
936 return layerImpl->parent();
938 return 0;
941 void LayerTreeHostImpl::createPendingTree()
943 CHECK(!m_pendingTree);
944 if (m_recycleTree)
945 m_recycleTree.swap(m_pendingTree);
946 else
947 m_pendingTree = LayerTreeImpl::create(this);
948 m_client->onCanDrawStateChanged(canDraw());
949 m_client->onHasPendingTreeStateChanged(pendingTree());
950 TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree", m_pendingTree.get());
951 TRACE_EVENT_ASYNC_STEP0("cc",
952 "PendingTree", m_pendingTree.get(), "waiting");
955 void LayerTreeHostImpl::checkForCompletedTileUploads()
957 DCHECK(!m_client->isInsideDraw()) << "Checking for completed uploads within a draw may trigger spurious redraws.";
958 if (m_tileManager)
959 m_tileManager->CheckForCompletedTileUploads();
962 void LayerTreeHostImpl::activatePendingTreeIfNeeded()
964 if (!pendingTree())
965 return;
967 CHECK(m_tileManager);
969 pendingTree()->UpdateDrawProperties(LayerTreeImpl::UPDATE_PENDING_TREE);
971 TRACE_EVENT_ASYNC_STEP1("cc",
972 "PendingTree", m_pendingTree.get(), "activate",
973 "state", ValueToString(activationStateAsValue()));
975 // It's always fine to activate to an empty tree. Otherwise, only
976 // activate once all visible resources in pending tree are ready
977 // or tile manager has no work scheduled for pending tree.
978 if (activeTree()->RootLayer() &&
979 !pendingTree()->AreVisibleResourcesReady()) {
980 // In smoothness takes priority mode, the pending tree's priorities are
981 // ignored, so the tile manager may not have work for it even though it
982 // is simultaneously not ready to be activated.
983 if (m_tileManager->GlobalState().tree_priority ==
984 SMOOTHNESS_TAKES_PRIORITY ||
985 m_tileManager->HasPendingWorkScheduled(PENDING_TREE)) {
986 TRACE_EVENT_ASYNC_STEP0("cc",
987 "PendingTree",
988 m_pendingTree.get(),
989 "waiting");
990 return;
994 activatePendingTree();
997 void LayerTreeHostImpl::activatePendingTree()
999 CHECK(m_pendingTree);
1000 TRACE_EVENT_ASYNC_END0("cc", "PendingTree", m_pendingTree.get());
1002 m_activeTree->PushPersistedState(m_pendingTree.get());
1003 if (m_pendingTree->needs_full_tree_sync())
1004 m_activeTree->SetRootLayer(TreeSynchronizer::synchronizeTrees(m_pendingTree->RootLayer(), m_activeTree->DetachLayerTree(), m_activeTree.get()));
1005 TreeSynchronizer::pushProperties(m_pendingTree->RootLayer(), m_activeTree->RootLayer());
1006 DCHECK(!m_recycleTree);
1008 m_pendingTree->pushPropertiesTo(m_activeTree.get());
1010 // Now that we've synced everything from the pending tree to the active
1011 // tree, rename the pending tree the recycle tree so we can reuse it on the
1012 // next sync.
1013 m_pendingTree.swap(m_recycleTree);
1014 m_recycleTree->ClearRenderSurfaces();
1016 m_activeTree->DidBecomeActive();
1018 // Reduce wasted memory now that unlinked resources are guaranteed not
1019 // to be used.
1020 m_client->reduceWastedContentsTextureMemoryOnImplThread();
1022 m_client->onCanDrawStateChanged(canDraw());
1023 m_client->onHasPendingTreeStateChanged(pendingTree());
1024 m_client->setNeedsRedrawOnImplThread();
1025 m_client->renewTreePriority();
1028 void LayerTreeHostImpl::setVisible(bool visible)
1030 DCHECK(m_proxy->isImplThread());
1032 if (m_visible == visible)
1033 return;
1034 m_visible = visible;
1035 didVisibilityChange(this, m_visible);
1036 enforceManagedMemoryPolicy(m_managedMemoryPolicy);
1038 if (!m_renderer)
1039 return;
1041 m_renderer->setVisible(visible);
1043 setBackgroundTickingEnabled(!m_visible && !m_animationRegistrar->active_animation_controllers().empty());
1046 bool LayerTreeHostImpl::initializeRenderer(scoped_ptr<OutputSurface> outputSurface)
1048 // Since we will create a new resource provider, we cannot continue to use
1049 // the old resources (i.e. renderSurfaces and texture IDs). Clear them
1050 // before we destroy the old resource provider.
1051 if (rootLayer())
1052 clearRenderSurfaces();
1053 if (activeTree()->RootLayer())
1054 sendDidLoseOutputSurfaceRecursive(activeTree()->RootLayer());
1055 if (pendingTree() && pendingTree()->RootLayer())
1056 sendDidLoseOutputSurfaceRecursive(pendingTree()->RootLayer());
1057 if (m_recycleTree && m_recycleTree->RootLayer())
1058 sendDidLoseOutputSurfaceRecursive(m_recycleTree->RootLayer());
1060 // Note: order is important here.
1061 m_renderer.reset();
1062 m_tileManager.reset();
1063 m_resourceProvider.reset();
1064 m_outputSurface.reset();
1066 if (!outputSurface->BindToClient(this))
1067 return false;
1069 scoped_ptr<ResourceProvider> resourceProvider = ResourceProvider::create(outputSurface.get());
1070 if (!resourceProvider)
1071 return false;
1073 if (m_settings.implSidePainting) {
1074 m_tileManager.reset(new TileManager(this, resourceProvider.get(), m_settings.numRasterThreads, m_settings.useCheapnessEstimator));
1075 m_tileManager->SetRecordRenderingStats(m_debugState.recordRenderingStats());
1078 if (outputSurface->capabilities().has_parent_compositor)
1079 m_renderer = DelegatingRenderer::Create(this, outputSurface.get(), resourceProvider.get());
1080 else if (outputSurface->context3d())
1081 m_renderer = GLRenderer::create(this, outputSurface.get(), resourceProvider.get());
1082 else if (outputSurface->software_device())
1083 m_renderer = SoftwareRenderer::create(this, resourceProvider.get(), outputSurface->software_device());
1084 if (!m_renderer)
1085 return false;
1087 m_resourceProvider = resourceProvider.Pass();
1088 m_outputSurface = outputSurface.Pass();
1090 if (!m_visible)
1091 m_renderer->setVisible(m_visible);
1093 m_client->onCanDrawStateChanged(canDraw());
1095 // See note in LayerTreeImpl::UpdateDrawProperties. Renderer needs
1096 // to be initialized to get max texture size.
1097 activeTree()->set_needs_update_draw_properties();
1098 if (pendingTree())
1099 pendingTree()->set_needs_update_draw_properties();
1101 return true;
1104 void LayerTreeHostImpl::setViewportSize(const gfx::Size& layoutViewportSize, const gfx::Size& deviceViewportSize)
1106 if (layoutViewportSize == m_layoutViewportSize && deviceViewportSize == m_deviceViewportSize)
1107 return;
1109 if (pendingTree() && m_deviceViewportSize != deviceViewportSize)
1110 activeTree()->SetViewportSizeInvalid();
1112 m_layoutViewportSize = layoutViewportSize;
1113 m_deviceViewportSize = deviceViewportSize;
1115 updateMaxScrollOffset();
1117 if (m_renderer)
1118 m_renderer->viewportChanged();
1120 m_client->onCanDrawStateChanged(canDraw());
1123 static void adjustScrollsForPageScaleChange(LayerImpl* layerImpl, float pageScaleChange)
1125 if (!layerImpl)
1126 return;
1128 if (layerImpl->scrollable()) {
1129 // We need to convert impl-side scroll deltas to pageScale space.
1130 gfx::Vector2dF scrollDelta = layerImpl->scrollDelta();
1131 scrollDelta.Scale(pageScaleChange);
1132 layerImpl->setScrollDelta(scrollDelta);
1135 for (size_t i = 0; i < layerImpl->children().size(); ++i)
1136 adjustScrollsForPageScaleChange(layerImpl->children()[i], pageScaleChange);
1139 void LayerTreeHostImpl::setDeviceScaleFactor(float deviceScaleFactor)
1141 if (deviceScaleFactor == m_deviceScaleFactor)
1142 return;
1143 m_deviceScaleFactor = deviceScaleFactor;
1145 updateMaxScrollOffset();
1148 void LayerTreeHostImpl::updateMaxScrollOffset()
1150 activeTree()->UpdateMaxScrollOffset();
1153 void LayerTreeHostImpl::setActiveTreeNeedsUpdateDrawProperties()
1155 activeTree()->set_needs_update_draw_properties();
1158 void LayerTreeHostImpl::setNeedsRedraw()
1160 m_client->setNeedsRedrawOnImplThread();
1163 bool LayerTreeHostImpl::ensureRenderSurfaceLayerList()
1165 activeTree()->UpdateDrawProperties(LayerTreeImpl::UPDATE_ACTIVE_TREE);
1166 return activeTree()->RenderSurfaceLayerList().size();
1169 InputHandlerClient::ScrollStatus LayerTreeHostImpl::scrollBegin(gfx::Point viewportPoint, InputHandlerClient::ScrollInputType type)
1171 TRACE_EVENT0("cc", "LayerTreeHostImpl::scrollBegin");
1173 if (m_topControlsManager)
1174 m_topControlsManager->ScrollBegin();
1176 DCHECK(!currentlyScrollingLayer());
1177 clearCurrentlyScrollingLayer();
1179 if (!ensureRenderSurfaceLayerList())
1180 return ScrollIgnored;
1182 gfx::PointF deviceViewportPoint = gfx::ScalePoint(viewportPoint, m_deviceScaleFactor);
1184 // First find out which layer was hit from the saved list of visible layers
1185 // in the most recent frame.
1186 LayerImpl* layerImpl = LayerTreeHostCommon::findLayerThatIsHitByPoint(deviceViewportPoint, activeTree()->RenderSurfaceLayerList());
1188 // Walk up the hierarchy and look for a scrollable layer.
1189 LayerImpl* potentiallyScrollingLayerImpl = 0;
1190 for (; layerImpl; layerImpl = layerImpl->parent()) {
1191 // The content layer can also block attempts to scroll outside the main thread.
1192 if (layerImpl->tryScroll(deviceViewportPoint, type) == ScrollOnMainThread) {
1193 m_numMainThreadScrolls++;
1194 UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", true);
1195 return ScrollOnMainThread;
1198 LayerImpl* scrollLayerImpl = findScrollLayerForContentLayer(layerImpl);
1199 if (!scrollLayerImpl)
1200 continue;
1202 ScrollStatus status = scrollLayerImpl->tryScroll(deviceViewportPoint, type);
1204 // If any layer wants to divert the scroll event to the main thread, abort.
1205 if (status == ScrollOnMainThread) {
1206 m_numMainThreadScrolls++;
1207 UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", true);
1208 return ScrollOnMainThread;
1211 if (status == ScrollStarted && !potentiallyScrollingLayerImpl)
1212 potentiallyScrollingLayerImpl = scrollLayerImpl;
1215 if (potentiallyScrollingLayerImpl) {
1216 m_activeTree->set_currently_scrolling_layer(potentiallyScrollingLayerImpl);
1217 m_shouldBubbleScrolls = (type != NonBubblingGesture);
1218 m_wheelScrolling = (type == Wheel);
1219 m_numImplThreadScrolls++;
1220 m_client->renewTreePriority();
1221 UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", false);
1222 return ScrollStarted;
1224 return ScrollIgnored;
1227 gfx::Vector2dF LayerTreeHostImpl::scrollLayerWithViewportSpaceDelta(LayerImpl* layerImpl, float scaleFromViewportToScreenSpace, gfx::PointF viewportPoint, gfx::Vector2dF viewportDelta)
1229 // Layers with non-invertible screen space transforms should not have passed the scroll hit
1230 // test in the first place.
1231 DCHECK(layerImpl->screenSpaceTransform().IsInvertible());
1232 gfx::Transform inverseScreenSpaceTransform(gfx::Transform::kSkipInitialization);
1233 bool didInvert = layerImpl->screenSpaceTransform().GetInverse(&inverseScreenSpaceTransform);
1234 // TODO: With the advent of impl-side crolling for non-root layers, we may
1235 // need to explicitly handle uninvertible transforms here.
1236 DCHECK(didInvert);
1238 gfx::PointF screenSpacePoint = gfx::ScalePoint(viewportPoint, scaleFromViewportToScreenSpace);
1240 gfx::Vector2dF screenSpaceDelta = viewportDelta;
1241 screenSpaceDelta.Scale(scaleFromViewportToScreenSpace);
1243 // First project the scroll start and end points to local layer space to find the scroll delta
1244 // in layer coordinates.
1245 bool startClipped, endClipped;
1246 gfx::PointF screenSpaceEndPoint = screenSpacePoint + screenSpaceDelta;
1247 gfx::PointF localStartPoint = MathUtil::projectPoint(inverseScreenSpaceTransform, screenSpacePoint, startClipped);
1248 gfx::PointF localEndPoint = MathUtil::projectPoint(inverseScreenSpaceTransform, screenSpaceEndPoint, endClipped);
1250 // In general scroll point coordinates should not get clipped.
1251 DCHECK(!startClipped);
1252 DCHECK(!endClipped);
1253 if (startClipped || endClipped)
1254 return gfx::Vector2dF();
1256 // localStartPoint and localEndPoint are in content space but we want to move them to layer space for scrolling.
1257 float widthScale = 1 / layerImpl->contentsScaleX();
1258 float heightScale = 1 / layerImpl->contentsScaleY();
1259 localStartPoint.Scale(widthScale, heightScale);
1260 localEndPoint.Scale(widthScale, heightScale);
1262 // Apply the scroll delta.
1263 gfx::Vector2dF previousDelta = layerImpl->scrollDelta();
1264 layerImpl->scrollBy(localEndPoint - localStartPoint);
1266 // Get the end point in the layer's content space so we can apply its screenSpaceTransform.
1267 gfx::PointF actualLocalEndPoint = localStartPoint + layerImpl->scrollDelta() - previousDelta;
1268 gfx::PointF actualLocalContentEndPoint = gfx::ScalePoint(actualLocalEndPoint, 1 / widthScale, 1 / heightScale);
1270 // Calculate the applied scroll delta in viewport space coordinates.
1271 gfx::PointF actualScreenSpaceEndPoint = MathUtil::mapPoint(layerImpl->screenSpaceTransform(), actualLocalContentEndPoint, endClipped);
1272 DCHECK(!endClipped);
1273 if (endClipped)
1274 return gfx::Vector2dF();
1275 gfx::PointF actualViewportEndPoint = gfx::ScalePoint(actualScreenSpaceEndPoint, 1 / scaleFromViewportToScreenSpace);
1276 return actualViewportEndPoint - viewportPoint;
1279 static gfx::Vector2dF scrollLayerWithLocalDelta(LayerImpl& layerImpl, gfx::Vector2dF localDelta)
1281 gfx::Vector2dF previousDelta(layerImpl.scrollDelta());
1282 layerImpl.scrollBy(localDelta);
1283 return layerImpl.scrollDelta() - previousDelta;
1286 bool LayerTreeHostImpl::scrollBy(const gfx::Point& viewportPoint,
1287 const gfx::Vector2d& scrollDelta)
1289 TRACE_EVENT0("cc", "LayerTreeHostImpl::scrollBy");
1290 if (!currentlyScrollingLayer())
1291 return false;
1293 gfx::Vector2dF pendingDelta = scrollDelta;
1294 bool didScroll = false;
1296 for (LayerImpl* layerImpl = currentlyScrollingLayer(); layerImpl; layerImpl = layerImpl->parent()) {
1297 if (!layerImpl->scrollable())
1298 continue;
1300 gfx::Vector2dF appliedDelta;
1301 if (m_topControlsManager && layerImpl == rootScrollLayer())
1302 pendingDelta = m_topControlsManager->ScrollBy(pendingDelta);
1304 // Gesture events need to be transformed from viewport coordinates to local layer coordinates
1305 // so that the scrolling contents exactly follow the user's finger. In contrast, wheel
1306 // events represent a fixed amount of scrolling so we can just apply them directly.
1307 if (!m_wheelScrolling) {
1308 float scaleFromViewportToScreenSpace = m_deviceScaleFactor;
1309 appliedDelta = scrollLayerWithViewportSpaceDelta(layerImpl, scaleFromViewportToScreenSpace, viewportPoint, pendingDelta);
1310 } else
1311 appliedDelta = scrollLayerWithLocalDelta(*layerImpl, pendingDelta);
1313 // If the layer wasn't able to move, try the next one in the hierarchy.
1314 float moveThresholdSquared = 0.1f * 0.1f;
1315 if (appliedDelta.LengthSquared() < moveThresholdSquared) {
1316 if (m_shouldBubbleScrolls || !m_didLockScrollingLayer)
1317 continue;
1318 else
1319 break;
1321 didScroll = true;
1322 m_didLockScrollingLayer = true;
1323 if (!m_shouldBubbleScrolls) {
1324 m_activeTree->set_currently_scrolling_layer(layerImpl);
1325 break;
1328 // If the applied delta is within 45 degrees of the input delta, bail out to make it easier
1329 // to scroll just one layer in one direction without affecting any of its parents.
1330 float angleThreshold = 45;
1331 if (MathUtil::smallestAngleBetweenVectors(appliedDelta, pendingDelta) < angleThreshold) {
1332 pendingDelta = gfx::Vector2d();
1333 break;
1336 // Allow further movement only on an axis perpendicular to the direction in which the layer
1337 // moved.
1338 gfx::Vector2dF perpendicularAxis(-appliedDelta.y(), appliedDelta.x());
1339 pendingDelta = MathUtil::projectVector(pendingDelta, perpendicularAxis);
1341 if (gfx::ToFlooredVector2d(pendingDelta).IsZero())
1342 break;
1345 if (didScroll) {
1346 m_client->setNeedsCommitOnImplThread();
1347 m_client->setNeedsRedrawOnImplThread();
1348 m_client->renewTreePriority();
1350 return didScroll;
1353 void LayerTreeHostImpl::clearCurrentlyScrollingLayer()
1355 m_activeTree->ClearCurrentlyScrollingLayer();
1356 m_didLockScrollingLayer = false;
1359 void LayerTreeHostImpl::scrollEnd()
1361 if (m_topControlsManager)
1362 m_topControlsManager->ScrollEnd();
1363 clearCurrentlyScrollingLayer();
1366 void LayerTreeHostImpl::pinchGestureBegin()
1368 m_pinchGestureActive = true;
1369 m_previousPinchAnchor = gfx::Point();
1370 m_client->renewTreePriority();
1373 void LayerTreeHostImpl::pinchGestureUpdate(float magnifyDelta, gfx::Point anchor)
1375 TRACE_EVENT0("cc", "LayerTreeHostImpl::pinchGestureUpdate");
1377 if (!rootScrollLayer())
1378 return;
1380 // Keep the center-of-pinch anchor specified by (x, y) in a stable
1381 // position over the course of the magnify.
1382 float pageScaleDelta = activeTree()->page_scale_delta();
1383 gfx::PointF previousScaleAnchor = gfx::ScalePoint(anchor, 1 / pageScaleDelta);
1384 activeTree()->SetPageScaleDelta(pageScaleDelta * magnifyDelta);
1385 pageScaleDelta = activeTree()->page_scale_delta();
1386 gfx::PointF newScaleAnchor = gfx::ScalePoint(anchor, 1 / pageScaleDelta);
1387 gfx::Vector2dF move = previousScaleAnchor - newScaleAnchor;
1389 m_previousPinchAnchor = anchor;
1391 if (m_settings.pageScalePinchZoomEnabled)
1392 move.Scale(1 / activeTree()->page_scale_factor());
1394 rootScrollLayer()->scrollBy(move);
1396 if (rootScrollLayer()->scrollbarAnimationController())
1397 rootScrollLayer()->scrollbarAnimationController()->didPinchGestureUpdate(base::TimeTicks::Now());
1399 m_client->setNeedsCommitOnImplThread();
1400 m_client->setNeedsRedrawOnImplThread();
1401 m_client->renewTreePriority();
1404 void LayerTreeHostImpl::pinchGestureEnd()
1406 m_pinchGestureActive = false;
1408 if (rootScrollLayer() && rootScrollLayer()->scrollbarAnimationController())
1409 rootScrollLayer()->scrollbarAnimationController()->didPinchGestureEnd(base::TimeTicks::Now());
1411 m_client->setNeedsCommitOnImplThread();
1414 void LayerTreeHostImpl::computeDoubleTapZoomDeltas(ScrollAndScaleSet* scrollInfo)
1416 gfx::Vector2dF scaledScrollOffset = m_pageScaleAnimation->targetScrollOffset();
1417 if (!m_settings.pageScalePinchZoomEnabled)
1418 scaledScrollOffset.Scale(activeTree()->page_scale_factor());
1419 makeScrollAndScaleSet(scrollInfo, ToFlooredVector2d(scaledScrollOffset), m_pageScaleAnimation->targetPageScaleFactor());
1422 void LayerTreeHostImpl::computePinchZoomDeltas(ScrollAndScaleSet* scrollInfo)
1424 if (!rootScrollLayer())
1425 return;
1427 // Only send fake scroll/zoom deltas if we're pinch zooming out by a
1428 // significant amount. This also ensures only one fake delta set will be
1429 // sent.
1430 const float pinchZoomOutSensitivity = 0.95f;
1431 if (activeTree()->page_scale_delta() > pinchZoomOutSensitivity)
1432 return;
1434 // Compute where the scroll offset/page scale would be if fully pinch-zoomed
1435 // out from the anchor point.
1436 gfx::Vector2dF scrollBegin = rootScrollLayer()->scrollOffset() + rootScrollLayer()->scrollDelta();
1437 scrollBegin.Scale(activeTree()->page_scale_delta());
1438 float scaleBegin = activeTree()->total_page_scale_factor();
1439 float pageScaleDeltaToSend = activeTree()->min_page_scale_factor() / activeTree()->page_scale_factor();
1440 gfx::SizeF scaledScrollableSize = gfx::ScaleSize(activeTree()->ScrollableSize(), pageScaleDeltaToSend);
1442 gfx::Vector2d anchorOffset = m_previousPinchAnchor.OffsetFromOrigin();
1443 gfx::Vector2dF scrollEnd = scrollBegin + anchorOffset;
1444 scrollEnd.Scale(activeTree()->min_page_scale_factor() / scaleBegin);
1445 scrollEnd -= anchorOffset;
1446 scrollEnd.ClampToMax(gfx::RectF(scaledScrollableSize).bottom_right() - gfx::Rect(m_deviceViewportSize).bottom_right());
1447 scrollEnd.ClampToMin(gfx::Vector2d());
1448 scrollEnd.Scale(1 / pageScaleDeltaToSend);
1449 scrollEnd.Scale(m_deviceScaleFactor);
1451 makeScrollAndScaleSet(scrollInfo, gfx::ToRoundedVector2d(scrollEnd), activeTree()->min_page_scale_factor());
1454 static void collectScrollDeltas(ScrollAndScaleSet* scrollInfo, LayerImpl* layerImpl)
1456 if (!layerImpl)
1457 return;
1459 gfx::Vector2d scrollDelta = gfx::ToFlooredVector2d(layerImpl->scrollDelta());
1460 if (!scrollDelta.IsZero()) {
1461 LayerTreeHostCommon::ScrollUpdateInfo scroll;
1462 scroll.layerId = layerImpl->id();
1463 scroll.scrollDelta = scrollDelta;
1464 scrollInfo->scrolls.push_back(scroll);
1465 layerImpl->setSentScrollDelta(scrollDelta);
1468 for (size_t i = 0; i < layerImpl->children().size(); ++i)
1469 collectScrollDeltas(scrollInfo, layerImpl->children()[i]);
1472 void LayerTreeHostImpl::makeScrollAndScaleSet(ScrollAndScaleSet* scrollInfo, gfx::Vector2d scrollOffset, float pageScale)
1474 if (!rootScrollLayer())
1475 return;
1477 LayerTreeHostCommon::ScrollUpdateInfo scroll;
1478 scroll.layerId = rootScrollLayer()->id();
1479 scroll.scrollDelta = scrollOffset - rootScrollLayer()->scrollOffset();
1480 scrollInfo->scrolls.push_back(scroll);
1481 activeTree()->RootScrollLayer()->setSentScrollDelta(scroll.scrollDelta);
1482 scrollInfo->pageScaleDelta = pageScale / activeTree()->page_scale_factor();
1483 activeTree()->set_sent_page_scale_delta(scrollInfo->pageScaleDelta);
1486 scoped_ptr<ScrollAndScaleSet> LayerTreeHostImpl::processScrollDeltas()
1488 scoped_ptr<ScrollAndScaleSet> scrollInfo(new ScrollAndScaleSet());
1490 if (!m_settings.pageScalePinchZoomEnabled && (m_pinchGestureActive || m_pageScaleAnimation)) {
1491 scrollInfo->pageScaleDelta = 1;
1492 activeTree()->set_sent_page_scale_delta(1);
1493 if (m_pinchGestureActive)
1494 computePinchZoomDeltas(scrollInfo.get());
1495 else if (m_pageScaleAnimation.get())
1496 computeDoubleTapZoomDeltas(scrollInfo.get());
1497 return scrollInfo.Pass();
1500 collectScrollDeltas(scrollInfo.get(), rootLayer());
1501 scrollInfo->pageScaleDelta = activeTree()->page_scale_delta();
1502 activeTree()->set_sent_page_scale_delta(scrollInfo->pageScaleDelta);
1504 return scrollInfo.Pass();
1507 void LayerTreeHostImpl::setFullRootLayerDamage()
1509 if (rootLayer()) {
1510 RenderSurfaceImpl* renderSurface = rootLayer()->renderSurface();
1511 if (renderSurface)
1512 renderSurface->damageTracker()->forceFullDamageNextUpdate();
1516 void LayerTreeHostImpl::animatePageScale(base::TimeTicks time)
1518 if (!m_pageScaleAnimation || !rootScrollLayer())
1519 return;
1521 double monotonicTime = (time - base::TimeTicks()).InSecondsF();
1522 gfx::Vector2dF scrollTotal = rootScrollLayer()->scrollOffset() + rootScrollLayer()->scrollDelta();
1524 activeTree()->SetPageScaleDelta(m_pageScaleAnimation->pageScaleFactorAtTime(monotonicTime) / activeTree()->page_scale_factor());
1525 gfx::Vector2dF nextScroll = m_pageScaleAnimation->scrollOffsetAtTime(monotonicTime);
1527 if (!m_settings.pageScalePinchZoomEnabled)
1528 nextScroll.Scale(activeTree()->page_scale_factor());
1529 rootScrollLayer()->scrollBy(nextScroll - scrollTotal);
1530 m_client->setNeedsRedrawOnImplThread();
1532 if (m_pageScaleAnimation->isAnimationCompleteAtTime(monotonicTime)) {
1533 m_pageScaleAnimation.reset();
1534 m_client->setNeedsCommitOnImplThread();
1538 void LayerTreeHostImpl::animateLayers(base::TimeTicks monotonicTime, base::Time wallClockTime)
1540 if (!m_settings.acceleratedAnimationEnabled || m_animationRegistrar->active_animation_controllers().empty() || !rootLayer())
1541 return;
1543 TRACE_EVENT0("cc", "LayerTreeHostImpl::animateLayers");
1545 m_lastAnimationTime = wallClockTime;
1546 double monotonicSeconds = (monotonicTime - base::TimeTicks()).InSecondsF();
1548 AnimationRegistrar::AnimationControllerMap copy = m_animationRegistrar->active_animation_controllers();
1549 for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin(); iter != copy.end(); ++iter)
1550 (*iter).second->animate(monotonicSeconds);
1552 m_client->setNeedsRedrawOnImplThread();
1553 setBackgroundTickingEnabled(!m_visible && !m_animationRegistrar->active_animation_controllers().empty());
1556 void LayerTreeHostImpl::updateAnimationState()
1558 if (!m_settings.acceleratedAnimationEnabled || m_animationRegistrar->active_animation_controllers().empty() || !rootLayer())
1559 return;
1561 TRACE_EVENT0("cc", "LayerTreeHostImpl::updateAnimationState");
1562 scoped_ptr<AnimationEventsVector> events(make_scoped_ptr(new AnimationEventsVector));
1563 AnimationRegistrar::AnimationControllerMap copy = m_animationRegistrar->active_animation_controllers();
1564 for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin(); iter != copy.end(); ++iter)
1565 (*iter).second->updateState(events.get());
1567 if (!events->empty())
1568 m_client->postAnimationEventsToMainThreadOnImplThread(events.Pass(), m_lastAnimationTime);
1571 base::TimeDelta LayerTreeHostImpl::lowFrequencyAnimationInterval() const
1573 return base::TimeDelta::FromSeconds(1);
1576 void LayerTreeHostImpl::sendDidLoseOutputSurfaceRecursive(LayerImpl* current)
1578 DCHECK(current);
1579 current->didLoseOutputSurface();
1580 if (current->maskLayer())
1581 sendDidLoseOutputSurfaceRecursive(current->maskLayer());
1582 if (current->replicaLayer())
1583 sendDidLoseOutputSurfaceRecursive(current->replicaLayer());
1584 for (size_t i = 0; i < current->children().size(); ++i)
1585 sendDidLoseOutputSurfaceRecursive(current->children()[i]);
1588 void LayerTreeHostImpl::clearRenderSurfaces()
1590 activeTree()->ClearRenderSurfaces();
1591 if (pendingTree())
1592 pendingTree()->ClearRenderSurfaces();
1595 std::string LayerTreeHostImpl::layerTreeAsText() const
1597 std::string str;
1598 if (rootLayer()) {
1599 str = rootLayer()->layerTreeAsText();
1600 str += "RenderSurfaces:\n";
1601 dumpRenderSurfaces(&str, 1, rootLayer());
1603 return str;
1606 std::string LayerTreeHostImpl::layerTreeAsJson() const
1608 std::string str;
1609 if (rootLayer()) {
1610 scoped_ptr<base::Value> json(rootLayer()->layerTreeAsJson());
1611 base::JSONWriter::WriteWithOptions(
1612 json.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &str);
1614 return str;
1617 void LayerTreeHostImpl::dumpRenderSurfaces(std::string* str, int indent, const LayerImpl* layer) const
1619 if (layer->renderSurface())
1620 layer->renderSurface()->dumpSurface(str, indent);
1622 for (size_t i = 0; i < layer->children().size(); ++i)
1623 dumpRenderSurfaces(str, indent, layer->children()[i]);
1626 int LayerTreeHostImpl::sourceAnimationFrameNumber() const
1628 return fpsCounter()->currentFrameNumber();
1631 void LayerTreeHostImpl::renderingStats(RenderingStats* stats) const
1633 stats->numFramesSentToScreen = fpsCounter()->currentFrameNumber();
1634 stats->droppedFrameCount = fpsCounter()->droppedFrameCount();
1635 stats->numImplThreadScrolls = m_numImplThreadScrolls;
1636 stats->numMainThreadScrolls = m_numMainThreadScrolls;
1637 stats->numLayersDrawn = m_cumulativeNumLayersDrawn;
1638 stats->numMissingTiles = m_cumulativeNumMissingTiles;
1640 if (m_tileManager)
1641 m_tileManager->GetRenderingStats(stats);
1644 void LayerTreeHostImpl::sendManagedMemoryStats(
1645 size_t memoryVisibleBytes,
1646 size_t memoryVisibleAndNearbyBytes,
1647 size_t memoryUseBytes)
1649 if (!renderer())
1650 return;
1652 // Round the numbers being sent up to the next 8MB, to throttle the rate
1653 // at which we spam the GPU process.
1654 static const size_t roundingStep = 8 * 1024 * 1024;
1655 memoryVisibleBytes = RoundUp(memoryVisibleBytes, roundingStep);
1656 memoryVisibleAndNearbyBytes = RoundUp(memoryVisibleAndNearbyBytes, roundingStep);
1657 memoryUseBytes = RoundUp(memoryUseBytes, roundingStep);
1658 if (m_lastSentMemoryVisibleBytes == memoryVisibleBytes &&
1659 m_lastSentMemoryVisibleAndNearbyBytes == memoryVisibleAndNearbyBytes &&
1660 m_lastSentMemoryUseBytes == memoryUseBytes) {
1661 return;
1663 m_lastSentMemoryVisibleBytes = memoryVisibleBytes;
1664 m_lastSentMemoryVisibleAndNearbyBytes = memoryVisibleAndNearbyBytes;
1665 m_lastSentMemoryUseBytes = memoryUseBytes;
1667 renderer()->sendManagedMemoryStats(m_lastSentMemoryVisibleBytes,
1668 m_lastSentMemoryVisibleAndNearbyBytes,
1669 m_lastSentMemoryUseBytes);
1672 void LayerTreeHostImpl::animateScrollbars(base::TimeTicks time)
1674 animateScrollbarsRecursive(rootLayer(), time);
1677 void LayerTreeHostImpl::animateScrollbarsRecursive(LayerImpl* layer, base::TimeTicks time)
1679 if (!layer)
1680 return;
1682 ScrollbarAnimationController* scrollbarController = layer->scrollbarAnimationController();
1683 if (scrollbarController && scrollbarController->animate(time))
1684 m_client->setNeedsRedrawOnImplThread();
1686 for (size_t i = 0; i < layer->children().size(); ++i)
1687 animateScrollbarsRecursive(layer->children()[i], time);
1690 void LayerTreeHostImpl::setTreePriority(TreePriority priority)
1692 if (!m_tileManager)
1693 return;
1695 GlobalStateThatImpactsTilePriority new_state(m_tileManager->GlobalState());
1696 if (new_state.tree_priority == priority)
1697 return;
1699 new_state.tree_priority = priority;
1700 m_tileManager->SetGlobalState(new_state);
1703 void LayerTreeHostImpl::beginNextFrame()
1705 m_currentFrameTime = base::TimeTicks();
1708 base::TimeTicks LayerTreeHostImpl::currentFrameTime()
1710 if (m_currentFrameTime.is_null())
1711 m_currentFrameTime = base::TimeTicks::Now();
1712 return m_currentFrameTime;
1715 scoped_ptr<base::Value> LayerTreeHostImpl::asValue() const
1717 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
1718 state->Set("activation_state", activationStateAsValue().release());
1719 state->Set("frame_state", frameStateAsValue().release());
1720 return state.PassAs<base::Value>();
1723 scoped_ptr<base::Value> LayerTreeHostImpl::activationStateAsValue() const
1725 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
1726 state->SetString("lthi_id", StringPrintf("%p", this));
1727 state->SetBoolean("visible_resources_ready", pendingTree()->AreVisibleResourcesReady());
1728 state->Set("tile_manager", m_tileManager->BasicStateAsValue().release());
1729 return state.PassAs<base::Value>();
1732 scoped_ptr<base::Value> LayerTreeHostImpl::frameStateAsValue() const
1734 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
1735 state->SetString("lthi_id", StringPrintf("%p", this));
1736 state->Set("device_viewport_size", MathUtil::asValue(m_deviceViewportSize).release());
1737 if (m_tileManager)
1738 state->Set("tiles", m_tileManager->AllTilesAsValue().release());
1739 state->Set("active_tree", activeTree()->AsValue().release());
1740 return state.PassAs<base::Value>();
1743 // static
1744 LayerImpl* LayerTreeHostImpl::getNonCompositedContentLayerRecursive(LayerImpl* layer)
1746 if (!layer)
1747 return NULL;
1749 if (layer->drawsContent())
1750 return layer;
1752 for (LayerImpl::LayerList::const_iterator it = layer->children().begin();
1753 it != layer->children().end(); ++it) {
1754 LayerImpl* nccr = getNonCompositedContentLayerRecursive(*it);
1755 if (nccr)
1756 return nccr;
1759 return NULL;
1762 skia::RefPtr<SkPicture> LayerTreeHostImpl::capturePicture()
1764 LayerTreeImpl* tree = pendingTree() ? pendingTree() : activeTree();
1765 LayerImpl* layer = getNonCompositedContentLayerRecursive(tree->RootLayer());
1766 return layer ? layer->getPicture() : skia::RefPtr<SkPicture>();
1769 void LayerTreeHostImpl::setDebugState(const LayerTreeDebugState& debugState)
1771 m_debugState = debugState;
1773 if (m_tileManager)
1774 m_tileManager->SetRecordRenderingStats(m_debugState.recordRenderingStats());
1777 void LayerTreeHostImpl::savePaintTime(const base::TimeDelta& totalPaintTime)
1779 m_paintTimeCounter->SavePaintTime(totalPaintTime);
1782 } // namespace cc