| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "config.h" | |
| 6 | |
| 7 #include "CCLayerTreeHostImpl.h" | |
| 8 | |
| 9 #include "base/basictypes.h" | |
| 10 #include "CCAppendQuadsData.h" | |
| 11 #include "CCDamageTracker.h" | |
| 12 #include "CCDebugRectHistory.h" | |
| 13 #include "CCDelayBasedTimeSource.h" | |
| 14 #include "CCFontAtlas.h" | |
| 15 #include "CCFrameRateCounter.h" | |
| 16 #include "CCHeadsUpDisplayLayerImpl.h" | |
| 17 #include "CCLayerIterator.h" | |
| 18 #include "CCLayerTreeHost.h" | |
| 19 #include "CCLayerTreeHostCommon.h" | |
| 20 #include "CCMathUtil.h" | |
| 21 #include "CCOverdrawMetrics.h" | |
| 22 #include "CCPageScaleAnimation.h" | |
| 23 #include "CCPrioritizedTextureManager.h" | |
| 24 #include "CCRenderPassDrawQuad.h" | |
| 25 #include "CCRendererGL.h" | |
| 26 #include "CCRendererSoftware.h" | |
| 27 #include "CCRenderingStats.h" | |
| 28 #include "CCScrollbarAnimationController.h" | |
| 29 #include "CCScrollbarLayerImpl.h" | |
| 30 #include "CCSettings.h" | |
| 31 #include "CCSingleThreadProxy.h" | |
| 32 #include "TextureUploader.h" | |
| 33 #include "TraceEvent.h" | |
| 34 #include <wtf/CurrentTime.h> | |
| 35 #include <algorithm> | |
| 36 | |
| 37 using WebKit::WebTransformationMatrix; | |
| 38 | |
| 39 namespace { | |
| 40 | |
| 41 void didVisibilityChange(cc::CCLayerTreeHostImpl* id, bool visible) | |
| 42 { | |
| 43 if (visible) { | |
| 44 TRACE_EVENT_ASYNC_BEGIN1("webkit", "CCLayerTreeHostImpl::setVisible", id
, "CCLayerTreeHostImpl", id); | |
| 45 return; | |
| 46 } | |
| 47 | |
| 48 TRACE_EVENT_ASYNC_END0("webkit", "CCLayerTreeHostImpl::setVisible", id); | |
| 49 } | |
| 50 | |
| 51 } // namespace | |
| 52 | |
| 53 namespace cc { | |
| 54 | |
| 55 CCPinchZoomViewport::CCPinchZoomViewport() | |
| 56 : m_pageScaleFactor(1) | |
| 57 , m_pageScaleDelta(1) | |
| 58 , m_sentPageScaleDelta(1) | |
| 59 , m_minPageScaleFactor(0) | |
| 60 , m_maxPageScaleFactor(0) | |
| 61 { | |
| 62 } | |
| 63 | |
| 64 float CCPinchZoomViewport::totalPageScaleFactor() const | |
| 65 { | |
| 66 return m_pageScaleFactor * m_pageScaleDelta; | |
| 67 } | |
| 68 | |
| 69 void CCPinchZoomViewport::setPageScaleDelta(float delta) | |
| 70 { | |
| 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; | |
| 77 | |
| 78 if (delta == m_pageScaleDelta) | |
| 79 return; | |
| 80 | |
| 81 m_pageScaleDelta = delta; | |
| 82 } | |
| 83 | |
| 84 bool CCPinchZoomViewport::setPageScaleFactorAndLimits(float pageScaleFactor, flo
at minPageScaleFactor, float maxPageScaleFactor) | |
| 85 { | |
| 86 ASSERT(pageScaleFactor); | |
| 87 | |
| 88 if (m_sentPageScaleDelta == 1 && pageScaleFactor == m_pageScaleFactor && min
PageScaleFactor == m_minPageScaleFactor && maxPageScaleFactor == m_maxPageScaleF
actor) | |
| 89 return false; | |
| 90 | |
| 91 m_minPageScaleFactor = minPageScaleFactor; | |
| 92 m_maxPageScaleFactor = maxPageScaleFactor; | |
| 93 | |
| 94 m_pageScaleFactor = pageScaleFactor; | |
| 95 return true; | |
| 96 } | |
| 97 | |
| 98 FloatRect CCPinchZoomViewport::bounds() const | |
| 99 { | |
| 100 FloatSize scaledViewportSize = m_layoutViewportSize; | |
| 101 scaledViewportSize.scale(1 / totalPageScaleFactor()); | |
| 102 | |
| 103 FloatRect bounds(FloatPoint(0, 0), scaledViewportSize); | |
| 104 bounds.setLocation(m_pinchViewportScrollDelta); | |
| 105 | |
| 106 return bounds; | |
| 107 } | |
| 108 | |
| 109 FloatSize CCPinchZoomViewport::applyScroll(FloatSize& delta) | |
| 110 { | |
| 111 FloatSize overflow; | |
| 112 FloatRect pinchedBounds = bounds(); | |
| 113 | |
| 114 pinchedBounds.move(delta); | |
| 115 if (pinchedBounds.x() < 0) { | |
| 116 overflow.setWidth(pinchedBounds.x()); | |
| 117 pinchedBounds.setX(0); | |
| 118 } | |
| 119 | |
| 120 if (pinchedBounds.y() < 0) { | |
| 121 overflow.setHeight(pinchedBounds.y()); | |
| 122 pinchedBounds.setY(0); | |
| 123 } | |
| 124 | |
| 125 if (pinchedBounds.maxX() > m_layoutViewportSize.width()) { | |
| 126 overflow.setWidth( | |
| 127 pinchedBounds.maxX() - m_layoutViewportSize.width()); | |
| 128 pinchedBounds.move( | |
| 129 m_layoutViewportSize.width() - pinchedBounds.maxX(), 0); | |
| 130 } | |
| 131 | |
| 132 if (pinchedBounds.maxY() > m_layoutViewportSize.height()) { | |
| 133 overflow.setHeight( | |
| 134 pinchedBounds.maxY() - m_layoutViewportSize.height()); | |
| 135 pinchedBounds.move( | |
| 136 0, m_layoutViewportSize.height() - pinchedBounds.maxY()); | |
| 137 } | |
| 138 m_pinchViewportScrollDelta = pinchedBounds.location(); | |
| 139 | |
| 140 return overflow; | |
| 141 } | |
| 142 | |
| 143 WebTransformationMatrix CCPinchZoomViewport::implTransform() const | |
| 144 { | |
| 145 WebTransformationMatrix transform; | |
| 146 transform.scale(m_pageScaleDelta); | |
| 147 | |
| 148 // If the pinch state is applied in the impl, then push it to the | |
| 149 // impl transform, otherwise the scale is handled by WebCore. | |
| 150 if (CCSettings::pageScalePinchZoomEnabled()) { | |
| 151 transform.scale(m_pageScaleFactor); | |
| 152 transform.translate(-m_pinchViewportScrollDelta.x(), | |
| 153 -m_pinchViewportScrollDelta.y()); | |
| 154 } | |
| 155 | |
| 156 return transform; | |
| 157 } | |
| 158 | |
| 159 class CCLayerTreeHostImplTimeSourceAdapter : public CCTimeSourceClient { | |
| 160 public: | |
| 161 static PassOwnPtr<CCLayerTreeHostImplTimeSourceAdapter> create(CCLayerTreeHo
stImpl* layerTreeHostImpl, PassRefPtr<CCDelayBasedTimeSource> timeSource) | |
| 162 { | |
| 163 return adoptPtr(new CCLayerTreeHostImplTimeSourceAdapter(layerTreeHostIm
pl, timeSource)); | |
| 164 } | |
| 165 virtual ~CCLayerTreeHostImplTimeSourceAdapter() | |
| 166 { | |
| 167 m_timeSource->setClient(0); | |
| 168 m_timeSource->setActive(false); | |
| 169 } | |
| 170 | |
| 171 virtual void onTimerTick() OVERRIDE | |
| 172 { | |
| 173 // FIXME: We require that animate be called on the impl thread. This | |
| 174 // avoids asserts in single threaded mode. Ideally background ticking | |
| 175 // would be handled by the proxy/scheduler and this could be removed. | |
| 176 DebugScopedSetImplThread impl; | |
| 177 | |
| 178 m_layerTreeHostImpl->animate(monotonicallyIncreasingTime(), currentTime(
)); | |
| 179 } | |
| 180 | |
| 181 void setActive(bool active) | |
| 182 { | |
| 183 if (active != m_timeSource->active()) | |
| 184 m_timeSource->setActive(active); | |
| 185 } | |
| 186 | |
| 187 private: | |
| 188 CCLayerTreeHostImplTimeSourceAdapter(CCLayerTreeHostImpl* layerTreeHostImpl,
PassRefPtr<CCDelayBasedTimeSource> timeSource) | |
| 189 : m_layerTreeHostImpl(layerTreeHostImpl) | |
| 190 , m_timeSource(timeSource) | |
| 191 { | |
| 192 m_timeSource->setClient(this); | |
| 193 } | |
| 194 | |
| 195 CCLayerTreeHostImpl* m_layerTreeHostImpl; | |
| 196 RefPtr<CCDelayBasedTimeSource> m_timeSource; | |
| 197 | |
| 198 DISALLOW_COPY_AND_ASSIGN(CCLayerTreeHostImplTimeSourceAdapter); | |
| 199 }; | |
| 200 | |
| 201 CCLayerTreeHostImpl::FrameData::FrameData() | |
| 202 { | |
| 203 } | |
| 204 | |
| 205 CCLayerTreeHostImpl::FrameData::~FrameData() | |
| 206 { | |
| 207 } | |
| 208 | |
| 209 scoped_ptr<CCLayerTreeHostImpl> CCLayerTreeHostImpl::create(const CCLayerTreeSet
tings& settings, CCLayerTreeHostImplClient* client) | |
| 210 { | |
| 211 return make_scoped_ptr(new CCLayerTreeHostImpl(settings, client)); | |
| 212 } | |
| 213 | |
| 214 CCLayerTreeHostImpl::CCLayerTreeHostImpl(const CCLayerTreeSettings& settings, CC
LayerTreeHostImplClient* client) | |
| 215 : m_client(client) | |
| 216 , m_sourceFrameNumber(-1) | |
| 217 , m_rootScrollLayerImpl(0) | |
| 218 , m_currentlyScrollingLayerImpl(0) | |
| 219 , m_hudLayerImpl(0) | |
| 220 , m_scrollingLayerIdFromPreviousTree(-1) | |
| 221 , m_scrollDeltaIsInScreenSpace(false) | |
| 222 , m_settings(settings) | |
| 223 , m_deviceScaleFactor(1) | |
| 224 , m_visible(true) | |
| 225 , m_contentsTexturesPurged(false) | |
| 226 , m_memoryAllocationLimitBytes(CCPrioritizedTextureManager::defaultMemoryAll
ocationLimit()) | |
| 227 , m_backgroundColor(0) | |
| 228 , m_hasTransparentBackground(false) | |
| 229 , m_needsAnimateLayers(false) | |
| 230 , m_pinchGestureActive(false) | |
| 231 , m_fpsCounter(CCFrameRateCounter::create()) | |
| 232 , m_debugRectHistory(CCDebugRectHistory::create()) | |
| 233 , m_numImplThreadScrolls(0) | |
| 234 , m_numMainThreadScrolls(0) | |
| 235 { | |
| 236 ASSERT(CCProxy::isImplThread()); | |
| 237 didVisibilityChange(this, m_visible); | |
| 238 } | |
| 239 | |
| 240 CCLayerTreeHostImpl::~CCLayerTreeHostImpl() | |
| 241 { | |
| 242 ASSERT(CCProxy::isImplThread()); | |
| 243 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::~CCLayerTreeHostImpl()"); | |
| 244 | |
| 245 if (m_rootLayerImpl) | |
| 246 clearRenderSurfaces(); | |
| 247 } | |
| 248 | |
| 249 void CCLayerTreeHostImpl::beginCommit() | |
| 250 { | |
| 251 } | |
| 252 | |
| 253 void CCLayerTreeHostImpl::commitComplete() | |
| 254 { | |
| 255 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::commitComplete"); | |
| 256 // Recompute max scroll position; must be after layer content bounds are | |
| 257 // updated. | |
| 258 updateMaxScrollPosition(); | |
| 259 } | |
| 260 | |
| 261 bool CCLayerTreeHostImpl::canDraw() | |
| 262 { | |
| 263 // Note: If you are changing this function or any other function that might | |
| 264 // affect the result of canDraw, make sure to call m_client->onCanDrawStateC
hanged | |
| 265 // in the proper places and update the notifyIfCanDrawChanged test. | |
| 266 | |
| 267 if (!m_rootLayerImpl) { | |
| 268 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw no root layer")
; | |
| 269 return false; | |
| 270 } | |
| 271 if (deviceViewportSize().isEmpty()) { | |
| 272 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw empty viewport"
); | |
| 273 return false; | |
| 274 } | |
| 275 if (!m_renderer) { | |
| 276 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw no renderer"); | |
| 277 return false; | |
| 278 } | |
| 279 if (m_contentsTexturesPurged) { | |
| 280 TRACE_EVENT_INSTANT0("cc", "CCLayerTreeHostImpl::canDraw contents textur
es purged"); | |
| 281 return false; | |
| 282 } | |
| 283 return true; | |
| 284 } | |
| 285 | |
| 286 CCGraphicsContext* CCLayerTreeHostImpl::context() const | |
| 287 { | |
| 288 return m_context.get(); | |
| 289 } | |
| 290 | |
| 291 void CCLayerTreeHostImpl::animate(double monotonicTime, double wallClockTime) | |
| 292 { | |
| 293 animatePageScale(monotonicTime); | |
| 294 animateLayers(monotonicTime, wallClockTime); | |
| 295 animateScrollbars(monotonicTime); | |
| 296 } | |
| 297 | |
| 298 void CCLayerTreeHostImpl::startPageScaleAnimation(const IntSize& targetPosition,
bool anchorPoint, float pageScale, double startTime, double duration) | |
| 299 { | |
| 300 if (!m_rootScrollLayerImpl) | |
| 301 return; | |
| 302 | |
| 303 IntSize scrollTotal = flooredIntSize(m_rootScrollLayerImpl->scrollPosition()
+ m_rootScrollLayerImpl->scrollDelta()); | |
| 304 scrollTotal.scale(m_pinchZoomViewport.pageScaleDelta()); | |
| 305 float scaleTotal = m_pinchZoomViewport.totalPageScaleFactor(); | |
| 306 IntSize scaledContentSize = contentSize(); | |
| 307 scaledContentSize.scale(m_pinchZoomViewport.pageScaleDelta()); | |
| 308 | |
| 309 m_pageScaleAnimation = CCPageScaleAnimation::create(scrollTotal, scaleTotal,
m_deviceViewportSize, scaledContentSize, startTime); | |
| 310 | |
| 311 if (anchorPoint) { | |
| 312 IntSize windowAnchor(targetPosition); | |
| 313 windowAnchor.scale(scaleTotal / pageScale); | |
| 314 windowAnchor -= scrollTotal; | |
| 315 m_pageScaleAnimation->zoomWithAnchor(windowAnchor, pageScale, duration); | |
| 316 } else | |
| 317 m_pageScaleAnimation->zoomTo(targetPosition, pageScale, duration); | |
| 318 | |
| 319 m_client->setNeedsRedrawOnImplThread(); | |
| 320 m_client->setNeedsCommitOnImplThread(); | |
| 321 } | |
| 322 | |
| 323 void CCLayerTreeHostImpl::scheduleAnimation() | |
| 324 { | |
| 325 m_client->setNeedsRedrawOnImplThread(); | |
| 326 } | |
| 327 | |
| 328 void CCLayerTreeHostImpl::trackDamageForAllSurfaces(CCLayerImpl* rootDrawLayer,
const CCLayerList& renderSurfaceLayerList) | |
| 329 { | |
| 330 // For now, we use damage tracking to compute a global scissor. To do this,
we must | |
| 331 // compute all damage tracking before drawing anything, so that we know the
root | |
| 332 // damage rect. The root damage rect is then used to scissor each surface. | |
| 333 | |
| 334 for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0
; --surfaceIndex) { | |
| 335 CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex]; | |
| 336 CCRenderSurface* renderSurface = renderSurfaceLayer->renderSurface(); | |
| 337 ASSERT(renderSurface); | |
| 338 renderSurface->damageTracker()->updateDamageTrackingState(renderSurface-
>layerList(), renderSurfaceLayer->id(), renderSurface->surfacePropertyChangedOnl
yFromDescendant(), renderSurface->contentRect(), renderSurfaceLayer->maskLayer()
, renderSurfaceLayer->filters()); | |
| 339 } | |
| 340 } | |
| 341 | |
| 342 void CCLayerTreeHostImpl::updateRootScrollLayerImplTransform() | |
| 343 { | |
| 344 if (m_rootScrollLayerImpl) { | |
| 345 m_rootScrollLayerImpl->setImplTransform(implTransform()); | |
| 346 } | |
| 347 } | |
| 348 | |
| 349 void CCLayerTreeHostImpl::calculateRenderSurfaceLayerList(CCLayerList& renderSur
faceLayerList) | |
| 350 { | |
| 351 ASSERT(renderSurfaceLayerList.empty()); | |
| 352 ASSERT(m_rootLayerImpl); | |
| 353 ASSERT(m_renderer); // For maxTextureSize. | |
| 354 | |
| 355 { | |
| 356 updateRootScrollLayerImplTransform(); | |
| 357 | |
| 358 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::calcDrawEtc"); | |
| 359 CCLayerTreeHostCommon::calculateDrawTransforms(m_rootLayerImpl.get(), de
viceViewportSize(), m_deviceScaleFactor, &m_layerSorter, rendererCapabilities().
maxTextureSize, renderSurfaceLayerList); | |
| 360 | |
| 361 trackDamageForAllSurfaces(m_rootLayerImpl.get(), renderSurfaceLayerList)
; | |
| 362 } | |
| 363 } | |
| 364 | |
| 365 void CCLayerTreeHostImpl::FrameData::appendRenderPass(scoped_ptr<CCRenderPass> r
enderPass) | |
| 366 { | |
| 367 CCRenderPass* pass = renderPass.get(); | |
| 368 renderPasses.push_back(pass); | |
| 369 renderPassesById.set(pass->id(), renderPass.Pass()); | |
| 370 } | |
| 371 | |
| 372 bool CCLayerTreeHostImpl::calculateRenderPasses(FrameData& frame) | |
| 373 { | |
| 374 ASSERT(frame.renderPasses.empty()); | |
| 375 | |
| 376 calculateRenderSurfaceLayerList(*frame.renderSurfaceLayerList); | |
| 377 | |
| 378 TRACE_EVENT1("cc", "CCLayerTreeHostImpl::calculateRenderPasses", "renderSurf
aceLayerList.size()", static_cast<long long unsigned>(frame.renderSurfaceLayerLi
st->size())); | |
| 379 | |
| 380 // Create the render passes in dependency order. | |
| 381 for (int surfaceIndex = frame.renderSurfaceLayerList->size() - 1; surfaceInd
ex >= 0 ; --surfaceIndex) { | |
| 382 CCLayerImpl* renderSurfaceLayer = (*frame.renderSurfaceLayerList)[surfac
eIndex]; | |
| 383 renderSurfaceLayer->renderSurface()->appendRenderPasses(frame); | |
| 384 } | |
| 385 | |
| 386 bool recordMetricsForFrame = true; // FIXME: In the future, disable this whe
n about:tracing is off. | |
| 387 CCOcclusionTrackerImpl occlusionTracker(m_rootLayerImpl->renderSurface()->co
ntentRect(), recordMetricsForFrame); | |
| 388 occlusionTracker.setMinimumTrackingSize(m_settings.minimumOcclusionTrackingS
ize); | |
| 389 | |
| 390 if (settings().showOccludingRects) | |
| 391 occlusionTracker.setOccludingScreenSpaceRectsContainer(&frame.occludingS
creenSpaceRects); | |
| 392 | |
| 393 // Add quads to the Render passes in FrontToBack order to allow for testing
occlusion and performing culling during the tree walk. | |
| 394 typedef CCLayerIterator<CCLayerImpl, std::vector<CCLayerImpl*>, CCRenderSurf
ace, CCLayerIteratorActions::FrontToBack> CCLayerIteratorType; | |
| 395 | |
| 396 // Typically when we are missing a texture and use a checkerboard quad, we s
till draw the frame. However when the layer being | |
| 397 // checkerboarded is moving due to an impl-animation, we drop the frame to a
void flashing due to the texture suddenly appearing | |
| 398 // in the future. | |
| 399 bool drawFrame = true; | |
| 400 | |
| 401 CCLayerIteratorType end = CCLayerIteratorType::end(frame.renderSurfaceLayerL
ist); | |
| 402 for (CCLayerIteratorType it = CCLayerIteratorType::begin(frame.renderSurface
LayerList); it != end; ++it) { | |
| 403 CCRenderPass::Id targetRenderPassId = it.targetRenderSurfaceLayer()->ren
derSurface()->renderPassId(); | |
| 404 CCRenderPass* targetRenderPass = frame.renderPassesById.get(targetRender
PassId); | |
| 405 | |
| 406 occlusionTracker.enterLayer(it); | |
| 407 | |
| 408 CCAppendQuadsData appendQuadsData(targetRenderPass->id()); | |
| 409 | |
| 410 if (it.representsContributingRenderSurface()) { | |
| 411 CCRenderPass::Id contributingRenderPassId = it->renderSurface()->ren
derPassId(); | |
| 412 CCRenderPass* contributingRenderPass = frame.renderPassesById.get(co
ntributingRenderPassId); | |
| 413 targetRenderPass->appendQuadsForRenderSurfaceLayer(*it, contributing
RenderPass, &occlusionTracker, appendQuadsData); | |
| 414 } else if (it.representsItself() && !it->visibleContentRect().isEmpty())
{ | |
| 415 bool hasOcclusionFromOutsideTargetSurface; | |
| 416 if (occlusionTracker.occluded(*it, it->visibleContentRect(), &hasOcc
lusionFromOutsideTargetSurface)) | |
| 417 appendQuadsData.hadOcclusionFromOutsideTargetSurface |= hasOcclu
sionFromOutsideTargetSurface; | |
| 418 else { | |
| 419 it->willDraw(m_resourceProvider.get()); | |
| 420 frame.willDrawLayers.push_back(*it); | |
| 421 | |
| 422 if (it->hasContributingDelegatedRenderPasses()) { | |
| 423 CCRenderPass::Id contributingRenderPassId = it->firstContrib
utingRenderPassId(); | |
| 424 while (frame.renderPassesById.contains(contributingRenderPas
sId)) { | |
| 425 CCRenderPass* renderPass = frame.renderPassesById.get(co
ntributingRenderPassId); | |
| 426 | |
| 427 CCAppendQuadsData appendQuadsData(renderPass->id()); | |
| 428 renderPass->appendQuadsForLayer(*it, &occlusionTracker,
appendQuadsData); | |
| 429 | |
| 430 contributingRenderPassId = it->nextContributingRenderPas
sId(contributingRenderPassId); | |
| 431 } | |
| 432 } | |
| 433 | |
| 434 targetRenderPass->appendQuadsForLayer(*it, &occlusionTracker, ap
pendQuadsData); | |
| 435 } | |
| 436 } | |
| 437 | |
| 438 if (appendQuadsData.hadOcclusionFromOutsideTargetSurface) | |
| 439 targetRenderPass->setHasOcclusionFromOutsideTargetSurface(true); | |
| 440 | |
| 441 if (appendQuadsData.hadMissingTiles) { | |
| 442 bool layerHasAnimatingTransform = it->screenSpaceTransformIsAnimatin
g() || it->drawTransformIsAnimating(); | |
| 443 if (layerHasAnimatingTransform || CCSettings::jankInsteadOfCheckerbo
ard()) | |
| 444 drawFrame = false; | |
| 445 } | |
| 446 | |
| 447 occlusionTracker.leaveLayer(it); | |
| 448 } | |
| 449 | |
| 450 #if !ASSERT_DISABLED | |
| 451 for (size_t i = 0; i < frame.renderPasses.size(); ++i) { | |
| 452 for (size_t j = 0; j < frame.renderPasses[i]->quadList().size(); ++j) | |
| 453 ASSERT(frame.renderPasses[i]->quadList()[j]->sharedQuadStateId() >=
0); | |
| 454 ASSERT(frame.renderPassesById.contains(frame.renderPasses[i]->id())); | |
| 455 } | |
| 456 #endif | |
| 457 | |
| 458 if (!m_hasTransparentBackground) { | |
| 459 frame.renderPasses.back()->setHasTransparentBackground(false); | |
| 460 frame.renderPasses.back()->appendQuadsToFillScreen(m_rootLayerImpl.get()
, m_backgroundColor, occlusionTracker); | |
| 461 } | |
| 462 | |
| 463 if (drawFrame) | |
| 464 occlusionTracker.overdrawMetrics().recordMetrics(this); | |
| 465 | |
| 466 removeRenderPasses(CullRenderPassesWithNoQuads(), frame); | |
| 467 m_renderer->decideRenderPassAllocationsForFrame(frame.renderPasses); | |
| 468 removeRenderPasses(CullRenderPassesWithCachedTextures(*m_renderer), frame); | |
| 469 | |
| 470 return drawFrame; | |
| 471 } | |
| 472 | |
| 473 void CCLayerTreeHostImpl::animateLayersRecursive(CCLayerImpl* current, double mo
notonicTime, double wallClockTime, CCAnimationEventsVector* events, bool& didAni
mate, bool& needsAnimateLayers) | |
| 474 { | |
| 475 bool subtreeNeedsAnimateLayers = false; | |
| 476 | |
| 477 CCLayerAnimationController* currentController = current->layerAnimationContr
oller(); | |
| 478 | |
| 479 bool hadActiveAnimation = currentController->hasActiveAnimation(); | |
| 480 currentController->animate(monotonicTime, events); | |
| 481 bool startedAnimation = events->size() > 0; | |
| 482 | |
| 483 // We animated if we either ticked a running animation, or started a new ani
mation. | |
| 484 if (hadActiveAnimation || startedAnimation) | |
| 485 didAnimate = true; | |
| 486 | |
| 487 // If the current controller still has an active animation, we must continue
animating layers. | |
| 488 if (currentController->hasActiveAnimation()) | |
| 489 subtreeNeedsAnimateLayers = true; | |
| 490 | |
| 491 for (size_t i = 0; i < current->children().size(); ++i) { | |
| 492 bool childNeedsAnimateLayers = false; | |
| 493 animateLayersRecursive(current->children()[i], monotonicTime, wallClockT
ime, events, didAnimate, childNeedsAnimateLayers); | |
| 494 if (childNeedsAnimateLayers) | |
| 495 subtreeNeedsAnimateLayers = true; | |
| 496 } | |
| 497 | |
| 498 needsAnimateLayers = subtreeNeedsAnimateLayers; | |
| 499 } | |
| 500 | |
| 501 void CCLayerTreeHostImpl::setBackgroundTickingEnabled(bool enabled) | |
| 502 { | |
| 503 // Lazily create the timeSource adapter so that we can vary the interval for
testing. | |
| 504 if (!m_timeSourceClientAdapter) | |
| 505 m_timeSourceClientAdapter = CCLayerTreeHostImplTimeSourceAdapter::create
(this, CCDelayBasedTimeSource::create(lowFrequencyAnimationInterval(), CCProxy::
currentThread())); | |
| 506 | |
| 507 m_timeSourceClientAdapter->setActive(enabled); | |
| 508 } | |
| 509 | |
| 510 IntSize CCLayerTreeHostImpl::contentSize() const | |
| 511 { | |
| 512 // TODO(aelias): Hardcoding the first child here is weird. Think of | |
| 513 // a cleaner way to get the contentBounds on the Impl side. | |
| 514 if (!m_rootScrollLayerImpl || m_rootScrollLayerImpl->children().isEmpty()) | |
| 515 return IntSize(); | |
| 516 return m_rootScrollLayerImpl->children()[0]->contentBounds(); | |
| 517 } | |
| 518 | |
| 519 static inline CCRenderPass* findRenderPassById(CCRenderPass::Id renderPassId, co
nst CCLayerTreeHostImpl::FrameData& frame) | |
| 520 { | |
| 521 CCRenderPassIdHashMap::const_iterator it = frame.renderPassesById.find(rende
rPassId); | |
| 522 ASSERT(it != frame.renderPassesById.end()); | |
| 523 return it->second; | |
| 524 } | |
| 525 | |
| 526 static void removeRenderPassesRecursive(CCRenderPass::Id removeRenderPassId, CCL
ayerTreeHostImpl::FrameData& frame) | |
| 527 { | |
| 528 CCRenderPass* removeRenderPass = findRenderPassById(removeRenderPassId, fram
e); | |
| 529 CCRenderPassList& renderPasses = frame.renderPasses; | |
| 530 CCRenderPassList::iterator toRemove = std::find(renderPasses.begin(), render
Passes.end(), removeRenderPass); | |
| 531 | |
| 532 // The pass was already removed by another quad - probably the original, and
we are the replica. | |
| 533 if (toRemove == renderPasses.end()) | |
| 534 return; | |
| 535 | |
| 536 const CCRenderPass* removedPass = *toRemove; | |
| 537 frame.renderPasses.erase(toRemove); | |
| 538 | |
| 539 // Now follow up for all RenderPass quads and remove their RenderPasses recu
rsively. | |
| 540 const CCQuadList& quadList = removedPass->quadList(); | |
| 541 CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToFront
Begin(); | |
| 542 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) { | |
| 543 CCDrawQuad* currentQuad = (*quadListIterator); | |
| 544 if (currentQuad->material() != CCDrawQuad::RenderPass) | |
| 545 continue; | |
| 546 | |
| 547 CCRenderPass::Id nextRemoveRenderPassId = CCRenderPassDrawQuad::material
Cast(currentQuad)->renderPassId(); | |
| 548 removeRenderPassesRecursive(nextRemoveRenderPassId, frame); | |
| 549 } | |
| 550 } | |
| 551 | |
| 552 bool CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures::shouldRemoveRender
Pass(const CCRenderPassDrawQuad& quad, const FrameData&) const | |
| 553 { | |
| 554 return quad.contentsChangedSinceLastFrame().isEmpty() && m_renderer.haveCach
edResourcesForRenderPassId(quad.renderPassId()); | |
| 555 } | |
| 556 | |
| 557 bool CCLayerTreeHostImpl::CullRenderPassesWithNoQuads::shouldRemoveRenderPass(co
nst CCRenderPassDrawQuad& quad, const FrameData& frame) const | |
| 558 { | |
| 559 const CCRenderPass* renderPass = findRenderPassById(quad.renderPassId(), fra
me); | |
| 560 const CCRenderPassList& renderPasses = frame.renderPasses; | |
| 561 CCRenderPassList::const_iterator foundPass = std::find(renderPasses.begin(),
renderPasses.end(), renderPass); | |
| 562 | |
| 563 bool renderPassAlreadyRemoved = foundPass == renderPasses.end(); | |
| 564 if (renderPassAlreadyRemoved) | |
| 565 return false; | |
| 566 | |
| 567 // If any quad or RenderPass draws into this RenderPass, then keep it. | |
| 568 const CCQuadList& quadList = (*foundPass)->quadList(); | |
| 569 for (CCQuadList::constBackToFrontIterator quadListIterator = quadList.backTo
FrontBegin(); quadListIterator != quadList.backToFrontEnd(); ++quadListIterator)
{ | |
| 570 CCDrawQuad* currentQuad = *quadListIterator; | |
| 571 | |
| 572 if (currentQuad->material() != CCDrawQuad::RenderPass) | |
| 573 return false; | |
| 574 | |
| 575 const CCRenderPass* contributingPass = findRenderPassById(CCRenderPassDr
awQuad::materialCast(currentQuad)->renderPassId(), frame); | |
| 576 CCRenderPassList::const_iterator foundContributingPass = std::find(rende
rPasses.begin(), renderPasses.end(), contributingPass); | |
| 577 if (foundContributingPass != renderPasses.end()) | |
| 578 return false; | |
| 579 } | |
| 580 return true; | |
| 581 } | |
| 582 | |
| 583 // Defined for linking tests. | |
| 584 template void CCLayerTreeHostImpl::removeRenderPasses<CCLayerTreeHostImpl::CullR
enderPassesWithCachedTextures>(CullRenderPassesWithCachedTextures, FrameData&); | |
| 585 template void CCLayerTreeHostImpl::removeRenderPasses<CCLayerTreeHostImpl::CullR
enderPassesWithNoQuads>(CullRenderPassesWithNoQuads, FrameData&); | |
| 586 | |
| 587 // static | |
| 588 template<typename RenderPassCuller> | |
| 589 void CCLayerTreeHostImpl::removeRenderPasses(RenderPassCuller culler, FrameData&
frame) | |
| 590 { | |
| 591 for (size_t it = culler.renderPassListBegin(frame.renderPasses); it != culle
r.renderPassListEnd(frame.renderPasses); it = culler.renderPassListNext(it)) { | |
| 592 const CCRenderPass* currentPass = frame.renderPasses[it]; | |
| 593 const CCQuadList& quadList = currentPass->quadList(); | |
| 594 CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToF
rontBegin(); | |
| 595 | |
| 596 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator
) { | |
| 597 CCDrawQuad* currentQuad = *quadListIterator; | |
| 598 | |
| 599 if (currentQuad->material() != CCDrawQuad::RenderPass) | |
| 600 continue; | |
| 601 | |
| 602 CCRenderPassDrawQuad* renderPassQuad = static_cast<CCRenderPassDrawQ
uad*>(currentQuad); | |
| 603 if (!culler.shouldRemoveRenderPass(*renderPassQuad, frame)) | |
| 604 continue; | |
| 605 | |
| 606 // We are changing the vector in the middle of iteration. Because we | |
| 607 // delete render passes that draw into the current pass, we are | |
| 608 // guaranteed that any data from the iterator to the end will not | |
| 609 // change. So, capture the iterator position from the end of the | |
| 610 // list, and restore it after the change. | |
| 611 int positionFromEnd = frame.renderPasses.size() - it; | |
| 612 removeRenderPassesRecursive(renderPassQuad->renderPassId(), frame); | |
| 613 it = frame.renderPasses.size() - positionFromEnd; | |
| 614 ASSERT(it >= 0); | |
| 615 } | |
| 616 } | |
| 617 } | |
| 618 | |
| 619 bool CCLayerTreeHostImpl::prepareToDraw(FrameData& frame) | |
| 620 { | |
| 621 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::prepareToDraw"); | |
| 622 ASSERT(canDraw()); | |
| 623 | |
| 624 frame.renderSurfaceLayerList = &m_renderSurfaceLayerList; | |
| 625 frame.renderPasses.clear(); | |
| 626 frame.renderPassesById.clear(); | |
| 627 frame.renderSurfaceLayerList->clear(); | |
| 628 frame.willDrawLayers.clear(); | |
| 629 | |
| 630 if (!calculateRenderPasses(frame)) | |
| 631 return false; | |
| 632 | |
| 633 // If we return true, then we expect drawLayers() to be called before this f
unction is called again. | |
| 634 return true; | |
| 635 } | |
| 636 | |
| 637 void CCLayerTreeHostImpl::releaseContentsTextures() | |
| 638 { | |
| 639 if (m_contentsTexturesPurged) | |
| 640 return; | |
| 641 m_client->releaseContentsTexturesOnImplThread(); | |
| 642 setContentsTexturesPurged(); | |
| 643 m_client->setNeedsCommitOnImplThread(); | |
| 644 m_client->onCanDrawStateChanged(canDraw()); | |
| 645 } | |
| 646 | |
| 647 void CCLayerTreeHostImpl::setMemoryAllocationLimitBytes(size_t bytes) | |
| 648 { | |
| 649 if (m_memoryAllocationLimitBytes == bytes) | |
| 650 return; | |
| 651 m_memoryAllocationLimitBytes = bytes; | |
| 652 | |
| 653 ASSERT(bytes); | |
| 654 m_client->setNeedsCommitOnImplThread(); | |
| 655 } | |
| 656 | |
| 657 void CCLayerTreeHostImpl::onVSyncParametersChanged(double monotonicTimebase, dou
ble intervalInSeconds) | |
| 658 { | |
| 659 m_client->onVSyncParametersChanged(monotonicTimebase, intervalInSeconds); | |
| 660 } | |
| 661 | |
| 662 void CCLayerTreeHostImpl::drawLayers(const FrameData& frame) | |
| 663 { | |
| 664 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::drawLayers"); | |
| 665 ASSERT(canDraw()); | |
| 666 ASSERT(!frame.renderPasses.empty()); | |
| 667 | |
| 668 // FIXME: use the frame begin time from the overall compositor scheduler. | |
| 669 // This value is currently inaccessible because it is up in Chromium's | |
| 670 // RenderWidget. | |
| 671 m_fpsCounter->markBeginningOfFrame(currentTime()); | |
| 672 | |
| 673 if (m_settings.showDebugRects()) | |
| 674 m_debugRectHistory->saveDebugRectsForCurrentFrame(m_rootLayerImpl.get(),
*frame.renderSurfaceLayerList, frame.occludingScreenSpaceRects, settings()); | |
| 675 | |
| 676 // Because the contents of the HUD depend on everything else in the frame, t
he contents | |
| 677 // of its texture are updated as the last thing before the frame is drawn. | |
| 678 if (m_hudLayerImpl) | |
| 679 m_hudLayerImpl->updateHudTexture(m_resourceProvider.get()); | |
| 680 | |
| 681 m_renderer->drawFrame(frame.renderPasses, frame.renderPassesById); | |
| 682 | |
| 683 // Once a RenderPass has been drawn, its damage should be cleared in | |
| 684 // case the RenderPass will be reused next frame. | |
| 685 for (unsigned int i = 0; i < frame.renderPasses.size(); i++) | |
| 686 frame.renderPasses[i]->setDamageRect(FloatRect()); | |
| 687 | |
| 688 // The next frame should start by assuming nothing has changed, and changes
are noted as they occur. | |
| 689 for (unsigned int i = 0; i < frame.renderSurfaceLayerList->size(); i++) | |
| 690 (*frame.renderSurfaceLayerList)[i]->renderSurface()->damageTracker()->di
dDrawDamagedArea(); | |
| 691 m_rootLayerImpl->resetAllChangeTrackingForSubtree(); | |
| 692 } | |
| 693 | |
| 694 void CCLayerTreeHostImpl::didDrawAllLayers(const FrameData& frame) | |
| 695 { | |
| 696 for (size_t i = 0; i < frame.willDrawLayers.size(); ++i) | |
| 697 frame.willDrawLayers[i]->didDraw(m_resourceProvider.get()); | |
| 698 | |
| 699 // Once all layers have been drawn, pending texture uploads should no | |
| 700 // longer block future uploads. | |
| 701 m_resourceProvider->textureUploader()->markPendingUploadsAsNonBlocking(); | |
| 702 } | |
| 703 | |
| 704 void CCLayerTreeHostImpl::finishAllRendering() | |
| 705 { | |
| 706 if (m_renderer) | |
| 707 m_renderer->finish(); | |
| 708 } | |
| 709 | |
| 710 bool CCLayerTreeHostImpl::isContextLost() | |
| 711 { | |
| 712 return m_renderer && m_renderer->isContextLost(); | |
| 713 } | |
| 714 | |
| 715 const RendererCapabilities& CCLayerTreeHostImpl::rendererCapabilities() const | |
| 716 { | |
| 717 return m_renderer->capabilities(); | |
| 718 } | |
| 719 | |
| 720 bool CCLayerTreeHostImpl::swapBuffers() | |
| 721 { | |
| 722 ASSERT(m_renderer); | |
| 723 | |
| 724 m_fpsCounter->markEndOfFrame(); | |
| 725 return m_renderer->swapBuffers(); | |
| 726 } | |
| 727 | |
| 728 const IntSize& CCLayerTreeHostImpl::deviceViewportSize() const | |
| 729 { | |
| 730 return m_deviceViewportSize; | |
| 731 } | |
| 732 | |
| 733 const CCLayerTreeSettings& CCLayerTreeHostImpl::settings() const | |
| 734 { | |
| 735 return m_settings; | |
| 736 } | |
| 737 | |
| 738 void CCLayerTreeHostImpl::didLoseContext() | |
| 739 { | |
| 740 m_client->didLoseContextOnImplThread(); | |
| 741 } | |
| 742 | |
| 743 void CCLayerTreeHostImpl::onSwapBuffersComplete() | |
| 744 { | |
| 745 m_client->onSwapBuffersCompleteOnImplThread(); | |
| 746 } | |
| 747 | |
| 748 void CCLayerTreeHostImpl::readback(void* pixels, const IntRect& rect) | |
| 749 { | |
| 750 ASSERT(m_renderer); | |
| 751 m_renderer->getFramebufferPixels(pixels, rect); | |
| 752 } | |
| 753 | |
| 754 static CCLayerImpl* findRootScrollLayer(CCLayerImpl* layer) | |
| 755 { | |
| 756 if (!layer) | |
| 757 return 0; | |
| 758 | |
| 759 if (layer->scrollable()) | |
| 760 return layer; | |
| 761 | |
| 762 for (size_t i = 0; i < layer->children().size(); ++i) { | |
| 763 CCLayerImpl* found = findRootScrollLayer(layer->children()[i]); | |
| 764 if (found) | |
| 765 return found; | |
| 766 } | |
| 767 | |
| 768 return 0; | |
| 769 } | |
| 770 | |
| 771 // Content layers can be either directly scrollable or contained in an outer | |
| 772 // scrolling layer which applies the scroll transform. Given a content layer, | |
| 773 // this function returns the associated scroll layer if any. | |
| 774 static CCLayerImpl* findScrollLayerForContentLayer(CCLayerImpl* layerImpl) | |
| 775 { | |
| 776 if (!layerImpl) | |
| 777 return 0; | |
| 778 | |
| 779 if (layerImpl->scrollable()) | |
| 780 return layerImpl; | |
| 781 | |
| 782 if (layerImpl->drawsContent() && layerImpl->parent() && layerImpl->parent()-
>scrollable()) | |
| 783 return layerImpl->parent(); | |
| 784 | |
| 785 return 0; | |
| 786 } | |
| 787 | |
| 788 void CCLayerTreeHostImpl::setRootLayer(scoped_ptr<CCLayerImpl> layer) | |
| 789 { | |
| 790 m_rootLayerImpl = layer.Pass(); | |
| 791 m_rootScrollLayerImpl = findRootScrollLayer(m_rootLayerImpl.get()); | |
| 792 m_currentlyScrollingLayerImpl = 0; | |
| 793 | |
| 794 if (m_rootLayerImpl && m_scrollingLayerIdFromPreviousTree != -1) | |
| 795 m_currentlyScrollingLayerImpl = CCLayerTreeHostCommon::findLayerInSubtre
e(m_rootLayerImpl.get(), m_scrollingLayerIdFromPreviousTree); | |
| 796 | |
| 797 m_scrollingLayerIdFromPreviousTree = -1; | |
| 798 | |
| 799 m_client->onCanDrawStateChanged(canDraw()); | |
| 800 } | |
| 801 | |
| 802 scoped_ptr<CCLayerImpl> CCLayerTreeHostImpl::detachLayerTree() | |
| 803 { | |
| 804 // Clear all data structures that have direct references to the layer tree. | |
| 805 m_scrollingLayerIdFromPreviousTree = m_currentlyScrollingLayerImpl ? m_curre
ntlyScrollingLayerImpl->id() : -1; | |
| 806 m_currentlyScrollingLayerImpl = 0; | |
| 807 m_renderSurfaceLayerList.clear(); | |
| 808 | |
| 809 return m_rootLayerImpl.Pass(); | |
| 810 } | |
| 811 | |
| 812 void CCLayerTreeHostImpl::setVisible(bool visible) | |
| 813 { | |
| 814 ASSERT(CCProxy::isImplThread()); | |
| 815 | |
| 816 if (m_visible == visible) | |
| 817 return; | |
| 818 m_visible = visible; | |
| 819 didVisibilityChange(this, m_visible); | |
| 820 | |
| 821 if (!m_renderer) | |
| 822 return; | |
| 823 | |
| 824 m_renderer->setVisible(visible); | |
| 825 | |
| 826 setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers); | |
| 827 } | |
| 828 | |
| 829 bool CCLayerTreeHostImpl::initializeRenderer(scoped_ptr<CCGraphicsContext> conte
xt) | |
| 830 { | |
| 831 // Since we will create a new resource provider, we cannot continue to use | |
| 832 // the old resources (i.e. renderSurfaces and texture IDs). Clear them | |
| 833 // before we destroy the old resource provider. | |
| 834 if (m_rootLayerImpl) { | |
| 835 clearRenderSurfaces(); | |
| 836 sendDidLoseContextRecursive(m_rootLayerImpl.get()); | |
| 837 } | |
| 838 // Note: order is important here. | |
| 839 m_renderer.clear(); | |
| 840 m_resourceProvider.clear(); | |
| 841 m_context.reset(); | |
| 842 | |
| 843 if (!context->bindToClient(this)) | |
| 844 return false; | |
| 845 | |
| 846 OwnPtr<CCResourceProvider> resourceProvider = CCResourceProvider::create(con
text.get()); | |
| 847 if (!resourceProvider) | |
| 848 return false; | |
| 849 | |
| 850 if (context->context3D()) | |
| 851 m_renderer = CCRendererGL::create(this, resourceProvider.get()); | |
| 852 else if (context->softwareDevice()) | |
| 853 m_renderer = CCRendererSoftware::create(this, resourceProvider.get(), co
ntext->softwareDevice()); | |
| 854 if (!m_renderer) | |
| 855 return false; | |
| 856 | |
| 857 m_resourceProvider = resourceProvider.release(); | |
| 858 m_context = context.Pass(); | |
| 859 | |
| 860 if (!m_visible) | |
| 861 m_renderer->setVisible(m_visible); | |
| 862 | |
| 863 m_client->onCanDrawStateChanged(canDraw()); | |
| 864 | |
| 865 return true; | |
| 866 } | |
| 867 | |
| 868 void CCLayerTreeHostImpl::setContentsTexturesPurged() | |
| 869 { | |
| 870 m_contentsTexturesPurged = true; | |
| 871 m_client->onCanDrawStateChanged(canDraw()); | |
| 872 } | |
| 873 | |
| 874 void CCLayerTreeHostImpl::resetContentsTexturesPurged() | |
| 875 { | |
| 876 m_contentsTexturesPurged = false; | |
| 877 m_client->onCanDrawStateChanged(canDraw()); | |
| 878 } | |
| 879 | |
| 880 void CCLayerTreeHostImpl::setViewportSize(const IntSize& layoutViewportSize, con
st IntSize& deviceViewportSize) | |
| 881 { | |
| 882 if (layoutViewportSize == m_layoutViewportSize && deviceViewportSize == m_de
viceViewportSize) | |
| 883 return; | |
| 884 | |
| 885 m_layoutViewportSize = layoutViewportSize; | |
| 886 m_deviceViewportSize = deviceViewportSize; | |
| 887 | |
| 888 m_pinchZoomViewport.setLayoutViewportSize(FloatSize(layoutViewportSize)); | |
| 889 | |
| 890 updateMaxScrollPosition(); | |
| 891 | |
| 892 if (m_renderer) | |
| 893 m_renderer->viewportChanged(); | |
| 894 | |
| 895 m_client->onCanDrawStateChanged(canDraw()); | |
| 896 } | |
| 897 | |
| 898 static void adjustScrollsForPageScaleChange(CCLayerImpl* layerImpl, float pageSc
aleChange) | |
| 899 { | |
| 900 if (!layerImpl) | |
| 901 return; | |
| 902 | |
| 903 if (layerImpl->scrollable()) { | |
| 904 // We need to convert impl-side scroll deltas to pageScale space. | |
| 905 FloatSize scrollDelta = layerImpl->scrollDelta(); | |
| 906 scrollDelta.scale(pageScaleChange); | |
| 907 layerImpl->setScrollDelta(scrollDelta); | |
| 908 } | |
| 909 | |
| 910 for (size_t i = 0; i < layerImpl->children().size(); ++i) | |
| 911 adjustScrollsForPageScaleChange(layerImpl->children()[i], pageScaleChang
e); | |
| 912 } | |
| 913 | |
| 914 void CCLayerTreeHostImpl::setDeviceScaleFactor(float deviceScaleFactor) | |
| 915 { | |
| 916 if (deviceScaleFactor == m_deviceScaleFactor) | |
| 917 return; | |
| 918 m_deviceScaleFactor = deviceScaleFactor; | |
| 919 | |
| 920 updateMaxScrollPosition(); | |
| 921 } | |
| 922 | |
| 923 float CCLayerTreeHostImpl::pageScaleFactor() const | |
| 924 { | |
| 925 return m_pinchZoomViewport.pageScaleFactor(); | |
| 926 } | |
| 927 | |
| 928 void CCLayerTreeHostImpl::setPageScaleFactorAndLimits(float pageScaleFactor, flo
at minPageScaleFactor, float maxPageScaleFactor) | |
| 929 { | |
| 930 if (!pageScaleFactor) | |
| 931 return; | |
| 932 | |
| 933 float pageScaleChange = pageScaleFactor / m_pinchZoomViewport.pageScaleFacto
r(); | |
| 934 m_pinchZoomViewport.setPageScaleFactorAndLimits(pageScaleFactor, minPageScal
eFactor, maxPageScaleFactor); | |
| 935 | |
| 936 if (!CCSettings::pageScalePinchZoomEnabled()) { | |
| 937 if (pageScaleChange != 1) | |
| 938 adjustScrollsForPageScaleChange(m_rootScrollLayerImpl, pageScaleChan
ge); | |
| 939 } | |
| 940 | |
| 941 // Clamp delta to limits and refresh display matrix. | |
| 942 setPageScaleDelta(m_pinchZoomViewport.pageScaleDelta() / m_pinchZoomViewport
.sentPageScaleDelta()); | |
| 943 m_pinchZoomViewport.setSentPageScaleDelta(1); | |
| 944 } | |
| 945 | |
| 946 void CCLayerTreeHostImpl::setPageScaleDelta(float delta) | |
| 947 { | |
| 948 m_pinchZoomViewport.setPageScaleDelta(delta); | |
| 949 | |
| 950 updateMaxScrollPosition(); | |
| 951 } | |
| 952 | |
| 953 void CCLayerTreeHostImpl::updateMaxScrollPosition() | |
| 954 { | |
| 955 if (!m_rootScrollLayerImpl || !m_rootScrollLayerImpl->children().size()) | |
| 956 return; | |
| 957 | |
| 958 FloatSize viewBounds = m_deviceViewportSize; | |
| 959 if (CCLayerImpl* clipLayer = m_rootScrollLayerImpl->parent()) { | |
| 960 // Compensate for non-overlay scrollbars. | |
| 961 if (clipLayer->masksToBounds()) { | |
| 962 viewBounds = clipLayer->bounds(); | |
| 963 viewBounds.scale(m_deviceScaleFactor); | |
| 964 } | |
| 965 } | |
| 966 | |
| 967 IntSize contentBounds = contentSize(); | |
| 968 if (CCSettings::pageScalePinchZoomEnabled()) { | |
| 969 // Pinch with pageScale scrolls entirely in layout space. contentSize | |
| 970 // returns the bounds including the page scale factor, so calculate the | |
| 971 // pre page-scale layout size here. | |
| 972 float pageScaleFactor = m_pinchZoomViewport.pageScaleFactor(); | |
| 973 contentBounds.setWidth(contentBounds.width() / pageScaleFactor); | |
| 974 contentBounds.setHeight(contentBounds.height() / pageScaleFactor); | |
| 975 } else { | |
| 976 viewBounds.scale(1 / m_pinchZoomViewport.pageScaleDelta()); | |
| 977 } | |
| 978 | |
| 979 IntSize maxScroll = contentBounds - expandedIntSize(viewBounds); | |
| 980 maxScroll.scale(1 / m_deviceScaleFactor); | |
| 981 | |
| 982 // The viewport may be larger than the contents in some cases, such as | |
| 983 // having a vertical scrollbar but no horizontal overflow. | |
| 984 maxScroll.clampNegativeToZero(); | |
| 985 | |
| 986 m_rootScrollLayerImpl->setMaxScrollPosition(maxScroll); | |
| 987 } | |
| 988 | |
| 989 void CCLayerTreeHostImpl::setNeedsRedraw() | |
| 990 { | |
| 991 m_client->setNeedsRedrawOnImplThread(); | |
| 992 } | |
| 993 | |
| 994 bool CCLayerTreeHostImpl::ensureRenderSurfaceLayerList() | |
| 995 { | |
| 996 if (!m_rootLayerImpl) | |
| 997 return false; | |
| 998 if (!m_renderer) | |
| 999 return false; | |
| 1000 | |
| 1001 // We need both a non-empty render surface layer list and a root render | |
| 1002 // surface to be able to iterate over the visible layers. | |
| 1003 if (m_renderSurfaceLayerList.size() && m_rootLayerImpl->renderSurface()) | |
| 1004 return true; | |
| 1005 | |
| 1006 // If we are called after setRootLayer() but before prepareToDraw(), we need | |
| 1007 // to recalculate the visible layers. This prevents being unable to scroll | |
| 1008 // during part of a commit. | |
| 1009 m_renderSurfaceLayerList.clear(); | |
| 1010 calculateRenderSurfaceLayerList(m_renderSurfaceLayerList); | |
| 1011 | |
| 1012 return m_renderSurfaceLayerList.size(); | |
| 1013 } | |
| 1014 | |
| 1015 CCInputHandlerClient::ScrollStatus CCLayerTreeHostImpl::scrollBegin(const IntPoi
nt& viewportPoint, CCInputHandlerClient::ScrollInputType type) | |
| 1016 { | |
| 1017 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::scrollBegin"); | |
| 1018 | |
| 1019 ASSERT(!m_currentlyScrollingLayerImpl); | |
| 1020 clearCurrentlyScrollingLayer(); | |
| 1021 | |
| 1022 if (!ensureRenderSurfaceLayerList()) | |
| 1023 return ScrollIgnored; | |
| 1024 | |
| 1025 IntPoint deviceViewportPoint = viewportPoint; | |
| 1026 deviceViewportPoint.scale(m_deviceScaleFactor, m_deviceScaleFactor); | |
| 1027 | |
| 1028 // First find out which layer was hit from the saved list of visible layers | |
| 1029 // in the most recent frame. | |
| 1030 CCLayerImpl* layerImpl = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(vi
ewportPoint, m_renderSurfaceLayerList); | |
| 1031 | |
| 1032 // Walk up the hierarchy and look for a scrollable layer. | |
| 1033 CCLayerImpl* potentiallyScrollingLayerImpl = 0; | |
| 1034 for (; layerImpl; layerImpl = layerImpl->parent()) { | |
| 1035 // The content layer can also block attempts to scroll outside the main
thread. | |
| 1036 if (layerImpl->tryScroll(deviceViewportPoint, type) == ScrollOnMainThrea
d) { | |
| 1037 m_numMainThreadScrolls++; | |
| 1038 return ScrollOnMainThread; | |
| 1039 } | |
| 1040 | |
| 1041 CCLayerImpl* scrollLayerImpl = findScrollLayerForContentLayer(layerImpl)
; | |
| 1042 if (!scrollLayerImpl) | |
| 1043 continue; | |
| 1044 | |
| 1045 ScrollStatus status = scrollLayerImpl->tryScroll(viewportPoint, type); | |
| 1046 | |
| 1047 // If any layer wants to divert the scroll event to the main thread, abo
rt. | |
| 1048 if (status == ScrollOnMainThread) { | |
| 1049 m_numMainThreadScrolls++; | |
| 1050 return ScrollOnMainThread; | |
| 1051 } | |
| 1052 | |
| 1053 if (status == ScrollStarted && !potentiallyScrollingLayerImpl) | |
| 1054 potentiallyScrollingLayerImpl = scrollLayerImpl; | |
| 1055 } | |
| 1056 | |
| 1057 if (potentiallyScrollingLayerImpl) { | |
| 1058 m_currentlyScrollingLayerImpl = potentiallyScrollingLayerImpl; | |
| 1059 // Gesture events need to be transformed from screen coordinates to loca
l layer coordinates | |
| 1060 // so that the scrolling contents exactly follow the user's finger. In c
ontrast, wheel | |
| 1061 // events are already in local layer coordinates so we can just apply th
em directly. | |
| 1062 m_scrollDeltaIsInScreenSpace = (type == Gesture); | |
| 1063 m_numImplThreadScrolls++; | |
| 1064 return ScrollStarted; | |
| 1065 } | |
| 1066 return ScrollIgnored; | |
| 1067 } | |
| 1068 | |
| 1069 static FloatSize scrollLayerWithScreenSpaceDelta(CCPinchZoomViewport* viewport,
CCLayerImpl& layerImpl, const FloatPoint& screenSpacePoint, const FloatSize& scr
eenSpaceDelta) | |
| 1070 { | |
| 1071 // Layers with non-invertible screen space transforms should not have passed
the scroll hit | |
| 1072 // test in the first place. | |
| 1073 ASSERT(layerImpl.screenSpaceTransform().isInvertible()); | |
| 1074 WebTransformationMatrix inverseScreenSpaceTransform = layerImpl.screenSpaceT
ransform().inverse(); | |
| 1075 | |
| 1076 // First project the scroll start and end points to local layer space to fin
d the scroll delta | |
| 1077 // in layer coordinates. | |
| 1078 bool startClipped, endClipped; | |
| 1079 FloatPoint screenSpaceEndPoint = screenSpacePoint + screenSpaceDelta; | |
| 1080 FloatPoint localStartPoint = CCMathUtil::projectPoint(inverseScreenSpaceTran
sform, screenSpacePoint, startClipped); | |
| 1081 FloatPoint localEndPoint = CCMathUtil::projectPoint(inverseScreenSpaceTransf
orm, screenSpaceEndPoint, endClipped); | |
| 1082 | |
| 1083 // In general scroll point coordinates should not get clipped. | |
| 1084 ASSERT(!startClipped); | |
| 1085 ASSERT(!endClipped); | |
| 1086 if (startClipped || endClipped) | |
| 1087 return FloatSize(); | |
| 1088 | |
| 1089 // Apply the scroll delta. | |
| 1090 FloatSize previousDelta(layerImpl.scrollDelta()); | |
| 1091 FloatSize unscrolled = layerImpl.scrollBy(localEndPoint - localStartPoint); | |
| 1092 | |
| 1093 if (viewport) | |
| 1094 viewport->applyScroll(unscrolled); | |
| 1095 | |
| 1096 // Calculate the applied scroll delta in screen space coordinates. | |
| 1097 FloatPoint actualLocalEndPoint = localStartPoint + layerImpl.scrollDelta() -
previousDelta; | |
| 1098 FloatPoint actualScreenSpaceEndPoint = CCMathUtil::mapPoint(layerImpl.screen
SpaceTransform(), actualLocalEndPoint, endClipped); | |
| 1099 ASSERT(!endClipped); | |
| 1100 if (endClipped) | |
| 1101 return FloatSize(); | |
| 1102 return actualScreenSpaceEndPoint - screenSpacePoint; | |
| 1103 } | |
| 1104 | |
| 1105 static FloatSize scrollLayerWithLocalDelta(CCLayerImpl& layerImpl, const FloatSi
ze& localDelta) | |
| 1106 { | |
| 1107 FloatSize previousDelta(layerImpl.scrollDelta()); | |
| 1108 layerImpl.scrollBy(localDelta); | |
| 1109 return layerImpl.scrollDelta() - previousDelta; | |
| 1110 } | |
| 1111 | |
| 1112 void CCLayerTreeHostImpl::scrollBy(const IntPoint& viewportPoint, const IntSize&
scrollDelta) | |
| 1113 { | |
| 1114 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::scrollBy"); | |
| 1115 if (!m_currentlyScrollingLayerImpl) | |
| 1116 return; | |
| 1117 | |
| 1118 FloatSize pendingDelta(scrollDelta); | |
| 1119 | |
| 1120 pendingDelta.scale(m_deviceScaleFactor); | |
| 1121 | |
| 1122 for (CCLayerImpl* layerImpl = m_currentlyScrollingLayerImpl; layerImpl; laye
rImpl = layerImpl->parent()) { | |
| 1123 if (!layerImpl->scrollable()) | |
| 1124 continue; | |
| 1125 | |
| 1126 CCPinchZoomViewport* viewport = layerImpl == m_rootScrollLayerImpl ? &m_
pinchZoomViewport : 0; | |
| 1127 FloatSize appliedDelta; | |
| 1128 if (m_scrollDeltaIsInScreenSpace) | |
| 1129 appliedDelta = scrollLayerWithScreenSpaceDelta(viewport, *layerImpl,
viewportPoint, pendingDelta); | |
| 1130 else | |
| 1131 appliedDelta = scrollLayerWithLocalDelta(*layerImpl, pendingDelta); | |
| 1132 | |
| 1133 // If the layer wasn't able to move, try the next one in the hierarchy. | |
| 1134 float moveThresholdSquared = 0.1f * 0.1f; | |
| 1135 if (appliedDelta.diagonalLengthSquared() < moveThresholdSquared) | |
| 1136 continue; | |
| 1137 | |
| 1138 // If the applied delta is within 45 degrees of the input delta, bail ou
t to make it easier | |
| 1139 // to scroll just one layer in one direction without affecting any of it
s parents. | |
| 1140 float angleThreshold = 45; | |
| 1141 if (CCMathUtil::smallestAngleBetweenVectors(appliedDelta, pendingDelta)
< angleThreshold) { | |
| 1142 pendingDelta = FloatSize(); | |
| 1143 break; | |
| 1144 } | |
| 1145 | |
| 1146 // Allow further movement only on an axis perpendicular to the direction
in which the layer | |
| 1147 // moved. | |
| 1148 FloatSize perpendicularAxis(-appliedDelta.height(), appliedDelta.width()
); | |
| 1149 pendingDelta = CCMathUtil::projectVector(pendingDelta, perpendicularAxis
); | |
| 1150 | |
| 1151 if (flooredIntSize(pendingDelta).isZero()) | |
| 1152 break; | |
| 1153 } | |
| 1154 | |
| 1155 if (!scrollDelta.isZero() && flooredIntSize(pendingDelta).isEmpty()) { | |
| 1156 m_client->setNeedsCommitOnImplThread(); | |
| 1157 m_client->setNeedsRedrawOnImplThread(); | |
| 1158 } | |
| 1159 } | |
| 1160 | |
| 1161 void CCLayerTreeHostImpl::clearCurrentlyScrollingLayer() | |
| 1162 { | |
| 1163 m_currentlyScrollingLayerImpl = 0; | |
| 1164 m_scrollingLayerIdFromPreviousTree = -1; | |
| 1165 } | |
| 1166 | |
| 1167 void CCLayerTreeHostImpl::scrollEnd() | |
| 1168 { | |
| 1169 clearCurrentlyScrollingLayer(); | |
| 1170 } | |
| 1171 | |
| 1172 void CCLayerTreeHostImpl::pinchGestureBegin() | |
| 1173 { | |
| 1174 m_pinchGestureActive = true; | |
| 1175 m_previousPinchAnchor = IntPoint(); | |
| 1176 | |
| 1177 if (m_rootScrollLayerImpl && m_rootScrollLayerImpl->scrollbarAnimationContro
ller()) | |
| 1178 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureBe
gin(); | |
| 1179 } | |
| 1180 | |
| 1181 void CCLayerTreeHostImpl::pinchGestureUpdate(float magnifyDelta, | |
| 1182 const IntPoint& anchor) | |
| 1183 { | |
| 1184 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::pinchGestureUpdate"); | |
| 1185 | |
| 1186 if (!m_rootScrollLayerImpl) | |
| 1187 return; | |
| 1188 | |
| 1189 if (m_previousPinchAnchor == IntPoint::zero()) | |
| 1190 m_previousPinchAnchor = anchor; | |
| 1191 | |
| 1192 // Keep the center-of-pinch anchor specified by (x, y) in a stable | |
| 1193 // position over the course of the magnify. | |
| 1194 float pageScaleDelta = m_pinchZoomViewport.pageScaleDelta(); | |
| 1195 FloatPoint previousScaleAnchor(m_previousPinchAnchor.x() / pageScaleDelta, | |
| 1196 m_previousPinchAnchor.y() / pageScaleDelta); | |
| 1197 setPageScaleDelta(pageScaleDelta * magnifyDelta); | |
| 1198 pageScaleDelta = m_pinchZoomViewport.pageScaleDelta(); | |
| 1199 FloatPoint newScaleAnchor(anchor.x() / pageScaleDelta, anchor.y() / pageScal
eDelta); | |
| 1200 FloatSize move = previousScaleAnchor - newScaleAnchor; | |
| 1201 | |
| 1202 m_previousPinchAnchor = anchor; | |
| 1203 | |
| 1204 if (CCSettings::pageScalePinchZoomEnabled()) { | |
| 1205 // Compute the application of the delta with respect to the current page
zoom of the page. | |
| 1206 move.scale(1 / (m_pinchZoomViewport.pageScaleFactor() * m_deviceScaleFac
tor)); | |
| 1207 } | |
| 1208 | |
| 1209 FloatSize scrollOverflow = CCSettings::pageScalePinchZoomEnabled() ? m_pinch
ZoomViewport.applyScroll(move) : move; | |
| 1210 m_rootScrollLayerImpl->scrollBy(roundedIntSize(scrollOverflow)); | |
| 1211 | |
| 1212 if (m_rootScrollLayerImpl->scrollbarAnimationController()) | |
| 1213 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureUp
date(); | |
| 1214 | |
| 1215 m_client->setNeedsCommitOnImplThread(); | |
| 1216 m_client->setNeedsRedrawOnImplThread(); | |
| 1217 } | |
| 1218 | |
| 1219 void CCLayerTreeHostImpl::pinchGestureEnd() | |
| 1220 { | |
| 1221 m_pinchGestureActive = false; | |
| 1222 | |
| 1223 if (m_rootScrollLayerImpl && m_rootScrollLayerImpl->scrollbarAnimationContro
ller()) | |
| 1224 m_rootScrollLayerImpl->scrollbarAnimationController()->didPinchGestureEn
d(); | |
| 1225 | |
| 1226 m_client->setNeedsCommitOnImplThread(); | |
| 1227 } | |
| 1228 | |
| 1229 void CCLayerTreeHostImpl::computeDoubleTapZoomDeltas(CCScrollAndScaleSet* scroll
Info) | |
| 1230 { | |
| 1231 float pageScale = m_pageScaleAnimation->finalPageScale(); | |
| 1232 IntSize scrollOffset = m_pageScaleAnimation->finalScrollOffset(); | |
| 1233 scrollOffset.scale(m_pinchZoomViewport.pageScaleFactor() / pageScale); | |
| 1234 makeScrollAndScaleSet(scrollInfo, scrollOffset, pageScale); | |
| 1235 } | |
| 1236 | |
| 1237 void CCLayerTreeHostImpl::computePinchZoomDeltas(CCScrollAndScaleSet* scrollInfo
) | |
| 1238 { | |
| 1239 if (!m_rootScrollLayerImpl) | |
| 1240 return; | |
| 1241 | |
| 1242 // Only send fake scroll/zoom deltas if we're pinch zooming out by a | |
| 1243 // significant amount. This also ensures only one fake delta set will be | |
| 1244 // sent. | |
| 1245 const float pinchZoomOutSensitivity = 0.95f; | |
| 1246 if (m_pinchZoomViewport.pageScaleDelta() > pinchZoomOutSensitivity) | |
| 1247 return; | |
| 1248 | |
| 1249 // Compute where the scroll offset/page scale would be if fully pinch-zoomed | |
| 1250 // out from the anchor point. | |
| 1251 IntSize scrollBegin = flooredIntSize(m_rootScrollLayerImpl->scrollPosition()
+ m_rootScrollLayerImpl->scrollDelta()); | |
| 1252 scrollBegin.scale(m_pinchZoomViewport.pageScaleDelta()); | |
| 1253 float scaleBegin = m_pinchZoomViewport.totalPageScaleFactor(); | |
| 1254 float pageScaleDeltaToSend = m_pinchZoomViewport.minPageScaleFactor() / m_pi
nchZoomViewport.pageScaleFactor(); | |
| 1255 FloatSize scaledContentsSize = contentSize(); | |
| 1256 scaledContentsSize.scale(pageScaleDeltaToSend); | |
| 1257 | |
| 1258 FloatSize anchor = toSize(m_previousPinchAnchor); | |
| 1259 FloatSize scrollEnd = scrollBegin + anchor; | |
| 1260 scrollEnd.scale(m_pinchZoomViewport.minPageScaleFactor() / scaleBegin); | |
| 1261 scrollEnd -= anchor; | |
| 1262 scrollEnd = scrollEnd.shrunkTo(roundedIntSize(scaledContentsSize - m_deviceV
iewportSize)).expandedTo(FloatSize(0, 0)); | |
| 1263 scrollEnd.scale(1 / pageScaleDeltaToSend); | |
| 1264 scrollEnd.scale(m_deviceScaleFactor); | |
| 1265 | |
| 1266 makeScrollAndScaleSet(scrollInfo, roundedIntSize(scrollEnd), m_pinchZoomView
port.minPageScaleFactor()); | |
| 1267 } | |
| 1268 | |
| 1269 void CCLayerTreeHostImpl::makeScrollAndScaleSet(CCScrollAndScaleSet* scrollInfo,
const IntSize& scrollOffset, float pageScale) | |
| 1270 { | |
| 1271 if (!m_rootScrollLayerImpl) | |
| 1272 return; | |
| 1273 | |
| 1274 CCLayerTreeHostCommon::ScrollUpdateInfo scroll; | |
| 1275 scroll.layerId = m_rootScrollLayerImpl->id(); | |
| 1276 scroll.scrollDelta = scrollOffset - toSize(m_rootScrollLayerImpl->scrollPosi
tion()); | |
| 1277 scrollInfo->scrolls.append(scroll); | |
| 1278 m_rootScrollLayerImpl->setSentScrollDelta(scroll.scrollDelta); | |
| 1279 scrollInfo->pageScaleDelta = pageScale / m_pinchZoomViewport.pageScaleFactor
(); | |
| 1280 m_pinchZoomViewport.setSentPageScaleDelta(scrollInfo->pageScaleDelta); | |
| 1281 } | |
| 1282 | |
| 1283 static void collectScrollDeltas(CCScrollAndScaleSet* scrollInfo, CCLayerImpl* la
yerImpl) | |
| 1284 { | |
| 1285 if (!layerImpl) | |
| 1286 return; | |
| 1287 | |
| 1288 if (!layerImpl->scrollDelta().isZero()) { | |
| 1289 IntSize scrollDelta = flooredIntSize(layerImpl->scrollDelta()); | |
| 1290 CCLayerTreeHostCommon::ScrollUpdateInfo scroll; | |
| 1291 scroll.layerId = layerImpl->id(); | |
| 1292 scroll.scrollDelta = scrollDelta; | |
| 1293 scrollInfo->scrolls.append(scroll); | |
| 1294 layerImpl->setSentScrollDelta(scrollDelta); | |
| 1295 } | |
| 1296 | |
| 1297 for (size_t i = 0; i < layerImpl->children().size(); ++i) | |
| 1298 collectScrollDeltas(scrollInfo, layerImpl->children()[i]); | |
| 1299 } | |
| 1300 | |
| 1301 scoped_ptr<CCScrollAndScaleSet> CCLayerTreeHostImpl::processScrollDeltas() | |
| 1302 { | |
| 1303 scoped_ptr<CCScrollAndScaleSet> scrollInfo(new CCScrollAndScaleSet()); | |
| 1304 | |
| 1305 if (m_pinchGestureActive || m_pageScaleAnimation) { | |
| 1306 scrollInfo->pageScaleDelta = 1; | |
| 1307 m_pinchZoomViewport.setSentPageScaleDelta(1); | |
| 1308 // FIXME(aelias): Make these painting optimizations compatible with | |
| 1309 // compositor-side scaling. | |
| 1310 if (!CCSettings::pageScalePinchZoomEnabled()) { | |
| 1311 if (m_pinchGestureActive) | |
| 1312 computePinchZoomDeltas(scrollInfo.get()); | |
| 1313 else if (m_pageScaleAnimation.get()) | |
| 1314 computeDoubleTapZoomDeltas(scrollInfo.get()); | |
| 1315 } | |
| 1316 return scrollInfo.Pass(); | |
| 1317 } | |
| 1318 | |
| 1319 collectScrollDeltas(scrollInfo.get(), m_rootLayerImpl.get()); | |
| 1320 scrollInfo->pageScaleDelta = m_pinchZoomViewport.pageScaleDelta(); | |
| 1321 m_pinchZoomViewport.setSentPageScaleDelta(scrollInfo->pageScaleDelta); | |
| 1322 | |
| 1323 return scrollInfo.Pass(); | |
| 1324 } | |
| 1325 | |
| 1326 WebTransformationMatrix CCLayerTreeHostImpl::implTransform() const | |
| 1327 { | |
| 1328 return m_pinchZoomViewport.implTransform(); | |
| 1329 } | |
| 1330 | |
| 1331 void CCLayerTreeHostImpl::setFullRootLayerDamage() | |
| 1332 { | |
| 1333 if (m_rootLayerImpl) { | |
| 1334 CCRenderSurface* renderSurface = m_rootLayerImpl->renderSurface(); | |
| 1335 if (renderSurface) | |
| 1336 renderSurface->damageTracker()->forceFullDamageNextUpdate(); | |
| 1337 } | |
| 1338 } | |
| 1339 | |
| 1340 void CCLayerTreeHostImpl::animatePageScale(double monotonicTime) | |
| 1341 { | |
| 1342 if (!m_pageScaleAnimation || !m_rootScrollLayerImpl) | |
| 1343 return; | |
| 1344 | |
| 1345 IntSize scrollTotal = flooredIntSize(m_rootScrollLayerImpl->scrollPosition()
+ m_rootScrollLayerImpl->scrollDelta()); | |
| 1346 | |
| 1347 setPageScaleDelta(m_pageScaleAnimation->pageScaleAtTime(monotonicTime) / m_p
inchZoomViewport.pageScaleFactor()); | |
| 1348 IntSize nextScroll = m_pageScaleAnimation->scrollOffsetAtTime(monotonicTime)
; | |
| 1349 nextScroll.scale(1 / m_pinchZoomViewport.pageScaleDelta()); | |
| 1350 m_rootScrollLayerImpl->scrollBy(nextScroll - scrollTotal); | |
| 1351 m_client->setNeedsRedrawOnImplThread(); | |
| 1352 | |
| 1353 if (m_pageScaleAnimation->isAnimationCompleteAtTime(monotonicTime)) { | |
| 1354 m_pageScaleAnimation.clear(); | |
| 1355 m_client->setNeedsCommitOnImplThread(); | |
| 1356 } | |
| 1357 } | |
| 1358 | |
| 1359 void CCLayerTreeHostImpl::animateLayers(double monotonicTime, double wallClockTi
me) | |
| 1360 { | |
| 1361 if (!CCSettings::acceleratedAnimationEnabled() || !m_needsAnimateLayers || !
m_rootLayerImpl) | |
| 1362 return; | |
| 1363 | |
| 1364 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::animateLayers"); | |
| 1365 | |
| 1366 scoped_ptr<CCAnimationEventsVector> events(make_scoped_ptr(new CCAnimationEv
entsVector)); | |
| 1367 | |
| 1368 bool didAnimate = false; | |
| 1369 animateLayersRecursive(m_rootLayerImpl.get(), monotonicTime, wallClockTime,
events.get(), didAnimate, m_needsAnimateLayers); | |
| 1370 | |
| 1371 if (!events->empty()) | |
| 1372 m_client->postAnimationEventsToMainThreadOnImplThread(events.Pass(), wal
lClockTime); | |
| 1373 | |
| 1374 if (didAnimate) | |
| 1375 m_client->setNeedsRedrawOnImplThread(); | |
| 1376 | |
| 1377 setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers); | |
| 1378 } | |
| 1379 | |
| 1380 base::TimeDelta CCLayerTreeHostImpl::lowFrequencyAnimationInterval() const | |
| 1381 { | |
| 1382 return base::TimeDelta::FromSeconds(1); | |
| 1383 } | |
| 1384 | |
| 1385 void CCLayerTreeHostImpl::sendDidLoseContextRecursive(CCLayerImpl* current) | |
| 1386 { | |
| 1387 ASSERT(current); | |
| 1388 current->didLoseContext(); | |
| 1389 if (current->maskLayer()) | |
| 1390 sendDidLoseContextRecursive(current->maskLayer()); | |
| 1391 if (current->replicaLayer()) | |
| 1392 sendDidLoseContextRecursive(current->replicaLayer()); | |
| 1393 for (size_t i = 0; i < current->children().size(); ++i) | |
| 1394 sendDidLoseContextRecursive(current->children()[i]); | |
| 1395 } | |
| 1396 | |
| 1397 static void clearRenderSurfacesOnCCLayerImplRecursive(CCLayerImpl* current) | |
| 1398 { | |
| 1399 ASSERT(current); | |
| 1400 for (size_t i = 0; i < current->children().size(); ++i) | |
| 1401 clearRenderSurfacesOnCCLayerImplRecursive(current->children()[i]); | |
| 1402 current->clearRenderSurface(); | |
| 1403 } | |
| 1404 | |
| 1405 void CCLayerTreeHostImpl::clearRenderSurfaces() | |
| 1406 { | |
| 1407 clearRenderSurfacesOnCCLayerImplRecursive(m_rootLayerImpl.get()); | |
| 1408 m_renderSurfaceLayerList.clear(); | |
| 1409 } | |
| 1410 | |
| 1411 std::string CCLayerTreeHostImpl::layerTreeAsText() const | |
| 1412 { | |
| 1413 std::string str; | |
| 1414 if (m_rootLayerImpl) { | |
| 1415 str = m_rootLayerImpl->layerTreeAsText(); | |
| 1416 str += "RenderSurfaces:\n"; | |
| 1417 dumpRenderSurfaces(&str, 1, m_rootLayerImpl.get()); | |
| 1418 } | |
| 1419 return str; | |
| 1420 } | |
| 1421 | |
| 1422 void CCLayerTreeHostImpl::dumpRenderSurfaces(std::string* str, int indent, const
CCLayerImpl* layer) const | |
| 1423 { | |
| 1424 if (layer->renderSurface()) | |
| 1425 layer->renderSurface()->dumpSurface(str, indent); | |
| 1426 | |
| 1427 for (size_t i = 0; i < layer->children().size(); ++i) | |
| 1428 dumpRenderSurfaces(str, indent, layer->children()[i]); | |
| 1429 } | |
| 1430 | |
| 1431 int CCLayerTreeHostImpl::sourceAnimationFrameNumber() const | |
| 1432 { | |
| 1433 return fpsCounter()->currentFrameNumber(); | |
| 1434 } | |
| 1435 | |
| 1436 void CCLayerTreeHostImpl::renderingStats(CCRenderingStats* stats) const | |
| 1437 { | |
| 1438 stats->numFramesSentToScreen = fpsCounter()->currentFrameNumber(); | |
| 1439 stats->droppedFrameCount = fpsCounter()->droppedFrameCount(); | |
| 1440 stats->numImplThreadScrolls = m_numImplThreadScrolls; | |
| 1441 stats->numMainThreadScrolls = m_numMainThreadScrolls; | |
| 1442 } | |
| 1443 | |
| 1444 void CCLayerTreeHostImpl::animateScrollbars(double monotonicTime) | |
| 1445 { | |
| 1446 animateScrollbarsRecursive(m_rootLayerImpl.get(), monotonicTime); | |
| 1447 } | |
| 1448 | |
| 1449 void CCLayerTreeHostImpl::animateScrollbarsRecursive(CCLayerImpl* layer, double
monotonicTime) | |
| 1450 { | |
| 1451 if (!layer) | |
| 1452 return; | |
| 1453 | |
| 1454 CCScrollbarAnimationController* scrollbarController = layer->scrollbarAnimat
ionController(); | |
| 1455 if (scrollbarController && scrollbarController->animate(monotonicTime)) | |
| 1456 m_client->setNeedsRedrawOnImplThread(); | |
| 1457 | |
| 1458 for (size_t i = 0; i < layer->children().size(); ++i) | |
| 1459 animateScrollbarsRecursive(layer->children()[i], monotonicTime); | |
| 1460 } | |
| 1461 | |
| 1462 } // namespace cc | |
| OLD | NEW |