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