diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp | 199 |
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" |