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