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/Frame.h>
35#include <WebCore/FrameView.h>
36#include <WebCore/GraphicsContext.h>
37#include <WebCore/InspectorController.h>
38#include <WebCore/NicosiaBackingStoreTextureMapperImpl.h>
39#include <WebCore/NicosiaContentLayerTextureMapperImpl.h>
40#include <WebCore/NicosiaImageBackingTextureMapperImpl.h>
41#include <WebCore/NicosiaPaintingEngine.h>
42#include <WebCore/Page.h>
43#include <wtf/MemoryPressureHandler.h>
44#include <wtf/SetForScope.h>
45
46#if USE(GLIB_EVENT_LOOP)
47#include <wtf/glib/RunLoopSourcePriority.h>
48#endif
49
50namespace WebKit {
51using namespace WebCore;
52
53CompositingCoordinator::CompositingCoordinator(Page* page, CompositingCoordinator::Client& client)
54 : m_page(page)
55 , m_client(client)
56 , m_paintingEngine(Nicosia::PaintingEngine::create())
57{
58 m_nicosia.scene = Nicosia::Scene::create();
59 m_state.nicosia.scene = m_nicosia.scene;
60}
61
62CompositingCoordinator::~CompositingCoordinator()
63{
64 m_isDestructing = true;
65
66 purgeBackingStores();
67
68 for (auto& registeredLayer : m_registeredLayers.values())
69 registeredLayer->setCoordinator(nullptr);
70}
71
72void CompositingCoordinator::invalidate()
73{
74 m_rootLayer = nullptr;
75 purgeBackingStores();
76}
77
78void CompositingCoordinator::setRootCompositingLayer(GraphicsLayer* graphicsLayer)
79{
80 if (m_rootCompositingLayer == graphicsLayer)
81 return;
82
83 if (m_rootCompositingLayer)
84 m_rootCompositingLayer->removeFromParent();
85
86 m_rootCompositingLayer = graphicsLayer;
87 if (m_rootCompositingLayer)
88 m_rootLayer->addChildAtIndex(*m_rootCompositingLayer, 0);
89}
90
91void CompositingCoordinator::setViewOverlayRootLayer(GraphicsLayer* graphicsLayer)
92{
93 if (m_overlayCompositingLayer == graphicsLayer)
94 return;
95
96 if (m_overlayCompositingLayer)
97 m_overlayCompositingLayer->removeFromParent();
98
99 m_overlayCompositingLayer = graphicsLayer;
100 if (m_overlayCompositingLayer)
101 m_rootLayer->addChild(*m_overlayCompositingLayer);
102}
103
104void CompositingCoordinator::sizeDidChange(const IntSize& newSize)
105{
106 m_rootLayer->setSize(newSize);
107 notifyFlushRequired(m_rootLayer.get());
108}
109
110bool CompositingCoordinator::flushPendingLayerChanges()
111{
112 SetForScope<bool> protector(m_isFlushingLayerChanges, true);
113
114 initializeRootCompositingLayerIfNeeded();
115
116 m_rootLayer->flushCompositingStateForThisLayerOnly();
117 m_client.didFlushRootLayer(m_visibleContentsRect);
118
119 if (m_overlayCompositingLayer)
120 m_overlayCompositingLayer->flushCompositingState(FloatRect(FloatPoint(), m_rootLayer->size()));
121
122 bool didSync = m_page->mainFrame().view()->flushCompositingStateIncludingSubframes();
123
124 auto& coordinatedLayer = downcast<CoordinatedGraphicsLayer>(*m_rootLayer);
125 coordinatedLayer.updateContentBuffersIncludingSubLayers();
126 coordinatedLayer.syncPendingStateChangesIncludingSubLayers();
127
128 if (m_shouldSyncFrame) {
129 didSync = true;
130
131 m_state.nicosia.scene->accessState(
132 [this](Nicosia::Scene::State& state)
133 {
134 bool platformLayerUpdated = false;
135 for (auto& compositionLayer : m_nicosia.state.layers) {
136 compositionLayer->flushState(
137 [&platformLayerUpdated]
138 (const Nicosia::CompositionLayer::LayerState& state)
139 {
140 if (state.backingStore) {
141 auto& impl = downcast<Nicosia::BackingStoreTextureMapperImpl>(state.backingStore->impl());
142 impl.flushUpdate();
143 }
144
145 if (state.imageBacking) {
146 auto& impl = downcast<Nicosia::ImageBackingTextureMapperImpl>(state.imageBacking->impl());
147 impl.flushUpdate();
148 }
149
150 if (state.contentLayer) {
151 auto& impl = downcast<Nicosia::ContentLayerTextureMapperImpl>(state.contentLayer->impl());
152 platformLayerUpdated |= impl.flushUpdate();
153 }
154 });
155 }
156
157 ++state.id;
158 state.platformLayerUpdated = platformLayerUpdated;
159 state.layers = m_nicosia.state.layers;
160 state.rootLayer = m_nicosia.state.rootLayer;
161 });
162
163 m_client.commitSceneState(m_state);
164 m_shouldSyncFrame = false;
165 }
166
167 return didSync;
168}
169
170double CompositingCoordinator::timestamp() const
171{
172 auto* document = m_page->mainFrame().document();
173 if (!document)
174 return 0;
175 return document->domWindow() ? document->domWindow()->nowTimestamp() : document->monotonicTimestamp();
176}
177
178void CompositingCoordinator::syncDisplayState()
179{
180 m_page->mainFrame().view()->updateLayoutAndStyleIfNeededRecursive();
181}
182
183double CompositingCoordinator::nextAnimationServiceTime() const
184{
185 // According to the requestAnimationFrame spec, rAF callbacks should not be faster than 60FPS.
186 static const double MinimalTimeoutForAnimations = 1. / 60.;
187 return std::max<double>(0., MinimalTimeoutForAnimations - timestamp() + m_lastAnimationServiceTime);
188}
189
190void CompositingCoordinator::initializeRootCompositingLayerIfNeeded()
191{
192 if (m_didInitializeRootCompositingLayer)
193 return;
194
195 auto& rootLayer = downcast<CoordinatedGraphicsLayer>(*m_rootLayer);
196 m_nicosia.state.rootLayer = rootLayer.compositionLayer();
197 m_didInitializeRootCompositingLayer = true;
198 m_shouldSyncFrame = true;
199}
200
201void CompositingCoordinator::createRootLayer(const IntSize& size)
202{
203 ASSERT(!m_rootLayer);
204 // Create a root layer.
205 m_rootLayer = GraphicsLayer::create(this, *this);
206#ifndef NDEBUG
207 m_rootLayer->setName("CompositingCoordinator root layer");
208#endif
209 m_rootLayer->setDrawsContent(false);
210 m_rootLayer->setSize(size);
211}
212
213void CompositingCoordinator::syncLayerState()
214{
215 m_shouldSyncFrame = true;
216}
217
218void CompositingCoordinator::notifyFlushRequired(const GraphicsLayer*)
219{
220 if (!m_isDestructing && !isFlushingLayerChanges())
221 m_client.notifyFlushRequired();
222}
223
224float CompositingCoordinator::deviceScaleFactor() const
225{
226 return m_page->deviceScaleFactor();
227}
228
229float CompositingCoordinator::pageScaleFactor() const
230{
231 return m_page->pageScaleFactor();
232}
233
234Ref<GraphicsLayer> CompositingCoordinator::createGraphicsLayer(GraphicsLayer::Type layerType, GraphicsLayerClient& client)
235{
236 auto layer = adoptRef(*new CoordinatedGraphicsLayer(layerType, client));
237 layer->setCoordinator(this);
238 m_nicosia.state.layers.add(layer->compositionLayer());
239 m_registeredLayers.add(layer->id(), layer.ptr());
240 layer->setNeedsVisibleRectAdjustment();
241 notifyFlushRequired(layer.ptr());
242 return layer;
243}
244
245FloatRect CompositingCoordinator::visibleContentsRect() const
246{
247 return m_visibleContentsRect;
248}
249
250void CompositingCoordinator::setVisibleContentsRect(const FloatRect& rect)
251{
252 bool contentsRectDidChange = rect != m_visibleContentsRect;
253 if (contentsRectDidChange) {
254 m_visibleContentsRect = rect;
255
256 for (auto& registeredLayer : m_registeredLayers.values())
257 registeredLayer->setNeedsVisibleRectAdjustment();
258 }
259
260 FrameView* view = m_page->mainFrame().view();
261 if (view->useFixedLayout() && contentsRectDidChange) {
262 // Round the rect instead of enclosing it to make sure that its size stays
263 // the same while panning. This can have nasty effects on layout.
264 view->setFixedVisibleContentRect(roundedIntRect(rect));
265 }
266}
267
268void CompositingCoordinator::deviceOrPageScaleFactorChanged()
269{
270 m_rootLayer->deviceOrPageScaleFactorChanged();
271}
272
273void CompositingCoordinator::detachLayer(CoordinatedGraphicsLayer* layer)
274{
275 if (m_isPurging)
276 return;
277
278 m_nicosia.state.layers.remove(layer->compositionLayer());
279 m_registeredLayers.remove(layer->id());
280 notifyFlushRequired(layer);
281}
282
283void CompositingCoordinator::attachLayer(CoordinatedGraphicsLayer* layer)
284{
285 layer->setCoordinator(this);
286 m_nicosia.state.layers.add(layer->compositionLayer());
287 m_registeredLayers.add(layer->id(), layer);
288 layer->setNeedsVisibleRectAdjustment();
289 notifyFlushRequired(layer);
290}
291
292void CompositingCoordinator::renderNextFrame()
293{
294}
295
296void CompositingCoordinator::purgeBackingStores()
297{
298 SetForScope<bool> purgingToggle(m_isPurging, true);
299
300 for (auto& registeredLayer : m_registeredLayers.values())
301 registeredLayer->purgeBackingStores();
302}
303
304Nicosia::PaintingEngine& CompositingCoordinator::paintingEngine()
305{
306 return *m_paintingEngine;
307}
308
309} // namespace WebKit
310
311#endif // USE(COORDINATED_GRAPHICS)
312