Crash removing RemoteLayerTreeDisplayRefreshMonitor from the drawing area's map
[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     // In order to ensure that we get a unique DisplayRefreshMonitor per-DrawingArea (necessary because DisplayRefreshMonitor
82     // is driven by this class), give each page a unique DisplayID derived from WebPage's unique ID.
83     // FIXME: While using the high end of the range of DisplayIDs makes a collision with real, non-RemoteLayerTreeDrawingArea
84     // DisplayIDs less likely, it is not entirely safe to have a RemoteLayerTreeDrawingArea and TiledCoreAnimationDrawingArea
85     // coeexist in the same process.
86     webPage.windowScreenDidChange(std::numeric_limits<uint32_t>::max() - webPage.pageID());
87 }
88
89 RemoteLayerTreeDrawingArea::~RemoteLayerTreeDrawingArea()
90 {
91     dispatch_release(m_commitQueue);
92 }
93
94 void RemoteLayerTreeDrawingArea::setNeedsDisplay()
95 {
96 }
97
98 void RemoteLayerTreeDrawingArea::setNeedsDisplayInRect(const IntRect&)
99 {
100 }
101
102 void RemoteLayerTreeDrawingArea::scroll(const IntRect& scrollRect, const IntSize& scrollDelta)
103 {
104 }
105
106 GraphicsLayerFactory* RemoteLayerTreeDrawingArea::graphicsLayerFactory()
107 {
108     return m_remoteLayerTreeContext.get();
109 }
110
111 PassRefPtr<DisplayRefreshMonitor> RemoteLayerTreeDrawingArea::createDisplayRefreshMonitor(PlatformDisplayID displayID)
112 {
113     RefPtr<RemoteLayerTreeDisplayRefreshMonitor> monitor = RemoteLayerTreeDisplayRefreshMonitor::create(displayID, *this);
114     m_displayRefreshMonitors.add(monitor.get());
115     return monitor.release();
116 }
117
118 void RemoteLayerTreeDrawingArea::willDestroyDisplayRefreshMonitor(DisplayRefreshMonitor* monitor)
119 {
120     auto remoteMonitor = static_cast<RemoteLayerTreeDisplayRefreshMonitor*>(monitor);
121     m_displayRefreshMonitors.remove(remoteMonitor);
122
123     if (m_displayRefreshMonitorsToNotify)
124         m_displayRefreshMonitorsToNotify->remove(remoteMonitor);
125 }
126
127 void RemoteLayerTreeDrawingArea::updateRootLayers()
128 {
129     Vector<GraphicsLayer*> children;
130     if (m_contentLayer) {
131         children.append(m_contentLayer);
132         if (m_viewOverlayRootLayer)
133             children.append(m_viewOverlayRootLayer);
134     }
135
136     m_rootLayer->setChildren(children);
137 }
138
139 void RemoteLayerTreeDrawingArea::attachViewOverlayGraphicsLayer(Frame* frame, GraphicsLayer* viewOverlayRootLayer)
140 {
141     if (!frame->isMainFrame())
142         return;
143
144     m_viewOverlayRootLayer = viewOverlayRootLayer;
145     updateRootLayers();
146 }
147
148 void RemoteLayerTreeDrawingArea::setRootCompositingLayer(GraphicsLayer* rootLayer)
149 {
150     m_contentLayer = rootLayer;
151     updateRootLayers();
152     scheduleCompositingLayerFlush();
153 }
154
155 void RemoteLayerTreeDrawingArea::updateGeometry(const IntSize& viewSize, const IntSize& layerPosition)
156 {
157     m_viewSize = viewSize;
158     m_webPage.setSize(viewSize);
159
160     scheduleCompositingLayerFlush();
161
162     m_webPage.send(Messages::DrawingAreaProxy::DidUpdateGeometry());
163 }
164
165 bool RemoteLayerTreeDrawingArea::shouldUseTiledBackingForFrameView(const FrameView* frameView)
166 {
167     return frameView && frameView->frame().isMainFrame();
168 }
169
170 void RemoteLayerTreeDrawingArea::updatePreferences(const WebPreferencesStore&)
171 {
172     Settings& settings = m_webPage.corePage()->settings();
173
174     // Fixed position elements need to be composited and create stacking contexts
175     // in order to be scrolled by the ScrollingCoordinator.
176     settings.setAcceleratedCompositingForFixedPositionEnabled(true);
177     settings.setFixedPositionCreatesStackingContext(true);
178
179     m_rootLayer->setShowDebugBorder(settings.showDebugBorders());
180
181     if (MainFrame* mainFrame = m_webPage.mainFrame())
182         DebugPageOverlays::settingsChanged(*mainFrame);
183 }
184
185 #if PLATFORM(IOS)
186 void RemoteLayerTreeDrawingArea::setDeviceScaleFactor(float deviceScaleFactor)
187 {
188     m_webPage.setDeviceScaleFactor(deviceScaleFactor);
189 }
190 #endif
191
192 void RemoteLayerTreeDrawingArea::setLayerTreeStateIsFrozen(bool isFrozen)
193 {
194     if (m_isFlushingSuspended == isFrozen)
195         return;
196
197     m_isFlushingSuspended = isFrozen;
198
199     if (!m_isFlushingSuspended && m_hasDeferredFlush) {
200         m_hasDeferredFlush = false;
201         scheduleCompositingLayerFlush();
202     }
203 }
204
205 void RemoteLayerTreeDrawingArea::forceRepaint()
206 {
207     if (m_isFlushingSuspended)
208         return;
209
210     for (Frame* frame = &m_webPage.corePage()->mainFrame(); frame; frame = frame->tree().traverseNext()) {
211         FrameView* frameView = frame->view();
212         if (!frameView || !frameView->tiledBacking())
213             continue;
214
215         frameView->tiledBacking()->forceRepaint();
216     }
217
218     flushLayers();
219 }
220
221 void RemoteLayerTreeDrawingArea::acceleratedAnimationDidStart(uint64_t layerID, const String& key, double startTime)
222 {
223     m_remoteLayerTreeContext->animationDidStart(layerID, key, startTime);
224 }
225
226 void RemoteLayerTreeDrawingArea::acceleratedAnimationDidEnd(uint64_t layerID, const String& key)
227 {
228     m_remoteLayerTreeContext->animationDidEnd(layerID, key);
229 }
230
231 void RemoteLayerTreeDrawingArea::setExposedRect(const FloatRect& exposedRect)
232 {
233     m_exposedRect = exposedRect;
234     updateScrolledExposedRect();
235 }
236
237 #if PLATFORM(IOS)
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_scrolledExposedRect = m_exposedRect;
258
259 #if !PLATFORM(IOS)
260     if (!m_exposedRect.isInfinite()) {
261         IntPoint scrollPositionWithOrigin = frameView->scrollPosition() + toIntSize(frameView->scrollOrigin());
262         m_scrolledExposedRect.moveBy(scrollPositionWithOrigin);
263     }
264 #endif
265
266     frameView->setExposedRect(m_scrolledExposedRect);
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_ms);
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 auto initialFlushDelay = 500_ms;
297     const auto flushDelay = 1500_ms;
298     auto throttleDelay = m_isThrottlingLayerFlushes ? (m_isInitialThrottledLayerFlush ? initialFlushDelay : flushDelay) : 0_ms;
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::layerFlushTimerFired()
324 {
325     flushLayers();
326 }
327
328 void RemoteLayerTreeDrawingArea::flushLayers()
329 {
330     if (!m_rootLayer)
331         return;
332
333     if (m_isFlushingSuspended) {
334         m_hasDeferredFlush = true;
335         return;
336     }
337
338     if (m_waitingForBackingStoreSwap) {
339         m_hadFlushDeferredWhileWaitingForBackingStoreSwap = true;
340         return;
341     }
342
343     RELEASE_ASSERT(!m_pendingBackingStoreFlusher || m_pendingBackingStoreFlusher->hasFlushed());
344
345     RemoteLayerBackingStoreCollection& backingStoreCollection = m_remoteLayerTreeContext->backingStoreCollection();
346     backingStoreCollection.willFlushLayers();
347
348     m_webPage.layoutIfNeeded();
349
350     FloatRect visibleRect(FloatPoint(), m_viewSize);
351     visibleRect.intersect(m_scrolledExposedRect);
352
353     m_webPage.mainFrameView()->flushCompositingStateIncludingSubframes();
354
355     // Because our view-relative overlay root layer is not attached to the FrameView's GraphicsLayer tree, we need to flush it manually.
356     if (m_viewOverlayRootLayer)
357         m_viewOverlayRootLayer->flushCompositingState(visibleRect);
358
359     m_rootLayer->flushCompositingStateForThisLayerOnly();
360
361     // FIXME: Minimize these transactions if nothing changed.
362     RemoteLayerTreeTransaction layerTransaction;
363     layerTransaction.setTransactionID(takeNextTransactionID());
364     layerTransaction.setCallbackIDs(WTF::move(m_pendingCallbackIDs));
365     m_remoteLayerTreeContext->buildTransaction(layerTransaction, *downcast<GraphicsLayerCARemote>(*m_rootLayer).platformCALayer());
366     backingStoreCollection.willCommitLayerTree(layerTransaction);
367     m_webPage.willCommitLayerTree(layerTransaction);
368
369     RemoteScrollingCoordinatorTransaction scrollingTransaction;
370 #if ENABLE(ASYNC_SCROLLING)
371     if (m_webPage.scrollingCoordinator())
372         downcast<RemoteScrollingCoordinator>(*m_webPage.scrollingCoordinator()).buildTransaction(scrollingTransaction);
373 #endif
374
375     m_waitingForBackingStoreSwap = true;
376
377     m_webPage.send(Messages::RemoteLayerTreeDrawingAreaProxy::WillCommitLayerTree(layerTransaction.transactionID()));
378
379     Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree message(layerTransaction, scrollingTransaction);
380     auto commitEncoder = std::make_unique<IPC::MessageEncoder>(Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::receiverName(), Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree::name(), m_webPage.pageID());
381     commitEncoder->encode(message.arguments());
382
383     // FIXME: Move all backing store flushing management to RemoteLayerBackingStoreCollection.
384     bool hadAnyChangedBackingStore = false;
385     Vector<RetainPtr<CGContextRef>> contextsToFlush;
386     for (auto& layer : layerTransaction.changedLayers()) {
387         if (layer->properties().changedProperties & RemoteLayerTreeTransaction::LayerChanges::BackingStoreChanged) {
388             hadAnyChangedBackingStore = true;
389             if (layer->properties().backingStore) {
390                 if (auto contextPendingFlush = layer->properties().backingStore->takeFrontContextPendingFlush())
391                     contextsToFlush.append(contextPendingFlush);
392             }
393         }
394
395         layer->didCommit();
396     }
397
398     backingStoreCollection.didFlushLayers();
399
400     if (hadAnyChangedBackingStore)
401         backingStoreCollection.scheduleVolatilityTimer();
402
403     RefPtr<BackingStoreFlusher> backingStoreFlusher = BackingStoreFlusher::create(WebProcess::singleton().parentProcessConnection(), WTF::move(commitEncoder), WTF::move(contextsToFlush));
404     m_pendingBackingStoreFlusher = backingStoreFlusher;
405
406     uint64_t pageID = m_webPage.pageID();
407     dispatch_async(m_commitQueue, [backingStoreFlusher, pageID] {
408         backingStoreFlusher->flush();
409
410         std::chrono::milliseconds timestamp = std::chrono::milliseconds(static_cast<std::chrono::milliseconds::rep>(monotonicallyIncreasingTime() * 1000));
411         dispatch_async(dispatch_get_main_queue(), [pageID, timestamp] {
412             if (WebPage* webPage = WebProcess::singleton().webPage(pageID))
413                 webPage->didFlushLayerTreeAtTime(timestamp);
414         });
415     });
416 }
417
418 void RemoteLayerTreeDrawingArea::didUpdate()
419 {
420     // FIXME: This should use a counted replacement for setLayerTreeStateIsFrozen, but
421     // the callers of that function are not strictly paired.
422
423     m_waitingForBackingStoreSwap = false;
424
425     if (m_hadFlushDeferredWhileWaitingForBackingStoreSwap) {
426         scheduleCompositingLayerFlush();
427         m_hadFlushDeferredWhileWaitingForBackingStoreSwap = false;
428     }
429
430     // This empty transaction serves to trigger CA's garbage collection of IOSurfaces. See <rdar://problem/16110687>
431     [CATransaction begin];
432     [CATransaction commit];
433
434     HashSet<RemoteLayerTreeDisplayRefreshMonitor*> monitorsToNotify = m_displayRefreshMonitors;
435     ASSERT(!m_displayRefreshMonitorsToNotify);
436     m_displayRefreshMonitorsToNotify = &monitorsToNotify;
437     while (!monitorsToNotify.isEmpty())
438         monitorsToNotify.takeAny()->didUpdateLayers();
439     m_displayRefreshMonitorsToNotify = nullptr;
440 }
441
442 void RemoteLayerTreeDrawingArea::mainFrameContentSizeChanged(const IntSize& contentsSize)
443 {
444     m_rootLayer->setSize(contentsSize);
445 }
446
447 bool RemoteLayerTreeDrawingArea::markLayersVolatileImmediatelyIfPossible()
448 {
449     return m_remoteLayerTreeContext->backingStoreCollection().markAllBackingStoreVolatileImmediatelyIfPossible();
450 }
451
452 PassRefPtr<RemoteLayerTreeDrawingArea::BackingStoreFlusher> RemoteLayerTreeDrawingArea::BackingStoreFlusher::create(IPC::Connection* connection, std::unique_ptr<IPC::MessageEncoder> encoder, Vector<RetainPtr<CGContextRef>> contextsToFlush)
453 {
454     return adoptRef(new RemoteLayerTreeDrawingArea::BackingStoreFlusher(connection, WTF::move(encoder), WTF::move(contextsToFlush)));
455 }
456
457 RemoteLayerTreeDrawingArea::BackingStoreFlusher::BackingStoreFlusher(IPC::Connection* connection, std::unique_ptr<IPC::MessageEncoder> encoder, Vector<RetainPtr<CGContextRef>> contextsToFlush)
458     : m_connection(connection)
459     , m_commitEncoder(WTF::move(encoder))
460     , m_contextsToFlush(WTF::move(contextsToFlush))
461     , m_hasFlushed(false)
462 {
463 }
464
465 void RemoteLayerTreeDrawingArea::BackingStoreFlusher::flush()
466 {
467     ASSERT(!m_hasFlushed);
468
469     for (auto& context : m_contextsToFlush)
470         CGContextFlush(context.get());
471     m_hasFlushed = true;
472
473     m_connection->sendMessage(WTF::move(m_commitEncoder));
474 }
475
476 void RemoteLayerTreeDrawingArea::viewStateDidChange(ViewState::Flags, bool wantsDidUpdateViewState, const Vector<uint64_t>&)
477 {
478     // FIXME: Should we suspend painting while not visible, like TiledCoreAnimationDrawingArea? Probably.
479
480     if (wantsDidUpdateViewState)
481         scheduleCompositingLayerFlushImmediately();
482 }
483
484 void RemoteLayerTreeDrawingArea::addTransactionCallbackID(uint64_t callbackID)
485 {
486     m_pendingCallbackIDs.append(static_cast<RemoteLayerTreeTransaction::TransactionCallbackID>(callbackID));
487     scheduleCompositingLayerFlush();
488 }
489
490 } // namespace WebKit