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