summaryrefslogtreecommitdiff
path: root/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp')
-rw-r--r--Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp199
1 files changed, 89 insertions, 110 deletions
diff --git a/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp b/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp
index 62400fa42..bfec37138 100644
--- a/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp
+++ b/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp
@@ -23,12 +23,10 @@
#include "QtViewportInteractionEngine.h"
#include "PassOwnPtr.h"
+#include "QtFlickProvider.h"
#include "qquickwebpage_p.h"
#include "qquickwebview_p.h"
#include <QPointF>
-#include <QScrollEvent>
-#include <QScrollPrepareEvent>
-#include <QScrollerProperties>
#include <QTransform>
#include <QWheelEvent>
#include <QtQuick/qquickitem.h>
@@ -80,7 +78,7 @@ public:
emit engine->contentResumeRequested();
// Make sure that tiles all around the viewport will be requested.
- emit engine->viewportTrajectoryVectorChanged(QPointF());
+ emit engine->contentWasMoved(QPointF());
}
private:
@@ -114,41 +112,25 @@ inline QRectF QtViewportInteractionEngine::itemRectFromCSS(const QRectF& cssRect
return itemRect;
}
-QtViewportInteractionEngine::QtViewportInteractionEngine(const QQuickWebView* viewport, QQuickWebPage* content)
+QtViewportInteractionEngine::QtViewportInteractionEngine(QQuickWebView* viewport, QQuickWebPage* content, QtFlickProvider* flickProvider)
: m_viewport(viewport)
, m_content(content)
+ , m_flickProvider(flickProvider)
, m_suspendCount(0)
+ , m_hadUserInteraction(false)
, m_scaleAnimation(new ScaleAnimation(this))
, m_pinchStartScale(-1)
{
reset();
- 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::ScrollingCurve, QEasingCurve(QEasingCurve::OutExpo));
- properties.setScrollMetric(QScrollerProperties::DecelerationFactor, 0.05);
- properties.setScrollMetric(QScrollerProperties::MaximumVelocity, 0.635);
- properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor, 0.33);
- properties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor, 0.33);
-
- scroller()->setScrollerProperties(properties);
-
- connect(m_content, SIGNAL(widthChanged()), this, SLOT(itemSizeChanged()), Qt::DirectConnection);
- connect(m_content, SIGNAL(heightChanged()), this, SLOT(itemSizeChanged()), Qt::DirectConnection);
+ connect(m_content, SIGNAL(widthChanged()), SLOT(itemSizeChanged()), Qt::DirectConnection);
+ connect(m_content, SIGNAL(heightChanged()), SLOT(itemSizeChanged()), Qt::DirectConnection);
+ connect(m_flickProvider, SIGNAL(movingChanged()), SLOT(flickableMovingStateChanged()), Qt::DirectConnection);
connect(m_scaleAnimation, SIGNAL(valueChanged(QVariant)),
SLOT(scaleAnimationValueChanged(QVariant)), Qt::DirectConnection);
connect(m_scaleAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)),
SLOT(scaleAnimationStateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), Qt::DirectConnection);
-
- connect(scroller(), SIGNAL(stateChanged(QScroller::State)),
- SLOT(scrollStateChanged(QScroller::State)), Qt::DirectConnection);
}
QtViewportInteractionEngine::~QtViewportInteractionEngine()
@@ -182,9 +164,11 @@ void QtViewportInteractionEngine::setItemRectVisible(const QRectF& itemRect)
m_content->setContentsScale(itemScale);
- // 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(- itemRect.topLeft() * 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_content->pos() + (itemRect.topLeft() * itemScale));
+
+ m_flickProvider->setContentPos(newPosition);
}
bool QtViewportInteractionEngine::animateItemRectVisible(const QRectF& itemRect)
@@ -203,6 +187,44 @@ bool QtViewportInteractionEngine::animateItemRectVisible(const QRectF& itemRect)
return true;
}
+void QtViewportInteractionEngine::flickableMovingStateChanged()
+{
+ if (m_flickProvider->isMoving()) {
+ if (m_scrollUpdateDeferrer)
+ return; // We get the isMoving() signal multiple times.
+ panMoveStarted();
+ } else
+ panMoveEnded();
+}
+
+void QtViewportInteractionEngine::panMoveStarted()
+{
+ m_scrollUpdateDeferrer = adoptPtr(new ViewportUpdateDeferrer(this));
+
+ m_lastScrollPosition = m_flickProvider->contentPos();
+ connect(m_flickProvider, SIGNAL(contentXChanged()), SLOT(flickableMovingPositionUpdate()));
+ connect(m_flickProvider, SIGNAL(contentYChanged()), SLOT(flickableMovingPositionUpdate()));
+}
+
+void QtViewportInteractionEngine::panMoveEnded()
+{
+ // This method is called on the end of the pan or pan kinetic animation.
+ m_scrollUpdateDeferrer.clear();
+
+ m_lastScrollPosition = QPointF();
+ disconnect(m_flickProvider, SIGNAL(contentXChanged()), this, SLOT(flickableMovingPositionUpdate()));
+ disconnect(m_flickProvider, SIGNAL(contentYChanged()), this, SLOT(flickableMovingPositionUpdate()));
+}
+
+void QtViewportInteractionEngine::flickableMovingPositionUpdate()
+{
+ QPointF newPosition = m_flickProvider->contentPos();
+
+ emit contentWasMoved(m_lastScrollPosition - newPosition);
+
+ m_lastScrollPosition = newPosition;
+}
+
void QtViewportInteractionEngine::scaleAnimationStateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State /*oldState*/)
{
switch (newState) {
@@ -218,60 +240,6 @@ void QtViewportInteractionEngine::scaleAnimationStateChanged(QAbstractAnimation:
}
}
-void QtViewportInteractionEngine::scrollStateChanged(QScroller::State newState)
-{
- switch (newState) {
- case QScroller::Inactive:
- // FIXME: QScroller gets when even when tapping while it is scrolling.
- m_scrollUpdateDeferrer.clear();
- break;
- case QScroller::Pressed:
- case QScroller::Dragging:
- case QScroller::Scrolling:
- if (m_scrollUpdateDeferrer)
- break;
- m_scrollUpdateDeferrer = adoptPtr(new ViewportUpdateDeferrer(this));
- 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 = m_viewport->mapRectFromItem(m_content, m_content->boundingRect());
- const QRectF posRange = computePosRangeForItemAtScale(m_content->contentsScale());
- prepareEvent->setContentPosRange(posRange);
- 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) {
- QPointF currentPosInCSSCoordinates = m_viewport->mapToWebContent(m_content->pos());
- QPointF newPosInCSSCoordinates = m_viewport->mapToWebContent(newPos);
-
- // This must be emitted before viewportUpdateRequested so that the web process knows where to look for tiles.
- emit viewportTrajectoryVectorChanged(currentPosInCSSCoordinates - newPosInCSSCoordinates);
- m_content->setPos(newPos);
- }
- return true;
- }
- default:
- break;
- }
- return QObject::event(event);
-}
-
static inline QPointF boundPosition(const QPointF minPosition, const QPointF& position, const QPointF& maxPosition)
{
return QPointF(qBound(minPosition.x(), position.x(), maxPosition.x()),
@@ -304,9 +272,12 @@ void QtViewportInteractionEngine::wheelEvent(QWheelEvent* ev)
newPos.ry() += delta;
QRectF endPosRange = computePosRangeForItemAtScale(m_content->contentsScale());
- m_content->setPos(-boundPosition(endPosRange.topLeft(), newPos, endPosRange.bottomRight()));
- emit visibleContentRectAndScaleChanged();
+ QPointF currentPosition = m_flickProvider->contentPos();
+ QPointF newPosition = -boundPosition(endPosRange.topLeft(), newPos, endPosRange.bottomRight());
+ m_flickProvider->setContentPos(newPosition);
+
+ emit contentWasMoved(currentPosition - newPosition);
}
void QtViewportInteractionEngine::pagePositionRequest(const QPoint& pagePosition)
@@ -434,8 +405,10 @@ void QtViewportInteractionEngine::reset()
m_hadUserInteraction = false;
- scroller()->stop();
+ m_flickProvider->cancelFlick();
m_scaleAnimation->stop();
+ m_scaleUpdateDeferrer.clear();
+ m_scrollUpdateDeferrer.clear();
}
void QtViewportInteractionEngine::applyConstraints(const Constraints& constraints)
@@ -452,7 +425,7 @@ void QtViewportInteractionEngine::applyConstraints(const Constraints& constraint
m_content->setContentsScale(itemScaleFromCSS(initialScale));
}
- // If the web app changes successively changes the viewport on purpose
+ // If the web app successively changes the viewport on purpose
// it wants to be in control and we should disable animations.
ensureContentWithinViewportBoundary(/* immediate */ true);
}
@@ -464,44 +437,49 @@ qreal QtViewportInteractionEngine::currentCSSScale()
bool QtViewportInteractionEngine::scrollAnimationActive() const
{
- QScroller* scroller = const_cast<QtViewportInteractionEngine*>(this)->scroller();
- return scroller->state() == QScroller::Scrolling;
-}
-
-void QtViewportInteractionEngine::interruptScrollAnimation()
-{
- // Stopping the scroller immediately stops kinetic scrolling and if the view is out of bounds it
- // is moved inside valid bounds immediately as well. This is the behavior that we want.
- scroller()->stop();
+ return m_flickProvider->isFlicking();
}
bool QtViewportInteractionEngine::panGestureActive() const
{
- QScroller* scroller = const_cast<QtViewportInteractionEngine*>(this)->scroller();
- return scroller->state() == QScroller::Pressed || scroller->state() == QScroller::Dragging;
+ return m_flickProvider->isDragging();
}
-void QtViewportInteractionEngine::panGestureStarted(const QPointF& viewportTouchPoint, qint64 eventTimestampMillis)
+void QtViewportInteractionEngine::panGestureStarted(const QTouchEvent* event)
{
m_hadUserInteraction = true;
- scroller()->handleInput(QScroller::InputPress, viewportTouchPoint, eventTimestampMillis);
+
+ ASSERT(event->type() == QEvent::TouchBegin);
+
+ m_flickProvider->handleTouchFlickEvent(const_cast<QTouchEvent*>(event));
+ m_lastPinchCenterInViewportCoordinates = event->touchPoints().first().pos();
}
-void QtViewportInteractionEngine::panGestureRequestUpdate(const QPointF& viewportTouchPoint, qint64 eventTimestampMillis)
+void QtViewportInteractionEngine::panGestureRequestUpdate(const QTouchEvent* event)
{
- scroller()->handleInput(QScroller::InputMove, viewportTouchPoint, eventTimestampMillis);
+ ASSERT(event->type() == QEvent::TouchUpdate);
+
+ m_flickProvider->handleTouchFlickEvent(const_cast<QTouchEvent*>(event));
+ m_lastPinchCenterInViewportCoordinates = event->touchPoints().first().pos();
}
void QtViewportInteractionEngine::panGestureCancelled()
{
- // Stopping the scroller immediately stops kinetic scrolling and if the view is out of bounds it
- // is moved inside valid bounds immediately as well. This is the behavior that we want.
- scroller()->stop();
+ // 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_flickProvider->cancelFlick();
}
-void QtViewportInteractionEngine::panGestureEnded(const QPointF& viewportTouchPoint, qint64 eventTimestampMillis)
+void QtViewportInteractionEngine::panGestureEnded(const QTouchEvent* event)
{
- scroller()->handleInput(QScroller::InputRelease, viewportTouchPoint, eventTimestampMillis);
+ ASSERT(event->type() == QEvent::TouchEnd);
+ m_flickProvider->handleTouchFlickEvent(const_cast<QTouchEvent*>(event));
+ m_lastPinchCenterInViewportCoordinates = event->touchPoints().first().pos();
}
bool QtViewportInteractionEngine::scaleAnimationActive() const
@@ -535,7 +513,7 @@ void QtViewportInteractionEngine::pinchGestureStarted(const QPointF& pinchCenter
m_pinchStartScale = m_content->contentsScale();
// Reset the tiling look-ahead vector so that tiles all around the viewport will be requested on pinch-end.
- emit viewportTrajectoryVectorChanged(QPointF());
+ emit contentWasMoved(QPointF());
}
void QtViewportInteractionEngine::pinchGestureRequestUpdate(const QPointF& pinchCenterInViewportCoordinates, qreal totalScaleFactor)
@@ -557,7 +535,7 @@ void QtViewportInteractionEngine::pinchGestureRequestUpdate(const QPointF& pinch
const QPointF positionDiff = pinchCenterInViewportCoordinates - m_lastPinchCenterInViewportCoordinates;
m_lastPinchCenterInViewportCoordinates = pinchCenterInViewportCoordinates;
- m_content->setPos(m_content->pos() + positionDiff);
+ m_flickProvider->setContentPos(m_flickProvider->contentPos() - positionDiff);
}
void QtViewportInteractionEngine::pinchGestureEnded()
@@ -588,7 +566,8 @@ void QtViewportInteractionEngine::scaleContent(const QPointF& centerInCSSCoordin
QPointF oldPinchCenterOnViewport = m_viewport->mapFromWebContent(centerInCSSCoordinates);
m_content->setContentsScale(itemScaleFromCSS(cssScale));
QPointF newPinchCenterOnViewport = m_viewport->mapFromWebContent(centerInCSSCoordinates);
- m_content->setPos(m_content->pos() - (newPinchCenterOnViewport - oldPinchCenterOnViewport));
+
+ m_flickProvider->setContentPos(m_flickProvider->contentPos() + (newPinchCenterOnViewport - oldPinchCenterOnViewport));
}
#include "moc_QtViewportInteractionEngine.cpp"