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