Merge "Fixed paste issue after selecting word in inputbox" into tizen_2.1
[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 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
469     m_webPage->send(Messages::DrawingAreaProxy::DidSuspendPainting());
470 #endif
471 }
472
473 void DrawingAreaImpl::resumePainting()
474 {
475     if (!m_isPaintingSuspended) {
476         // FIXME: We can get a call to resumePainting when painting is not suspended.
477         // This happens when sending a synchronous message to create a new page. See <rdar://problem/8976531>.
478         return;
479     }
480
481 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
482     if (--m_paintingSuspendCount > 0)
483         return;
484 #endif
485
486     if (m_layerTreeHost)
487         m_layerTreeHost->resumeRendering();
488         
489     m_isPaintingSuspended = false;
490
491     // FIXME: We shouldn't always repaint everything here.
492     setNeedsDisplay(m_webPage->bounds());
493
494 #if PLATFORM(MAC)
495     if (m_webPage->windowIsVisible())
496         m_webPage->corePage()->resumeScriptedAnimations();
497 #else
498     m_webPage->corePage()->resumeScriptedAnimations();
499 #endif
500 }
501
502 void DrawingAreaImpl::enterAcceleratedCompositingMode(GraphicsLayer* graphicsLayer)
503 {
504     m_exitCompositingTimer.stop();
505     m_wantsToExitAcceleratedCompositingMode = false;
506
507     ASSERT(!m_layerTreeHost);
508
509     m_layerTreeHost = LayerTreeHost::create(m_webPage);
510     if (!m_inUpdateBackingStoreState)
511         m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(true);
512
513     m_layerTreeHost->setRootCompositingLayer(graphicsLayer);
514     
515     // Non-composited content will now be handled exclusively by the layer tree host.
516     m_dirtyRegion = Region();
517     m_scrollRect = IntRect();
518     m_scrollOffset = IntSize();
519     m_displayTimer.stop();
520     m_isWaitingForDidUpdate = false;
521 }
522
523 void DrawingAreaImpl::exitAcceleratedCompositingMode()
524 {
525     if (m_alwaysUseCompositing && !m_webPage->mainFrameHasCustomRepresentation())
526         return;
527
528     ASSERT(!m_layerTreeStateIsFrozen);
529
530     m_exitCompositingTimer.stop();
531     m_wantsToExitAcceleratedCompositingMode = false;
532
533     ASSERT(m_layerTreeHost);
534
535     m_layerTreeHost->invalidate();
536     m_layerTreeHost = nullptr;
537     m_dirtyRegion = m_webPage->bounds();
538
539     if (m_inUpdateBackingStoreState)
540         return;
541
542     if (m_shouldSendDidUpdateBackingStoreState) {
543         sendDidUpdateBackingStoreState();
544         return;
545     }
546
547     UpdateInfo updateInfo;
548     if (m_isPaintingSuspended) {
549         updateInfo.viewSize = m_webPage->size();
550         updateInfo.deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor();
551     } else
552         display(updateInfo);
553
554 #if USE(ACCELERATED_COMPOSITING)
555     // Send along a complete update of the page so we can paint the contents right after we exit the
556     // accelerated compositing mode, eliminiating flicker.
557     if (m_compositingAccordingToProxyMessages) {
558         m_webPage->send(Messages::DrawingAreaProxy::ExitAcceleratedCompositingMode(m_backingStoreStateID, updateInfo));
559         m_compositingAccordingToProxyMessages = false;
560     } else {
561         // If we left accelerated compositing mode before we sent an EnterAcceleratedCompositingMode message to the
562         // UI process, we still need to let it know about the new contents, so send an Update message.
563         m_webPage->send(Messages::DrawingAreaProxy::Update(m_backingStoreStateID, updateInfo));
564     }
565 #endif
566 }
567
568 void DrawingAreaImpl::exitAcceleratedCompositingModeSoon()
569 {
570     if (m_layerTreeStateIsFrozen) {
571         m_wantsToExitAcceleratedCompositingMode = true;
572         return;
573     }
574
575     if (exitAcceleratedCompositingModePending())
576         return;
577
578     m_exitCompositingTimer.startOneShot(0);
579 }
580
581 void DrawingAreaImpl::scheduleDisplay()
582 {
583     ASSERT(!m_layerTreeHost);
584
585     if (m_isWaitingForDidUpdate)
586         return;
587
588     if (m_isPaintingSuspended)
589         return;
590
591     if (m_dirtyRegion.isEmpty())
592         return;
593
594     if (m_displayTimer.isActive())
595         return;
596
597     m_displayTimer.startOneShot(0);
598 }
599
600 void DrawingAreaImpl::displayTimerFired()
601 {
602     display();
603 }
604
605 void DrawingAreaImpl::display()
606 {
607     ASSERT(!m_layerTreeHost);
608     ASSERT(!m_isWaitingForDidUpdate);
609     ASSERT(!m_inUpdateBackingStoreState);
610
611     if (m_isPaintingSuspended)
612         return;
613
614     if (m_dirtyRegion.isEmpty())
615         return;
616
617     if (m_shouldSendDidUpdateBackingStoreState) {
618         sendDidUpdateBackingStoreState();
619         return;
620     }
621
622     UpdateInfo updateInfo;
623     display(updateInfo);
624
625     if (m_layerTreeHost) {
626         // The call to update caused layout which turned on accelerated compositing.
627         // Don't send an Update message in this case.
628         return;
629     }
630
631     m_webPage->send(Messages::DrawingAreaProxy::Update(m_backingStoreStateID, updateInfo));
632     m_isWaitingForDidUpdate = true;
633 }
634
635 static bool shouldPaintBoundsRect(const IntRect& bounds, const Vector<IntRect>& rects)
636 {
637     const size_t rectThreshold = 10;
638     const double wastedSpaceThreshold = 0.75;
639
640     if (rects.size() <= 1 || rects.size() > rectThreshold)
641         return true;
642
643     // Attempt to guess whether or not we should use the region bounds rect or the individual rects.
644     // We do this by computing the percentage of "wasted space" in the bounds.  If that wasted space
645     // is too large, then we will do individual rect painting instead.
646     unsigned boundsArea = bounds.width() * bounds.height();
647     unsigned rectsArea = 0;
648     for (size_t i = 0; i < rects.size(); ++i)
649         rectsArea += rects[i].width() * rects[i].height();
650
651     double wastedSpace = 1 - (static_cast<double>(rectsArea) / boundsArea);
652
653     return wastedSpace <= wastedSpaceThreshold;
654 }
655
656 #if !PLATFORM(WIN)
657 PassOwnPtr<GraphicsContext> DrawingAreaImpl::createGraphicsContext(ShareableBitmap* bitmap)
658 {
659     return bitmap->createGraphicsContext();
660 }
661 #endif
662
663 void DrawingAreaImpl::display(UpdateInfo& updateInfo)
664 {
665     ASSERT(!m_isPaintingSuspended);
666     ASSERT(!m_layerTreeHost);
667     ASSERT(!m_webPage->size().isEmpty());
668
669     // FIXME: It would be better if we could avoid painting altogether when there is a custom representation.
670     if (m_webPage->mainFrameHasCustomRepresentation()) {
671         // ASSUMPTION: the custom representation will be painting the dirty region for us.
672         m_dirtyRegion = Region();
673         return;
674     }
675
676     m_webPage->layoutIfNeeded();
677
678     // The layout may have put the page into accelerated compositing mode. If the LayerTreeHost is
679     // in charge of displaying, we have nothing more to do.
680     if (m_layerTreeHost)
681         return;
682
683     updateInfo.viewSize = m_webPage->size();
684     updateInfo.deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor();
685
686     IntRect bounds = m_dirtyRegion.bounds();
687     ASSERT(m_webPage->bounds().contains(bounds));
688
689     IntSize bitmapSize = bounds.size();
690     float deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor();
691     bitmapSize.scale(deviceScaleFactor);
692     RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(bitmapSize, ShareableBitmap::SupportsAlpha);
693     if (!bitmap)
694         return;
695
696     if (!bitmap->createHandle(updateInfo.bitmapHandle))
697         return;
698
699     Vector<IntRect> rects = m_dirtyRegion.rects();
700
701     if (shouldPaintBoundsRect(bounds, rects)) {
702         rects.clear();
703         rects.append(bounds);
704     }
705
706     updateInfo.scrollRect = m_scrollRect;
707     updateInfo.scrollOffset = m_scrollOffset;
708
709     m_dirtyRegion = Region();
710     m_scrollRect = IntRect();
711     m_scrollOffset = IntSize();
712
713     OwnPtr<GraphicsContext> graphicsContext = createGraphicsContext(bitmap.get());
714     graphicsContext->applyDeviceScaleFactor(deviceScaleFactor);
715     
716     updateInfo.updateRectBounds = bounds;
717
718     graphicsContext->translate(-bounds.x(), -bounds.y());
719
720     for (size_t i = 0; i < rects.size(); ++i) {
721         m_webPage->drawRect(*graphicsContext, rects[i]);
722         if (m_webPage->hasPageOverlay())
723             m_webPage->drawPageOverlay(*graphicsContext, rects[i]);
724         updateInfo.updateRects.append(rects[i]);
725     }
726
727     // Layout can trigger more calls to setNeedsDisplay and we don't want to process them
728     // until the UI process has painted the update, so we stop the timer here.
729     m_displayTimer.stop();
730 }
731
732 #if USE(UI_SIDE_COMPOSITING)
733 void DrawingAreaImpl::didReceiveLayerTreeCoordinatorMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
734 {
735     if (m_layerTreeHost)
736         m_layerTreeHost->didReceiveLayerTreeCoordinatorMessage(connection, messageID, arguments);
737 }
738 #endif
739
740 #if PLATFORM(MAC)
741 void DrawingAreaImpl::setLayerHostingMode(uint32_t opaqueLayerHostingMode)
742 {
743     LayerHostingMode layerHostingMode = static_cast<LayerHostingMode>(opaqueLayerHostingMode);
744     m_webPage->setLayerHostingMode(layerHostingMode);
745
746     if (!m_layerTreeHost)
747         return;
748
749     LayerTreeContext oldLayerTreeContext = m_layerTreeHost->layerTreeContext();
750     m_layerTreeHost->setLayerHostingMode(layerHostingMode);
751
752     if (m_layerTreeHost->layerTreeContext() != oldLayerTreeContext)
753         m_webPage->send(Messages::DrawingAreaProxy::UpdateAcceleratedCompositingMode(m_backingStoreStateID, m_layerTreeHost->layerTreeContext()));
754 }
755 #endif
756
757 #if ENABLE(TIZEN_LAYER_FLUSH_THROTTLING)
758 void DrawingAreaImpl::didStartProgress()
759 {
760     if (!m_layerTreeHost)
761         return;
762
763     m_layerTreeHost->setDeferLayerFlush(true);
764 }
765
766 void DrawingAreaImpl::didFinishProgress()
767 {
768     if (!m_layerTreeHost)
769         return;
770
771     m_layerTreeHost->setDeferLayerFlush(false);
772 }
773 #endif
774
775 } // namespace WebKit