Add WTF::move()
[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     LayerMap::iterator end = m_registeredLayers.end();
51     for (LayerMap::iterator it = m_registeredLayers.begin(); it != end; ++it)
52         it->value->setCoordinator(0);
53 }
54
55 CompositingCoordinator::CompositingCoordinator(Page* page, CompositingCoordinator::Client* client)
56     : m_page(page)
57     , m_client(client)
58     , m_rootCompositingLayer(0)
59     , m_isPurging(false)
60     , m_isFlushingLayerChanges(false)
61     , m_shouldSyncFrame(false)
62     , m_didInitializeRootCompositingLayer(false)
63     , m_releaseInactiveAtlasesTimer(this, &CompositingCoordinator::releaseInactiveAtlasesTimerFired)
64 #if ENABLE(REQUEST_ANIMATION_FRAME)
65     , m_lastAnimationServiceTime(0)
66 #endif
67 {
68     m_page->settings().setApplyDeviceScaleFactorInCompositor(true);
69
70     // This is a temporary way to enable this only in the GL case, until TextureMapperImageBuffer is removed.
71     // See https://bugs.webkit.org/show_bug.cgi?id=114869
72     CoordinatedGraphicsLayer::setShouldSupportContentsTiling(true);
73 }
74
75 void CompositingCoordinator::setRootCompositingLayer(GraphicsLayer* compositingLayer, GraphicsLayer* overlayLayer)
76 {
77     if (m_rootCompositingLayer)
78         m_rootCompositingLayer->removeFromParent();
79
80     m_rootCompositingLayer = compositingLayer;
81     if (m_rootCompositingLayer)
82         m_rootLayer->addChildAtIndex(m_rootCompositingLayer, 0);
83
84     if (overlayLayer)
85         m_rootLayer->addChild(overlayLayer);
86 }
87
88 void CompositingCoordinator::sizeDidChange(const IntSize& newSize)
89 {
90     m_rootLayer->setSize(newSize);
91     notifyFlushRequired(m_rootLayer.get());
92 }
93
94 bool CompositingCoordinator::flushPendingLayerChanges()
95 {
96     TemporaryChange<bool> protector(m_isFlushingLayerChanges, true);
97
98     initializeRootCompositingLayerIfNeeded();
99
100     m_rootLayer->flushCompositingStateForThisLayerOnly();
101     m_client->didFlushRootLayer(m_visibleContentsRect);
102
103     bool didSync = m_page->mainFrame().view()->flushCompositingStateIncludingSubframes();
104
105     toCoordinatedGraphicsLayer(m_rootLayer.get())->updateContentBuffersIncludingSubLayers();
106     toCoordinatedGraphicsLayer(m_rootLayer.get())->syncPendingStateChangesIncludingSubLayers();
107
108     flushPendingImageBackingChanges();
109
110     if (m_shouldSyncFrame) {
111         didSync = true;
112
113         if (m_rootCompositingLayer) {
114             m_state.contentsSize = roundedIntSize(m_rootCompositingLayer->size());
115             if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer())
116                 m_state.coveredRect = contentsLayer->coverRect();
117         }
118         m_state.scrollPosition = m_visibleContentsRect.location();
119
120         m_client->commitSceneState(m_state);
121
122         clearPendingStateChanges();
123         m_shouldSyncFrame = false;
124     }
125
126     return didSync;
127 }
128
129 void CompositingCoordinator::syncDisplayState()
130 {
131 #if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) && !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
132     // Make sure that any previously registered animation callbacks are being executed before we flush the layers.
133     m_lastAnimationServiceTime = WTF::monotonicallyIncreasingTime();
134     m_page->mainFrame().view()->serviceScriptedAnimations(m_lastAnimationServiceTime);
135 #endif
136     m_page->mainFrame().view()->updateLayoutAndStyleIfNeededRecursive();
137 }
138
139 #if ENABLE(REQUEST_ANIMATION_FRAME)
140 double CompositingCoordinator::nextAnimationServiceTime() const
141 {
142     // According to the requestAnimationFrame spec, rAF callbacks should not be faster than 60FPS.
143     static const double MinimalTimeoutForAnimations = 1. / 60.;
144     return std::max<double>(0., MinimalTimeoutForAnimations - WTF::monotonicallyIncreasingTime() + m_lastAnimationServiceTime);
145 }
146 #endif
147
148 void CompositingCoordinator::clearPendingStateChanges()
149 {
150     m_state.layersToCreate.clear();
151     m_state.layersToUpdate.clear();
152     m_state.layersToRemove.clear();
153
154     m_state.imagesToCreate.clear();
155     m_state.imagesToRemove.clear();
156     m_state.imagesToUpdate.clear();
157     m_state.imagesToClear.clear();
158
159     m_state.updateAtlasesToCreate.clear();
160     m_state.updateAtlasesToRemove.clear();
161 }
162
163 void CompositingCoordinator::initializeRootCompositingLayerIfNeeded()
164 {
165     if (m_didInitializeRootCompositingLayer)
166         return;
167
168     m_state.rootCompositingLayer = toCoordinatedGraphicsLayer(m_rootLayer.get())->id();
169     m_didInitializeRootCompositingLayer = true;
170     m_shouldSyncFrame = true;
171 }
172
173 void CompositingCoordinator::createRootLayer(const IntSize& size)
174 {
175     ASSERT(!m_rootLayer);
176     // Create a root layer.
177     m_rootLayer = GraphicsLayer::create(this, *this);
178 #ifndef NDEBUG
179     m_rootLayer->setName("CompositingCoordinator root layer");
180 #endif
181     m_rootLayer->setDrawsContent(false);
182     m_rootLayer->setSize(size);
183 }
184
185 void CompositingCoordinator::syncLayerState(CoordinatedLayerID id, CoordinatedGraphicsLayerState& state)
186 {
187     m_shouldSyncFrame = true;
188     m_state.layersToUpdate.append(std::make_pair(id, state));
189 }
190
191 PassRefPtr<CoordinatedImageBacking> CompositingCoordinator::createImageBackingIfNeeded(Image* image)
192 {
193     CoordinatedImageBackingID imageID = CoordinatedImageBacking::getCoordinatedImageBackingID(image);
194     ImageBackingMap::iterator it = m_imageBackings.find(imageID);
195     RefPtr<CoordinatedImageBacking> imageBacking;
196     if (it == m_imageBackings.end()) {
197         imageBacking = CoordinatedImageBacking::create(this, image);
198         m_imageBackings.add(imageID, imageBacking);
199     } else
200         imageBacking = it->value;
201
202     return imageBacking;
203 }
204
205 void CompositingCoordinator::createImageBacking(CoordinatedImageBackingID imageID)
206 {
207     m_state.imagesToCreate.append(imageID);
208 }
209
210 void CompositingCoordinator::updateImageBacking(CoordinatedImageBackingID imageID, PassRefPtr<CoordinatedSurface> coordinatedSurface)
211 {
212     m_shouldSyncFrame = true;
213     m_state.imagesToUpdate.append(std::make_pair(imageID, coordinatedSurface));
214 }
215
216 void CompositingCoordinator::clearImageBackingContents(CoordinatedImageBackingID imageID)
217 {
218     m_shouldSyncFrame = true;
219     m_state.imagesToClear.append(imageID);
220 }
221
222 void CompositingCoordinator::removeImageBacking(CoordinatedImageBackingID imageID)
223 {
224     if (m_isPurging)
225         return;
226
227     ASSERT(m_imageBackings.contains(imageID));
228     m_imageBackings.remove(imageID);
229
230     m_state.imagesToRemove.append(imageID);
231
232     size_t imageIDPosition = m_state.imagesToClear.find(imageID);
233     if (imageIDPosition != notFound)
234         m_state.imagesToClear.remove(imageIDPosition);
235 }
236
237 void CompositingCoordinator::flushPendingImageBackingChanges()
238 {
239     ImageBackingMap::iterator end = m_imageBackings.end();
240     for (ImageBackingMap::iterator iter = m_imageBackings.begin(); iter != end; ++iter)
241         iter->value->update();
242 }
243
244 void CompositingCoordinator::notifyAnimationStarted(const GraphicsLayer*, double /* time */)
245 {
246 }
247
248 void CompositingCoordinator::notifyFlushRequired(const GraphicsLayer*)
249 {
250     if (!isFlushingLayerChanges())
251         m_client->notifyFlushRequired();
252 }
253
254
255 void CompositingCoordinator::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect& clipRect)
256 {
257     m_client->paintLayerContents(graphicsLayer, graphicsContext, enclosingIntRect(clipRect));
258 }
259
260 std::unique_ptr<GraphicsLayer> CompositingCoordinator::createGraphicsLayer(GraphicsLayerClient& client)
261 {
262     CoordinatedGraphicsLayer* layer = new CoordinatedGraphicsLayer(client);
263     layer->setCoordinator(this);
264     m_registeredLayers.add(layer->id(), layer);
265     m_state.layersToCreate.append(layer->id());
266     layer->setNeedsVisibleRectAdjustment();
267     notifyFlushRequired(layer);
268     return std::unique_ptr<GraphicsLayer>(layer);
269 }
270
271 float CompositingCoordinator::deviceScaleFactor() const
272 {
273     return m_page->deviceScaleFactor();
274 }
275
276 float CompositingCoordinator::pageScaleFactor() const
277 {
278     return m_page->pageScaleFactor();
279 }
280
281 void CompositingCoordinator::createUpdateAtlas(uint32_t atlasID, PassRefPtr<CoordinatedSurface> coordinatedSurface)
282 {
283     m_state.updateAtlasesToCreate.append(std::make_pair(atlasID, coordinatedSurface));
284 }
285
286 void CompositingCoordinator::removeUpdateAtlas(uint32_t atlasID)
287 {
288     if (m_isPurging)
289         return;
290     m_state.updateAtlasesToRemove.append(atlasID);
291 }
292
293 FloatRect CompositingCoordinator::visibleContentsRect() const
294 {
295     return m_visibleContentsRect;
296 }
297
298 CoordinatedGraphicsLayer* CompositingCoordinator::mainContentsLayer()
299 {
300     if (!m_rootCompositingLayer)
301         return 0;
302
303     return toCoordinatedGraphicsLayer(m_rootCompositingLayer)->findFirstDescendantWithContentsRecursively();
304 }
305
306 void CompositingCoordinator::setVisibleContentsRect(const FloatRect& rect, const FloatPoint& trajectoryVector)
307 {
308     // A zero trajectoryVector indicates that tiles all around the viewport are requested.
309     if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer())
310         contentsLayer->setVisibleContentRectTrajectoryVector(trajectoryVector);
311
312     bool contentsRectDidChange = rect != m_visibleContentsRect;
313     if (contentsRectDidChange) {
314         m_visibleContentsRect = rect;
315
316         LayerMap::iterator end = m_registeredLayers.end();
317         for (LayerMap::iterator it = m_registeredLayers.begin(); it != end; ++it)
318             it->value->setNeedsVisibleRectAdjustment();
319     }
320
321     FrameView* view = m_page->mainFrame().view();
322     if (view->useFixedLayout()) {
323         // Round the rect instead of enclosing it to make sure that its size stays
324         // the same while panning. This can have nasty effects on layout.
325         view->setFixedVisibleContentRect(roundedIntRect(rect));
326     }
327 }
328
329 void CompositingCoordinator::deviceOrPageScaleFactorChanged()
330 {
331     m_rootLayer->deviceOrPageScaleFactorChanged();
332 }
333
334 void CompositingCoordinator::detachLayer(CoordinatedGraphicsLayer* layer)
335 {
336     if (m_isPurging)
337         return;
338
339     m_registeredLayers.remove(layer->id());
340
341     size_t index = m_state.layersToCreate.find(layer->id());
342     if (index != notFound) {
343         m_state.layersToCreate.remove(index);
344         return;
345     }
346
347     m_state.layersToRemove.append(layer->id());
348     notifyFlushRequired(layer);
349 }
350
351 void CompositingCoordinator::commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset)
352 {
353     LayerMap::iterator i = m_registeredLayers.find(layerID);
354     if (i == m_registeredLayers.end())
355         return;
356
357     i->value->commitScrollOffset(offset);
358 }
359
360 void CompositingCoordinator::renderNextFrame()
361 {
362     for (unsigned i = 0; i < m_updateAtlases.size(); ++i)
363         m_updateAtlases[i]->didSwapBuffers();
364 }
365
366 void CompositingCoordinator::purgeBackingStores()
367 {
368     TemporaryChange<bool> purgingToggle(m_isPurging, true);
369
370     LayerMap::iterator end = m_registeredLayers.end();
371     for (LayerMap::iterator it = m_registeredLayers.begin(); it != end; ++it)
372         it->value->purgeBackingStores();
373
374     m_imageBackings.clear();
375     m_updateAtlases.clear();
376 }
377
378 bool CompositingCoordinator::paintToSurface(const IntSize& size, CoordinatedSurface::Flags flags, uint32_t& atlasID, IntPoint& offset, CoordinatedSurface::Client* client)
379 {
380     for (unsigned i = 0; i < m_updateAtlases.size(); ++i) {
381         UpdateAtlas* atlas = m_updateAtlases[i].get();
382         if (atlas->supportsAlpha() == (flags & CoordinatedSurface::SupportsAlpha)) {
383             // This will be false if there is no available buffer space.
384             if (atlas->paintOnAvailableBuffer(size, atlasID, offset, client))
385                 return true;
386         }
387     }
388
389     static const int ScratchBufferDimension = 1024; // Should be a power of two.
390     m_updateAtlases.append(std::make_unique<UpdateAtlas>(this, ScratchBufferDimension, flags));
391     scheduleReleaseInactiveAtlases();
392     return m_updateAtlases.last()->paintOnAvailableBuffer(size, atlasID, offset, client);
393 }
394
395 const double ReleaseInactiveAtlasesTimerInterval = 0.5;
396
397 void CompositingCoordinator::scheduleReleaseInactiveAtlases()
398 {
399     if (!m_releaseInactiveAtlasesTimer.isActive())
400         m_releaseInactiveAtlasesTimer.startRepeating(ReleaseInactiveAtlasesTimerInterval);
401 }
402
403 void CompositingCoordinator::releaseInactiveAtlasesTimerFired(Timer<CompositingCoordinator>*)
404 {
405     // We always want to keep one atlas for root contents layer.
406     std::unique_ptr<UpdateAtlas> atlasToKeepAnyway;
407     bool foundActiveAtlasForRootContentsLayer = false;
408     for (int i = m_updateAtlases.size() - 1;  i >= 0; --i) {
409         UpdateAtlas* atlas = m_updateAtlases[i].get();
410         if (!atlas->isInUse())
411             atlas->addTimeInactive(ReleaseInactiveAtlasesTimerInterval);
412         bool usableForRootContentsLayer = !atlas->supportsAlpha();
413         if (atlas->isInactive()) {
414             if (!foundActiveAtlasForRootContentsLayer && !atlasToKeepAnyway && usableForRootContentsLayer)
415                 atlasToKeepAnyway = WTF::move(m_updateAtlases[i]);
416             m_updateAtlases.remove(i);
417         } else if (usableForRootContentsLayer)
418             foundActiveAtlasForRootContentsLayer = true;
419     }
420
421     if (!foundActiveAtlasForRootContentsLayer && atlasToKeepAnyway)
422         m_updateAtlases.append(atlasToKeepAnyway.release());
423
424     if (m_updateAtlases.size() <= 1)
425         m_releaseInactiveAtlasesTimer.stop();
426 }
427
428 } // namespace WebCore
429
430 #endif // USE(COORDINATED_GRAPHICS)