Stop using PassRefPtr in platform/graphics
[WebKit-https.git] / Source / WebKit2 / Shared / CoordinatedGraphics / CoordinatedGraphicsScene.cpp
1 /*
2     Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
3     Copyright (C) 2012 Company 100, Inc.
4     Copyright (C) 2017 Sony Interactive Entertainment Inc.
5
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Library General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Library General Public License for more details.
15
16     You should have received a copy of the GNU Library General Public License
17     along with this library; see the file COPYING.LIB.  If not, write to
18     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19     Boston, MA 02110-1301, USA.
20 */
21
22 #include "config.h"
23
24 #if USE(COORDINATED_GRAPHICS)
25 #include "CoordinatedGraphicsScene.h"
26
27 #include "CoordinatedBackingStore.h"
28 #include <WebCore/TextureMapper.h>
29 #include <WebCore/TextureMapperBackingStore.h>
30 #include <WebCore/TextureMapperGL.h>
31 #include <WebCore/TextureMapperLayer.h>
32 #include <wtf/Atomics.h>
33
34 using namespace WebCore;
35
36 namespace WebKit {
37
38 void CoordinatedGraphicsScene::dispatchOnMainThread(Function<void()>&& function)
39 {
40     if (isMainThread()) {
41         function();
42         return;
43     }
44
45     RunLoop::main().dispatch([protectedThis = makeRef(*this), function = WTFMove(function)] {
46         function();
47     });
48 }
49
50 void CoordinatedGraphicsScene::dispatchOnClientRunLoop(Function<void()>&& function)
51 {
52     if (&m_clientRunLoop == &RunLoop::current()) {
53         function();
54         return;
55     }
56
57     m_clientRunLoop.dispatch([protectedThis = makeRef(*this), function = WTFMove(function)] {
58         function();
59     });
60 }
61
62 static bool layerShouldHaveBackingStore(TextureMapperLayer* layer)
63 {
64     return layer->drawsContent() && layer->contentsAreVisible() && !layer->size().isEmpty();
65 }
66
67 CoordinatedGraphicsScene::CoordinatedGraphicsScene(CoordinatedGraphicsSceneClient* client)
68     : m_client(client)
69     , m_isActive(false)
70     , m_rootLayerID(InvalidCoordinatedLayerID)
71     , m_viewBackgroundColor(Color::white)
72     , m_clientRunLoop(RunLoop::current())
73 {
74 }
75
76 CoordinatedGraphicsScene::~CoordinatedGraphicsScene()
77 {
78 }
79
80 void CoordinatedGraphicsScene::paintToCurrentGLContext(const TransformationMatrix& matrix, float opacity, const FloatRect& clipRect, const Color& backgroundColor, bool drawsBackground, const FloatPoint& contentPosition, TextureMapper::PaintFlags PaintFlags)
81 {
82     if (!m_textureMapper) {
83         m_textureMapper = TextureMapper::create();
84         static_cast<TextureMapperGL*>(m_textureMapper.get())->setEnableEdgeDistanceAntialiasing(true);
85     }
86
87     syncRemoteContent();
88
89     adjustPositionForFixedLayers(contentPosition);
90     TextureMapperLayer* currentRootLayer = rootLayer();
91     if (!currentRootLayer)
92         return;
93
94 #if USE(COORDINATED_GRAPHICS_THREADED)
95     for (auto& proxy : m_platformLayerProxies.values())
96         proxy->swapBuffer();
97 #endif
98
99     currentRootLayer->setTextureMapper(m_textureMapper.get());
100     currentRootLayer->applyAnimationsRecursively();
101     m_textureMapper->beginPainting(PaintFlags);
102     m_textureMapper->beginClip(TransformationMatrix(), clipRect);
103
104     if (drawsBackground) {
105         RGBA32 rgba = makeRGBA32FromFloats(backgroundColor.red(),
106             backgroundColor.green(), backgroundColor.blue(),
107             backgroundColor.alpha() * opacity);
108         m_textureMapper->drawSolidColor(clipRect, TransformationMatrix(), Color(rgba));
109     } else {
110         GraphicsContext3D* context = static_cast<TextureMapperGL*>(m_textureMapper.get())->graphicsContext3D();
111         context->clearColor(m_viewBackgroundColor.red() / 255.0f, m_viewBackgroundColor.green() / 255.0f, m_viewBackgroundColor.blue() / 255.0f, m_viewBackgroundColor.alpha() / 255.0f);
112         context->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
113     }
114
115     if (currentRootLayer->opacity() != opacity || currentRootLayer->transform() != matrix) {
116         currentRootLayer->setOpacity(opacity);
117         currentRootLayer->setTransform(matrix);
118     }
119
120     currentRootLayer->paint();
121     m_fpsCounter.updateFPSAndDisplay(*m_textureMapper, clipRect.location(), matrix);
122     m_textureMapper->endClip();
123     m_textureMapper->endPainting();
124
125     if (currentRootLayer->descendantsOrSelfHaveRunningAnimations())
126         updateViewport();
127 }
128
129 void CoordinatedGraphicsScene::updateViewport()
130 {
131     if (m_client)
132         m_client->updateViewport();
133 }
134
135 void CoordinatedGraphicsScene::adjustPositionForFixedLayers(const FloatPoint& contentPosition)
136 {
137     if (m_fixedLayers.isEmpty())
138         return;
139
140     // Fixed layer positions are updated by the web process when we update the visible contents rect / scroll position.
141     // If we want those layers to follow accurately the viewport when we move between the web process updates, we have to offset
142     // them by the delta between the current position and the position of the viewport used for the last layout.
143     FloatSize delta = contentPosition - m_renderedContentsScrollPosition;
144
145     for (auto& fixedLayer : m_fixedLayers.values())
146         fixedLayer->setScrollPositionDeltaIfNeeded(delta);
147 }
148
149 void CoordinatedGraphicsScene::syncPlatformLayerIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state)
150 {
151 #if USE(COORDINATED_GRAPHICS_THREADED)
152     if (!state.platformLayerChanged)
153         return;
154
155     if (state.platformLayerProxy) {
156         m_platformLayerProxies.set(layer, state.platformLayerProxy);
157         state.platformLayerProxy->activateOnCompositingThread(this, layer);
158     } else
159         m_platformLayerProxies.remove(layer);
160 #else
161     UNUSED_PARAM(layer);
162     UNUSED_PARAM(state);
163 #endif
164 }
165
166 #if USE(COORDINATED_GRAPHICS_THREADED)
167 void CoordinatedGraphicsScene::onNewBufferAvailable()
168 {
169     updateViewport();
170 }
171 #endif
172
173 void CoordinatedGraphicsScene::setLayerRepaintCountIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state)
174 {
175     if (!layer->isShowingRepaintCounter() || !state.repaintCountChanged)
176         return;
177
178     layer->setRepaintCount(state.repaintCount);
179 }
180
181 void CoordinatedGraphicsScene::setLayerChildrenIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state)
182 {
183     if (!state.childrenChanged)
184         return;
185
186     Vector<TextureMapperLayer*> children;
187     children.reserveCapacity(state.children.size());
188     for (auto& child : state.children)
189         children.append(layerByID(child));
190
191     layer->setChildren(children);
192 }
193
194 void CoordinatedGraphicsScene::setLayerFiltersIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state)
195 {
196     if (!state.filtersChanged)
197         return;
198
199     layer->setFilters(state.filters);
200 }
201
202 void CoordinatedGraphicsScene::setLayerState(CoordinatedLayerID id, const CoordinatedGraphicsLayerState& layerState)
203 {
204     ASSERT(m_rootLayerID != InvalidCoordinatedLayerID);
205     TextureMapperLayer* layer = layerByID(id);
206
207     if (layerState.positionChanged)
208         layer->setPosition(layerState.pos);
209
210     if (layerState.anchorPointChanged)
211         layer->setAnchorPoint(layerState.anchorPoint);
212
213     if (layerState.sizeChanged)
214         layer->setSize(layerState.size);
215
216     if (layerState.transformChanged)
217         layer->setTransform(layerState.transform);
218
219     if (layerState.childrenTransformChanged)
220         layer->setChildrenTransform(layerState.childrenTransform);
221
222     if (layerState.contentsRectChanged)
223         layer->setContentsRect(layerState.contentsRect);
224
225     if (layerState.contentsTilingChanged) {
226         layer->setContentsTilePhase(layerState.contentsTilePhase);
227         layer->setContentsTileSize(layerState.contentsTileSize);
228     }
229
230     if (layerState.opacityChanged)
231         layer->setOpacity(layerState.opacity);
232
233     if (layerState.solidColorChanged)
234         layer->setSolidColor(layerState.solidColor);
235
236     if (layerState.debugVisualsChanged)
237         layer->setDebugVisuals(layerState.debugVisuals.showDebugBorders, layerState.debugVisuals.debugBorderColor, layerState.debugVisuals.debugBorderWidth, layerState.debugVisuals.showRepaintCounter);
238
239     if (layerState.replicaChanged)
240         layer->setReplicaLayer(getLayerByIDIfExists(layerState.replica));
241
242     if (layerState.maskChanged)
243         layer->setMaskLayer(getLayerByIDIfExists(layerState.mask));
244
245     if (layerState.imageChanged)
246         assignImageBackingToLayer(layer, layerState.imageID);
247
248     if (layerState.flagsChanged) {
249         layer->setContentsOpaque(layerState.contentsOpaque);
250         layer->setDrawsContent(layerState.drawsContent);
251         layer->setContentsVisible(layerState.contentsVisible);
252         layer->setBackfaceVisibility(layerState.backfaceVisible);
253
254         // Never clip the root layer.
255         layer->setMasksToBounds(id == m_rootLayerID ? false : layerState.masksToBounds);
256         layer->setPreserves3D(layerState.preserves3D);
257
258         bool fixedToViewportChanged = layer->fixedToViewport() != layerState.fixedToViewport;
259         layer->setFixedToViewport(layerState.fixedToViewport);
260         if (fixedToViewportChanged) {
261             if (layerState.fixedToViewport)
262                 m_fixedLayers.add(id, layer);
263             else
264                 m_fixedLayers.remove(id);
265         }
266
267         layer->setIsScrollable(layerState.isScrollable);
268     }
269
270     if (layerState.committedScrollOffsetChanged)
271         layer->didCommitScrollOffset(layerState.committedScrollOffset);
272
273     prepareContentBackingStore(layer);
274
275     // Apply Operations.
276     setLayerChildrenIfNeeded(layer, layerState);
277     createTilesIfNeeded(layer, layerState);
278     removeTilesIfNeeded(layer, layerState);
279     updateTilesIfNeeded(layer, layerState);
280     setLayerFiltersIfNeeded(layer, layerState);
281     setLayerAnimationsIfNeeded(layer, layerState);
282     syncPlatformLayerIfNeeded(layer, layerState);
283     setLayerRepaintCountIfNeeded(layer, layerState);
284 }
285
286 TextureMapperLayer* CoordinatedGraphicsScene::getLayerByIDIfExists(CoordinatedLayerID id)
287 {
288     return (id != InvalidCoordinatedLayerID) ? layerByID(id) : 0;
289 }
290
291 void CoordinatedGraphicsScene::createLayers(const Vector<CoordinatedLayerID>& layerIDs)
292 {
293     for (auto& layerID : layerIDs)
294         createLayer(layerID);
295 }
296
297 void CoordinatedGraphicsScene::createLayer(CoordinatedLayerID id)
298 {
299     std::unique_ptr<TextureMapperLayer> newLayer = std::make_unique<TextureMapperLayer>();
300     newLayer->setID(id);
301     newLayer->setScrollClient(this);
302     m_layers.add(id, WTFMove(newLayer));
303 }
304
305 void CoordinatedGraphicsScene::deleteLayers(const Vector<CoordinatedLayerID>& layerIDs)
306 {
307     for (auto& layerID : layerIDs)
308         deleteLayer(layerID);
309 }
310
311 void CoordinatedGraphicsScene::deleteLayer(CoordinatedLayerID layerID)
312 {
313     std::unique_ptr<TextureMapperLayer> layer = m_layers.take(layerID);
314     ASSERT(layer);
315
316     m_backingStores.remove(layer.get());
317     m_fixedLayers.remove(layerID);
318 #if USE(COORDINATED_GRAPHICS_THREADED)
319     if (auto platformLayerProxy = m_platformLayerProxies.take(layer.get()))
320         platformLayerProxy->invalidate();
321 #endif
322 }
323
324 void CoordinatedGraphicsScene::setRootLayerID(CoordinatedLayerID layerID)
325 {
326     ASSERT(layerID != InvalidCoordinatedLayerID);
327     ASSERT(m_rootLayerID == InvalidCoordinatedLayerID);
328
329     m_rootLayerID = layerID;
330
331     TextureMapperLayer* layer = layerByID(layerID);
332     ASSERT(m_rootLayer->children().isEmpty());
333     m_rootLayer->addChild(layer);
334 }
335
336 void CoordinatedGraphicsScene::prepareContentBackingStore(TextureMapperLayer* layer)
337 {
338     if (!layerShouldHaveBackingStore(layer)) {
339         removeBackingStoreIfNeeded(layer);
340         return;
341     }
342
343     createBackingStoreIfNeeded(layer);
344     resetBackingStoreSizeToLayerSize(layer);
345 }
346
347 void CoordinatedGraphicsScene::createBackingStoreIfNeeded(TextureMapperLayer* layer)
348 {
349     if (m_backingStores.contains(layer))
350         return;
351
352     auto backingStore = CoordinatedBackingStore::create();
353     m_backingStores.add(layer, backingStore.copyRef());
354     layer->setBackingStore(WTFMove(backingStore));
355 }
356
357 void CoordinatedGraphicsScene::removeBackingStoreIfNeeded(TextureMapperLayer* layer)
358 {
359     RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.take(layer);
360     if (!backingStore)
361         return;
362
363     layer->setBackingStore(nullptr);
364 }
365
366 void CoordinatedGraphicsScene::resetBackingStoreSizeToLayerSize(TextureMapperLayer* layer)
367 {
368     RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer);
369     ASSERT(backingStore);
370     backingStore->setSize(layer->size());
371     m_backingStoresWithPendingBuffers.add(backingStore);
372 }
373
374 void CoordinatedGraphicsScene::createTilesIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state)
375 {
376     if (state.tilesToCreate.isEmpty())
377         return;
378
379     RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer);
380     ASSERT(backingStore || !layerShouldHaveBackingStore(layer));
381     if (!backingStore)
382         return;
383
384     for (auto& tile : state.tilesToCreate)
385         backingStore->createTile(tile.tileID, tile.scale);
386 }
387
388 void CoordinatedGraphicsScene::removeTilesIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state)
389 {
390     if (state.tilesToRemove.isEmpty())
391         return;
392
393     RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer);
394     if (!backingStore)
395         return;
396
397     for (auto& tile : state.tilesToRemove)
398         backingStore->removeTile(tile);
399
400     m_backingStoresWithPendingBuffers.add(backingStore);
401 }
402
403 void CoordinatedGraphicsScene::updateTilesIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state)
404 {
405     if (state.tilesToUpdate.isEmpty())
406         return;
407
408     RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer);
409     ASSERT(backingStore || !layerShouldHaveBackingStore(layer));
410     if (!backingStore)
411         return;
412
413     for (auto& tile : state.tilesToUpdate) {
414         const SurfaceUpdateInfo& surfaceUpdateInfo = tile.updateInfo;
415
416         SurfaceMap::iterator surfaceIt = m_surfaces.find(surfaceUpdateInfo.atlasID);
417         ASSERT(surfaceIt != m_surfaces.end());
418
419         backingStore->updateTile(tile.tileID, surfaceUpdateInfo.updateRect, tile.tileRect, surfaceIt->value, surfaceUpdateInfo.surfaceOffset);
420         m_backingStoresWithPendingBuffers.add(backingStore);
421     }
422 }
423
424 void CoordinatedGraphicsScene::syncUpdateAtlases(const CoordinatedGraphicsState& state)
425 {
426     for (auto& atlas : state.updateAtlasesToCreate)
427         createUpdateAtlas(atlas.first, atlas.second);
428 }
429
430 void CoordinatedGraphicsScene::createUpdateAtlas(uint32_t atlasID, PassRefPtr<CoordinatedSurface> surface)
431 {
432     ASSERT(!m_surfaces.contains(atlasID));
433     m_surfaces.add(atlasID, surface);
434 }
435
436 void CoordinatedGraphicsScene::removeUpdateAtlas(uint32_t atlasID)
437 {
438     ASSERT(m_surfaces.contains(atlasID));
439     m_surfaces.remove(atlasID);
440 }
441
442 void CoordinatedGraphicsScene::releaseUpdateAtlases(const Vector<uint32_t>& atlasesToRemove)
443 {
444     for (auto& atlas : atlasesToRemove)
445         removeUpdateAtlas(atlas);
446 }
447
448 void CoordinatedGraphicsScene::syncImageBackings(const CoordinatedGraphicsState& state)
449 {
450     for (auto& image : state.imagesToRemove)
451         removeImageBacking(image);
452
453     for (auto& image : state.imagesToCreate)
454         createImageBacking(image);
455
456     for (auto& image : state.imagesToUpdate)
457         updateImageBacking(image.first, image.second);
458
459     for (auto& image : state.imagesToClear)
460         clearImageBackingContents(image);
461 }
462
463 void CoordinatedGraphicsScene::createImageBacking(CoordinatedImageBackingID imageID)
464 {
465     ASSERT(!m_imageBackings.contains(imageID));
466     RefPtr<CoordinatedBackingStore> backingStore(CoordinatedBackingStore::create());
467     m_imageBackings.add(imageID, backingStore.release());
468 }
469
470 void CoordinatedGraphicsScene::updateImageBacking(CoordinatedImageBackingID imageID, PassRefPtr<CoordinatedSurface> surface)
471 {
472     ASSERT(m_imageBackings.contains(imageID));
473     ImageBackingMap::iterator it = m_imageBackings.find(imageID);
474     RefPtr<CoordinatedBackingStore> backingStore = it->value;
475
476     // CoordinatedImageBacking is realized to CoordinatedBackingStore with only one tile in UI Process.
477     backingStore->createTile(1 /* id */, 1 /* scale */);
478     IntRect rect(IntPoint::zero(), surface->size());
479     // See CoordinatedGraphicsLayer::shouldDirectlyCompositeImage()
480     ASSERT(2000 >= std::max(rect.width(), rect.height()));
481     backingStore->setSize(rect.size());
482     backingStore->updateTile(1 /* id */, rect, rect, surface, rect.location());
483
484     m_backingStoresWithPendingBuffers.add(backingStore);
485 }
486
487 void CoordinatedGraphicsScene::clearImageBackingContents(CoordinatedImageBackingID imageID)
488 {
489     ASSERT(m_imageBackings.contains(imageID));
490     ImageBackingMap::iterator it = m_imageBackings.find(imageID);
491     RefPtr<CoordinatedBackingStore> backingStore = it->value;
492     backingStore->removeAllTiles();
493     m_backingStoresWithPendingBuffers.add(backingStore);
494 }
495
496 void CoordinatedGraphicsScene::removeImageBacking(CoordinatedImageBackingID imageID)
497 {
498     ASSERT(m_imageBackings.contains(imageID));
499
500     // We don't want TextureMapperLayer refers a dangling pointer.
501     m_releasedImageBackings.append(m_imageBackings.take(imageID));
502 }
503
504 void CoordinatedGraphicsScene::assignImageBackingToLayer(TextureMapperLayer* layer, CoordinatedImageBackingID imageID)
505 {
506     if (imageID == InvalidCoordinatedImageBackingID) {
507         layer->setContentsLayer(0);
508         return;
509     }
510
511     ImageBackingMap::iterator it = m_imageBackings.find(imageID);
512     ASSERT(it != m_imageBackings.end());
513     layer->setContentsLayer(it->value.get());
514 }
515
516 void CoordinatedGraphicsScene::removeReleasedImageBackingsIfNeeded()
517 {
518     m_releasedImageBackings.clear();
519 }
520
521 void CoordinatedGraphicsScene::commitPendingBackingStoreOperations()
522 {
523     for (auto& backingStore : m_backingStoresWithPendingBuffers)
524         backingStore->commitTileOperations(*m_textureMapper);
525
526     m_backingStoresWithPendingBuffers.clear();
527 }
528
529 void CoordinatedGraphicsScene::commitSceneState(const CoordinatedGraphicsState& state)
530 {
531     if (!m_client)
532         return;
533
534     m_renderedContentsScrollPosition = state.scrollPosition;
535
536     createLayers(state.layersToCreate);
537     deleteLayers(state.layersToRemove);
538
539     if (state.rootCompositingLayer != m_rootLayerID)
540         setRootLayerID(state.rootCompositingLayer);
541
542     syncImageBackings(state);
543     syncUpdateAtlases(state);
544
545     for (auto& layer : state.layersToUpdate)
546         setLayerState(layer.first, layer.second);
547
548     commitPendingBackingStoreOperations();
549     removeReleasedImageBackingsIfNeeded();
550 }
551
552 void CoordinatedGraphicsScene::renderNextFrame()
553 {
554     if (!m_client)
555         return;
556     dispatchOnMainThread([this] {
557         if (m_client)
558             m_client->renderNextFrame();
559     });
560 }
561
562 void CoordinatedGraphicsScene::ensureRootLayer()
563 {
564     if (m_rootLayer)
565         return;
566
567     m_rootLayer = std::make_unique<TextureMapperLayer>();
568     m_rootLayer->setMasksToBounds(false);
569     m_rootLayer->setDrawsContent(false);
570     m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0));
571
572     // The root layer should not have zero size, or it would be optimized out.
573     m_rootLayer->setSize(FloatSize(1.0, 1.0));
574
575     ASSERT(m_textureMapper);
576     m_rootLayer->setTextureMapper(m_textureMapper.get());
577 }
578
579 void CoordinatedGraphicsScene::syncRemoteContent()
580 {
581     // We enqueue messages and execute them during paint, as they require an active GL context.
582     ensureRootLayer();
583
584     Vector<std::function<void()>> renderQueue;
585     bool calledOnMainThread = WTF::isMainThread();
586     if (!calledOnMainThread)
587         m_renderQueueMutex.lock();
588     renderQueue = WTFMove(m_renderQueue);
589     if (!calledOnMainThread)
590         m_renderQueueMutex.unlock();
591
592     for (auto& function : renderQueue)
593         function();
594 }
595
596 void CoordinatedGraphicsScene::purgeGLResources()
597 {
598     ASSERT(!m_client);
599
600     m_imageBackings.clear();
601     m_releasedImageBackings.clear();
602 #if USE(COORDINATED_GRAPHICS_THREADED)
603     for (auto& proxy : m_platformLayerProxies.values())
604         proxy->invalidate();
605     m_platformLayerProxies.clear();
606 #endif
607     m_surfaces.clear();
608
609     m_rootLayer = nullptr;
610     m_rootLayerID = InvalidCoordinatedLayerID;
611     m_layers.clear();
612     m_fixedLayers.clear();
613     m_textureMapper = nullptr;
614     m_backingStores.clear();
615     m_backingStoresWithPendingBuffers.clear();
616 }
617
618 void CoordinatedGraphicsScene::commitScrollOffset(uint32_t layerID, const IntSize& offset)
619 {
620     if (!m_client)
621         return;
622     dispatchOnMainThread([this, layerID, offset] {
623         if (m_client)
624             m_client->commitScrollOffset(layerID, offset);
625     });
626 }
627
628 void CoordinatedGraphicsScene::setLayerAnimationsIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state)
629 {
630     if (!state.animationsChanged)
631         return;
632
633     layer->setAnimations(state.animations);
634 }
635
636 void CoordinatedGraphicsScene::detach()
637 {
638     ASSERT(isMainThread());
639     m_isActive = false;
640     m_client = nullptr;
641     LockHolder locker(m_renderQueueMutex);
642     m_renderQueue.clear();
643 }
644
645 void CoordinatedGraphicsScene::appendUpdate(std::function<void()>&& function)
646 {
647     if (!m_isActive)
648         return;
649
650     ASSERT(isMainThread());
651     LockHolder locker(m_renderQueueMutex);
652     m_renderQueue.append(WTFMove(function));
653 }
654
655 void CoordinatedGraphicsScene::setActive(bool active)
656 {
657     if (!m_client)
658         return;
659
660     if (m_isActive == active)
661         return;
662
663     // Have to clear render queue in both cases.
664     // If there are some updates in queue during activation then those updates are from previous instance of paint node
665     // and cannot be applied to the newly created instance.
666     m_renderQueue.clear();
667     m_isActive = active;
668     if (m_isActive)
669         renderNextFrame();
670 }
671
672 TextureMapperLayer* CoordinatedGraphicsScene::findScrollableContentsLayerAt(const FloatPoint& point)
673 {
674     return rootLayer() ? rootLayer()->findScrollableContentsLayerAt(point) : 0;
675 }
676
677 } // namespace WebKit
678
679 #endif // USE(COORDINATED_GRAPHICS)