2 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DrawingAreaProxyImpl.h"
29 #include "DrawingAreaMessages.h"
30 #include "DrawingAreaProxyMessages.h"
31 #include "LayerTreeContext.h"
32 #include "UpdateInfo.h"
33 #include "WebPageGroup.h"
34 #include "WebPageProxy.h"
35 #include "WebPreferences.h"
36 #include "WebProcessProxy.h"
37 #include <WebCore/Region.h>
39 #if USE(UI_SIDE_COMPOSITING)
40 #include "LayerTreeCoordinatorProxy.h"
43 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
44 #include <Ecore_Evas.h>
45 #include "ewk_view_private.h"
48 using namespace WebCore;
52 PassOwnPtr<DrawingAreaProxyImpl> DrawingAreaProxyImpl::create(WebPageProxy* webPageProxy)
54 return adoptPtr(new DrawingAreaProxyImpl(webPageProxy));
57 DrawingAreaProxyImpl::DrawingAreaProxyImpl(WebPageProxy* webPageProxy)
58 : DrawingAreaProxy(DrawingAreaTypeImpl, webPageProxy)
59 , m_currentBackingStoreStateID(0)
60 , m_nextBackingStoreStateID(0)
61 , m_isWaitingForDidUpdateBackingStoreState(false)
62 , m_hasReceivedFirstUpdate(false)
63 , m_isBackingStoreDiscardable(true)
64 , m_discardBackingStoreTimer(RunLoop::current(), this, &DrawingAreaProxyImpl::discardBackingStore)
66 #if USE(UI_SIDE_COMPOSITING)
67 // Construct the proxy early to allow messages to be sent to the web process while AC is entered there.
68 if (webPageProxy->pageGroup()->preferences()->forceCompositingMode())
69 #if ENABLE(TIZEN_RUNTIME_BACKEND_SELECTION)
70 m_layerTreeCoordinatorProxy = adoptPtr(new LayerTreeCoordinatorProxy(this, ewk_view_is_opengl_backend(m_webPageProxy->viewWidget())));
72 m_layerTreeCoordinatorProxy = adoptPtr(new LayerTreeCoordinatorProxy(this));
73 #endif // ENABLE(TIZEN_RUNTIME_BACKEND_SELECTION)
77 DrawingAreaProxyImpl::~DrawingAreaProxyImpl()
79 #if USE(ACCELERATED_COMPOSITING)
80 // Make sure to exit accelerated compositing mode.
81 if (isInAcceleratedCompositingMode())
82 exitAcceleratedCompositingMode();
86 void DrawingAreaProxyImpl::paint(BackingStore::PlatformGraphicsContext context, const IntRect& rect, Region& unpaintedRegion)
88 unpaintedRegion = rect;
90 if (isInAcceleratedCompositingMode())
93 ASSERT(m_currentBackingStoreStateID <= m_nextBackingStoreStateID);
94 if (m_currentBackingStoreStateID < m_nextBackingStoreStateID) {
95 // Tell the web process to do a full backing store update now, in case we previously told
96 // it about our next state but didn't request an immediate update.
97 sendUpdateBackingStoreState(RespondImmediately);
99 // If we haven't yet received our first bits from the WebProcess then don't paint anything.
100 if (!m_hasReceivedFirstUpdate)
103 if (m_isWaitingForDidUpdateBackingStoreState) {
104 // Wait for a DidUpdateBackingStoreState message that contains the new bits before we paint
105 // what's currently in the backing store.
106 waitForAndDispatchDidUpdateBackingStoreState();
109 // Dispatching DidUpdateBackingStoreState (either beneath sendUpdateBackingStoreState or
110 // beneath waitForAndDispatchDidUpdateBackingStoreState) could destroy our backing store or
111 // change the compositing mode.
112 if (!m_backingStore || isInAcceleratedCompositingMode())
115 ASSERT(!m_isWaitingForDidUpdateBackingStoreState);
116 if (!m_backingStore) {
117 // The view has asked us to paint before the web process has painted anything. There's
118 // nothing we can do.
123 m_backingStore->paint(context, rect);
124 unpaintedRegion.subtract(IntRect(IntPoint(), m_backingStore->size()));
126 discardBackingStoreSoon();
129 void DrawingAreaProxyImpl::sizeDidChange()
131 backingStoreStateDidChange(RespondImmediately);
134 void DrawingAreaProxyImpl::deviceScaleFactorDidChange()
136 backingStoreStateDidChange(RespondImmediately);
139 void DrawingAreaProxyImpl::layerHostingModeDidChange()
141 m_webPageProxy->process()->send(Messages::DrawingArea::SetLayerHostingMode(m_webPageProxy->layerHostingMode()), m_webPageProxy->pageID());
144 void DrawingAreaProxyImpl::visibilityDidChange()
146 if (!m_webPageProxy->suppressVisibilityUpdates()) {
147 if (!m_webPageProxy->isViewVisible()) {
149 m_webPageProxy->process()->send(Messages::DrawingArea::SuspendPainting(), m_webPageProxy->pageID());
154 m_webPageProxy->process()->send(Messages::DrawingArea::ResumePainting(), m_webPageProxy->pageID());
157 #if USE(ACCELERATED_COMPOSITING)
158 // If we don't have a backing store, go ahead and mark the backing store as being changed so
159 // that when paint we'll actually wait for something to paint and not flash white.
160 if (!m_backingStore && m_layerTreeContext.isEmpty())
161 backingStoreStateDidChange(DoNotRespondImmediately);
165 void DrawingAreaProxyImpl::setBackingStoreIsDiscardable(bool isBackingStoreDiscardable)
167 if (m_isBackingStoreDiscardable == isBackingStoreDiscardable)
170 m_isBackingStoreDiscardable = isBackingStoreDiscardable;
171 if (m_isBackingStoreDiscardable)
172 discardBackingStoreSoon();
174 m_discardBackingStoreTimer.stop();
177 void DrawingAreaProxyImpl::waitForBackingStoreUpdateOnNextPaint()
179 m_hasReceivedFirstUpdate = true;
182 void DrawingAreaProxyImpl::update(uint64_t backingStoreStateID, const UpdateInfo& updateInfo)
184 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
185 if (backingStoreStateID < m_currentBackingStoreStateID)
188 // FIXME: Handle the case where the view is hidden.
190 incorporateUpdate(updateInfo);
191 m_webPageProxy->process()->send(Messages::DrawingArea::DidUpdate(), m_webPageProxy->pageID());
194 void DrawingAreaProxyImpl::didUpdateBackingStoreState(uint64_t backingStoreStateID, const UpdateInfo& updateInfo, const LayerTreeContext& layerTreeContext)
196 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_nextBackingStoreStateID);
197 ASSERT_ARG(backingStoreStateID, backingStoreStateID > m_currentBackingStoreStateID);
198 m_currentBackingStoreStateID = backingStoreStateID;
200 m_isWaitingForDidUpdateBackingStoreState = false;
202 // Stop the responsiveness timer that was started in sendUpdateBackingStoreState.
203 m_webPageProxy->process()->responsivenessTimer()->stop();
205 if (m_nextBackingStoreStateID != m_currentBackingStoreStateID)
206 sendUpdateBackingStoreState(RespondImmediately);
208 m_hasReceivedFirstUpdate = true;
210 #if USE(ACCELERATED_COMPOSITING)
211 if (layerTreeContext != m_layerTreeContext) {
212 if (!m_layerTreeContext.isEmpty()) {
213 exitAcceleratedCompositingMode();
214 ASSERT(m_layerTreeContext.isEmpty());
217 if (!layerTreeContext.isEmpty()) {
218 enterAcceleratedCompositingMode(layerTreeContext);
219 ASSERT(layerTreeContext == m_layerTreeContext);
223 if (isInAcceleratedCompositingMode()) {
224 ASSERT(!m_backingStore);
229 // If we have a backing store the right size, reuse it.
230 if (m_backingStore && (m_backingStore->size() != updateInfo.viewSize || m_backingStore->deviceScaleFactor() != updateInfo.deviceScaleFactor))
231 m_backingStore = nullptr;
232 incorporateUpdate(updateInfo);
235 void DrawingAreaProxyImpl::enterAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext& layerTreeContext)
237 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
238 if (backingStoreStateID < m_currentBackingStoreStateID)
241 #if USE(ACCELERATED_COMPOSITING)
242 enterAcceleratedCompositingMode(layerTreeContext);
246 void DrawingAreaProxyImpl::exitAcceleratedCompositingMode(uint64_t backingStoreStateID, const UpdateInfo& updateInfo)
248 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
249 if (backingStoreStateID < m_currentBackingStoreStateID)
252 #if USE(ACCELERATED_COMPOSITING)
253 exitAcceleratedCompositingMode();
256 incorporateUpdate(updateInfo);
259 void DrawingAreaProxyImpl::updateAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext& layerTreeContext)
261 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
262 if (backingStoreStateID < m_currentBackingStoreStateID)
265 #if USE(ACCELERATED_COMPOSITING)
266 updateAcceleratedCompositingMode(layerTreeContext);
270 void DrawingAreaProxyImpl::incorporateUpdate(const UpdateInfo& updateInfo)
272 ASSERT(!isInAcceleratedCompositingMode());
274 if (updateInfo.updateRectBounds.isEmpty())
278 m_backingStore = BackingStore::create(updateInfo.viewSize, updateInfo.deviceScaleFactor, m_webPageProxy);
280 m_backingStore->incorporateUpdate(updateInfo);
282 bool shouldScroll = !updateInfo.scrollRect.isEmpty();
285 m_webPageProxy->scrollView(updateInfo.scrollRect, updateInfo.scrollOffset);
287 for (size_t i = 0; i < updateInfo.updateRects.size(); ++i)
288 m_webPageProxy->setViewNeedsDisplay(updateInfo.updateRects[i]);
290 if (WebPageProxy::debugPaintFlags() & kWKDebugFlashBackingStoreUpdates)
291 m_webPageProxy->flashBackingStoreUpdates(updateInfo.updateRects);
294 m_webPageProxy->displayView();
297 void DrawingAreaProxyImpl::backingStoreStateDidChange(RespondImmediatelyOrNot respondImmediatelyOrNot)
299 ++m_nextBackingStoreStateID;
300 sendUpdateBackingStoreState(respondImmediatelyOrNot);
303 void DrawingAreaProxyImpl::sendUpdateBackingStoreState(RespondImmediatelyOrNot respondImmediatelyOrNot)
305 ASSERT(m_currentBackingStoreStateID < m_nextBackingStoreStateID);
307 if (!m_webPageProxy->isValid())
310 if (m_isWaitingForDidUpdateBackingStoreState)
313 if (m_webPageProxy->viewSize().isEmpty())
316 m_isWaitingForDidUpdateBackingStoreState = respondImmediatelyOrNot == RespondImmediately;
318 m_webPageProxy->process()->send(Messages::DrawingArea::UpdateBackingStoreState(m_nextBackingStoreStateID, respondImmediatelyOrNot == RespondImmediately, m_webPageProxy->deviceScaleFactor(), m_size, m_scrollOffset), m_webPageProxy->pageID());
319 m_scrollOffset = IntSize();
321 if (m_isWaitingForDidUpdateBackingStoreState) {
322 // Start the responsiveness timer. We will stop it when we hear back from the WebProcess
323 // in didUpdateBackingStoreState.
324 m_webPageProxy->process()->responsivenessTimer()->start();
327 #if USE(ACCELERATED_COMPOSITING)
328 if (m_isWaitingForDidUpdateBackingStoreState && !m_layerTreeContext.isEmpty()) {
329 // Wait for the DidUpdateBackingStoreState message. Normally we do this in DrawingAreaProxyImpl::paint, but that
330 // function is never called when in accelerated compositing mode.
331 waitForAndDispatchDidUpdateBackingStoreState();
336 void DrawingAreaProxyImpl::waitForAndDispatchDidUpdateBackingStoreState()
338 ASSERT(m_isWaitingForDidUpdateBackingStoreState);
340 if (!m_webPageProxy->isValid())
342 if (m_webPageProxy->process()->isLaunching())
345 #if USE(ACCELERATED_COMPOSITING)
346 // FIXME: waitForAndDispatchImmediately will always return the oldest DidUpdateBackingStoreState message that
347 // hasn't yet been processed. But it might be better to skip ahead to some other DidUpdateBackingStoreState
348 // message, if multiple DidUpdateBackingStoreState messages are waiting to be processed. For instance, we could
349 // choose the most recent one, or the one that is closest to our current size.
351 // The timeout, in seconds, we use when waiting for a DidUpdateBackingStoreState message when we're asked to paint.
352 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
353 // we don't need to wait for replay of this message when tiled ac is used.
354 static const double didUpdateBackingStoreStateTimeout = 0.0;
356 static const double didUpdateBackingStoreStateTimeout = 0.5;
358 m_webPageProxy->process()->connection()->waitForAndDispatchImmediately<Messages::DrawingAreaProxy::DidUpdateBackingStoreState>(m_webPageProxy->pageID(), didUpdateBackingStoreStateTimeout);
362 #if USE(ACCELERATED_COMPOSITING)
363 void DrawingAreaProxyImpl::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
365 ASSERT(!isInAcceleratedCompositingMode());
367 m_backingStore = nullptr;
368 m_layerTreeContext = layerTreeContext;
369 m_webPageProxy->enterAcceleratedCompositingMode(layerTreeContext);
370 #if USE(UI_SIDE_COMPOSITING)
371 if (!m_layerTreeCoordinatorProxy)
372 m_layerTreeCoordinatorProxy = adoptPtr(new LayerTreeCoordinatorProxy(this));
376 #if USE(UI_SIDE_COMPOSITING)
377 void DrawingAreaProxyImpl::didReceiveLayerTreeCoordinatorProxyMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
379 if (m_layerTreeCoordinatorProxy)
380 m_layerTreeCoordinatorProxy->didReceiveLayerTreeCoordinatorProxyMessage(connection, messageID, arguments);
383 void DrawingAreaProxyImpl::setVisibleContentsRect(const WebCore::IntRect& visibleContentsRect, float scale, const WebCore::FloatPoint& trajectoryVector, const WebCore::FloatPoint& accurateVisibleContentsPosition)
385 if (m_layerTreeCoordinatorProxy)
386 m_layerTreeCoordinatorProxy->setVisibleContentsRect(visibleContentsRect, scale, trajectoryVector, accurateVisibleContentsPosition);
389 #if ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION_ON_UI_SIDE)
390 void DrawingAreaProxyImpl::setVisibleContentsRectForScrollingContentsLayers(const WebCore::IntRect& visibleRect)
392 if (m_layerTreeCoordinatorProxy)
393 m_layerTreeCoordinatorProxy->setVisibleContentsRectForScrollingContentsLayers(visibleRect);
396 #endif // #if USE(UI_SIDE_COMPOSITING)
398 void DrawingAreaProxyImpl::exitAcceleratedCompositingMode()
400 ASSERT(isInAcceleratedCompositingMode());
402 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
403 m_webPageProxy->makeContextCurrent();
404 m_layerTreeCoordinatorProxy = nullptr;
407 m_layerTreeContext = LayerTreeContext();
408 m_webPageProxy->exitAcceleratedCompositingMode();
411 void DrawingAreaProxyImpl::updateAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
413 ASSERT(isInAcceleratedCompositingMode());
415 m_layerTreeContext = layerTreeContext;
416 m_webPageProxy->updateAcceleratedCompositingMode(layerTreeContext);
420 void DrawingAreaProxyImpl::pageCustomRepresentationChanged()
422 m_webPageProxy->process()->send(Messages::DrawingArea::PageCustomRepresentationChanged(), m_webPageProxy->pageID());
425 void DrawingAreaProxyImpl::discardBackingStoreSoon()
427 if (!m_isBackingStoreDiscardable || m_discardBackingStoreTimer.isActive())
430 // We'll wait this many seconds after the last paint before throwing away our backing store to save memory.
431 // FIXME: It would be smarter to make this delay based on how expensive painting is. See <http://webkit.org/b/55733>.
432 static const double discardBackingStoreDelay = 2;
434 m_discardBackingStoreTimer.startOneShot(discardBackingStoreDelay);
437 void DrawingAreaProxyImpl::discardBackingStore()
439 m_backingStore = nullptr;
440 backingStoreStateDidChange(DoNotRespondImmediately);
443 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
444 void DrawingAreaProxyImpl::didSuspendPainting()
446 if (!m_webPageProxy->isViewVisible()) {
447 m_layerTreeCoordinatorProxy->clearBackingStores();
448 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
449 m_webPageProxy->process()->platformSurfaceTexturePool()->removeUnusedPlatformSurfaceTextures(m_webPageProxy->process());
455 } // namespace WebKit