Modified: trunk/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp (98459 => 98460)
--- trunk/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp 2011-10-26 09:41:27 UTC (rev 98459)
+++ trunk/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp 2011-10-26 09:49:21 UTC (rev 98460)
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2011 Benjamin Poulain <[email protected]>
*
* This library is free software; you can redistribute it and/or
@@ -23,58 +24,64 @@
#include "PassOwnPtr.h"
#include <QPointF>
+#include <QScrollEvent>
+#include <QScrollPrepareEvent>
+#include <QScrollerProperties>
#include <QtDeclarative/qsgitem.h>
namespace WebKit {
-static inline QRectF visibleRectInContentCoordinate(const QSGItem* content, const QSGItem* viewport)
-{
- const QRectF viewportInContentCoordinate = content->mapRectFromItem(viewport, viewport->boundingRect());
- const QRectF visibleArea = content->boundingRect().intersected(viewportInContentCoordinate);
- return visibleArea;
-}
+static const int kScaleAnimationDurationMillis = 400;
static inline QRectF contentRectInViewportCoordinate(const QSGItem* content, const QSGItem* viewport)
{
return viewport->mapRectFromItem(content, content->boundingRect());
}
+static inline qreal bindToScaleLimits(qreal scale)
+{
+ // Bounded by [0.1, 10.0] like the viewport meta code in WebCore.
+ return qBound(qreal(0.1), scale, qreal(10.0));
+}
+
// Updating content properties cause the notify signals to be sent by the content item itself.
// Since we manage those differently, we do not want to respond
// to them when we are the one changing the content.
//
-// The guard make sure the signal viewportUpdateRequested() is sent if necessary.
+// The guard makes sure that the signal viewportUpdateRequested() is sent if necessary.
// When multiple guards are alive, their lifetime must be perfectly imbricated (e.g. if used ouside stack frames).
-// We rely on the first one to trigger the update at the end since it only uses one bool internally.
+// We rely on the first one to trigger the update at the end.
//
// The public methods should create the guard if they might update content.
class ViewportUpdateGuard {
public:
ViewportUpdateGuard(QtViewportInteractionEngine* viewportInteractionEngine)
: viewportInteractionEngine(viewportInteractionEngine)
- , wasUpdatingContent(viewportInteractionEngine->m_isUpdatingContent)
, previousPosition(viewportInteractionEngine->m_content->pos())
, previousSize(viewportInteractionEngine->m_content->width(), viewportInteractionEngine->m_content->height())
, previousScale(viewportInteractionEngine->m_content->scale())
+
{
- viewportInteractionEngine->m_isUpdatingContent = true;
+ ++(viewportInteractionEngine->m_pendingUpdates);
}
~ViewportUpdateGuard()
{
- if (!wasUpdatingContent) {
+ --(viewportInteractionEngine->m_pendingUpdates);
+ if (!viewportInteractionEngine->m_pendingUpdates) {
+ // Reset the tiling look-ahead vector so that tiles all around the viewport will be requested.
+ emit viewportInteractionEngine->viewportTrajectoryVectorChanged(QPointF());
if (previousPosition != viewportInteractionEngine->m_content->pos()
|| previousSize.width() != viewportInteractionEngine->m_content->width()
|| previousSize.height() != viewportInteractionEngine->m_content->height()
|| previousScale != viewportInteractionEngine->m_content->scale())
+ // We must notify the change so the client can rely on us for all changes of geometry.
emit viewportInteractionEngine->viewportUpdateRequested();
}
- viewportInteractionEngine->m_isUpdatingContent = wasUpdatingContent;
}
private:
QtViewportInteractionEngine* const viewportInteractionEngine;
- const bool wasUpdatingContent;
const QPointF previousPosition;
const QSizeF previousSize;
const qreal previousScale;
@@ -83,7 +90,8 @@
QtViewportInteractionEngine::QtViewportInteractionEngine(const QSGItem* viewport, QSGItem* content)
: m_viewport(viewport)
, m_content(content)
- , m_isUpdatingContent(false)
+ , m_pendingUpdates(0)
+ , m_scaleAnimation(new ScaleAnimation(this))
, m_pinchStartScale(1.f)
{
reset();
@@ -92,16 +100,180 @@
connect(m_content, SIGNAL(widthChanged()), this, SLOT(contentViewportChanged()), Qt::DirectConnection);
connect(m_content, SIGNAL(heightChanged()), this, SLOT(contentViewportChanged()), Qt::DirectConnection);
connect(m_content, SIGNAL(scaleChanged()), this, SLOT(contentViewportChanged()), Qt::DirectConnection);
+ connect(m_scaleAnimation, SIGNAL(valueChanged(QVariant)), SLOT(updateVisibleRect(QVariant)), Qt::DirectConnection);
+ connect(m_scaleAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))
+ , SLOT(scaleAnimationStateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), Qt::DirectConnection);
}
QtViewportInteractionEngine::~QtViewportInteractionEngine()
{
}
+qreal QtViewportInteractionEngine::innerBoundedScale(qreal scale)
+{
+ return qBound(m_constraints.minimumScale, scale, m_constraints.maximumScale);
+}
+
+qreal QtViewportInteractionEngine::outerBoundedScale(qreal scale)
+{
+ if (m_constraints.isUserScalable) {
+ qreal hardMin = qreal(0.5) * m_constraints.minimumScale;
+ qreal hardMax = qreal(2.0) * m_constraints.maximumScale;
+ return bindToScaleLimits(qBound(hardMin, scale, hardMax));
+ }
+ return innerBoundedScale(scale);
+}
+
+void QtViewportInteractionEngine::updateVisibleRect(QVariant rect)
+{
+ ViewportUpdateGuard guard(this);
+
+ QRectF visibleRect = rect.toRectF();
+ qreal currentScale = m_viewport->width() / visibleRect.width();
+
+ m_content->setScale(currentScale);
+
+ // We need to animate the content but the position represents the viewport hence we need to invert the position here.
+ // To animate the position together with the scale we multiply the position with the current scale;
+ m_content->setPos(-visibleRect.topLeft() * currentScale);
+}
+
+void QtViewportInteractionEngine::scaleAnimationStateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State /*oldState*/)
+{
+ switch (newState) {
+ case QAbstractAnimation::Running:
+ m_pinchViewportUpdateDeferrer = adoptPtr(new ViewportUpdateGuard(this));
+ break;
+ case QAbstractAnimation::Stopped:
+ m_pinchViewportUpdateDeferrer.clear();
+ break;
+ default:
+ break;
+ }
+}
+
+bool QtViewportInteractionEngine::event(QEvent* event)
+{
+ switch (event->type()) {
+ case QEvent::ScrollPrepare: {
+ QScrollPrepareEvent* prepareEvent = static_cast<QScrollPrepareEvent*>(event);
+ const QRectF viewportRect = m_viewport->boundingRect();
+ const QRectF contentRect = contentRectInViewportCoordinate(m_content, m_viewport);
+ const QRectF contentPositionRange = calculateBoundariesForScale(contentRect.size(), viewportRect.size(), 1);
+ prepareEvent->setContentPosRange(contentPositionRange);
+ prepareEvent->setViewportSize(viewportRect.size());
+
+ // As we want to push the contents and not actually scroll it, we need to invert the positions here.
+ prepareEvent->setContentPos(-contentRect.topLeft());
+ prepareEvent->accept();
+ return true;
+ }
+ case QEvent::Scroll: {
+ QScrollEvent* scrollEvent = static_cast<QScrollEvent*>(event);
+ QPointF newPos = -scrollEvent->contentPos() - scrollEvent->overshootDistance();
+ if (m_content->pos() != newPos) {
+ ViewportUpdateGuard guard(this);
+
+ QPointF currentPosInContentCoordinates = m_content->mapToItem(m_content->parentItem(), m_content->pos());
+ QPointF newPosInContentCoordinates = m_content->mapToItem(m_content->parentItem(), newPos);
+
+ // This must be emitted before viewportUpdateRequested so that the web process knows where to look for tiles.
+ emit viewportTrajectoryVectorChanged(currentPosInContentCoordinates- newPosInContentCoordinates);
+ m_content->setPos(newPos);
+ }
+ return true;
+ }
+ default:
+ break;
+ }
+ return QObject::event(event);
+}
+
+void QtViewportInteractionEngine::stopAnimations()
+{
+ m_scaleAnimation->stop();
+ scroller()->stop();
+
+ // If the animations were stopped we need to scale and reposition the content into valid boundaries immediately.
+ m_userInteractionFlags |= UserHasStoppedAnimations;
+ animateContentIntoBoundariesIfNeeded();
+ m_userInteractionFlags &= ~UserHasStoppedAnimations;
+}
+
+const QRectF QtViewportInteractionEngine::calculateBoundariesForScale(const QSizeF contentSize, const QSizeF viewportSize, qreal scale)
+{
+ const QSizeF scaledViewportSize = viewportSize / scale;
+
+ const qreal horizontalOffset = contentSize.width() - scaledViewportSize.width();
+ const qreal verticalOffset = contentSize.height() - scaledViewportSize.height();
+
+ const QPointF contentPositionRangeTopLeft(qMin<qreal>(0, horizontalOffset / 2), 0);
+ const qreal contentPositionRangeWidth = qMax<qreal>(0, horizontalOffset);
+ const qreal contentPositionRangeHeight = qMax<qreal>(0, verticalOffset);
+
+ return QRectF(contentPositionRangeTopLeft, QSizeF(contentPositionRangeWidth, contentPositionRangeHeight));
+}
+
+void QtViewportInteractionEngine::animateContentIntoBoundariesIfNeeded()
+{
+ m_scaleAnimation->stop();
+
+ qreal currentScale = m_content->scale();
+ bool userHasScaledContent = m_userInteractionFlags & UserHasScaledContent;
+ bool userHasStoppedAnimations = m_userInteractionFlags & UserHasStoppedAnimations;
+
+ if (!userHasScaledContent)
+ currentScale = m_constraints.initialScale;
+
+ qreal boundedScale = innerBoundedScale(currentScale);
+
+ QRectF viewportRect = m_viewport->boundingRect();
+ QPointF viewportHotspot = viewportRect.center();
+ QPointF position = m_content->mapFromItem(m_viewport, viewportHotspot) - viewportHotspot / boundedScale;
+ QRectF positionBoundaries = calculateBoundariesForScale(m_content->boundingRect().size(), viewportRect.size(), boundedScale);
+ QPointF minOffset = positionBoundaries.topLeft();
+ QPointF maxOffset = positionBoundaries.bottomRight();
+ QPointF boundedPosition;
+ boundedPosition.setX(qBound(minOffset.x(), position.x(), maxOffset.x()));
+ boundedPosition.setY(qBound(minOffset.y(), position.y(), maxOffset.y()));
+
+ QRectF scaledRect(boundedPosition, viewportRect.size() / boundedScale);
+ QRectF currentRect = m_viewport->mapRectToItem(m_content, viewportRect);
+
+ if (scaledRect == currentRect)
+ return;
+
+ if (userHasScaledContent && !userHasStoppedAnimations) {
+ m_scaleAnimation->setDuration(kScaleAnimationDurationMillis);
+ m_scaleAnimation->setEasingCurve(QEasingCurve::OutCubic);
+ m_scaleAnimation->setStartValue(currentRect);
+ m_scaleAnimation->setEndValue(scaledRect);
+ m_scaleAnimation->start();
+ } else
+ updateVisibleRect(scaledRect);
+}
+
void QtViewportInteractionEngine::reset()
{
ViewportUpdateGuard guard(this);
m_userInteractionFlags = UserHasNotInteractedWithContent;
+
+ stopAnimations();
+
+ QScrollerProperties properties = scroller()->scrollerProperties();
+
+ // The QtPanGestureRecognizer is responsible for recognizing the gesture
+ // thus we need to disable the drag start distance.
+ properties.setScrollMetric(QScrollerProperties::DragStartDistance, 0.0);
+
+ // Set some default QScroller constrains to mimic the physics engine of the N9 browser.
+ properties.setScrollMetric(QScrollerProperties::AxisLockThreshold, 0.66);
+ properties.setScrollMetric(QScrollerProperties::DecelerationFactor, 0.20);
+ properties.setScrollMetric(QScrollerProperties::MaximumVelocity, 0.2);
+ properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor, 0.33);
+ properties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor, 0.33);
+
+ scroller()->setScrollerProperties(properties);
setConstraints(Constraints());
}
@@ -110,60 +282,43 @@
if (m_constraints == constraints)
return;
- // FIXME: if a pinch gesture is ongoing, we have to:
- // -cancel the gesture if isUserScalable becomes true
- // -update the page on the fly without modifying its position
-
- // FIXME: if a pan gesture is ongoing, we have to
- // -update the page without changing the position
- // -animate the page back in viewport if necessary (if the page is fully in
- // viewport, it does not pan horizontally anymore).
-
ViewportUpdateGuard guard(this);
m_constraints = constraints;
- updateContentIfNeeded();
+ animateContentIntoBoundariesIfNeeded();
}
-void QtViewportInteractionEngine::panGestureStarted()
+void QtViewportInteractionEngine::panGestureStarted(const QPointF& touchPoint, qint64 eventTimestampMillis)
{
// FIXME: suspend the Web engine (stop animated GIF, etc).
- // FIXME: initialize physics for panning (stop animation, etc).
m_userInteractionFlags |= UserHasMovedContent;
+ scroller()->handleInput(QScroller::InputPress, m_viewport->mapFromItem(m_content, touchPoint), eventTimestampMillis);
}
-void QtViewportInteractionEngine::panGestureRequestUpdate(qreal deltaX, qreal deltaY)
+void QtViewportInteractionEngine::panGestureRequestUpdate(const QPointF& touchPoint, qint64 eventTimestampMillis)
{
ViewportUpdateGuard guard(this);
-
- QPointF itemPositionInItemCoords = m_content->mapFromItem(m_content->parentItem(), m_content->pos());
- QPointF destInViewportCoords = m_viewport->mapFromItem(m_content, itemPositionInItemCoords + QPointF(deltaX, deltaY));
-
- m_content->setPos(destInViewportCoords);
- // This must be emitted before viewportUpdateRequested so that the web process knows where to look for tiles.
- emit viewportTrajectoryVectorChanged(QPointF(-deltaX, -deltaY));
+ scroller()->handleInput(QScroller::InputMove, m_viewport->mapFromItem(m_content, touchPoint), eventTimestampMillis);
}
void QtViewportInteractionEngine::panGestureCancelled()
{
ViewportUpdateGuard guard(this);
- // FIXME: reset physics.
- panGestureEnded();
+ stopAnimations();
}
-void QtViewportInteractionEngine::panGestureEnded()
+void QtViewportInteractionEngine::panGestureEnded(const QPointF& touchPoint, qint64 eventTimestampMillis)
{
ViewportUpdateGuard guard(this);
- animateContentIntoBoundariesIfNeeded();
- // FIXME: emit viewportTrajectoryVectorChanged(QPointF()) when the pan throw animation ends and the page stops moving.
+ scroller()->handleInput(QScroller::InputRelease, m_viewport->mapFromItem(m_content, touchPoint), eventTimestampMillis);
}
-void QtViewportInteractionEngine::pinchGestureStarted()
+void QtViewportInteractionEngine::pinchGestureStarted(const QPointF& pinchCenterInContentCoordinate)
{
if (!m_constraints.isUserScalable)
return;
m_pinchViewportUpdateDeferrer = adoptPtr(new ViewportUpdateGuard(this));
-
+ m_lastPinchCenterInViewportCoordinates = m_viewport->mapFromItem(m_content, pinchCenterInContentCoordinate);
m_userInteractionFlags |= UserHasScaledContent;
m_userInteractionFlags |= UserHasMovedContent;
m_pinchStartScale = m_content->scale();
@@ -180,12 +335,19 @@
ViewportUpdateGuard guard(this);
// Changes of the center position should move the page even if the zoom factor
- // does not change. Both the zoom and the panning should be handled through the physics engine.
+ // does not change.
const qreal scale = m_pinchStartScale * totalScaleFactor;
- QPointF oldPinchCenterOnParent = m_content->mapToItem(m_content->parentItem(), pinchCenterInContentCoordinate);
- m_content->setScale(scale);
- QPointF newPinchCenterOnParent = m_content->mapToItem(m_content->parentItem(), pinchCenterInContentCoordinate);
- m_content->setPos(m_content->pos() - (newPinchCenterOnParent - oldPinchCenterOnParent));
+
+ // Allow zooming out beyond mimimum scale on pages that do not explicitly disallow it.
+ const qreal boundedScale = outerBoundedScale(scale);
+
+ QPointF pinchCenterInViewportCoordinates = m_viewport->mapFromItem(m_content, pinchCenterInContentCoordinate);
+
+ scaleContent(pinchCenterInContentCoordinate, boundedScale);
+
+ const QPointF positionDiff = pinchCenterInViewportCoordinates - m_lastPinchCenterInViewportCoordinates;
+ m_lastPinchCenterInViewportCoordinates = pinchCenterInViewportCoordinates;
+ m_content->setPos(m_content->pos() + positionDiff);
}
void QtViewportInteractionEngine::pinchGestureEnded()
@@ -193,105 +355,21 @@
if (!m_constraints.isUserScalable)
return;
- {
- ViewportUpdateGuard guard(this);
- // FIXME: resume the engine after the animation.
- animateContentIntoBoundariesIfNeeded();
- }
m_pinchViewportUpdateDeferrer.clear();
+ // FIXME: resume the engine after the animation.
+ animateContentIntoBoundariesIfNeeded();
}
void QtViewportInteractionEngine::contentViewportChanged()
{
- if (m_isUpdatingContent)
+ if (m_pendingUpdates)
return;
ViewportUpdateGuard guard(this);
- updateContentIfNeeded();
- // We must notify the change so the client can rely on us for all change of Geometry.
- emit viewportUpdateRequested();
+ animateContentIntoBoundariesIfNeeded();
}
-void QtViewportInteractionEngine::updateContentIfNeeded()
-{
- updateContentScaleIfNeeded();
- updateContentPositionIfNeeded();
-}
-
-void QtViewportInteractionEngine::updateContentScaleIfNeeded()
-{
- const qreal currentContentScale = m_content->scale();
- qreal contentScale = m_content->scale();
- if (!(m_userInteractionFlags & UserHasScaledContent))
- contentScale = m_constraints.initialScale;
-
- contentScale = qBound(m_constraints.minimumScale, contentScale, m_constraints.maximumScale);
-
- if (contentScale != currentContentScale) {
- const QPointF centerOfInterest = visibleRectInContentCoordinate(m_content, m_viewport).center();
- scaleContent(centerOfInterest, contentScale);
- }
-}
-
-void QtViewportInteractionEngine::updateContentPositionIfNeeded()
-{
- if (!(m_userInteractionFlags & UserHasMovedContent)) {
- m_content->setX((m_viewport->width() - contentRectInViewportCoordinate(m_content, m_viewport).width()) / 2);
- m_content->setY(0);
- }
-
- // FIXME: if the item can be fully in the viewport and is over a side, push it back in view
- // FIXME: if the item cannot be fully in viewport, and is not covering the viewport, push it back in view
-}
-
-void QtViewportInteractionEngine::animateContentIntoBoundariesIfNeeded()
-{
- animateContentScaleIntoBoundariesIfNeeded();
- animateContentPositionIntoBoundariesIfNeeded();
-}
-
-void QtViewportInteractionEngine::animateContentPositionIntoBoundariesIfNeeded()
-{
- const QRectF contentGeometry = m_viewport->mapRectFromItem(m_content, m_content->boundingRect());
- QPointF newPos = contentGeometry.topLeft();
-
- // Horizontal correction.
- if (contentGeometry.width() < m_viewport->width())
- newPos.setX((m_viewport->width() - contentGeometry.width()) / 2);
- else {
- newPos.setX(qMin<qreal>(0., newPos.x()));
- const qreal rightSideGap = m_viewport->boundingRect().right() - contentGeometry.right();
- if (rightSideGap > 0.)
- newPos.setX(newPos.x() + rightSideGap);
- }
-
- // Vertical correction.
- if (contentGeometry.height() < m_viewport->height())
- newPos.setY(0);
- else {
- newPos.setY(qMin<qreal>(0., newPos.y()));
- const qreal bottomSideGap = m_viewport->boundingRect().bottom() - contentGeometry.bottom();
- if (bottomSideGap > 0.)
- newPos.setY(newPos.y() + bottomSideGap);
- }
-
- if (newPos != m_content->pos())
- // FIXME: Do you know what ANIMATE means?
- m_content->setPos(newPos);
-}
-
-void QtViewportInteractionEngine::animateContentScaleIntoBoundariesIfNeeded()
-{
- const qreal currentScale = m_content->scale();
- const qreal boundedScale = qBound(m_constraints.minimumScale, currentScale, m_constraints.maximumScale);
- if (currentScale != boundedScale) {
- // FIXME: Do you know what ANIMATE means?
- const QPointF centerOfInterest = visibleRectInContentCoordinate(m_content, m_viewport).center();
- scaleContent(centerOfInterest, boundedScale);
- }
-}
-
void QtViewportInteractionEngine::scaleContent(const QPointF& centerInContentCoordinate, qreal scale)
{
QPointF oldPinchCenterOnParent = m_content->mapToItem(m_content->parentItem(), centerInContentCoordinate);
Modified: trunk/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.h (98459 => 98460)
--- trunk/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.h 2011-10-26 09:41:27 UTC (rev 98459)
+++ trunk/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.h 2011-10-26 09:49:21 UTC (rev 98460)
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2011 Benjamin Poulain <[email protected]>
*
* This library is free software; you can redistribute it and/or
@@ -22,8 +23,11 @@
#define QtViewportInteractionEngine_h
#include "OwnPtr.h"
+#include <QScroller>
#include "qwebkitglobal.h"
#include <QtCore/QObject>
+#include <QtCore/QVariant>
+#include <QtCore/QVariantAnimation>
QT_BEGIN_NAMESPACE
class QPointF;
@@ -41,6 +45,7 @@
QtViewportInteractionEngine(const QSGItem*, QSGItem*);
~QtViewportInteractionEngine();
+
struct Constraints {
Constraints()
: initialScale(1.0)
@@ -55,17 +60,20 @@
bool isUserScalable;
};
+ bool event(QEvent*);
+
void reset();
void setConstraints(const Constraints&);
- void panGestureStarted();
- void panGestureRequestUpdate(qreal deltaX, qreal deltaY);
+ void panGestureStarted(const QPointF& touchPoint, qint64 eventTimestampMillis);
+ void panGestureRequestUpdate(const QPointF& touchPoint, qint64 eventTimestampMillis);
void panGestureCancelled();
- void panGestureEnded();
+ void panGestureEnded(const QPointF& touchPoint, qint64 eventTimestampMillis);
- void pinchGestureStarted();
+ void pinchGestureStarted(const QPointF& pinchCenterInContentCoordinate);
void pinchGestureRequestUpdate(const QPointF& pinchCenterInContentCoordinate, qreal totalScaleFactor);
void pinchGestureEnded();
+ void stopAnimations();
Q_SIGNALS:
void viewportUpdateRequested();
@@ -74,34 +82,48 @@
private Q_SLOTS:
// Respond to changes of content that are not driven by us, like the page resizing itself.
void contentViewportChanged();
+ void updateVisibleRect(QVariant visibleRectVariant);
+ void scaleAnimationStateChanged(QAbstractAnimation::State, QAbstractAnimation::State);
private:
- void updateContentIfNeeded();
- void updateContentScaleIfNeeded();
- void updateContentPositionIfNeeded();
-
+ qreal innerBoundedScale(qreal scale);
+ qreal outerBoundedScale(qreal scale);
+ const QRectF calculateBoundariesForScale(const QSizeF contentSize, const QSizeF viewportSize, qreal scale);
void animateContentIntoBoundariesIfNeeded();
- void animateContentPositionIntoBoundariesIfNeeded();
- void animateContentScaleIntoBoundariesIfNeeded();
void scaleContent(const QPointF& centerInContentCoordinate, qreal scale);
+ // As long as the object exists this function will always return the same QScroller instance.
+ QScroller* scroller() { return QScroller::scroller(this); }
+
friend class ViewportUpdateGuard;
const QSGItem* const m_viewport;
QSGItem* const m_content;
Constraints m_constraints;
- bool m_isUpdatingContent;
+ int m_pendingUpdates;
OwnPtr<ViewportUpdateGuard> m_pinchViewportUpdateDeferrer;
enum UserInteractionFlag {
UserHasNotInteractedWithContent = 0,
UserHasMovedContent = 1,
- UserHasScaledContent = 2
+ UserHasScaledContent = 2,
+ UserHasStoppedAnimations = 4
};
Q_DECLARE_FLAGS(UserInteractionFlags, UserInteractionFlag);
UserInteractionFlags m_userInteractionFlags;
+ class ScaleAnimation : public QVariantAnimation {
+ public:
+ ScaleAnimation(QObject* parent = 0)
+ : QVariantAnimation(parent)
+ { }
+
+ virtual void updateCurrentValue(const QVariant&) { }
+ };
+
+ ScaleAnimation* m_scaleAnimation;
+ QPointF m_lastPinchCenterInViewportCoordinates;
qreal m_pinchStartScale;
};