OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
| 3 * |
| 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions |
| 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the |
| 11 * documentation and/or other materials provided with the distribution. |
| 12 * |
| 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND AN
Y |
| 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR AN
Y |
| 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND O
N |
| 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 23 */ |
| 24 |
| 25 #include "config.h" |
| 26 |
| 27 #include "cc/CCLayerTreeHostImpl.h" |
| 28 |
| 29 #include "LayerRendererChromium.h" |
| 30 #include "TextStream.h" |
| 31 #include "TraceEvent.h" |
| 32 #include "TrackingTextureAllocator.h" |
| 33 #include "cc/CCActiveGestureAnimation.h" |
| 34 #include "cc/CCDamageTracker.h" |
| 35 #include "cc/CCDebugRectHistory.h" |
| 36 #include "cc/CCDelayBasedTimeSource.h" |
| 37 #include "cc/CCFontAtlas.h" |
| 38 #include "cc/CCFrameRateCounter.h" |
| 39 #include "cc/CCHeadsUpDisplay.h" |
| 40 #include "cc/CCLayerIterator.h" |
| 41 #include "cc/CCLayerTreeHost.h" |
| 42 #include "cc/CCLayerTreeHostCommon.h" |
| 43 #include "cc/CCOverdrawMetrics.h" |
| 44 #include "cc/CCPageScaleAnimation.h" |
| 45 #include "cc/CCRenderPassDrawQuad.h" |
| 46 #include "cc/CCSettings.h" |
| 47 #include "cc/CCSingleThreadProxy.h" |
| 48 #include <wtf/CurrentTime.h> |
| 49 |
| 50 using WebKit::WebTransformationMatrix; |
| 51 |
| 52 namespace { |
| 53 |
| 54 void didVisibilityChange(WebCore::CCLayerTreeHostImpl* id, bool visible) |
| 55 { |
| 56 if (visible) { |
| 57 TRACE_EVENT_ASYNC_BEGIN1("webkit", "CCLayerTreeHostImpl::setVisible", id
, "CCLayerTreeHostImpl", id); |
| 58 return; |
| 59 } |
| 60 |
| 61 TRACE_EVENT_ASYNC_END0("webkit", "CCLayerTreeHostImpl::setVisible", id); |
| 62 } |
| 63 |
| 64 } // namespace |
| 65 |
| 66 namespace WebCore { |
| 67 |
| 68 class CCLayerTreeHostImplTimeSourceAdapter : public CCTimeSourceClient { |
| 69 WTF_MAKE_NONCOPYABLE(CCLayerTreeHostImplTimeSourceAdapter); |
| 70 public: |
| 71 static PassOwnPtr<CCLayerTreeHostImplTimeSourceAdapter> create(CCLayerTreeHo
stImpl* layerTreeHostImpl, PassRefPtr<CCDelayBasedTimeSource> timeSource) |
| 72 { |
| 73 return adoptPtr(new CCLayerTreeHostImplTimeSourceAdapter(layerTreeHostIm
pl, timeSource)); |
| 74 } |
| 75 virtual ~CCLayerTreeHostImplTimeSourceAdapter() |
| 76 { |
| 77 m_timeSource->setClient(0); |
| 78 m_timeSource->setActive(false); |
| 79 } |
| 80 |
| 81 virtual void onTimerTick() OVERRIDE |
| 82 { |
| 83 // FIXME: We require that animate be called on the impl thread. This |
| 84 // avoids asserts in single threaded mode. Ideally background ticking |
| 85 // would be handled by the proxy/scheduler and this could be removed. |
| 86 DebugScopedSetImplThread impl; |
| 87 |
| 88 m_layerTreeHostImpl->animate(monotonicallyIncreasingTime(), currentTime(
)); |
| 89 } |
| 90 |
| 91 void setActive(bool active) |
| 92 { |
| 93 if (active != m_timeSource->active()) |
| 94 m_timeSource->setActive(active); |
| 95 } |
| 96 |
| 97 private: |
| 98 CCLayerTreeHostImplTimeSourceAdapter(CCLayerTreeHostImpl* layerTreeHostImpl,
PassRefPtr<CCDelayBasedTimeSource> timeSource) |
| 99 : m_layerTreeHostImpl(layerTreeHostImpl) |
| 100 , m_timeSource(timeSource) |
| 101 { |
| 102 m_timeSource->setClient(this); |
| 103 } |
| 104 |
| 105 CCLayerTreeHostImpl* m_layerTreeHostImpl; |
| 106 RefPtr<CCDelayBasedTimeSource> m_timeSource; |
| 107 }; |
| 108 |
| 109 PassOwnPtr<CCLayerTreeHostImpl> CCLayerTreeHostImpl::create(const CCLayerTreeSet
tings& settings, CCLayerTreeHostImplClient* client) |
| 110 { |
| 111 return adoptPtr(new CCLayerTreeHostImpl(settings, client)); |
| 112 } |
| 113 |
| 114 CCLayerTreeHostImpl::CCLayerTreeHostImpl(const CCLayerTreeSettings& settings, CC
LayerTreeHostImplClient* client) |
| 115 : m_client(client) |
| 116 , m_sourceFrameNumber(-1) |
| 117 , m_sourceAnimationFrameNumber(0) |
| 118 , m_rootScrollLayerImpl(0) |
| 119 , m_currentlyScrollingLayerImpl(0) |
| 120 , m_scrollingLayerIdFromPreviousTree(-1) |
| 121 , m_settings(settings) |
| 122 , m_deviceScaleFactor(1) |
| 123 , m_visible(true) |
| 124 , m_contentsTexturesWerePurgedSinceLastCommit(false) |
| 125 , m_memoryAllocationLimitBytes(TextureManager::highLimitBytes(viewportSize()
)) |
| 126 , m_headsUpDisplay(CCHeadsUpDisplay::create()) |
| 127 , m_pageScale(1) |
| 128 , m_pageScaleDelta(1) |
| 129 , m_sentPageScaleDelta(1) |
| 130 , m_minPageScale(0) |
| 131 , m_maxPageScale(0) |
| 132 , m_backgroundColor(0) |
| 133 , m_hasTransparentBackground(false) |
| 134 , m_needsAnimateLayers(false) |
| 135 , m_pinchGestureActive(false) |
| 136 , m_fpsCounter(CCFrameRateCounter::create()) |
| 137 , m_debugRectHistory(CCDebugRectHistory::create()) |
| 138 { |
| 139 ASSERT(CCProxy::isImplThread()); |
| 140 didVisibilityChange(this, m_visible); |
| 141 } |
| 142 |
| 143 CCLayerTreeHostImpl::~CCLayerTreeHostImpl() |
| 144 { |
| 145 ASSERT(CCProxy::isImplThread()); |
| 146 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::~CCLayerTreeHostImpl()"); |
| 147 |
| 148 if (m_rootLayerImpl) |
| 149 clearRenderSurfaces(); |
| 150 } |
| 151 |
| 152 void CCLayerTreeHostImpl::beginCommit() |
| 153 { |
| 154 } |
| 155 |
| 156 void CCLayerTreeHostImpl::commitComplete() |
| 157 { |
| 158 // Recompute max scroll position; must be after layer content bounds are |
| 159 // updated. |
| 160 updateMaxScrollPosition(); |
| 161 m_contentsTexturesWerePurgedSinceLastCommit = false; |
| 162 } |
| 163 |
| 164 bool CCLayerTreeHostImpl::canDraw() |
| 165 { |
| 166 if (!m_rootLayerImpl) |
| 167 return false; |
| 168 if (viewportSize().isEmpty()) |
| 169 return false; |
| 170 if (!m_layerRenderer) |
| 171 return false; |
| 172 if (m_contentsTexturesWerePurgedSinceLastCommit) |
| 173 return false; |
| 174 return true; |
| 175 } |
| 176 |
| 177 CCGraphicsContext* CCLayerTreeHostImpl::context() const |
| 178 { |
| 179 return m_context.get(); |
| 180 } |
| 181 |
| 182 void CCLayerTreeHostImpl::animate(double monotonicTime, double wallClockTime) |
| 183 { |
| 184 animatePageScale(monotonicTime); |
| 185 animateLayers(monotonicTime, wallClockTime); |
| 186 animateGestures(monotonicTime); |
| 187 } |
| 188 |
| 189 void CCLayerTreeHostImpl::startPageScaleAnimation(const IntSize& targetPosition,
bool anchorPoint, float pageScale, double startTime, double duration) |
| 190 { |
| 191 if (!m_rootScrollLayerImpl) |
| 192 return; |
| 193 |
| 194 IntSize scrollTotal = flooredIntSize(m_rootScrollLayerImpl->scrollPosition()
+ m_rootScrollLayerImpl->scrollDelta()); |
| 195 scrollTotal.scale(m_pageScaleDelta); |
| 196 float scaleTotal = m_pageScale * m_pageScaleDelta; |
| 197 IntSize scaledContentSize = contentSize(); |
| 198 scaledContentSize.scale(m_pageScaleDelta); |
| 199 |
| 200 m_pageScaleAnimation = CCPageScaleAnimation::create(scrollTotal, scaleTotal,
m_viewportSize, scaledContentSize, startTime); |
| 201 |
| 202 if (anchorPoint) { |
| 203 IntSize windowAnchor(targetPosition); |
| 204 windowAnchor.scale(scaleTotal / pageScale); |
| 205 windowAnchor -= scrollTotal; |
| 206 m_pageScaleAnimation->zoomWithAnchor(windowAnchor, pageScale, duration); |
| 207 } else |
| 208 m_pageScaleAnimation->zoomTo(targetPosition, pageScale, duration); |
| 209 |
| 210 m_client->setNeedsRedrawOnImplThread(); |
| 211 m_client->setNeedsCommitOnImplThread(); |
| 212 } |
| 213 |
| 214 void CCLayerTreeHostImpl::setActiveGestureAnimation(PassOwnPtr<CCActiveGestureAn
imation> gestureAnimation) |
| 215 { |
| 216 m_activeGestureAnimation = gestureAnimation; |
| 217 |
| 218 if (m_activeGestureAnimation) |
| 219 m_client->setNeedsRedrawOnImplThread(); |
| 220 } |
| 221 |
| 222 void CCLayerTreeHostImpl::scheduleAnimation() |
| 223 { |
| 224 m_client->setNeedsRedrawOnImplThread(); |
| 225 } |
| 226 |
| 227 void CCLayerTreeHostImpl::trackDamageForAllSurfaces(CCLayerImpl* rootDrawLayer,
const CCLayerList& renderSurfaceLayerList) |
| 228 { |
| 229 // For now, we use damage tracking to compute a global scissor. To do this,
we must |
| 230 // compute all damage tracking before drawing anything, so that we know the
root |
| 231 // damage rect. The root damage rect is then used to scissor each surface. |
| 232 |
| 233 for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0
; --surfaceIndex) { |
| 234 CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex]; |
| 235 CCRenderSurface* renderSurface = renderSurfaceLayer->renderSurface(); |
| 236 ASSERT(renderSurface); |
| 237 renderSurface->damageTracker()->updateDamageTrackingState(renderSurface-
>layerList(), renderSurfaceLayer->id(), renderSurface->surfacePropertyChangedOnl
yFromDescendant(), renderSurface->contentRect(), renderSurfaceLayer->maskLayer()
, renderSurfaceLayer->filters()); |
| 238 } |
| 239 } |
| 240 |
| 241 void CCLayerTreeHostImpl::calculateRenderSurfaceLayerList(CCLayerList& renderSur
faceLayerList) |
| 242 { |
| 243 ASSERT(renderSurfaceLayerList.isEmpty()); |
| 244 ASSERT(m_rootLayerImpl); |
| 245 |
| 246 renderSurfaceLayerList.append(m_rootLayerImpl.get()); |
| 247 |
| 248 if (!m_rootLayerImpl->renderSurface()) |
| 249 m_rootLayerImpl->createRenderSurface(); |
| 250 m_rootLayerImpl->renderSurface()->clearLayerList(); |
| 251 m_rootLayerImpl->renderSurface()->setContentRect(IntRect(IntPoint(), deviceV
iewportSize())); |
| 252 |
| 253 m_rootLayerImpl->setClipRect(IntRect(IntPoint(), deviceViewportSize())); |
| 254 |
| 255 { |
| 256 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::calcDrawEtc"); |
| 257 WebTransformationMatrix identityMatrix; |
| 258 WebTransformationMatrix deviceScaleTransform; |
| 259 deviceScaleTransform.scale(m_deviceScaleFactor); |
| 260 CCLayerTreeHostCommon::calculateDrawTransforms(m_rootLayerImpl.get(), m_
rootLayerImpl.get(), deviceScaleTransform, identityMatrix, renderSurfaceLayerLis
t, m_rootLayerImpl->renderSurface()->layerList(), &m_layerSorter, layerRendererC
apabilities().maxTextureSize); |
| 261 |
| 262 trackDamageForAllSurfaces(m_rootLayerImpl.get(), renderSurfaceLayerList)
; |
| 263 |
| 264 if (layerRendererCapabilities().usingPartialSwap) |
| 265 m_rootScissorRect = m_rootLayerImpl->renderSurface()->damageTracker(
)->currentDamageRect(); |
| 266 else |
| 267 m_rootScissorRect = FloatRect(FloatPoint(0, 0), deviceViewportSize()
); |
| 268 |
| 269 CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLaye
rList, m_rootScissorRect); |
| 270 } |
| 271 } |
| 272 |
| 273 bool CCLayerTreeHostImpl::calculateRenderPasses(FrameData& frame) |
| 274 { |
| 275 ASSERT(frame.renderPasses.isEmpty()); |
| 276 |
| 277 calculateRenderSurfaceLayerList(*frame.renderSurfaceLayerList); |
| 278 |
| 279 TRACE_EVENT1("cc", "CCLayerTreeHostImpl::calculateRenderPasses", "renderSurf
aceLayerList.size()", static_cast<long long unsigned>(frame.renderSurfaceLayerLi
st->size())); |
| 280 |
| 281 m_rootLayerImpl->setScissorRect(enclosingIntRect(m_rootScissorRect)); |
| 282 |
| 283 // Create the render passes in dependency order. |
| 284 HashMap<CCRenderSurface*, CCRenderPass*> surfacePassMap; |
| 285 for (int surfaceIndex = frame.renderSurfaceLayerList->size() - 1; surfaceInd
ex >= 0 ; --surfaceIndex) { |
| 286 CCLayerImpl* renderSurfaceLayer = (*frame.renderSurfaceLayerList)[surfac
eIndex]; |
| 287 CCRenderSurface* renderSurface = renderSurfaceLayer->renderSurface(); |
| 288 |
| 289 OwnPtr<CCRenderPass> pass = CCRenderPass::create(renderSurface); |
| 290 surfacePassMap.add(renderSurface, pass.get()); |
| 291 frame.renderPasses.append(pass.release()); |
| 292 } |
| 293 |
| 294 bool recordMetricsForFrame = true; // FIXME: In the future, disable this whe
n about:tracing is off. |
| 295 CCOcclusionTrackerImpl occlusionTracker(enclosingIntRect(m_rootScissorRect),
recordMetricsForFrame); |
| 296 occlusionTracker.setMinimumTrackingSize(CCOcclusionTrackerImpl::preferredMin
imumTrackingSize()); |
| 297 |
| 298 if (settings().showOccludingRects) |
| 299 occlusionTracker.setOccludingScreenSpaceRectsContainer(&frame.occludingS
creenSpaceRects); |
| 300 |
| 301 // Add quads to the Render passes in FrontToBack order to allow for testing
occlusion and performing culling during the tree walk. |
| 302 typedef CCLayerIterator<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface,
CCLayerIteratorActions::FrontToBack> CCLayerIteratorType; |
| 303 |
| 304 // Typically when we are missing a texture and use a checkerboard quad, we s
till draw the frame. However when the layer being |
| 305 // checkerboarded is moving due to an impl-animation, we drop the frame to a
void flashing due to the texture suddenly appearing |
| 306 // in the future. |
| 307 bool drawFrame = true; |
| 308 |
| 309 CCLayerIteratorType end = CCLayerIteratorType::end(frame.renderSurfaceLayerL
ist); |
| 310 for (CCLayerIteratorType it = CCLayerIteratorType::begin(frame.renderSurface
LayerList); it != end; ++it) { |
| 311 CCRenderSurface* renderSurface = it.targetRenderSurfaceLayer()->renderSu
rface(); |
| 312 CCRenderPass* pass = surfacePassMap.get(renderSurface); |
| 313 bool hadMissingTiles = false; |
| 314 |
| 315 occlusionTracker.enterLayer(it); |
| 316 |
| 317 if (it.representsContributingRenderSurface() && !it->renderSurface()->sc
issorRect().isEmpty()) { |
| 318 CCRenderPass* contributingRenderPass = surfacePassMap.get(it->render
Surface()); |
| 319 pass->appendQuadsForRenderSurfaceLayer(*it, contributingRenderPass,
&occlusionTracker); |
| 320 } else if (it.representsItself() && !occlusionTracker.occluded(*it, it->
visibleLayerRect()) && !it->visibleLayerRect().isEmpty() && !it->scissorRect().i
sEmpty()) { |
| 321 it->willDraw(m_layerRenderer.get(), context()); |
| 322 frame.willDrawLayers.append(*it); |
| 323 |
| 324 pass->appendQuadsForLayer(*it, &occlusionTracker, hadMissingTiles); |
| 325 } |
| 326 |
| 327 if (hadMissingTiles) { |
| 328 bool layerHasAnimatingTransform = it->screenSpaceTransformIsAnimatin
g() || it->drawTransformIsAnimating(); |
| 329 if (layerHasAnimatingTransform) |
| 330 drawFrame = false; |
| 331 } |
| 332 |
| 333 occlusionTracker.leaveLayer(it); |
| 334 } |
| 335 |
| 336 if (!m_hasTransparentBackground) { |
| 337 frame.renderPasses.last()->setHasTransparentBackground(false); |
| 338 frame.renderPasses.last()->appendQuadsToFillScreen(m_rootLayerImpl.get()
, m_backgroundColor, occlusionTracker); |
| 339 } |
| 340 |
| 341 if (drawFrame) |
| 342 occlusionTracker.overdrawMetrics().recordMetrics(this); |
| 343 |
| 344 m_layerRenderer->decideRenderPassAllocationsForFrame(frame.renderPasses); |
| 345 removePassesWithCachedTextures(frame.renderPasses, frame.skippedPasses); |
| 346 |
| 347 return drawFrame; |
| 348 } |
| 349 |
| 350 void CCLayerTreeHostImpl::animateLayersRecursive(CCLayerImpl* current, double mo
notonicTime, double wallClockTime, CCAnimationEventsVector* events, bool& didAni
mate, bool& needsAnimateLayers) |
| 351 { |
| 352 bool subtreeNeedsAnimateLayers = false; |
| 353 |
| 354 CCLayerAnimationController* currentController = current->layerAnimationContr
oller(); |
| 355 |
| 356 bool hadActiveAnimation = currentController->hasActiveAnimation(); |
| 357 currentController->animate(monotonicTime, events); |
| 358 bool startedAnimation = events->size() > 0; |
| 359 |
| 360 // We animated if we either ticked a running animation, or started a new ani
mation. |
| 361 if (hadActiveAnimation || startedAnimation) |
| 362 didAnimate = true; |
| 363 |
| 364 // If the current controller still has an active animation, we must continue
animating layers. |
| 365 if (currentController->hasActiveAnimation()) |
| 366 subtreeNeedsAnimateLayers = true; |
| 367 |
| 368 for (size_t i = 0; i < current->children().size(); ++i) { |
| 369 bool childNeedsAnimateLayers = false; |
| 370 animateLayersRecursive(current->children()[i].get(), monotonicTime, wall
ClockTime, events, didAnimate, childNeedsAnimateLayers); |
| 371 if (childNeedsAnimateLayers) |
| 372 subtreeNeedsAnimateLayers = true; |
| 373 } |
| 374 |
| 375 needsAnimateLayers = subtreeNeedsAnimateLayers; |
| 376 } |
| 377 |
| 378 void CCLayerTreeHostImpl::setBackgroundTickingEnabled(bool enabled) |
| 379 { |
| 380 // Lazily create the timeSource adapter so that we can vary the interval for
testing. |
| 381 if (!m_timeSourceClientAdapter) |
| 382 m_timeSourceClientAdapter = CCLayerTreeHostImplTimeSourceAdapter::create
(this, CCDelayBasedTimeSource::create(lowFrequencyAnimationInterval(), CCProxy::
currentThread())); |
| 383 |
| 384 m_timeSourceClientAdapter->setActive(enabled); |
| 385 } |
| 386 |
| 387 IntSize CCLayerTreeHostImpl::contentSize() const |
| 388 { |
| 389 // TODO(aelias): Hardcoding the first child here is weird. Think of |
| 390 // a cleaner way to get the contentBounds on the Impl side. |
| 391 if (!m_rootScrollLayerImpl || m_rootScrollLayerImpl->children().isEmpty()) |
| 392 return IntSize(); |
| 393 return m_rootScrollLayerImpl->children()[0]->contentBounds(); |
| 394 } |
| 395 |
| 396 void CCLayerTreeHostImpl::removeRenderPassesRecursive(CCRenderPassList& passes,
size_t bottomPass, const CCRenderPass* firstToRemove, CCRenderPassList& skippedP
asses) |
| 397 { |
| 398 size_t removeIndex = passes.find(firstToRemove); |
| 399 |
| 400 // The pass was already removed by another quad - probably the original, and
we are the replica. |
| 401 if (removeIndex == notFound) |
| 402 return; |
| 403 |
| 404 OwnPtr<CCRenderPass> removedPass = passes[removeIndex].release(); |
| 405 passes.remove(removeIndex); |
| 406 |
| 407 // Now follow up for all RenderPass quads and remove their render passes rec
ursively. |
| 408 const CCQuadList& quadList = removedPass->quadList(); |
| 409 CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToFront
Begin(); |
| 410 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator) { |
| 411 CCDrawQuad* currentQuad = (*quadListIterator).get(); |
| 412 if (currentQuad->material() != CCDrawQuad::RenderPass) |
| 413 continue; |
| 414 |
| 415 CCRenderPassDrawQuad* renderPassQuad = static_cast<CCRenderPassDrawQuad*
>(currentQuad); |
| 416 const CCRenderPass* nextRenderPass = renderPassQuad->renderPass(); |
| 417 |
| 418 // Our search is now limited up to the pass that we just removed. |
| 419 // Substitute removeIndex for bottomPass now. |
| 420 removeRenderPassesRecursive(passes, removeIndex, nextRenderPass, skipped
Passes); |
| 421 } |
| 422 skippedPasses.append(removedPass.release()); |
| 423 } |
| 424 |
| 425 void CCLayerTreeHostImpl::removePassesWithCachedTextures(CCRenderPassList& passe
s, CCRenderPassList& skippedPasses) |
| 426 { |
| 427 for (int passIndex = passes.size() - 1; passIndex >= 0; --passIndex) { |
| 428 CCRenderPass* currentPass = passes[passIndex].get(); |
| 429 const CCQuadList& quadList = currentPass->quadList(); |
| 430 CCQuadList::constBackToFrontIterator quadListIterator = quadList.backToF
rontBegin(); |
| 431 |
| 432 for (; quadListIterator != quadList.backToFrontEnd(); ++quadListIterator
) { |
| 433 CCDrawQuad* currentQuad = quadListIterator->get(); |
| 434 |
| 435 if (currentQuad->material() != CCDrawQuad::RenderPass) |
| 436 continue; |
| 437 |
| 438 CCRenderPassDrawQuad* renderPassQuad = static_cast<CCRenderPassDrawQ
uad*>(currentQuad); |
| 439 CCRenderSurface* targetSurface = renderPassQuad->renderPass()->targe
tSurface(); |
| 440 |
| 441 if (targetSurface->contentsChanged() || !targetSurface->hasCachedCon
tentsTexture()) |
| 442 continue; |
| 443 |
| 444 // Reserve the texture immediately. We do not need to pass in layer
renderer |
| 445 // since the texture already exists, just needs to be reserved. |
| 446 if (!targetSurface->prepareContentsTexture(0)) |
| 447 continue; |
| 448 |
| 449 // We are changing the vector in the middle of reverse iteration. |
| 450 // We are guaranteed that any data from iterator to the end will not
change. |
| 451 // Capture the iterator position from the end, and restore it after
the change. |
| 452 int positionFromEnd = passes.size() - passIndex; |
| 453 removeRenderPassesRecursive(passes, passIndex, renderPassQuad->rende
rPass(), skippedPasses); |
| 454 passIndex = passes.size() - positionFromEnd; |
| 455 ASSERT(passIndex >= 0); |
| 456 } |
| 457 } |
| 458 } |
| 459 |
| 460 bool CCLayerTreeHostImpl::prepareToDraw(FrameData& frame) |
| 461 { |
| 462 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::prepareToDraw"); |
| 463 ASSERT(canDraw()); |
| 464 |
| 465 frame.renderSurfaceLayerList = &m_renderSurfaceLayerList; |
| 466 frame.renderPasses.clear(); |
| 467 frame.renderSurfaceLayerList->clear(); |
| 468 frame.willDrawLayers.clear(); |
| 469 |
| 470 if (!calculateRenderPasses(frame)) |
| 471 return false; |
| 472 |
| 473 // If we return true, then we expect drawLayers() to be called before this f
unction is called again. |
| 474 return true; |
| 475 } |
| 476 |
| 477 void CCLayerTreeHostImpl::releaseContentsTextures() |
| 478 { |
| 479 contentsTextureAllocator()->deleteAllTextures(); |
| 480 m_contentsTexturesWerePurgedSinceLastCommit = true; |
| 481 } |
| 482 |
| 483 void CCLayerTreeHostImpl::setMemoryAllocationLimitBytes(size_t bytes) |
| 484 { |
| 485 if (m_memoryAllocationLimitBytes == bytes) |
| 486 return; |
| 487 m_memoryAllocationLimitBytes = bytes; |
| 488 |
| 489 ASSERT(bytes); |
| 490 m_client->setNeedsCommitOnImplThread(); |
| 491 } |
| 492 |
| 493 void CCLayerTreeHostImpl::drawLayers(const FrameData& frame) |
| 494 { |
| 495 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::drawLayers"); |
| 496 ASSERT(canDraw()); |
| 497 ASSERT(!frame.renderPasses.isEmpty()); |
| 498 |
| 499 // FIXME: use the frame begin time from the overall compositor scheduler. |
| 500 // This value is currently inaccessible because it is up in Chromium's |
| 501 // RenderWidget. |
| 502 |
| 503 // The root RenderPass is the last one to be drawn. |
| 504 CCRenderPass* rootRenderPass = frame.renderPasses.last().get(); |
| 505 |
| 506 m_fpsCounter->markBeginningOfFrame(currentTime()); |
| 507 m_layerRenderer->beginDrawingFrame(rootRenderPass); |
| 508 |
| 509 for (size_t i = 0; i < frame.renderPasses.size(); ++i) { |
| 510 CCRenderPass* renderPass = frame.renderPasses[i].get(); |
| 511 |
| 512 FloatRect rootScissorRectInCurrentSurface = renderPass->targetSurface()-
>computeRootScissorRectInCurrentSurface(m_rootScissorRect); |
| 513 m_layerRenderer->drawRenderPass(renderPass, rootScissorRectInCurrentSurf
ace); |
| 514 |
| 515 renderPass->targetSurface()->damageTracker()->didDrawDamagedArea(); |
| 516 } |
| 517 |
| 518 if (m_debugRectHistory->enabled(settings())) |
| 519 m_debugRectHistory->saveDebugRectsForCurrentFrame(m_rootLayerImpl.get(),
*frame.renderSurfaceLayerList, frame.occludingScreenSpaceRects, settings()); |
| 520 |
| 521 if (m_headsUpDisplay->enabled(settings())) |
| 522 m_headsUpDisplay->draw(this); |
| 523 |
| 524 m_layerRenderer->finishDrawingFrame(); |
| 525 |
| 526 ++m_sourceAnimationFrameNumber; |
| 527 |
| 528 // The next frame should start by assuming nothing has changed, and changes
are noted as they occur. |
| 529 m_rootLayerImpl->resetAllChangeTrackingForSubtree(); |
| 530 } |
| 531 |
| 532 void CCLayerTreeHostImpl::didDrawAllLayers(const FrameData& frame) |
| 533 { |
| 534 for (size_t i = 0; i < frame.willDrawLayers.size(); ++i) |
| 535 frame.willDrawLayers[i]->didDraw(); |
| 536 } |
| 537 |
| 538 void CCLayerTreeHostImpl::finishAllRendering() |
| 539 { |
| 540 if (m_layerRenderer) |
| 541 m_layerRenderer->finish(); |
| 542 } |
| 543 |
| 544 bool CCLayerTreeHostImpl::isContextLost() |
| 545 { |
| 546 return m_layerRenderer && m_layerRenderer->isContextLost(); |
| 547 } |
| 548 |
| 549 const LayerRendererCapabilities& CCLayerTreeHostImpl::layerRendererCapabilities(
) const |
| 550 { |
| 551 return m_layerRenderer->capabilities(); |
| 552 } |
| 553 |
| 554 TextureAllocator* CCLayerTreeHostImpl::contentsTextureAllocator() const |
| 555 { |
| 556 return m_layerRenderer ? m_layerRenderer->contentsTextureAllocator() : 0; |
| 557 } |
| 558 |
| 559 bool CCLayerTreeHostImpl::swapBuffers() |
| 560 { |
| 561 ASSERT(m_layerRenderer); |
| 562 |
| 563 m_fpsCounter->markEndOfFrame(); |
| 564 return m_layerRenderer->swapBuffers(enclosingIntRect(m_rootScissorRect)); |
| 565 } |
| 566 |
| 567 void CCLayerTreeHostImpl::didLoseContext() |
| 568 { |
| 569 m_client->didLoseContextOnImplThread(); |
| 570 } |
| 571 |
| 572 void CCLayerTreeHostImpl::onSwapBuffersComplete() |
| 573 { |
| 574 m_client->onSwapBuffersCompleteOnImplThread(); |
| 575 } |
| 576 |
| 577 void CCLayerTreeHostImpl::readback(void* pixels, const IntRect& rect) |
| 578 { |
| 579 ASSERT(m_layerRenderer); |
| 580 m_layerRenderer->getFramebufferPixels(pixels, rect); |
| 581 } |
| 582 |
| 583 static CCLayerImpl* findRootScrollLayer(CCLayerImpl* layer) |
| 584 { |
| 585 if (!layer) |
| 586 return 0; |
| 587 |
| 588 if (layer->scrollable()) |
| 589 return layer; |
| 590 |
| 591 for (size_t i = 0; i < layer->children().size(); ++i) { |
| 592 CCLayerImpl* found = findRootScrollLayer(layer->children()[i].get()); |
| 593 if (found) |
| 594 return found; |
| 595 } |
| 596 |
| 597 return 0; |
| 598 } |
| 599 |
| 600 // Content layers can be either directly scrollable or contained in an outer |
| 601 // scrolling layer which applies the scroll transform. Given a content layer, |
| 602 // this function returns the associated scroll layer if any. |
| 603 static CCLayerImpl* findScrollLayerForContentLayer(CCLayerImpl* layerImpl) |
| 604 { |
| 605 if (!layerImpl) |
| 606 return 0; |
| 607 |
| 608 if (layerImpl->scrollable()) |
| 609 return layerImpl; |
| 610 |
| 611 if (layerImpl->drawsContent() && layerImpl->parent() && layerImpl->parent()-
>scrollable()) |
| 612 return layerImpl->parent(); |
| 613 |
| 614 return 0; |
| 615 } |
| 616 |
| 617 void CCLayerTreeHostImpl::setRootLayer(PassOwnPtr<CCLayerImpl> layer) |
| 618 { |
| 619 m_rootLayerImpl = layer; |
| 620 m_rootScrollLayerImpl = findRootScrollLayer(m_rootLayerImpl.get()); |
| 621 m_currentlyScrollingLayerImpl = 0; |
| 622 |
| 623 if (m_rootLayerImpl && m_scrollingLayerIdFromPreviousTree != -1) |
| 624 m_currentlyScrollingLayerImpl = CCLayerTreeHostCommon::findLayerInSubtre
e(m_rootLayerImpl.get(), m_scrollingLayerIdFromPreviousTree); |
| 625 |
| 626 m_scrollingLayerIdFromPreviousTree = -1; |
| 627 } |
| 628 |
| 629 PassOwnPtr<CCLayerImpl> CCLayerTreeHostImpl::detachLayerTree() |
| 630 { |
| 631 // Clear all data structures that have direct references to the layer tree. |
| 632 m_scrollingLayerIdFromPreviousTree = m_currentlyScrollingLayerImpl ? m_curre
ntlyScrollingLayerImpl->id() : -1; |
| 633 m_currentlyScrollingLayerImpl = 0; |
| 634 m_renderSurfaceLayerList.clear(); |
| 635 |
| 636 return m_rootLayerImpl.release(); |
| 637 } |
| 638 |
| 639 void CCLayerTreeHostImpl::setVisible(bool visible) |
| 640 { |
| 641 ASSERT(CCProxy::isImplThread()); |
| 642 |
| 643 if (m_visible == visible) |
| 644 return; |
| 645 m_visible = visible; |
| 646 didVisibilityChange(this, m_visible); |
| 647 |
| 648 if (!m_layerRenderer) |
| 649 return; |
| 650 |
| 651 m_layerRenderer->setVisible(visible); |
| 652 |
| 653 setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers); |
| 654 } |
| 655 |
| 656 bool CCLayerTreeHostImpl::initializeLayerRenderer(PassOwnPtr<CCGraphicsContext>
context, TextureUploaderOption textureUploader) |
| 657 { |
| 658 WebKit::WebGraphicsContext3D* context3d = context->context3D(); |
| 659 if (!context3d) { |
| 660 // FIXME: Implement this path for software compositing. |
| 661 return false; |
| 662 } |
| 663 |
| 664 OwnPtr<LayerRendererChromium> layerRenderer; |
| 665 layerRenderer = LayerRendererChromium::create(this, context3d, textureUpload
er); |
| 666 |
| 667 // Since we now have a new context/layerRenderer, we cannot continue to use
the old |
| 668 // resources (i.e. renderSurfaces and texture IDs). |
| 669 if (m_rootLayerImpl) { |
| 670 clearRenderSurfaces(); |
| 671 sendDidLoseContextRecursive(m_rootLayerImpl.get()); |
| 672 } |
| 673 |
| 674 m_layerRenderer = layerRenderer.release(); |
| 675 if (m_layerRenderer) |
| 676 m_context = context; |
| 677 |
| 678 if (!m_visible && m_layerRenderer) |
| 679 m_layerRenderer->setVisible(m_visible); |
| 680 |
| 681 return m_layerRenderer; |
| 682 } |
| 683 |
| 684 void CCLayerTreeHostImpl::setViewportSize(const IntSize& viewportSize) |
| 685 { |
| 686 if (viewportSize == m_viewportSize) |
| 687 return; |
| 688 |
| 689 m_viewportSize = viewportSize; |
| 690 |
| 691 m_deviceViewportSize = viewportSize; |
| 692 m_deviceViewportSize.scale(m_deviceScaleFactor); |
| 693 |
| 694 updateMaxScrollPosition(); |
| 695 |
| 696 if (m_layerRenderer) |
| 697 m_layerRenderer->viewportChanged(); |
| 698 } |
| 699 |
| 700 static void adjustScrollsForPageScaleChange(CCLayerImpl* layerImpl, float pageSc
aleChange) |
| 701 { |
| 702 if (!layerImpl) |
| 703 return; |
| 704 |
| 705 if (layerImpl->scrollable()) { |
| 706 // We need to convert impl-side scroll deltas to pageScale space. |
| 707 FloatSize scrollDelta = layerImpl->scrollDelta(); |
| 708 scrollDelta.scale(pageScaleChange); |
| 709 layerImpl->setScrollDelta(scrollDelta); |
| 710 } |
| 711 |
| 712 for (size_t i = 0; i < layerImpl->children().size(); ++i) |
| 713 adjustScrollsForPageScaleChange(layerImpl->children()[i].get(), pageScal
eChange); |
| 714 } |
| 715 |
| 716 static void applyPageScaleDeltaToScrollLayers(CCLayerImpl* layerImpl, float page
ScaleDelta) |
| 717 { |
| 718 if (!layerImpl) |
| 719 return; |
| 720 |
| 721 if (layerImpl->scrollable()) |
| 722 layerImpl->setPageScaleDelta(pageScaleDelta); |
| 723 |
| 724 for (size_t i = 0; i < layerImpl->children().size(); ++i) |
| 725 applyPageScaleDeltaToScrollLayers(layerImpl->children()[i].get(), pageSc
aleDelta); |
| 726 } |
| 727 |
| 728 void CCLayerTreeHostImpl::setDeviceScaleFactor(float deviceScaleFactor) |
| 729 { |
| 730 if (deviceScaleFactor == m_deviceScaleFactor) |
| 731 return; |
| 732 m_deviceScaleFactor = deviceScaleFactor; |
| 733 |
| 734 m_deviceViewportSize = viewportSize(); |
| 735 m_deviceViewportSize.scale(m_deviceScaleFactor); |
| 736 updateMaxScrollPosition(); |
| 737 if (m_layerRenderer) |
| 738 m_layerRenderer->viewportChanged(); |
| 739 } |
| 740 |
| 741 |
| 742 void CCLayerTreeHostImpl::setPageScaleFactorAndLimits(float pageScale, float min
PageScale, float maxPageScale) |
| 743 { |
| 744 if (!pageScale) |
| 745 return; |
| 746 |
| 747 if (m_sentPageScaleDelta == 1 && pageScale == m_pageScale && minPageScale ==
m_minPageScale && maxPageScale == m_maxPageScale) |
| 748 return; |
| 749 |
| 750 m_minPageScale = minPageScale; |
| 751 m_maxPageScale = maxPageScale; |
| 752 |
| 753 float pageScaleChange = pageScale / m_pageScale; |
| 754 m_pageScale = pageScale; |
| 755 |
| 756 if (pageScaleChange != 1) |
| 757 adjustScrollsForPageScaleChange(m_rootScrollLayerImpl, pageScaleChange); |
| 758 |
| 759 // Clamp delta to limits and refresh display matrix. |
| 760 setPageScaleDelta(m_pageScaleDelta / m_sentPageScaleDelta); |
| 761 m_sentPageScaleDelta = 1; |
| 762 applyPageScaleDeltaToScrollLayers(m_rootScrollLayerImpl, m_pageScaleDelta); |
| 763 } |
| 764 |
| 765 void CCLayerTreeHostImpl::setPageScaleDelta(float delta) |
| 766 { |
| 767 // Clamp to the current min/max limits. |
| 768 float finalMagnifyScale = m_pageScale * delta; |
| 769 if (m_minPageScale && finalMagnifyScale < m_minPageScale) |
| 770 delta = m_minPageScale / m_pageScale; |
| 771 else if (m_maxPageScale && finalMagnifyScale > m_maxPageScale) |
| 772 delta = m_maxPageScale / m_pageScale; |
| 773 |
| 774 if (delta == m_pageScaleDelta) |
| 775 return; |
| 776 |
| 777 m_pageScaleDelta = delta; |
| 778 |
| 779 updateMaxScrollPosition(); |
| 780 applyPageScaleDeltaToScrollLayers(m_rootScrollLayerImpl, m_pageScaleDelta); |
| 781 } |
| 782 |
| 783 void CCLayerTreeHostImpl::updateMaxScrollPosition() |
| 784 { |
| 785 if (!m_rootScrollLayerImpl || !m_rootScrollLayerImpl->children().size()) |
| 786 return; |
| 787 |
| 788 FloatSize viewBounds = m_viewportSize; |
| 789 if (CCLayerImpl* clipLayer = m_rootScrollLayerImpl->parent()) { |
| 790 if (clipLayer->masksToBounds()) |
| 791 viewBounds = clipLayer->bounds(); |
| 792 } |
| 793 viewBounds.scale(1 / m_pageScaleDelta); |
| 794 viewBounds.scale(m_deviceScaleFactor); |
| 795 |
| 796 // maxScroll is computed in physical pixels, but scroll positions are in lay
out pixels. |
| 797 IntSize maxScroll = contentSize() - expandedIntSize(viewBounds); |
| 798 maxScroll.scale(1 / m_deviceScaleFactor); |
| 799 // The viewport may be larger than the contents in some cases, such as |
| 800 // having a vertical scrollbar but no horizontal overflow. |
| 801 maxScroll.clampNegativeToZero(); |
| 802 |
| 803 m_rootScrollLayerImpl->setMaxScrollPosition(maxScroll); |
| 804 } |
| 805 |
| 806 void CCLayerTreeHostImpl::setNeedsRedraw() |
| 807 { |
| 808 m_client->setNeedsRedrawOnImplThread(); |
| 809 } |
| 810 |
| 811 bool CCLayerTreeHostImpl::ensureRenderSurfaceLayerList() |
| 812 { |
| 813 if (!m_rootLayerImpl) |
| 814 return false; |
| 815 |
| 816 // We need both a non-empty render surface layer list and a root render |
| 817 // surface to be able to iterate over the visible layers. |
| 818 if (m_renderSurfaceLayerList.size() && m_rootLayerImpl->renderSurface()) |
| 819 return true; |
| 820 |
| 821 // If we are called after setRootLayer() but before prepareToDraw(), we need |
| 822 // to recalculate the visible layers. This prevents being unable to scroll |
| 823 // during part of a commit. |
| 824 m_renderSurfaceLayerList.clear(); |
| 825 calculateRenderSurfaceLayerList(m_renderSurfaceLayerList); |
| 826 |
| 827 return m_renderSurfaceLayerList.size(); |
| 828 } |
| 829 |
| 830 CCInputHandlerClient::ScrollStatus CCLayerTreeHostImpl::scrollBegin(const IntPoi
nt& viewportPoint, CCInputHandlerClient::ScrollInputType type) |
| 831 { |
| 832 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::scrollBegin"); |
| 833 |
| 834 ASSERT(!m_currentlyScrollingLayerImpl); |
| 835 clearCurrentlyScrollingLayer(); |
| 836 |
| 837 if (!ensureRenderSurfaceLayerList()) |
| 838 return ScrollIgnored; |
| 839 |
| 840 IntPoint deviceViewportPoint = viewportPoint; |
| 841 deviceViewportPoint.scale(m_deviceScaleFactor, m_deviceScaleFactor); |
| 842 |
| 843 // First find out which layer was hit from the saved list of visible layers |
| 844 // in the most recent frame. |
| 845 CCLayerImpl* layerImpl = CCLayerTreeHostCommon::findLayerThatIsHitByPoint(vi
ewportPoint, m_renderSurfaceLayerList); |
| 846 |
| 847 // Walk up the hierarchy and look for a scrollable layer. |
| 848 CCLayerImpl* potentiallyScrollingLayerImpl = 0; |
| 849 for (; layerImpl; layerImpl = layerImpl->parent()) { |
| 850 // The content layer can also block attempts to scroll outside the main
thread. |
| 851 if (layerImpl->tryScroll(deviceViewportPoint, type) == ScrollOnMainThrea
d) |
| 852 return ScrollOnMainThread; |
| 853 |
| 854 CCLayerImpl* scrollLayerImpl = findScrollLayerForContentLayer(layerImpl)
; |
| 855 if (!scrollLayerImpl) |
| 856 continue; |
| 857 |
| 858 ScrollStatus status = scrollLayerImpl->tryScroll(viewportPoint, type); |
| 859 |
| 860 // If any layer wants to divert the scroll event to the main thread, abo
rt. |
| 861 if (status == ScrollOnMainThread) |
| 862 return ScrollOnMainThread; |
| 863 |
| 864 if (status == ScrollStarted && !potentiallyScrollingLayerImpl) |
| 865 potentiallyScrollingLayerImpl = scrollLayerImpl; |
| 866 } |
| 867 |
| 868 if (potentiallyScrollingLayerImpl) { |
| 869 m_currentlyScrollingLayerImpl = potentiallyScrollingLayerImpl; |
| 870 return ScrollStarted; |
| 871 } |
| 872 return ScrollIgnored; |
| 873 } |
| 874 |
| 875 void CCLayerTreeHostImpl::scrollBy(const IntSize& scrollDelta) |
| 876 { |
| 877 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::scrollBy"); |
| 878 if (!m_currentlyScrollingLayerImpl) |
| 879 return; |
| 880 |
| 881 FloatSize pendingDelta(scrollDelta); |
| 882 pendingDelta.scale(1 / m_pageScaleDelta); |
| 883 |
| 884 for (CCLayerImpl* layerImpl = m_currentlyScrollingLayerImpl; layerImpl && !p
endingDelta.isZero(); layerImpl = layerImpl->parent()) { |
| 885 if (!layerImpl->scrollable()) |
| 886 continue; |
| 887 FloatSize previousDelta(layerImpl->scrollDelta()); |
| 888 layerImpl->scrollBy(pendingDelta); |
| 889 // Reset the pending scroll delta to zero if the layer was able to move
along the requested |
| 890 // axis. This is to ensure it is possible to scroll exactly to the begin
ning or end of a |
| 891 // scroll area regardless of the scroll step. For diagonal scrolls this
also avoids applying |
| 892 // the scroll on one axis to multiple layers. |
| 893 if (previousDelta.width() != layerImpl->scrollDelta().width()) |
| 894 pendingDelta.setWidth(0); |
| 895 if (previousDelta.height() != layerImpl->scrollDelta().height()) |
| 896 pendingDelta.setHeight(0); |
| 897 } |
| 898 |
| 899 if (!scrollDelta.isZero() && pendingDelta.isEmpty()) { |
| 900 m_client->setNeedsCommitOnImplThread(); |
| 901 m_client->setNeedsRedrawOnImplThread(); |
| 902 } |
| 903 } |
| 904 |
| 905 void CCLayerTreeHostImpl::clearCurrentlyScrollingLayer() |
| 906 { |
| 907 m_currentlyScrollingLayerImpl = 0; |
| 908 m_scrollingLayerIdFromPreviousTree = -1; |
| 909 } |
| 910 |
| 911 void CCLayerTreeHostImpl::scrollEnd() |
| 912 { |
| 913 clearCurrentlyScrollingLayer(); |
| 914 } |
| 915 |
| 916 void CCLayerTreeHostImpl::pinchGestureBegin() |
| 917 { |
| 918 m_pinchGestureActive = true; |
| 919 m_previousPinchAnchor = IntPoint(); |
| 920 } |
| 921 |
| 922 void CCLayerTreeHostImpl::pinchGestureUpdate(float magnifyDelta, |
| 923 const IntPoint& anchor) |
| 924 { |
| 925 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::pinchGestureUpdate"); |
| 926 |
| 927 if (!m_rootScrollLayerImpl) |
| 928 return; |
| 929 |
| 930 if (m_previousPinchAnchor == IntPoint::zero()) |
| 931 m_previousPinchAnchor = anchor; |
| 932 |
| 933 // Keep the center-of-pinch anchor specified by (x, y) in a stable |
| 934 // position over the course of the magnify. |
| 935 FloatPoint previousScaleAnchor(m_previousPinchAnchor.x() / m_pageScaleDelta,
m_previousPinchAnchor.y() / m_pageScaleDelta); |
| 936 setPageScaleDelta(m_pageScaleDelta * magnifyDelta); |
| 937 FloatPoint newScaleAnchor(anchor.x() / m_pageScaleDelta, anchor.y() / m_page
ScaleDelta); |
| 938 FloatSize move = previousScaleAnchor - newScaleAnchor; |
| 939 |
| 940 m_previousPinchAnchor = anchor; |
| 941 |
| 942 m_rootScrollLayerImpl->scrollBy(roundedIntSize(move)); |
| 943 m_client->setNeedsCommitOnImplThread(); |
| 944 m_client->setNeedsRedrawOnImplThread(); |
| 945 } |
| 946 |
| 947 void CCLayerTreeHostImpl::pinchGestureEnd() |
| 948 { |
| 949 m_pinchGestureActive = false; |
| 950 |
| 951 m_client->setNeedsCommitOnImplThread(); |
| 952 } |
| 953 |
| 954 void CCLayerTreeHostImpl::computeDoubleTapZoomDeltas(CCScrollAndScaleSet* scroll
Info) |
| 955 { |
| 956 float pageScale = m_pageScaleAnimation->finalPageScale(); |
| 957 IntSize scrollOffset = m_pageScaleAnimation->finalScrollOffset(); |
| 958 scrollOffset.scale(m_pageScale / pageScale); |
| 959 makeScrollAndScaleSet(scrollInfo, scrollOffset, pageScale); |
| 960 } |
| 961 |
| 962 void CCLayerTreeHostImpl::computePinchZoomDeltas(CCScrollAndScaleSet* scrollInfo
) |
| 963 { |
| 964 if (!m_rootScrollLayerImpl) |
| 965 return; |
| 966 |
| 967 // Only send fake scroll/zoom deltas if we're pinch zooming out by a |
| 968 // significant amount. This also ensures only one fake delta set will be |
| 969 // sent. |
| 970 const float pinchZoomOutSensitivity = 0.95; |
| 971 if (m_pageScaleDelta > pinchZoomOutSensitivity) |
| 972 return; |
| 973 |
| 974 // Compute where the scroll offset/page scale would be if fully pinch-zoomed |
| 975 // out from the anchor point. |
| 976 IntSize scrollBegin = flooredIntSize(m_rootScrollLayerImpl->scrollPosition()
+ m_rootScrollLayerImpl->scrollDelta()); |
| 977 scrollBegin.scale(m_pageScaleDelta); |
| 978 float scaleBegin = m_pageScale * m_pageScaleDelta; |
| 979 float pageScaleDeltaToSend = m_minPageScale / m_pageScale; |
| 980 FloatSize scaledContentsSize = contentSize(); |
| 981 scaledContentsSize.scale(pageScaleDeltaToSend); |
| 982 |
| 983 FloatSize anchor = toSize(m_previousPinchAnchor); |
| 984 FloatSize scrollEnd = scrollBegin + anchor; |
| 985 scrollEnd.scale(m_minPageScale / scaleBegin); |
| 986 scrollEnd -= anchor; |
| 987 scrollEnd = scrollEnd.shrunkTo(roundedIntSize(scaledContentsSize - m_deviceV
iewportSize)).expandedTo(FloatSize(0, 0)); |
| 988 scrollEnd.scale(1 / pageScaleDeltaToSend); |
| 989 scrollEnd.scale(m_deviceScaleFactor); |
| 990 |
| 991 makeScrollAndScaleSet(scrollInfo, roundedIntSize(scrollEnd), m_minPageScale)
; |
| 992 } |
| 993 |
| 994 void CCLayerTreeHostImpl::makeScrollAndScaleSet(CCScrollAndScaleSet* scrollInfo,
const IntSize& scrollOffset, float pageScale) |
| 995 { |
| 996 if (!m_rootScrollLayerImpl) |
| 997 return; |
| 998 |
| 999 CCLayerTreeHostCommon::ScrollUpdateInfo scroll; |
| 1000 scroll.layerId = m_rootScrollLayerImpl->id(); |
| 1001 scroll.scrollDelta = scrollOffset - toSize(m_rootScrollLayerImpl->scrollPosi
tion()); |
| 1002 scrollInfo->scrolls.append(scroll); |
| 1003 m_rootScrollLayerImpl->setSentScrollDelta(scroll.scrollDelta); |
| 1004 m_sentPageScaleDelta = scrollInfo->pageScaleDelta = pageScale / m_pageScale; |
| 1005 } |
| 1006 |
| 1007 static void collectScrollDeltas(CCScrollAndScaleSet* scrollInfo, CCLayerImpl* la
yerImpl) |
| 1008 { |
| 1009 if (!layerImpl) |
| 1010 return; |
| 1011 |
| 1012 if (!layerImpl->scrollDelta().isZero()) { |
| 1013 IntSize scrollDelta = flooredIntSize(layerImpl->scrollDelta()); |
| 1014 CCLayerTreeHostCommon::ScrollUpdateInfo scroll; |
| 1015 scroll.layerId = layerImpl->id(); |
| 1016 scroll.scrollDelta = scrollDelta; |
| 1017 scrollInfo->scrolls.append(scroll); |
| 1018 layerImpl->setSentScrollDelta(scrollDelta); |
| 1019 } |
| 1020 |
| 1021 for (size_t i = 0; i < layerImpl->children().size(); ++i) |
| 1022 collectScrollDeltas(scrollInfo, layerImpl->children()[i].get()); |
| 1023 } |
| 1024 |
| 1025 PassOwnPtr<CCScrollAndScaleSet> CCLayerTreeHostImpl::processScrollDeltas() |
| 1026 { |
| 1027 OwnPtr<CCScrollAndScaleSet> scrollInfo = adoptPtr(new CCScrollAndScaleSet())
; |
| 1028 |
| 1029 if (m_pinchGestureActive || m_pageScaleAnimation) { |
| 1030 m_sentPageScaleDelta = scrollInfo->pageScaleDelta = 1; |
| 1031 if (m_pinchGestureActive) |
| 1032 computePinchZoomDeltas(scrollInfo.get()); |
| 1033 else if (m_pageScaleAnimation.get()) |
| 1034 computeDoubleTapZoomDeltas(scrollInfo.get()); |
| 1035 return scrollInfo.release(); |
| 1036 } |
| 1037 |
| 1038 collectScrollDeltas(scrollInfo.get(), m_rootLayerImpl.get()); |
| 1039 m_sentPageScaleDelta = scrollInfo->pageScaleDelta = m_pageScaleDelta; |
| 1040 |
| 1041 return scrollInfo.release(); |
| 1042 } |
| 1043 |
| 1044 void CCLayerTreeHostImpl::setFullRootLayerDamage() |
| 1045 { |
| 1046 if (m_rootLayerImpl) { |
| 1047 CCRenderSurface* renderSurface = m_rootLayerImpl->renderSurface(); |
| 1048 if (renderSurface) |
| 1049 renderSurface->damageTracker()->forceFullDamageNextUpdate(); |
| 1050 } |
| 1051 } |
| 1052 |
| 1053 void CCLayerTreeHostImpl::animatePageScale(double monotonicTime) |
| 1054 { |
| 1055 if (!m_pageScaleAnimation || !m_rootScrollLayerImpl) |
| 1056 return; |
| 1057 |
| 1058 IntSize scrollTotal = flooredIntSize(m_rootScrollLayerImpl->scrollPosition()
+ m_rootScrollLayerImpl->scrollDelta()); |
| 1059 |
| 1060 setPageScaleDelta(m_pageScaleAnimation->pageScaleAtTime(monotonicTime) / m_p
ageScale); |
| 1061 IntSize nextScroll = m_pageScaleAnimation->scrollOffsetAtTime(monotonicTime)
; |
| 1062 nextScroll.scale(1 / m_pageScaleDelta); |
| 1063 m_rootScrollLayerImpl->scrollBy(nextScroll - scrollTotal); |
| 1064 m_client->setNeedsRedrawOnImplThread(); |
| 1065 |
| 1066 if (m_pageScaleAnimation->isAnimationCompleteAtTime(monotonicTime)) { |
| 1067 m_pageScaleAnimation.clear(); |
| 1068 m_client->setNeedsCommitOnImplThread(); |
| 1069 } |
| 1070 } |
| 1071 |
| 1072 void CCLayerTreeHostImpl::animateLayers(double monotonicTime, double wallClockTi
me) |
| 1073 { |
| 1074 if (!CCSettings::acceleratedAnimationEnabled() || !m_needsAnimateLayers || !
m_rootLayerImpl) |
| 1075 return; |
| 1076 |
| 1077 TRACE_EVENT0("cc", "CCLayerTreeHostImpl::animateLayers"); |
| 1078 |
| 1079 OwnPtr<CCAnimationEventsVector> events(adoptPtr(new CCAnimationEventsVector)
); |
| 1080 |
| 1081 bool didAnimate = false; |
| 1082 animateLayersRecursive(m_rootLayerImpl.get(), monotonicTime, wallClockTime,
events.get(), didAnimate, m_needsAnimateLayers); |
| 1083 |
| 1084 if (!events->isEmpty()) |
| 1085 m_client->postAnimationEventsToMainThreadOnImplThread(events.release(),
wallClockTime); |
| 1086 |
| 1087 if (didAnimate) |
| 1088 m_client->setNeedsRedrawOnImplThread(); |
| 1089 |
| 1090 setBackgroundTickingEnabled(!m_visible && m_needsAnimateLayers); |
| 1091 } |
| 1092 |
| 1093 double CCLayerTreeHostImpl::lowFrequencyAnimationInterval() const |
| 1094 { |
| 1095 return 1; |
| 1096 } |
| 1097 |
| 1098 void CCLayerTreeHostImpl::sendDidLoseContextRecursive(CCLayerImpl* current) |
| 1099 { |
| 1100 ASSERT(current); |
| 1101 current->didLoseContext(); |
| 1102 if (current->maskLayer()) |
| 1103 sendDidLoseContextRecursive(current->maskLayer()); |
| 1104 if (current->replicaLayer()) |
| 1105 sendDidLoseContextRecursive(current->replicaLayer()); |
| 1106 for (size_t i = 0; i < current->children().size(); ++i) |
| 1107 sendDidLoseContextRecursive(current->children()[i].get()); |
| 1108 } |
| 1109 |
| 1110 static void clearRenderSurfacesOnCCLayerImplRecursive(CCLayerImpl* current) |
| 1111 { |
| 1112 ASSERT(current); |
| 1113 for (size_t i = 0; i < current->children().size(); ++i) |
| 1114 clearRenderSurfacesOnCCLayerImplRecursive(current->children()[i].get()); |
| 1115 current->clearRenderSurface(); |
| 1116 } |
| 1117 |
| 1118 void CCLayerTreeHostImpl::clearRenderSurfaces() |
| 1119 { |
| 1120 clearRenderSurfacesOnCCLayerImplRecursive(m_rootLayerImpl.get()); |
| 1121 m_renderSurfaceLayerList.clear(); |
| 1122 } |
| 1123 |
| 1124 String CCLayerTreeHostImpl::layerTreeAsText() const |
| 1125 { |
| 1126 TextStream ts; |
| 1127 if (m_rootLayerImpl) { |
| 1128 ts << m_rootLayerImpl->layerTreeAsText(); |
| 1129 ts << "RenderSurfaces:\n"; |
| 1130 dumpRenderSurfaces(ts, 1, m_rootLayerImpl.get()); |
| 1131 } |
| 1132 return ts.release(); |
| 1133 } |
| 1134 |
| 1135 void CCLayerTreeHostImpl::setFontAtlas(PassOwnPtr<CCFontAtlas> fontAtlas) |
| 1136 { |
| 1137 m_headsUpDisplay->setFontAtlas(fontAtlas); |
| 1138 } |
| 1139 |
| 1140 void CCLayerTreeHostImpl::dumpRenderSurfaces(TextStream& ts, int indent, const C
CLayerImpl* layer) const |
| 1141 { |
| 1142 if (layer->renderSurface()) |
| 1143 layer->renderSurface()->dumpSurface(ts, indent); |
| 1144 |
| 1145 for (size_t i = 0; i < layer->children().size(); ++i) |
| 1146 dumpRenderSurfaces(ts, indent, layer->children()[i].get()); |
| 1147 } |
| 1148 |
| 1149 |
| 1150 void CCLayerTreeHostImpl::animateGestures(double monotonicTime) |
| 1151 { |
| 1152 if (!m_activeGestureAnimation) |
| 1153 return; |
| 1154 |
| 1155 bool isContinuing = m_activeGestureAnimation->animate(monotonicTime); |
| 1156 if (isContinuing) |
| 1157 m_client->setNeedsRedrawOnImplThread(); |
| 1158 else |
| 1159 m_activeGestureAnimation.clear(); |
| 1160 } |
| 1161 |
| 1162 } // namespace WebCore |
OLD | NEW |