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