summaryrefslogtreecommitdiffstats
path: root/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp')
-rw-r--r--Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp247
1 files changed, 247 insertions, 0 deletions
diff --git a/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp b/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp
new file mode 100644
index 0000000..ab4655a
--- /dev/null
+++ b/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp
@@ -0,0 +1,247 @@
+/*
+ * 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 "DrawingAreaImpl.h"
+
+#include "DrawingAreaProxyMessages.h"
+#include "ShareableBitmap.h"
+#include "UpdateInfo.h"
+#include "WebPage.h"
+#include "WebProcess.h"
+#include <WebCore/GraphicsContext.h>
+
+#ifndef __APPLE__
+#error "This drawing area is not ready for use by other ports yet."
+#endif
+
+using namespace WebCore;
+
+namespace WebKit {
+
+PassRefPtr<DrawingAreaImpl> DrawingAreaImpl::create(DrawingAreaInfo::Identifier identifier, WebPage* webPage)
+{
+ return adoptRef(new DrawingAreaImpl(identifier, webPage));
+}
+
+DrawingAreaImpl::~DrawingAreaImpl()
+{
+}
+
+DrawingAreaImpl::DrawingAreaImpl(DrawingAreaInfo::Identifier identifier, WebPage* webPage)
+ : DrawingArea(DrawingAreaInfo::Impl, identifier, webPage)
+ , m_isWaitingForDidUpdate(false)
+ , m_displayTimer(WebProcess::shared().runLoop(), this, &DrawingAreaImpl::display)
+{
+}
+
+void DrawingAreaImpl::setNeedsDisplay(const IntRect& rect)
+{
+ if (rect.isEmpty())
+ return;
+
+ m_dirtyRegion.unite(rect);
+ scheduleDisplay();
+}
+
+void DrawingAreaImpl::scroll(const IntRect& scrollRect, const IntSize& scrollDelta)
+{
+ 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_scrollDelta = 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, scrollDelta), scrollRect);
+
+ // And add them back.
+ m_dirtyRegion.unite(movedDirtyRegionInScrollRect);
+ }
+
+ // Compute the scroll repaint region.
+ Region scrollRepaintRegion = subtract(scrollRect, translate(scrollRect, scrollDelta));
+
+ m_dirtyRegion.unite(scrollRepaintRegion);
+
+ m_scrollRect = scrollRect;
+ m_scrollDelta += scrollDelta;
+}
+
+void DrawingAreaImpl::attachCompositingContext()
+{
+}
+
+void DrawingAreaImpl::detachCompositingContext()
+{
+}
+
+void DrawingAreaImpl::setRootCompositingLayer(WebCore::GraphicsLayer*)
+{
+}
+
+void DrawingAreaImpl::scheduleCompositingLayerSync()
+{
+}
+
+void DrawingAreaImpl::syncCompositingLayers()
+{
+}
+
+void DrawingAreaImpl::didReceiveMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*)
+{
+}
+
+void DrawingAreaImpl::setSize(const IntSize& size)
+{
+ // Set this to false since we're about to call display().
+ m_isWaitingForDidUpdate = false;
+
+ m_webPage->setSize(size);
+ m_webPage->layoutIfNeeded();
+
+ // FIXME: Repaint.
+
+ m_webPage->send(Messages::DrawingAreaProxy::DidSetSize());
+}
+
+void DrawingAreaImpl::didUpdate()
+{
+ m_isWaitingForDidUpdate = false;
+
+ // Display if needed.
+ display();
+}
+
+void DrawingAreaImpl::scheduleDisplay()
+{
+ if (m_isWaitingForDidUpdate)
+ return;
+
+ if (m_dirtyRegion.isEmpty())
+ return;
+
+ if (m_displayTimer.isActive())
+ return;
+
+ m_displayTimer.startOneShot(0);
+}
+
+void DrawingAreaImpl::display()
+{
+ if (m_dirtyRegion.isEmpty())
+ return;
+
+ UpdateInfo updateInfo;
+ display(updateInfo);
+
+ m_webPage->send(Messages::DrawingAreaProxy::Update(updateInfo));
+ m_isWaitingForDidUpdate = true;
+}
+
+static bool shouldPaintBoundsRect(const IntRect& bounds, const Vector<IntRect>& rects)
+{
+ const size_t rectThreshold = 10;
+ const float wastedSpaceThreshold = 0.75f;
+
+ 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();
+
+ float wastedSpace = 1 - (rectsArea / boundsArea);
+
+ return wastedSpace <= wastedSpaceThreshold;
+}
+
+void DrawingAreaImpl::display(UpdateInfo& updateInfo)
+{
+ // FIXME: It would be better if we could avoid painting altogether when there is a custom representation.
+ if (m_webPage->mainFrameHasCustomRepresentation())
+ return;
+
+ IntRect bounds = m_dirtyRegion.bounds();
+ Vector<IntRect> rects = m_dirtyRegion.rects();
+
+ if (shouldPaintBoundsRect(bounds, rects)) {
+ rects.clear();
+ rects.append(bounds);
+ }
+
+ updateInfo.scrollRect = m_scrollRect;
+ updateInfo.scrollDelta = m_scrollDelta;
+
+ m_dirtyRegion = Region();
+ m_scrollRect = IntRect();
+ m_scrollDelta = IntSize();
+
+ RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(bounds.size());
+ if (!bitmap->createHandle(updateInfo.bitmapHandle))
+ return;
+
+ OwnPtr<GraphicsContext> graphicsContext = bitmap->createGraphicsContext();
+
+ m_webPage->layoutIfNeeded();
+
+ updateInfo.viewSize = m_webPage->size();
+ updateInfo.updateRectBounds = bounds;
+
+ graphicsContext->translate(-bounds.x(), -bounds.y());
+
+ for (size_t i = 0; i < rects.size(); ++i) {
+ m_webPage->drawRect(*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();
+}
+
+
+} // namespace WebKit