Add animationDidEnd callbacks on GraphicsLayer
[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_isThrottlingLayerFlushes(false)
63     , m_isLayerFlushThrottlingTemporarilyDisabledForInteraction(false)
64     , m_isInitialThrottledLayerFlush(false)
65     , m_waitingForBackingStoreSwap(false)
66     , m_hadFlushDeferredWhileWaitingForBackingStoreSwap(false)
67     , m_displayRefreshMonitorsToNotify(nullptr)
68     , m_currentTransactionID(0)
69 {
70     webPage.corePage()->settings().setForceCompositingMode(true);
71 #if PLATFORM(IOS)
72     webPage.corePage()->settings().setDelegatesPageScaling(true);
73 #endif
74
75     m_commitQueue = dispatch_queue_create("com.apple.WebKit.WebContent.RemoteLayerTreeDrawingArea.CommitQueue", nullptr);
76 }
77
78 RemoteLayerTreeDrawingArea::~RemoteLayerTreeDrawingArea()
79 {
80     dispatch_release(m_commitQueue);
81 }
82
83 void RemoteLayerTreeDrawingArea::setNeedsDisplay()
84 {
85 }
86
87 void RemoteLayerTreeDrawingArea::setNeedsDisplayInRect(const IntRect&)
88 {
89 }
90
91 void RemoteLayerTreeDrawingArea::scroll(const IntRect& scrollRect, const IntSize& scrollDelta)
92 {
93 }
94
95 GraphicsLayerFactory* RemoteLayerTreeDrawingArea::graphicsLayerFactory()
96 {
97     return m_remoteLayerTreeContext.get();
98 }
99
100 PassRefPtr<DisplayRefreshMonitor> RemoteLayerTreeDrawingArea::createDisplayRefreshMonitor(PlatformDisplayID displayID)
101 {
102     RefPtr<RemoteLayerTreeDisplayRefreshMonitor> monitor = RemoteLayerTreeDisplayRefreshMonitor::create(displayID, *this);
103     m_displayRefreshMonitors.add(monitor.get());
104     return monitor.release();
105 }
106
107 void RemoteLayerTreeDrawingArea::willDestroyDisplayRefreshMonitor(DisplayRefreshMonitor* monitor)
108 {
109     auto remoteMonitor = static_cast<RemoteLayerTreeDisplayRefreshMonitor*>(monitor);
110     m_displayRefreshMonitors.remove(remoteMonitor);
111
112     if (m_displayRefreshMonitorsToNotify)
113         m_displayRefreshMonitorsToNotify->remove(remoteMonitor);
114 }
115
116 void RemoteLayerTreeDrawingArea::setRootCompositingLayer(GraphicsLayer* rootLayer)
117 {
118     Vector<GraphicsLayer*> children;
119     if (rootLayer) {
120         children.append(rootLayer);
121         children.append(m_webPage.pageOverlayController().viewOverlayRootLayer());
122     }
123     m_rootLayer->setChildren(children);
124
125     scheduleCompositingLayerFlush();
126 }
127
128 void RemoteLayerTreeDrawingArea::updateGeometry(const IntSize& viewSize, const IntSize& layerPosition)
129 {
130     m_viewSize = viewSize;
131     m_webPage.setSize(viewSize);
132
133     scheduleCompositingLayerFlush();
134
135     m_webPage.send(Messages::DrawingAreaProxy::DidUpdateGeometry());
136 }
137
138 bool RemoteLayerTreeDrawingArea::shouldUseTiledBackingForFrameView(const FrameView* frameView)
139 {
140     return frameView && frameView->frame().isMainFrame();
141 }
142
143 void RemoteLayerTreeDrawingArea::updatePreferences(const WebPreferencesStore&)
144 {
145     Settings& settings = m_webPage.corePage()->settings();
146
147     // Fixed position elements need to be composited and create stacking contexts
148     // in order to be scrolled by the ScrollingCoordinator.
149     settings.setAcceleratedCompositingForFixedPositionEnabled(true);
150     settings.setFixedPositionCreatesStackingContext(true);
151
152     m_rootLayer->setShowDebugBorder(settings.showDebugBorders());
153 }
154
155 #if PLATFORM(IOS)
156 void RemoteLayerTreeDrawingArea::setDeviceScaleFactor(float deviceScaleFactor)
157 {
158     m_webPage.setDeviceScaleFactor(deviceScaleFactor);
159 }
160 #endif
161
162 void RemoteLayerTreeDrawingArea::setLayerTreeStateIsFrozen(bool isFrozen)
163 {
164     if (m_isFlushingSuspended == isFrozen)
165         return;
166
167     m_isFlushingSuspended = isFrozen;
168
169     if (!m_isFlushingSuspended && m_hasDeferredFlush) {
170         m_hasDeferredFlush = false;
171         scheduleCompositingLayerFlush();
172     }
173 }
174
175 void RemoteLayerTreeDrawingArea::forceRepaint()
176 {
177     if (m_isFlushingSuspended)
178         return;
179
180     for (Frame* frame = &m_webPage.corePage()->mainFrame(); frame; frame = frame->tree().traverseNext()) {
181         FrameView* frameView = frame->view();
182         if (!frameView || !frameView->tiledBacking())
183             continue;
184
185         frameView->tiledBacking()->forceRepaint();
186     }
187
188     flushLayers();
189 }
190
191 void RemoteLayerTreeDrawingArea::acceleratedAnimationDidStart(uint64_t layerID, const String& key, double startTime)
192 {
193     m_remoteLayerTreeContext->animationDidStart(layerID, key, startTime);
194 }
195
196 void RemoteLayerTreeDrawingArea::acceleratedAnimationDidEnd(uint64_t layerID, const String& key)
197 {
198     m_remoteLayerTreeContext->animationDidEnd(layerID, key);
199 }
200
201 void RemoteLayerTreeDrawingArea::setExposedRect(const FloatRect& exposedRect)
202 {
203     m_exposedRect = exposedRect;
204     updateScrolledExposedRect();
205 }
206
207 #if PLATFORM(IOS)
208 void RemoteLayerTreeDrawingArea::setExposedContentRect(const FloatRect& exposedContentRect)
209 {
210     FrameView* frameView = m_webPage.mainFrameView();
211     if (!frameView)
212         return;
213     if (frameView->exposedContentRect() == exposedContentRect)
214         return;
215
216     frameView->setExposedContentRect(exposedContentRect);
217     scheduleCompositingLayerFlush();
218 }
219 #endif
220
221 void RemoteLayerTreeDrawingArea::updateScrolledExposedRect()
222 {
223     FrameView* frameView = m_webPage.mainFrameView();
224     if (!frameView)
225         return;
226
227     m_scrolledExposedRect = m_exposedRect;
228
229 #if !PLATFORM(IOS)
230     if (!m_exposedRect.isInfinite()) {
231         IntPoint scrollPositionWithOrigin = frameView->scrollPosition() + toIntSize(frameView->scrollOrigin());
232         m_scrolledExposedRect.moveBy(scrollPositionWithOrigin);
233     }
234 #endif
235
236     frameView->setExposedRect(m_scrolledExposedRect);
237
238     m_webPage.pageOverlayController().didChangeExposedRect();
239 }
240
241 TiledBacking* RemoteLayerTreeDrawingArea::mainFrameTiledBacking() const
242 {
243     FrameView* frameView = m_webPage.mainFrameView();
244     return frameView ? frameView->tiledBacking() : nullptr;
245 }
246
247 void RemoteLayerTreeDrawingArea::scheduleCompositingLayerFlushImmediately()
248 {
249     m_layerFlushTimer.startOneShot(0_ms);
250 }
251
252 void RemoteLayerTreeDrawingArea::scheduleCompositingLayerFlush()
253 {
254     if (m_isFlushingSuspended) {
255         m_isLayerFlushThrottlingTemporarilyDisabledForInteraction = false;
256         m_hasDeferredFlush = true;
257         return;
258     }
259     if (m_isLayerFlushThrottlingTemporarilyDisabledForInteraction) {
260         m_isLayerFlushThrottlingTemporarilyDisabledForInteraction = false;
261         scheduleCompositingLayerFlushImmediately();
262         return;
263     }
264
265     if (m_layerFlushTimer.isActive())
266         return;
267
268     const auto initialFlushDelay = 500_ms;
269     const auto flushDelay = 1500_ms;
270     auto throttleDelay = m_isThrottlingLayerFlushes ? (m_isInitialThrottledLayerFlush ? initialFlushDelay : flushDelay) : 0_ms;
271     m_isInitialThrottledLayerFlush = false;
272
273     m_layerFlushTimer.startOneShot(throttleDelay);
274 }
275
276 bool RemoteLayerTreeDrawingArea::adjustLayerFlushThrottling(WebCore::LayerFlushThrottleState::Flags flags)
277 {
278     if (flags & WebCore::LayerFlushThrottleState::UserIsInteracting)
279         m_isLayerFlushThrottlingTemporarilyDisabledForInteraction = true;
280
281     bool wasThrottlingLayerFlushes = m_isThrottlingLayerFlushes;
282     m_isThrottlingLayerFlushes = flags & WebCore::LayerFlushThrottleState::Enabled;
283
284     if (!wasThrottlingLayerFlushes && m_isThrottlingLayerFlushes)
285         m_isInitialThrottledLayerFlush = true;
286
287     // Re-schedule the flush if we stopped throttling.
288     if (wasThrottlingLayerFlushes && !m_isThrottlingLayerFlushes && m_layerFlushTimer.isActive()) {
289         m_layerFlushTimer.stop();
290         scheduleCompositingLayerFlush();
291     }
292     return true;
293 }
294
295 void RemoteLayerTreeDrawingArea::layerFlushTimerFired(WebCore::Timer<RemoteLayerTreeDrawingArea>*)
296 {
297     flushLayers();
298 }
299
300 void RemoteLayerTreeDrawingArea::flushLayers()
301 {
302     if (!m_rootLayer)
303         return;
304
305     if (m_isFlushingSuspended) {
306         m_hasDeferredFlush = true;
307         return;
308     }
309
310     if (m_waitingForBackingStoreSwap) {
311         m_hadFlushDeferredWhileWaitingForBackingStoreSwap = true;
312         return;
313     }
314
315     RELEASE_ASSERT(!m_pendingBackingStoreFlusher || m_pendingBackingStoreFlusher->hasFlushed());
316
317     RemoteLayerBackingStoreCollection& backingStoreCollection = m_remoteLayerTreeContext->backingStoreCollection();
318     backingStoreCollection.willFlushLayers();
319
320     m_webPage.layoutIfNeeded();
321
322     FloatRect visibleRect(FloatPoint(), m_viewSize);
323     visibleRect.intersect(m_scrolledExposedRect);
324     m_webPage.pageOverlayController().flushPageOverlayLayers(visibleRect);
325     m_webPage.mainFrameView()->flushCompositingStateIncludingSubframes();
326     m_rootLayer->flushCompositingStateForThisLayerOnly();
327
328     // FIXME: Minimize these transactions if nothing changed.
329     RemoteLayerTreeTransaction layerTransaction;
330     layerTransaction.setTransactionID(takeNextTransactionID());
331     layerTransaction.setCallbackIDs(WTF::move(m_pendingCallbackIDs));
332     m_remoteLayerTreeContext->buildTransaction(layerTransaction, *toGraphicsLayerCARemote(m_rootLayer.get())->platformCALayer());
333     backingStoreCollection.willCommitLayerTree(layerTransaction);
334     m_webPage.willCommitLayerTree(layerTransaction);
335
336     RemoteScrollingCoordinatorTransaction scrollingTransaction;
337 #if ENABLE(ASYNC_SCROLLING)
338     if (m_webPage.scrollingCoordinator())
339         toRemoteScrollingCoordinator(m_webPage.scrollingCoordinator())->buildTransaction(scrollingTransaction);
340 #endif
341
342     m_waitingForBackingStoreSwap = true;
343
344     m_webPage.send(Messages::RemoteLayerTreeDrawingAreaProxy::WillCommitLayerTree(layerTransaction.transactionID()));
345
346     Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree message(layerTransaction, scrollingTransaction);
347     auto commitEncoder = std::make_unique<IPC::MessageEncoder>(Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::receiverName(), Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::name(), m_webPage.pageID());
348     commitEncoder->encode(message.arguments());
349
350     // FIXME: Move all backing store flushing management to RemoteLayerBackingStoreCollection.
351     bool hadAnyChangedBackingStore = false;
352     Vector<RetainPtr<CGContextRef>> contextsToFlush;
353     for (auto& layer : layerTransaction.changedLayers()) {
354         if (layer->properties().changedProperties & RemoteLayerTreeTransaction::LayerChanges::BackingStoreChanged) {
355             hadAnyChangedBackingStore = true;
356             if (layer->properties().backingStore) {
357                 if (auto contextPendingFlush = layer->properties().backingStore->takeFrontContextPendingFlush())
358                     contextsToFlush.append(contextPendingFlush);
359             }
360         }
361
362         layer->didCommit();
363     }
364
365     backingStoreCollection.didFlushLayers();
366
367     if (hadAnyChangedBackingStore)
368         backingStoreCollection.scheduleVolatilityTimer();
369
370     RefPtr<BackingStoreFlusher> backingStoreFlusher = BackingStoreFlusher::create(WebProcess::shared().parentProcessConnection(), WTF::move(commitEncoder), WTF::move(contextsToFlush));
371     m_pendingBackingStoreFlusher = backingStoreFlusher;
372
373     uint64_t pageID = m_webPage.pageID();
374     dispatch_async(m_commitQueue, [backingStoreFlusher, pageID] {
375         backingStoreFlusher->flush();
376
377         if (WebPage *webPage = WebProcess::shared().webPage(pageID)) {
378             std::chrono::milliseconds timestamp = std::chrono::milliseconds(static_cast<std::chrono::milliseconds::rep>(monotonicallyIncreasingTime() * 1000));
379             dispatch_async(dispatch_get_main_queue(), ^{
380                 webPage->didFlushLayerTreeAtTime(timestamp);
381             });
382         }
383     });
384 }
385
386 void RemoteLayerTreeDrawingArea::didUpdate()
387 {
388     // FIXME: This should use a counted replacement for setLayerTreeStateIsFrozen, but
389     // the callers of that function are not strictly paired.
390
391     m_waitingForBackingStoreSwap = false;
392
393     if (m_hadFlushDeferredWhileWaitingForBackingStoreSwap) {
394         scheduleCompositingLayerFlush();
395         m_hadFlushDeferredWhileWaitingForBackingStoreSwap = false;
396     }
397
398     // This empty transaction serves to trigger CA's garbage collection of IOSurfaces. See <rdar://problem/16110687>
399     [CATransaction begin];
400     [CATransaction commit];
401
402     HashSet<RemoteLayerTreeDisplayRefreshMonitor*> monitorsToNotify = m_displayRefreshMonitors;
403     ASSERT(!m_displayRefreshMonitorsToNotify);
404     m_displayRefreshMonitorsToNotify = &monitorsToNotify;
405     while (!monitorsToNotify.isEmpty())
406         monitorsToNotify.takeAny()->didUpdateLayers();
407     m_displayRefreshMonitorsToNotify = nullptr;
408 }
409
410 void RemoteLayerTreeDrawingArea::mainFrameContentSizeChanged(const IntSize& contentsSize)
411 {
412     m_rootLayer->setSize(contentsSize);
413     m_webPage.pageOverlayController().didChangeDocumentSize();
414 }
415
416 bool RemoteLayerTreeDrawingArea::markLayersVolatileImmediatelyIfPossible()
417 {
418     return m_remoteLayerTreeContext->backingStoreCollection().markAllBackingStoreVolatileImmediatelyIfPossible();
419 }
420
421 PassRefPtr<RemoteLayerTreeDrawingArea::BackingStoreFlusher> RemoteLayerTreeDrawingArea::BackingStoreFlusher::create(IPC::Connection* connection, std::unique_ptr<IPC::MessageEncoder> encoder, Vector<RetainPtr<CGContextRef>> contextsToFlush)
422 {
423     return adoptRef(new RemoteLayerTreeDrawingArea::BackingStoreFlusher(connection, WTF::move(encoder), WTF::move(contextsToFlush)));
424 }
425
426 RemoteLayerTreeDrawingArea::BackingStoreFlusher::BackingStoreFlusher(IPC::Connection* connection, std::unique_ptr<IPC::MessageEncoder> encoder, Vector<RetainPtr<CGContextRef>> contextsToFlush)
427     : m_connection(connection)
428     , m_commitEncoder(WTF::move(encoder))
429     , m_contextsToFlush(WTF::move(contextsToFlush))
430     , m_hasFlushed(false)
431 {
432 }
433
434 void RemoteLayerTreeDrawingArea::BackingStoreFlusher::flush()
435 {
436     ASSERT(!m_hasFlushed);
437
438     for (auto& context : m_contextsToFlush)
439         CGContextFlush(context.get());
440     m_hasFlushed = true;
441
442     m_connection->sendMessage(WTF::move(m_commitEncoder));
443 }
444
445 void RemoteLayerTreeDrawingArea::viewStateDidChange(ViewState::Flags, bool wantsDidUpdateViewState)
446 {
447     // FIXME: Should we suspend painting while not visible, like TiledCoreAnimationDrawingArea? Probably.
448
449     if (wantsDidUpdateViewState)
450         scheduleCompositingLayerFlushImmediately();
451 }
452
453 void RemoteLayerTreeDrawingArea::addTransactionCallbackID(uint64_t callbackID)
454 {
455     m_pendingCallbackIDs.append(static_cast<RemoteLayerTreeTransaction::TransactionCallbackID>(callbackID));
456     scheduleCompositingLayerFlush();
457 }
458
459 } // namespace WebKit