Reenable NullOpenerRedirectForksProcess, as the offending patch has been reverted
[chromium-blink-merge.git] / cc / layer_tree_host_impl.cc
blob69eb10bc8f3370fa110d4f2f11566e3f104072c9
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 "cc/append_quads_data.h"
12 #include "cc/damage_tracker.h"
13 #include "cc/debug_rect_history.h"
14 #include "cc/delay_based_time_source.h"
15 #include "cc/font_atlas.h"
16 #include "cc/frame_rate_counter.h"
17 #include "cc/geometry.h"
18 #include "cc/gl_renderer.h"
19 #include "cc/heads_up_display_layer_impl.h"
20 #include "cc/layer_iterator.h"
21 #include "cc/layer_tree_host.h"
22 #include "cc/layer_tree_host_common.h"
23 #include "cc/math_util.h"
24 #include "cc/overdraw_metrics.h"
25 #include "cc/page_scale_animation.h"
26 #include "cc/prioritized_resource_manager.h"
27 #include "cc/render_pass_draw_quad.h"
28 #include "cc/rendering_stats.h"
29 #include "cc/scrollbar_animation_controller.h"
30 #include "cc/scrollbar_layer_impl.h"
31 #include "cc/single_thread_proxy.h"
32 #include "cc/software_renderer.h"
33 #include "cc/texture_uploader.h"
34 #include "ui/gfx/size_conversions.h"
35 #include "ui/gfx/vector2d_conversions.h"
37 using WebKit::WebTransformationMatrix;
39 namespace {
41 void didVisibilityChange(cc::LayerTreeHostImpl* id, bool visible)
43 if (visible) {
44 TRACE_EVENT_ASYNC_BEGIN1("webkit", "LayerTreeHostImpl::setVisible", id, "LayerTreeHostImpl", id);
45 return;
48 TRACE_EVENT_ASYNC_END0("webkit", "LayerTreeHostImpl::setVisible", id);
51 } // namespace
53 namespace cc {
55 PinchZoomViewport::PinchZoomViewport()
56 : m_pageScaleFactor(1)
57 , m_pageScaleDelta(1)
58 , m_sentPageScaleDelta(1)
59 , m_minPageScaleFactor(0)
60 , m_maxPageScaleFactor(0)
64 float PinchZoomViewport::totalPageScaleFactor() const
66 return m_pageScaleFactor * m_pageScaleDelta;
69 void PinchZoomViewport::setPageScaleDelta(float delta)
71 // Clamp to the current min/max limits.
72 float totalPageScaleFactor = m_pageScaleFactor * delta;
73 if (m_minPageScaleFactor && totalPageScaleFactor < m_minPageScaleFactor)
74 delta = m_minPageScaleFactor / m_pageScaleFactor;
75 else if (m_maxPageScaleFactor && totalPageScaleFactor > m_maxPageScaleFactor)
76 delta = m_maxPageScaleFactor / m_pageScaleFactor;
78 if (delta == m_pageScaleDelta)
79 return;
81 m_pageScaleDelta = delta;
84 bool PinchZoomViewport::setPageScaleFactorAndLimits(float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor)
86 DCHECK(pageScaleFactor);
88 if (m_sentPageScaleDelta == 1 && pageScaleFactor == m_pageScaleFactor && minPageScaleFactor == m_minPageScaleFactor && maxPageScaleFactor == m_maxPageScaleFactor)
89 return false;
91 m_minPageScaleFactor = minPageScaleFactor;
92 m_maxPageScaleFactor = maxPageScaleFactor;
94 m_pageScaleFactor = pageScaleFactor;
95 return true;
98 gfx::RectF PinchZoomViewport::bounds() const
100 gfx::RectF bounds(gfx::PointF(), m_layoutViewportSize);
101 bounds.Scale(1 / totalPageScaleFactor());
102 bounds += m_pinchViewportScrollDelta;
103 return bounds;
106 gfx::Vector2dF PinchZoomViewport::applyScroll(const gfx::Vector2dF& delta)
108 gfx::Vector2dF overflow;
109 gfx::RectF pinchedBounds = bounds() + delta;
111 if (pinchedBounds.x() < 0) {
112 overflow.set_x(pinchedBounds.x());
113 pinchedBounds.set_x(0);
116 if (pinchedBounds.y() < 0) {
117 overflow.set_y(pinchedBounds.y());
118 pinchedBounds.set_y(0);
121 if (pinchedBounds.right() > m_layoutViewportSize.width()) {
122 overflow.set_x(pinchedBounds.right() - m_layoutViewportSize.width());
123 pinchedBounds += gfx::Vector2dF(m_layoutViewportSize.width() - pinchedBounds.right(), 0);
126 if (pinchedBounds.bottom() > m_layoutViewportSize.height()) {
127 overflow.set_y(pinchedBounds.bottom() - m_layoutViewportSize.height());
128 pinchedBounds += gfx::Vector2dF(0, m_layoutViewportSize.height() - pinchedBounds.bottom());
130 m_pinchViewportScrollDelta = pinchedBounds.OffsetFromOrigin();
132 return overflow;
135 WebTransformationMatrix PinchZoomViewport::implTransform(bool pageScalePinchZoomEnabled) const
137 WebTransformationMatrix transform;
138 transform.scale(m_pageScaleDelta);
140 // If the pinch state is applied in the impl, then push it to the
141 // impl transform, otherwise the scale is handled by WebCore.
142 if (pageScalePinchZoomEnabled) {
143 transform.scale(m_pageScaleFactor);
144 transform.translate(-m_pinchViewportScrollDelta.x(),
145 -m_pinchViewportScrollDelta.y());
148 return transform;
151 class LayerTreeHostImplTimeSourceAdapter : public TimeSourceClient {
152 public:
153 static scoped_ptr<LayerTreeHostImplTimeSourceAdapter> create(LayerTreeHostImpl* layerTreeHostImpl, scoped_refptr<DelayBasedTimeSource> timeSource)
155 return make_scoped_ptr(new LayerTreeHostImplTimeSourceAdapter(layerTreeHostImpl, timeSource));
157 virtual ~LayerTreeHostImplTimeSourceAdapter()
159 m_timeSource->setClient(0);
160 m_timeSource->setActive(false);
163 virtual void onTimerTick() OVERRIDE
165 m_layerTreeHostImpl->animate(base::TimeTicks::Now(), base::Time::Now());
168 void setActive(bool active)
170 if (active != m_timeSource->active())
171 m_timeSource->setActive(active);
174 private:
175 LayerTreeHostImplTimeSourceAdapter(LayerTreeHostImpl* layerTreeHostImpl, scoped_refptr<DelayBasedTimeSource> timeSource)
176 : m_layerTreeHostImpl(layerTreeHostImpl)
177 , m_timeSource(timeSource)
179 m_timeSource->setClient(this);
182 LayerTreeHostImpl* m_layerTreeHostImpl;
183 scoped_refptr<DelayBasedTimeSource> m_timeSource;
185 DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImplTimeSourceAdapter);
188 LayerTreeHostImpl::FrameData::FrameData()
192 LayerTreeHostImpl::FrameData::~FrameData()
196 scoped_ptr<LayerTreeHostImpl> LayerTreeHostImpl::create(const LayerTreeSettings& settings, LayerTreeHostImplClient* client, Proxy* proxy)
198 return make_scoped_ptr(new LayerTreeHostImpl(settings, client, proxy));
201 LayerTreeHostImpl::LayerTreeHostImpl(const LayerTreeSettings& settings, LayerTreeHostImplClient* client, Proxy* proxy)
202 : m_client(client)
203 , m_proxy(proxy)
204 , m_sourceFrameNumber(-1)
205 , m_rootScrollLayerImpl(0)
206 , m_currentlyScrollingLayerImpl(0)
207 , m_hudLayerImpl(0)
208 , m_scrollingLayerIdFromPreviousTree(-1)
209 , m_scrollDeltaIsInViewportSpace(false)
210 , m_settings(settings)
211 , m_deviceScaleFactor(1)
212 , m_visible(true)
213 , m_contentsTexturesPurged(false)
214 , m_managedMemoryPolicy(PrioritizedResourceManager::defaultMemoryAllocationLimit(),
215 PriorityCalculator::allowEverythingCutoff(),
217 PriorityCalculator::allowNothingCutoff())
218 , m_backgroundColor(0)
219 , m_hasTransparentBackground(false)
220 , m_needsAnimateLayers(false)
221 , m_pinchGestureActive(false)
222 , m_fpsCounter(FrameRateCounter::create(m_proxy->hasImplThread()))
223 , m_debugRectHistory(DebugRectHistory::create())
224 , m_numImplThreadScrolls(0)
225 , m_numMainThreadScrolls(0)
227 DCHECK(m_proxy->isImplThread());
228 didVisibilityChange(this, m_visible);
231 LayerTreeHostImpl::~LayerTreeHostImpl()
233 DCHECK(m_proxy->isImplThread());
234 TRACE_EVENT0("cc", "LayerTreeHostImpl::~LayerTreeHostImpl()");
236 if (m_rootLayerImpl)
237 clearRenderSurfaces();
240 void LayerTreeHostImpl::beginCommit()
244 void LayerTreeHostImpl::commitComplete()
246 TRACE_EVENT0("cc", "LayerTreeHostImpl::commitComplete");
247 // Recompute max scroll position; must be after layer content bounds are
248 // updated.
249 updateMaxScrollOffset();
250 m_client->sendManagedMemoryStats();
253 bool LayerTreeHostImpl::canDraw()
255 // Note: If you are changing this function or any other function that might
256 // affect the result of canDraw, make sure to call m_client->onCanDrawStateChanged
257 // in the proper places and update the notifyIfCanDrawChanged test.
259 if (!m_rootLayerImpl) {
260 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw no root layer");
261 return false;
263 if (deviceViewportSize().IsEmpty()) {
264 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw empty viewport");
265 return false;
267 if (!m_renderer) {
268 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw no renderer");
269 return false;
271 if (m_contentsTexturesPurged) {
272 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw contents textures purged");
273 return false;
275 return true;
278 GraphicsContext* LayerTreeHostImpl::context() const
280 return m_context.get();
283 void LayerTreeHostImpl::animate(base::TimeTicks monotonicTime, base::Time wallClockTime)
285 animatePageScale(monotonicTime);
286 animateLayers(monotonicTime, wallClockTime);
287 animateScrollbars(monotonicTime);
290 void LayerTreeHostImpl::startPageScaleAnimation(gfx::Vector2d targetOffset, bool anchorPoint, float pageScale, base::TimeTicks startTime, base::TimeDelta duration)
292 if (!m_rootScrollLayerImpl)
293 return;
295 gfx::Vector2dF scrollTotal = m_rootScrollLayerImpl->scrollOffset() + m_rootScrollLayerImpl->scrollDelta();
296 gfx::SizeF scaledContentSize = contentSize();
297 if (!m_settings.pageScalePinchZoomEnabled) {
298 scrollTotal.Scale(1 / m_pinchZoomViewport.pageScaleFactor());
299 scaledContentSize.Scale(1 / m_pinchZoomViewport.pageScaleFactor());
301 gfx::SizeF viewportSize = gfx::ScaleSize(m_deviceViewportSize, 1 / m_deviceScaleFactor);
303 double startTimeSeconds = (startTime - base::TimeTicks()).InSecondsF();
304 m_pageScaleAnimation = PageScaleAnimation::create(scrollTotal, m_pinchZoomViewport.totalPageScaleFactor(), viewportSize, scaledContentSize, startTimeSeconds);
306 if (anchorPoint) {
307 gfx::Vector2dF anchor(targetOffset);
308 if (!m_settings.pageScalePinchZoomEnabled)
309 anchor.Scale(1 / pageScale);
310 m_pageScaleAnimation->zoomWithAnchor(anchor, pageScale, duration.InSecondsF());
311 } else {
312 gfx::Vector2dF scaledTargetOffset = targetOffset;
313 if (!m_settings.pageScalePinchZoomEnabled)
314 scaledTargetOffset.Scale(1 / pageScale);
315 m_pageScaleAnimation->zoomTo(scaledTargetOffset, pageScale, duration.InSecondsF());
318 m_client->setNeedsRedrawOnImplThread();
319 m_client->setNeedsCommitOnImplThread();
322 void LayerTreeHostImpl::scheduleAnimation()
324 m_client->setNeedsRedrawOnImplThread();
327 void LayerTreeHostImpl::trackDamageForAllSurfaces(LayerImpl* rootDrawLayer, const LayerList& renderSurfaceLayerList)
329 // For now, we use damage tracking to compute a global scissor. To do this, we must
330 // compute all damage tracking before drawing anything, so that we know the root
331 // damage rect. The root damage rect is then used to scissor each surface.
333 for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
334 LayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex];
335 RenderSurfaceImpl* renderSurface = renderSurfaceLayer->renderSurface();
336 DCHECK(renderSurface);
337 renderSurface->damageTracker()->updateDamageTrackingState(renderSurface->layerList(), renderSurfaceLayer->id(), renderSurface->surfacePropertyChangedOnlyFromDescendant(), renderSurface->contentRect(), renderSurfaceLayer->maskLayer(), renderSurfaceLayer->filters(), renderSurfaceLayer->filter());
341 void LayerTreeHostImpl::updateRootScrollLayerImplTransform()
343 if (m_rootScrollLayerImpl) {
344 m_rootScrollLayerImpl->setImplTransform(implTransform());
348 void LayerTreeHostImpl::calculateRenderSurfaceLayerList(LayerList& renderSurfaceLayerList)
350 DCHECK(renderSurfaceLayerList.empty());
351 DCHECK(m_rootLayerImpl);
352 DCHECK(m_renderer); // For maxTextureSize.
355 updateRootScrollLayerImplTransform();
357 TRACE_EVENT0("cc", "LayerTreeHostImpl::calcDrawEtc");
358 float pageScaleFactor = m_pinchZoomViewport.pageScaleFactor();
359 LayerTreeHostCommon::calculateDrawTransforms(m_rootLayerImpl.get(), deviceViewportSize(), m_deviceScaleFactor, pageScaleFactor, &m_layerSorter, rendererCapabilities().maxTextureSize, renderSurfaceLayerList);
361 trackDamageForAllSurfaces(m_rootLayerImpl.get(), renderSurfaceLayerList);
365 void LayerTreeHostImpl::FrameData::appendRenderPass(scoped_ptr<RenderPass> renderPass)
367 RenderPass* pass = renderPass.get();
368 renderPasses.push_back(pass);
369 renderPassesById.set(pass->id(), renderPass.Pass());
372 bool LayerTreeHostImpl::calculateRenderPasses(FrameData& frame)
374 DCHECK(frame.renderPasses.empty());
376 calculateRenderSurfaceLayerList(*frame.renderSurfaceLayerList);
378 TRACE_EVENT1("cc", "LayerTreeHostImpl::calculateRenderPasses", "renderSurfaceLayerList.size()", static_cast<long long unsigned>(frame.renderSurfaceLayerList->size()));
380 // Create the render passes in dependency order.
381 for (int surfaceIndex = frame.renderSurfaceLayerList->size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
382 LayerImpl* renderSurfaceLayer = (*frame.renderSurfaceLayerList)[surfaceIndex];
383 renderSurfaceLayer->renderSurface()->appendRenderPasses(frame);
386 bool recordMetricsForFrame = m_settings.showOverdrawInTracing && base::debug::TraceLog::GetInstance() && base::debug::TraceLog::GetInstance()->IsEnabled();
387 OcclusionTrackerImpl occlusionTracker(m_rootLayerImpl->renderSurface()->contentRect(), recordMetricsForFrame);
388 occlusionTracker.setMinimumTrackingSize(m_settings.minimumOcclusionTrackingSize);
390 if (settings().showOccludingRects)
391 occlusionTracker.setOccludingScreenSpaceRectsContainer(&frame.occludingScreenSpaceRects);
392 if (settings().showNonOccludingRects)
393 occlusionTracker.setNonOccludingScreenSpaceRectsContainer(&frame.nonOccludingScreenSpaceRects);
395 // Add quads to the Render passes in FrontToBack order to allow for testing occlusion and performing culling during the tree walk.
396 typedef LayerIterator<LayerImpl, std::vector<LayerImpl*>, RenderSurfaceImpl, LayerIteratorActions::FrontToBack> LayerIteratorType;
398 // Typically when we are missing a texture and use a checkerboard quad, we still draw the frame. However when the layer being
399 // checkerboarded is moving due to an impl-animation, we drop the frame to avoid flashing due to the texture suddenly appearing
400 // in the future.
401 bool drawFrame = true;
403 LayerIteratorType end = LayerIteratorType::end(frame.renderSurfaceLayerList);
404 for (LayerIteratorType it = LayerIteratorType::begin(frame.renderSurfaceLayerList); it != end; ++it) {
405 RenderPass::Id targetRenderPassId = it.targetRenderSurfaceLayer()->renderSurface()->renderPassId();
406 RenderPass* targetRenderPass = frame.renderPassesById.get(targetRenderPassId);
408 occlusionTracker.enterLayer(it);
410 AppendQuadsData appendQuadsData(targetRenderPass->id());
412 if (it.representsContributingRenderSurface()) {
413 RenderPass::Id contributingRenderPassId = it->renderSurface()->renderPassId();
414 RenderPass* contributingRenderPass = frame.renderPassesById.get(contributingRenderPassId);
415 targetRenderPass->appendQuadsForRenderSurfaceLayer(*it, contributingRenderPass, &occlusionTracker, appendQuadsData);
416 } else if (it.representsItself() && !it->visibleContentRect().IsEmpty()) {
417 bool hasOcclusionFromOutsideTargetSurface;
418 bool implDrawTransformIsUnknown = false;
419 if (occlusionTracker.occluded(it->renderTarget(), it->visibleContentRect(), it->drawTransform(), implDrawTransformIsUnknown, it->drawableContentRect(), &hasOcclusionFromOutsideTargetSurface))
420 appendQuadsData.hadOcclusionFromOutsideTargetSurface |= hasOcclusionFromOutsideTargetSurface;
421 else {
422 it->willDraw(m_resourceProvider.get());
423 frame.willDrawLayers.push_back(*it);
425 if (it->hasContributingDelegatedRenderPasses()) {
426 RenderPass::Id contributingRenderPassId = it->firstContributingRenderPassId();
427 while (frame.renderPassesById.contains(contributingRenderPassId)) {
428 RenderPass* renderPass = frame.renderPassesById.get(contributingRenderPassId);
430 AppendQuadsData appendQuadsData(renderPass->id());
431 renderPass->appendQuadsForLayer(*it, &occlusionTracker, appendQuadsData);
433 contributingRenderPassId = it->nextContributingRenderPassId(contributingRenderPassId);
437 targetRenderPass->appendQuadsForLayer(*it, &occlusionTracker, appendQuadsData);
441 if (appendQuadsData.hadOcclusionFromOutsideTargetSurface)
442 targetRenderPass->setHasOcclusionFromOutsideTargetSurface(true);
444 if (appendQuadsData.hadMissingTiles) {
445 bool layerHasAnimatingTransform = it->screenSpaceTransformIsAnimating() || it->drawTransformIsAnimating();
446 if (layerHasAnimatingTransform)
447 drawFrame = false;
450 occlusionTracker.leaveLayer(it);
453 #ifndef NDEBUG
454 for (size_t i = 0; i < frame.renderPasses.size(); ++i) {
455 for (size_t j = 0; j < frame.renderPasses[i]->quadList().size(); ++j)
456 DCHECK(frame.renderPasses[i]->quadList()[j]->sharedQuadStateId() >= 0);
457 DCHECK(frame.renderPassesById.contains(frame.renderPasses[i]->id()));
459 #endif
461 if (!m_hasTransparentBackground) {
462 frame.renderPasses.back()->setHasTransparentBackground(false);
463 frame.renderPasses.back()->appendQuadsToFillScreen(m_rootLayerImpl.get(), m_backgroundColor, occlusionTracker);
466 if (drawFrame)
467 occlusionTracker.overdrawMetrics().recordMetrics(this);
469 removeRenderPasses(CullRenderPassesWithNoQuads(), frame);
470 m_renderer->decideRenderPassAllocationsForFrame(frame.renderPasses);
471 removeRenderPasses(CullRenderPassesWithCachedTextures(*m_renderer), frame);
473 return drawFrame;
476 void LayerTreeHostImpl::animateLayersRecursive(LayerImpl* current, base::TimeTicks monotonicTime, base::Time wallClockTime, AnimationEventsVector* events, bool& didAnimate, bool& needsAnimateLayers)
478 bool subtreeNeedsAnimateLayers = false;
480 LayerAnimationController* currentController = current->layerAnimationController();
482 bool hadActiveAnimation = currentController->hasActiveAnimation();
483 double monotonicTimeSeconds = (monotonicTime - base::TimeTicks()).InSecondsF();
484 currentController->animate(monotonicTimeSeconds, events);
485 bool startedAnimation = events->size() > 0;
487 // We animated if we either ticked a running animation, or started a new animation.
488 if (hadActiveAnimation || startedAnimation)
489 didAnimate = true;
491 // If the current controller still has an active animation, we must continue animating layers.
492 if (currentController->hasActiveAnimation())
493 subtreeNeedsAnimateLayers = true;
495 for (size_t i = 0; i < current->children().size(); ++i) {
496 bool childNeedsAnimateLayers = false;
497 animateLayersRecursive(current->children()[i], monotonicTime, wallClockTime, events, didAnimate, childNeedsAnimateLayers);
498 if (childNeedsAnimateLayers)
499 subtreeNeedsAnimateLayers = true;
502 needsAnimateLayers = subtreeNeedsAnimateLayers;
505 void LayerTreeHostImpl::setBackgroundTickingEnabled(bool enabled)
507 // Lazily create the timeSource adapter so that we can vary the interval for testing.
508 if (!m_timeSourceClientAdapter)
509 m_timeSourceClientAdapter = LayerTreeHostImplTimeSourceAdapter::create(this, DelayBasedTimeSource::create(lowFrequencyAnimationInterval(), m_proxy->currentThread()));
511 m_timeSourceClientAdapter->setActive(enabled);
514 gfx::Size LayerTreeHostImpl::contentSize() const
516 // TODO(aelias): Hardcoding the first child here is weird. Think of
517 // a cleaner way to get the contentBounds on the Impl side.
518 if (!m_rootScrollLayerImpl || m_rootScrollLayerImpl->children().isEmpty())
519 return gfx::Size();
520 return m_rootScrollLayerImpl->children()[0]->contentBounds();
523 static inline RenderPass* findRenderPassById(RenderPass::Id renderPassId, const LayerTreeHostImpl::FrameData& frame)
525 RenderPassIdHashMap::const_iterator it = frame.renderPassesById.find(renderPassId);
526 DCHECK(it != frame.renderPassesById.end());
527 return it->second;
530 static void removeRenderPassesRecursive(RenderPass::Id removeRenderPassId, LayerTreeHostImpl::FrameData& frame)
532 RenderPass* removeRenderPass = findRenderPassById(removeRenderPassId, frame);
533 RenderPassList& renderPasses = frame.renderPasses;
534 RenderPassList::iterator toRemove = std::find(renderPasses.begin(), renderPasses.end(), removeRenderPass);
536 // The pass was already removed by another quad - probably the original, and we are the replica.
537 if (toRemove == renderPasses.end())
538 return;
540 const RenderPass* removedPass = *toRemove;
541 frame.renderPasses.erase(toRemove);
543 // Now follow up for all RenderPass quads and remove their RenderPasses recursively.
544 const QuadList& quadList = removedPass->quadList();
545 QuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin();
546 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) {
547 DrawQuad* currentQuad = (*quadListIterator);
548 if (currentQuad->material() != DrawQuad::RenderPass)
549 continue;
551 RenderPass::Id nextRemoveRenderPassId = RenderPassDrawQuad::materialCast(currentQuad)->renderPassId();
552 removeRenderPassesRecursive(nextRemoveRenderPassId, frame);
556 bool LayerTreeHostImpl::CullRenderPassesWithCachedTextures::shouldRemoveRenderPass(const RenderPassDrawQuad& quad, const FrameData&) const
558 return quad.contentsChangedSinceLastFrame().IsEmpty() && m_renderer.haveCachedResourcesForRenderPassId(quad.renderPassId());
561 bool LayerTreeHostImpl::CullRenderPassesWithNoQuads::shouldRemoveRenderPass(const RenderPassDrawQuad& quad, const FrameData& frame) const
563 const RenderPass* renderPass = findRenderPassById(quad.renderPassId(), frame);
564 const RenderPassList& renderPasses = frame.renderPasses;
565 RenderPassList::const_iterator foundPass = std::find(renderPasses.begin(), renderPasses.end(), renderPass);
567 bool renderPassAlreadyRemoved = foundPass == renderPasses.end();
568 if (renderPassAlreadyRemoved)
569 return false;
571 // If any quad or RenderPass draws into this RenderPass, then keep it.
572 const QuadList& quadList = (*foundPass)->quadList();
573 for (QuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin(); quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) {
574 DrawQuad* currentQuad = *quadListIterator;
576 if (currentQuad->material() != DrawQuad::RenderPass)
577 return false;
579 const RenderPass* contributingPass = findRenderPassById(RenderPassDrawQuad::materialCast(currentQuad)->renderPassId(), frame);
580 RenderPassList::const_iterator foundContributingPass = std::find(renderPasses.begin(), renderPasses.end(), contributingPass);
581 if (foundContributingPass != renderPasses.end())
582 return false;
584 return true;
587 // Defined for linking tests.
588 template CC_EXPORT void LayerTreeHostImpl::removeRenderPasses<LayerTreeHostImpl::CullRenderPassesWithCachedTextures>(CullRenderPassesWithCachedTextures, FrameData&);
589 template CC_EXPORT void LayerTreeHostImpl::removeRenderPasses<LayerTreeHostImpl::CullRenderPassesWithNoQuads>(CullRenderPassesWithNoQuads, FrameData&);
591 // static
592 template<typename RenderPassCuller>
593 void LayerTreeHostImpl::removeRenderPasses(RenderPassCuller culler, FrameData& frame)
595 for (size_t it = culler.renderPassListBegin(frame.renderPasses); it != culler.renderPassListEnd(frame.renderPasses); it = culler.renderPassListNext(it)) {
596 const RenderPass* currentPass = frame.renderPasses[it];
597 const QuadList& quadList = currentPass->quadList();
598 QuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin();
600 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) {
601 DrawQuad* currentQuad = *quadListIterator;
603 if (currentQuad->material() != DrawQuad::RenderPass)
604 continue;
606 RenderPassDrawQuad* renderPassQuad = static_cast<RenderPassDrawQuad*>(currentQuad);
607 if (!culler.shouldRemoveRenderPass(*renderPassQuad, frame))
608 continue;
610 // We are changing the vector in the middle of iteration. Because we
611 // delete render passes that draw into the current pass, we are
612 // guaranteed that any data from the iterator to the end will not
613 // change. So, capture the iterator position from the end of the
614 // list, and restore it after the change.
615 int positionFromEnd = frame.renderPasses.size() - it;
616 removeRenderPassesRecursive(renderPassQuad->renderPassId(), frame);
617 it = frame.renderPasses.size() - positionFromEnd;
618 DCHECK(it >= 0);
623 bool LayerTreeHostImpl::prepareToDraw(FrameData& frame)
625 TRACE_EVENT0("cc", "LayerTreeHostImpl::prepareToDraw");
626 DCHECK(canDraw());
628 frame.renderSurfaceLayerList = &m_renderSurfaceLayerList;
629 frame.renderPasses.clear();
630 frame.renderPassesById.clear();
631 frame.renderSurfaceLayerList->clear();
632 frame.willDrawLayers.clear();
634 if (!calculateRenderPasses(frame))
635 return false;
637 // If we return true, then we expect drawLayers() to be called before this function is called again.
638 return true;
641 void LayerTreeHostImpl::enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy)
643 bool evictedResources = m_client->reduceContentsTextureMemoryOnImplThread(
644 m_visible ? policy.bytesLimitWhenVisible : policy.bytesLimitWhenNotVisible,
645 m_visible ? policy.priorityCutoffWhenVisible : policy.priorityCutoffWhenNotVisible);
646 if (evictedResources) {
647 setContentsTexturesPurged();
648 m_client->setNeedsCommitOnImplThread();
649 m_client->onCanDrawStateChanged(canDraw());
651 m_client->sendManagedMemoryStats();
654 bool LayerTreeHostImpl::hasImplThread() const
656 return m_proxy->hasImplThread();
659 void LayerTreeHostImpl::setManagedMemoryPolicy(const ManagedMemoryPolicy& policy)
661 if (m_managedMemoryPolicy == policy)
662 return;
664 m_managedMemoryPolicy = policy;
665 if (!m_proxy->hasImplThread()) {
666 // FIXME: In single-thread mode, this can be called on the main thread
667 // by GLRenderer::onMemoryAllocationChanged.
668 DebugScopedSetImplThread implThread(m_proxy);
669 enforceManagedMemoryPolicy(m_managedMemoryPolicy);
670 } else {
671 DCHECK(m_proxy->isImplThread());
672 enforceManagedMemoryPolicy(m_managedMemoryPolicy);
674 // We always need to commit after changing the memory policy because the new
675 // limit can result in more or less content having texture allocated for it.
676 m_client->setNeedsCommitOnImplThread();
679 void LayerTreeHostImpl::onVSyncParametersChanged(double monotonicTimebase, double intervalInSeconds)
681 base::TimeTicks timebase = base::TimeTicks::FromInternalValue(monotonicTimebase * base::Time::kMicrosecondsPerSecond);
682 base::TimeDelta interval = base::TimeDelta::FromMicroseconds(intervalInSeconds * base::Time::kMicrosecondsPerSecond);
683 m_client->onVSyncParametersChanged(timebase, interval);
686 void LayerTreeHostImpl::drawLayers(const FrameData& frame)
688 TRACE_EVENT0("cc", "LayerTreeHostImpl::drawLayers");
689 DCHECK(canDraw());
690 DCHECK(!frame.renderPasses.empty());
692 // FIXME: use the frame begin time from the overall compositor scheduler.
693 // This value is currently inaccessible because it is up in Chromium's
694 // RenderWidget.
695 m_fpsCounter->markBeginningOfFrame(base::TimeTicks::Now());
697 if (m_settings.showDebugRects())
698 m_debugRectHistory->saveDebugRectsForCurrentFrame(m_rootLayerImpl.get(), *frame.renderSurfaceLayerList, frame.occludingScreenSpaceRects, frame.nonOccludingScreenSpaceRects, settings());
700 // Because the contents of the HUD depend on everything else in the frame, the contents
701 // of its texture are updated as the last thing before the frame is drawn.
702 if (m_hudLayerImpl)
703 m_hudLayerImpl->updateHudTexture(m_resourceProvider.get());
705 m_renderer->drawFrame(frame.renderPasses, frame.renderPassesById);
707 // Once a RenderPass has been drawn, its damage should be cleared in
708 // case the RenderPass will be reused next frame.
709 for (unsigned int i = 0; i < frame.renderPasses.size(); i++)
710 frame.renderPasses[i]->setDamageRect(gfx::RectF());
712 // The next frame should start by assuming nothing has changed, and changes are noted as they occur.
713 for (unsigned int i = 0; i < frame.renderSurfaceLayerList->size(); i++)
714 (*frame.renderSurfaceLayerList)[i]->renderSurface()->damageTracker()->didDrawDamagedArea();
715 m_rootLayerImpl->resetAllChangeTrackingForSubtree();
718 void LayerTreeHostImpl::didDrawAllLayers(const FrameData& frame)
720 for (size_t i = 0; i < frame.willDrawLayers.size(); ++i)
721 frame.willDrawLayers[i]->didDraw(m_resourceProvider.get());
723 // Once all layers have been drawn, pending texture uploads should no
724 // longer block future uploads.
725 m_resourceProvider->markPendingUploadsAsNonBlocking();
728 void LayerTreeHostImpl::finishAllRendering()
730 if (m_renderer)
731 m_renderer->finish();
734 bool LayerTreeHostImpl::isContextLost()
736 return m_renderer && m_renderer->isContextLost();
739 const RendererCapabilities& LayerTreeHostImpl::rendererCapabilities() const
741 return m_renderer->capabilities();
744 bool LayerTreeHostImpl::swapBuffers()
746 DCHECK(m_renderer);
748 m_fpsCounter->markEndOfFrame();
749 return m_renderer->swapBuffers();
752 const gfx::Size& LayerTreeHostImpl::deviceViewportSize() const
754 return m_deviceViewportSize;
757 const LayerTreeSettings& LayerTreeHostImpl::settings() const
759 return m_settings;
762 void LayerTreeHostImpl::didLoseContext()
764 m_client->didLoseContextOnImplThread();
767 void LayerTreeHostImpl::onSwapBuffersComplete()
769 m_client->onSwapBuffersCompleteOnImplThread();
772 void LayerTreeHostImpl::readback(void* pixels, const gfx::Rect& rect)
774 DCHECK(m_renderer);
775 m_renderer->getFramebufferPixels(pixels, rect);
778 static LayerImpl* findRootScrollLayer(LayerImpl* layer)
780 if (!layer)
781 return 0;
783 if (layer->scrollable())
784 return layer;
786 for (size_t i = 0; i < layer->children().size(); ++i) {
787 LayerImpl* found = findRootScrollLayer(layer->children()[i]);
788 if (found)
789 return found;
792 return 0;
795 // Content layers can be either directly scrollable or contained in an outer
796 // scrolling layer which applies the scroll transform. Given a content layer,
797 // this function returns the associated scroll layer if any.
798 static LayerImpl* findScrollLayerForContentLayer(LayerImpl* layerImpl)
800 if (!layerImpl)
801 return 0;
803 if (layerImpl->scrollable())
804 return layerImpl;
806 if (layerImpl->drawsContent() && layerImpl->parent() && layerImpl->parent()->scrollable())
807 return layerImpl->parent();
809 return 0;
812 void LayerTreeHostImpl::setRootLayer(scoped_ptr<LayerImpl> layer)
814 m_rootLayerImpl = layer.Pass();
815 m_rootScrollLayerImpl = findRootScrollLayer(m_rootLayerImpl.get());
816 m_currentlyScrollingLayerImpl = 0;
818 if (m_rootLayerImpl && m_scrollingLayerIdFromPreviousTree != -1)
819 m_currentlyScrollingLayerImpl = LayerTreeHostCommon::findLayerInSubtree(m_rootLayerImpl.get(), m_scrollingLayerIdFromPreviousTree);
821 m_scrollingLayerIdFromPreviousTree = -1;
823 m_client->onCanDrawStateChanged(canDraw());
826 scoped_ptr<LayerImpl> LayerTreeHostImpl::detachLayerTree()
828 // Clear all data structures that have direct references to the layer tree.
829 m_scrollingLayerIdFromPreviousTree = m_currentlyScrollingLayerImpl ? m_currentlyScrollingLayerImpl->id() : -1;
830 m_currentlyScrollingLayerImpl = 0;
831 m_renderSurfaceLayerList.clear();
833 return m_rootLayerImpl.Pass();
836 void LayerTreeHostImpl::setVisible(bool visible)
838 DCHECK(m_proxy->isImplThread());
840 if (m_visible == visible)
841 return;
842 m_visible = visible;
843 didVisibilityChange(this, m_visible);
844 enforceManagedMemoryPolicy(m_managedMemoryPolicy);
846 if (!m_renderer)
847 return;
849 m_renderer->setVisible(visible);
851 setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers);
854 bool LayerTreeHostImpl::initializeRenderer(scoped_ptr<GraphicsContext> context)
856 // Since we will create a new resource provider, we cannot continue to use
857 // the old resources (i.e. renderSurfaces and texture IDs). Clear them
858 // before we destroy the old resource provider.
859 if (m_rootLayerImpl) {
860 clearRenderSurfaces();
861 sendDidLoseContextRecursive(m_rootLayerImpl.get());
863 // Note: order is important here.
864 m_renderer.reset();
865 m_resourceProvider.reset();
866 m_context.reset();
868 if (!context->bindToClient(this))
869 return false;
871 scoped_ptr<ResourceProvider> resourceProvider = ResourceProvider::create(context.get());
872 if (!resourceProvider)
873 return false;
875 if (context->context3D())
876 m_renderer = GLRenderer::create(this, resourceProvider.get());
877 else if (context->softwareDevice())
878 m_renderer = SoftwareRenderer::create(this, resourceProvider.get(), context->softwareDevice());
879 if (!m_renderer)
880 return false;
882 m_resourceProvider = resourceProvider.Pass();
883 m_context = context.Pass();
885 if (!m_visible)
886 m_renderer->setVisible(m_visible);
888 m_client->onCanDrawStateChanged(canDraw());
890 return true;
893 void LayerTreeHostImpl::setContentsTexturesPurged()
895 m_contentsTexturesPurged = true;
896 m_client->onCanDrawStateChanged(canDraw());
899 void LayerTreeHostImpl::resetContentsTexturesPurged()
901 m_contentsTexturesPurged = false;
902 m_client->onCanDrawStateChanged(canDraw());
905 void LayerTreeHostImpl::setViewportSize(const gfx::Size& layoutViewportSize, const gfx::Size& deviceViewportSize)
907 if (layoutViewportSize == m_layoutViewportSize && deviceViewportSize == m_deviceViewportSize)
908 return;
910 m_layoutViewportSize = layoutViewportSize;
911 m_deviceViewportSize = deviceViewportSize;
913 m_pinchZoomViewport.setLayoutViewportSize(layoutViewportSize);
915 updateMaxScrollOffset();
917 if (m_renderer)
918 m_renderer->viewportChanged();
920 m_client->onCanDrawStateChanged(canDraw());
923 static void adjustScrollsForPageScaleChange(LayerImpl* layerImpl, float pageScaleChange)
925 if (!layerImpl)
926 return;
928 if (layerImpl->scrollable()) {
929 // We need to convert impl-side scroll deltas to pageScale space.
930 gfx::Vector2dF scrollDelta = layerImpl->scrollDelta();
931 scrollDelta.Scale(pageScaleChange);
932 layerImpl->setScrollDelta(scrollDelta);
935 for (size_t i = 0; i < layerImpl->children().size(); ++i)
936 adjustScrollsForPageScaleChange(layerImpl->children()[i], pageScaleChange);
939 void LayerTreeHostImpl::setDeviceScaleFactor(float deviceScaleFactor)
941 if (deviceScaleFactor == m_deviceScaleFactor)
942 return;
943 m_deviceScaleFactor = deviceScaleFactor;
945 updateMaxScrollOffset();
948 float LayerTreeHostImpl::pageScaleFactor() const
950 return m_pinchZoomViewport.pageScaleFactor();
953 void LayerTreeHostImpl::setPageScaleFactorAndLimits(float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor)
955 if (!pageScaleFactor)
956 return;
958 float pageScaleChange = pageScaleFactor / m_pinchZoomViewport.pageScaleFactor();
959 m_pinchZoomViewport.setPageScaleFactorAndLimits(pageScaleFactor, minPageScaleFactor, maxPageScaleFactor);
961 if (!m_settings.pageScalePinchZoomEnabled) {
962 if (pageScaleChange != 1)
963 adjustScrollsForPageScaleChange(m_rootScrollLayerImpl, pageScaleChange);
966 // Clamp delta to limits and refresh display matrix.
967 setPageScaleDelta(m_pinchZoomViewport.pageScaleDelta() / m_pinchZoomViewport.sentPageScaleDelta());
968 m_pinchZoomViewport.setSentPageScaleDelta(1);
971 void LayerTreeHostImpl::setPageScaleDelta(float delta)
973 m_pinchZoomViewport.setPageScaleDelta(delta);
975 updateMaxScrollOffset();
978 void LayerTreeHostImpl::updateMaxScrollOffset()
980 if (!m_rootScrollLayerImpl || !m_rootScrollLayerImpl->children().size())
981 return;
983 gfx::SizeF viewBounds = m_deviceViewportSize;
984 if (LayerImpl* clipLayer = m_rootScrollLayerImpl->parent()) {
985 // Compensate for non-overlay scrollbars.
986 if (clipLayer->masksToBounds())
987 viewBounds = gfx::ScaleSize(clipLayer->bounds(), m_deviceScaleFactor);
990 gfx::Size contentBounds = contentSize();
991 if (m_settings.pageScalePinchZoomEnabled) {
992 // Pinch with pageScale scrolls entirely in layout space. contentSize
993 // returns the bounds including the page scale factor, so calculate the
994 // pre page-scale layout size here.
995 float pageScaleFactor = m_pinchZoomViewport.pageScaleFactor();
996 contentBounds.set_width(contentBounds.width() / pageScaleFactor);
997 contentBounds.set_height(contentBounds.height() / pageScaleFactor);
998 } else {
999 viewBounds.Scale(1 / m_pinchZoomViewport.pageScaleDelta());
1002 gfx::Vector2dF maxScroll = BottomRight(gfx::Rect(contentBounds)) - BottomRight(gfx::RectF(viewBounds));
1003 maxScroll.Scale(1 / m_deviceScaleFactor);
1005 // The viewport may be larger than the contents in some cases, such as
1006 // having a vertical scrollbar but no horizontal overflow.
1007 maxScroll.ClampToMin(gfx::Vector2dF());
1009 m_rootScrollLayerImpl->setMaxScrollOffset(gfx::ToFlooredVector2d(maxScroll));
1012 void LayerTreeHostImpl::setNeedsRedraw()
1014 m_client->setNeedsRedrawOnImplThread();
1017 bool LayerTreeHostImpl::ensureRenderSurfaceLayerList()
1019 if (!m_rootLayerImpl)
1020 return false;
1021 if (!m_renderer)
1022 return false;
1024 // We need both a non-empty render surface layer list and a root render
1025 // surface to be able to iterate over the visible layers.
1026 if (m_renderSurfaceLayerList.size() && m_rootLayerImpl->renderSurface())
1027 return true;
1029 // If we are called after setRootLayer() but before prepareToDraw(), we need
1030 // to recalculate the visible layers. This prevents being unable to scroll
1031 // during part of a commit.
1032 m_renderSurfaceLayerList.clear();
1033 calculateRenderSurfaceLayerList(m_renderSurfaceLayerList);
1035 return m_renderSurfaceLayerList.size();
1038 InputHandlerClient::ScrollStatus LayerTreeHostImpl::scrollBegin(gfx::Point viewportPoint, InputHandlerClient::ScrollInputType type)
1040 TRACE_EVENT0("cc", "LayerTreeHostImpl::scrollBegin");
1042 DCHECK(!m_currentlyScrollingLayerImpl);
1043 clearCurrentlyScrollingLayer();
1045 if (!ensureRenderSurfaceLayerList())
1046 return ScrollIgnored;
1048 gfx::PointF deviceViewportPoint = gfx::ScalePoint(viewportPoint, m_deviceScaleFactor);
1050 // First find out which layer was hit from the saved list of visible layers
1051 // in the most recent frame.
1052 LayerImpl* layerImpl = LayerTreeHostCommon::findLayerThatIsHitByPoint(deviceViewportPoint, m_renderSurfaceLayerList);
1054 // Walk up the hierarchy and look for a scrollable layer.
1055 LayerImpl* potentiallyScrollingLayerImpl = 0;
1056 for (; layerImpl; layerImpl = layerImpl->parent()) {
1057 // The content layer can also block attempts to scroll outside the main thread.
1058 if (layerImpl->tryScroll(deviceViewportPoint, type) == ScrollOnMainThread) {
1059 m_numMainThreadScrolls++;
1060 return ScrollOnMainThread;
1063 LayerImpl* scrollLayerImpl = findScrollLayerForContentLayer(layerImpl);
1064 if (!scrollLayerImpl)
1065 continue;
1067 ScrollStatus status = scrollLayerImpl->tryScroll(deviceViewportPoint, type);
1069 // If any layer wants to divert the scroll event to the main thread, abort.
1070 if (status == ScrollOnMainThread) {
1071 m_numMainThreadScrolls++;
1072 return ScrollOnMainThread;
1075 if (status == ScrollStarted && !potentiallyScrollingLayerImpl)
1076 potentiallyScrollingLayerImpl = scrollLayerImpl;
1079 if (potentiallyScrollingLayerImpl) {
1080 m_currentlyScrollingLayerImpl = potentiallyScrollingLayerImpl;
1081 // Gesture events need to be transformed from viewport coordinates to local layer coordinates
1082 // so that the scrolling contents exactly follow the user's finger. In contrast, wheel
1083 // events are already in local layer coordinates so we can just apply them directly.
1084 m_scrollDeltaIsInViewportSpace = (type == Gesture);
1085 m_numImplThreadScrolls++;
1086 return ScrollStarted;
1088 return ScrollIgnored;
1091 static gfx::Vector2dF scrollLayerWithViewportSpaceDelta(PinchZoomViewport* viewport, LayerImpl& layerImpl, float scaleFromViewportToScreenSpace, gfx::PointF viewportPoint, gfx::Vector2dF viewportDelta)
1093 // Layers with non-invertible screen space transforms should not have passed the scroll hit
1094 // test in the first place.
1095 DCHECK(layerImpl.screenSpaceTransform().isInvertible());
1096 WebTransformationMatrix inverseScreenSpaceTransform = layerImpl.screenSpaceTransform().inverse();
1098 gfx::PointF screenSpacePoint = gfx::ScalePoint(viewportPoint, scaleFromViewportToScreenSpace);
1100 gfx::Vector2dF screenSpaceDelta = viewportDelta;
1101 screenSpaceDelta.Scale(scaleFromViewportToScreenSpace);
1103 // First project the scroll start and end points to local layer space to find the scroll delta
1104 // in layer coordinates.
1105 bool startClipped, endClipped;
1106 gfx::PointF screenSpaceEndPoint = screenSpacePoint + screenSpaceDelta;
1107 gfx::PointF localStartPoint = MathUtil::projectPoint(inverseScreenSpaceTransform, screenSpacePoint, startClipped);
1108 gfx::PointF localEndPoint = MathUtil::projectPoint(inverseScreenSpaceTransform, screenSpaceEndPoint, endClipped);
1110 // In general scroll point coordinates should not get clipped.
1111 DCHECK(!startClipped);
1112 DCHECK(!endClipped);
1113 if (startClipped || endClipped)
1114 return gfx::Vector2dF();
1116 // localStartPoint and localEndPoint are in content space but we want to move them to layer space for scrolling.
1117 float widthScale = 1 / layerImpl.contentsScaleX();
1118 float heightScale = 1 / layerImpl.contentsScaleY();
1119 localStartPoint.Scale(widthScale, heightScale);
1120 localEndPoint.Scale(widthScale, heightScale);
1122 // Apply the scroll delta.
1123 gfx::Vector2dF previousDelta = layerImpl.scrollDelta();
1124 gfx::Vector2dF unscrolled = layerImpl.scrollBy(localEndPoint - localStartPoint);
1126 if (viewport)
1127 viewport->applyScroll(unscrolled);
1129 // Get the end point in the layer's content space so we can apply its screenSpaceTransform.
1130 gfx::PointF actualLocalEndPoint = localStartPoint + layerImpl.scrollDelta() - previousDelta;
1131 gfx::PointF actualLocalContentEndPoint = gfx::ScalePoint(actualLocalEndPoint, 1 / widthScale, 1 / heightScale);
1133 // Calculate the applied scroll delta in viewport space coordinates.
1134 gfx::PointF actualScreenSpaceEndPoint = MathUtil::mapPoint(layerImpl.screenSpaceTransform(), actualLocalContentEndPoint, endClipped);
1135 DCHECK(!endClipped);
1136 if (endClipped)
1137 return gfx::Vector2dF();
1138 gfx::PointF actualViewportEndPoint = gfx::ScalePoint(actualScreenSpaceEndPoint, 1 / scaleFromViewportToScreenSpace);
1139 return actualViewportEndPoint - viewportPoint;
1142 static gfx::Vector2dF scrollLayerWithLocalDelta(LayerImpl& layerImpl, gfx::Vector2dF localDelta)
1144 gfx::Vector2dF previousDelta(layerImpl.scrollDelta());
1145 layerImpl.scrollBy(localDelta);
1146 return layerImpl.scrollDelta() - previousDelta;
1149 bool LayerTreeHostImpl::scrollBy(const gfx::Point& viewportPoint,
1150 const gfx::Vector2d& scrollDelta)
1152 TRACE_EVENT0("cc", "LayerTreeHostImpl::scrollBy");
1153 if (!m_currentlyScrollingLayerImpl)
1154 return false;
1156 gfx::Vector2dF pendingDelta = scrollDelta;
1158 for (LayerImpl* layerImpl = m_currentlyScrollingLayerImpl; layerImpl; layerImpl = layerImpl->parent()) {
1159 if (!layerImpl->scrollable())
1160 continue;
1162 PinchZoomViewport* viewport = layerImpl == m_rootScrollLayerImpl ? &m_pinchZoomViewport : 0;
1163 gfx::Vector2dF appliedDelta;
1164 if (m_scrollDeltaIsInViewportSpace) {
1165 float scaleFromViewportToScreenSpace = m_deviceScaleFactor;
1166 appliedDelta = scrollLayerWithViewportSpaceDelta(viewport, *layerImpl, scaleFromViewportToScreenSpace, viewportPoint, pendingDelta);
1167 } else
1168 appliedDelta = scrollLayerWithLocalDelta(*layerImpl, pendingDelta);
1170 // If the layer wasn't able to move, try the next one in the hierarchy.
1171 float moveThresholdSquared = 0.1f * 0.1f;
1172 if (appliedDelta.LengthSquared() < moveThresholdSquared)
1173 continue;
1175 // If the applied delta is within 45 degrees of the input delta, bail out to make it easier
1176 // to scroll just one layer in one direction without affecting any of its parents.
1177 float angleThreshold = 45;
1178 if (MathUtil::smallestAngleBetweenVectors(appliedDelta, pendingDelta) < angleThreshold) {
1179 pendingDelta = gfx::Vector2d();
1180 break;
1183 // Allow further movement only on an axis perpendicular to the direction in which the layer
1184 // moved.
1185 gfx::Vector2dF perpendicularAxis(-appliedDelta.y(), appliedDelta.x());
1186 pendingDelta = MathUtil::projectVector(pendingDelta, perpendicularAxis);
1188 if (gfx::ToFlooredVector2d(pendingDelta).IsZero())
1189 break;
1192 if (!scrollDelta.IsZero() && gfx::ToFlooredVector2d(pendingDelta).IsZero()) {
1193 m_client->setNeedsCommitOnImplThread();
1194 m_client->setNeedsRedrawOnImplThread();
1195 return true;
1197 return false;
1200 void LayerTreeHostImpl::clearCurrentlyScrollingLayer()
1202 m_currentlyScrollingLayerImpl = 0;
1203 m_scrollingLayerIdFromPreviousTree = -1;
1206 void LayerTreeHostImpl::scrollEnd()
1208 clearCurrentlyScrollingLayer();
1211 void LayerTreeHostImpl::pinchGestureBegin()
1213 m_pinchGestureActive = true;
1214 m_previousPinchAnchor = gfx::Point();
1216 if (m_rootScrollLayerImpl && m_rootScrollLayerImpl->scrollbarAnimationController())
1217 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureBegin();
1220 void LayerTreeHostImpl::pinchGestureUpdate(float magnifyDelta, gfx::Point anchor)
1222 TRACE_EVENT0("cc", "LayerTreeHostImpl::pinchGestureUpdate");
1224 if (!m_rootScrollLayerImpl)
1225 return;
1227 if (m_previousPinchAnchor == gfx::Point())
1228 m_previousPinchAnchor = anchor;
1230 // Keep the center-of-pinch anchor specified by (x, y) in a stable
1231 // position over the course of the magnify.
1232 float pageScaleDelta = m_pinchZoomViewport.pageScaleDelta();
1233 gfx::PointF previousScaleAnchor = gfx::ScalePoint(m_previousPinchAnchor, 1 / pageScaleDelta);
1234 setPageScaleDelta(pageScaleDelta * magnifyDelta);
1235 pageScaleDelta = m_pinchZoomViewport.pageScaleDelta();
1236 gfx::PointF newScaleAnchor = gfx::ScalePoint(anchor, 1 / pageScaleDelta);
1237 gfx::Vector2dF move = previousScaleAnchor - newScaleAnchor;
1239 m_previousPinchAnchor = anchor;
1241 if (m_settings.pageScalePinchZoomEnabled) {
1242 // Compute the application of the delta with respect to the current page zoom of the page.
1243 move.Scale(1 / (m_pinchZoomViewport.pageScaleFactor() * m_deviceScaleFactor));
1246 gfx::Vector2dF scrollOverflow = m_settings.pageScalePinchZoomEnabled ? m_pinchZoomViewport.applyScroll(move) : move;
1247 m_rootScrollLayerImpl->scrollBy(scrollOverflow);
1249 if (m_rootScrollLayerImpl->scrollbarAnimationController())
1250 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureUpdate();
1252 m_client->setNeedsCommitOnImplThread();
1253 m_client->setNeedsRedrawOnImplThread();
1256 void LayerTreeHostImpl::pinchGestureEnd()
1258 m_pinchGestureActive = false;
1260 if (m_rootScrollLayerImpl && m_rootScrollLayerImpl->scrollbarAnimationController())
1261 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureEnd();
1263 m_client->setNeedsCommitOnImplThread();
1266 void LayerTreeHostImpl::computeDoubleTapZoomDeltas(ScrollAndScaleSet* scrollInfo)
1268 gfx::Vector2dF scaledScrollOffset = m_pageScaleAnimation->targetScrollOffset();
1269 if (!m_settings.pageScalePinchZoomEnabled)
1270 scaledScrollOffset.Scale(m_pinchZoomViewport.pageScaleFactor());
1271 makeScrollAndScaleSet(scrollInfo, ToFlooredVector2d(scaledScrollOffset), m_pageScaleAnimation->targetPageScaleFactor());
1274 void LayerTreeHostImpl::computePinchZoomDeltas(ScrollAndScaleSet* scrollInfo)
1276 if (!m_rootScrollLayerImpl)
1277 return;
1279 // Only send fake scroll/zoom deltas if we're pinch zooming out by a
1280 // significant amount. This also ensures only one fake delta set will be
1281 // sent.
1282 const float pinchZoomOutSensitivity = 0.95f;
1283 if (m_pinchZoomViewport.pageScaleDelta() > pinchZoomOutSensitivity)
1284 return;
1286 // Compute where the scroll offset/page scale would be if fully pinch-zoomed
1287 // out from the anchor point.
1288 gfx::Vector2dF scrollBegin = m_rootScrollLayerImpl->scrollOffset() + m_rootScrollLayerImpl->scrollDelta();
1289 scrollBegin.Scale(m_pinchZoomViewport.pageScaleDelta());
1290 float scaleBegin = m_pinchZoomViewport.totalPageScaleFactor();
1291 float pageScaleDeltaToSend = m_pinchZoomViewport.minPageScaleFactor() / m_pinchZoomViewport.pageScaleFactor();
1292 gfx::SizeF scaledContentsSize = gfx::ScaleSize(contentSize(), pageScaleDeltaToSend);
1294 gfx::Vector2d anchorOffset = m_previousPinchAnchor.OffsetFromOrigin();
1295 gfx::Vector2dF scrollEnd = scrollBegin + anchorOffset;
1296 scrollEnd.Scale(m_pinchZoomViewport.minPageScaleFactor() / scaleBegin);
1297 scrollEnd -= anchorOffset;
1298 scrollEnd.ClampToMax(BottomRight(gfx::RectF(scaledContentsSize)) - BottomRight(gfx::Rect(m_deviceViewportSize)));
1299 scrollEnd.ClampToMin(gfx::Vector2d());
1300 scrollEnd.Scale(1 / pageScaleDeltaToSend);
1301 scrollEnd.Scale(m_deviceScaleFactor);
1303 makeScrollAndScaleSet(scrollInfo, gfx::ToRoundedVector2d(scrollEnd), m_pinchZoomViewport.minPageScaleFactor());
1306 void LayerTreeHostImpl::makeScrollAndScaleSet(ScrollAndScaleSet* scrollInfo, gfx::Vector2d scrollOffset, float pageScale)
1308 if (!m_rootScrollLayerImpl)
1309 return;
1311 LayerTreeHostCommon::ScrollUpdateInfo scroll;
1312 scroll.layerId = m_rootScrollLayerImpl->id();
1313 scroll.scrollDelta = scrollOffset - m_rootScrollLayerImpl->scrollOffset();
1314 scrollInfo->scrolls.push_back(scroll);
1315 m_rootScrollLayerImpl->setSentScrollDelta(scroll.scrollDelta);
1316 scrollInfo->pageScaleDelta = pageScale / m_pinchZoomViewport.pageScaleFactor();
1317 m_pinchZoomViewport.setSentPageScaleDelta(scrollInfo->pageScaleDelta);
1320 static void collectScrollDeltas(ScrollAndScaleSet* scrollInfo, LayerImpl* layerImpl)
1322 if (!layerImpl)
1323 return;
1325 if (!layerImpl->scrollDelta().IsZero()) {
1326 gfx::Vector2d scrollDelta = gfx::ToFlooredVector2d(layerImpl->scrollDelta());
1327 LayerTreeHostCommon::ScrollUpdateInfo scroll;
1328 scroll.layerId = layerImpl->id();
1329 scroll.scrollDelta = scrollDelta;
1330 scrollInfo->scrolls.push_back(scroll);
1331 layerImpl->setSentScrollDelta(scrollDelta);
1334 for (size_t i = 0; i < layerImpl->children().size(); ++i)
1335 collectScrollDeltas(scrollInfo, layerImpl->children()[i]);
1338 scoped_ptr<ScrollAndScaleSet> LayerTreeHostImpl::processScrollDeltas()
1340 scoped_ptr<ScrollAndScaleSet> scrollInfo(new ScrollAndScaleSet());
1342 if (m_pinchGestureActive || m_pageScaleAnimation) {
1343 scrollInfo->pageScaleDelta = 1;
1344 m_pinchZoomViewport.setSentPageScaleDelta(1);
1345 // FIXME(aelias): Make pinch-zoom painting optimization compatible with
1346 // compositor-side scaling.
1347 if (!m_settings.pageScalePinchZoomEnabled && m_pinchGestureActive)
1348 computePinchZoomDeltas(scrollInfo.get());
1349 else if (m_pageScaleAnimation.get())
1350 computeDoubleTapZoomDeltas(scrollInfo.get());
1351 return scrollInfo.Pass();
1354 collectScrollDeltas(scrollInfo.get(), m_rootLayerImpl.get());
1355 scrollInfo->pageScaleDelta = m_pinchZoomViewport.pageScaleDelta();
1356 m_pinchZoomViewport.setSentPageScaleDelta(scrollInfo->pageScaleDelta);
1358 return scrollInfo.Pass();
1361 WebTransformationMatrix LayerTreeHostImpl::implTransform() const
1363 return m_pinchZoomViewport.implTransform(m_settings.pageScalePinchZoomEnabled);
1366 void LayerTreeHostImpl::setFullRootLayerDamage()
1368 if (m_rootLayerImpl) {
1369 RenderSurfaceImpl* renderSurface = m_rootLayerImpl->renderSurface();
1370 if (renderSurface)
1371 renderSurface->damageTracker()->forceFullDamageNextUpdate();
1375 void LayerTreeHostImpl::animatePageScale(base::TimeTicks time)
1377 if (!m_pageScaleAnimation || !m_rootScrollLayerImpl)
1378 return;
1380 double monotonicTime = (time - base::TimeTicks()).InSecondsF();
1381 gfx::Vector2dF scrollTotal = m_rootScrollLayerImpl->scrollOffset() + m_rootScrollLayerImpl->scrollDelta();
1383 setPageScaleDelta(m_pageScaleAnimation->pageScaleFactorAtTime(monotonicTime) / m_pinchZoomViewport.pageScaleFactor());
1384 gfx::Vector2dF nextScroll = m_pageScaleAnimation->scrollOffsetAtTime(monotonicTime);
1386 if (!m_settings.pageScalePinchZoomEnabled)
1387 nextScroll.Scale(m_pinchZoomViewport.pageScaleFactor());
1388 m_rootScrollLayerImpl->scrollBy(nextScroll - scrollTotal);
1389 m_client->setNeedsRedrawOnImplThread();
1391 if (m_pageScaleAnimation->isAnimationCompleteAtTime(monotonicTime)) {
1392 m_pageScaleAnimation.reset();
1393 m_client->setNeedsCommitOnImplThread();
1397 void LayerTreeHostImpl::animateLayers(base::TimeTicks monotonicTime, base::Time wallClockTime)
1399 if (!m_settings.acceleratedAnimationEnabled || !m_needsAnimateLayers || !m_rootLayerImpl)
1400 return;
1402 TRACE_EVENT0("cc", "LayerTreeHostImpl::animateLayers");
1404 scoped_ptr<AnimationEventsVector> events(make_scoped_ptr(new AnimationEventsVector));
1406 bool didAnimate = false;
1407 animateLayersRecursive(m_rootLayerImpl.get(), monotonicTime, wallClockTime, events.get(), didAnimate, m_needsAnimateLayers);
1409 if (!events->empty())
1410 m_client->postAnimationEventsToMainThreadOnImplThread(events.Pass(), wallClockTime);
1412 if (didAnimate)
1413 m_client->setNeedsRedrawOnImplThread();
1415 setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers);
1418 base::TimeDelta LayerTreeHostImpl::lowFrequencyAnimationInterval() const
1420 return base::TimeDelta::FromSeconds(1);
1423 void LayerTreeHostImpl::sendDidLoseContextRecursive(LayerImpl* current)
1425 DCHECK(current);
1426 current->didLoseContext();
1427 if (current->maskLayer())
1428 sendDidLoseContextRecursive(current->maskLayer());
1429 if (current->replicaLayer())
1430 sendDidLoseContextRecursive(current->replicaLayer());
1431 for (size_t i = 0; i < current->children().size(); ++i)
1432 sendDidLoseContextRecursive(current->children()[i]);
1435 static void clearRenderSurfacesOnLayerImplRecursive(LayerImpl* current)
1437 DCHECK(current);
1438 for (size_t i = 0; i < current->children().size(); ++i)
1439 clearRenderSurfacesOnLayerImplRecursive(current->children()[i]);
1440 current->clearRenderSurface();
1443 void LayerTreeHostImpl::clearRenderSurfaces()
1445 clearRenderSurfacesOnLayerImplRecursive(m_rootLayerImpl.get());
1446 m_renderSurfaceLayerList.clear();
1449 std::string LayerTreeHostImpl::layerTreeAsText() const
1451 std::string str;
1452 if (m_rootLayerImpl) {
1453 str = m_rootLayerImpl->layerTreeAsText();
1454 str += "RenderSurfaces:\n";
1455 dumpRenderSurfaces(&str, 1, m_rootLayerImpl.get());
1457 return str;
1460 void LayerTreeHostImpl::dumpRenderSurfaces(std::string* str, int indent, const LayerImpl* layer) const
1462 if (layer->renderSurface())
1463 layer->renderSurface()->dumpSurface(str, indent);
1465 for (size_t i = 0; i < layer->children().size(); ++i)
1466 dumpRenderSurfaces(str, indent, layer->children()[i]);
1469 int LayerTreeHostImpl::sourceAnimationFrameNumber() const
1471 return fpsCounter()->currentFrameNumber();
1474 void LayerTreeHostImpl::renderingStats(RenderingStats* stats) const
1476 stats->numFramesSentToScreen = fpsCounter()->currentFrameNumber();
1477 stats->droppedFrameCount = fpsCounter()->droppedFrameCount();
1478 stats->numImplThreadScrolls = m_numImplThreadScrolls;
1479 stats->numMainThreadScrolls = m_numMainThreadScrolls;
1482 void LayerTreeHostImpl::animateScrollbars(base::TimeTicks time)
1484 animateScrollbarsRecursive(m_rootLayerImpl.get(), time);
1487 void LayerTreeHostImpl::animateScrollbarsRecursive(LayerImpl* layer, base::TimeTicks time)
1489 if (!layer)
1490 return;
1492 ScrollbarAnimationController* scrollbarController = layer->scrollbarAnimationController();
1493 double monotonicTime = (time - base::TimeTicks()).InSecondsF();
1494 if (scrollbarController && scrollbarController->animate(monotonicTime))
1495 m_client->setNeedsRedrawOnImplThread();
1497 for (size_t i = 0; i < layer->children().size(); ++i)
1498 animateScrollbarsRecursive(layer->children()[i], time);
1501 } // namespace cc