Replace uses of ArgumentEncoder/ArgumentDecoder with MessageEncoder/MessageDecoder
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / DrawingAreaImpl.cpp
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 "DrawingAreaImpl.h"
28
29 #include "DrawingAreaProxyMessages.h"
30 #include "LayerTreeContext.h"
31 #include "ShareableBitmap.h"
32 #include "UpdateInfo.h"
33 #include "WebPage.h"
34 #include "WebPageCreationParameters.h"
35 #include "WebProcess.h"
36 #include <WebCore/GraphicsContext.h>
37 #include <WebCore/Page.h>
38 #include <WebCore/Settings.h>
39
40 using namespace WebCore;
41 using namespace std;
42
43 namespace WebKit {
44
45 PassOwnPtr<DrawingAreaImpl> DrawingAreaImpl::create(WebPage* webPage, const WebPageCreationParameters& parameters)
46 {
47     return adoptPtr(new DrawingAreaImpl(webPage, parameters));
48 }
49
50 DrawingAreaImpl::~DrawingAreaImpl()
51 {
52     if (m_layerTreeHost)
53         m_layerTreeHost->invalidate();
54 }
55
56 DrawingAreaImpl::DrawingAreaImpl(WebPage* webPage, const WebPageCreationParameters& parameters)
57     : DrawingArea(DrawingAreaTypeImpl, webPage)
58     , m_backingStoreStateID(0)
59     , m_isPaintingEnabled(true)
60     , m_inUpdateBackingStoreState(false)
61     , m_shouldSendDidUpdateBackingStoreState(false)
62     , m_isWaitingForDidUpdate(false)
63     , m_compositingAccordingToProxyMessages(false)
64     , m_layerTreeStateIsFrozen(false)
65     , m_wantsToExitAcceleratedCompositingMode(false)
66     , m_isPaintingSuspended(!parameters.isVisible)
67     , m_alwaysUseCompositing(false)
68     , m_displayTimer(WebProcess::shared().runLoop(), this, &DrawingAreaImpl::displayTimerFired)
69     , m_exitCompositingTimer(WebProcess::shared().runLoop(), this, &DrawingAreaImpl::exitAcceleratedCompositingMode)
70 {
71     if (webPage->corePage()->settings()->acceleratedDrawingEnabled() || webPage->corePage()->settings()->forceCompositingMode())
72         m_alwaysUseCompositing = true;
73
74 #if USE(COORDINATED_GRAPHICS)
75     m_alwaysUseCompositing = true;
76 #endif
77
78     if (m_alwaysUseCompositing)
79         enterAcceleratedCompositingMode(0);
80 }
81
82 void DrawingAreaImpl::setNeedsDisplay(const IntRect& rect)
83 {
84     if (!m_isPaintingEnabled)
85         return;
86
87     IntRect dirtyRect = rect;
88     dirtyRect.intersect(m_webPage->bounds());
89
90     if (dirtyRect.isEmpty())
91         return;
92
93     if (m_layerTreeHost) {
94         ASSERT(m_dirtyRegion.isEmpty());
95
96         m_layerTreeHost->setNonCompositedContentsNeedDisplay(dirtyRect);
97         return;
98     }
99     
100     if (m_webPage->mainFrameHasCustomRepresentation())
101         return;
102
103     m_dirtyRegion.unite(dirtyRect);
104     scheduleDisplay();
105 }
106
107 void DrawingAreaImpl::scroll(const IntRect& scrollRect, const IntSize& scrollOffset)
108 {
109     if (!m_isPaintingEnabled)
110         return;
111
112     if (m_layerTreeHost) {
113         ASSERT(m_scrollRect.isEmpty());
114         ASSERT(m_scrollOffset.isEmpty());
115         ASSERT(m_dirtyRegion.isEmpty());
116
117         m_layerTreeHost->scrollNonCompositedContents(scrollRect, scrollOffset);
118         return;
119     }
120
121     if (m_webPage->mainFrameHasCustomRepresentation())
122         return;
123
124     if (scrollRect.isEmpty())
125         return;
126
127     if (!m_scrollRect.isEmpty() && scrollRect != m_scrollRect) {
128         unsigned scrollArea = scrollRect.width() * scrollRect.height();
129         unsigned currentScrollArea = m_scrollRect.width() * m_scrollRect.height();
130
131         if (currentScrollArea >= scrollArea) {
132             // The rect being scrolled is at least as large as the rect we'd like to scroll.
133             // Go ahead and just invalidate the scroll rect.
134             setNeedsDisplay(scrollRect);
135             return;
136         }
137
138         // Just repaint the entire current scroll rect, we'll scroll the new rect instead.
139         setNeedsDisplay(m_scrollRect);
140         m_scrollRect = IntRect();
141         m_scrollOffset = IntSize();
142     }
143
144     // Get the part of the dirty region that is in the scroll rect.
145     Region dirtyRegionInScrollRect = intersect(scrollRect, m_dirtyRegion);
146     if (!dirtyRegionInScrollRect.isEmpty()) {
147         // There are parts of the dirty region that are inside the scroll rect.
148         // We need to subtract them from the region, move them and re-add them.
149         m_dirtyRegion.subtract(scrollRect);
150
151         // Move the dirty parts.
152         Region movedDirtyRegionInScrollRect = intersect(translate(dirtyRegionInScrollRect, scrollOffset), scrollRect);
153
154         // And add them back.
155         m_dirtyRegion.unite(movedDirtyRegionInScrollRect);
156     } 
157     
158     // Compute the scroll repaint region.
159     Region scrollRepaintRegion = subtract(scrollRect, translate(scrollRect, scrollOffset));
160
161     m_dirtyRegion.unite(scrollRepaintRegion);
162     scheduleDisplay();
163
164     m_scrollRect = scrollRect;
165     m_scrollOffset += scrollOffset;
166 }
167
168 void DrawingAreaImpl::setLayerTreeStateIsFrozen(bool isFrozen)
169 {
170     if (m_layerTreeStateIsFrozen == isFrozen)
171         return;
172
173     m_layerTreeStateIsFrozen = isFrozen;
174
175     if (m_layerTreeHost)
176         m_layerTreeHost->setLayerFlushSchedulingEnabled(!isFrozen);
177
178     if (isFrozen)
179         m_exitCompositingTimer.stop();
180     else if (m_wantsToExitAcceleratedCompositingMode)
181         exitAcceleratedCompositingModeSoon();
182 }
183
184 void DrawingAreaImpl::forceRepaint()
185 {
186     setNeedsDisplay(m_webPage->bounds());
187
188     m_webPage->layoutIfNeeded();
189
190     if (m_layerTreeHost) {
191         // FIXME: We need to do the same work as the layerHostDidFlushLayers function here,
192         // but clearly it doesn't make sense to call the function with that name.
193         // Consider refactoring and renaming it.
194         if (m_compositingAccordingToProxyMessages)
195             m_layerTreeHost->forceRepaint();
196         else {
197             // Call setShouldNotifyAfterNextScheduledLayerFlush(false) here to 
198             // prevent layerHostDidFlushLayers() from being called a second time.
199             m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(false);
200             layerHostDidFlushLayers();
201         }
202         return;
203     }
204
205     m_isWaitingForDidUpdate = false;
206     display();
207 }
208
209 bool DrawingAreaImpl::forceRepaintAsync(uint64_t callbackID)
210 {
211     return m_layerTreeHost && m_layerTreeHost->forceRepaintAsync(callbackID);
212 }
213
214 void DrawingAreaImpl::didInstallPageOverlay()
215 {
216     if (m_layerTreeHost)
217         m_layerTreeHost->didInstallPageOverlay();
218 }
219
220 void DrawingAreaImpl::didUninstallPageOverlay()
221 {
222     if (m_layerTreeHost)
223         m_layerTreeHost->didUninstallPageOverlay();
224
225     setNeedsDisplay(m_webPage->bounds());
226 }
227
228 void DrawingAreaImpl::setPageOverlayNeedsDisplay(const IntRect& rect)
229 {
230     if (m_layerTreeHost) {
231         m_layerTreeHost->setPageOverlayNeedsDisplay(rect);
232         return;
233     }
234
235     setNeedsDisplay(rect);
236 }
237
238 void DrawingAreaImpl::setPageOverlayOpacity(float value)
239 {
240     if (m_layerTreeHost)
241         m_layerTreeHost->setPageOverlayOpacity(value);
242 }
243
244 bool DrawingAreaImpl::pageOverlayShouldApplyFadeWhenPainting() const
245 {
246     if (m_layerTreeHost && !m_layerTreeHost->pageOverlayShouldApplyFadeWhenPainting())
247         return false;
248
249     return true;
250 }
251
252 void DrawingAreaImpl::pageCustomRepresentationChanged()
253 {
254     if (!m_alwaysUseCompositing)
255         return;
256
257     if (m_webPage->mainFrameHasCustomRepresentation()) {
258         if (m_layerTreeHost)
259             exitAcceleratedCompositingMode();
260     } else if (!m_layerTreeHost)
261         enterAcceleratedCompositingMode(0);
262 }
263
264 void DrawingAreaImpl::setPaintingEnabled(bool paintingEnabled)
265 {
266     m_isPaintingEnabled = paintingEnabled;
267 }
268
269 void DrawingAreaImpl::updatePreferences(const WebPreferencesStore& store)
270 {
271 #if PLATFORM(MAC)
272     // Soon we want pages with fixed positioned elements to be able to be scrolled by the ScrollingCoordinator.
273     // As a part of that work, we have to composite fixed position elements, and we have to allow those
274     // elements to create a stacking context.
275     m_webPage->corePage()->settings()->setAcceleratedCompositingForFixedPositionEnabled(true);
276     m_webPage->corePage()->settings()->setFixedPositionCreatesStackingContext(true);
277
278     // <rdar://problem/10697417>: It is necessary to force compositing when accelerate drawing
279     // is enabled on Mac so that scrollbars are always in their own layers.
280     if (m_webPage->corePage()->settings()->acceleratedDrawingEnabled())
281         m_webPage->corePage()->settings()->setForceCompositingMode(LayerTreeHost::supportsAcceleratedCompositing());
282     else
283 #endif
284         m_webPage->corePage()->settings()->setForceCompositingMode(store.getBoolValueForKey(WebPreferencesKey::forceCompositingModeKey()) && LayerTreeHost::supportsAcceleratedCompositing());
285 }
286
287 void DrawingAreaImpl::layerHostDidFlushLayers()
288 {
289     ASSERT(m_layerTreeHost);
290
291     m_layerTreeHost->forceRepaint();
292
293     if (m_shouldSendDidUpdateBackingStoreState && !exitAcceleratedCompositingModePending()) {
294         sendDidUpdateBackingStoreState();
295         return;
296     }
297
298     if (!m_layerTreeHost)
299         return;
300
301 #if USE(ACCELERATED_COMPOSITING)
302     ASSERT(!m_compositingAccordingToProxyMessages);
303     if (!exitAcceleratedCompositingModePending()) {
304         m_webPage->send(Messages::DrawingAreaProxy::EnterAcceleratedCompositingMode(m_backingStoreStateID, m_layerTreeHost->layerTreeContext()));
305         m_compositingAccordingToProxyMessages = true;
306     }
307 #endif
308 }
309
310 GraphicsLayerFactory* DrawingAreaImpl::graphicsLayerFactory()
311 {
312     if (m_layerTreeHost)
313         return m_layerTreeHost->graphicsLayerFactory();
314
315     return 0;
316 }
317
318 void DrawingAreaImpl::setRootCompositingLayer(GraphicsLayer* graphicsLayer)
319 {
320     // FIXME: Instead of using nested if statements, we should keep a compositing state
321     // enum in the DrawingAreaImpl object and have a changeAcceleratedCompositingState function
322     // that takes the new state.
323
324     if (graphicsLayer) {
325         if (!m_layerTreeHost) {
326             // We're actually entering accelerated compositing mode.
327             enterAcceleratedCompositingMode(graphicsLayer);
328         } else {
329             // We're already in accelerated compositing mode, but the root compositing layer changed.
330
331             m_exitCompositingTimer.stop();
332             m_wantsToExitAcceleratedCompositingMode = false;
333
334             // If we haven't sent the EnterAcceleratedCompositingMode message, make sure that the
335             // layer tree host calls us back after the next layer flush so we can send it then.
336             if (!m_compositingAccordingToProxyMessages)
337                 m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(true);
338
339             m_layerTreeHost->setRootCompositingLayer(graphicsLayer);
340         }
341     } else {
342         if (m_layerTreeHost) {
343             m_layerTreeHost->setRootCompositingLayer(0);
344             if (!m_alwaysUseCompositing) {
345                 // We'll exit accelerated compositing mode on a timer, to avoid re-entering
346                 // compositing code via display() and layout.
347                 // If we're leaving compositing mode because of a setSize, it is safe to
348                 // exit accelerated compositing mode right away.
349                 if (m_inUpdateBackingStoreState)
350                     exitAcceleratedCompositingMode();
351                 else
352                     exitAcceleratedCompositingModeSoon();
353             }
354         }
355     }
356 }
357
358 void DrawingAreaImpl::scheduleCompositingLayerFlush()
359 {
360     if (!m_layerTreeHost)
361         return;
362     m_layerTreeHost->scheduleLayerFlush();
363 }
364
365 void DrawingAreaImpl::updateBackingStoreState(uint64_t stateID, bool respondImmediately, float deviceScaleFactor, const WebCore::IntSize& size, const WebCore::IntSize& scrollOffset)
366 {
367     ASSERT(!m_inUpdateBackingStoreState);
368     m_inUpdateBackingStoreState = true;
369
370     ASSERT_ARG(stateID, stateID >= m_backingStoreStateID);
371     if (stateID != m_backingStoreStateID) {
372         m_backingStoreStateID = stateID;
373         m_shouldSendDidUpdateBackingStoreState = true;
374
375         m_webPage->setDeviceScaleFactor(deviceScaleFactor);
376         m_webPage->setSize(size);
377         m_webPage->layoutIfNeeded();
378         m_webPage->scrollMainFrameIfNotAtMaxScrollPosition(scrollOffset);
379
380         if (m_layerTreeHost) {
381             m_layerTreeHost->deviceScaleFactorDidChange();
382             // Use the previously set page size instead of the argument.
383             // It gets adjusted properly when using the fixed layout mode.
384             m_layerTreeHost->sizeDidChange(m_webPage->size());
385         } else
386             m_dirtyRegion = m_webPage->bounds();
387     } else {
388         ASSERT(size == m_webPage->size());
389         if (!m_shouldSendDidUpdateBackingStoreState) {
390             // We've already sent a DidUpdateBackingStoreState message for this state. We have nothing more to do.
391             m_inUpdateBackingStoreState = false;
392             return;
393         }
394     }
395
396     // The UI process has updated to a new backing store state. Any Update messages we sent before
397     // this point will be ignored. We wait to set this to false until after updating the page's
398     // size so that any displays triggered by the relayout will be ignored. If we're supposed to
399     // respond to the UpdateBackingStoreState message immediately, we'll do a display anyway in
400     // sendDidUpdateBackingStoreState; otherwise we shouldn't do one right now.
401     m_isWaitingForDidUpdate = false;
402
403     if (respondImmediately) {
404         // Make sure to resume painting if we're supposed to respond immediately, otherwise we'll just
405         // send back an empty UpdateInfo struct.
406         if (m_isPaintingSuspended)
407             resumePainting();
408
409         sendDidUpdateBackingStoreState();
410     }
411
412     m_inUpdateBackingStoreState = false;
413 }
414
415 void DrawingAreaImpl::sendDidUpdateBackingStoreState()
416 {
417     ASSERT(!m_isWaitingForDidUpdate);
418     ASSERT(m_shouldSendDidUpdateBackingStoreState);
419
420     m_shouldSendDidUpdateBackingStoreState = false;
421
422     UpdateInfo updateInfo;
423
424     if (!m_isPaintingSuspended && !m_layerTreeHost)
425         display(updateInfo);
426
427     LayerTreeContext layerTreeContext;
428
429     if (m_isPaintingSuspended || m_layerTreeHost) {
430         updateInfo.viewSize = m_webPage->size();
431         updateInfo.deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor();
432
433         if (m_layerTreeHost) {
434             layerTreeContext = m_layerTreeHost->layerTreeContext();
435
436             // We don't want the layer tree host to notify after the next scheduled
437             // layer flush because that might end up sending an EnterAcceleratedCompositingMode
438             // message back to the UI process, but the updated layer tree context
439             // will be sent back in the DidUpdateBackingStoreState message.
440             m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(false);
441             m_layerTreeHost->forceRepaint();
442         }
443     }
444
445     m_webPage->send(Messages::DrawingAreaProxy::DidUpdateBackingStoreState(m_backingStoreStateID, updateInfo, layerTreeContext));
446     m_compositingAccordingToProxyMessages = !layerTreeContext.isEmpty();
447 }
448
449 void DrawingAreaImpl::didUpdate()
450 {
451     // We might get didUpdate messages from the UI process even after we've
452     // entered accelerated compositing mode. Ignore them.
453     if (m_layerTreeHost)
454         return;
455
456     m_isWaitingForDidUpdate = false;
457
458     // Display if needed. We call displayTimerFired here since it will throttle updates to 60fps.
459     displayTimerFired();
460 }
461
462 void DrawingAreaImpl::suspendPainting()
463 {
464     ASSERT(!m_isPaintingSuspended);
465
466     if (m_layerTreeHost)
467         m_layerTreeHost->pauseRendering();
468
469     m_isPaintingSuspended = true;
470     m_displayTimer.stop();
471
472     m_webPage->corePage()->suspendScriptedAnimations();
473 }
474
475 void DrawingAreaImpl::resumePainting()
476 {
477     if (!m_isPaintingSuspended) {
478         // FIXME: We can get a call to resumePainting when painting is not suspended.
479         // This happens when sending a synchronous message to create a new page. See <rdar://problem/8976531>.
480         return;
481     }
482     
483     if (m_layerTreeHost)
484         m_layerTreeHost->resumeRendering();
485         
486     m_isPaintingSuspended = false;
487
488     // FIXME: We shouldn't always repaint everything here.
489     setNeedsDisplay(m_webPage->bounds());
490
491 #if PLATFORM(MAC)
492     if (m_webPage->windowIsVisible())
493         m_webPage->corePage()->resumeScriptedAnimations();
494 #else
495     m_webPage->corePage()->resumeScriptedAnimations();
496 #endif
497 }
498
499 void DrawingAreaImpl::enterAcceleratedCompositingMode(GraphicsLayer* graphicsLayer)
500 {
501     m_exitCompositingTimer.stop();
502     m_wantsToExitAcceleratedCompositingMode = false;
503
504     ASSERT(!m_layerTreeHost);
505
506     m_layerTreeHost = LayerTreeHost::create(m_webPage);
507     if (!m_inUpdateBackingStoreState)
508         m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(true);
509
510     m_layerTreeHost->setRootCompositingLayer(graphicsLayer);
511     
512     // Non-composited content will now be handled exclusively by the layer tree host.
513     m_dirtyRegion = Region();
514     m_scrollRect = IntRect();
515     m_scrollOffset = IntSize();
516     m_displayTimer.stop();
517     m_isWaitingForDidUpdate = false;
518 }
519
520 void DrawingAreaImpl::exitAcceleratedCompositingMode()
521 {
522     if (m_alwaysUseCompositing && !m_webPage->mainFrameHasCustomRepresentation())
523         return;
524
525     ASSERT(!m_layerTreeStateIsFrozen);
526
527     m_exitCompositingTimer.stop();
528     m_wantsToExitAcceleratedCompositingMode = false;
529
530     ASSERT(m_layerTreeHost);
531
532     m_layerTreeHost->invalidate();
533     m_layerTreeHost = nullptr;
534     m_dirtyRegion = m_webPage->bounds();
535
536     if (m_inUpdateBackingStoreState)
537         return;
538
539     if (m_shouldSendDidUpdateBackingStoreState) {
540         sendDidUpdateBackingStoreState();
541         return;
542     }
543
544     UpdateInfo updateInfo;
545     if (m_isPaintingSuspended) {
546         updateInfo.viewSize = m_webPage->size();
547         updateInfo.deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor();
548     } else
549         display(updateInfo);
550
551 #if USE(ACCELERATED_COMPOSITING)
552     // Send along a complete update of the page so we can paint the contents right after we exit the
553     // accelerated compositing mode, eliminiating flicker.
554     if (m_compositingAccordingToProxyMessages) {
555         m_webPage->send(Messages::DrawingAreaProxy::ExitAcceleratedCompositingMode(m_backingStoreStateID, updateInfo));
556         m_compositingAccordingToProxyMessages = false;
557     } else {
558         // If we left accelerated compositing mode before we sent an EnterAcceleratedCompositingMode message to the
559         // UI process, we still need to let it know about the new contents, so send an Update message.
560         m_webPage->send(Messages::DrawingAreaProxy::Update(m_backingStoreStateID, updateInfo));
561     }
562 #endif
563 }
564
565 void DrawingAreaImpl::exitAcceleratedCompositingModeSoon()
566 {
567     if (m_layerTreeStateIsFrozen) {
568         m_wantsToExitAcceleratedCompositingMode = true;
569         return;
570     }
571
572     if (exitAcceleratedCompositingModePending())
573         return;
574
575     m_exitCompositingTimer.startOneShot(0);
576 }
577
578 void DrawingAreaImpl::scheduleDisplay()
579 {
580     ASSERT(!m_layerTreeHost);
581
582     if (m_isWaitingForDidUpdate)
583         return;
584
585     if (m_isPaintingSuspended)
586         return;
587
588     if (m_dirtyRegion.isEmpty())
589         return;
590
591     if (m_displayTimer.isActive())
592         return;
593
594     m_displayTimer.startOneShot(0);
595 }
596
597 void DrawingAreaImpl::displayTimerFired()
598 {
599     display();
600 }
601
602 void DrawingAreaImpl::display()
603 {
604     ASSERT(!m_layerTreeHost);
605     ASSERT(!m_isWaitingForDidUpdate);
606     ASSERT(!m_inUpdateBackingStoreState);
607
608     if (m_isPaintingSuspended)
609         return;
610
611     if (m_dirtyRegion.isEmpty())
612         return;
613
614     if (m_shouldSendDidUpdateBackingStoreState) {
615         sendDidUpdateBackingStoreState();
616         return;
617     }
618
619     UpdateInfo updateInfo;
620     display(updateInfo);
621
622     if (m_layerTreeHost) {
623         // The call to update caused layout which turned on accelerated compositing.
624         // Don't send an Update message in this case.
625         return;
626     }
627
628     m_webPage->send(Messages::DrawingAreaProxy::Update(m_backingStoreStateID, updateInfo));
629     m_isWaitingForDidUpdate = true;
630 }
631
632 static bool shouldPaintBoundsRect(const IntRect& bounds, const Vector<IntRect>& rects)
633 {
634     const size_t rectThreshold = 10;
635     const double wastedSpaceThreshold = 0.75;
636
637     if (rects.size() <= 1 || rects.size() > rectThreshold)
638         return true;
639
640     // Attempt to guess whether or not we should use the region bounds rect or the individual rects.
641     // We do this by computing the percentage of "wasted space" in the bounds.  If that wasted space
642     // is too large, then we will do individual rect painting instead.
643     unsigned boundsArea = bounds.width() * bounds.height();
644     unsigned rectsArea = 0;
645     for (size_t i = 0; i < rects.size(); ++i)
646         rectsArea += rects[i].width() * rects[i].height();
647
648     double wastedSpace = 1 - (static_cast<double>(rectsArea) / boundsArea);
649
650     return wastedSpace <= wastedSpaceThreshold;
651 }
652
653 #if !PLATFORM(WIN)
654 PassOwnPtr<GraphicsContext> DrawingAreaImpl::createGraphicsContext(ShareableBitmap* bitmap)
655 {
656     return bitmap->createGraphicsContext();
657 }
658 #endif
659
660 void DrawingAreaImpl::display(UpdateInfo& updateInfo)
661 {
662     ASSERT(!m_isPaintingSuspended);
663     ASSERT(!m_layerTreeHost);
664     ASSERT(!m_webPage->size().isEmpty());
665
666     // FIXME: It would be better if we could avoid painting altogether when there is a custom representation.
667     if (m_webPage->mainFrameHasCustomRepresentation()) {
668         // ASSUMPTION: the custom representation will be painting the dirty region for us.
669         m_dirtyRegion = Region();
670         return;
671     }
672
673     m_webPage->layoutIfNeeded();
674
675     // The layout may have put the page into accelerated compositing mode. If the LayerTreeHost is
676     // in charge of displaying, we have nothing more to do.
677     if (m_layerTreeHost)
678         return;
679
680     updateInfo.viewSize = m_webPage->size();
681     updateInfo.deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor();
682
683     IntRect bounds = m_dirtyRegion.bounds();
684     ASSERT(m_webPage->bounds().contains(bounds));
685
686     IntSize bitmapSize = bounds.size();
687     float deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor();
688     bitmapSize.scale(deviceScaleFactor);
689     RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(bitmapSize, ShareableBitmap::SupportsAlpha);
690     if (!bitmap)
691         return;
692
693     if (!bitmap->createHandle(updateInfo.bitmapHandle))
694         return;
695
696     Vector<IntRect> rects = m_dirtyRegion.rects();
697
698     if (shouldPaintBoundsRect(bounds, rects)) {
699         rects.clear();
700         rects.append(bounds);
701     }
702
703     updateInfo.scrollRect = m_scrollRect;
704     updateInfo.scrollOffset = m_scrollOffset;
705
706     m_dirtyRegion = Region();
707     m_scrollRect = IntRect();
708     m_scrollOffset = IntSize();
709
710     OwnPtr<GraphicsContext> graphicsContext = createGraphicsContext(bitmap.get());
711     graphicsContext->applyDeviceScaleFactor(deviceScaleFactor);
712     
713     updateInfo.updateRectBounds = bounds;
714
715     graphicsContext->translate(-bounds.x(), -bounds.y());
716
717     for (size_t i = 0; i < rects.size(); ++i) {
718         m_webPage->drawRect(*graphicsContext, rects[i]);
719         if (m_webPage->hasPageOverlay())
720             m_webPage->drawPageOverlay(*graphicsContext, rects[i]);
721         updateInfo.updateRects.append(rects[i]);
722     }
723
724     // Layout can trigger more calls to setNeedsDisplay and we don't want to process them
725     // until the UI process has painted the update, so we stop the timer here.
726     m_displayTimer.stop();
727 }
728
729 #if USE(COORDINATED_GRAPHICS)
730 void DrawingAreaImpl::didReceiveLayerTreeCoordinatorMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::MessageDecoder& decoder)
731 {
732     if (m_layerTreeHost)
733         m_layerTreeHost->didReceiveLayerTreeCoordinatorMessage(connection, messageID, decoder);
734 }
735 #endif
736
737 #if PLATFORM(MAC)
738 void DrawingAreaImpl::setLayerHostingMode(uint32_t opaqueLayerHostingMode)
739 {
740     LayerHostingMode layerHostingMode = static_cast<LayerHostingMode>(opaqueLayerHostingMode);
741     m_webPage->setLayerHostingMode(layerHostingMode);
742
743     if (!m_layerTreeHost)
744         return;
745
746     LayerTreeContext oldLayerTreeContext = m_layerTreeHost->layerTreeContext();
747     m_layerTreeHost->setLayerHostingMode(layerHostingMode);
748
749     if (m_layerTreeHost->layerTreeContext() != oldLayerTreeContext)
750         m_webPage->send(Messages::DrawingAreaProxy::UpdateAcceleratedCompositingMode(m_backingStoreStateID, m_layerTreeHost->layerTreeContext()));
751 }
752 #endif
753
754 } // namespace WebKit