Rollout r231818, as it introduced regression on tickets.com.
[WebKit-https.git] / Source / WebKit / UIProcess / AcceleratedDrawingAreaProxy.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
4  * Copyright (C) 2016 Igalia S.L.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25  * THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "AcceleratedDrawingAreaProxy.h"
30
31 #include "DrawingAreaMessages.h"
32 #include "DrawingAreaProxyMessages.h"
33 #include "LayerTreeContext.h"
34 #include "UpdateInfo.h"
35 #include "WebPageProxy.h"
36 #include "WebPreferences.h"
37 #include "WebProcessProxy.h"
38 #include <WebCore/Region.h>
39
40 #if PLATFORM(WAYLAND)
41 #include "WaylandCompositor.h"
42 #include <WebCore/PlatformDisplay.h>
43 #endif
44
45 namespace WebKit {
46 using namespace WebCore;
47
48 AcceleratedDrawingAreaProxy::AcceleratedDrawingAreaProxy(WebPageProxy& webPageProxy)
49     : DrawingAreaProxy(DrawingAreaTypeImpl, webPageProxy)
50 {
51 }
52
53 AcceleratedDrawingAreaProxy::~AcceleratedDrawingAreaProxy()
54 {
55     // Make sure to exit accelerated compositing mode.
56     if (isInAcceleratedCompositingMode())
57         exitAcceleratedCompositingMode();
58 }
59
60 bool AcceleratedDrawingAreaProxy::alwaysUseCompositing() const
61 {
62     return m_webPageProxy.preferences().acceleratedCompositingEnabled() && m_webPageProxy.preferences().forceCompositingMode();
63 }
64
65 void AcceleratedDrawingAreaProxy::dispatchAfterEnsuringDrawing(WTF::Function<void(CallbackBase::Error)>&& callbackFunction)
66 {
67     if (!m_webPageProxy.isValid()) {
68         callbackFunction(CallbackBase::Error::OwnerWasInvalidated);
69         return;
70     }
71
72     RunLoop::main().dispatch([callbackFunction = WTFMove(callbackFunction)] {
73         callbackFunction(CallbackBase::Error::None);
74     });
75 }
76
77 void AcceleratedDrawingAreaProxy::sizeDidChange()
78 {
79     backingStoreStateDidChange(RespondImmediately);
80 }
81
82 void AcceleratedDrawingAreaProxy::deviceScaleFactorDidChange()
83 {
84     backingStoreStateDidChange(RespondImmediately);
85 }
86
87 void AcceleratedDrawingAreaProxy::visibilityDidChange()
88 {
89     // If we don't have a backing store, go ahead and mark the backing store as being changed so
90     // that when paint we'll actually wait for something to paint and not flash white.
91     if (m_layerTreeContext.isEmpty())
92         backingStoreStateDidChange(DoNotRespondImmediately);
93 }
94
95 void AcceleratedDrawingAreaProxy::waitForBackingStoreUpdateOnNextPaint()
96 {
97     m_hasReceivedFirstUpdate = true;
98 }
99
100 void AcceleratedDrawingAreaProxy::didUpdateBackingStoreState(uint64_t backingStoreStateID, const UpdateInfo& updateInfo, const LayerTreeContext& layerTreeContext)
101 {
102     ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_nextBackingStoreStateID);
103     ASSERT_ARG(backingStoreStateID, backingStoreStateID > m_currentBackingStoreStateID);
104     m_currentBackingStoreStateID = backingStoreStateID;
105
106     m_isWaitingForDidUpdateBackingStoreState = false;
107
108     // Stop the responsiveness timer that was started in sendUpdateBackingStoreState.
109     m_webPageProxy.process().responsivenessTimer().stop();
110
111     if (layerTreeContext != m_layerTreeContext) {
112         if (layerTreeContext.isEmpty() && !m_layerTreeContext.isEmpty()) {
113             exitAcceleratedCompositingMode();
114             ASSERT(m_layerTreeContext.isEmpty());
115         } else if (!layerTreeContext.isEmpty() && m_layerTreeContext.isEmpty()) {
116             enterAcceleratedCompositingMode(layerTreeContext);
117             ASSERT(layerTreeContext == m_layerTreeContext);
118         } else {
119             updateAcceleratedCompositingMode(layerTreeContext);
120             ASSERT(layerTreeContext == m_layerTreeContext);
121         }
122     }
123
124     if (m_nextBackingStoreStateID != m_currentBackingStoreStateID)
125         sendUpdateBackingStoreState(RespondImmediately);
126     else {
127         m_hasReceivedFirstUpdate = true;
128
129 #if USE(TEXTURE_MAPPER_GL) && PLATFORM(GTK) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
130         if (m_pendingNativeSurfaceHandleForCompositing) {
131             setNativeSurfaceHandleForCompositing(m_pendingNativeSurfaceHandleForCompositing);
132             m_pendingNativeSurfaceHandleForCompositing = 0;
133         }
134 #endif
135     }
136 }
137
138 void AcceleratedDrawingAreaProxy::enterAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext& layerTreeContext)
139 {
140     ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
141     if (backingStoreStateID < m_currentBackingStoreStateID)
142         return;
143
144     enterAcceleratedCompositingMode(layerTreeContext);
145 }
146
147 void AcceleratedDrawingAreaProxy::exitAcceleratedCompositingMode(uint64_t backingStoreStateID, const UpdateInfo& updateInfo)
148 {
149     ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
150     if (backingStoreStateID < m_currentBackingStoreStateID)
151         return;
152
153     exitAcceleratedCompositingMode();
154 }
155
156 void AcceleratedDrawingAreaProxy::updateAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext& layerTreeContext)
157 {
158     ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
159     if (backingStoreStateID < m_currentBackingStoreStateID)
160         return;
161
162     updateAcceleratedCompositingMode(layerTreeContext);
163 }
164
165 void AcceleratedDrawingAreaProxy::backingStoreStateDidChange(RespondImmediatelyOrNot respondImmediatelyOrNot)
166 {
167     ++m_nextBackingStoreStateID;
168     sendUpdateBackingStoreState(respondImmediatelyOrNot);
169 }
170
171 void AcceleratedDrawingAreaProxy::sendUpdateBackingStoreState(RespondImmediatelyOrNot respondImmediatelyOrNot)
172 {
173     ASSERT(m_currentBackingStoreStateID < m_nextBackingStoreStateID);
174
175     if (!m_webPageProxy.isValid())
176         return;
177
178     if (m_isWaitingForDidUpdateBackingStoreState)
179         return;
180
181     if (m_webPageProxy.viewSize().isEmpty() && !m_webPageProxy.useFixedLayout())
182         return;
183
184     m_isWaitingForDidUpdateBackingStoreState = respondImmediatelyOrNot == RespondImmediately;
185
186     m_webPageProxy.process().send(Messages::DrawingArea::UpdateBackingStoreState(m_nextBackingStoreStateID, respondImmediatelyOrNot == RespondImmediately, m_webPageProxy.deviceScaleFactor(), m_size, m_scrollOffset), m_webPageProxy.pageID());
187     m_scrollOffset = IntSize();
188
189     if (m_isWaitingForDidUpdateBackingStoreState) {
190         // Start the responsiveness timer. We will stop it when we hear back from the WebProcess
191         // in didUpdateBackingStoreState.
192         m_webPageProxy.process().responsivenessTimer().start();
193     }
194
195     if (m_isWaitingForDidUpdateBackingStoreState && !m_layerTreeContext.isEmpty()) {
196         // Wait for the DidUpdateBackingStoreState message. Normally we do this in AcceleratedDrawingAreaProxy::paint, but that
197         // function is never called when in accelerated compositing mode.
198         waitForAndDispatchDidUpdateBackingStoreState();
199     }
200 }
201
202 void AcceleratedDrawingAreaProxy::waitForAndDispatchDidUpdateBackingStoreState()
203 {
204     ASSERT(m_isWaitingForDidUpdateBackingStoreState);
205
206     if (!m_webPageProxy.isValid())
207         return;
208     if (m_webPageProxy.process().state() == WebProcessProxy::State::Launching)
209         return;
210     if (!m_webPageProxy.isViewVisible())
211         return;
212 #if PLATFORM(WAYLAND) && USE(EGL)
213     // Never block the UI process in Wayland when waiting for DidUpdateBackingStoreState after a resize,
214     // because the nested compositor needs to handle the web process requests that happens while resizing.
215     if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland && isInAcceleratedCompositingMode())
216         return;
217 #endif
218
219     // FIXME: waitForAndDispatchImmediately will always return the oldest DidUpdateBackingStoreState message that
220     // hasn't yet been processed. But it might be better to skip ahead to some other DidUpdateBackingStoreState
221     // message, if multiple DidUpdateBackingStoreState messages are waiting to be processed. For instance, we could
222     // choose the most recent one, or the one that is closest to our current size.
223
224     // The timeout, in seconds, we use when waiting for a DidUpdateBackingStoreState message when we're asked to paint.
225     m_webPageProxy.process().connection()->waitForAndDispatchImmediately<Messages::DrawingAreaProxy::DidUpdateBackingStoreState>(m_webPageProxy.pageID(), Seconds::fromMilliseconds(500));
226 }
227
228 void AcceleratedDrawingAreaProxy::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
229 {
230     ASSERT(alwaysUseCompositing() || !isInAcceleratedCompositingMode());
231
232     m_layerTreeContext = layerTreeContext;
233     m_webPageProxy.enterAcceleratedCompositingMode(layerTreeContext);
234 }
235
236 void AcceleratedDrawingAreaProxy::exitAcceleratedCompositingMode()
237 {
238     ASSERT(isInAcceleratedCompositingMode());
239
240     m_layerTreeContext = LayerTreeContext();
241     m_webPageProxy.exitAcceleratedCompositingMode();
242 }
243
244 void AcceleratedDrawingAreaProxy::updateAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
245 {
246     ASSERT(isInAcceleratedCompositingMode());
247
248     m_layerTreeContext = layerTreeContext;
249     m_webPageProxy.updateAcceleratedCompositingMode(layerTreeContext);
250 }
251
252 #if USE(TEXTURE_MAPPER_GL) && PLATFORM(GTK) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
253 void AcceleratedDrawingAreaProxy::setNativeSurfaceHandleForCompositing(uint64_t handle)
254 {
255     if (!m_hasReceivedFirstUpdate) {
256         m_pendingNativeSurfaceHandleForCompositing = handle;
257         return;
258     }
259     m_webPageProxy.process().send(Messages::DrawingArea::SetNativeSurfaceHandleForCompositing(handle), m_webPageProxy.pageID(), IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply);
260 }
261
262 void AcceleratedDrawingAreaProxy::destroyNativeSurfaceHandleForCompositing()
263 {
264     if (m_pendingNativeSurfaceHandleForCompositing) {
265         m_pendingNativeSurfaceHandleForCompositing = 0;
266         return;
267     }
268     bool handled;
269     m_webPageProxy.process().sendSync(Messages::DrawingArea::DestroyNativeSurfaceHandleForCompositing(), Messages::DrawingArea::DestroyNativeSurfaceHandleForCompositing::Reply(handled), m_webPageProxy.pageID());
270 }
271 #endif
272
273 } // namespace WebKit