0268893498e1440195c5f1f45aa750d892bbe61e
[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 <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/QuartzCoreSPI.h>
48 #import <WebCore/RenderLayerCompositor.h>
49 #import <WebCore/RenderView.h>
50 #import <WebCore/Settings.h>
51 #import <WebCore/TiledBacking.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     , m_weakPtrFactory(this)
64 {
65     webPage.corePage()->settings().setForceCompositingMode(true);
66 #if PLATFORM(IOS)
67     webPage.corePage()->settings().setDelegatesPageScaling(true);
68 #endif
69     m_rootLayer->setName("drawing area root");
70
71     m_commitQueue = dispatch_queue_create("com.apple.WebKit.WebContent.RemoteLayerTreeDrawingArea.CommitQueue", nullptr);
72
73     // In order to ensure that we get a unique DisplayRefreshMonitor per-DrawingArea (necessary because DisplayRefreshMonitor
74     // is driven by this class), give each page a unique DisplayID derived from WebPage's unique ID.
75     // FIXME: While using the high end of the range of DisplayIDs makes a collision with real, non-RemoteLayerTreeDrawingArea
76     // DisplayIDs less likely, it is not entirely safe to have a RemoteLayerTreeDrawingArea and TiledCoreAnimationDrawingArea
77     // coeexist in the same process.
78     webPage.windowScreenDidChange(std::numeric_limits<uint32_t>::max() - webPage.pageID());
79 }
80
81 RemoteLayerTreeDrawingArea::~RemoteLayerTreeDrawingArea()
82 {
83     dispatch_release(m_commitQueue);
84 }
85
86 void RemoteLayerTreeDrawingArea::setNeedsDisplay()
87 {
88 }
89
90 void RemoteLayerTreeDrawingArea::setNeedsDisplayInRect(const IntRect&)
91 {
92 }
93
94 void RemoteLayerTreeDrawingArea::scroll(const IntRect& scrollRect, const IntSize& scrollDelta)
95 {
96 }
97
98 GraphicsLayerFactory* RemoteLayerTreeDrawingArea::graphicsLayerFactory()
99 {
100     return m_remoteLayerTreeContext.get();
101 }
102
103 RefPtr<DisplayRefreshMonitor> RemoteLayerTreeDrawingArea::createDisplayRefreshMonitor(PlatformDisplayID displayID)
104 {
105     auto monitor = RemoteLayerTreeDisplayRefreshMonitor::create(displayID, *this);
106     m_displayRefreshMonitors.add(monitor.ptr());
107     return WTFMove(monitor);
108 }
109
110 void RemoteLayerTreeDrawingArea::willDestroyDisplayRefreshMonitor(DisplayRefreshMonitor* monitor)
111 {
112     auto remoteMonitor = static_cast<RemoteLayerTreeDisplayRefreshMonitor*>(monitor);
113     m_displayRefreshMonitors.remove(remoteMonitor);
114
115     if (m_displayRefreshMonitorsToNotify)
116         m_displayRefreshMonitorsToNotify->remove(remoteMonitor);
117 }
118
119 void RemoteLayerTreeDrawingArea::updateRootLayers()
120 {
121     Vector<GraphicsLayer*> children;
122     if (m_contentLayer) {
123         children.append(m_contentLayer);
124         if (m_viewOverlayRootLayer)
125             children.append(m_viewOverlayRootLayer);
126     }
127
128     m_rootLayer->setChildren(children);
129 }
130
131 void RemoteLayerTreeDrawingArea::attachViewOverlayGraphicsLayer(Frame* frame, GraphicsLayer* viewOverlayRootLayer)
132 {
133     if (!frame->isMainFrame())
134         return;
135
136     m_viewOverlayRootLayer = viewOverlayRootLayer;
137     updateRootLayers();
138 }
139
140 void RemoteLayerTreeDrawingArea::setRootCompositingLayer(GraphicsLayer* rootLayer)
141 {
142     m_contentLayer = rootLayer;
143     updateRootLayers();
144     scheduleCompositingLayerFlush();
145 }
146
147 void RemoteLayerTreeDrawingArea::updateGeometry(const IntSize& viewSize, const IntSize& layerPosition, bool flushSynchronously, const WebCore::MachSendRight&)
148 {
149     m_viewSize = viewSize;
150     m_webPage.setSize(viewSize);
151
152     scheduleCompositingLayerFlush();
153
154     m_webPage.send(Messages::DrawingAreaProxy::DidUpdateGeometry());
155 }
156
157 bool RemoteLayerTreeDrawingArea::shouldUseTiledBackingForFrameView(const FrameView* frameView)
158 {
159     return frameView && frameView->frame().isMainFrame();
160 }
161
162 void RemoteLayerTreeDrawingArea::updatePreferences(const WebPreferencesStore&)
163 {
164     Settings& settings = m_webPage.corePage()->settings();
165
166     // Fixed position elements need to be composited and create stacking contexts
167     // in order to be scrolled by the ScrollingCoordinator.
168     settings.setAcceleratedCompositingForFixedPositionEnabled(true);
169
170     m_rootLayer->setShowDebugBorder(settings.showDebugBorders());
171
172     if (MainFrame* mainFrame = m_webPage.mainFrame())
173         DebugPageOverlays::settingsChanged(*mainFrame);
174 }
175
176 #if PLATFORM(IOS)
177 void RemoteLayerTreeDrawingArea::setDeviceScaleFactor(float deviceScaleFactor)
178 {
179     m_webPage.setDeviceScaleFactor(deviceScaleFactor);
180 }
181 #endif
182
183 void RemoteLayerTreeDrawingArea::setLayerTreeStateIsFrozen(bool isFrozen)
184 {
185     if (m_isFlushingSuspended == isFrozen)
186         return;
187
188     m_isFlushingSuspended = isFrozen;
189
190     if (!m_isFlushingSuspended && m_hasDeferredFlush) {
191         m_hasDeferredFlush = false;
192         scheduleCompositingLayerFlush();
193     }
194 }
195
196 void RemoteLayerTreeDrawingArea::forceRepaint()
197 {
198     if (m_isFlushingSuspended)
199         return;
200
201     for (Frame* frame = &m_webPage.corePage()->mainFrame(); frame; frame = frame->tree().traverseNext()) {
202         FrameView* frameView = frame->view();
203         if (!frameView || !frameView->tiledBacking())
204             continue;
205
206         frameView->tiledBacking()->forceRepaint();
207     }
208
209     flushLayers();
210 }
211
212 void RemoteLayerTreeDrawingArea::acceleratedAnimationDidStart(uint64_t layerID, const String& key, double startTime)
213 {
214     m_remoteLayerTreeContext->animationDidStart(layerID, key, startTime);
215 }
216
217 void RemoteLayerTreeDrawingArea::acceleratedAnimationDidEnd(uint64_t layerID, const String& key)
218 {
219     m_remoteLayerTreeContext->animationDidEnd(layerID, key);
220 }
221
222 void RemoteLayerTreeDrawingArea::setViewExposedRect(std::optional<WebCore::FloatRect> viewExposedRect)
223 {
224     m_viewExposedRect = viewExposedRect;
225     updateScrolledExposedRect();
226 }
227
228 #if PLATFORM(IOS)
229 WebCore::FloatRect RemoteLayerTreeDrawingArea::exposedContentRect() const
230 {
231     FrameView* frameView = m_webPage.mainFrameView();
232     if (!frameView)
233         return FloatRect();
234
235     return frameView->exposedContentRect();
236 }
237
238 void RemoteLayerTreeDrawingArea::setExposedContentRect(const FloatRect& exposedContentRect)
239 {
240     FrameView* frameView = m_webPage.mainFrameView();
241     if (!frameView)
242         return;
243     if (frameView->exposedContentRect() == exposedContentRect)
244         return;
245
246     frameView->setExposedContentRect(exposedContentRect);
247     scheduleCompositingLayerFlush();
248 }
249 #endif
250
251 void RemoteLayerTreeDrawingArea::updateScrolledExposedRect()
252 {
253     FrameView* frameView = m_webPage.mainFrameView();
254     if (!frameView)
255         return;
256
257     m_scrolledViewExposedRect = m_viewExposedRect;
258
259 #if !PLATFORM(IOS)
260     if (m_viewExposedRect) {
261         ScrollOffset scrollOffset = frameView->scrollOffsetFromPosition(frameView->scrollPosition());
262         m_scrolledViewExposedRect.value().moveBy(scrollOffset);
263     }
264 #endif
265
266     frameView->setViewExposedRect(m_scrolledViewExposedRect);
267 }
268
269 TiledBacking* RemoteLayerTreeDrawingArea::mainFrameTiledBacking() const
270 {
271     FrameView* frameView = m_webPage.mainFrameView();
272     return frameView ? frameView->tiledBacking() : nullptr;
273 }
274
275 void RemoteLayerTreeDrawingArea::scheduleCompositingLayerFlushImmediately()
276 {
277     m_layerFlushTimer.startOneShot(0_s);
278 }
279
280 void RemoteLayerTreeDrawingArea::scheduleCompositingLayerFlush()
281 {
282     if (m_isFlushingSuspended) {
283         m_isLayerFlushThrottlingTemporarilyDisabledForInteraction = false;
284         m_hasDeferredFlush = true;
285         return;
286     }
287     if (m_isLayerFlushThrottlingTemporarilyDisabledForInteraction) {
288         m_isLayerFlushThrottlingTemporarilyDisabledForInteraction = false;
289         scheduleCompositingLayerFlushImmediately();
290         return;
291     }
292
293     if (m_layerFlushTimer.isActive())
294         return;
295
296     const Seconds initialFlushDelay = 500_ms;
297     const Seconds flushDelay = 1500_ms;
298     Seconds throttleDelay = m_isThrottlingLayerFlushes ? (m_isInitialThrottledLayerFlush ? initialFlushDelay : flushDelay) : 0_s;
299     m_isInitialThrottledLayerFlush = false;
300
301     m_layerFlushTimer.startOneShot(throttleDelay);
302 }
303
304 bool RemoteLayerTreeDrawingArea::adjustLayerFlushThrottling(WebCore::LayerFlushThrottleState::Flags flags)
305 {
306     if (flags & WebCore::LayerFlushThrottleState::UserIsInteracting)
307         m_isLayerFlushThrottlingTemporarilyDisabledForInteraction = true;
308
309     bool wasThrottlingLayerFlushes = m_isThrottlingLayerFlushes;
310     m_isThrottlingLayerFlushes = flags & WebCore::LayerFlushThrottleState::Enabled;
311
312     if (!wasThrottlingLayerFlushes && m_isThrottlingLayerFlushes)
313         m_isInitialThrottledLayerFlush = true;
314
315     // Re-schedule the flush if we stopped throttling.
316     if (wasThrottlingLayerFlushes && !m_isThrottlingLayerFlushes && m_layerFlushTimer.isActive()) {
317         m_layerFlushTimer.stop();
318         scheduleCompositingLayerFlush();
319     }
320     return true;
321 }
322
323 void RemoteLayerTreeDrawingArea::flushLayers()
324 {
325     if (!m_rootLayer)
326         return;
327
328     if (m_isFlushingSuspended) {
329         m_hasDeferredFlush = true;
330         return;
331     }
332
333     if (m_waitingForBackingStoreSwap) {
334         m_hadFlushDeferredWhileWaitingForBackingStoreSwap = true;
335         return;
336     }
337
338     RELEASE_ASSERT(!m_pendingBackingStoreFlusher || m_pendingBackingStoreFlusher->hasFlushed());
339
340     RemoteLayerBackingStoreCollection& backingStoreCollection = m_remoteLayerTreeContext->backingStoreCollection();
341     backingStoreCollection.willFlushLayers();
342
343     m_webPage.layoutIfNeeded();
344
345     FloatRect visibleRect(FloatPoint(), m_viewSize);
346     if (m_scrolledViewExposedRect)
347         visibleRect.intersect(m_scrolledViewExposedRect.value());
348
349 #if PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
350     RefPtr<WebPage> retainedPage = &m_webPage;
351     [CATransaction addCommitHandler:[retainedPage] {
352         if (Page* corePage = retainedPage->corePage()) {
353             if (Frame* coreFrame = retainedPage->mainFrame())
354                 corePage->inspectorController().didComposite(*coreFrame);
355         }
356     } forPhase:kCATransactionPhasePostCommit];
357 #endif
358
359     m_webPage.mainFrameView()->flushCompositingStateIncludingSubframes();
360
361     // Because our view-relative overlay root layer is not attached to the FrameView's GraphicsLayer tree, we need to flush it manually.
362     if (m_viewOverlayRootLayer)
363         m_viewOverlayRootLayer->flushCompositingState(visibleRect);
364
365     m_rootLayer->flushCompositingStateForThisLayerOnly();
366
367     // FIXME: Minimize these transactions if nothing changed.
368     RemoteLayerTreeTransaction layerTransaction;
369     layerTransaction.setTransactionID(takeNextTransactionID());
370     layerTransaction.setCallbackIDs(WTFMove(m_pendingCallbackIDs));
371     m_remoteLayerTreeContext->setNextFlushIsForImmediatePaint(m_nextFlushIsForImmediatePaint);
372     m_remoteLayerTreeContext->buildTransaction(layerTransaction, *downcast<GraphicsLayerCARemote>(*m_rootLayer).platformCALayer());
373     m_remoteLayerTreeContext->setNextFlushIsForImmediatePaint(false);
374     backingStoreCollection.willCommitLayerTree(layerTransaction);
375     m_webPage.willCommitLayerTree(layerTransaction);
376
377     layerTransaction.setNewlyReachedLayoutMilestones(m_pendingNewlyReachedLayoutMilestones);
378     m_pendingNewlyReachedLayoutMilestones = 0;
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::LayerChanges::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(ActivityState::Flags, bool wantsDidUpdateActivityState, const Vector<uint64_t>&)
491 {
492     // FIXME: Should we suspend painting while not visible, like TiledCoreAnimationDrawingArea? Probably.
493
494     if (wantsDidUpdateActivityState) {
495         m_nextFlushIsForImmediatePaint = true;
496         scheduleCompositingLayerFlushImmediately();
497     }
498 }
499
500 void RemoteLayerTreeDrawingArea::addTransactionCallbackID(uint64_t callbackID)
501 {
502     m_pendingCallbackIDs.append(static_cast<RemoteLayerTreeTransaction::TransactionCallbackID>(callbackID));
503     scheduleCompositingLayerFlush();
504 }
505
506 bool RemoteLayerTreeDrawingArea::dispatchDidReachLayoutMilestone(WebCore::LayoutMilestones layoutMilestones)
507 {
508     m_pendingNewlyReachedLayoutMilestones |= layoutMilestones;
509     return true;
510 }
511
512 } // namespace WebKit