summaryrefslogtreecommitdiff
path: root/Source/WebKit2/UIProcess/DrawingAreaProxyImpl.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/UIProcess/DrawingAreaProxyImpl.cpp
downloadqtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/WebKit2/UIProcess/DrawingAreaProxyImpl.cpp')
-rw-r--r--Source/WebKit2/UIProcess/DrawingAreaProxyImpl.cpp395
1 files changed, 395 insertions, 0 deletions
diff --git a/Source/WebKit2/UIProcess/DrawingAreaProxyImpl.cpp b/Source/WebKit2/UIProcess/DrawingAreaProxyImpl.cpp
new file mode 100644
index 000000000..7b153848d
--- /dev/null
+++ b/Source/WebKit2/UIProcess/DrawingAreaProxyImpl.cpp
@@ -0,0 +1,395 @@
+/*
+ * 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 "DrawingAreaProxyImpl.h"
+
+#include "DrawingAreaMessages.h"
+#include "DrawingAreaProxyMessages.h"
+#include "LayerTreeContext.h"
+#include "UpdateInfo.h"
+#include "WebPageProxy.h"
+#include "WebProcessProxy.h"
+#include <WebCore/Region.h>
+
+#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
+#include "LayerTreeHostProxy.h"
+#endif
+
+using namespace WebCore;
+
+namespace WebKit {
+
+PassOwnPtr<DrawingAreaProxyImpl> DrawingAreaProxyImpl::create(WebPageProxy* webPageProxy)
+{
+ return adoptPtr(new DrawingAreaProxyImpl(webPageProxy));
+}
+
+DrawingAreaProxyImpl::DrawingAreaProxyImpl(WebPageProxy* webPageProxy)
+ : DrawingAreaProxy(DrawingAreaTypeImpl, webPageProxy)
+ , m_currentBackingStoreStateID(0)
+ , m_nextBackingStoreStateID(0)
+ , m_isWaitingForDidUpdateBackingStoreState(false)
+ , m_hasReceivedFirstUpdate(false)
+ , m_isBackingStoreDiscardable(true)
+ , m_discardBackingStoreTimer(RunLoop::current(), this, &DrawingAreaProxyImpl::discardBackingStore)
+{
+}
+
+DrawingAreaProxyImpl::~DrawingAreaProxyImpl()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ // Make sure to exit accelerated compositing mode.
+ if (isInAcceleratedCompositingMode())
+ exitAcceleratedCompositingMode();
+#endif
+}
+
+void DrawingAreaProxyImpl::paint(BackingStore::PlatformGraphicsContext context, const IntRect& rect, Region& unpaintedRegion)
+{
+ unpaintedRegion = rect;
+
+ if (isInAcceleratedCompositingMode())
+ return;
+
+ ASSERT(m_currentBackingStoreStateID <= m_nextBackingStoreStateID);
+ if (m_currentBackingStoreStateID < m_nextBackingStoreStateID) {
+ // Tell the web process to do a full backing store update now, in case we previously told
+ // it about our next state but didn't request an immediate update.
+ sendUpdateBackingStoreState(RespondImmediately);
+
+ // If we haven't yet received our first bits from the WebProcess then don't paint anything.
+ if (!m_hasReceivedFirstUpdate)
+ return;
+
+ if (m_isWaitingForDidUpdateBackingStoreState) {
+ // Wait for a DidUpdateBackingStoreState message that contains the new bits before we paint
+ // what's currently in the backing store.
+ waitForAndDispatchDidUpdateBackingStoreState();
+ }
+
+ // Dispatching DidUpdateBackingStoreState (either beneath sendUpdateBackingStoreState or
+ // beneath waitForAndDispatchDidUpdateBackingStoreState) could destroy our backing store or
+ // change the compositing mode.
+ if (!m_backingStore || isInAcceleratedCompositingMode())
+ return;
+ } else {
+ ASSERT(!m_isWaitingForDidUpdateBackingStoreState);
+ if (!m_backingStore) {
+ // The view has asked us to paint before the web process has painted anything. There's
+ // nothing we can do.
+ return;
+ }
+ }
+
+ m_backingStore->paint(context, rect);
+ unpaintedRegion.subtract(IntRect(IntPoint(), m_backingStore->size()));
+
+ discardBackingStoreSoon();
+}
+
+void DrawingAreaProxyImpl::sizeDidChange()
+{
+ backingStoreStateDidChange(RespondImmediately);
+}
+
+void DrawingAreaProxyImpl::deviceScaleFactorDidChange()
+{
+ backingStoreStateDidChange(RespondImmediately);
+}
+
+void DrawingAreaProxyImpl::visibilityDidChange()
+{
+ if (!m_webPageProxy->isViewVisible()) {
+ // Suspend painting.
+ m_webPageProxy->process()->send(Messages::DrawingArea::SuspendPainting(), m_webPageProxy->pageID());
+ return;
+ }
+
+ // Resume painting.
+ m_webPageProxy->process()->send(Messages::DrawingArea::ResumePainting(), m_webPageProxy->pageID());
+
+#if USE(ACCELERATED_COMPOSITING)
+ // If we don't have a backing store, go ahead and mark the backing store as being changed so
+ // that when paint we'll actually wait for something to paint and not flash white.
+ if (!m_backingStore && m_layerTreeContext.isEmpty())
+ backingStoreStateDidChange(DoNotRespondImmediately);
+#endif
+}
+
+void DrawingAreaProxyImpl::setBackingStoreIsDiscardable(bool isBackingStoreDiscardable)
+{
+ if (m_isBackingStoreDiscardable == isBackingStoreDiscardable)
+ return;
+
+ m_isBackingStoreDiscardable = isBackingStoreDiscardable;
+ if (m_isBackingStoreDiscardable)
+ discardBackingStoreSoon();
+ else
+ m_discardBackingStoreTimer.stop();
+}
+
+void DrawingAreaProxyImpl::waitForBackingStoreUpdateOnNextPaint()
+{
+ m_hasReceivedFirstUpdate = true;
+}
+
+void DrawingAreaProxyImpl::update(uint64_t backingStoreStateID, const UpdateInfo& updateInfo)
+{
+ ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
+ if (backingStoreStateID < m_currentBackingStoreStateID)
+ return;
+
+ // FIXME: Handle the case where the view is hidden.
+
+ incorporateUpdate(updateInfo);
+ m_webPageProxy->process()->send(Messages::DrawingArea::DidUpdate(), m_webPageProxy->pageID());
+}
+
+void DrawingAreaProxyImpl::didUpdateBackingStoreState(uint64_t backingStoreStateID, const UpdateInfo& updateInfo, const LayerTreeContext& layerTreeContext)
+{
+ ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_nextBackingStoreStateID);
+ ASSERT_ARG(backingStoreStateID, backingStoreStateID > m_currentBackingStoreStateID);
+ m_currentBackingStoreStateID = backingStoreStateID;
+
+ m_isWaitingForDidUpdateBackingStoreState = false;
+
+ // Stop the responsiveness timer that was started in sendUpdateBackingStoreState.
+ m_webPageProxy->process()->responsivenessTimer()->stop();
+
+ if (m_nextBackingStoreStateID != m_currentBackingStoreStateID)
+ sendUpdateBackingStoreState(RespondImmediately);
+ else
+ m_hasReceivedFirstUpdate = true;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (layerTreeContext != m_layerTreeContext) {
+ if (!m_layerTreeContext.isEmpty()) {
+ exitAcceleratedCompositingMode();
+ ASSERT(m_layerTreeContext.isEmpty());
+ }
+
+ if (!layerTreeContext.isEmpty()) {
+ enterAcceleratedCompositingMode(layerTreeContext);
+ ASSERT(layerTreeContext == m_layerTreeContext);
+ }
+ }
+
+ if (isInAcceleratedCompositingMode()) {
+ ASSERT(!m_backingStore);
+ return;
+ }
+#endif
+
+ // If we have a backing store the right size, reuse it.
+ if (m_backingStore && (m_backingStore->size() != updateInfo.viewSize || m_backingStore->deviceScaleFactor() != updateInfo.deviceScaleFactor))
+ m_backingStore = nullptr;
+ incorporateUpdate(updateInfo);
+}
+
+void DrawingAreaProxyImpl::enterAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext& layerTreeContext)
+{
+ ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
+ if (backingStoreStateID < m_currentBackingStoreStateID)
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ enterAcceleratedCompositingMode(layerTreeContext);
+#endif
+}
+
+void DrawingAreaProxyImpl::exitAcceleratedCompositingMode(uint64_t backingStoreStateID, const UpdateInfo& updateInfo)
+{
+ ASSERT_ARG(backingStoreStateID, backingStoreStateID <= m_currentBackingStoreStateID);
+ if (backingStoreStateID < m_currentBackingStoreStateID)
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ exitAcceleratedCompositingMode();
+#endif
+
+ incorporateUpdate(updateInfo);
+}
+
+void DrawingAreaProxyImpl::incorporateUpdate(const UpdateInfo& updateInfo)
+{
+ ASSERT(!isInAcceleratedCompositingMode());
+
+ if (updateInfo.updateRectBounds.isEmpty())
+ return;
+
+ if (!m_backingStore)
+ m_backingStore = BackingStore::create(updateInfo.viewSize, updateInfo.deviceScaleFactor, m_webPageProxy);
+
+ m_backingStore->incorporateUpdate(updateInfo);
+
+ bool shouldScroll = !updateInfo.scrollRect.isEmpty();
+
+ if (shouldScroll)
+ m_webPageProxy->scrollView(updateInfo.scrollRect, updateInfo.scrollOffset);
+
+ for (size_t i = 0; i < updateInfo.updateRects.size(); ++i)
+ m_webPageProxy->setViewNeedsDisplay(updateInfo.updateRects[i]);
+
+ if (WebPageProxy::debugPaintFlags() & kWKDebugFlashBackingStoreUpdates)
+ m_webPageProxy->flashBackingStoreUpdates(updateInfo.updateRects);
+
+ if (shouldScroll)
+ m_webPageProxy->displayView();
+}
+
+void DrawingAreaProxyImpl::backingStoreStateDidChange(RespondImmediatelyOrNot respondImmediatelyOrNot)
+{
+ ++m_nextBackingStoreStateID;
+ sendUpdateBackingStoreState(respondImmediatelyOrNot);
+}
+
+void DrawingAreaProxyImpl::sendUpdateBackingStoreState(RespondImmediatelyOrNot respondImmediatelyOrNot)
+{
+ ASSERT(m_currentBackingStoreStateID < m_nextBackingStoreStateID);
+
+ if (!m_webPageProxy->isValid())
+ return;
+
+ if (m_isWaitingForDidUpdateBackingStoreState)
+ return;
+
+ if (m_webPageProxy->viewSize().isEmpty())
+ return;
+
+ m_isWaitingForDidUpdateBackingStoreState = respondImmediatelyOrNot == RespondImmediately;
+
+ m_webPageProxy->process()->send(Messages::DrawingArea::UpdateBackingStoreState(m_nextBackingStoreStateID, respondImmediatelyOrNot == RespondImmediately, m_webPageProxy->deviceScaleFactor(), m_size, m_scrollOffset), m_webPageProxy->pageID());
+ m_scrollOffset = IntSize();
+
+ if (m_isWaitingForDidUpdateBackingStoreState) {
+ // Start the responsiveness timer. We will stop it when we hear back from the WebProcess
+ // in didUpdateBackingStoreState.
+ m_webPageProxy->process()->responsivenessTimer()->start();
+ }
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_isWaitingForDidUpdateBackingStoreState && !m_layerTreeContext.isEmpty()) {
+ // Wait for the DidUpdateBackingStoreState message. Normally we do this in DrawingAreaProxyImpl::paint, but that
+ // function is never called when in accelerated compositing mode.
+ waitForAndDispatchDidUpdateBackingStoreState();
+ }
+#endif
+}
+
+void DrawingAreaProxyImpl::waitForAndDispatchDidUpdateBackingStoreState()
+{
+ ASSERT(m_isWaitingForDidUpdateBackingStoreState);
+
+ if (!m_webPageProxy->isValid())
+ return;
+ if (m_webPageProxy->process()->isLaunching())
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ // FIXME: waitForAndDispatchImmediately will always return the oldest DidUpdateBackingStoreState message that
+ // hasn't yet been processed. But it might be better to skip ahead to some other DidUpdateBackingStoreState
+ // message, if multiple DidUpdateBackingStoreState messages are waiting to be processed. For instance, we could
+ // choose the most recent one, or the one that is closest to our current size.
+
+ // The timeout, in seconds, we use when waiting for a DidUpdateBackingStoreState message when we're asked to paint.
+ static const double didUpdateBackingStoreStateTimeout = 0.5;
+ m_webPageProxy->process()->connection()->waitForAndDispatchImmediately<Messages::DrawingAreaProxy::DidUpdateBackingStoreState>(m_webPageProxy->pageID(), didUpdateBackingStoreStateTimeout);
+#endif
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+void DrawingAreaProxyImpl::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
+{
+ ASSERT(!isInAcceleratedCompositingMode());
+
+ m_backingStore = nullptr;
+ m_layerTreeContext = layerTreeContext;
+ m_webPageProxy->enterAcceleratedCompositingMode(layerTreeContext);
+#if USE(TEXTURE_MAPPER)
+ if (!m_layerTreeHostProxy)
+ m_layerTreeHostProxy = adoptPtr(new LayerTreeHostProxy(this));
+#endif
+}
+
+#if USE(TILED_BACKING_STORE)
+void DrawingAreaProxyImpl::didReceiveLayerTreeHostProxyMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
+{
+ if (m_layerTreeHostProxy)
+ m_layerTreeHostProxy->didReceiveLayerTreeHostProxyMessage(connection, messageID, arguments);
+}
+
+void DrawingAreaProxyImpl::setVisibleContentsRectAndScale(const WebCore::IntRect& visibleContentsRect, float scale)
+{
+ if (m_layerTreeHostProxy)
+ m_layerTreeHostProxy->setVisibleContentsRectAndScale(visibleContentsRect, scale);
+}
+
+void DrawingAreaProxyImpl::setVisibleContentRectTrajectoryVector(const WebCore::FloatPoint& trajectoryVector)
+{
+ if (m_layerTreeHostProxy)
+ m_layerTreeHostProxy->setVisibleContentRectTrajectoryVector(trajectoryVector);
+}
+
+void DrawingAreaProxyImpl::paintToCurrentGLContext(const TransformationMatrix& matrix, float opacity)
+{
+ if (m_layerTreeHostProxy)
+ m_layerTreeHostProxy->paintToCurrentGLContext(matrix, opacity);
+}
+#endif
+
+void DrawingAreaProxyImpl::exitAcceleratedCompositingMode()
+{
+ ASSERT(isInAcceleratedCompositingMode());
+
+ m_layerTreeContext = LayerTreeContext();
+ m_webPageProxy->exitAcceleratedCompositingMode();
+}
+#endif
+
+void DrawingAreaProxyImpl::pageCustomRepresentationChanged()
+{
+ m_webPageProxy->process()->send(Messages::DrawingArea::PageCustomRepresentationChanged(), m_webPageProxy->pageID());
+}
+
+void DrawingAreaProxyImpl::discardBackingStoreSoon()
+{
+ if (!m_isBackingStoreDiscardable || m_discardBackingStoreTimer.isActive())
+ return;
+
+ // We'll wait this many seconds after the last paint before throwing away our backing store to save memory.
+ // FIXME: It would be smarter to make this delay based on how expensive painting is. See <http://webkit.org/b/55733>.
+ static const double discardBackingStoreDelay = 2;
+
+ m_discardBackingStoreTimer.startOneShot(discardBackingStoreDelay);
+}
+
+void DrawingAreaProxyImpl::discardBackingStore()
+{
+ m_backingStore = nullptr;
+ backingStoreStateDidChange(DoNotRespondImmediately);
+}
+
+} // namespace WebKit