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