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