837d6c5066502373508fe2494807d10b6233469f
[WebKit-https.git] / Source / WebKit / WebProcess / WebPage / RemoteLayerTree / RemoteLayerTreeDrawingArea.mm
1 /*
2  * Copyright (C) 2012-2018 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 <QuartzCore/QuartzCore.h>
41 #import <WebCore/DebugPageOverlays.h>
42 #import <WebCore/Frame.h>
43 #import <WebCore/FrameView.h>
44 #import <WebCore/InspectorController.h>
45 #import <WebCore/PageOverlayController.h>
46 #import <WebCore/RenderLayerCompositor.h>
47 #import <WebCore/RenderView.h>
48 #import <WebCore/Settings.h>
49 #import <WebCore/TiledBacking.h>
50 #import <pal/spi/cocoa/QuartzCoreSPI.h>
51 #import <wtf/SystemTracing.h>
52
53 namespace WebKit {
54 using namespace WebCore;
55
56 RemoteLayerTreeDrawingArea::RemoteLayerTreeDrawingArea(WebPage& webPage, const WebPageCreationParameters&)
57     : DrawingArea(DrawingAreaTypeRemoteLayerTree, webPage)
58     , m_remoteLayerTreeContext(std::make_unique<RemoteLayerTreeContext>(webPage))
59     , m_rootLayer(GraphicsLayer::create(graphicsLayerFactory(), *this))
60     , m_layerFlushTimer(*this, &RemoteLayerTreeDrawingArea::flushLayers)
61 {
62     webPage.corePage()->settings().setForceCompositingMode(true);
63 #if PLATFORM(IOS)
64     webPage.corePage()->settings().setDelegatesPageScaling(true);
65 #endif
66     m_rootLayer->setName("drawing area root");
67
68     m_commitQueue = dispatch_queue_create("com.apple.WebKit.WebContent.RemoteLayerTreeDrawingArea.CommitQueue", nullptr);
69
70     // In order to ensure that we get a unique DisplayRefreshMonitor per-DrawingArea (necessary because DisplayRefreshMonitor
71     // is driven by this class), give each page a unique DisplayID derived from WebPage's unique ID.
72     // FIXME: While using the high end of the range of DisplayIDs makes a collision with real, non-RemoteLayerTreeDrawingArea
73     // DisplayIDs less likely, it is not entirely safe to have a RemoteLayerTreeDrawingArea and TiledCoreAnimationDrawingArea
74     // coeexist in the same process.
75     webPage.windowScreenDidChange(std::numeric_limits<uint32_t>::max() - webPage.pageID());
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 RefPtr<DisplayRefreshMonitor> RemoteLayerTreeDrawingArea::createDisplayRefreshMonitor(PlatformDisplayID displayID)
101 {
102     auto monitor = RemoteLayerTreeDisplayRefreshMonitor::create(displayID, *this);
103     m_displayRefreshMonitors.add(monitor.ptr());
104     return WTFMove(monitor);
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::updateRootLayers()
117 {
118     Vector<GraphicsLayer*> children;
119     if (m_contentLayer) {
120         children.append(m_contentLayer);
121         if (m_viewOverlayRootLayer)
122             children.append(m_viewOverlayRootLayer);
123     }
124
125     m_rootLayer->setChildren(children);
126 }
127
128 void RemoteLayerTreeDrawingArea::attachViewOverlayGraphicsLayer(Frame* frame, GraphicsLayer* viewOverlayRootLayer)
129 {
130     if (!frame->isMainFrame())
131         return;
132
133     m_viewOverlayRootLayer = viewOverlayRootLayer;
134     updateRootLayers();
135 }
136
137 void RemoteLayerTreeDrawingArea::setRootCompositingLayer(GraphicsLayer* rootLayer)
138 {
139     m_contentLayer = rootLayer;
140     updateRootLayers();
141     scheduleCompositingLayerFlush();
142 }
143
144 void RemoteLayerTreeDrawingArea::updateGeometry(const IntSize& viewSize, bool flushSynchronously, const WTF::MachSendRight&)
145 {
146     m_viewSize = viewSize;
147     m_webPage.setSize(viewSize);
148
149     scheduleCompositingLayerFlush();
150
151     m_webPage.send(Messages::DrawingAreaProxy::DidUpdateGeometry());
152 }
153
154 bool RemoteLayerTreeDrawingArea::shouldUseTiledBackingForFrameView(const FrameView& frameView)
155 {
156     return frameView.frame().isMainFrame() || m_webPage.corePage()->settings().asyncFrameScrollingEnabled();
157 }
158
159 void RemoteLayerTreeDrawingArea::updatePreferences(const WebPreferencesStore&)
160 {
161     Settings& settings = m_webPage.corePage()->settings();
162
163     // Fixed position elements need to be composited and create stacking contexts
164     // in order to be scrolled by the ScrollingCoordinator.
165     settings.setAcceleratedCompositingForFixedPositionEnabled(true);
166
167     m_rootLayer->setShowDebugBorder(settings.showDebugBorders());
168
169     DebugPageOverlays::settingsChanged(*m_webPage.corePage());
170 }
171
172 #if PLATFORM(IOS)
173 void RemoteLayerTreeDrawingArea::setDeviceScaleFactor(float deviceScaleFactor)
174 {
175     m_webPage.setDeviceScaleFactor(deviceScaleFactor);
176 }
177 #endif
178
179 void RemoteLayerTreeDrawingArea::setLayerTreeStateIsFrozen(bool isFrozen)
180 {
181     if (m_isFlushingSuspended == isFrozen)
182         return;
183
184     m_isFlushingSuspended = isFrozen;
185
186     if (!m_isFlushingSuspended && m_hasDeferredFlush) {
187         m_hasDeferredFlush = false;
188         scheduleCompositingLayerFlush();
189     }
190 }
191
192 void RemoteLayerTreeDrawingArea::forceRepaint()
193 {
194     if (m_isFlushingSuspended)
195         return;
196
197     for (Frame* frame = &m_webPage.corePage()->mainFrame(); frame; frame = frame->tree().traverseNext()) {
198         FrameView* frameView = frame->view();
199         if (!frameView || !frameView->tiledBacking())
200             continue;
201
202         frameView->tiledBacking()->forceRepaint();
203     }
204
205     flushLayers();
206 }
207
208 void RemoteLayerTreeDrawingArea::acceleratedAnimationDidStart(uint64_t layerID, const String& key, MonotonicTime startTime)
209 {
210     m_remoteLayerTreeContext->animationDidStart(layerID, key, startTime);
211 }
212
213 void RemoteLayerTreeDrawingArea::acceleratedAnimationDidEnd(uint64_t layerID, const String& key)
214 {
215     m_remoteLayerTreeContext->animationDidEnd(layerID, key);
216 }
217
218 void RemoteLayerTreeDrawingArea::setViewExposedRect(std::optional<WebCore::FloatRect> viewExposedRect)
219 {
220     m_viewExposedRect = viewExposedRect;
221     updateScrolledExposedRect();
222 }
223
224 #if PLATFORM(IOS)
225 WebCore::FloatRect RemoteLayerTreeDrawingArea::exposedContentRect() const
226 {
227     FrameView* frameView = m_webPage.mainFrameView();
228     if (!frameView)
229         return FloatRect();
230
231     return frameView->exposedContentRect();
232 }
233
234 void RemoteLayerTreeDrawingArea::setExposedContentRect(const FloatRect& exposedContentRect)
235 {
236     FrameView* frameView = m_webPage.mainFrameView();
237     if (!frameView)
238         return;
239     if (frameView->exposedContentRect() == exposedContentRect)
240         return;
241
242     frameView->setExposedContentRect(exposedContentRect);
243     scheduleCompositingLayerFlush();
244 }
245 #endif
246
247 void RemoteLayerTreeDrawingArea::updateScrolledExposedRect()
248 {
249     FrameView* frameView = m_webPage.mainFrameView();
250     if (!frameView)
251         return;
252
253     m_scrolledViewExposedRect = m_viewExposedRect;
254
255 #if !PLATFORM(IOS)
256     if (m_viewExposedRect) {
257         ScrollOffset scrollOffset = frameView->scrollOffsetFromPosition(frameView->scrollPosition());
258         m_scrolledViewExposedRect.value().moveBy(scrollOffset);
259     }
260 #endif
261
262     frameView->setViewExposedRect(m_scrolledViewExposedRect);
263 }
264
265 TiledBacking* RemoteLayerTreeDrawingArea::mainFrameTiledBacking() const
266 {
267     FrameView* frameView = m_webPage.mainFrameView();
268     return frameView ? frameView->tiledBacking() : nullptr;
269 }
270
271 void RemoteLayerTreeDrawingArea::scheduleCompositingLayerFlushImmediately()
272 {
273     m_layerFlushTimer.startOneShot(0_s);
274 }
275
276 void RemoteLayerTreeDrawingArea::scheduleCompositingLayerFlush()
277 {
278     if (m_isFlushingSuspended) {
279         m_isLayerFlushThrottlingTemporarilyDisabledForInteraction = false;
280         m_hasDeferredFlush = true;
281         return;
282     }
283     if (m_isLayerFlushThrottlingTemporarilyDisabledForInteraction) {
284         m_isLayerFlushThrottlingTemporarilyDisabledForInteraction = false;
285         scheduleCompositingLayerFlushImmediately();
286         return;
287     }
288
289     if (m_layerFlushTimer.isActive())
290         return;
291
292     const Seconds initialFlushDelay = 500_ms;
293     const Seconds flushDelay = 1500_ms;
294     Seconds throttleDelay = m_isThrottlingLayerFlushes ? (m_isInitialThrottledLayerFlush ? initialFlushDelay : flushDelay) : 0_s;
295     m_isInitialThrottledLayerFlush = false;
296
297     m_layerFlushTimer.startOneShot(throttleDelay);
298 }
299
300 bool RemoteLayerTreeDrawingArea::adjustLayerFlushThrottling(WebCore::LayerFlushThrottleState::Flags flags)
301 {
302     if (flags & WebCore::LayerFlushThrottleState::UserIsInteracting)
303         m_isLayerFlushThrottlingTemporarilyDisabledForInteraction = true;
304
305     bool wasThrottlingLayerFlushes = m_isThrottlingLayerFlushes;
306     m_isThrottlingLayerFlushes = flags & WebCore::LayerFlushThrottleState::Enabled;
307
308     if (!wasThrottlingLayerFlushes && m_isThrottlingLayerFlushes)
309         m_isInitialThrottledLayerFlush = true;
310
311     // Re-schedule the flush if we stopped throttling.
312     if (wasThrottlingLayerFlushes && !m_isThrottlingLayerFlushes && m_layerFlushTimer.isActive()) {
313         m_layerFlushTimer.stop();
314         scheduleCompositingLayerFlush();
315     }
316     return true;
317 }
318
319 void RemoteLayerTreeDrawingArea::flushLayers()
320 {
321     if (!m_rootLayer)
322         return;
323
324     if (m_isFlushingSuspended) {
325         m_hasDeferredFlush = true;
326         return;
327     }
328
329     if (m_waitingForBackingStoreSwap) {
330         m_hadFlushDeferredWhileWaitingForBackingStoreSwap = true;
331         return;
332     }
333
334     RELEASE_ASSERT(!m_pendingBackingStoreFlusher || m_pendingBackingStoreFlusher->hasFlushed());
335
336     RemoteLayerBackingStoreCollection& backingStoreCollection = m_remoteLayerTreeContext->backingStoreCollection();
337     backingStoreCollection.willFlushLayers();
338
339     m_webPage.layoutIfNeeded();
340
341     FloatRect visibleRect(FloatPoint(), m_viewSize);
342     if (m_scrolledViewExposedRect)
343         visibleRect.intersect(m_scrolledViewExposedRect.value());
344
345     RefPtr<WebPage> protectedWebPage = &m_webPage;
346     [CATransaction addCommitHandler:[protectedWebPage] {
347         if (Page* corePage = protectedWebPage->corePage()) {
348             if (Frame* coreFrame = protectedWebPage->mainFrame())
349                 corePage->inspectorController().didComposite(*coreFrame);
350         }
351     } forPhase:kCATransactionPhasePostCommit];
352
353     if (m_nextFlushIsForImmediatePaint)
354         m_webPage.mainFrameView()->invalidateImagesWithAsyncDecodes();
355
356     m_webPage.mainFrameView()->flushCompositingStateIncludingSubframes();
357
358     // Because our view-relative overlay root layer is not attached to the FrameView's GraphicsLayer tree, we need to flush it manually.
359     if (m_viewOverlayRootLayer)
360         m_viewOverlayRootLayer->flushCompositingState(visibleRect);
361
362     m_rootLayer->flushCompositingStateForThisLayerOnly();
363
364     // FIXME: Minimize these transactions if nothing changed.
365     RemoteLayerTreeTransaction layerTransaction;
366     layerTransaction.setTransactionID(takeNextTransactionID());
367     layerTransaction.setCallbackIDs(WTFMove(m_pendingCallbackIDs));
368     m_remoteLayerTreeContext->setNextFlushIsForImmediatePaint(m_nextFlushIsForImmediatePaint);
369     m_remoteLayerTreeContext->buildTransaction(layerTransaction, *downcast<GraphicsLayerCARemote>(*m_rootLayer).platformCALayer());
370     m_remoteLayerTreeContext->setNextFlushIsForImmediatePaint(false);
371     backingStoreCollection.willCommitLayerTree(layerTransaction);
372     m_webPage.willCommitLayerTree(layerTransaction);
373
374     layerTransaction.setNewlyReachedLayoutMilestones(m_pendingNewlyReachedLayoutMilestones);
375     m_pendingNewlyReachedLayoutMilestones = 0;
376
377     layerTransaction.setActivityStateChangeID(m_activityStateChangeID);
378     m_activityStateChangeID = ActivityStateChangeAsynchronous;
379
380     RemoteScrollingCoordinatorTransaction scrollingTransaction;
381 #if ENABLE(ASYNC_SCROLLING)
382     if (m_webPage.scrollingCoordinator())
383         downcast<RemoteScrollingCoordinator>(*m_webPage.scrollingCoordinator()).buildTransaction(scrollingTransaction);
384 #endif
385
386     m_nextFlushIsForImmediatePaint = false;
387     m_waitingForBackingStoreSwap = true;
388
389     m_webPage.send(Messages::RemoteLayerTreeDrawingAreaProxy::WillCommitLayerTree(layerTransaction.transactionID()));
390
391     Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree message(layerTransaction, scrollingTransaction);
392     auto commitEncoder = std::make_unique<IPC::Encoder>(Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::receiverName(), Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::name(), m_webPage.pageID());
393     commitEncoder->encode(message.arguments());
394
395     // FIXME: Move all backing store flushing management to RemoteLayerBackingStoreCollection.
396     bool hadAnyChangedBackingStore = false;
397     Vector<RetainPtr<CGContextRef>> contextsToFlush;
398     for (auto& layer : layerTransaction.changedLayers()) {
399         if (layer->properties().changedProperties & RemoteLayerTreeTransaction::BackingStoreChanged) {
400             hadAnyChangedBackingStore = true;
401             if (layer->properties().backingStore) {
402                 if (auto contextPendingFlush = layer->properties().backingStore->takeFrontContextPendingFlush())
403                     contextsToFlush.append(contextPendingFlush);
404             }
405         }
406
407         layer->didCommit();
408     }
409
410     backingStoreCollection.didFlushLayers();
411
412     if (hadAnyChangedBackingStore)
413         backingStoreCollection.scheduleVolatilityTimer();
414
415     RefPtr<BackingStoreFlusher> backingStoreFlusher = BackingStoreFlusher::create(WebProcess::singleton().parentProcessConnection(), WTFMove(commitEncoder), WTFMove(contextsToFlush));
416     m_pendingBackingStoreFlusher = backingStoreFlusher;
417
418     uint64_t pageID = m_webPage.pageID();
419     dispatch_async(m_commitQueue, [backingStoreFlusher, pageID] {
420         backingStoreFlusher->flush();
421
422         MonotonicTime timestamp = MonotonicTime::now();
423         dispatch_async(dispatch_get_main_queue(), [pageID, timestamp] {
424             if (WebPage* webPage = WebProcess::singleton().webPage(pageID))
425                 webPage->didFlushLayerTreeAtTime(timestamp);
426         });
427     });
428 }
429
430 void RemoteLayerTreeDrawingArea::didUpdate()
431 {
432     // FIXME: This should use a counted replacement for setLayerTreeStateIsFrozen, but
433     // the callers of that function are not strictly paired.
434
435     m_waitingForBackingStoreSwap = false;
436
437     if (m_hadFlushDeferredWhileWaitingForBackingStoreSwap) {
438         scheduleCompositingLayerFlush();
439         m_hadFlushDeferredWhileWaitingForBackingStoreSwap = false;
440     }
441
442     // This empty transaction serves to trigger CA's garbage collection of IOSurfaces. See <rdar://problem/16110687>
443     [CATransaction begin];
444     [CATransaction commit];
445
446     HashSet<RemoteLayerTreeDisplayRefreshMonitor*> monitorsToNotify = m_displayRefreshMonitors;
447     ASSERT(!m_displayRefreshMonitorsToNotify);
448     m_displayRefreshMonitorsToNotify = &monitorsToNotify;
449     while (!monitorsToNotify.isEmpty())
450         monitorsToNotify.takeAny()->didUpdateLayers();
451     m_displayRefreshMonitorsToNotify = nullptr;
452 }
453
454 void RemoteLayerTreeDrawingArea::mainFrameContentSizeChanged(const IntSize& contentsSize)
455 {
456     m_rootLayer->setSize(contentsSize);
457 }
458
459 bool RemoteLayerTreeDrawingArea::markLayersVolatileImmediatelyIfPossible()
460 {
461     return m_remoteLayerTreeContext->backingStoreCollection().markAllBackingStoreVolatileImmediatelyIfPossible();
462 }
463
464 Ref<RemoteLayerTreeDrawingArea::BackingStoreFlusher> RemoteLayerTreeDrawingArea::BackingStoreFlusher::create(IPC::Connection* connection, std::unique_ptr<IPC::Encoder> encoder, Vector<RetainPtr<CGContextRef>> contextsToFlush)
465 {
466     return adoptRef(*new RemoteLayerTreeDrawingArea::BackingStoreFlusher(connection, WTFMove(encoder), WTFMove(contextsToFlush)));
467 }
468
469 RemoteLayerTreeDrawingArea::BackingStoreFlusher::BackingStoreFlusher(IPC::Connection* connection, std::unique_ptr<IPC::Encoder> encoder, Vector<RetainPtr<CGContextRef>> contextsToFlush)
470     : m_connection(connection)
471     , m_commitEncoder(WTFMove(encoder))
472     , m_contextsToFlush(WTFMove(contextsToFlush))
473     , m_hasFlushed(false)
474 {
475 }
476
477 void RemoteLayerTreeDrawingArea::BackingStoreFlusher::flush()
478 {
479     ASSERT(!m_hasFlushed);
480
481     TraceScope tracingScope(BackingStoreFlushStart, BackingStoreFlushEnd);
482     
483     for (auto& context : m_contextsToFlush)
484         CGContextFlush(context.get());
485     m_hasFlushed = true;
486
487     m_connection->sendMessage(WTFMove(m_commitEncoder), { });
488 }
489
490 void RemoteLayerTreeDrawingArea::activityStateDidChange(OptionSet<WebCore::ActivityState::Flag>, ActivityStateChangeID activityStateChangeID, const Vector<CallbackID>&)
491 {
492     // FIXME: Should we suspend painting while not visible, like TiledCoreAnimationDrawingArea? Probably.
493
494     if (activityStateChangeID != ActivityStateChangeAsynchronous) {
495         m_nextFlushIsForImmediatePaint = true;
496         m_activityStateChangeID = activityStateChangeID;
497         scheduleCompositingLayerFlushImmediately();
498     }
499 }
500
501 void RemoteLayerTreeDrawingArea::addTransactionCallbackID(CallbackID callbackID)
502 {
503     // Assume that if someone is listening for this transaction's completion, that they want it to
504     // be a "complete" paint (including images that would normally be asynchronously decoding).
505     m_nextFlushIsForImmediatePaint = true;
506
507     m_pendingCallbackIDs.append(static_cast<RemoteLayerTreeTransaction::TransactionCallbackID>(callbackID));
508     scheduleCompositingLayerFlush();
509 }
510
511 bool RemoteLayerTreeDrawingArea::dispatchDidReachLayoutMilestone(WebCore::LayoutMilestones layoutMilestones)
512 {
513     m_pendingNewlyReachedLayoutMilestones |= layoutMilestones;
514     return true;
515 }
516
517 } // namespace WebKit