Index: cc/CCLayerTreeHostImpl.cpp |
diff --git a/cc/CCLayerTreeHostImpl.cpp b/cc/CCLayerTreeHostImpl.cpp |
deleted file mode 100644 |
index bc50697ad25a5f7b5d0e779fd95870c62ba3aba1..0000000000000000000000000000000000000000 |
--- a/cc/CCLayerTreeHostImpl.cpp |
+++ /dev/null |
@@ -1,1462 +0,0 @@ |
-// Copyright 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "config.h" |
- |
-#include "CCLayerTreeHostImpl.h" |
- |
-#include "base/basictypes.h" |
-#include "CCAppendQuadsData.h" |
-#include "CCDamageTracker.h" |
-#include "CCDebugRectHistory.h" |
-#include "CCDelayBasedTimeSource.h" |
-#include "CCFontAtlas.h" |
-#include "CCFrameRateCounter.h" |
-#include "CCHeadsUpDisplayLayerImpl.h" |
-#include "CCLayerIterator.h" |
-#include "CCLayerTreeHost.h" |
-#include "CCLayerTreeHostCommon.h" |
-#include "CCMathUtil.h" |
-#include "CCOverdrawMetrics.h" |
-#include "CCPageScaleAnimation.h" |
-#include "CCPrioritizedTextureManager.h" |
-#include "CCRenderPassDrawQuad.h" |
-#include "CCRendererGL.h" |
-#include "CCRendererSoftware.h" |
-#include "CCRenderingStats.h" |
-#include "CCScrollbarAnimationController.h" |
-#include "CCScrollbarLayerImpl.h" |
-#include "CCSettings.h" |
-#include "CCSingleThreadProxy.h" |
-#include "TextureUploader.h" |
-#include "TraceEvent.h" |
-#include <wtf/CurrentTime.h> |
-#include <algorithm> |
- |
-using WebKit::WebTransformationMatrix; |
- |
-namespace { |
- |
-void didVisibilityChange(cc::CCLayerTreeHostImpl* id, bool visible) |
-{ |
- if (visible) { |
- TRACE_EVENT_ASYNC_BEGIN1("webkit", "CCLayerTreeHostImpl::setVisible", id, "CCLayerTreeHostImpl", id); |
- return; |
- } |
- |
- TRACE_EVENT_ASYNC_END0("webkit", "CCLayerTreeHostImpl::setVisible", id); |
-} |
- |
-} // namespace |
- |
-namespace cc { |
- |
-CCPinchZoomViewport::CCPinchZoomViewport() |
- : m_pageScaleFactor(1) |
- , m_pageScaleDelta(1) |
- , m_sentPageScaleDelta(1) |
- , m_minPageScaleFactor(0) |
- , m_maxPageScaleFactor(0) |
-{ |
-} |
- |
-float CCPinchZoomViewport::totalPageScaleFactor() const |
-{ |
- return m_pageScaleFactor * m_pageScaleDelta; |
-} |
- |
-void CCPinchZoomViewport::setPageScaleDelta(float delta) |
-{ |
- // Clamp to the current min/max limits. |
- float totalPageScaleFactor = m_pageScaleFactor * delta; |
- if (m_minPageScaleFactor && totalPageScaleFactor < m_minPageScaleFactor) |
- delta = m_minPageScaleFactor / m_pageScaleFactor; |
- else if (m_maxPageScaleFactor && totalPageScaleFactor > m_maxPageScaleFactor) |
- delta = m_maxPageScaleFactor / m_pageScaleFactor; |
- |
- if (delta == m_pageScaleDelta) |
- return; |
- |
- m_pageScaleDelta = delta; |
-} |
- |
-bool CCPinchZoomViewport::setPageScaleFactorAndLimits(float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) |
-{ |
- ASSERT(pageScaleFactor); |
- |
- if (m_sentPageScaleDelta == 1 && pageScaleFactor == m_pageScaleFactor && minPageScaleFactor == m_minPageScaleFactor && maxPageScaleFactor == m_maxPageScaleFactor) |
- return false; |
- |
- m_minPageScaleFactor = minPageScaleFactor; |
- m_maxPageScaleFactor = maxPageScaleFactor; |
- |
- m_pageScaleFactor = pageScaleFactor; |
- return true; |
-} |
- |
-FloatRect CCPinchZoomViewport::bounds() const |
-{ |
- FloatSize scaledViewportSize = m_layoutViewportSize; |
- scaledViewportSize.scale(1 / totalPageScaleFactor()); |
- |
- FloatRect bounds(FloatPoint(0, 0), scaledViewportSize); |
- bounds.setLocation(m_pinchViewportScrollDelta); |
- |
- return bounds; |
-} |
- |
-FloatSize CCPinchZoomViewport::applyScroll(FloatSize& delta) |
-{ |
- FloatSize overflow; |
- FloatRect pinchedBounds = bounds(); |
- |
- pinchedBounds.move(delta); |
- if (pinchedBounds.x() < 0) { |
- overflow.setWidth(pinchedBounds.x()); |
- pinchedBounds.setX(0); |
- } |
- |
- if (pinchedBounds.y() < 0) { |
- overflow.setHeight(pinchedBounds.y()); |
- pinchedBounds.setY(0); |
- } |
- |
- if (pinchedBounds.maxX() > m_layoutViewportSize.width()) { |
- overflow.setWidth( |
- pinchedBounds.maxX() - m_layoutViewportSize.width()); |
- pinchedBounds.move( |
- m_layoutViewportSize.width() - pinchedBounds.maxX(), 0); |
- } |
- |
- if (pinchedBounds.maxY() > m_layoutViewportSize.height()) { |
- overflow.setHeight( |
- pinchedBounds.maxY() - m_layoutViewportSize.height()); |
- pinchedBounds.move( |
- 0, m_layoutViewportSize.height() - pinchedBounds.maxY()); |
- } |
- m_pinchViewportScrollDelta = pinchedBounds.location(); |
- |
- return overflow; |
-} |
- |
-WebTransformationMatrix CCPinchZoomViewport::implTransform() const |
-{ |
- WebTransformationMatrix transform; |
- transform.scale(m_pageScaleDelta); |
- |
- // If the pinch state is applied in the impl, then push it to the |
- // impl transform, otherwise the scale is handled by WebCore. |
- if (CCSettings::pageScalePinchZoomEnabled()) { |
- transform.scale(m_pageScaleFactor); |
- transform.translate(-m_pinchViewportScrollDelta.x(), |
- -m_pinchViewportScrollDelta.y()); |
- } |
- |
- return transform; |
-} |
- |
-class CCLayerTreeHostImplTimeSourceAdapter : public CCTimeSourceClient { |
-public: |
- static PassOwnPtr<CCLayerTreeHostImplTimeSourceAdapter> create(CCLayerTreeHostImpl* layerTreeHostImpl, PassRefPtr<CCDelayBasedTimeSource> timeSource) |
- { |
- return adoptPtr(new CCLayerTreeHostImplTimeSourceAdapter(layerTreeHostImpl, timeSource)); |
- } |
- virtual ~CCLayerTreeHostImplTimeSourceAdapter() |
- { |
- m_timeSource->setClient(0); |
- m_timeSource->setActive(false); |
- } |
- |
- virtual void onTimerTick() OVERRIDE |
- { |
- // FIXME: We require that animate be called on the impl thread. This |
- // avoids asserts in single threaded mode. Ideally background ticking |
- // would be handled by the proxy/scheduler and this could be removed. |
- DebugScopedSetImplThread impl; |
- |
- m_layerTreeHostImpl->animate(monotonicallyIncreasingTime(), currentTime()); |
- } |
- |
- void setActive(bool active) |
- { |
- if (active != m_timeSource->active()) |
- m_timeSource->setActive(active); |
- } |
- |
-private: |
- CCLayerTreeHostImplTimeSourceAdapter(CCLayerTreeHostImpl* layerTreeHostImpl, PassRefPtr<CCDelayBasedTimeSource> timeSource) |
- : m_layerTreeHostImpl(layerTreeHostImpl) |
- , m_timeSource(timeSource) |
- { |
- m_timeSource->setClient(this); |
- } |
- |
- CCLayerTreeHostImpl* m_layerTreeHostImpl; |
- RefPtr<CCDelayBasedTimeSource> m_timeSource; |
- |
- DISALLOW_COPY_AND_ASSIGN(CCLayerTreeHostImplTimeSourceAdapter); |
-}; |
- |
-CCLayerTreeHostImpl::FrameData::FrameData() |
-{ |
-} |
- |
-CCLayerTreeHostImpl::FrameData::~FrameData() |
-{ |
-} |
- |
-scoped_ptr<CCLayerTreeHostImpl> CCLayerTreeHostImpl::create(const CCLayerTreeSettings& settings, CCLayerTreeHostImplClient* client) |
-{ |
- return make_scoped_ptr(new CCLayerTreeHostImpl(settings, client)); |
-} |
- |
-CCLayerTreeHostImpl::CCLayerTreeHostImpl(const CCLayerTreeSettings& settings, CCLayerTreeHostImplClient* client) |
- : m_client(client) |
- , m_sourceFrameNumber(-1) |
- , m_rootScrollLayerImpl(0) |
- , m_currentlyScrollingLayerImpl(0) |
- , m_hudLayerImpl(0) |
- , m_scrollingLayerIdFromPreviousTree(-1) |
- , m_scrollDeltaIsInScreenSpace(false) |
- , m_settings(settings) |
- , m_deviceScaleFactor(1) |
- , m_visible(true) |
- , m_contentsTexturesPurged(false) |
- , m_memoryAllocationLimitBytes(CCPrioritizedTextureManager::defaultMemoryAllocationLimit()) |
- , m_backgroundColor(0) |
- , m_hasTransparentBackground(false) |
- , m_needsAnimateLayers(false) |
- , m_pinchGestureActive(false) |
- , m_fpsCounter(CCFrameRateCounter::create()) |
- , m_debugRectHistory(CCDebugRectHistory::create()) |
- , m_numImplThreadScrolls(0) |
- , m_numMainThreadScrolls(0) |
-{ |
- ASSERT(CCProxy::isImplThread()); |
- didVisibilityChange(this, m_visible); |
-} |
- |
-CCLayerTreeHostImpl::~CCLayerTreeHostImpl() |
-{ |
- ASSERT(CCProxy::isImplThread()); |
- TRACE_EVENT0("cc", "CCLayerTreeHostImpl::~CCLayerTreeHostImpl()"); |
- |
- if (m_rootLayerImpl) |
- clearRenderSurfaces(); |
-} |
- |
-void CCLayerTreeHostImpl::beginCommit() |
-{ |
-} |
- |
-void CCLayerTreeHostImpl::commitComplete() |
-{ |
- TRACE_EVENT0("cc", "CCLayerTreeHostImpl::commitComplete"); |
- // Recompute max scroll position; must be after layer content bounds are |
- // updated. |
- updateMaxScrollPosition(); |
-} |
- |
-bool CCLayerTreeHostImpl::canDraw() |
-{ |
- // Note: If you are changing this function or any other function that might |
- // affect the result of canDraw, make sure to call m_client->onCanDrawStateChanged |
- // in the proper places and update the notifyIfCanDrawChanged test. |
- |
- if (!m_rootLayerImpl) { |
- TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw no root layer"); |
- return false; |
- } |
- if (deviceViewportSize().isEmpty()) { |
- TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw empty viewport"); |
- return false; |
- } |
- if (!m_renderer) { |
- TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw no renderer"); |
- return false; |
- } |
- if (m_contentsTexturesPurged) { |
- TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw contents textures purged"); |
- return false; |
- } |
- return true; |
-} |
- |
-CCGraphicsContext* CCLayerTreeHostImpl::context() const |
-{ |
- return m_context.get(); |
-} |
- |
-void CCLayerTreeHostImpl::animate(double monotonicTime, double wallClockTime) |
-{ |
- animatePageScale(monotonicTime); |
- animateLayers(monotonicTime, wallClockTime); |
- animateScrollbars(monotonicTime); |
-} |
- |
-void CCLayerTreeHostImpl::startPageScaleAnimation(const IntSize& targetPosition, bool anchorPoint, float pageScale, double startTime, double duration) |
-{ |
- if (!m_rootScrollLayerImpl) |
- return; |
- |
- IntSize scrollTotal = flooredIntSize(m_rootScrollLayerImpl->scrollPosition() + m_rootScrollLayerImpl->scrollDelta()); |
- scrollTotal.scale(m_pinchZoomViewport.pageScaleDelta()); |
- float scaleTotal = m_pinchZoomViewport.totalPageScaleFactor(); |
- IntSize scaledContentSize = contentSize(); |
- scaledContentSize.scale(m_pinchZoomViewport.pageScaleDelta()); |
- |
- m_pageScaleAnimation = CCPageScaleAnimation::create(scrollTotal, scaleTotal, m_deviceViewportSize, scaledContentSize, startTime); |
- |
- if (anchorPoint) { |
- IntSize windowAnchor(targetPosition); |
- windowAnchor.scale(scaleTotal / pageScale); |
- windowAnchor -= scrollTotal; |
- m_pageScaleAnimation->zoomWithAnchor(windowAnchor, pageScale, duration); |
- } else |
- m_pageScaleAnimation->zoomTo(targetPosition, pageScale, duration); |
- |
- m_client->setNeedsRedrawOnImplThread(); |
- m_client->setNeedsCommitOnImplThread(); |
-} |
- |
-void CCLayerTreeHostImpl::scheduleAnimation() |
-{ |
- m_client->setNeedsRedrawOnImplThread(); |
-} |
- |
-void CCLayerTreeHostImpl::trackDamageForAllSurfaces(CCLayerImpl* rootDrawLayer, const CCLayerList& renderSurfaceLayerList) |
-{ |
- // For now, we use damage tracking to compute a global scissor. To do this, we must |
- // compute all damage tracking before drawing anything, so that we know the root |
- // damage rect. The root damage rect is then used to scissor each surface. |
- |
- for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) { |
- CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex]; |
- CCRenderSurface* renderSurface = renderSurfaceLayer->renderSurface(); |
- ASSERT(renderSurface); |
- renderSurface->damageTracker()->updateDamageTrackingState(renderSurface->layerList(), renderSurfaceLayer->id(), renderSurface->surfacePropertyChangedOnlyFromDescendant(), renderSurface->contentRect(), renderSurfaceLayer->maskLayer(), renderSurfaceLayer->filters()); |
- } |
-} |
- |
-void CCLayerTreeHostImpl::updateRootScrollLayerImplTransform() |
-{ |
- if (m_rootScrollLayerImpl) { |
- m_rootScrollLayerImpl->setImplTransform(implTransform()); |
- } |
-} |
- |
-void CCLayerTreeHostImpl::calculateRenderSurfaceLayerList(CCLayerList& renderSurfaceLayerList) |
-{ |
- ASSERT(renderSurfaceLayerList.empty()); |
- ASSERT(m_rootLayerImpl); |
- ASSERT(m_renderer); // For maxTextureSize. |
- |
- { |
- updateRootScrollLayerImplTransform(); |
- |
- TRACE_EVENT0("cc", "CCLayerTreeHostImpl::calcDrawEtc"); |
- CCLayerTreeHostCommon::calculateDrawTransforms(m_rootLayerImpl.get(), deviceViewportSize(), m_deviceScaleFactor, &m_layerSorter, rendererCapabilities().maxTextureSize, renderSurfaceLayerList); |
- |
- trackDamageForAllSurfaces(m_rootLayerImpl.get(), renderSurfaceLayerList); |
- } |
-} |
- |
-void CCLayerTreeHostImpl::FrameData::appendRenderPass(scoped_ptr<CCRenderPass> renderPass) |
-{ |
- CCRenderPass* pass = renderPass.get(); |
- renderPasses.push_back(pass); |
- renderPassesById.set(pass->id(), renderPass.Pass()); |
-} |
- |
-bool CCLayerTreeHostImpl::calculateRenderPasses(FrameData& frame) |
-{ |
- ASSERT(frame.renderPasses.empty()); |
- |
- calculateRenderSurfaceLayerList(*frame.renderSurfaceLayerList); |
- |
- TRACE_EVENT1("cc", "CCLayerTreeHostImpl::calculateRenderPasses", "renderSurfaceLayerList.size()", static_cast<long long unsigned>(frame.renderSurfaceLayerList->size())); |
- |
- // Create the render passes in dependency order. |
- for (int surfaceIndex = frame.renderSurfaceLayerList->size() - 1; surfaceIndex >= 0 ; --surfaceIndex) { |
- CCLayerImpl* renderSurfaceLayer = (*frame.renderSurfaceLayerList)[surfaceIndex]; |
- renderSurfaceLayer->renderSurface()->appendRenderPasses(frame); |
- } |
- |
- bool recordMetricsForFrame = true; // FIXME: In the future, disable this when about:tracing is off. |
- CCOcclusionTrackerImpl occlusionTracker(m_rootLayerImpl->renderSurface()->contentRect(), recordMetricsForFrame); |
- occlusionTracker.setMinimumTrackingSize(m_settings.minimumOcclusionTrackingSize); |
- |
- if (settings().showOccludingRects) |
- occlusionTracker.setOccludingScreenSpaceRectsContainer(&frame.occludingScreenSpaceRects); |
- |
- // Add quads to the Render passes in FrontToBack order to allow for testing occlusion and performing culling during the tree walk. |
- typedef CCLayerIterator<CCLayerImpl, std::vector<CCLayerImpl*>, CCRenderSurface, CCLayerIteratorActions::FrontToBack> CCLayerIteratorType; |
- |
- // Typically when we are missing a texture and use a checkerboard quad, we still draw the frame. However when the layer being |
- // checkerboarded is moving due to an impl-animation, we drop the frame to avoid flashing due to the texture suddenly appearing |
- // in the future. |
- bool drawFrame = true; |
- |
- CCLayerIteratorType end = CCLayerIteratorType::end(frame.renderSurfaceLayerList); |
- for (CCLayerIteratorType it = CCLayerIteratorType::begin(frame.renderSurfaceLayerList); it != end; ++it) { |
- CCRenderPass::Id targetRenderPassId = it.targetRenderSurfaceLayer()->renderSurface()->renderPassId(); |
- CCRenderPass* targetRenderPass = frame.renderPassesById.get(targetRenderPassId); |
- |
- occlusionTracker.enterLayer(it); |
- |
- CCAppendQuadsData appendQuadsData(targetRenderPass->id()); |
- |
- if (it.representsContributingRenderSurface()) { |
- CCRenderPass::Id contributingRenderPassId = it->renderSurface()->renderPassId(); |
- CCRenderPass* contributingRenderPass = frame.renderPassesById.get(contributingRenderPassId); |
- targetRenderPass->appendQuadsForRenderSurfaceLayer(*it, contributingRenderPass, &occlusionTracker, appendQuadsData); |
- } else if (it.representsItself() && !it->visibleContentRect().isEmpty()) { |
- bool hasOcclusionFromOutsideTargetSurface; |
- if (occlusionTracker.occluded(*it, it->visibleContentRect(), &hasOcclusionFromOutsideTargetSurface)) |
- appendQuadsData.hadOcclusionFromOutsideTargetSurface |= hasOcclusionFromOutsideTargetSurface; |
- else { |
- it->willDraw(m_resourceProvider.get()); |
- frame.willDrawLayers.push_back(*it); |
- |
- if (it->hasContributingDelegatedRenderPasses()) { |
- CCRenderPass::Id contributingRenderPassId = it->firstContributingRenderPassId(); |
- while (frame.renderPassesById.contains(contributingRenderPassId)) { |
- CCRenderPass* renderPass = frame.renderPassesById.get(contributingRenderPassId); |
- |
- CCAppendQuadsData appendQuadsData(renderPass->id()); |
- renderPass->appendQuadsForLayer(*it, &occlusionTracker, appendQuadsData); |
- |
- contributingRenderPassId = it->nextContributingRenderPassId(contributingRenderPassId); |
- } |
- } |
- |
- targetRenderPass->appendQuadsForLayer(*it, &occlusionTracker, appendQuadsData); |
- } |
- } |
- |
- if (appendQuadsData.hadOcclusionFromOutsideTargetSurface) |
- targetRenderPass->setHasOcclusionFromOutsideTargetSurface(true); |
- |
- if (appendQuadsData.hadMissingTiles) { |
- bool layerHasAnimatingTransform = it->screenSpaceTransformIsAnimating() || it->drawTransformIsAnimating(); |
- if (layerHasAnimatingTransform || CCSettings::jankInsteadOfCheckerboard()) |
- drawFrame = false; |
- } |
- |
- occlusionTracker.leaveLayer(it); |
- } |
- |
-#if !ASSERT_DISABLED |
- for (size_t i = 0; i < frame.renderPasses.size(); ++i) { |
- for (size_t j = 0; j < frame.renderPasses[i]->quadList().size(); ++j) |
- ASSERT(frame.renderPasses[i]->quadList()[j]->sharedQuadStateId() >= 0); |
- ASSERT(frame.renderPassesById.contains(frame.renderPasses[i]->id())); |
- } |
-#endif |
- |
- if (!m_hasTransparentBackground) { |
- frame.renderPasses.back()->setHasTransparentBackground(false); |
- frame.renderPasses.back()->appendQuadsToFillScreen(m_rootLayerImpl.get(), m_backgroundColor, occlusionTracker); |
- } |
- |
- if (drawFrame) |
- occlusionTracker.overdrawMetrics().recordMetrics(this); |
- |
- removeRenderPasses(CullRenderPassesWithNoQuads(), frame); |
- m_renderer->decideRenderPassAllocationsForFrame(frame.renderPasses); |
- removeRenderPasses(CullRenderPassesWithCachedTextures(*m_renderer), frame); |
- |
- return drawFrame; |
-} |
- |
-void CCLayerTreeHostImpl::animateLayersRecursive(CCLayerImpl* current, double monotonicTime, double wallClockTime, CCAnimationEventsVector* events, bool& didAnimate, bool& needsAnimateLayers) |
-{ |
- bool subtreeNeedsAnimateLayers = false; |
- |
- CCLayerAnimationController* currentController = current->layerAnimationController(); |
- |
- bool hadActiveAnimation = currentController->hasActiveAnimation(); |
- currentController->animate(monotonicTime, events); |
- bool startedAnimation = events->size() > 0; |
- |
- // We animated if we either ticked a running animation, or started a new animation. |
- if (hadActiveAnimation || startedAnimation) |
- didAnimate = true; |
- |
- // If the current controller still has an active animation, we must continue animating layers. |
- if (currentController->hasActiveAnimation()) |
- subtreeNeedsAnimateLayers = true; |
- |
- for (size_t i = 0; i < current->children().size(); ++i) { |
- bool childNeedsAnimateLayers = false; |
- animateLayersRecursive(current->children()[i], monotonicTime, wallClockTime, events, didAnimate, childNeedsAnimateLayers); |
- if (childNeedsAnimateLayers) |
- subtreeNeedsAnimateLayers = true; |
- } |
- |
- needsAnimateLayers = subtreeNeedsAnimateLayers; |
-} |
- |
-void CCLayerTreeHostImpl::setBackgroundTickingEnabled(bool enabled) |
-{ |
- // Lazily create the timeSource adapter so that we can vary the interval for testing. |
- if (!m_timeSourceClientAdapter) |
- m_timeSourceClientAdapter = CCLayerTreeHostImplTimeSourceAdapter::create(this, CCDelayBasedTimeSource::create(lowFrequencyAnimationInterval(), CCProxy::currentThread())); |
- |
- m_timeSourceClientAdapter->setActive(enabled); |
-} |
- |
-IntSize CCLayerTreeHostImpl::contentSize() const |
-{ |
- // TODO(aelias): Hardcoding the first child here is weird. Think of |
- // a cleaner way to get the contentBounds on the Impl side. |
- if (!m_rootScrollLayerImpl || m_rootScrollLayerImpl->children().isEmpty()) |
- return IntSize(); |
- return m_rootScrollLayerImpl->children()[0]->contentBounds(); |
-} |
- |
-static inline CCRenderPass* findRenderPassById(CCRenderPass::Id renderPassId, const CCLayerTreeHostImpl::FrameData& frame) |
-{ |
- CCRenderPassIdHashMap::const_iterator it = frame.renderPassesById.find(renderPassId); |
- ASSERT(it != frame.renderPassesById.end()); |
- return it->second; |
-} |
- |
-static void removeRenderPassesRecursive(CCRenderPass::Id removeRenderPassId, CCLayerTreeHostImpl::FrameData& frame) |
-{ |
- CCRenderPass* removeRenderPass = findRenderPassById(removeRenderPassId, frame); |
- CCRenderPassList& renderPasses = frame.renderPasses; |
- CCRenderPassList::iterator toRemove = std::find(renderPasses.begin(), renderPasses.end(), removeRenderPass); |
- |
- // The pass was already removed by another quad - probably the original, and we are the replica. |
- if (toRemove == renderPasses.end()) |
- return; |
- |
- const CCRenderPass* removedPass = *toRemove; |
- frame.renderPasses.erase(toRemove); |
- |
- // Now follow up for all RenderPass quads and remove their RenderPasses recursively. |
- const CCQuadList& quadList = removedPass->quadList(); |
- CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin(); |
- for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) { |
- CCDrawQuad* currentQuad = (*quadListIterator); |
- if (currentQuad->material() != CCDrawQuad::RenderPass) |
- continue; |
- |
- CCRenderPass::Id nextRemoveRenderPassId = CCRenderPassDrawQuad::materialCast(currentQuad)->renderPassId(); |
- removeRenderPassesRecursive(nextRemoveRenderPassId, frame); |
- } |
-} |
- |
-bool CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures::shouldRemoveRenderPass(const CCRenderPassDrawQuad& quad, const FrameData&) const |
-{ |
- return quad.contentsChangedSinceLastFrame().isEmpty() && m_renderer.haveCachedResourcesForRenderPassId(quad.renderPassId()); |
-} |
- |
-bool CCLayerTreeHostImpl::CullRenderPassesWithNoQuads::shouldRemoveRenderPass(const CCRenderPassDrawQuad& quad, const FrameData& frame) const |
-{ |
- const CCRenderPass* renderPass = findRenderPassById(quad.renderPassId(), frame); |
- const CCRenderPassList& renderPasses = frame.renderPasses; |
- CCRenderPassList::const_iterator foundPass = std::find(renderPasses.begin(), renderPasses.end(), renderPass); |
- |
- bool renderPassAlreadyRemoved = foundPass == renderPasses.end(); |
- if (renderPassAlreadyRemoved) |
- return false; |
- |
- // If any quad or RenderPass draws into this RenderPass, then keep it. |
- const CCQuadList& quadList = (*foundPass)->quadList(); |
- for (CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin(); quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) { |
- CCDrawQuad* currentQuad = *quadListIterator; |
- |
- if (currentQuad->material() != CCDrawQuad::RenderPass) |
- return false; |
- |
- const CCRenderPass* contributingPass = findRenderPassById(CCRenderPassDrawQuad::materialCast(currentQuad)->renderPassId(), frame); |
- CCRenderPassList::const_iterator foundContributingPass = std::find(renderPasses.begin(), renderPasses.end(), contributingPass); |
- if (foundContributingPass != renderPasses.end()) |
- return false; |
- } |
- return true; |
-} |
- |
-// Defined for linking tests. |
-template void CCLayerTreeHostImpl::removeRenderPasses<CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures>(CullRenderPassesWithCachedTextures, FrameData&); |
-template void CCLayerTreeHostImpl::removeRenderPasses<CCLayerTreeHostImpl::CullRenderPassesWithNoQuads>(CullRenderPassesWithNoQuads, FrameData&); |
- |
-// static |
-template<typename RenderPassCuller> |
-void CCLayerTreeHostImpl::removeRenderPasses(RenderPassCuller culler, FrameData& frame) |
-{ |
- for (size_t it = culler.renderPassListBegin(frame.renderPasses); it != culler.renderPassListEnd(frame.renderPasses); it = culler.renderPassListNext(it)) { |
- const CCRenderPass* currentPass = frame.renderPasses[it]; |
- const CCQuadList& quadList = currentPass->quadList(); |
- CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToFrontBegin(); |
- |
- for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) { |
- CCDrawQuad* currentQuad = *quadListIterator; |
- |
- if (currentQuad->material() != CCDrawQuad::RenderPass) |
- continue; |
- |
- CCRenderPassDrawQuad* renderPassQuad = static_cast<CCRenderPassDrawQuad*>(currentQuad); |
- if (!culler.shouldRemoveRenderPass(*renderPassQuad, frame)) |
- continue; |
- |
- // We are changing the vector in the middle of iteration. Because we |
- // delete render passes that draw into the current pass, we are |
- // guaranteed that any data from the iterator to the end will not |
- // change. So, capture the iterator position from the end of the |
- // list, and restore it after the change. |
- int positionFromEnd = frame.renderPasses.size() - it; |
- removeRenderPassesRecursive(renderPassQuad->renderPassId(), frame); |
- it = frame.renderPasses.size() - positionFromEnd; |
- ASSERT(it >= 0); |
- } |
- } |
-} |
- |
-bool CCLayerTreeHostImpl::prepareToDraw(FrameData& frame) |
-{ |
- TRACE_EVENT0("cc", "CCLayerTreeHostImpl::prepareToDraw"); |
- ASSERT(canDraw()); |
- |
- frame.renderSurfaceLayerList = &m_renderSurfaceLayerList; |
- frame.renderPasses.clear(); |
- frame.renderPassesById.clear(); |
- frame.renderSurfaceLayerList->clear(); |
- frame.willDrawLayers.clear(); |
- |
- if (!calculateRenderPasses(frame)) |
- return false; |
- |
- // If we return true, then we expect drawLayers() to be called before this function is called again. |
- return true; |
-} |
- |
-void CCLayerTreeHostImpl::releaseContentsTextures() |
-{ |
- if (m_contentsTexturesPurged) |
- return; |
- m_client->releaseContentsTexturesOnImplThread(); |
- setContentsTexturesPurged(); |
- m_client->setNeedsCommitOnImplThread(); |
- m_client->onCanDrawStateChanged(canDraw()); |
-} |
- |
-void CCLayerTreeHostImpl::setMemoryAllocationLimitBytes(size_t bytes) |
-{ |
- if (m_memoryAllocationLimitBytes == bytes) |
- return; |
- m_memoryAllocationLimitBytes = bytes; |
- |
- ASSERT(bytes); |
- m_client->setNeedsCommitOnImplThread(); |
-} |
- |
-void CCLayerTreeHostImpl::onVSyncParametersChanged(double monotonicTimebase, double intervalInSeconds) |
-{ |
- m_client->onVSyncParametersChanged(monotonicTimebase, intervalInSeconds); |
-} |
- |
-void CCLayerTreeHostImpl::drawLayers(const FrameData& frame) |
-{ |
- TRACE_EVENT0("cc", "CCLayerTreeHostImpl::drawLayers"); |
- ASSERT(canDraw()); |
- ASSERT(!frame.renderPasses.empty()); |
- |
- // FIXME: use the frame begin time from the overall compositor scheduler. |
- // This value is currently inaccessible because it is up in Chromium's |
- // RenderWidget. |
- m_fpsCounter->markBeginningOfFrame(currentTime()); |
- |
- if (m_settings.showDebugRects()) |
- m_debugRectHistory->saveDebugRectsForCurrentFrame(m_rootLayerImpl.get(), *frame.renderSurfaceLayerList, frame.occludingScreenSpaceRects, settings()); |
- |
- // Because the contents of the HUD depend on everything else in the frame, the contents |
- // of its texture are updated as the last thing before the frame is drawn. |
- if (m_hudLayerImpl) |
- m_hudLayerImpl->updateHudTexture(m_resourceProvider.get()); |
- |
- m_renderer->drawFrame(frame.renderPasses, frame.renderPassesById); |
- |
- // Once a RenderPass has been drawn, its damage should be cleared in |
- // case the RenderPass will be reused next frame. |
- for (unsigned int i = 0; i < frame.renderPasses.size(); i++) |
- frame.renderPasses[i]->setDamageRect(FloatRect()); |
- |
- // The next frame should start by assuming nothing has changed, and changes are noted as they occur. |
- for (unsigned int i = 0; i < frame.renderSurfaceLayerList->size(); i++) |
- (*frame.renderSurfaceLayerList)[i]->renderSurface()->damageTracker()->didDrawDamagedArea(); |
- m_rootLayerImpl->resetAllChangeTrackingForSubtree(); |
-} |
- |
-void CCLayerTreeHostImpl::didDrawAllLayers(const FrameData& frame) |
-{ |
- for (size_t i = 0; i < frame.willDrawLayers.size(); ++i) |
- frame.willDrawLayers[i]->didDraw(m_resourceProvider.get()); |
- |
- // Once all layers have been drawn, pending texture uploads should no |
- // longer block future uploads. |
- m_resourceProvider->textureUploader()->markPendingUploadsAsNonBlocking(); |
-} |
- |
-void CCLayerTreeHostImpl::finishAllRendering() |
-{ |
- if (m_renderer) |
- m_renderer->finish(); |
-} |
- |
-bool CCLayerTreeHostImpl::isContextLost() |
-{ |
- return m_renderer && m_renderer->isContextLost(); |
-} |
- |
-const RendererCapabilities& CCLayerTreeHostImpl::rendererCapabilities() const |
-{ |
- return m_renderer->capabilities(); |
-} |
- |
-bool CCLayerTreeHostImpl::swapBuffers() |
-{ |
- ASSERT(m_renderer); |
- |
- m_fpsCounter->markEndOfFrame(); |
- return m_renderer->swapBuffers(); |
-} |
- |
-const IntSize& CCLayerTreeHostImpl::deviceViewportSize() const |
-{ |
- return m_deviceViewportSize; |
-} |
- |
-const CCLayerTreeSettings& CCLayerTreeHostImpl::settings() const |
-{ |
- return m_settings; |
-} |
- |
-void CCLayerTreeHostImpl::didLoseContext() |
-{ |
- m_client->didLoseContextOnImplThread(); |
-} |
- |
-void CCLayerTreeHostImpl::onSwapBuffersComplete() |
-{ |
- m_client->onSwapBuffersCompleteOnImplThread(); |
-} |
- |
-void CCLayerTreeHostImpl::readback(void* pixels, const IntRect& rect) |
-{ |
- ASSERT(m_renderer); |
- m_renderer->getFramebufferPixels(pixels, rect); |
-} |
- |
-static CCLayerImpl* findRootScrollLayer(CCLayerImpl* layer) |
-{ |
- if (!layer) |
- return 0; |
- |
- if (layer->scrollable()) |
- return layer; |
- |
- for (size_t i = 0; i < layer->children().size(); ++i) { |
- CCLayerImpl* found = findRootScrollLayer(layer->children()[i]); |
- if (found) |
- return found; |
- } |
- |
- return 0; |
-} |
- |
-// Content layers can be either directly scrollable or contained in an outer |
-// scrolling layer which applies the scroll transform. Given a content layer, |
-// this function returns the associated scroll layer if any. |
-static CCLayerImpl* findScrollLayerForContentLayer(CCLayerImpl* layerImpl) |
-{ |
- if (!layerImpl) |
- return 0; |
- |
- if (layerImpl->scrollable()) |
- return layerImpl; |
- |
- if (layerImpl->drawsContent() && layerImpl->parent() && layerImpl->parent()->scrollable()) |
- return layerImpl->parent(); |
- |
- return 0; |
-} |
- |
-void CCLayerTreeHostImpl::setRootLayer(scoped_ptr<CCLayerImpl> layer) |
-{ |
- m_rootLayerImpl = layer.Pass(); |
- m_rootScrollLayerImpl = findRootScrollLayer(m_rootLayerImpl.get()); |
- m_currentlyScrollingLayerImpl = 0; |
- |
- if (m_rootLayerImpl && m_scrollingLayerIdFromPreviousTree != -1) |
- m_currentlyScrollingLayerImpl = CCLayerTreeHostCommon::findLayerInSubtree(m_rootLayerImpl.get(), m_scrollingLayerIdFromPreviousTree); |
- |
- m_scrollingLayerIdFromPreviousTree = -1; |
- |
- m_client->onCanDrawStateChanged(canDraw()); |
-} |
- |
-scoped_ptr<CCLayerImpl> CCLayerTreeHostImpl::detachLayerTree() |
-{ |
- // Clear all data structures that have direct references to the layer tree. |
- m_scrollingLayerIdFromPreviousTree = m_currentlyScrollingLayerImpl ? m_currentlyScrollingLayerImpl->id() : -1; |
- m_currentlyScrollingLayerImpl = 0; |
- m_renderSurfaceLayerList.clear(); |
- |
- return m_rootLayerImpl.Pass(); |
-} |
- |
-void CCLayerTreeHostImpl::setVisible(bool visible) |
-{ |
- ASSERT(CCProxy::isImplThread()); |
- |
- if (m_visible == visible) |
- return; |
- m_visible = visible; |
- didVisibilityChange(this, m_visible); |
- |
- if (!m_renderer) |
- return; |
- |
- m_renderer->setVisible(visible); |
- |
- setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers); |
-} |
- |
-bool CCLayerTreeHostImpl::initializeRenderer(scoped_ptr<CCGraphicsContext> context) |
-{ |
- // Since we will create a new resource provider, we cannot continue to use |
- // the old resources (i.e. renderSurfaces and texture IDs). Clear them |
- // before we destroy the old resource provider. |
- if (m_rootLayerImpl) { |
- clearRenderSurfaces(); |
- sendDidLoseContextRecursive(m_rootLayerImpl.get()); |
- } |
- // Note: order is important here. |
- m_renderer.clear(); |
- m_resourceProvider.clear(); |
- m_context.reset(); |
- |
- if (!context->bindToClient(this)) |
- return false; |
- |
- OwnPtr<CCResourceProvider> resourceProvider = CCResourceProvider::create(context.get()); |
- if (!resourceProvider) |
- return false; |
- |
- if (context->context3D()) |
- m_renderer = CCRendererGL::create(this, resourceProvider.get()); |
- else if (context->softwareDevice()) |
- m_renderer = CCRendererSoftware::create(this, resourceProvider.get(), context->softwareDevice()); |
- if (!m_renderer) |
- return false; |
- |
- m_resourceProvider = resourceProvider.release(); |
- m_context = context.Pass(); |
- |
- if (!m_visible) |
- m_renderer->setVisible(m_visible); |
- |
- m_client->onCanDrawStateChanged(canDraw()); |
- |
- return true; |
-} |
- |
-void CCLayerTreeHostImpl::setContentsTexturesPurged() |
-{ |
- m_contentsTexturesPurged = true; |
- m_client->onCanDrawStateChanged(canDraw()); |
-} |
- |
-void CCLayerTreeHostImpl::resetContentsTexturesPurged() |
-{ |
- m_contentsTexturesPurged = false; |
- m_client->onCanDrawStateChanged(canDraw()); |
-} |
- |
-void CCLayerTreeHostImpl::setViewportSize(const IntSize& layoutViewportSize, const IntSize& deviceViewportSize) |
-{ |
- if (layoutViewportSize == m_layoutViewportSize && deviceViewportSize == m_deviceViewportSize) |
- return; |
- |
- m_layoutViewportSize = layoutViewportSize; |
- m_deviceViewportSize = deviceViewportSize; |
- |
- m_pinchZoomViewport.setLayoutViewportSize(FloatSize(layoutViewportSize)); |
- |
- updateMaxScrollPosition(); |
- |
- if (m_renderer) |
- m_renderer->viewportChanged(); |
- |
- m_client->onCanDrawStateChanged(canDraw()); |
-} |
- |
-static void adjustScrollsForPageScaleChange(CCLayerImpl* layerImpl, float pageScaleChange) |
-{ |
- if (!layerImpl) |
- return; |
- |
- if (layerImpl->scrollable()) { |
- // We need to convert impl-side scroll deltas to pageScale space. |
- FloatSize scrollDelta = layerImpl->scrollDelta(); |
- scrollDelta.scale(pageScaleChange); |
- layerImpl->setScrollDelta(scrollDelta); |
- } |
- |
- for (size_t i = 0; i < layerImpl->children().size(); ++i) |
- adjustScrollsForPageScaleChange(layerImpl->children()[i], pageScaleChange); |
-} |
- |
-void CCLayerTreeHostImpl::setDeviceScaleFactor(float deviceScaleFactor) |
-{ |
- if (deviceScaleFactor == m_deviceScaleFactor) |
- return; |
- m_deviceScaleFactor = deviceScaleFactor; |
- |
- updateMaxScrollPosition(); |
-} |
- |
-float CCLayerTreeHostImpl::pageScaleFactor() const |
-{ |
- return m_pinchZoomViewport.pageScaleFactor(); |
-} |
- |
-void CCLayerTreeHostImpl::setPageScaleFactorAndLimits(float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) |
-{ |
- if (!pageScaleFactor) |
- return; |
- |
- float pageScaleChange = pageScaleFactor / m_pinchZoomViewport.pageScaleFactor(); |
- m_pinchZoomViewport.setPageScaleFactorAndLimits(pageScaleFactor, minPageScaleFactor, maxPageScaleFactor); |
- |
- if (!CCSettings::pageScalePinchZoomEnabled()) { |
- if (pageScaleChange != 1) |
- adjustScrollsForPageScaleChange(m_rootScrollLayerImpl, pageScaleChange); |
- } |
- |
- // Clamp delta to limits and refresh display matrix. |
- setPageScaleDelta(m_pinchZoomViewport.pageScaleDelta() / m_pinchZoomViewport.sentPageScaleDelta()); |
- m_pinchZoomViewport.setSentPageScaleDelta(1); |
-} |
- |
-void CCLayerTreeHostImpl::setPageScaleDelta(float delta) |
-{ |
- m_pinchZoomViewport.setPageScaleDelta(delta); |
- |
- updateMaxScrollPosition(); |
-} |
- |
-void CCLayerTreeHostImpl::updateMaxScrollPosition() |
-{ |
- if (!m_rootScrollLayerImpl || !m_rootScrollLayerImpl->children().size()) |
- return; |
- |
- FloatSize viewBounds = m_deviceViewportSize; |
- if (CCLayerImpl* clipLayer = m_rootScrollLayerImpl->parent()) { |
- // Compensate for non-overlay scrollbars. |
- if (clipLayer->masksToBounds()) { |
- viewBounds = clipLayer->bounds(); |
- viewBounds.scale(m_deviceScaleFactor); |
- } |
- } |
- |
- IntSize contentBounds = contentSize(); |
- if (CCSettings::pageScalePinchZoomEnabled()) { |
- // Pinch with pageScale scrolls entirely in layout space. contentSize |
- // returns the bounds including the page scale factor, so calculate the |
- // pre page-scale layout size here. |
- float pageScaleFactor = m_pinchZoomViewport.pageScaleFactor(); |
- contentBounds.setWidth(contentBounds.width() / pageScaleFactor); |
- contentBounds.setHeight(contentBounds.height() / pageScaleFactor); |
- } else { |
- viewBounds.scale(1 / m_pinchZoomViewport.pageScaleDelta()); |
- } |
- |
- IntSize maxScroll = contentBounds - expandedIntSize(viewBounds); |
- maxScroll.scale(1 / m_deviceScaleFactor); |
- |
- // The viewport may be larger than the contents in some cases, such as |
- // having a vertical scrollbar but no horizontal overflow. |
- maxScroll.clampNegativeToZero(); |
- |
- m_rootScrollLayerImpl->setMaxScrollPosition(maxScroll); |
-} |
- |
-void CCLayerTreeHostImpl::setNeedsRedraw() |
-{ |
- m_client->setNeedsRedrawOnImplThread(); |
-} |
- |
-bool CCLayerTreeHostImpl::ensureRenderSurfaceLayerList() |
-{ |
- if (!m_rootLayerImpl) |
- return false; |
- if (!m_renderer) |
- return false; |
- |
- // We need both a non-empty render surface layer list and a root render |
- // surface to be able to iterate over the visible layers. |
- if (m_renderSurfaceLayerList.size() && m_rootLayerImpl->renderSurface()) |
- return true; |
- |
- // If we are called after setRootLayer() but before prepareToDraw(), we need |
- // to recalculate the visible layers. This prevents being unable to scroll |
- // during part of a commit. |
- m_renderSurfaceLayerList.clear(); |
- calculateRenderSurfaceLayerList(m_renderSurfaceLayerList); |
- |
- return m_renderSurfaceLayerList.size(); |
-} |
- |
-CCInputHandlerClient::ScrollStatus CCLayerTreeHostImpl::scrollBegin(const IntPoint& viewportPoint, CCInputHandlerClient::ScrollInputType type) |
-{ |
- TRACE_EVENT0("cc", "CCLayerTreeHostImpl::scrollBegin"); |
- |
- ASSERT(!m_currentlyScrollingLayerImpl); |
- clearCurrentlyScrollingLayer(); |
- |
- if (!ensureRenderSurfaceLayerList()) |
- return ScrollIgnored; |
- |
- IntPoint deviceViewportPoint = viewportPoint; |
- deviceViewportPoint.scale(m_deviceScaleFactor, m_deviceScaleFactor); |
- |
- // First find out which layer was hit from the saved list of visible layers |
- // in the most recent frame. |
- CCLayerImpl* layerImpl = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(viewportPoint, m_renderSurfaceLayerList); |
- |
- // Walk up the hierarchy and look for a scrollable layer. |
- CCLayerImpl* potentiallyScrollingLayerImpl = 0; |
- for (; layerImpl; layerImpl = layerImpl->parent()) { |
- // The content layer can also block attempts to scroll outside the main thread. |
- if (layerImpl->tryScroll(deviceViewportPoint, type) == ScrollOnMainThread) { |
- m_numMainThreadScrolls++; |
- return ScrollOnMainThread; |
- } |
- |
- CCLayerImpl* scrollLayerImpl = findScrollLayerForContentLayer(layerImpl); |
- if (!scrollLayerImpl) |
- continue; |
- |
- ScrollStatus status = scrollLayerImpl->tryScroll(viewportPoint, type); |
- |
- // If any layer wants to divert the scroll event to the main thread, abort. |
- if (status == ScrollOnMainThread) { |
- m_numMainThreadScrolls++; |
- return ScrollOnMainThread; |
- } |
- |
- if (status == ScrollStarted && !potentiallyScrollingLayerImpl) |
- potentiallyScrollingLayerImpl = scrollLayerImpl; |
- } |
- |
- if (potentiallyScrollingLayerImpl) { |
- m_currentlyScrollingLayerImpl = potentiallyScrollingLayerImpl; |
- // Gesture events need to be transformed from screen coordinates to local layer coordinates |
- // so that the scrolling contents exactly follow the user's finger. In contrast, wheel |
- // events are already in local layer coordinates so we can just apply them directly. |
- m_scrollDeltaIsInScreenSpace = (type == Gesture); |
- m_numImplThreadScrolls++; |
- return ScrollStarted; |
- } |
- return ScrollIgnored; |
-} |
- |
-static FloatSize scrollLayerWithScreenSpaceDelta(CCPinchZoomViewport* viewport, CCLayerImpl& layerImpl, const FloatPoint& screenSpacePoint, const FloatSize& screenSpaceDelta) |
-{ |
- // Layers with non-invertible screen space transforms should not have passed the scroll hit |
- // test in the first place. |
- ASSERT(layerImpl.screenSpaceTransform().isInvertible()); |
- WebTransformationMatrix inverseScreenSpaceTransform = layerImpl.screenSpaceTransform().inverse(); |
- |
- // First project the scroll start and end points to local layer space to find the scroll delta |
- // in layer coordinates. |
- bool startClipped, endClipped; |
- FloatPoint screenSpaceEndPoint = screenSpacePoint + screenSpaceDelta; |
- FloatPoint localStartPoint = CCMathUtil::projectPoint(inverseScreenSpaceTransform, screenSpacePoint, startClipped); |
- FloatPoint localEndPoint = CCMathUtil::projectPoint(inverseScreenSpaceTransform, screenSpaceEndPoint, endClipped); |
- |
- // In general scroll point coordinates should not get clipped. |
- ASSERT(!startClipped); |
- ASSERT(!endClipped); |
- if (startClipped || endClipped) |
- return FloatSize(); |
- |
- // Apply the scroll delta. |
- FloatSize previousDelta(layerImpl.scrollDelta()); |
- FloatSize unscrolled = layerImpl.scrollBy(localEndPoint - localStartPoint); |
- |
- if (viewport) |
- viewport->applyScroll(unscrolled); |
- |
- // Calculate the applied scroll delta in screen space coordinates. |
- FloatPoint actualLocalEndPoint = localStartPoint + layerImpl.scrollDelta() - previousDelta; |
- FloatPoint actualScreenSpaceEndPoint = CCMathUtil::mapPoint(layerImpl.screenSpaceTransform(), actualLocalEndPoint, endClipped); |
- ASSERT(!endClipped); |
- if (endClipped) |
- return FloatSize(); |
- return actualScreenSpaceEndPoint - screenSpacePoint; |
-} |
- |
-static FloatSize scrollLayerWithLocalDelta(CCLayerImpl& layerImpl, const FloatSize& localDelta) |
-{ |
- FloatSize previousDelta(layerImpl.scrollDelta()); |
- layerImpl.scrollBy(localDelta); |
- return layerImpl.scrollDelta() - previousDelta; |
-} |
- |
-void CCLayerTreeHostImpl::scrollBy(const IntPoint& viewportPoint, const IntSize& scrollDelta) |
-{ |
- TRACE_EVENT0("cc", "CCLayerTreeHostImpl::scrollBy"); |
- if (!m_currentlyScrollingLayerImpl) |
- return; |
- |
- FloatSize pendingDelta(scrollDelta); |
- |
- pendingDelta.scale(m_deviceScaleFactor); |
- |
- for (CCLayerImpl* layerImpl = m_currentlyScrollingLayerImpl; layerImpl; layerImpl = layerImpl->parent()) { |
- if (!layerImpl->scrollable()) |
- continue; |
- |
- CCPinchZoomViewport* viewport = layerImpl == m_rootScrollLayerImpl ? &m_pinchZoomViewport : 0; |
- FloatSize appliedDelta; |
- if (m_scrollDeltaIsInScreenSpace) |
- appliedDelta = scrollLayerWithScreenSpaceDelta(viewport, *layerImpl, viewportPoint, pendingDelta); |
- else |
- appliedDelta = scrollLayerWithLocalDelta(*layerImpl, pendingDelta); |
- |
- // If the layer wasn't able to move, try the next one in the hierarchy. |
- float moveThresholdSquared = 0.1f * 0.1f; |
- if (appliedDelta.diagonalLengthSquared() < moveThresholdSquared) |
- continue; |
- |
- // If the applied delta is within 45 degrees of the input delta, bail out to make it easier |
- // to scroll just one layer in one direction without affecting any of its parents. |
- float angleThreshold = 45; |
- if (CCMathUtil::smallestAngleBetweenVectors(appliedDelta, pendingDelta) < angleThreshold) { |
- pendingDelta = FloatSize(); |
- break; |
- } |
- |
- // Allow further movement only on an axis perpendicular to the direction in which the layer |
- // moved. |
- FloatSize perpendicularAxis(-appliedDelta.height(), appliedDelta.width()); |
- pendingDelta = CCMathUtil::projectVector(pendingDelta, perpendicularAxis); |
- |
- if (flooredIntSize(pendingDelta).isZero()) |
- break; |
- } |
- |
- if (!scrollDelta.isZero() && flooredIntSize(pendingDelta).isEmpty()) { |
- m_client->setNeedsCommitOnImplThread(); |
- m_client->setNeedsRedrawOnImplThread(); |
- } |
-} |
- |
-void CCLayerTreeHostImpl::clearCurrentlyScrollingLayer() |
-{ |
- m_currentlyScrollingLayerImpl = 0; |
- m_scrollingLayerIdFromPreviousTree = -1; |
-} |
- |
-void CCLayerTreeHostImpl::scrollEnd() |
-{ |
- clearCurrentlyScrollingLayer(); |
-} |
- |
-void CCLayerTreeHostImpl::pinchGestureBegin() |
-{ |
- m_pinchGestureActive = true; |
- m_previousPinchAnchor = IntPoint(); |
- |
- if (m_rootScrollLayerImpl && m_rootScrollLayerImpl->scrollbarAnimationController()) |
- m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureBegin(); |
-} |
- |
-void CCLayerTreeHostImpl::pinchGestureUpdate(float magnifyDelta, |
- const IntPoint& anchor) |
-{ |
- TRACE_EVENT0("cc", "CCLayerTreeHostImpl::pinchGestureUpdate"); |
- |
- if (!m_rootScrollLayerImpl) |
- return; |
- |
- if (m_previousPinchAnchor == IntPoint::zero()) |
- m_previousPinchAnchor = anchor; |
- |
- // Keep the center-of-pinch anchor specified by (x, y) in a stable |
- // position over the course of the magnify. |
- float pageScaleDelta = m_pinchZoomViewport.pageScaleDelta(); |
- FloatPoint previousScaleAnchor(m_previousPinchAnchor.x() / pageScaleDelta, |
- m_previousPinchAnchor.y() / pageScaleDelta); |
- setPageScaleDelta(pageScaleDelta * magnifyDelta); |
- pageScaleDelta = m_pinchZoomViewport.pageScaleDelta(); |
- FloatPoint newScaleAnchor(anchor.x() / pageScaleDelta, anchor.y() / pageScaleDelta); |
- FloatSize move = previousScaleAnchor - newScaleAnchor; |
- |
- m_previousPinchAnchor = anchor; |
- |
- if (CCSettings::pageScalePinchZoomEnabled()) { |
- // Compute the application of the delta with respect to the current page zoom of the page. |
- move.scale(1 / (m_pinchZoomViewport.pageScaleFactor() * m_deviceScaleFactor)); |
- } |
- |
- FloatSize scrollOverflow = CCSettings::pageScalePinchZoomEnabled() ? m_pinchZoomViewport.applyScroll(move) : move; |
- m_rootScrollLayerImpl->scrollBy(roundedIntSize(scrollOverflow)); |
- |
- if (m_rootScrollLayerImpl->scrollbarAnimationController()) |
- m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureUpdate(); |
- |
- m_client->setNeedsCommitOnImplThread(); |
- m_client->setNeedsRedrawOnImplThread(); |
-} |
- |
-void CCLayerTreeHostImpl::pinchGestureEnd() |
-{ |
- m_pinchGestureActive = false; |
- |
- if (m_rootScrollLayerImpl && m_rootScrollLayerImpl->scrollbarAnimationController()) |
- m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureEnd(); |
- |
- m_client->setNeedsCommitOnImplThread(); |
-} |
- |
-void CCLayerTreeHostImpl::computeDoubleTapZoomDeltas(CCScrollAndScaleSet* scrollInfo) |
-{ |
- float pageScale = m_pageScaleAnimation->finalPageScale(); |
- IntSize scrollOffset = m_pageScaleAnimation->finalScrollOffset(); |
- scrollOffset.scale(m_pinchZoomViewport.pageScaleFactor() / pageScale); |
- makeScrollAndScaleSet(scrollInfo, scrollOffset, pageScale); |
-} |
- |
-void CCLayerTreeHostImpl::computePinchZoomDeltas(CCScrollAndScaleSet* scrollInfo) |
-{ |
- if (!m_rootScrollLayerImpl) |
- return; |
- |
- // Only send fake scroll/zoom deltas if we're pinch zooming out by a |
- // significant amount. This also ensures only one fake delta set will be |
- // sent. |
- const float pinchZoomOutSensitivity = 0.95f; |
- if (m_pinchZoomViewport.pageScaleDelta() > pinchZoomOutSensitivity) |
- return; |
- |
- // Compute where the scroll offset/page scale would be if fully pinch-zoomed |
- // out from the anchor point. |
- IntSize scrollBegin = flooredIntSize(m_rootScrollLayerImpl->scrollPosition() + m_rootScrollLayerImpl->scrollDelta()); |
- scrollBegin.scale(m_pinchZoomViewport.pageScaleDelta()); |
- float scaleBegin = m_pinchZoomViewport.totalPageScaleFactor(); |
- float pageScaleDeltaToSend = m_pinchZoomViewport.minPageScaleFactor() / m_pinchZoomViewport.pageScaleFactor(); |
- FloatSize scaledContentsSize = contentSize(); |
- scaledContentsSize.scale(pageScaleDeltaToSend); |
- |
- FloatSize anchor = toSize(m_previousPinchAnchor); |
- FloatSize scrollEnd = scrollBegin + anchor; |
- scrollEnd.scale(m_pinchZoomViewport.minPageScaleFactor() / scaleBegin); |
- scrollEnd -= anchor; |
- scrollEnd = scrollEnd.shrunkTo(roundedIntSize(scaledContentsSize - m_deviceViewportSize)).expandedTo(FloatSize(0, 0)); |
- scrollEnd.scale(1 / pageScaleDeltaToSend); |
- scrollEnd.scale(m_deviceScaleFactor); |
- |
- makeScrollAndScaleSet(scrollInfo, roundedIntSize(scrollEnd), m_pinchZoomViewport.minPageScaleFactor()); |
-} |
- |
-void CCLayerTreeHostImpl::makeScrollAndScaleSet(CCScrollAndScaleSet* scrollInfo, const IntSize& scrollOffset, float pageScale) |
-{ |
- if (!m_rootScrollLayerImpl) |
- return; |
- |
- CCLayerTreeHostCommon::ScrollUpdateInfo scroll; |
- scroll.layerId = m_rootScrollLayerImpl->id(); |
- scroll.scrollDelta = scrollOffset - toSize(m_rootScrollLayerImpl->scrollPosition()); |
- scrollInfo->scrolls.append(scroll); |
- m_rootScrollLayerImpl->setSentScrollDelta(scroll.scrollDelta); |
- scrollInfo->pageScaleDelta = pageScale / m_pinchZoomViewport.pageScaleFactor(); |
- m_pinchZoomViewport.setSentPageScaleDelta(scrollInfo->pageScaleDelta); |
-} |
- |
-static void collectScrollDeltas(CCScrollAndScaleSet* scrollInfo, CCLayerImpl* layerImpl) |
-{ |
- if (!layerImpl) |
- return; |
- |
- if (!layerImpl->scrollDelta().isZero()) { |
- IntSize scrollDelta = flooredIntSize(layerImpl->scrollDelta()); |
- CCLayerTreeHostCommon::ScrollUpdateInfo scroll; |
- scroll.layerId = layerImpl->id(); |
- scroll.scrollDelta = scrollDelta; |
- scrollInfo->scrolls.append(scroll); |
- layerImpl->setSentScrollDelta(scrollDelta); |
- } |
- |
- for (size_t i = 0; i < layerImpl->children().size(); ++i) |
- collectScrollDeltas(scrollInfo, layerImpl->children()[i]); |
-} |
- |
-scoped_ptr<CCScrollAndScaleSet> CCLayerTreeHostImpl::processScrollDeltas() |
-{ |
- scoped_ptr<CCScrollAndScaleSet> scrollInfo(new CCScrollAndScaleSet()); |
- |
- if (m_pinchGestureActive || m_pageScaleAnimation) { |
- scrollInfo->pageScaleDelta = 1; |
- m_pinchZoomViewport.setSentPageScaleDelta(1); |
- // FIXME(aelias): Make these painting optimizations compatible with |
- // compositor-side scaling. |
- if (!CCSettings::pageScalePinchZoomEnabled()) { |
- if (m_pinchGestureActive) |
- computePinchZoomDeltas(scrollInfo.get()); |
- else if (m_pageScaleAnimation.get()) |
- computeDoubleTapZoomDeltas(scrollInfo.get()); |
- } |
- return scrollInfo.Pass(); |
- } |
- |
- collectScrollDeltas(scrollInfo.get(), m_rootLayerImpl.get()); |
- scrollInfo->pageScaleDelta = m_pinchZoomViewport.pageScaleDelta(); |
- m_pinchZoomViewport.setSentPageScaleDelta(scrollInfo->pageScaleDelta); |
- |
- return scrollInfo.Pass(); |
-} |
- |
-WebTransformationMatrix CCLayerTreeHostImpl::implTransform() const |
-{ |
- return m_pinchZoomViewport.implTransform(); |
-} |
- |
-void CCLayerTreeHostImpl::setFullRootLayerDamage() |
-{ |
- if (m_rootLayerImpl) { |
- CCRenderSurface* renderSurface = m_rootLayerImpl->renderSurface(); |
- if (renderSurface) |
- renderSurface->damageTracker()->forceFullDamageNextUpdate(); |
- } |
-} |
- |
-void CCLayerTreeHostImpl::animatePageScale(double monotonicTime) |
-{ |
- if (!m_pageScaleAnimation || !m_rootScrollLayerImpl) |
- return; |
- |
- IntSize scrollTotal = flooredIntSize(m_rootScrollLayerImpl->scrollPosition() + m_rootScrollLayerImpl->scrollDelta()); |
- |
- setPageScaleDelta(m_pageScaleAnimation->pageScaleAtTime(monotonicTime) / m_pinchZoomViewport.pageScaleFactor()); |
- IntSize nextScroll = m_pageScaleAnimation->scrollOffsetAtTime(monotonicTime); |
- nextScroll.scale(1 / m_pinchZoomViewport.pageScaleDelta()); |
- m_rootScrollLayerImpl->scrollBy(nextScroll - scrollTotal); |
- m_client->setNeedsRedrawOnImplThread(); |
- |
- if (m_pageScaleAnimation->isAnimationCompleteAtTime(monotonicTime)) { |
- m_pageScaleAnimation.clear(); |
- m_client->setNeedsCommitOnImplThread(); |
- } |
-} |
- |
-void CCLayerTreeHostImpl::animateLayers(double monotonicTime, double wallClockTime) |
-{ |
- if (!CCSettings::acceleratedAnimationEnabled() || !m_needsAnimateLayers || !m_rootLayerImpl) |
- return; |
- |
- TRACE_EVENT0("cc", "CCLayerTreeHostImpl::animateLayers"); |
- |
- scoped_ptr<CCAnimationEventsVector> events(make_scoped_ptr(new CCAnimationEventsVector)); |
- |
- bool didAnimate = false; |
- animateLayersRecursive(m_rootLayerImpl.get(), monotonicTime, wallClockTime, events.get(), didAnimate, m_needsAnimateLayers); |
- |
- if (!events->empty()) |
- m_client->postAnimationEventsToMainThreadOnImplThread(events.Pass(), wallClockTime); |
- |
- if (didAnimate) |
- m_client->setNeedsRedrawOnImplThread(); |
- |
- setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers); |
-} |
- |
-base::TimeDelta CCLayerTreeHostImpl::lowFrequencyAnimationInterval() const |
-{ |
- return base::TimeDelta::FromSeconds(1); |
-} |
- |
-void CCLayerTreeHostImpl::sendDidLoseContextRecursive(CCLayerImpl* current) |
-{ |
- ASSERT(current); |
- current->didLoseContext(); |
- if (current->maskLayer()) |
- sendDidLoseContextRecursive(current->maskLayer()); |
- if (current->replicaLayer()) |
- sendDidLoseContextRecursive(current->replicaLayer()); |
- for (size_t i = 0; i < current->children().size(); ++i) |
- sendDidLoseContextRecursive(current->children()[i]); |
-} |
- |
-static void clearRenderSurfacesOnCCLayerImplRecursive(CCLayerImpl* current) |
-{ |
- ASSERT(current); |
- for (size_t i = 0; i < current->children().size(); ++i) |
- clearRenderSurfacesOnCCLayerImplRecursive(current->children()[i]); |
- current->clearRenderSurface(); |
-} |
- |
-void CCLayerTreeHostImpl::clearRenderSurfaces() |
-{ |
- clearRenderSurfacesOnCCLayerImplRecursive(m_rootLayerImpl.get()); |
- m_renderSurfaceLayerList.clear(); |
-} |
- |
-std::string CCLayerTreeHostImpl::layerTreeAsText() const |
-{ |
- std::string str; |
- if (m_rootLayerImpl) { |
- str = m_rootLayerImpl->layerTreeAsText(); |
- str += "RenderSurfaces:\n"; |
- dumpRenderSurfaces(&str, 1, m_rootLayerImpl.get()); |
- } |
- return str; |
-} |
- |
-void CCLayerTreeHostImpl::dumpRenderSurfaces(std::string* str, int indent, const CCLayerImpl* layer) const |
-{ |
- if (layer->renderSurface()) |
- layer->renderSurface()->dumpSurface(str, indent); |
- |
- for (size_t i = 0; i < layer->children().size(); ++i) |
- dumpRenderSurfaces(str, indent, layer->children()[i]); |
-} |
- |
-int CCLayerTreeHostImpl::sourceAnimationFrameNumber() const |
-{ |
- return fpsCounter()->currentFrameNumber(); |
-} |
- |
-void CCLayerTreeHostImpl::renderingStats(CCRenderingStats* stats) const |
-{ |
- stats->numFramesSentToScreen = fpsCounter()->currentFrameNumber(); |
- stats->droppedFrameCount = fpsCounter()->droppedFrameCount(); |
- stats->numImplThreadScrolls = m_numImplThreadScrolls; |
- stats->numMainThreadScrolls = m_numMainThreadScrolls; |
-} |
- |
-void CCLayerTreeHostImpl::animateScrollbars(double monotonicTime) |
-{ |
- animateScrollbarsRecursive(m_rootLayerImpl.get(), monotonicTime); |
-} |
- |
-void CCLayerTreeHostImpl::animateScrollbarsRecursive(CCLayerImpl* layer, double monotonicTime) |
-{ |
- if (!layer) |
- return; |
- |
- CCScrollbarAnimationController* scrollbarController = layer->scrollbarAnimationController(); |
- if (scrollbarController && scrollbarController->animate(monotonicTime)) |
- m_client->setNeedsRedrawOnImplThread(); |
- |
- for (size_t i = 0; i < layer->children().size(); ++i) |
- animateScrollbarsRecursive(layer->children()[i], monotonicTime); |
-} |
- |
-} // namespace cc |