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 "LayerTreeHostProxy.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 m_layerTreeHostProxy = adoptPtr(new LayerTreeHostProxy(this));
73 DrawingAreaProxyImpl::~DrawingAreaProxyImpl()
75 #if USE(ACCELERATED_COMPOSITING)
76 // Make sure to exit accelerated compositing mode.
77 if (isInAcceleratedCompositingMode())
78 exitAcceleratedCompositingMode();
82 void DrawingAreaProxyImpl::paint(BackingStore::PlatformGraphicsContext context, const IntRect& rect, Region& unpaintedRegion)
84 unpaintedRegion = rect;
86 if (isInAcceleratedCompositingMode())
89 ASSERT(m_currentBackingStoreStateID <= m_nextBackingStoreStateID);
90 if (m_currentBackingStoreStateID < m_nextBackingStoreStateID) {
91 // Tell the web process to do a full backing store update now, in case we previously told
92 // it about our next state but didn't request an immediate update.
93 sendUpdateBackingStoreState(RespondImmediately);
95 // If we haven't yet received our first bits from the WebProcess then don't paint anything.
96 if (!m_hasReceivedFirstUpdate)
99 if (m_isWaitingForDidUpdateBackingStoreState) {
100 // Wait for a DidUpdateBackingStoreState message that contains the new bits before we paint
101 // what's currently in the backing store.
102 waitForAndDispatchDidUpdateBackingStoreState();
105 // Dispatching DidUpdateBackingStoreState (either beneath sendUpdateBackingStoreState or
106 // beneath waitForAndDispatchDidUpdateBackingStoreState) could destroy our backing store or
107 // change the compositing mode.
108 if (!m_backingStore || isInAcceleratedCompositingMode())
111 ASSERT(!m_isWaitingForDidUpdateBackingStoreState);
112 if (!m_backingStore) {
113 // The view has asked us to paint before the web process has painted anything. There's
114 // nothing we can do.
119 m_backingStore->paint(context, rect);
120 unpaintedRegion.subtract(IntRect(IntPoint(), m_backingStore->size()));
122 discardBackingStoreSoon();
125 void DrawingAreaProxyImpl::sizeDidChange()
127 backingStoreStateDidChange(RespondImmediately);
130 void DrawingAreaProxyImpl::deviceScaleFactorDidChange()
132 backingStoreStateDidChange(RespondImmediately);
135 void DrawingAreaProxyImpl::layerHostingModeDidChange()
137 m_webPageProxy->process()->send(Messages::DrawingArea::SetLayerHostingMode(m_webPageProxy->layerHostingMode()), m_webPageProxy->pageID());
140 void DrawingAreaProxyImpl::visibilityDidChange()
142 if (!m_webPageProxy->isViewVisible()) {
144 m_webPageProxy->process()->send(Messages::DrawingArea::SuspendPainting(), m_webPageProxy->pageID());
149 m_webPageProxy->process()->send(Messages::DrawingArea::ResumePainting(), m_webPageProxy->pageID());
151 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
152 m_layerTreeHostProxy->restoreBackingStores();
155 #if USE(ACCELERATED_COMPOSITING)
156 // If we don't have a backing store, go ahead and mark the backing store as being changed so
157 // that when paint we'll actually wait for something to paint and not flash white.
158 if (!m_backingStore && m_layerTreeContext.isEmpty())
159 backingStoreStateDidChange(DoNotRespondImmediately);
163 void DrawingAreaProxyImpl::setBackingStoreIsDiscardable(bool isBackingStoreDiscardable)
165 if (m_isBackingStoreDiscardable == isBackingStoreDiscardable)
168 m_isBackingStoreDiscardable = isBackingStoreDiscardable;
169 if (m_isBackingStoreDiscardable)
170 discardBackingStoreSoon();
172 m_discardBackingStoreTimer.stop();
175 void DrawingAreaProxyImpl::waitForBackingStoreUpdateOnNextPaint()
177 m_hasReceivedFirstUpdate = true;
180 void DrawingAreaProxyImpl::update(uint64_t backingStoreStateID, const UpdateInfo& updateInfo)
182 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
183 if (backingStoreStateID < m_currentBackingStoreStateID)
186 // FIXME: Handle the case where the view is hidden.
188 incorporateUpdate(updateInfo);
189 m_webPageProxy->process()->send(Messages::DrawingArea::DidUpdate(), m_webPageProxy->pageID());
192 void DrawingAreaProxyImpl::didUpdateBackingStoreState(uint64_t backingStoreStateID, const UpdateInfo& updateInfo, const LayerTreeContext& layerTreeContext)
194 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_nextBackingStoreStateID);
195 ASSERT_ARG(backingStoreStateID, backingStoreStateID > m_currentBackingStoreStateID);
196 m_currentBackingStoreStateID = backingStoreStateID;
198 m_isWaitingForDidUpdateBackingStoreState = false;
200 // Stop the responsiveness timer that was started in sendUpdateBackingStoreState.
201 m_webPageProxy->process()->responsivenessTimer()->stop();
203 if (m_nextBackingStoreStateID != m_currentBackingStoreStateID)
204 sendUpdateBackingStoreState(RespondImmediately);
206 m_hasReceivedFirstUpdate = true;
208 #if USE(ACCELERATED_COMPOSITING)
209 if (layerTreeContext != m_layerTreeContext) {
210 if (!m_layerTreeContext.isEmpty()) {
211 exitAcceleratedCompositingMode();
212 ASSERT(m_layerTreeContext.isEmpty());
215 if (!layerTreeContext.isEmpty()) {
216 enterAcceleratedCompositingMode(layerTreeContext);
217 ASSERT(layerTreeContext == m_layerTreeContext);
221 if (isInAcceleratedCompositingMode()) {
222 ASSERT(!m_backingStore);
227 // If we have a backing store the right size, reuse it.
228 if (m_backingStore && (m_backingStore->size() != updateInfo.viewSize || m_backingStore->deviceScaleFactor() != updateInfo.deviceScaleFactor))
229 m_backingStore = nullptr;
230 incorporateUpdate(updateInfo);
233 void DrawingAreaProxyImpl::enterAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext& layerTreeContext)
235 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
236 if (backingStoreStateID < m_currentBackingStoreStateID)
239 #if USE(ACCELERATED_COMPOSITING)
240 enterAcceleratedCompositingMode(layerTreeContext);
244 void DrawingAreaProxyImpl::exitAcceleratedCompositingMode(uint64_t backingStoreStateID, const UpdateInfo& updateInfo)
246 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
247 if (backingStoreStateID < m_currentBackingStoreStateID)
250 #if USE(ACCELERATED_COMPOSITING)
251 exitAcceleratedCompositingMode();
254 incorporateUpdate(updateInfo);
257 void DrawingAreaProxyImpl::updateAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext& layerTreeContext)
259 ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
260 if (backingStoreStateID < m_currentBackingStoreStateID)
263 #if USE(ACCELERATED_COMPOSITING)
264 updateAcceleratedCompositingMode(layerTreeContext);
268 void DrawingAreaProxyImpl::incorporateUpdate(const UpdateInfo& updateInfo)
270 ASSERT(!isInAcceleratedCompositingMode());
272 if (updateInfo.updateRectBounds.isEmpty())
276 m_backingStore = BackingStore::create(updateInfo.viewSize, updateInfo.deviceScaleFactor, m_webPageProxy);
278 m_backingStore->incorporateUpdate(updateInfo);
280 bool shouldScroll = !updateInfo.scrollRect.isEmpty();
283 m_webPageProxy->scrollView(updateInfo.scrollRect, updateInfo.scrollOffset);
285 for (size_t i = 0; i < updateInfo.updateRects.size(); ++i)
286 m_webPageProxy->setViewNeedsDisplay(updateInfo.updateRects[i]);
288 if (WebPageProxy::debugPaintFlags() & kWKDebugFlashBackingStoreUpdates)
289 m_webPageProxy->flashBackingStoreUpdates(updateInfo.updateRects);
292 m_webPageProxy->displayView();
295 void DrawingAreaProxyImpl::backingStoreStateDidChange(RespondImmediatelyOrNot respondImmediatelyOrNot)
297 ++m_nextBackingStoreStateID;
298 sendUpdateBackingStoreState(respondImmediatelyOrNot);
301 void DrawingAreaProxyImpl::sendUpdateBackingStoreState(RespondImmediatelyOrNot respondImmediatelyOrNot)
303 ASSERT(m_currentBackingStoreStateID < m_nextBackingStoreStateID);
305 if (!m_webPageProxy->isValid())
308 if (m_isWaitingForDidUpdateBackingStoreState)
311 if (m_webPageProxy->viewSize().isEmpty())
314 m_isWaitingForDidUpdateBackingStoreState = respondImmediatelyOrNot == RespondImmediately;
316 m_webPageProxy->process()->send(Messages::DrawingArea::UpdateBackingStoreState(m_nextBackingStoreStateID, respondImmediatelyOrNot == RespondImmediately, m_webPageProxy->deviceScaleFactor(), m_size, m_scrollOffset), m_webPageProxy->pageID());
317 m_scrollOffset = IntSize();
319 if (m_isWaitingForDidUpdateBackingStoreState) {
320 // Start the responsiveness timer. We will stop it when we hear back from the WebProcess
321 // in didUpdateBackingStoreState.
322 m_webPageProxy->process()->responsivenessTimer()->start();
325 #if USE(ACCELERATED_COMPOSITING)
326 if (m_isWaitingForDidUpdateBackingStoreState && !m_layerTreeContext.isEmpty()) {
327 // Wait for the DidUpdateBackingStoreState message. Normally we do this in DrawingAreaProxyImpl::paint, but that
328 // function is never called when in accelerated compositing mode.
329 waitForAndDispatchDidUpdateBackingStoreState();
334 void DrawingAreaProxyImpl::waitForAndDispatchDidUpdateBackingStoreState()
336 ASSERT(m_isWaitingForDidUpdateBackingStoreState);
338 if (!m_webPageProxy->isValid())
340 if (m_webPageProxy->process()->isLaunching())
343 #if USE(ACCELERATED_COMPOSITING)
344 // FIXME: waitForAndDispatchImmediately will always return the oldest DidUpdateBackingStoreState message that
345 // hasn't yet been processed. But it might be better to skip ahead to some other DidUpdateBackingStoreState
346 // message, if multiple DidUpdateBackingStoreState messages are waiting to be processed. For instance, we could
347 // choose the most recent one, or the one that is closest to our current size.
349 // The timeout, in seconds, we use when waiting for a DidUpdateBackingStoreState message when we're asked to paint.
350 static const double didUpdateBackingStoreStateTimeout = 0.5;
351 m_webPageProxy->process()->connection()->waitForAndDispatchImmediately<Messages::DrawingAreaProxy::DidUpdateBackingStoreState>(m_webPageProxy->pageID(), didUpdateBackingStoreStateTimeout);
355 #if USE(ACCELERATED_COMPOSITING)
356 void DrawingAreaProxyImpl::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
358 ASSERT(!isInAcceleratedCompositingMode());
360 m_backingStore = nullptr;
361 m_layerTreeContext = layerTreeContext;
362 m_webPageProxy->enterAcceleratedCompositingMode(layerTreeContext);
363 #if USE(UI_SIDE_COMPOSITING)
364 if (!m_layerTreeHostProxy)
365 m_layerTreeHostProxy = adoptPtr(new LayerTreeHostProxy(this));
369 #if USE(UI_SIDE_COMPOSITING)
370 void DrawingAreaProxyImpl::didReceiveLayerTreeHostProxyMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
372 if (m_layerTreeHostProxy)
373 m_layerTreeHostProxy->didReceiveLayerTreeHostProxyMessage(connection, messageID, arguments);
376 void DrawingAreaProxyImpl::setVisibleContentsRect(const WebCore::IntRect& visibleContentsRect, float scale, const WebCore::FloatPoint& trajectoryVector, const WebCore::FloatPoint& accurateVisibleContentsPosition)
378 if (m_layerTreeHostProxy)
379 m_layerTreeHostProxy->setVisibleContentsRect(visibleContentsRect, scale, trajectoryVector, accurateVisibleContentsPosition);
382 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
383 #if ENABLE(TIZEN_WEBKIT2_DIRECT_RENDERING)
384 void DrawingAreaProxyImpl::setAngle(int angle)
386 if (m_layerTreeHostProxy)
387 m_layerTreeHostProxy->setAngle(angle);
392 #if ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION_ON_UI_SIDE)
393 void DrawingAreaProxyImpl::setVisibleContentsRectForScrollingContentsLayers(const WebCore::IntRect& visibleRect)
395 if (m_layerTreeHostProxy)
396 m_layerTreeHostProxy->setVisibleContentsRectForScrollingContentsLayers(visibleRect);
402 void DrawingAreaProxyImpl::exitAcceleratedCompositingMode()
404 ASSERT(isInAcceleratedCompositingMode());
406 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
407 m_layerTreeHostProxy = nullptr;
410 m_layerTreeContext = LayerTreeContext();
411 m_webPageProxy->exitAcceleratedCompositingMode();
414 void DrawingAreaProxyImpl::updateAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
416 ASSERT(isInAcceleratedCompositingMode());
418 m_layerTreeContext = layerTreeContext;
419 m_webPageProxy->updateAcceleratedCompositingMode(layerTreeContext);
423 void DrawingAreaProxyImpl::pageCustomRepresentationChanged()
425 m_webPageProxy->process()->send(Messages::DrawingArea::PageCustomRepresentationChanged(), m_webPageProxy->pageID());
428 void DrawingAreaProxyImpl::discardBackingStoreSoon()
430 if (!m_isBackingStoreDiscardable || m_discardBackingStoreTimer.isActive())
433 // We'll wait this many seconds after the last paint before throwing away our backing store to save memory.
434 // FIXME: It would be smarter to make this delay based on how expensive painting is. See <http://webkit.org/b/55733>.
435 static const double discardBackingStoreDelay = 2;
437 m_discardBackingStoreTimer.startOneShot(discardBackingStoreDelay);
440 void DrawingAreaProxyImpl::discardBackingStore()
442 m_backingStore = nullptr;
443 backingStoreStateDidChange(DoNotRespondImmediately);
446 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
447 void DrawingAreaProxyImpl::didSuspendPainting()
449 if (!m_webPageProxy->isViewVisible())
450 m_layerTreeHostProxy->clearBackingStores();
454 } // namespace WebKit