summaryrefslogtreecommitdiff
path: root/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-09-10 19:10:20 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-09-10 19:10:20 +0200
commit284837daa07b29d6a63a748544a90b1f5842ac5c (patch)
treeecd258180bde91fe741e0cfd2638beb3c6da7e8e /Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp
parent2e2ba8ff45915f40ed3e014101269c175f2a89a0 (diff)
downloadqtwebkit-284837daa07b29d6a63a748544a90b1f5842ac5c.tar.gz
Imported WebKit commit 68645295d2e3e09af2c942f092556f06aa5f8b0d (http://svn.webkit.org/repository/webkit/trunk@128073)
New snapshot
Diffstat (limited to 'Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp')
-rw-r--r--Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp547
1 files changed, 547 insertions, 0 deletions
diff --git a/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp b/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp
new file mode 100644
index 000000000..3d134ea93
--- /dev/null
+++ b/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2011, 2012 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "config.h"
+#include "PageViewportControllerClientQt.h"
+
+#include "qquickwebpage_p.h"
+#include "qquickwebview_p.h"
+#include "qwebkittest_p.h"
+#include <QPointF>
+#include <QTransform>
+#include <QtQuick/qquickitem.h>
+#include <WebCore/FloatRect.h>
+#include <WebCore/FloatSize.h>
+
+namespace WebKit {
+
+static const int kScaleAnimationDurationMillis = 250;
+
+PageViewportControllerClientQt::PageViewportControllerClientQt(QQuickWebView* viewportItem, QQuickWebPage* pageItem)
+ : m_viewportItem(viewportItem)
+ , m_pageItem(pageItem)
+ , m_scaleAnimation(new ScaleAnimation(this))
+ , m_pinchStartScale(-1)
+ , m_lastCommittedScale(-1)
+ , m_zoomOutScale(0)
+ , m_ignoreViewportChanges(true)
+{
+ m_scaleAnimation->setDuration(kScaleAnimationDurationMillis);
+ m_scaleAnimation->setEasingCurve(QEasingCurve::OutCubic);
+
+ connect(m_viewportItem, SIGNAL(movementStarted()), SLOT(flickMoveStarted()), Qt::DirectConnection);
+ connect(m_viewportItem, SIGNAL(movementEnded()), SLOT(flickMoveEnded()), Qt::DirectConnection);
+ connect(m_viewportItem, SIGNAL(contentXChanged()), SLOT(pageItemPositionChanged()));
+ connect(m_viewportItem, SIGNAL(contentYChanged()), SLOT(pageItemPositionChanged()));
+
+
+ connect(m_scaleAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)),
+ SLOT(scaleAnimationStateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
+}
+
+void PageViewportControllerClientQt::ScaleAnimation::updateCurrentValue(const QVariant& value)
+{
+ // Resetting the end value, the easing curve or the duration of the scale animation
+ // triggers a recalculation of the animation interval. This might change the current
+ // value of the animated property.
+ // Make sure we only act on animation value changes if the animation is active.
+ if (!m_controllerClient->scaleAnimationActive())
+ return;
+
+ QRectF itemRect = value.toRectF();
+ float itemScale = m_controllerClient->viewportScaleForRect(itemRect);
+
+ m_controllerClient->setContentRectVisiblePositionAtScale(itemRect.topLeft(), itemScale);
+}
+
+PageViewportControllerClientQt::~PageViewportControllerClientQt()
+{
+}
+
+void PageViewportControllerClientQt::setContentRectVisiblePositionAtScale(const QPointF& location, qreal itemScale)
+{
+ ASSERT(itemScale >= 0);
+
+ scaleContent(itemScale);
+
+ // To animate the position together with the scale we multiply the position with the current scale
+ // and add it to the page position (displacement on the flickable contentItem because of additional items).
+ QPointF newPosition(m_pageItem->pos() + location * itemScale);
+
+ m_viewportItem->setContentPos(newPosition);
+}
+
+void PageViewportControllerClientQt::animateContentRectVisible(const QRectF& contentRect)
+{
+ ASSERT(m_scaleAnimation->state() == QAbstractAnimation::Stopped);
+
+ ASSERT(!scrollAnimationActive());
+ if (scrollAnimationActive())
+ return;
+
+ QRectF viewportRectInContentCoords = m_viewportItem->mapRectToWebContent(m_viewportItem->boundingRect());
+ if (contentRect == viewportRectInContentCoords) {
+ updateViewportController();
+ return;
+ }
+
+ // Since we have to animate scale and position at the same time the scale animation interpolates
+ // from the current viewport rect in content coordinates to a visible rect of the content.
+ m_scaleAnimation->setStartValue(viewportRectInContentCoords);
+ m_scaleAnimation->setEndValue(contentRect);
+
+ // Inform the web process about the requested visible content rect
+ // if zooming-out so that no white tiles are exposed during animation.
+ if (viewportRectInContentCoords.width() / contentRect.width() < m_pageItem->contentsScale())
+ m_controller->setVisibleContentsRect(contentRect, viewportScaleForRect(contentRect));
+
+ m_scaleAnimation->start();
+}
+
+void PageViewportControllerClientQt::flickMoveStarted()
+{
+ Q_ASSERT(m_viewportItem->isMoving());
+ m_scrollUpdateDeferrer.reset(new ViewportUpdateDeferrer(m_controller, ViewportUpdateDeferrer::DeferUpdateAndSuspendContent));
+
+ m_lastScrollPosition = m_viewportItem->contentPos();
+
+ m_ignoreViewportChanges = false;
+}
+
+void PageViewportControllerClientQt::flickMoveEnded()
+{
+ Q_ASSERT(!m_viewportItem->isMoving());
+ // This method is called on the end of the pan or pan kinetic animation.
+
+ m_ignoreViewportChanges = true;
+
+ m_scrollUpdateDeferrer.reset();
+}
+
+void PageViewportControllerClientQt::pageItemPositionChanged()
+{
+ if (m_ignoreViewportChanges)
+ return;
+
+ QPointF newPosition = m_viewportItem->contentPos();
+
+ updateViewportController(m_lastScrollPosition - newPosition);
+
+ m_lastScrollPosition = newPosition;
+}
+
+void PageViewportControllerClientQt::scaleAnimationStateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State /*oldState*/)
+{
+ switch (newState) {
+ case QAbstractAnimation::Running:
+ m_viewportItem->cancelFlick();
+ ASSERT(!m_animationUpdateDeferrer);
+ m_animationUpdateDeferrer.reset(new ViewportUpdateDeferrer(m_controller, ViewportUpdateDeferrer::DeferUpdateAndSuspendContent));
+ break;
+ case QAbstractAnimation::Stopped:
+ m_animationUpdateDeferrer.reset();
+ break;
+ default:
+ break;
+ }
+}
+
+void PageViewportControllerClientQt::touchBegin()
+{
+ m_controller->setHadUserInteraction(true);
+
+ // Prevents resuming the page between the user's flicks of the page while the animation is running.
+ if (scrollAnimationActive())
+ m_touchUpdateDeferrer.reset(new ViewportUpdateDeferrer(m_controller, ViewportUpdateDeferrer::DeferUpdateAndSuspendContent));
+}
+
+void PageViewportControllerClientQt::touchEnd()
+{
+ m_touchUpdateDeferrer.reset();
+}
+
+void PageViewportControllerClientQt::focusEditableArea(const QRectF& caretArea, const QRectF& targetArea)
+{
+ // This can only happen as a result of a user interaction.
+ ASSERT(m_controller->hadUserInteraction());
+
+ QRectF endArea = m_controller->convertToViewport(targetArea);
+
+ qreal endItemScale = m_controller->convertToViewport(m_controller->innerBoundedContentsScale(2.0));
+ const QRectF viewportRect = m_viewportItem->boundingRect();
+
+ qreal x;
+ const qreal borderOffset = 10;
+ if ((endArea.width() + borderOffset) * endItemScale <= viewportRect.width()) {
+ // Center the input field in the middle of the view, if it is smaller than
+ // the view at the scale target.
+ x = viewportRect.center().x() - endArea.width() * endItemScale / 2.0;
+ } else {
+ // Ensure that the caret always has borderOffset contents pixels to the right
+ // of it, and secondarily (if possible), that the area has borderOffset
+ // contents pixels to the left of it.
+ qreal caretOffset = m_controller->convertToViewport(caretArea.x()) - endArea.x();
+ x = qMin(viewportRect.width() - (caretOffset + borderOffset) * endItemScale, borderOffset * endItemScale);
+ }
+
+ const QPointF hotspot = QPointF(endArea.x(), endArea.center().y());
+ const QPointF viewportHotspot = QPointF(x, /* FIXME: visibleCenter */ viewportRect.center().y());
+
+ QPointF endPosition = hotspot * endItemScale - viewportHotspot;
+ QRectF endPosRange = m_controller->positionRangeForContentAtScale(endItemScale);
+
+ endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight());
+
+ QRectF endVisibleContentRect(endPosition / endItemScale, viewportRect.size() / endItemScale);
+
+ animateContentRectVisible(endVisibleContentRect);
+}
+
+void PageViewportControllerClientQt::zoomToAreaGestureEnded(const QPointF& touchPoint, const QRectF& targetArea)
+{
+ // This can only happen as a result of a user interaction.
+ ASSERT(m_controller->hadUserInteraction());
+
+ if (!targetArea.isValid())
+ return;
+
+ if (m_controller->hasSuspendedContent())
+ return;
+
+ const int margin = 10; // We want at least a little bit of margin.
+ QRectF endArea = m_controller->convertToViewport(targetArea.adjusted(-margin, -margin, margin, margin));
+
+ const QRectF viewportRect = m_viewportItem->boundingRect();
+
+ qreal targetCSSScale = viewportRect.size().width() / endArea.size().width();
+ qreal endCSSScale = m_controller->innerBoundedContentsScale(qMin(targetCSSScale, qreal(2.5)));
+ qreal endItemScale = m_controller->convertToViewport(endCSSScale);
+ qreal currentScale = m_pageItem->contentsScale();
+
+ // We want to end up with the target area filling the whole width of the viewport (if possible),
+ // and centralized vertically where the user requested zoom. Thus our hotspot is the center of
+ // the targetArea x-wise and the requested zoom position, y-wise.
+ const QPointF hotspot = QPointF(endArea.center().x(), m_controller->convertToViewport(touchPoint.y()));
+ const QPointF viewportHotspot = viewportRect.center();
+
+ QPointF endPosition = hotspot * endCSSScale - viewportHotspot;
+
+ QRectF endPosRange = m_controller->positionRangeForContentAtScale(endItemScale);
+ endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight());
+
+ QRectF endVisibleContentRect(endPosition / endItemScale, viewportRect.size() / endItemScale);
+
+ enum { ZoomIn, ZoomBack, ZoomOut, NoZoom } zoomAction = ZoomIn;
+
+ if (!m_scaleStack.isEmpty()) {
+ // Zoom back out if attempting to scale to the same current scale, or
+ // attempting to continue scaling out from the inner most level.
+ // Use fuzzy compare with a fixed error to be able to deal with largish differences due to pixel rounding.
+ if (fuzzyCompare(endItemScale, currentScale, 0.01)) {
+ // If moving the viewport would expose more of the targetRect and move at least 40 pixels, update position but do not scale out.
+ QRectF currentContentRect(visibleContentsRect());
+ QRectF targetIntersection = endVisibleContentRect.intersected(targetArea);
+ if (!currentContentRect.contains(targetIntersection)
+ && (qAbs(endVisibleContentRect.top() - currentContentRect.top()) >= 40
+ || qAbs(endVisibleContentRect.left() - currentContentRect.left()) >= 40))
+ zoomAction = NoZoom;
+ else
+ zoomAction = ZoomBack;
+ } else if (fuzzyCompare(endItemScale, m_zoomOutScale, 0.01))
+ zoomAction = ZoomBack;
+ else if (endItemScale < currentScale)
+ zoomAction = ZoomOut;
+ }
+
+ switch (zoomAction) {
+ case ZoomIn:
+ m_scaleStack.append(ScaleStackItem(currentScale, m_viewportItem->contentPos().x()));
+ m_zoomOutScale = endItemScale;
+ break;
+ case ZoomBack: {
+ ScaleStackItem lastScale = m_scaleStack.takeLast();
+ endItemScale = lastScale.scale;
+ endCSSScale = m_controller->convertFromViewport(lastScale.scale);
+ // Recalculate endPosition and bound it according to new scale.
+ endPosition.setY(hotspot.y() * endCSSScale - viewportHotspot.y());
+ endPosition.setX(lastScale.xPosition);
+ endPosRange = m_controller->positionRangeForContentAtScale(endItemScale);
+ endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight());
+ endVisibleContentRect = QRectF(endPosition / endItemScale, viewportRect.size() / endItemScale);
+ break;
+ }
+ case ZoomOut:
+ // Unstack all scale-levels deeper than the new level, so a zoom-back won't end up zooming in.
+ while (!m_scaleStack.isEmpty() && m_scaleStack.last().scale >= endItemScale)
+ m_scaleStack.removeLast();
+ m_zoomOutScale = endItemScale;
+ break;
+ case NoZoom:
+ break;
+ }
+
+ animateContentRectVisible(endVisibleContentRect);
+}
+
+QRectF PageViewportControllerClientQt::nearestValidVisibleContentsRect() const
+{
+ float cssScale = m_controller->convertFromViewport(m_pageItem->contentsScale());
+ float endItemScale = m_controller->convertToViewport(m_controller->innerBoundedContentsScale(cssScale));
+
+ const QRectF viewportRect = m_viewportItem->boundingRect();
+ QPointF viewportHotspot = viewportRect.center();
+ QPointF endPosition = m_viewportItem->mapToWebContent(viewportHotspot) * endItemScale - viewportHotspot;
+
+ FloatRect endPosRange = m_controller->positionRangeForContentAtScale(endItemScale);
+ endPosition = boundPosition(endPosRange.minXMinYCorner(), endPosition, endPosRange.maxXMaxYCorner());
+
+ QRectF endVisibleContentRect(endPosition / endItemScale, viewportRect.size() / endItemScale);
+
+ return endVisibleContentRect;
+}
+
+void PageViewportControllerClientQt::setContentsPosition(const FloatPoint& localPoint)
+{
+ QPointF newPosition(m_pageItem->pos() + QPointF(localPoint));
+ m_viewportItem->setContentPos(newPosition);
+ updateViewportController();
+}
+
+void PageViewportControllerClientQt::setContentsScale(float localScale, bool treatAsInitialValue)
+{
+ if (treatAsInitialValue) {
+ m_zoomOutScale = 0;
+ m_scaleStack.clear();
+ setContentRectVisiblePositionAtScale(QPointF(), localScale);
+ } else
+ scaleContent(localScale);
+
+ updateViewportController();
+}
+
+void PageViewportControllerClientQt::setContentsRectToNearestValidBounds()
+{
+ ViewportUpdateDeferrer guard(m_controller);
+ float validCSSScale = m_controller->innerBoundedContentsScale(m_controller->convertFromViewport(m_pageItem->contentsScale()));
+ setContentRectVisiblePositionAtScale(nearestValidVisibleContentsRect().topLeft(), m_controller->convertToViewport(validCSSScale));
+}
+
+void PageViewportControllerClientQt::didResumeContent()
+{
+ updateViewportController();
+}
+
+bool PageViewportControllerClientQt::scrollAnimationActive() const
+{
+ return m_viewportItem->isFlicking();
+}
+
+bool PageViewportControllerClientQt::panGestureActive() const
+{
+ return m_controller->hadUserInteraction() && m_viewportItem->isDragging();
+}
+
+void PageViewportControllerClientQt::panGestureStarted(const QPointF& position, qint64 eventTimestampMillis)
+{
+ // This can only happen as a result of a user interaction.
+ ASSERT(m_controller->hadUserInteraction());
+
+ m_viewportItem->handleFlickableMousePress(position, eventTimestampMillis);
+ m_lastPinchCenterInViewportCoordinates = position;
+}
+
+void PageViewportControllerClientQt::panGestureRequestUpdate(const QPointF& position, qint64 eventTimestampMillis)
+{
+ m_viewportItem->handleFlickableMouseMove(position, eventTimestampMillis);
+ m_lastPinchCenterInViewportCoordinates = position;
+}
+
+void PageViewportControllerClientQt::panGestureEnded(const QPointF& position, qint64 eventTimestampMillis)
+{
+ m_viewportItem->handleFlickableMouseRelease(position, eventTimestampMillis);
+ m_lastPinchCenterInViewportCoordinates = position;
+}
+
+void PageViewportControllerClientQt::panGestureCancelled()
+{
+ // Reset the velocity samples of the flickable.
+ // This should only be called by the recognizer if we have a recognized
+ // pan gesture and receive a touch event with multiple touch points
+ // (ie. transition to a pinch gesture) as it does not move the content
+ // back inside valid bounds.
+ // When the pinch gesture ends, the content is positioned and scaled
+ // back to valid boundaries.
+ m_viewportItem->cancelFlick();
+}
+
+bool PageViewportControllerClientQt::scaleAnimationActive() const
+{
+ return m_scaleAnimation->state() == QAbstractAnimation::Running;
+}
+
+void PageViewportControllerClientQt::cancelScrollAnimation()
+{
+ if (!scrollAnimationActive())
+ return;
+
+ // If the pan gesture recognizer receives a touch begin event
+ // during an ongoing kinetic scroll animation of a previous
+ // pan gesture, the animation is stopped and the content is
+ // immediately positioned back to valid boundaries.
+
+ m_viewportItem->cancelFlick();
+ setContentsRectToNearestValidBounds();
+}
+
+void PageViewportControllerClientQt::interruptScaleAnimation()
+{
+ // This interrupts the scale animation exactly where it is, even if it is out of bounds.
+ m_scaleAnimation->stop();
+}
+
+bool PageViewportControllerClientQt::pinchGestureActive() const
+{
+ return m_controller->hadUserInteraction() && (m_pinchStartScale > 0);
+}
+
+void PageViewportControllerClientQt::pinchGestureStarted(const QPointF& pinchCenterInViewportCoordinates)
+{
+ // This can only happen as a result of a user interaction.
+ ASSERT(m_controller->hadUserInteraction());
+
+ if (!m_controller->allowsUserScaling())
+ return;
+
+ m_scaleStack.clear();
+ m_zoomOutScale = 0.0;
+
+ m_scaleUpdateDeferrer.reset(new ViewportUpdateDeferrer(m_controller, ViewportUpdateDeferrer::DeferUpdateAndSuspendContent));
+
+ m_lastPinchCenterInViewportCoordinates = pinchCenterInViewportCoordinates;
+ m_pinchStartScale = m_pageItem->contentsScale();
+}
+
+void PageViewportControllerClientQt::pinchGestureRequestUpdate(const QPointF& pinchCenterInViewportCoordinates, qreal totalScaleFactor)
+{
+ ASSERT(m_controller->hasSuspendedContent());
+
+ if (!m_controller->allowsUserScaling())
+ return;
+
+ // Changes of the center position should move the page even if the zoom factor does not change.
+ const qreal cssScale = m_controller->convertFromViewport(m_pinchStartScale * totalScaleFactor);
+
+ // Allow zooming out beyond mimimum scale on pages that do not explicitly disallow it.
+ const qreal targetItemScale = m_controller->convertToViewport(m_controller->outerBoundedContentsScale(cssScale));
+
+ scaleContent(targetItemScale, m_viewportItem->mapToWebContent(pinchCenterInViewportCoordinates));
+
+ const QPointF positionDiff = pinchCenterInViewportCoordinates - m_lastPinchCenterInViewportCoordinates;
+ m_lastPinchCenterInViewportCoordinates = pinchCenterInViewportCoordinates;
+
+ m_viewportItem->setContentPos(m_viewportItem->contentPos() - positionDiff);
+
+ // Inform the web process to render the currently visible area with low-resolution tiles not
+ // to expose white tiles during pinch gestures and to show fixed position layers correctly.
+ // The actual scale is restored after the pinch gesture ends.
+ updateViewportController(QPointF(), 1);
+}
+
+void PageViewportControllerClientQt::pinchGestureEnded()
+{
+ ASSERT(m_controller->hasSuspendedContent());
+
+ if (!m_controller->allowsUserScaling())
+ return;
+
+ m_pinchStartScale = -1;
+
+ animateContentRectVisible(nearestValidVisibleContentsRect());
+ m_scaleUpdateDeferrer.reset(); // Clear after starting potential animation, which takes over deferring.
+}
+
+void PageViewportControllerClientQt::pinchGestureCancelled()
+{
+ m_pinchStartScale = -1;
+ m_scaleUpdateDeferrer.reset();
+}
+
+QRectF PageViewportControllerClientQt::visibleContentsRect() const
+{
+ const QRectF visibleRect(m_viewportItem->boundingRect().intersected(m_pageItem->boundingRect()));
+ return m_viewportItem->mapRectToWebContent(visibleRect);
+}
+
+void PageViewportControllerClientQt::didChangeContentsSize()
+{
+ // Emit for testing purposes, so that it can be verified that
+ // we didn't do scale adjustment.
+ emit m_viewportItem->experimental()->test()->contentsScaleCommitted();
+
+ if (!m_controller->hasSuspendedContent())
+ setContentsRectToNearestValidBounds();
+}
+
+void PageViewportControllerClientQt::didChangeVisibleContents()
+{
+ qreal scale = m_pageItem->contentsScale();
+
+ if (scale != m_lastCommittedScale)
+ emit m_viewportItem->experimental()->test()->contentsScaleCommitted();
+ m_lastCommittedScale = scale;
+
+ // Ensure that updatePaintNode is always called before painting.
+ m_pageItem->update();
+}
+
+void PageViewportControllerClientQt::didChangeViewportAttributes()
+{
+ // Make sure we apply the new initial scale when deferring ends.
+ ViewportUpdateDeferrer guard(m_controller);
+
+ emit m_viewportItem->experimental()->test()->devicePixelRatioChanged();
+ emit m_viewportItem->experimental()->test()->viewportChanged();
+}
+
+void PageViewportControllerClientQt::updateViewportController(const QPointF& trajectory, qreal scale)
+{
+ FloatRect currentVisibleRect(visibleContentsRect());
+ float viewportScale = (scale < 0) ? viewportScaleForRect(currentVisibleRect) : scale;
+ m_controller->setVisibleContentsRect(currentVisibleRect, viewportScale, trajectory);
+}
+
+void PageViewportControllerClientQt::scaleContent(qreal itemScale, const QPointF& centerInCSSCoordinates)
+{
+ QPointF oldPinchCenterOnViewport = m_viewportItem->mapFromWebContent(centerInCSSCoordinates);
+ m_pageItem->setContentsScale(itemScale);
+ QPointF newPinchCenterOnViewport = m_viewportItem->mapFromWebContent(centerInCSSCoordinates);
+ m_viewportItem->setContentPos(m_viewportItem->contentPos() + (newPinchCenterOnViewport - oldPinchCenterOnViewport));
+}
+
+float PageViewportControllerClientQt::viewportScaleForRect(const QRectF& rect) const
+{
+ return static_cast<float>(m_viewportItem->width()) / static_cast<float>(rect.width());
+}
+
+} // namespace WebKit
+
+#include "moc_PageViewportControllerClientQt.cpp"