Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / platform / graphics / texmap / coordinated / CompositingCoordinator.cpp
1 /*
2  * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
3  * Copyright (C) 2013 Company 100, Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28
29 #if USE(COORDINATED_GRAPHICS)
30
31 #include "CompositingCoordinator.h"
32
33 #include "FrameView.h"
34 #include "GraphicsContext.h"
35 #include "InspectorController.h"
36 #include "MainFrame.h"
37 #include "Page.h"
38 #include "Settings.h"
39 #include <wtf/CurrentTime.h>
40 #include <wtf/TemporaryChange.h>
41
42 // FIXME: Having this in the platform directory is a layering violation. This does not belong here.
43
44 namespace WebCore {
45
46 CompositingCoordinator::~CompositingCoordinator()
47 {
48     purgeBackingStores();
49
50     for (auto& registeredLayer : m_registeredLayers.values())
51         registeredLayer->setCoordinator(0);
52 }
53
54 CompositingCoordinator::CompositingCoordinator(Page* page, CompositingCoordinator::Client* client)
55     : m_page(page)
56     , m_client(client)
57     , m_rootCompositingLayer(0)
58     , m_isPurging(false)
59     , m_isFlushingLayerChanges(false)
60     , m_shouldSyncFrame(false)
61     , m_didInitializeRootCompositingLayer(false)
62     , m_releaseInactiveAtlasesTimer(*this, &CompositingCoordinator::releaseInactiveAtlasesTimerFired)
63 #if ENABLE(REQUEST_ANIMATION_FRAME)
64     , m_lastAnimationServiceTime(0)
65 #endif
66 {
67 }
68
69 void CompositingCoordinator::setRootCompositingLayer(GraphicsLayer* compositingLayer, GraphicsLayer* overlayLayer)
70 {
71     if (m_rootCompositingLayer)
72         m_rootCompositingLayer->removeFromParent();
73
74     m_rootCompositingLayer = compositingLayer;
75     if (m_rootCompositingLayer)
76         m_rootLayer->addChildAtIndex(m_rootCompositingLayer, 0);
77
78     if (overlayLayer)
79         m_rootLayer->addChild(overlayLayer);
80 }
81
82 void CompositingCoordinator::sizeDidChange(const IntSize& newSize)
83 {
84     m_rootLayer->setSize(newSize);
85     notifyFlushRequired(m_rootLayer.get());
86 }
87
88 bool CompositingCoordinator::flushPendingLayerChanges()
89 {
90     TemporaryChange<bool> protector(m_isFlushingLayerChanges, true);
91
92     initializeRootCompositingLayerIfNeeded();
93
94     m_rootLayer->flushCompositingStateForThisLayerOnly(m_page->mainFrame().view()->viewportIsStable());
95     m_client->didFlushRootLayer(m_visibleContentsRect);
96
97     bool didSync = m_page->mainFrame().view()->flushCompositingStateIncludingSubframes();
98
99     toCoordinatedGraphicsLayer(m_rootLayer.get())->updateContentBuffersIncludingSubLayers();
100     toCoordinatedGraphicsLayer(m_rootLayer.get())->syncPendingStateChangesIncludingSubLayers();
101
102     flushPendingImageBackingChanges();
103
104     if (m_shouldSyncFrame) {
105         didSync = true;
106
107         if (m_rootCompositingLayer) {
108             m_state.contentsSize = roundedIntSize(m_rootCompositingLayer->size());
109             if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer())
110                 m_state.coveredRect = contentsLayer->coverRect();
111         }
112         m_state.scrollPosition = m_visibleContentsRect.location();
113
114         m_client->commitSceneState(m_state);
115
116         clearPendingStateChanges();
117         m_shouldSyncFrame = false;
118     }
119
120     return didSync;
121 }
122
123 void CompositingCoordinator::syncDisplayState()
124 {
125 #if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) && !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
126     // Make sure that any previously registered animation callbacks are being executed before we flush the layers.
127     m_lastAnimationServiceTime = WTF::monotonicallyIncreasingTime();
128     m_page->mainFrame().view()->serviceScriptedAnimations(m_lastAnimationServiceTime);
129 #endif
130     m_page->mainFrame().view()->updateLayoutAndStyleIfNeededRecursive();
131 }
132
133 #if ENABLE(REQUEST_ANIMATION_FRAME)
134 double CompositingCoordinator::nextAnimationServiceTime() const
135 {
136     // According to the requestAnimationFrame spec, rAF callbacks should not be faster than 60FPS.
137     static const double MinimalTimeoutForAnimations = 1. / 60.;
138     return std::max<double>(0., MinimalTimeoutForAnimations - WTF::monotonicallyIncreasingTime() + m_lastAnimationServiceTime);
139 }
140 #endif
141
142 void CompositingCoordinator::clearPendingStateChanges()
143 {
144     m_state.layersToCreate.clear();
145     m_state.layersToUpdate.clear();
146     m_state.layersToRemove.clear();
147
148     m_state.imagesToCreate.clear();
149     m_state.imagesToRemove.clear();
150     m_state.imagesToUpdate.clear();
151     m_state.imagesToClear.clear();
152
153     m_state.updateAtlasesToCreate.clear();
154     m_state.updateAtlasesToRemove.clear();
155 }
156
157 void CompositingCoordinator::initializeRootCompositingLayerIfNeeded()
158 {
159     if (m_didInitializeRootCompositingLayer)
160         return;
161
162     m_state.rootCompositingLayer = toCoordinatedGraphicsLayer(m_rootLayer.get())->id();
163     m_didInitializeRootCompositingLayer = true;
164     m_shouldSyncFrame = true;
165 }
166
167 void CompositingCoordinator::createRootLayer(const IntSize& size)
168 {
169     ASSERT(!m_rootLayer);
170     // Create a root layer.
171     m_rootLayer = GraphicsLayer::create(this, *this);
172 #ifndef NDEBUG
173     m_rootLayer->setName("CompositingCoordinator root layer");
174 #endif
175     m_rootLayer->setDrawsContent(false);
176     m_rootLayer->setSize(size);
177 }
178
179 void CompositingCoordinator::syncLayerState(CoordinatedLayerID id, CoordinatedGraphicsLayerState& state)
180 {
181     m_shouldSyncFrame = true;
182     m_state.layersToUpdate.append(std::make_pair(id, state));
183 }
184
185 PassRefPtr<CoordinatedImageBacking> CompositingCoordinator::createImageBackingIfNeeded(Image* image)
186 {
187     CoordinatedImageBackingID imageID = CoordinatedImageBacking::getCoordinatedImageBackingID(image);
188     ImageBackingMap::iterator it = m_imageBackings.find(imageID);
189     RefPtr<CoordinatedImageBacking> imageBacking;
190     if (it == m_imageBackings.end()) {
191         imageBacking = CoordinatedImageBacking::create(this, image);
192         m_imageBackings.add(imageID, imageBacking);
193     } else
194         imageBacking = it->value;
195
196     return imageBacking;
197 }
198
199 void CompositingCoordinator::createImageBacking(CoordinatedImageBackingID imageID)
200 {
201     m_state.imagesToCreate.append(imageID);
202 }
203
204 void CompositingCoordinator::updateImageBacking(CoordinatedImageBackingID imageID, PassRefPtr<CoordinatedSurface> coordinatedSurface)
205 {
206     m_shouldSyncFrame = true;
207     m_state.imagesToUpdate.append(std::make_pair(imageID, coordinatedSurface));
208 }
209
210 void CompositingCoordinator::clearImageBackingContents(CoordinatedImageBackingID imageID)
211 {
212     m_shouldSyncFrame = true;
213     m_state.imagesToClear.append(imageID);
214 }
215
216 void CompositingCoordinator::removeImageBacking(CoordinatedImageBackingID imageID)
217 {
218     if (m_isPurging)
219         return;
220
221     ASSERT(m_imageBackings.contains(imageID));
222     m_imageBackings.remove(imageID);
223
224     m_state.imagesToRemove.append(imageID);
225
226     size_t imageIDPosition = m_state.imagesToClear.find(imageID);
227     if (imageIDPosition != notFound)
228         m_state.imagesToClear.remove(imageIDPosition);
229 }
230
231 void CompositingCoordinator::flushPendingImageBackingChanges()
232 {
233     for (auto& imageBacking : m_imageBackings.values())
234         imageBacking->update();
235 }
236
237 void CompositingCoordinator::notifyAnimationStarted(const GraphicsLayer*, const String&, double /* time */)
238 {
239 }
240
241 void CompositingCoordinator::notifyFlushRequired(const GraphicsLayer*)
242 {
243     if (!isFlushingLayerChanges())
244         m_client->notifyFlushRequired();
245 }
246
247
248 void CompositingCoordinator::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect& clipRect)
249 {
250     m_client->paintLayerContents(graphicsLayer, graphicsContext, enclosingIntRect(clipRect));
251 }
252
253 std::unique_ptr<GraphicsLayer> CompositingCoordinator::createGraphicsLayer(GraphicsLayer::Type layerType, GraphicsLayerClient& client)
254 {
255     CoordinatedGraphicsLayer* layer = new CoordinatedGraphicsLayer(layerType, client);
256     layer->setCoordinator(this);
257     m_registeredLayers.add(layer->id(), layer);
258     m_state.layersToCreate.append(layer->id());
259     layer->setNeedsVisibleRectAdjustment();
260     notifyFlushRequired(layer);
261     return std::unique_ptr<GraphicsLayer>(layer);
262 }
263
264 float CompositingCoordinator::deviceScaleFactor() const
265 {
266     return m_page->deviceScaleFactor();
267 }
268
269 float CompositingCoordinator::pageScaleFactor() const
270 {
271     return m_page->pageScaleFactor();
272 }
273
274 void CompositingCoordinator::createUpdateAtlas(uint32_t atlasID, PassRefPtr<CoordinatedSurface> coordinatedSurface)
275 {
276     m_state.updateAtlasesToCreate.append(std::make_pair(atlasID, coordinatedSurface));
277 }
278
279 void CompositingCoordinator::removeUpdateAtlas(uint32_t atlasID)
280 {
281     if (m_isPurging)
282         return;
283     m_state.updateAtlasesToRemove.append(atlasID);
284 }
285
286 FloatRect CompositingCoordinator::visibleContentsRect() const
287 {
288     return m_visibleContentsRect;
289 }
290
291 CoordinatedGraphicsLayer* CompositingCoordinator::mainContentsLayer()
292 {
293     if (!m_rootCompositingLayer)
294         return 0;
295
296     return toCoordinatedGraphicsLayer(m_rootCompositingLayer)->findFirstDescendantWithContentsRecursively();
297 }
298
299 void CompositingCoordinator::setVisibleContentsRect(const FloatRect& rect, const FloatPoint& trajectoryVector)
300 {
301     // A zero trajectoryVector indicates that tiles all around the viewport are requested.
302     if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer())
303         contentsLayer->setVisibleContentRectTrajectoryVector(trajectoryVector);
304
305     bool contentsRectDidChange = rect != m_visibleContentsRect;
306     if (contentsRectDidChange) {
307         m_visibleContentsRect = rect;
308
309         for (auto& registeredLayer : m_registeredLayers.values())
310             registeredLayer->setNeedsVisibleRectAdjustment();
311     }
312
313     FrameView* view = m_page->mainFrame().view();
314     if (view->useFixedLayout() && contentsRectDidChange) {
315         // Round the rect instead of enclosing it to make sure that its size stays
316         // the same while panning. This can have nasty effects on layout.
317         view->setFixedVisibleContentRect(roundedIntRect(rect));
318     }
319 }
320
321 void CompositingCoordinator::deviceOrPageScaleFactorChanged()
322 {
323     m_rootLayer->deviceOrPageScaleFactorChanged();
324 }
325
326 void CompositingCoordinator::detachLayer(CoordinatedGraphicsLayer* layer)
327 {
328     if (m_isPurging)
329         return;
330
331     m_registeredLayers.remove(layer->id());
332
333     size_t index = m_state.layersToCreate.find(layer->id());
334     if (index != notFound) {
335         m_state.layersToCreate.remove(index);
336         return;
337     }
338
339     m_state.layersToRemove.append(layer->id());
340     notifyFlushRequired(layer);
341 }
342
343 void CompositingCoordinator::commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset)
344 {
345     LayerMap::iterator i = m_registeredLayers.find(layerID);
346     if (i == m_registeredLayers.end())
347         return;
348
349     i->value->commitScrollOffset(offset);
350 }
351
352 void CompositingCoordinator::renderNextFrame()
353 {
354     for (auto& atlas : m_updateAtlases)
355         atlas->didSwapBuffers();
356 }
357
358 void CompositingCoordinator::purgeBackingStores()
359 {
360     TemporaryChange<bool> purgingToggle(m_isPurging, true);
361
362     for (auto& registeredLayer : m_registeredLayers.values())
363         registeredLayer->purgeBackingStores();
364
365     m_imageBackings.clear();
366     m_updateAtlases.clear();
367 }
368
369 bool CompositingCoordinator::paintToSurface(const IntSize& size, CoordinatedSurface::Flags flags, uint32_t& atlasID, IntPoint& offset, CoordinatedSurface::Client* client)
370 {
371     for (auto& updateAtlas : m_updateAtlases) {
372         UpdateAtlas* atlas = updateAtlas.get();
373         if (atlas->supportsAlpha() == (flags & CoordinatedSurface::SupportsAlpha)) {
374             // This will be false if there is no available buffer space.
375             if (atlas->paintOnAvailableBuffer(size, atlasID, offset, client))
376                 return true;
377         }
378     }
379
380     static const int ScratchBufferDimension = 1024; // Should be a power of two.
381     m_updateAtlases.append(std::make_unique<UpdateAtlas>(this, ScratchBufferDimension, flags));
382     scheduleReleaseInactiveAtlases();
383     return m_updateAtlases.last()->paintOnAvailableBuffer(size, atlasID, offset, client);
384 }
385
386 const double ReleaseInactiveAtlasesTimerInterval = 0.5;
387
388 void CompositingCoordinator::scheduleReleaseInactiveAtlases()
389 {
390     if (!m_releaseInactiveAtlasesTimer.isActive())
391         m_releaseInactiveAtlasesTimer.startRepeating(ReleaseInactiveAtlasesTimerInterval);
392 }
393
394 void CompositingCoordinator::releaseInactiveAtlasesTimerFired()
395 {
396     // We always want to keep one atlas for root contents layer.
397     std::unique_ptr<UpdateAtlas> atlasToKeepAnyway;
398     bool foundActiveAtlasForRootContentsLayer = false;
399     for (int i = m_updateAtlases.size() - 1;  i >= 0; --i) {
400         UpdateAtlas* atlas = m_updateAtlases[i].get();
401         if (!atlas->isInUse())
402             atlas->addTimeInactive(ReleaseInactiveAtlasesTimerInterval);
403         bool usableForRootContentsLayer = !atlas->supportsAlpha();
404         if (atlas->isInactive()) {
405             if (!foundActiveAtlasForRootContentsLayer && !atlasToKeepAnyway && usableForRootContentsLayer)
406                 atlasToKeepAnyway = WTFMove(m_updateAtlases[i]);
407             m_updateAtlases.remove(i);
408         } else if (usableForRootContentsLayer)
409             foundActiveAtlasForRootContentsLayer = true;
410     }
411
412     if (!foundActiveAtlasForRootContentsLayer && atlasToKeepAnyway)
413         m_updateAtlases.append(atlasToKeepAnyway.release());
414
415     if (m_updateAtlases.size() <= 1)
416         m_releaseInactiveAtlasesTimer.stop();
417 }
418
419 } // namespace WebCore
420
421 #endif // USE(COORDINATED_GRAPHICS)