summaryrefslogtreecommitdiff
path: root/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
commit40736c5763bf61337c8c14e16d8587db021a87d4 (patch)
treeb17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp
downloadqtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp')
-rw-r--r--Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp679
1 files changed, 679 insertions, 0 deletions
diff --git a/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp b/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp
new file mode 100644
index 000000000..e281d3652
--- /dev/null
+++ b/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp
@@ -0,0 +1,679 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DrawingAreaImpl.h"
+
+#include "DrawingAreaProxyMessages.h"
+#include "LayerTreeContext.h"
+#include "ShareableBitmap.h"
+#include "UpdateInfo.h"
+#include "WebPage.h"
+#include "WebPageCreationParameters.h"
+#include "WebProcess.h"
+#include <WebCore/GraphicsContext.h>
+#include <WebCore/Page.h>
+#include <WebCore/Settings.h>
+
+using namespace WebCore;
+using namespace std;
+
+namespace WebKit {
+
+PassOwnPtr<DrawingAreaImpl> DrawingAreaImpl::create(WebPage* webPage, const WebPageCreationParameters& parameters)
+{
+ return adoptPtr(new DrawingAreaImpl(webPage, parameters));
+}
+
+DrawingAreaImpl::~DrawingAreaImpl()
+{
+ if (m_layerTreeHost)
+ m_layerTreeHost->invalidate();
+}
+
+DrawingAreaImpl::DrawingAreaImpl(WebPage* webPage, const WebPageCreationParameters& parameters)
+ : DrawingArea(DrawingAreaTypeImpl, webPage)
+ , m_backingStoreStateID(0)
+ , m_isPaintingEnabled(true)
+ , m_inUpdateBackingStoreState(false)
+ , m_shouldSendDidUpdateBackingStoreState(false)
+ , m_isWaitingForDidUpdate(false)
+ , m_compositingAccordingToProxyMessages(false)
+ , m_layerTreeStateIsFrozen(false)
+ , m_wantsToExitAcceleratedCompositingMode(false)
+ , m_isPaintingSuspended(!parameters.isVisible)
+ , m_alwaysUseCompositing(false)
+ , m_displayTimer(WebProcess::shared().runLoop(), this, &DrawingAreaImpl::displayTimerFired)
+ , m_exitCompositingTimer(WebProcess::shared().runLoop(), this, &DrawingAreaImpl::exitAcceleratedCompositingMode)
+{
+ if (webPage->corePage()->settings()->acceleratedDrawingEnabled())
+ m_alwaysUseCompositing = true;
+
+ if (m_alwaysUseCompositing)
+ enterAcceleratedCompositingMode(0);
+}
+
+void DrawingAreaImpl::setNeedsDisplay(const IntRect& rect)
+{
+ if (!m_isPaintingEnabled)
+ return;
+
+ IntRect dirtyRect = rect;
+ dirtyRect.intersect(m_webPage->bounds());
+
+ if (dirtyRect.isEmpty())
+ return;
+
+ if (m_layerTreeHost) {
+ ASSERT(m_dirtyRegion.isEmpty());
+
+ m_layerTreeHost->setNonCompositedContentsNeedDisplay(dirtyRect);
+ return;
+ }
+
+ if (m_webPage->mainFrameHasCustomRepresentation())
+ return;
+
+ m_dirtyRegion.unite(dirtyRect);
+ scheduleDisplay();
+}
+
+void DrawingAreaImpl::scroll(const IntRect& scrollRect, const IntSize& scrollOffset)
+{
+ if (!m_isPaintingEnabled)
+ return;
+
+ if (m_layerTreeHost) {
+ ASSERT(m_scrollRect.isEmpty());
+ ASSERT(m_scrollOffset.isEmpty());
+ ASSERT(m_dirtyRegion.isEmpty());
+
+ m_layerTreeHost->scrollNonCompositedContents(scrollRect, scrollOffset);
+ return;
+ }
+
+ if (m_webPage->mainFrameHasCustomRepresentation())
+ return;
+
+ if (!m_scrollRect.isEmpty() && scrollRect != m_scrollRect) {
+ unsigned scrollArea = scrollRect.width() * scrollRect.height();
+ unsigned currentScrollArea = m_scrollRect.width() * m_scrollRect.height();
+
+ if (currentScrollArea >= scrollArea) {
+ // The rect being scrolled is at least as large as the rect we'd like to scroll.
+ // Go ahead and just invalidate the scroll rect.
+ setNeedsDisplay(scrollRect);
+ return;
+ }
+
+ // Just repaint the entire current scroll rect, we'll scroll the new rect instead.
+ setNeedsDisplay(m_scrollRect);
+ m_scrollRect = IntRect();
+ m_scrollOffset = IntSize();
+ }
+
+ // Get the part of the dirty region that is in the scroll rect.
+ Region dirtyRegionInScrollRect = intersect(scrollRect, m_dirtyRegion);
+ if (!dirtyRegionInScrollRect.isEmpty()) {
+ // There are parts of the dirty region that are inside the scroll rect.
+ // We need to subtract them from the region, move them and re-add them.
+ m_dirtyRegion.subtract(scrollRect);
+
+ // Move the dirty parts.
+ Region movedDirtyRegionInScrollRect = intersect(translate(dirtyRegionInScrollRect, scrollOffset), scrollRect);
+
+ // And add them back.
+ m_dirtyRegion.unite(movedDirtyRegionInScrollRect);
+ }
+
+ // Compute the scroll repaint region.
+ Region scrollRepaintRegion = subtract(scrollRect, translate(scrollRect, scrollOffset));
+
+ m_dirtyRegion.unite(scrollRepaintRegion);
+ scheduleDisplay();
+
+ m_scrollRect = scrollRect;
+ m_scrollOffset += scrollOffset;
+}
+
+void DrawingAreaImpl::setLayerTreeStateIsFrozen(bool isFrozen)
+{
+ if (m_layerTreeStateIsFrozen == isFrozen)
+ return;
+
+ m_layerTreeStateIsFrozen = isFrozen;
+
+ if (m_layerTreeHost)
+ m_layerTreeHost->setLayerFlushSchedulingEnabled(!isFrozen);
+
+ if (isFrozen)
+ m_exitCompositingTimer.stop();
+ else if (m_wantsToExitAcceleratedCompositingMode)
+ exitAcceleratedCompositingModeSoon();
+}
+
+void DrawingAreaImpl::forceRepaint()
+{
+ setNeedsDisplay(m_webPage->bounds());
+
+ m_webPage->layoutIfNeeded();
+
+ if (m_layerTreeHost) {
+ // FIXME: We need to do the same work as the layerHostDidFlushLayers function here,
+ // but clearly it doesn't make sense to call the function with that name.
+ // Consider refactoring and renaming it.
+ if (m_compositingAccordingToProxyMessages)
+ m_layerTreeHost->forceRepaint();
+ else {
+ // Call setShouldNotifyAfterNextScheduledLayerFlush(false) here to
+ // prevent layerHostDidFlushLayers() from being called a second time.
+ m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(false);
+ layerHostDidFlushLayers();
+ }
+ return;
+ }
+
+ m_isWaitingForDidUpdate = false;
+ display();
+}
+
+void DrawingAreaImpl::didInstallPageOverlay()
+{
+ if (m_layerTreeHost)
+ m_layerTreeHost->didInstallPageOverlay();
+}
+
+void DrawingAreaImpl::didUninstallPageOverlay()
+{
+ if (m_layerTreeHost)
+ m_layerTreeHost->didUninstallPageOverlay();
+
+ setNeedsDisplay(m_webPage->bounds());
+}
+
+void DrawingAreaImpl::setPageOverlayNeedsDisplay(const IntRect& rect)
+{
+ if (m_layerTreeHost) {
+ m_layerTreeHost->setPageOverlayNeedsDisplay(rect);
+ return;
+ }
+
+ setNeedsDisplay(rect);
+}
+
+void DrawingAreaImpl::pageCustomRepresentationChanged()
+{
+ if (!m_alwaysUseCompositing)
+ return;
+
+ if (m_webPage->mainFrameHasCustomRepresentation()) {
+ if (m_layerTreeHost)
+ exitAcceleratedCompositingMode();
+ } else if (!m_layerTreeHost)
+ enterAcceleratedCompositingMode(0);
+}
+
+void DrawingAreaImpl::setPaintingEnabled(bool paintingEnabled)
+{
+ m_isPaintingEnabled = paintingEnabled;
+}
+
+void DrawingAreaImpl::layerHostDidFlushLayers()
+{
+ ASSERT(m_layerTreeHost);
+
+ m_layerTreeHost->forceRepaint();
+
+ if (m_shouldSendDidUpdateBackingStoreState && !exitAcceleratedCompositingModePending()) {
+ sendDidUpdateBackingStoreState();
+ return;
+ }
+
+ if (!m_layerTreeHost)
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(!m_compositingAccordingToProxyMessages);
+ if (!exitAcceleratedCompositingModePending()) {
+ m_webPage->send(Messages::DrawingAreaProxy::EnterAcceleratedCompositingMode(m_backingStoreStateID, m_layerTreeHost->layerTreeContext()));
+ m_compositingAccordingToProxyMessages = true;
+ }
+#endif
+}
+
+void DrawingAreaImpl::setRootCompositingLayer(GraphicsLayer* graphicsLayer)
+{
+ // FIXME: Instead of using nested if statements, we should keep a compositing state
+ // enum in the DrawingAreaImpl object and have a changeAcceleratedCompositingState function
+ // that takes the new state.
+
+ if (graphicsLayer) {
+ if (!m_layerTreeHost) {
+ // We're actually entering accelerated compositing mode.
+ enterAcceleratedCompositingMode(graphicsLayer);
+ } else {
+ // We're already in accelerated compositing mode, but the root compositing layer changed.
+
+ m_exitCompositingTimer.stop();
+ m_wantsToExitAcceleratedCompositingMode = false;
+
+ // If we haven't sent the EnterAcceleratedCompositingMode message, make sure that the
+ // layer tree host calls us back after the next layer flush so we can send it then.
+ if (!m_compositingAccordingToProxyMessages)
+ m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(true);
+
+ m_layerTreeHost->setRootCompositingLayer(graphicsLayer);
+ }
+ } else {
+ if (m_layerTreeHost) {
+ m_layerTreeHost->setRootCompositingLayer(0);
+ if (!m_alwaysUseCompositing) {
+ // We'll exit accelerated compositing mode on a timer, to avoid re-entering
+ // compositing code via display() and layout.
+ // If we're leaving compositing mode because of a setSize, it is safe to
+ // exit accelerated compositing mode right away.
+ if (m_inUpdateBackingStoreState)
+ exitAcceleratedCompositingMode();
+ else
+ exitAcceleratedCompositingModeSoon();
+ }
+ }
+ }
+}
+
+void DrawingAreaImpl::scheduleCompositingLayerSync()
+{
+ if (!m_layerTreeHost)
+ return;
+ m_layerTreeHost->scheduleLayerFlush();
+}
+
+void DrawingAreaImpl::updateBackingStoreState(uint64_t stateID, bool respondImmediately, float deviceScaleFactor, const WebCore::IntSize& size, const WebCore::IntSize& scrollOffset)
+{
+ ASSERT(!m_inUpdateBackingStoreState);
+ m_inUpdateBackingStoreState = true;
+
+ ASSERT_ARG(stateID, stateID >= m_backingStoreStateID);
+ if (stateID != m_backingStoreStateID) {
+ m_backingStoreStateID = stateID;
+ m_shouldSendDidUpdateBackingStoreState = true;
+
+ m_webPage->setDeviceScaleFactor(deviceScaleFactor);
+ m_webPage->setSize(size);
+ m_webPage->layoutIfNeeded();
+ m_webPage->scrollMainFrameIfNotAtMaxScrollPosition(scrollOffset);
+
+ if (m_layerTreeHost) {
+ m_layerTreeHost->deviceScaleFactorDidChange();
+ m_layerTreeHost->sizeDidChange(size);
+ } else
+ m_dirtyRegion = m_webPage->bounds();
+ } else {
+ ASSERT(size == m_webPage->size());
+ if (!m_shouldSendDidUpdateBackingStoreState) {
+ // We've already sent a DidUpdateBackingStoreState message for this state. We have nothing more to do.
+ m_inUpdateBackingStoreState = false;
+ return;
+ }
+ }
+
+ // The UI process has updated to a new backing store state. Any Update messages we sent before
+ // this point will be ignored. We wait to set this to false until after updating the page's
+ // size so that any displays triggered by the relayout will be ignored. If we're supposed to
+ // respond to the UpdateBackingStoreState message immediately, we'll do a display anyway in
+ // sendDidUpdateBackingStoreState; otherwise we shouldn't do one right now.
+ m_isWaitingForDidUpdate = false;
+
+ if (respondImmediately) {
+ // Make sure to resume painting if we're supposed to respond immediately, otherwise we'll just
+ // send back an empty UpdateInfo struct.
+ if (m_isPaintingSuspended)
+ resumePainting();
+
+ sendDidUpdateBackingStoreState();
+ }
+
+ m_inUpdateBackingStoreState = false;
+}
+
+void DrawingAreaImpl::sendDidUpdateBackingStoreState()
+{
+ ASSERT(!m_isWaitingForDidUpdate);
+ ASSERT(m_shouldSendDidUpdateBackingStoreState);
+
+ m_shouldSendDidUpdateBackingStoreState = false;
+
+ UpdateInfo updateInfo;
+
+ if (!m_isPaintingSuspended && !m_layerTreeHost)
+ display(updateInfo);
+
+ LayerTreeContext layerTreeContext;
+
+ if (m_isPaintingSuspended || m_layerTreeHost) {
+ updateInfo.viewSize = m_webPage->size();
+ updateInfo.deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor();
+
+ if (m_layerTreeHost) {
+ layerTreeContext = m_layerTreeHost->layerTreeContext();
+
+ // We don't want the layer tree host to notify after the next scheduled
+ // layer flush because that might end up sending an EnterAcceleratedCompositingMode
+ // message back to the UI process, but the updated layer tree context
+ // will be sent back in the DidUpdateBackingStoreState message.
+ m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(false);
+ m_layerTreeHost->forceRepaint();
+ }
+ }
+
+ m_webPage->send(Messages::DrawingAreaProxy::DidUpdateBackingStoreState(m_backingStoreStateID, updateInfo, layerTreeContext));
+ m_compositingAccordingToProxyMessages = !layerTreeContext.isEmpty();
+}
+
+void DrawingAreaImpl::didUpdate()
+{
+ // We might get didUpdate messages from the UI process even after we've
+ // entered accelerated compositing mode. Ignore them.
+ if (m_layerTreeHost)
+ return;
+
+ m_isWaitingForDidUpdate = false;
+
+ // Display if needed. We call displayTimerFired here since it will throttle updates to 60fps.
+ displayTimerFired();
+}
+
+void DrawingAreaImpl::suspendPainting()
+{
+ ASSERT(!m_isPaintingSuspended);
+
+ if (m_layerTreeHost)
+ m_layerTreeHost->pauseRendering();
+
+ m_isPaintingSuspended = true;
+ m_displayTimer.stop();
+
+ m_webPage->corePage()->suspendScriptedAnimations();
+}
+
+void DrawingAreaImpl::resumePainting()
+{
+ if (!m_isPaintingSuspended) {
+ // FIXME: We can get a call to resumePainting when painting is not suspended.
+ // This happens when sending a synchronous message to create a new page. See <rdar://problem/8976531>.
+ return;
+ }
+
+ if (m_layerTreeHost)
+ m_layerTreeHost->resumeRendering();
+
+ m_isPaintingSuspended = false;
+
+ // FIXME: We shouldn't always repaint everything here.
+ setNeedsDisplay(m_webPage->bounds());
+
+ m_webPage->corePage()->resumeScriptedAnimations();
+}
+
+void DrawingAreaImpl::enterAcceleratedCompositingMode(GraphicsLayer* graphicsLayer)
+{
+ m_exitCompositingTimer.stop();
+ m_wantsToExitAcceleratedCompositingMode = false;
+
+ ASSERT(!m_layerTreeHost);
+
+ m_layerTreeHost = LayerTreeHost::create(m_webPage);
+ if (!m_inUpdateBackingStoreState)
+ m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(true);
+
+ m_layerTreeHost->setRootCompositingLayer(graphicsLayer);
+
+ // Non-composited content will now be handled exclusively by the layer tree host.
+ m_dirtyRegion = Region();
+ m_scrollRect = IntRect();
+ m_scrollOffset = IntSize();
+ m_displayTimer.stop();
+ m_isWaitingForDidUpdate = false;
+}
+
+void DrawingAreaImpl::exitAcceleratedCompositingMode()
+{
+ if (m_alwaysUseCompositing && !m_webPage->mainFrameHasCustomRepresentation())
+ return;
+
+ ASSERT(!m_layerTreeStateIsFrozen);
+
+ m_exitCompositingTimer.stop();
+ m_wantsToExitAcceleratedCompositingMode = false;
+
+ ASSERT(m_layerTreeHost);
+
+ m_layerTreeHost->invalidate();
+ m_layerTreeHost = nullptr;
+ m_dirtyRegion = m_webPage->bounds();
+
+ if (m_inUpdateBackingStoreState)
+ return;
+
+ if (m_shouldSendDidUpdateBackingStoreState) {
+ sendDidUpdateBackingStoreState();
+ return;
+ }
+
+ UpdateInfo updateInfo;
+ if (m_isPaintingSuspended) {
+ updateInfo.viewSize = m_webPage->size();
+ updateInfo.deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor();
+ } else
+ display(updateInfo);
+
+#if USE(ACCELERATED_COMPOSITING)
+ // Send along a complete update of the page so we can paint the contents right after we exit the
+ // accelerated compositing mode, eliminiating flicker.
+ if (m_compositingAccordingToProxyMessages) {
+ m_webPage->send(Messages::DrawingAreaProxy::ExitAcceleratedCompositingMode(m_backingStoreStateID, updateInfo));
+ m_compositingAccordingToProxyMessages = false;
+ } else {
+ // If we left accelerated compositing mode before we sent an EnterAcceleratedCompositingMode message to the
+ // UI process, we still need to let it know about the new contents, so send an Update message.
+ m_webPage->send(Messages::DrawingAreaProxy::Update(m_backingStoreStateID, updateInfo));
+ }
+#endif
+}
+
+void DrawingAreaImpl::exitAcceleratedCompositingModeSoon()
+{
+ if (m_layerTreeStateIsFrozen) {
+ m_wantsToExitAcceleratedCompositingMode = true;
+ return;
+ }
+
+ if (exitAcceleratedCompositingModePending())
+ return;
+
+ m_exitCompositingTimer.startOneShot(0);
+}
+
+void DrawingAreaImpl::scheduleDisplay()
+{
+ ASSERT(!m_layerTreeHost);
+
+ if (m_isWaitingForDidUpdate)
+ return;
+
+ if (m_isPaintingSuspended)
+ return;
+
+ if (m_dirtyRegion.isEmpty())
+ return;
+
+ if (m_displayTimer.isActive())
+ return;
+
+ m_displayTimer.startOneShot(0);
+}
+
+void DrawingAreaImpl::displayTimerFired()
+{
+ display();
+}
+
+void DrawingAreaImpl::display()
+{
+ ASSERT(!m_layerTreeHost);
+ ASSERT(!m_isWaitingForDidUpdate);
+ ASSERT(!m_inUpdateBackingStoreState);
+
+ if (m_isPaintingSuspended)
+ return;
+
+ if (m_dirtyRegion.isEmpty())
+ return;
+
+ if (m_shouldSendDidUpdateBackingStoreState) {
+ sendDidUpdateBackingStoreState();
+ return;
+ }
+
+ UpdateInfo updateInfo;
+ display(updateInfo);
+
+ if (m_layerTreeHost) {
+ // The call to update caused layout which turned on accelerated compositing.
+ // Don't send an Update message in this case.
+ return;
+ }
+
+ m_webPage->send(Messages::DrawingAreaProxy::Update(m_backingStoreStateID, updateInfo));
+ m_isWaitingForDidUpdate = true;
+}
+
+static bool shouldPaintBoundsRect(const IntRect& bounds, const Vector<IntRect>& rects)
+{
+ const size_t rectThreshold = 10;
+ const double wastedSpaceThreshold = 0.75;
+
+ if (rects.size() <= 1 || rects.size() > rectThreshold)
+ return true;
+
+ // Attempt to guess whether or not we should use the region bounds rect or the individual rects.
+ // We do this by computing the percentage of "wasted space" in the bounds. If that wasted space
+ // is too large, then we will do individual rect painting instead.
+ unsigned boundsArea = bounds.width() * bounds.height();
+ unsigned rectsArea = 0;
+ for (size_t i = 0; i < rects.size(); ++i)
+ rectsArea += rects[i].width() * rects[i].height();
+
+ double wastedSpace = 1 - (static_cast<double>(rectsArea) / boundsArea);
+
+ return wastedSpace <= wastedSpaceThreshold;
+}
+
+#if !PLATFORM(WIN)
+PassOwnPtr<GraphicsContext> DrawingAreaImpl::createGraphicsContext(ShareableBitmap* bitmap)
+{
+ return bitmap->createGraphicsContext();
+}
+#endif
+
+void DrawingAreaImpl::display(UpdateInfo& updateInfo)
+{
+ ASSERT(!m_isPaintingSuspended);
+ ASSERT(!m_layerTreeHost);
+ ASSERT(!m_webPage->size().isEmpty());
+
+ // FIXME: It would be better if we could avoid painting altogether when there is a custom representation.
+ if (m_webPage->mainFrameHasCustomRepresentation()) {
+ // ASSUMPTION: the custom representation will be painting the dirty region for us.
+ m_dirtyRegion = Region();
+ return;
+ }
+
+ m_webPage->layoutIfNeeded();
+
+ // The layout may have put the page into accelerated compositing mode. If the LayerTreeHost is
+ // in charge of displaying, we have nothing more to do.
+ if (m_layerTreeHost)
+ return;
+
+ updateInfo.viewSize = m_webPage->size();
+ updateInfo.deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor();
+
+ IntRect bounds = m_dirtyRegion.bounds();
+ ASSERT(m_webPage->bounds().contains(bounds));
+
+ IntSize bitmapSize = bounds.size();
+ float deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor();
+ bitmapSize.scale(deviceScaleFactor);
+ RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(bitmapSize, ShareableBitmap::SupportsAlpha);
+ if (!bitmap)
+ return;
+
+ if (!bitmap->createHandle(updateInfo.bitmapHandle))
+ return;
+
+ Vector<IntRect> rects = m_dirtyRegion.rects();
+
+ if (shouldPaintBoundsRect(bounds, rects)) {
+ rects.clear();
+ rects.append(bounds);
+ }
+
+ updateInfo.scrollRect = m_scrollRect;
+ updateInfo.scrollOffset = m_scrollOffset;
+
+ m_dirtyRegion = Region();
+ m_scrollRect = IntRect();
+ m_scrollOffset = IntSize();
+
+ OwnPtr<GraphicsContext> graphicsContext = createGraphicsContext(bitmap.get());
+ graphicsContext->applyDeviceScaleFactor(deviceScaleFactor);
+
+ updateInfo.updateRectBounds = bounds;
+
+ graphicsContext->translate(-bounds.x(), -bounds.y());
+
+ for (size_t i = 0; i < rects.size(); ++i) {
+ m_webPage->drawRect(*graphicsContext, rects[i]);
+ if (m_webPage->hasPageOverlay())
+ m_webPage->drawPageOverlay(*graphicsContext, rects[i]);
+ updateInfo.updateRects.append(rects[i]);
+ }
+
+ // Layout can trigger more calls to setNeedsDisplay and we don't want to process them
+ // until the UI process has painted the update, so we stop the timer here.
+ m_displayTimer.stop();
+}
+
+#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
+void DrawingAreaImpl::didReceiveLayerTreeHostMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
+{
+ if (m_layerTreeHost)
+ m_layerTreeHost->didReceiveLayerTreeHostMessage(connection, messageID, arguments);
+}
+#endif
+
+
+} // namespace WebKit