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