REGRESSION (iOS WebKit2): requestAnimationFrame fires more than once between layer...
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / mac / RemoteLayerTreeDrawingArea.mm
1 /*
2  * Copyright (C) 2012-2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "RemoteLayerTreeDrawingArea.h"
28
29 #import "DrawingAreaProxyMessages.h"
30 #import "GraphicsLayerCARemote.h"
31 #import "PlatformCALayerRemote.h"
32 #import "RemoteLayerBackingStoreCollection.h"
33 #import "RemoteLayerTreeContext.h"
34 #import "RemoteLayerTreeDisplayRefreshMonitor.h"
35 #import "RemoteLayerTreeDrawingAreaProxyMessages.h"
36 #import "RemoteScrollingCoordinator.h"
37 #import "RemoteScrollingCoordinatorTransaction.h"
38 #import "WebPage.h"
39 #import "WebProcess.h"
40 #import <WebCore/Frame.h>
41 #import <WebCore/FrameView.h>
42 #import <WebCore/MainFrame.h>
43 #import <WebCore/RenderLayerCompositor.h>
44 #import <WebCore/RenderView.h>
45 #import <WebCore/Settings.h>
46 #import <WebCore/TiledBacking.h>
47 #import <QuartzCore/QuartzCore.h>
48
49 using namespace WebCore;
50
51 namespace WebKit {
52
53 RemoteLayerTreeDrawingArea::RemoteLayerTreeDrawingArea(WebPage* webPage, const WebPageCreationParameters&)
54     : DrawingArea(DrawingAreaTypeRemoteLayerTree, webPage)
55     , m_remoteLayerTreeContext(std::make_unique<RemoteLayerTreeContext>(webPage))
56     , m_rootLayer(GraphicsLayer::create(graphicsLayerFactory(), *this))
57     , m_exposedRect(FloatRect::infiniteRect())
58     , m_scrolledExposedRect(FloatRect::infiniteRect())
59     , m_layerFlushTimer(this, &RemoteLayerTreeDrawingArea::layerFlushTimerFired)
60     , m_isFlushingSuspended(false)
61     , m_hasDeferredFlush(false)
62     , m_waitingForBackingStoreSwap(false)
63     , m_hadFlushDeferredWhileWaitingForBackingStoreSwap(false)
64 {
65     webPage->corePage()->settings().setForceCompositingMode(true);
66 #if PLATFORM(IOS)
67     webPage->corePage()->settings().setDelegatesPageScaling(true);
68 #endif
69
70     m_commitQueue = dispatch_queue_create("com.apple.WebKit.WebContent.RemoteLayerTreeDrawingArea.CommitQueue", nullptr);
71 }
72
73 RemoteLayerTreeDrawingArea::~RemoteLayerTreeDrawingArea()
74 {
75     dispatch_release(m_commitQueue);
76 }
77
78 void RemoteLayerTreeDrawingArea::setNeedsDisplay()
79 {
80 }
81
82 void RemoteLayerTreeDrawingArea::setNeedsDisplayInRect(const IntRect&)
83 {
84 }
85
86 void RemoteLayerTreeDrawingArea::scroll(const IntRect& scrollRect, const IntSize& scrollDelta)
87 {
88 }
89
90 GraphicsLayerFactory* RemoteLayerTreeDrawingArea::graphicsLayerFactory()
91 {
92     return m_remoteLayerTreeContext.get();
93 }
94
95 PassRefPtr<DisplayRefreshMonitor> RemoteLayerTreeDrawingArea::createDisplayRefreshMonitor(PlatformDisplayID displayID)
96 {
97     RefPtr<RemoteLayerTreeDisplayRefreshMonitor> monitor = RemoteLayerTreeDisplayRefreshMonitor::create(displayID, *this);
98     m_displayRefreshMonitors.add(monitor.get());
99     return monitor.release();
100 }
101
102 void RemoteLayerTreeDrawingArea::willDestroyDisplayRefreshMonitor(DisplayRefreshMonitor* monitor)
103 {
104     m_displayRefreshMonitors.remove(static_cast<RemoteLayerTreeDisplayRefreshMonitor*>(monitor));
105 }
106
107 void RemoteLayerTreeDrawingArea::setRootCompositingLayer(GraphicsLayer* rootLayer)
108 {
109     Vector<GraphicsLayer *> children;
110     if (rootLayer) {
111         children.append(rootLayer);
112         children.append(m_webPage->pageOverlayController().viewOverlayRootLayer());
113     }
114     m_rootLayer->setChildren(children);
115 }
116
117 void RemoteLayerTreeDrawingArea::updateGeometry(const IntSize& viewSize, const IntSize& layerPosition)
118 {
119     m_viewSize = viewSize;
120     m_webPage->setSize(viewSize);
121
122     scheduleCompositingLayerFlush();
123
124     m_webPage->send(Messages::DrawingAreaProxy::DidUpdateGeometry());
125 }
126
127 bool RemoteLayerTreeDrawingArea::shouldUseTiledBackingForFrameView(const FrameView* frameView)
128 {
129     return frameView && frameView->frame().isMainFrame();
130 }
131
132 void RemoteLayerTreeDrawingArea::updatePreferences(const WebPreferencesStore&)
133 {
134     Settings& settings = m_webPage->corePage()->settings();
135
136     // Fixed position elements need to be composited and create stacking contexts
137     // in order to be scrolled by the ScrollingCoordinator.
138     settings.setAcceleratedCompositingForFixedPositionEnabled(true);
139     settings.setFixedPositionCreatesStackingContext(true);
140
141     m_rootLayer->setShowDebugBorder(settings.showDebugBorders());
142 }
143
144 #if PLATFORM(IOS)
145 void RemoteLayerTreeDrawingArea::setDeviceScaleFactor(float deviceScaleFactor)
146 {
147     m_webPage->setDeviceScaleFactor(deviceScaleFactor);
148 }
149 #endif
150
151 void RemoteLayerTreeDrawingArea::setLayerTreeStateIsFrozen(bool isFrozen)
152 {
153     if (m_isFlushingSuspended == isFrozen)
154         return;
155
156     m_isFlushingSuspended = isFrozen;
157
158     if (!m_isFlushingSuspended && m_hasDeferredFlush) {
159         m_hasDeferredFlush = false;
160         scheduleCompositingLayerFlush();
161     }
162 }
163
164 void RemoteLayerTreeDrawingArea::forceRepaint()
165 {
166     if (m_isFlushingSuspended)
167         return;
168
169     for (Frame* frame = &m_webPage->corePage()->mainFrame(); frame; frame = frame->tree().traverseNext()) {
170         FrameView* frameView = frame->view();
171         if (!frameView || !frameView->tiledBacking())
172             continue;
173
174         frameView->tiledBacking()->forceRepaint();
175     }
176
177     flushLayers();
178 }
179
180 void RemoteLayerTreeDrawingArea::acceleratedAnimationDidStart(uint64_t layerID, const String& key, double startTime)
181 {
182     m_remoteLayerTreeContext->animationDidStart(layerID, key, startTime);
183 }
184
185 void RemoteLayerTreeDrawingArea::setExposedRect(const FloatRect& exposedRect)
186 {
187     m_exposedRect = exposedRect;
188     updateScrolledExposedRect();
189 }
190
191 #if PLATFORM(IOS)
192 void RemoteLayerTreeDrawingArea::setExposedContentRect(const FloatRect& exposedContentRect)
193 {
194     FrameView* frameView = m_webPage->corePage()->mainFrame().view();
195     if (!frameView)
196         return;
197
198     frameView->setExposedContentRect(enclosingIntRect(exposedContentRect));
199     scheduleCompositingLayerFlush();
200 }
201 #endif
202
203 void RemoteLayerTreeDrawingArea::updateScrolledExposedRect()
204 {
205     FrameView* frameView = m_webPage->corePage()->mainFrame().view();
206     if (!frameView)
207         return;
208
209     m_scrolledExposedRect = m_exposedRect;
210
211 #if !PLATFORM(IOS)
212     if (!m_exposedRect.isInfinite()) {
213         IntPoint scrollPositionWithOrigin = frameView->scrollPosition() + toIntSize(frameView->scrollOrigin());
214         m_scrolledExposedRect.moveBy(scrollPositionWithOrigin);
215     }
216 #endif
217
218     frameView->setExposedRect(m_scrolledExposedRect);
219     frameView->adjustTiledBackingCoverage();
220
221     m_webPage->pageOverlayController().didChangeExposedRect();
222 }
223
224 TiledBacking* RemoteLayerTreeDrawingArea::mainFrameTiledBacking() const
225 {
226     FrameView* frameView = m_webPage->corePage()->mainFrame().view();
227     return frameView ? frameView->tiledBacking() : 0;
228 }
229
230 void RemoteLayerTreeDrawingArea::scheduleCompositingLayerFlush()
231 {
232     if (m_layerFlushTimer.isActive())
233         return;
234
235     m_layerFlushTimer.startOneShot(0);
236 }
237
238 void RemoteLayerTreeDrawingArea::layerFlushTimerFired(WebCore::Timer<RemoteLayerTreeDrawingArea>*)
239 {
240     flushLayers();
241 }
242
243 void RemoteLayerTreeDrawingArea::flushLayers()
244 {
245     if (!m_rootLayer)
246         return;
247
248     if (m_isFlushingSuspended) {
249         m_hasDeferredFlush = true;
250         return;
251     }
252
253     if (m_waitingForBackingStoreSwap) {
254         m_hadFlushDeferredWhileWaitingForBackingStoreSwap = true;
255         return;
256     }
257
258     RELEASE_ASSERT(!m_pendingBackingStoreFlusher || m_pendingBackingStoreFlusher->hasFlushed());
259
260     m_webPage->layoutIfNeeded();
261
262     FloatRect visibleRect(FloatPoint(), m_viewSize);
263     visibleRect.intersect(m_scrolledExposedRect);
264     m_webPage->pageOverlayController().flushPageOverlayLayers(visibleRect);
265     m_webPage->corePage()->mainFrame().view()->flushCompositingStateIncludingSubframes();
266     m_rootLayer->flushCompositingStateForThisLayerOnly();
267
268     // FIXME: minize these transactions if nothing changed.
269     RemoteLayerTreeTransaction layerTransaction;
270     m_remoteLayerTreeContext->buildTransaction(layerTransaction, *toGraphicsLayerCARemote(m_rootLayer.get())->platformCALayer());
271     m_webPage->willCommitLayerTree(layerTransaction);
272
273     RemoteScrollingCoordinatorTransaction scrollingTransaction;
274 #if ENABLE(ASYNC_SCROLLING)
275     if (m_webPage->scrollingCoordinator())
276         toRemoteScrollingCoordinator(m_webPage->scrollingCoordinator())->buildTransaction(scrollingTransaction);
277 #endif
278
279     m_waitingForBackingStoreSwap = true;
280
281     Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree message(layerTransaction, scrollingTransaction);
282     auto commitEncoder = std::make_unique<IPC::MessageEncoder>(Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::receiverName(), Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::name(), m_webPage->pageID());
283     commitEncoder->encode(message.arguments());
284
285     bool hadAnyChangedBackingStore = false;
286     Vector<RetainPtr<CGContextRef>> contextsToFlush;
287     for (auto& layer : layerTransaction.changedLayers()) {
288         if (layer->properties().changedProperties & RemoteLayerTreeTransaction::LayerChanges::BackingStoreChanged) {
289             hadAnyChangedBackingStore = true;
290             if (layer->properties().backingStore) {
291                 if (auto contextPendingFlush = layer->properties().backingStore->takeFrontContextPendingFlush())
292                     contextsToFlush.append(contextPendingFlush);
293             }
294         }
295
296         layer->didCommit();
297     }
298
299     if (hadAnyChangedBackingStore)
300         m_remoteLayerTreeContext->backingStoreCollection().schedulePurgeabilityTimer();
301
302     RefPtr<BackingStoreFlusher> backingStoreFlusher = BackingStoreFlusher::create(WebProcess::shared().parentProcessConnection(), std::move(commitEncoder), std::move(contextsToFlush));
303     m_pendingBackingStoreFlusher = backingStoreFlusher;
304
305     dispatch_async(m_commitQueue, [backingStoreFlusher]{
306         backingStoreFlusher->flush();
307     });
308 }
309
310 void RemoteLayerTreeDrawingArea::didUpdate()
311 {
312     // FIXME: This should use a counted replacement for setLayerTreeStateIsFrozen, but
313     // the callers of that function are not strictly paired.
314
315     m_waitingForBackingStoreSwap = false;
316
317     if (m_hadFlushDeferredWhileWaitingForBackingStoreSwap) {
318         scheduleCompositingLayerFlush();
319         m_hadFlushDeferredWhileWaitingForBackingStoreSwap = false;
320     }
321
322     // This empty transaction serves to trigger CA's garbage collection of IOSurfaces. See <rdar://problem/16110687>
323     [CATransaction begin];
324     [CATransaction commit];
325
326     for (auto& monitor : m_displayRefreshMonitors)
327         monitor->didUpdateLayers();
328 }
329
330 void RemoteLayerTreeDrawingArea::mainFrameContentSizeChanged(const IntSize& contentsSize)
331 {
332     m_rootLayer->setSize(contentsSize);
333     m_webPage->pageOverlayController().didChangeDocumentSize();
334 }
335
336 PassRefPtr<RemoteLayerTreeDrawingArea::BackingStoreFlusher> RemoteLayerTreeDrawingArea::BackingStoreFlusher::create(IPC::Connection* connection, std::unique_ptr<IPC::MessageEncoder> encoder, Vector<RetainPtr<CGContextRef>> contextsToFlush)
337 {
338     return adoptRef(new RemoteLayerTreeDrawingArea::BackingStoreFlusher(connection, std::move(encoder), std::move(contextsToFlush)));
339 }
340
341 RemoteLayerTreeDrawingArea::BackingStoreFlusher::BackingStoreFlusher(IPC::Connection* connection, std::unique_ptr<IPC::MessageEncoder> encoder, Vector<RetainPtr<CGContextRef>> contextsToFlush)
342     : m_connection(connection)
343     , m_commitEncoder(std::move(encoder))
344     , m_contextsToFlush(std::move(contextsToFlush))
345     , m_hasFlushed(false)
346 {
347 }
348
349 void RemoteLayerTreeDrawingArea::BackingStoreFlusher::flush()
350 {
351     ASSERT(!m_hasFlushed);
352
353     for (auto& context : m_contextsToFlush)
354         CGContextFlush(context.get());
355     m_hasFlushed = true;
356
357     m_connection->sendMessage(std::move(m_commitEncoder));
358 }
359
360 } // namespace WebKit