• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 #include "config.h"
27 #include "DrawingAreaProxyImpl.h"
28 
29 #include "DrawingAreaMessages.h"
30 #include "DrawingAreaProxyMessages.h"
31 #include "LayerTreeContext.h"
32 #include "Region.h"
33 #include "UpdateInfo.h"
34 #include "WebPageProxy.h"
35 #include "WebProcessProxy.h"
36 
37 #if !PLATFORM(MAC) && !PLATFORM(WIN)
38 #error "This drawing area is not ready for use by other ports yet."
39 #endif
40 
41 using namespace WebCore;
42 
43 namespace WebKit {
44 
create(WebPageProxy * webPageProxy)45 PassOwnPtr<DrawingAreaProxyImpl> DrawingAreaProxyImpl::create(WebPageProxy* webPageProxy)
46 {
47     return adoptPtr(new DrawingAreaProxyImpl(webPageProxy));
48 }
49 
DrawingAreaProxyImpl(WebPageProxy * webPageProxy)50 DrawingAreaProxyImpl::DrawingAreaProxyImpl(WebPageProxy* webPageProxy)
51     : DrawingAreaProxy(DrawingAreaTypeImpl, webPageProxy)
52     , m_currentBackingStoreStateID(0)
53     , m_nextBackingStoreStateID(0)
54     , m_isWaitingForDidUpdateBackingStoreState(false)
55     , m_isBackingStoreDiscardable(true)
56     , m_discardBackingStoreTimer(RunLoop::current(), this, &DrawingAreaProxyImpl::discardBackingStore)
57 {
58 }
59 
~DrawingAreaProxyImpl()60 DrawingAreaProxyImpl::~DrawingAreaProxyImpl()
61 {
62 #if USE(ACCELERATED_COMPOSITING)
63     // Make sure to exit accelerated compositing mode.
64     if (isInAcceleratedCompositingMode())
65         exitAcceleratedCompositingMode();
66 #endif
67 }
68 
paint(BackingStore::PlatformGraphicsContext context,const IntRect & rect,Region & unpaintedRegion)69 void DrawingAreaProxyImpl::paint(BackingStore::PlatformGraphicsContext context, const IntRect& rect, Region& unpaintedRegion)
70 {
71     unpaintedRegion = rect;
72 
73     if (isInAcceleratedCompositingMode())
74         return;
75 
76     ASSERT(m_currentBackingStoreStateID <= m_nextBackingStoreStateID);
77     if (m_currentBackingStoreStateID < m_nextBackingStoreStateID) {
78         // Tell the web process to do a full backing store update now, in case we previously told
79         // it about our next state but didn't request an immediate update.
80         sendUpdateBackingStoreState(RespondImmediately);
81 
82         if (m_isWaitingForDidUpdateBackingStoreState) {
83             // Wait for a DidUpdateBackingStoreState message that contains the new bits before we paint
84             // what's currently in the backing store.
85             waitForAndDispatchDidUpdateBackingStoreState();
86         }
87 
88         // Dispatching DidUpdateBackingStoreState (either beneath sendUpdateBackingStoreState or
89         // beneath waitForAndDispatchDidUpdateBackingStoreState) could destroy our backing store or
90         // change the compositing mode.
91         if (!m_backingStore || isInAcceleratedCompositingMode())
92             return;
93     } else {
94         ASSERT(!m_isWaitingForDidUpdateBackingStoreState);
95         if (!m_backingStore) {
96             // The view has asked us to paint before the web process has painted anything. There's
97             // nothing we can do.
98             return;
99         }
100     }
101 
102     m_backingStore->paint(context, rect);
103     unpaintedRegion.subtract(IntRect(IntPoint(), m_backingStore->size()));
104 
105     discardBackingStoreSoon();
106 }
107 
didReceiveMessage(CoreIPC::Connection *,CoreIPC::MessageID,CoreIPC::ArgumentDecoder *)108 void DrawingAreaProxyImpl::didReceiveMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*)
109 {
110     ASSERT_NOT_REACHED();
111 }
112 
didReceiveSyncMessage(CoreIPC::Connection *,CoreIPC::MessageID,CoreIPC::ArgumentDecoder *,CoreIPC::ArgumentEncoder *)113 void DrawingAreaProxyImpl::didReceiveSyncMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*, CoreIPC::ArgumentEncoder*)
114 {
115     ASSERT_NOT_REACHED();
116 }
117 
paint(const WebCore::IntRect &,PlatformDrawingContext)118 bool DrawingAreaProxyImpl::paint(const WebCore::IntRect&, PlatformDrawingContext)
119 {
120     ASSERT_NOT_REACHED();
121     return false;
122 }
123 
sizeDidChange()124 void DrawingAreaProxyImpl::sizeDidChange()
125 {
126     backingStoreStateDidChange(RespondImmediately);
127 }
128 
visibilityDidChange()129 void DrawingAreaProxyImpl::visibilityDidChange()
130 {
131     if (!m_webPageProxy->isViewVisible()) {
132         // Suspend painting.
133         m_webPageProxy->process()->send(Messages::DrawingArea::SuspendPainting(), m_webPageProxy->pageID());
134         return;
135     }
136 
137     // Resume painting.
138     m_webPageProxy->process()->send(Messages::DrawingArea::ResumePainting(), m_webPageProxy->pageID());
139 
140 #if USE(ACCELERATED_COMPOSITING)
141     // If we don't have a backing store, go ahead and mark the backing store as being changed so
142     // that when paint we'll actually wait for something to paint and not flash white.
143     if (!m_backingStore && m_layerTreeContext.isEmpty())
144         backingStoreStateDidChange(DoNotRespondImmediately);
145 #endif
146 }
147 
setPageIsVisible(bool)148 void DrawingAreaProxyImpl::setPageIsVisible(bool)
149 {
150 }
151 
setBackingStoreIsDiscardable(bool isBackingStoreDiscardable)152 void DrawingAreaProxyImpl::setBackingStoreIsDiscardable(bool isBackingStoreDiscardable)
153 {
154     if (m_isBackingStoreDiscardable == isBackingStoreDiscardable)
155         return;
156 
157     m_isBackingStoreDiscardable = isBackingStoreDiscardable;
158     if (m_isBackingStoreDiscardable)
159         discardBackingStoreSoon();
160     else
161         m_discardBackingStoreTimer.stop();
162 }
163 
update(uint64_t backingStoreStateID,const UpdateInfo & updateInfo)164 void DrawingAreaProxyImpl::update(uint64_t backingStoreStateID, const UpdateInfo& updateInfo)
165 {
166     ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
167     if (backingStoreStateID < m_currentBackingStoreStateID)
168         return;
169 
170     // FIXME: Handle the case where the view is hidden.
171 
172     incorporateUpdate(updateInfo);
173     m_webPageProxy->process()->send(Messages::DrawingArea::DidUpdate(), m_webPageProxy->pageID());
174 }
175 
didUpdateBackingStoreState(uint64_t backingStoreStateID,const UpdateInfo & updateInfo,const LayerTreeContext & layerTreeContext)176 void DrawingAreaProxyImpl::didUpdateBackingStoreState(uint64_t backingStoreStateID, const UpdateInfo& updateInfo, const LayerTreeContext& layerTreeContext)
177 {
178     ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_nextBackingStoreStateID);
179     ASSERT_ARG(backingStoreStateID, backingStoreStateID > m_currentBackingStoreStateID);
180     m_currentBackingStoreStateID = backingStoreStateID;
181 
182     m_isWaitingForDidUpdateBackingStoreState = false;
183 
184     if (m_nextBackingStoreStateID != m_currentBackingStoreStateID)
185         sendUpdateBackingStoreState(RespondImmediately);
186 
187 #if USE(ACCELERATED_COMPOSITING)
188     if (layerTreeContext != m_layerTreeContext) {
189         if (!m_layerTreeContext.isEmpty()) {
190             exitAcceleratedCompositingMode();
191             ASSERT(m_layerTreeContext.isEmpty());
192         }
193 
194         if (!layerTreeContext.isEmpty()) {
195             enterAcceleratedCompositingMode(layerTreeContext);
196             ASSERT(layerTreeContext == m_layerTreeContext);
197         }
198     }
199 
200     if (isInAcceleratedCompositingMode()) {
201         ASSERT(!m_backingStore);
202         return;
203     }
204 #endif
205 
206     // FIXME: We could just reuse our existing backing store if it's the same size as
207     // updateInfo.viewSize.
208     m_backingStore = nullptr;
209     incorporateUpdate(updateInfo);
210 }
211 
enterAcceleratedCompositingMode(uint64_t backingStoreStateID,const LayerTreeContext & layerTreeContext)212 void DrawingAreaProxyImpl::enterAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext& layerTreeContext)
213 {
214     ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
215     if (backingStoreStateID < m_currentBackingStoreStateID)
216         return;
217 
218 #if USE(ACCELERATED_COMPOSITING)
219     enterAcceleratedCompositingMode(layerTreeContext);
220 #endif
221 }
222 
exitAcceleratedCompositingMode(uint64_t backingStoreStateID,const UpdateInfo & updateInfo)223 void DrawingAreaProxyImpl::exitAcceleratedCompositingMode(uint64_t backingStoreStateID, const UpdateInfo& updateInfo)
224 {
225     ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
226     if (backingStoreStateID < m_currentBackingStoreStateID)
227         return;
228 
229 #if USE(ACCELERATED_COMPOSITING)
230     exitAcceleratedCompositingMode();
231 #endif
232 
233     incorporateUpdate(updateInfo);
234 }
235 
incorporateUpdate(const UpdateInfo & updateInfo)236 void DrawingAreaProxyImpl::incorporateUpdate(const UpdateInfo& updateInfo)
237 {
238     ASSERT(!isInAcceleratedCompositingMode());
239 
240     if (updateInfo.updateRectBounds.isEmpty())
241         return;
242 
243     if (!m_backingStore)
244         m_backingStore = BackingStore::create(updateInfo.viewSize, m_webPageProxy);
245 
246     m_backingStore->incorporateUpdate(updateInfo);
247 
248     bool shouldScroll = !updateInfo.scrollRect.isEmpty();
249 
250     if (shouldScroll)
251         m_webPageProxy->scrollView(updateInfo.scrollRect, updateInfo.scrollOffset);
252 
253     for (size_t i = 0; i < updateInfo.updateRects.size(); ++i)
254         m_webPageProxy->setViewNeedsDisplay(updateInfo.updateRects[i]);
255 
256     if (WebPageProxy::debugPaintFlags() & kWKDebugFlashBackingStoreUpdates)
257         m_webPageProxy->flashBackingStoreUpdates(updateInfo.updateRects);
258 
259     if (shouldScroll)
260         m_webPageProxy->displayView();
261 }
262 
backingStoreStateDidChange(RespondImmediatelyOrNot respondImmediatelyOrNot)263 void DrawingAreaProxyImpl::backingStoreStateDidChange(RespondImmediatelyOrNot respondImmediatelyOrNot)
264 {
265     ++m_nextBackingStoreStateID;
266     sendUpdateBackingStoreState(respondImmediatelyOrNot);
267 }
268 
sendUpdateBackingStoreState(RespondImmediatelyOrNot respondImmediatelyOrNot)269 void DrawingAreaProxyImpl::sendUpdateBackingStoreState(RespondImmediatelyOrNot respondImmediatelyOrNot)
270 {
271     ASSERT(m_currentBackingStoreStateID < m_nextBackingStoreStateID);
272 
273     if (!m_webPageProxy->isValid())
274         return;
275 
276     if (m_isWaitingForDidUpdateBackingStoreState)
277         return;
278 
279     m_isWaitingForDidUpdateBackingStoreState = respondImmediatelyOrNot == RespondImmediately;
280     m_webPageProxy->process()->send(Messages::DrawingArea::UpdateBackingStoreState(m_nextBackingStoreStateID, respondImmediatelyOrNot == RespondImmediately, m_size, m_scrollOffset), m_webPageProxy->pageID());
281     m_scrollOffset = IntSize();
282 
283 #if USE(ACCELERATED_COMPOSITING)
284     if (m_isWaitingForDidUpdateBackingStoreState && !m_layerTreeContext.isEmpty()) {
285         // Wait for the DidUpdateBackingStoreState message. Normally we don this in DrawingAreaProxyImpl::paint, but that
286         // function is never called when in accelerated compositing mode.
287         waitForAndDispatchDidUpdateBackingStoreState();
288     }
289 #endif
290 }
291 
waitForAndDispatchDidUpdateBackingStoreState()292 void DrawingAreaProxyImpl::waitForAndDispatchDidUpdateBackingStoreState()
293 {
294     ASSERT(m_isWaitingForDidUpdateBackingStoreState);
295 
296     if (!m_webPageProxy->isValid())
297         return;
298     if (m_webPageProxy->process()->isLaunching())
299         return;
300 
301 #if USE(ACCELERATED_COMPOSITING)
302     // FIXME: waitForAndDispatchImmediately will always return the oldest DidUpdateBackingStoreState message that
303     // hasn't yet been processed. But it might be better to skip ahead to some other DidUpdateBackingStoreState
304     // message, if multiple DidUpdateBackingStoreState messages are waiting to be processed. For instance, we could
305     // choose the most recent one, or the one that is closest to our current size.
306 
307     // The timeout, in seconds, we use when waiting for a DidUpdateBackingStoreState message when we're asked to paint.
308     static const double didUpdateBackingStoreStateTimeout = 0.5;
309     m_webPageProxy->process()->connection()->waitForAndDispatchImmediately<Messages::DrawingAreaProxy::DidUpdateBackingStoreState>(m_webPageProxy->pageID(), didUpdateBackingStoreStateTimeout);
310 #endif
311 }
312 
313 #if USE(ACCELERATED_COMPOSITING)
enterAcceleratedCompositingMode(const LayerTreeContext & layerTreeContext)314 void DrawingAreaProxyImpl::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
315 {
316     ASSERT(!isInAcceleratedCompositingMode());
317 
318     m_backingStore = nullptr;
319     m_layerTreeContext = layerTreeContext;
320     m_webPageProxy->enterAcceleratedCompositingMode(layerTreeContext);
321 }
322 
exitAcceleratedCompositingMode()323 void DrawingAreaProxyImpl::exitAcceleratedCompositingMode()
324 {
325     ASSERT(isInAcceleratedCompositingMode());
326 
327     m_layerTreeContext = LayerTreeContext();
328     m_webPageProxy->exitAcceleratedCompositingMode();
329 }
330 #endif
331 
discardBackingStoreSoon()332 void DrawingAreaProxyImpl::discardBackingStoreSoon()
333 {
334     if (!m_isBackingStoreDiscardable)
335         return;
336 
337     // We'll wait this many seconds after the last paint before throwing away our backing store to save memory.
338     // FIXME: It would be smarter to make this delay based on how expensive painting is. See <http://webkit.org/b/55733>.
339     static const double discardBackingStoreDelay = 5;
340 
341     m_discardBackingStoreTimer.startOneShot(discardBackingStoreDelay);
342 }
343 
discardBackingStore()344 void DrawingAreaProxyImpl::discardBackingStore()
345 {
346     m_backingStore = nullptr;
347     backingStoreStateDidChange(DoNotRespondImmediately);
348 }
349 
350 } // namespace WebKit
351