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"
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
;
41 void didVisibilityChange(cc::LayerTreeHostImpl
* id
, bool visible
)
44 TRACE_EVENT_ASYNC_BEGIN1("webkit", "LayerTreeHostImpl::setVisible", id
, "LayerTreeHostImpl", id
);
48 TRACE_EVENT_ASYNC_END0("webkit", "LayerTreeHostImpl::setVisible", id
);
55 PinchZoomViewport::PinchZoomViewport()
56 : m_pageScaleFactor(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
)
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
)
91 m_minPageScaleFactor
= minPageScaleFactor
;
92 m_maxPageScaleFactor
= maxPageScaleFactor
;
94 m_pageScaleFactor
= pageScaleFactor
;
98 gfx::RectF
PinchZoomViewport::bounds() const
100 gfx::RectF
bounds(gfx::PointF(), m_layoutViewportSize
);
101 bounds
.Scale(1 / totalPageScaleFactor());
102 bounds
+= m_pinchViewportScrollDelta
;
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();
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());
151 class LayerTreeHostImplTimeSourceAdapter
: public TimeSourceClient
{
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
);
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
)
204 , m_sourceFrameNumber(-1)
205 , m_rootScrollLayerImpl(0)
206 , m_currentlyScrollingLayerImpl(0)
208 , m_scrollingLayerIdFromPreviousTree(-1)
209 , m_scrollDeltaIsInViewportSpace(false)
210 , m_settings(settings
)
211 , m_deviceScaleFactor(1)
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()");
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
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");
263 if (deviceViewportSize().IsEmpty()) {
264 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw empty viewport");
268 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw no renderer");
271 if (m_contentsTexturesPurged
) {
272 TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::canDraw contents textures purged");
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
)
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
);
307 gfx::Vector2dF
anchor(targetOffset
);
308 if (!m_settings
.pageScalePinchZoomEnabled
)
309 anchor
.Scale(1 / pageScale
);
310 m_pageScaleAnimation
->zoomWithAnchor(anchor
, pageScale
, duration
.InSecondsF());
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
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
;
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
)
450 occlusionTracker
.leaveLayer(it
);
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()));
461 if (!m_hasTransparentBackground
) {
462 frame
.renderPasses
.back()->setHasTransparentBackground(false);
463 frame
.renderPasses
.back()->appendQuadsToFillScreen(m_rootLayerImpl
.get(), m_backgroundColor
, occlusionTracker
);
467 occlusionTracker
.overdrawMetrics().recordMetrics(this);
469 removeRenderPasses(CullRenderPassesWithNoQuads(), frame
);
470 m_renderer
->decideRenderPassAllocationsForFrame(frame
.renderPasses
);
471 removeRenderPasses(CullRenderPassesWithCachedTextures(*m_renderer
), frame
);
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
)
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())
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());
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())
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
)
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
)
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
)
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())
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
&);
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
)
606 RenderPassDrawQuad
* renderPassQuad
= static_cast<RenderPassDrawQuad
*>(currentQuad
);
607 if (!culler
.shouldRemoveRenderPass(*renderPassQuad
, frame
))
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
;
623 bool LayerTreeHostImpl::prepareToDraw(FrameData
& frame
)
625 TRACE_EVENT0("cc", "LayerTreeHostImpl::prepareToDraw");
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
))
637 // If we return true, then we expect drawLayers() to be called before this function is called again.
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
)
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
);
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");
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
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.
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()
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()
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
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
)
775 m_renderer
->getFramebufferPixels(pixels
, rect
);
778 static LayerImpl
* findRootScrollLayer(LayerImpl
* layer
)
783 if (layer
->scrollable())
786 for (size_t i
= 0; i
< layer
->children().size(); ++i
) {
787 LayerImpl
* found
= findRootScrollLayer(layer
->children()[i
]);
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
)
803 if (layerImpl
->scrollable())
806 if (layerImpl
->drawsContent() && layerImpl
->parent() && layerImpl
->parent()->scrollable())
807 return layerImpl
->parent();
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
)
843 didVisibilityChange(this, m_visible
);
844 enforceManagedMemoryPolicy(m_managedMemoryPolicy
);
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.
865 m_resourceProvider
.reset();
868 if (!context
->bindToClient(this))
871 scoped_ptr
<ResourceProvider
> resourceProvider
= ResourceProvider::create(context
.get());
872 if (!resourceProvider
)
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());
882 m_resourceProvider
= resourceProvider
.Pass();
883 m_context
= context
.Pass();
886 m_renderer
->setVisible(m_visible
);
888 m_client
->onCanDrawStateChanged(canDraw());
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
)
910 m_layoutViewportSize
= layoutViewportSize
;
911 m_deviceViewportSize
= deviceViewportSize
;
913 m_pinchZoomViewport
.setLayoutViewportSize(layoutViewportSize
);
915 updateMaxScrollOffset();
918 m_renderer
->viewportChanged();
920 m_client
->onCanDrawStateChanged(canDraw());
923 static void adjustScrollsForPageScaleChange(LayerImpl
* layerImpl
, float pageScaleChange
)
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
)
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
)
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())
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
);
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
)
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())
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
)
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
);
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
);
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
)
1156 gfx::Vector2dF pendingDelta
= scrollDelta
;
1158 for (LayerImpl
* layerImpl
= m_currentlyScrollingLayerImpl
; layerImpl
; layerImpl
= layerImpl
->parent()) {
1159 if (!layerImpl
->scrollable())
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
);
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
)
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();
1183 // Allow further movement only on an axis perpendicular to the direction in which the layer
1185 gfx::Vector2dF
perpendicularAxis(-appliedDelta
.y(), appliedDelta
.x());
1186 pendingDelta
= MathUtil::projectVector(pendingDelta
, perpendicularAxis
);
1188 if (gfx::ToFlooredVector2d(pendingDelta
).IsZero())
1192 if (!scrollDelta
.IsZero() && gfx::ToFlooredVector2d(pendingDelta
).IsZero()) {
1193 m_client
->setNeedsCommitOnImplThread();
1194 m_client
->setNeedsRedrawOnImplThread();
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
)
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
)
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
1282 const float pinchZoomOutSensitivity
= 0.95f
;
1283 if (m_pinchZoomViewport
.pageScaleDelta() > pinchZoomOutSensitivity
)
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
)
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
)
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();
1371 renderSurface
->damageTracker()->forceFullDamageNextUpdate();
1375 void LayerTreeHostImpl::animatePageScale(base::TimeTicks time
)
1377 if (!m_pageScaleAnimation
|| !m_rootScrollLayerImpl
)
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
)
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
);
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
)
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
)
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
1452 if (m_rootLayerImpl
) {
1453 str
= m_rootLayerImpl
->layerTreeAsText();
1454 str
+= "RenderSurfaces:\n";
1455 dumpRenderSurfaces(&str
, 1, m_rootLayerImpl
.get());
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
)
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
);