1/*
2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 * Copyright (C) 2012 Company 100, Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25 * THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "config.h"
29
30#if USE(COORDINATED_GRAPHICS)
31#include "CoordinatedLayerTreeHost.h"
32
33#include "CoordinatedGraphicsArgumentCoders.h"
34#include "CoordinatedLayerTreeHostProxyMessages.h"
35#include "DrawingAreaImpl.h"
36#include "GraphicsContext.h"
37#include "WebCoordinatedSurface.h"
38#include "WebCoreArgumentCoders.h"
39#include "WebPage.h"
40#include "WebPageProxyMessages.h"
41#include <WebCore/Frame.h>
42#include <WebCore/FrameView.h>
43#include <WebCore/GraphicsSurface.h>
44#include <WebCore/InspectorController.h>
45#include <WebCore/Page.h>
46#include <WebCore/RenderLayer.h>
47#include <WebCore/RenderLayerBacking.h>
48#include <WebCore/RenderLayerCompositor.h>
49#include <WebCore/RenderView.h>
50#include <WebCore/Settings.h>
51#include <WebCore/SurfaceUpdateInfo.h>
52#include <WebCore/TextureMapperPlatformLayer.h>
53#include <wtf/CurrentTime.h>
54#include <wtf/TemporaryChange.h>
55
56#if ENABLE(CSS_SHADERS)
57#include "CustomFilterValidatedProgram.h"
58#include "ValidatedCustomFilterOperation.h"
59#endif
60
61using namespace WebCore;
62
63namespace WebKit {
64
65PassRefPtr<CoordinatedLayerTreeHost> CoordinatedLayerTreeHost::create(WebPage* webPage)
66{
67    return adoptRef(new CoordinatedLayerTreeHost(webPage));
68}
69
70CoordinatedLayerTreeHost::~CoordinatedLayerTreeHost()
71{
72#if ENABLE(CSS_SHADERS)
73    disconnectCustomFilterPrograms();
74#endif
75    purgeBackingStores();
76
77    LayerMap::iterator end = m_registeredLayers.end();
78    for (LayerMap::iterator it = m_registeredLayers.begin(); it != end; ++it)
79        it->value->setCoordinator(0);
80}
81
82CoordinatedLayerTreeHost::CoordinatedLayerTreeHost(WebPage* webPage)
83    : LayerTreeHost(webPage)
84    , m_rootCompositingLayer(0)
85    , m_notifyAfterScheduledLayerFlush(false)
86    , m_isValid(true)
87    , m_isPurging(false)
88    , m_isFlushingLayerChanges(false)
89    , m_waitingForUIProcess(true)
90    , m_isSuspended(false)
91    , m_shouldSyncFrame(false)
92    , m_didInitializeRootCompositingLayer(false)
93    , m_layerFlushTimer(this, &CoordinatedLayerTreeHost::layerFlushTimerFired)
94    , m_releaseInactiveAtlasesTimer(this, &CoordinatedLayerTreeHost::releaseInactiveAtlasesTimerFired)
95    , m_layerFlushSchedulingEnabled(true)
96    , m_forceRepaintAsyncCallbackID(0)
97    , m_animationsLocked(false)
98#if ENABLE(REQUEST_ANIMATION_FRAME)
99    , m_lastAnimationServiceTime(0)
100#endif
101{
102    m_webPage->corePage()->settings()->setApplyDeviceScaleFactorInCompositor(true);
103
104    // Create a root layer.
105    m_rootLayer = GraphicsLayer::create(this, this);
106#ifndef NDEBUG
107    m_rootLayer->setName("CoordinatedLayerTreeHost root layer");
108#endif
109    m_rootLayer->setDrawsContent(false);
110    m_rootLayer->setSize(m_webPage->size());
111    m_layerTreeContext.coordinatedLayerID = toCoordinatedGraphicsLayer(m_rootLayer.get())->id();
112
113    CoordinatedSurface::setFactory(createCoordinatedSurface);
114
115    // This is a temporary way to enable this only in the GL case, until TextureMapperImageBuffer is removed.
116    // See https://bugs.webkit.org/show_bug.cgi?id=114869
117    CoordinatedGraphicsLayer::setShouldSupportContentsTiling(true);
118
119    if (m_webPage->hasPageOverlay())
120        createPageOverlayLayer();
121
122    scheduleLayerFlush();
123}
124
125void CoordinatedLayerTreeHost::setLayerFlushSchedulingEnabled(bool layerFlushingEnabled)
126{
127    if (m_layerFlushSchedulingEnabled == layerFlushingEnabled)
128        return;
129
130    m_layerFlushSchedulingEnabled = layerFlushingEnabled;
131
132    if (m_layerFlushSchedulingEnabled) {
133        scheduleLayerFlush();
134        return;
135    }
136
137    cancelPendingLayerFlush();
138}
139
140void CoordinatedLayerTreeHost::scheduleLayerFlush()
141{
142    if (!m_layerFlushSchedulingEnabled)
143        return;
144
145    if (!m_layerFlushTimer.isActive() || m_layerFlushTimer.nextFireInterval() > 0)
146        m_layerFlushTimer.startOneShot(0);
147}
148
149void CoordinatedLayerTreeHost::cancelPendingLayerFlush()
150{
151    m_layerFlushTimer.stop();
152}
153
154void CoordinatedLayerTreeHost::setShouldNotifyAfterNextScheduledLayerFlush(bool notifyAfterScheduledLayerFlush)
155{
156    m_notifyAfterScheduledLayerFlush = notifyAfterScheduledLayerFlush;
157}
158
159void CoordinatedLayerTreeHost::setRootCompositingLayer(WebCore::GraphicsLayer* graphicsLayer)
160{
161    if (m_rootCompositingLayer)
162        m_rootCompositingLayer->removeFromParent();
163
164    m_rootCompositingLayer = graphicsLayer;
165    if (m_rootCompositingLayer)
166        m_rootLayer->addChildAtIndex(m_rootCompositingLayer, 0);
167}
168
169void CoordinatedLayerTreeHost::invalidate()
170{
171    cancelPendingLayerFlush();
172
173    ASSERT(m_isValid);
174    m_rootLayer = nullptr;
175    m_isValid = false;
176}
177
178void CoordinatedLayerTreeHost::forceRepaint()
179{
180    // This is necessary for running layout tests. Since in this case we are not waiting for a UIProcess to reply nicely.
181    // Instead we are just triggering forceRepaint. But we still want to have the scripted animation callbacks being executed.
182    syncDisplayState();
183
184    // We need to schedule another flush, otherwise the forced paint might cancel a later expected flush.
185    // This is aligned with LayerTreeHostCA.
186    scheduleLayerFlush();
187    flushPendingLayerChanges();
188}
189
190bool CoordinatedLayerTreeHost::forceRepaintAsync(uint64_t callbackID)
191{
192    // We expect the UI process to not require a new repaint until the previous one has finished.
193    ASSERT(!m_forceRepaintAsyncCallbackID);
194    m_forceRepaintAsyncCallbackID = callbackID;
195    scheduleLayerFlush();
196    return true;
197}
198
199void CoordinatedLayerTreeHost::sizeDidChange(const WebCore::IntSize& newSize)
200{
201    m_rootLayer->setSize(newSize);
202    scheduleLayerFlush();
203}
204
205void CoordinatedLayerTreeHost::didInstallPageOverlay(PageOverlay* pageOverlay)
206{
207    ASSERT(!m_pageOverlay);
208    m_pageOverlay = pageOverlay;
209
210    createPageOverlayLayer();
211    scheduleLayerFlush();
212}
213
214void CoordinatedLayerTreeHost::didUninstallPageOverlay(PageOverlay*)
215{
216    m_pageOverlay = 0;
217
218    destroyPageOverlayLayer();
219    scheduleLayerFlush();
220}
221
222void CoordinatedLayerTreeHost::setPageOverlayNeedsDisplay(PageOverlay*, const WebCore::IntRect& rect)
223{
224    ASSERT(m_pageOverlayLayer);
225    m_pageOverlayLayer->setNeedsDisplayInRect(rect);
226    scheduleLayerFlush();
227}
228
229void CoordinatedLayerTreeHost::setPageOverlayOpacity(PageOverlay*, float value)
230{
231    ASSERT(m_pageOverlayLayer);
232    m_pageOverlayLayer->setOpacity(value);
233    scheduleLayerFlush();
234}
235
236bool CoordinatedLayerTreeHost::flushPendingLayerChanges()
237{
238    if (m_waitingForUIProcess)
239        return false;
240
241    TemporaryChange<bool> protector(m_isFlushingLayerChanges, true);
242
243    initializeRootCompositingLayerIfNeeded();
244
245    m_rootLayer->flushCompositingStateForThisLayerOnly();
246    if (m_pageOverlayLayer)
247        m_pageOverlayLayer->flushCompositingStateForThisLayerOnly();
248
249    bool didSync = m_webPage->corePage()->mainFrame()->view()->flushCompositingStateIncludingSubframes();
250
251    toCoordinatedGraphicsLayer(m_rootLayer.get())->updateContentBuffersIncludingSubLayers();
252    toCoordinatedGraphicsLayer(m_rootLayer.get())->syncPendingStateChangesIncludingSubLayers();
253
254    flushPendingImageBackingChanges();
255
256    if (m_shouldSyncFrame) {
257        didSync = true;
258
259        if (m_rootCompositingLayer) {
260            m_state.contentsSize = roundedIntSize(m_rootCompositingLayer->size());
261            if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer())
262                m_state.coveredRect = contentsLayer->coverRect();
263        }
264
265        m_state.scrollPosition = m_visibleContentsRect.location();
266
267        m_webPage->send(Messages::CoordinatedLayerTreeHostProxy::CommitCoordinatedGraphicsState(m_state));
268
269        clearPendingStateChanges();
270        m_waitingForUIProcess = true;
271        m_shouldSyncFrame = false;
272    }
273
274    if (m_forceRepaintAsyncCallbackID) {
275        m_webPage->send(Messages::WebPageProxy::VoidCallback(m_forceRepaintAsyncCallbackID));
276        m_forceRepaintAsyncCallbackID = 0;
277    }
278
279    return didSync;
280}
281
282void CoordinatedLayerTreeHost::clearPendingStateChanges()
283{
284    m_state.layersToCreate.clear();
285    m_state.layersToUpdate.clear();
286    m_state.layersToRemove.clear();
287
288    m_state.imagesToCreate.clear();
289    m_state.imagesToRemove.clear();
290    m_state.imagesToUpdate.clear();
291    m_state.imagesToClear.clear();
292
293    m_state.updateAtlasesToCreate.clear();
294    m_state.updateAtlasesToRemove.clear();
295
296#if ENABLE(CSS_SHADERS)
297    m_state.customFiltersToCreate.clear();
298    m_state.customFiltersToRemove.clear();
299#endif
300}
301
302void CoordinatedLayerTreeHost::initializeRootCompositingLayerIfNeeded()
303{
304    if (m_didInitializeRootCompositingLayer)
305        return;
306
307    m_state.rootCompositingLayer = toCoordinatedGraphicsLayer(m_rootLayer.get())->id();
308    m_didInitializeRootCompositingLayer = true;
309    m_shouldSyncFrame = true;
310}
311
312void CoordinatedLayerTreeHost::syncLayerState(CoordinatedLayerID id, CoordinatedGraphicsLayerState& state)
313{
314    m_shouldSyncFrame = true;
315
316#if ENABLE(CSS_SHADERS)
317    prepareCustomFilterProxiesIfNeeded(state);
318#endif
319
320    m_state.layersToUpdate.append(std::make_pair(id, state));
321}
322
323#if ENABLE(CSS_SHADERS)
324void CoordinatedLayerTreeHost::prepareCustomFilterProxiesIfNeeded(CoordinatedGraphicsLayerState& state)
325{
326    if (state.animationsChanged) {
327        GraphicsLayerAnimations& activeAnimations = state.animations;
328        for (size_t i = 0; i < activeAnimations.animations().size(); ++i) {
329            const KeyframeValueList& keyframes = activeAnimations.animations().at(i).keyframes();
330            if (keyframes.property() != AnimatedPropertyWebkitFilter)
331                continue;
332            for (size_t j = 0; j < keyframes.size(); ++j) {
333                const FilterAnimationValue& filterValue = static_cast<const FilterAnimationValue&>(keyframes.at(j));
334                checkCustomFilterProgramProxies(filterValue.value());
335            }
336        }
337    }
338
339    if (state.filtersChanged)
340        checkCustomFilterProgramProxies(state.filters);
341}
342
343void CoordinatedLayerTreeHost::checkCustomFilterProgramProxies(const FilterOperations& filters)
344{
345    // We need to create the WebCustomFilterProgramProxy objects before we get to serialize the
346    // custom filters to the other process. That's because WebCustomFilterProgramProxy needs
347    // to link back to the coordinator, so that we can send a message to the UI process when
348    // the program is not needed anymore.
349    // Note that the serialization will only happen at a later time in ArgumentCoder<WebCore::FilterOperations>::encode.
350    // At that point the program will only be serialized once. All the other times it will only use the ID of the program.
351    for (size_t i = 0; i < filters.size(); ++i) {
352        const FilterOperation* operation = filters.at(i);
353        if (operation->getOperationType() != FilterOperation::VALIDATED_CUSTOM)
354            continue;
355        const ValidatedCustomFilterOperation* customOperation = static_cast<const ValidatedCustomFilterOperation*>(operation);
356        ASSERT(customOperation->validatedProgram()->isInitialized());
357        TextureMapperPlatformCompiledProgram* program = customOperation->validatedProgram()->platformCompiledProgram();
358
359        RefPtr<WebCustomFilterProgramProxy> customFilterProgramProxy;
360        if (program->client())
361            customFilterProgramProxy = static_cast<WebCustomFilterProgramProxy*>(program->client());
362        else {
363            customFilterProgramProxy = WebCustomFilterProgramProxy::create();
364            program->setClient(customFilterProgramProxy);
365        }
366
367        if (!customFilterProgramProxy->client()) {
368            customFilterProgramProxy->setClient(this);
369            m_customFilterPrograms.add(customFilterProgramProxy.get());
370            m_state.customFiltersToCreate.append(std::make_pair(customFilterProgramProxy->id(), customOperation->validatedProgram()->validatedProgramInfo()));
371        } else {
372            // If the client was not disconnected then this coordinator must be the client for it.
373            ASSERT(customFilterProgramProxy->client() == this);
374        }
375    }
376}
377
378void CoordinatedLayerTreeHost::removeCustomFilterProgramProxy(WebCustomFilterProgramProxy* customFilterProgramProxy)
379{
380    // At this time the shader is not needed anymore, so we remove it from our set and
381    // send a message to the other process to delete it.
382    m_customFilterPrograms.remove(customFilterProgramProxy);
383    m_state.customFiltersToRemove.append(customFilterProgramProxy->id());
384}
385
386void CoordinatedLayerTreeHost::disconnectCustomFilterPrograms()
387{
388    // Make sure that WebCore will not call into this coordinator anymore.
389    HashSet<WebCustomFilterProgramProxy*>::iterator iter = m_customFilterPrograms.begin();
390    for (; iter != m_customFilterPrograms.end(); ++iter)
391        (*iter)->setClient(0);
392}
393#endif // ENABLE(CSS_SHADERS)
394
395void CoordinatedLayerTreeHost::detachLayer(CoordinatedGraphicsLayer* layer)
396{
397    m_registeredLayers.remove(layer->id());
398
399    size_t index = m_state.layersToCreate.find(layer->id());
400    if (index != notFound) {
401        m_state.layersToCreate.remove(index);
402        return;
403    }
404
405    m_state.layersToRemove.append(layer->id());
406    scheduleLayerFlush();
407}
408
409void CoordinatedLayerTreeHost::performScheduledLayerFlush()
410{
411    if (m_isSuspended || m_waitingForUIProcess)
412        return;
413
414    syncDisplayState();
415
416    if (!m_isValid)
417        return;
418
419    if (flushPendingLayerChanges())
420        didPerformScheduledLayerFlush();
421}
422
423void CoordinatedLayerTreeHost::syncDisplayState()
424{
425#if ENABLE(INSPECTOR)
426    m_webPage->corePage()->inspectorController()->didBeginFrame();
427#endif
428
429#if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) && !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
430    // Make sure that any previously registered animation callbacks are being executed before we flush the layers.
431    m_lastAnimationServiceTime = WTF::monotonicallyIncreasingTime();
432    m_webPage->corePage()->mainFrame()->view()->serviceScriptedAnimations(m_lastAnimationServiceTime);
433#endif
434
435    m_webPage->layoutIfNeeded();
436}
437
438void CoordinatedLayerTreeHost::didPerformScheduledLayerFlush()
439{
440    if (m_notifyAfterScheduledLayerFlush) {
441        static_cast<DrawingAreaImpl*>(m_webPage->drawingArea())->layerHostDidFlushLayers();
442        m_notifyAfterScheduledLayerFlush = false;
443    }
444}
445
446void CoordinatedLayerTreeHost::layerFlushTimerFired(Timer<CoordinatedLayerTreeHost>*)
447{
448    performScheduledLayerFlush();
449}
450
451void CoordinatedLayerTreeHost::createPageOverlayLayer()
452{
453    ASSERT(!m_pageOverlayLayer);
454
455    m_pageOverlayLayer = GraphicsLayer::create(this, this);
456#ifndef NDEBUG
457    m_pageOverlayLayer->setName("CoordinatedLayerTreeHost page overlay content");
458#endif
459
460    m_pageOverlayLayer->setDrawsContent(true);
461    m_pageOverlayLayer->setSize(m_webPage->size());
462
463    m_rootLayer->addChild(m_pageOverlayLayer.get());
464}
465
466void CoordinatedLayerTreeHost::destroyPageOverlayLayer()
467{
468    ASSERT(m_pageOverlayLayer);
469    m_pageOverlayLayer->removeFromParent();
470    m_pageOverlayLayer = nullptr;
471}
472
473PassRefPtr<CoordinatedImageBacking> CoordinatedLayerTreeHost::createImageBackingIfNeeded(Image* image)
474{
475    CoordinatedImageBackingID imageID = CoordinatedImageBacking::getCoordinatedImageBackingID(image);
476    ImageBackingMap::iterator it = m_imageBackings.find(imageID);
477    RefPtr<CoordinatedImageBacking> imageBacking;
478    if (it == m_imageBackings.end()) {
479        imageBacking = CoordinatedImageBacking::create(this, image);
480        m_imageBackings.add(imageID, imageBacking);
481    } else
482        imageBacking = it->value;
483
484    return imageBacking;
485}
486
487void CoordinatedLayerTreeHost::createImageBacking(CoordinatedImageBackingID imageID)
488{
489    m_state.imagesToCreate.append(imageID);
490}
491
492void CoordinatedLayerTreeHost::updateImageBacking(CoordinatedImageBackingID imageID, PassRefPtr<CoordinatedSurface> coordinatedSurface)
493{
494    m_shouldSyncFrame = true;
495    m_state.imagesToUpdate.append(std::make_pair(imageID, coordinatedSurface));
496}
497
498void CoordinatedLayerTreeHost::clearImageBackingContents(CoordinatedImageBackingID imageID)
499{
500    m_shouldSyncFrame = true;
501    m_state.imagesToClear.append(imageID);
502}
503
504void CoordinatedLayerTreeHost::removeImageBacking(CoordinatedImageBackingID imageID)
505{
506    if (m_isPurging)
507        return;
508
509    ASSERT(m_imageBackings.contains(imageID));
510    m_imageBackings.remove(imageID);
511
512    m_state.imagesToRemove.append(imageID);
513}
514
515void CoordinatedLayerTreeHost::flushPendingImageBackingChanges()
516{
517    ImageBackingMap::iterator end = m_imageBackings.end();
518    for (ImageBackingMap::iterator iter = m_imageBackings.begin(); iter != end; ++iter)
519        iter->value->update();
520}
521
522void CoordinatedLayerTreeHost::notifyAnimationStarted(const WebCore::GraphicsLayer*, double /* time */)
523{
524}
525
526void CoordinatedLayerTreeHost::notifyFlushRequired(const WebCore::GraphicsLayer*)
527{
528    scheduleLayerFlush();
529}
530
531void CoordinatedLayerTreeHost::paintContents(const WebCore::GraphicsLayer* graphicsLayer, WebCore::GraphicsContext& graphicsContext, WebCore::GraphicsLayerPaintingPhase, const WebCore::IntRect& clipRect)
532{
533    if (graphicsLayer == m_pageOverlayLayer) {
534        // Overlays contain transparent contents and won't clear the context as part of their rendering, so we do it here.
535        graphicsContext.clearRect(clipRect);
536        m_webPage->drawPageOverlay(m_pageOverlay.get(), graphicsContext, clipRect);
537        return;
538    }
539}
540
541PassOwnPtr<GraphicsLayer> CoordinatedLayerTreeHost::createGraphicsLayer(GraphicsLayerClient* client)
542{
543    CoordinatedGraphicsLayer* layer = new CoordinatedGraphicsLayer(client);
544    layer->setCoordinator(this);
545    m_registeredLayers.add(layer->id(), layer);
546    m_state.layersToCreate.append(layer->id());
547    layer->setNeedsVisibleRectAdjustment();
548    scheduleLayerFlush();
549    return adoptPtr(layer);
550}
551
552PassRefPtr<CoordinatedSurface> CoordinatedLayerTreeHost::createCoordinatedSurface(const IntSize& size, CoordinatedSurface::Flags flags)
553{
554    return WebCoordinatedSurface::create(size, flags);
555}
556
557float CoordinatedLayerTreeHost::deviceScaleFactor() const
558{
559    return m_webPage->deviceScaleFactor();
560}
561
562float CoordinatedLayerTreeHost::pageScaleFactor() const
563{
564    return m_webPage->pageScaleFactor();
565}
566
567bool LayerTreeHost::supportsAcceleratedCompositing()
568{
569    return true;
570}
571
572void CoordinatedLayerTreeHost::createUpdateAtlas(uint32_t atlasID, PassRefPtr<CoordinatedSurface> coordinatedSurface)
573{
574    m_state.updateAtlasesToCreate.append(std::make_pair(atlasID, coordinatedSurface));
575}
576
577void CoordinatedLayerTreeHost::removeUpdateAtlas(uint32_t atlasID)
578{
579    if (m_isPurging)
580        return;
581    m_state.updateAtlasesToRemove.append(atlasID);
582}
583
584WebCore::FloatRect CoordinatedLayerTreeHost::visibleContentsRect() const
585{
586    return m_visibleContentsRect;
587}
588
589CoordinatedGraphicsLayer* CoordinatedLayerTreeHost::mainContentsLayer()
590{
591    if (!m_rootCompositingLayer)
592        return 0;
593
594    return toCoordinatedGraphicsLayer(m_rootCompositingLayer)->findFirstDescendantWithContentsRecursively();
595}
596
597void CoordinatedLayerTreeHost::setVisibleContentsRect(const FloatRect& rect, const FloatPoint& trajectoryVector)
598{
599    // A zero trajectoryVector indicates that tiles all around the viewport are requested.
600    if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer())
601        contentsLayer->setVisibleContentRectTrajectoryVector(trajectoryVector);
602
603    bool contentsRectDidChange = rect != m_visibleContentsRect;
604    if (contentsRectDidChange) {
605        m_visibleContentsRect = rect;
606
607        LayerMap::iterator end = m_registeredLayers.end();
608        for (LayerMap::iterator it = m_registeredLayers.begin(); it != end; ++it) {
609            it->value->setNeedsVisibleRectAdjustment();
610        }
611    }
612
613    scheduleLayerFlush();
614    if (m_webPage->useFixedLayout()) {
615        // Round the rect instead of enclosing it to make sure that its size stays
616        // the same while panning. This can have nasty effects on layout.
617        m_webPage->setFixedVisibleContentRect(roundedIntRect(rect));
618    }
619}
620
621void CoordinatedLayerTreeHost::deviceOrPageScaleFactorChanged()
622{
623    m_rootLayer->deviceOrPageScaleFactorChanged();
624    if (m_pageOverlayLayer)
625        m_pageOverlayLayer->deviceOrPageScaleFactorChanged();
626}
627
628void CoordinatedLayerTreeHost::pageBackgroundTransparencyChanged()
629{
630}
631
632GraphicsLayerFactory* CoordinatedLayerTreeHost::graphicsLayerFactory()
633{
634    return this;
635}
636
637#if ENABLE(REQUEST_ANIMATION_FRAME)
638void CoordinatedLayerTreeHost::scheduleAnimation()
639{
640    if (m_waitingForUIProcess)
641        return;
642
643    if (m_layerFlushTimer.isActive())
644        return;
645
646    // According to the requestAnimationFrame spec, rAF callbacks should not be faster than 60FPS.
647    static const double MinimalTimeoutForAnimations = 1. / 60.;
648    m_layerFlushTimer.startOneShot(std::max<double>(0., MinimalTimeoutForAnimations - WTF::monotonicallyIncreasingTime() + m_lastAnimationServiceTime));
649    scheduleLayerFlush();
650}
651#endif
652
653void CoordinatedLayerTreeHost::renderNextFrame()
654{
655    m_waitingForUIProcess = false;
656    scheduleLayerFlush();
657    for (unsigned i = 0; i < m_updateAtlases.size(); ++i)
658        m_updateAtlases[i]->didSwapBuffers();
659}
660
661void CoordinatedLayerTreeHost::purgeBackingStores()
662{
663    TemporaryChange<bool> purgingToggle(m_isPurging, true);
664
665    LayerMap::iterator end = m_registeredLayers.end();
666    for (LayerMap::iterator it = m_registeredLayers.begin(); it != end; ++it)
667        it->value->purgeBackingStores();
668
669    m_imageBackings.clear();
670    m_updateAtlases.clear();
671}
672
673bool CoordinatedLayerTreeHost::paintToSurface(const IntSize& size, CoordinatedSurface::Flags flags, uint32_t& atlasID, IntPoint& offset, CoordinatedSurface::Client* client)
674{
675    for (unsigned i = 0; i < m_updateAtlases.size(); ++i) {
676        UpdateAtlas* atlas = m_updateAtlases[i].get();
677        if (atlas->supportsAlpha() == (flags & CoordinatedSurface::SupportsAlpha)) {
678            // This will false if there is no available buffer space.
679            if (atlas->paintOnAvailableBuffer(size, atlasID, offset, client))
680                return true;
681        }
682    }
683
684    static const int ScratchBufferDimension = 1024; // Should be a power of two.
685    m_updateAtlases.append(adoptPtr(new UpdateAtlas(this, ScratchBufferDimension, flags)));
686    scheduleReleaseInactiveAtlases();
687    return m_updateAtlases.last()->paintOnAvailableBuffer(size, atlasID, offset, client);
688}
689
690const double ReleaseInactiveAtlasesTimerInterval = 0.5;
691
692void CoordinatedLayerTreeHost::scheduleReleaseInactiveAtlases()
693{
694    if (!m_releaseInactiveAtlasesTimer.isActive())
695        m_releaseInactiveAtlasesTimer.startRepeating(ReleaseInactiveAtlasesTimerInterval);
696}
697
698void CoordinatedLayerTreeHost::releaseInactiveAtlasesTimerFired(Timer<CoordinatedLayerTreeHost>*)
699{
700    // We always want to keep one atlas for non-composited content.
701    OwnPtr<UpdateAtlas> atlasToKeepAnyway;
702    bool foundActiveAtlasForNonCompositedContent = false;
703    for (int i = m_updateAtlases.size() - 1;  i >= 0; --i) {
704        UpdateAtlas* atlas = m_updateAtlases[i].get();
705        if (!atlas->isInUse())
706            atlas->addTimeInactive(ReleaseInactiveAtlasesTimerInterval);
707        bool usableForNonCompositedContent = !atlas->supportsAlpha();
708        if (atlas->isInactive()) {
709            if (!foundActiveAtlasForNonCompositedContent && !atlasToKeepAnyway && usableForNonCompositedContent)
710                atlasToKeepAnyway = m_updateAtlases[i].release();
711            m_updateAtlases.remove(i);
712        } else if (usableForNonCompositedContent)
713            foundActiveAtlasForNonCompositedContent = true;
714    }
715
716    if (!foundActiveAtlasForNonCompositedContent && atlasToKeepAnyway)
717        m_updateAtlases.append(atlasToKeepAnyway.release());
718
719    if (m_updateAtlases.size() <= 1)
720        m_releaseInactiveAtlasesTimer.stop();
721}
722
723void CoordinatedLayerTreeHost::setBackgroundColor(const WebCore::Color& color)
724{
725    m_webPage->send(Messages::CoordinatedLayerTreeHostProxy::SetBackgroundColor(color));
726}
727
728void CoordinatedLayerTreeHost::commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset)
729{
730    LayerMap::iterator i = m_registeredLayers.find(layerID);
731    if (i == m_registeredLayers.end())
732        return;
733
734    i->value->commitScrollOffset(offset);
735}
736
737} // namespace WebKit
738#endif // USE(COORDINATED_GRAPHICS)
739