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.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
29 #include "AcceleratedDrawingAreaProxy.h"
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>
40 #if USE(COORDINATED_GRAPHICS_MULTIPROCESS)
41 #include "CoordinatedLayerTreeHostProxy.h"
45 #include "WaylandCompositor.h"
46 #include <WebCore/PlatformDisplay.h>
49 using namespace WebCore;
53 AcceleratedDrawingAreaProxy::AcceleratedDrawingAreaProxy(WebPageProxy& webPageProxy)
54 #if USE(COORDINATED_GRAPHICS_MULTIPROCESS)
55 : DrawingAreaProxy(DrawingAreaTypeCoordinated, webPageProxy)
57 : DrawingAreaProxy(DrawingAreaTypeImpl, webPageProxy)
60 #if USE(COORDINATED_GRAPHICS_MULTIPROCESS)
61 // Construct the proxy early to allow messages to be sent to the web process while AC is entered there.
62 m_coordinatedLayerTreeHostProxy = std::make_unique<CoordinatedLayerTreeHostProxy>(webPageProxy);
66 AcceleratedDrawingAreaProxy::~AcceleratedDrawingAreaProxy()
68 // Make sure to exit accelerated compositing mode.
69 if (isInAcceleratedCompositingMode())
70 exitAcceleratedCompositingMode();
73 bool AcceleratedDrawingAreaProxy::alwaysUseCompositing() const
75 return m_webPageProxy.preferences().acceleratedCompositingEnabled() && m_webPageProxy.preferences().forceCompositingMode();
78 void AcceleratedDrawingAreaProxy::dispatchAfterEnsuringDrawing(std::function<void(CallbackBase::Error)> callbackFunction)
80 if (!m_webPageProxy.isValid()) {
81 callbackFunction(CallbackBase::Error::OwnerWasInvalidated);
85 RunLoop::main().dispatch([callbackFunction] {
86 callbackFunction(CallbackBase::Error::None);
90 void AcceleratedDrawingAreaProxy::sizeDidChange()
92 backingStoreStateDidChange(RespondImmediately);
95 void AcceleratedDrawingAreaProxy::deviceScaleFactorDidChange()
97 backingStoreStateDidChange(RespondImmediately);
100 void AcceleratedDrawingAreaProxy::visibilityDidChange()
102 // If we don't have a backing store, go ahead and mark the backing store as being changed so
103 // that when paint we'll actually wait for something to paint and not flash white.
104 if (m_layerTreeContext.isEmpty())
105 backingStoreStateDidChange(DoNotRespondImmediately);
108 void AcceleratedDrawingAreaProxy::waitForBackingStoreUpdateOnNextPaint()
110 m_hasReceivedFirstUpdate = true;
113 void AcceleratedDrawingAreaProxy::didUpdateBackingStoreState(uint64_t backingStoreStateID, const UpdateInfo& updateInfo, const LayerTreeContext& layerTreeContext)
115 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_nextBackingStoreStateID);
116 ASSERT_ARG(backingStoreStateID, backingStoreStateID > m_currentBackingStoreStateID);
117 m_currentBackingStoreStateID = backingStoreStateID;
119 m_isWaitingForDidUpdateBackingStoreState = false;
121 // Stop the responsiveness timer that was started in sendUpdateBackingStoreState.
122 m_webPageProxy.process().responsivenessTimer().stop();
124 if (layerTreeContext != m_layerTreeContext) {
125 if (layerTreeContext.isEmpty() && !m_layerTreeContext.isEmpty()) {
126 exitAcceleratedCompositingMode();
127 ASSERT(m_layerTreeContext.isEmpty());
128 } else if (!layerTreeContext.isEmpty() && m_layerTreeContext.isEmpty()) {
129 enterAcceleratedCompositingMode(layerTreeContext);
130 ASSERT(layerTreeContext == m_layerTreeContext);
132 updateAcceleratedCompositingMode(layerTreeContext);
133 ASSERT(layerTreeContext == m_layerTreeContext);
137 if (m_nextBackingStoreStateID != m_currentBackingStoreStateID)
138 sendUpdateBackingStoreState(RespondImmediately);
140 m_hasReceivedFirstUpdate = true;
142 #if USE(TEXTURE_MAPPER) && PLATFORM(GTK) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
143 if (m_pendingNativeSurfaceHandleForCompositing) {
144 setNativeSurfaceHandleForCompositing(m_pendingNativeSurfaceHandleForCompositing);
145 m_pendingNativeSurfaceHandleForCompositing = 0;
151 void AcceleratedDrawingAreaProxy::enterAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext& layerTreeContext)
153 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
154 if (backingStoreStateID < m_currentBackingStoreStateID)
157 enterAcceleratedCompositingMode(layerTreeContext);
160 void AcceleratedDrawingAreaProxy::exitAcceleratedCompositingMode(uint64_t backingStoreStateID, const UpdateInfo& updateInfo)
162 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
163 if (backingStoreStateID < m_currentBackingStoreStateID)
166 exitAcceleratedCompositingMode();
169 void AcceleratedDrawingAreaProxy::updateAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext& layerTreeContext)
171 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
172 if (backingStoreStateID < m_currentBackingStoreStateID)
175 updateAcceleratedCompositingMode(layerTreeContext);
178 void AcceleratedDrawingAreaProxy::backingStoreStateDidChange(RespondImmediatelyOrNot respondImmediatelyOrNot)
180 ++m_nextBackingStoreStateID;
181 sendUpdateBackingStoreState(respondImmediatelyOrNot);
184 void AcceleratedDrawingAreaProxy::sendUpdateBackingStoreState(RespondImmediatelyOrNot respondImmediatelyOrNot)
186 ASSERT(m_currentBackingStoreStateID < m_nextBackingStoreStateID);
188 if (!m_webPageProxy.isValid())
191 if (m_isWaitingForDidUpdateBackingStoreState)
194 if (m_webPageProxy.viewSize().isEmpty() && !m_webPageProxy.useFixedLayout())
197 m_isWaitingForDidUpdateBackingStoreState = respondImmediatelyOrNot == RespondImmediately;
199 m_webPageProxy.process().send(Messages::DrawingArea::UpdateBackingStoreState(m_nextBackingStoreStateID, respondImmediatelyOrNot == RespondImmediately, m_webPageProxy.deviceScaleFactor(), m_size, m_scrollOffset), m_webPageProxy.pageID());
200 m_scrollOffset = IntSize();
202 if (m_isWaitingForDidUpdateBackingStoreState) {
203 // Start the responsiveness timer. We will stop it when we hear back from the WebProcess
204 // in didUpdateBackingStoreState.
205 m_webPageProxy.process().responsivenessTimer().start();
208 if (m_isWaitingForDidUpdateBackingStoreState && !m_layerTreeContext.isEmpty()) {
209 // Wait for the DidUpdateBackingStoreState message. Normally we do this in AcceleratedDrawingAreaProxy::paint, but that
210 // function is never called when in accelerated compositing mode.
211 waitForAndDispatchDidUpdateBackingStoreState();
215 void AcceleratedDrawingAreaProxy::waitForAndDispatchDidUpdateBackingStoreState()
217 ASSERT(m_isWaitingForDidUpdateBackingStoreState);
219 if (!m_webPageProxy.isValid())
221 if (m_webPageProxy.process().state() == WebProcessProxy::State::Launching)
223 if (!m_webPageProxy.isViewVisible())
226 #if PLATFORM(WAYLAND)
227 // Never block the UI process in Wayland when waiting for DidUpdateBackingStoreState after a resize,
228 // because the nested compositor needs to handle the web process requests that happens while resizing.
229 if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland && WaylandCompositor::singleton().isRunning())
233 // FIXME: waitForAndDispatchImmediately will always return the oldest DidUpdateBackingStoreState message that
234 // hasn't yet been processed. But it might be better to skip ahead to some other DidUpdateBackingStoreState
235 // message, if multiple DidUpdateBackingStoreState messages are waiting to be processed. For instance, we could
236 // choose the most recent one, or the one that is closest to our current size.
238 // The timeout, in seconds, we use when waiting for a DidUpdateBackingStoreState message when we're asked to paint.
239 m_webPageProxy.process().connection()->waitForAndDispatchImmediately<Messages::DrawingAreaProxy::DidUpdateBackingStoreState>(m_webPageProxy.pageID(), std::chrono::milliseconds(500));
242 void AcceleratedDrawingAreaProxy::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
244 ASSERT(alwaysUseCompositing() || !isInAcceleratedCompositingMode());
246 m_layerTreeContext = layerTreeContext;
247 m_webPageProxy.enterAcceleratedCompositingMode(layerTreeContext);
250 void AcceleratedDrawingAreaProxy::exitAcceleratedCompositingMode()
252 ASSERT(isInAcceleratedCompositingMode());
254 m_layerTreeContext = LayerTreeContext();
255 m_webPageProxy.exitAcceleratedCompositingMode();
258 void AcceleratedDrawingAreaProxy::updateAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
260 ASSERT(isInAcceleratedCompositingMode());
262 m_layerTreeContext = layerTreeContext;
263 m_webPageProxy.updateAcceleratedCompositingMode(layerTreeContext);
266 #if USE(TEXTURE_MAPPER) && PLATFORM(GTK) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
267 void AcceleratedDrawingAreaProxy::setNativeSurfaceHandleForCompositing(uint64_t handle)
269 if (!m_hasReceivedFirstUpdate) {
270 m_pendingNativeSurfaceHandleForCompositing = handle;
273 m_webPageProxy.process().send(Messages::DrawingArea::SetNativeSurfaceHandleForCompositing(handle), m_webPageProxy.pageID(), IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply);
276 void AcceleratedDrawingAreaProxy::destroyNativeSurfaceHandleForCompositing()
278 if (m_pendingNativeSurfaceHandleForCompositing) {
279 m_pendingNativeSurfaceHandleForCompositing = 0;
283 m_webPageProxy.process().sendSync(Messages::DrawingArea::DestroyNativeSurfaceHandleForCompositing(), Messages::DrawingArea::DestroyNativeSurfaceHandleForCompositing::Reply(handled), m_webPageProxy.pageID());
287 } // namespace WebKit