Title: [109575] trunk/Tools
Revision
109575
Author
abe...@webkit.org
Date
2012-03-02 07:27:33 -0800 (Fri, 02 Mar 2012)

Log Message

[Qt][WK2] Infinite loop on history navigation, when panning
https://bugs.webkit.org/show_bug.cgi?id=79119

Reviewed by Simon Hausmann.

Make the touch mocking more robust by creating touch events
directly and sending them synchronously to the browser window.
If the sent touch event was not accepted we propagate the
original mouse event to its target.
This way we make sure we only send either a touch or a mouse
event and do not end up in an infinite loop between our mocking
code and the Qt5 automatic mouse event synthesizing.

* MiniBrowser/qt/BrowserWindow.cpp:
(BrowserWindow::updateVisualMockTouchPoints):
* MiniBrowser/qt/BrowserWindow.h:
(BrowserWindow):
* MiniBrowser/qt/MiniBrowserApplication.cpp:
(touchRectForPosition):
(MiniBrowserApplication::notify):
(MiniBrowserApplication::sendTouchEvent):
* MiniBrowser/qt/MiniBrowserApplication.h:
(MiniBrowserApplication):

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (109574 => 109575)


--- trunk/Tools/ChangeLog	2012-03-02 15:14:47 UTC (rev 109574)
+++ trunk/Tools/ChangeLog	2012-03-02 15:27:33 UTC (rev 109575)
@@ -1,3 +1,29 @@
+2012-03-02  Andras Becsi  <andras.be...@nokia.com>
+
+        [Qt][WK2] Infinite loop on history navigation, when panning
+        https://bugs.webkit.org/show_bug.cgi?id=79119
+
+        Reviewed by Simon Hausmann.
+
+        Make the touch mocking more robust by creating touch events
+        directly and sending them synchronously to the browser window.
+        If the sent touch event was not accepted we propagate the
+        original mouse event to its target.
+        This way we make sure we only send either a touch or a mouse
+        event and do not end up in an infinite loop between our mocking
+        code and the Qt5 automatic mouse event synthesizing.
+
+        * MiniBrowser/qt/BrowserWindow.cpp:
+        (BrowserWindow::updateVisualMockTouchPoints):
+        * MiniBrowser/qt/BrowserWindow.h:
+        (BrowserWindow):
+        * MiniBrowser/qt/MiniBrowserApplication.cpp:
+        (touchRectForPosition):
+        (MiniBrowserApplication::notify):
+        (MiniBrowserApplication::sendTouchEvent):
+        * MiniBrowser/qt/MiniBrowserApplication.h:
+        (MiniBrowserApplication):
+
 2012-03-02  Tor Arne Vestbø  <tor.arne.ves...@nokia.com>
 
         [Qt] Use 'all' as default target when debug_and_release is in effect

Modified: trunk/Tools/MiniBrowser/qt/BrowserWindow.cpp (109574 => 109575)


--- trunk/Tools/MiniBrowser/qt/BrowserWindow.cpp	2012-03-02 15:14:47 UTC (rev 109574)
+++ trunk/Tools/MiniBrowser/qt/BrowserWindow.cpp	2012-03-02 15:27:33 UTC (rev 109575)
@@ -93,30 +93,27 @@
     return window;
 }
 
-void BrowserWindow::updateVisualMockTouchPoints(const QList<QWindowSystemInterface::TouchPoint>& touchPoints)
+void BrowserWindow::updateVisualMockTouchPoints(const QList<QTouchEvent::TouchPoint>& touchPoints)
 {
-    foreach (const QWindowSystemInterface::TouchPoint& touchPoint, touchPoints) {
-        QString mockTouchPointIdentifier = QString("mockTouchPoint%1").arg(touchPoint.id);
+    foreach (const QTouchEvent::TouchPoint& touchPoint, touchPoints) {
+        QString mockTouchPointIdentifier = QString("mockTouchPoint%1").arg(touchPoint.id());
         QQuickItem* mockTouchPointItem = rootObject()->findChild<QQuickItem*>(mockTouchPointIdentifier, Qt::FindDirectChildrenOnly);
 
         if (!mockTouchPointItem) {
             QDeclarativeComponent touchMockPointComponent(engine(), QUrl("qrc:/qml/MockTouchPoint.qml"));
             mockTouchPointItem = qobject_cast<QQuickItem*>(touchMockPointComponent.create());
             mockTouchPointItem->setObjectName(mockTouchPointIdentifier);
-            mockTouchPointItem->setProperty("pointId", QVariant(touchPoint.id));
+            mockTouchPointItem->setProperty("pointId", QVariant(touchPoint.id()));
             mockTouchPointItem->setParent(rootObject());
             mockTouchPointItem->setParentItem(rootObject());
         }
 
-        QPointF position = touchPoint.area.center();
-        position.rx() -= geometry().x();
-        position.ry() -= geometry().y();
-
-        mockTouchPointItem->setX(position.x());
-        mockTouchPointItem->setY(position.y());
-        mockTouchPointItem->setWidth(touchPoint.area.width());
-        mockTouchPointItem->setHeight(touchPoint.area.height());
-        mockTouchPointItem->setProperty("pressed", QVariant(touchPoint.state != Qt::TouchPointReleased));
+        QRectF touchRect = touchPoint.rect();
+        mockTouchPointItem->setX(touchRect.center().x());
+        mockTouchPointItem->setY(touchRect.center().y());
+        mockTouchPointItem->setWidth(touchRect.width());
+        mockTouchPointItem->setHeight(touchRect.height());
+        mockTouchPointItem->setProperty("pressed", QVariant(touchPoint.state() != Qt::TouchPointReleased));
     }
 }
 

Modified: trunk/Tools/MiniBrowser/qt/BrowserWindow.h (109574 => 109575)


--- trunk/Tools/MiniBrowser/qt/BrowserWindow.h	2012-03-02 15:14:47 UTC (rev 109574)
+++ trunk/Tools/MiniBrowser/qt/BrowserWindow.h	2012-03-02 15:27:33 UTC (rev 109575)
@@ -46,7 +46,7 @@
     void focusAddressBar();
     QQuickWebView* webView() const;
 
-    void updateVisualMockTouchPoints(const QList<QWindowSystemInterface::TouchPoint>& touchPoints);
+    void updateVisualMockTouchPoints(const QList<QTouchEvent::TouchPoint>& touchPoints);
 
 public slots:
     BrowserWindow* newWindow(const QString& url = ""

Modified: trunk/Tools/MiniBrowser/qt/MiniBrowserApplication.cpp (109574 => 109575)


--- trunk/Tools/MiniBrowser/qt/MiniBrowserApplication.cpp	2012-03-02 15:14:47 UTC (rev 109574)
+++ trunk/Tools/MiniBrowser/qt/MiniBrowserApplication.cpp	2012-03-02 15:27:33 UTC (rev 109575)
@@ -36,6 +36,13 @@
 #include <QMouseEvent>
 #include <QTouchEvent>
 
+static inline QRectF touchRectForPosition(QPointF centerPoint)
+{
+    QRectF touchRect(0, 0, 40, 40);
+    touchRect.moveCenter(centerPoint);
+    return touchRect;
+}
+
 static inline bool isTouchEvent(const QEvent* event)
 {
     switch (event->type()) {
@@ -80,11 +87,6 @@
 
 bool MiniBrowserApplication::notify(QObject* target, QEvent* event)
 {
-    if(QInputEvent* ie = static_cast<QInputEvent*>(event))
-        m_holdingControl = ie->modifiers().testFlag(Qt::ControlModifier);
-    else
-        m_holdingControl = false;
-
     // We try to be smart, if we received real touch event, we are probably on a device
     // with touch screen, and we should not have touch mocking.
 
@@ -121,39 +123,69 @@
     if (event->type() == QEvent::KeyRelease && static_cast<QKeyEvent*>(event)->key() == Qt::Key_Control) {
         foreach (int id, m_heldTouchPoints)
             if (m_touchPoints.contains(id))
-                m_touchPoints[id].state = Qt::TouchPointReleased;
+                m_touchPoints[id].setState(Qt::TouchPointReleased);
         m_heldTouchPoints.clear();
-        sendTouchEvent(browserWindow);
+        sendTouchEvent(browserWindow, QEvent::TouchEnd, static_cast<QKeyEvent*>(event)->timestamp());
     }
 
     if (isMouseEvent(event)) {
         const QMouseEvent* const mouseEvent = static_cast<QMouseEvent*>(event);
+        m_holdingControl = mouseEvent->modifiers().testFlag(Qt::ControlModifier);
 
-        QWindowSystemInterface::TouchPoint touchPoint;
-        touchPoint.area = QRectF(mouseEvent->globalPos() - QPointF(30, 40), QSizeF(60, 80));
-        touchPoint.pressure = 1;
+        QTouchEvent::TouchPoint touchPoint;
 
+        touchPoint.setRect(touchRectForPosition(mouseEvent->localPos()));
+        touchPoint.setLastPos(m_lastPos);
+        m_lastPos = mouseEvent->pos();
+
+        // Gesture recognition uses the screen position for the initial threshold
+        // but since the canvas translates touch events we actually need to pass
+        // the screen position as the scene position to deliver the appropriate
+        // coordinates to the target.
+        touchPoint.setSceneRect(touchRectForPosition(mouseEvent->screenPos()));
+        touchPoint.setLastScenePos(m_lastScreenPos);
+        m_lastScreenPos = mouseEvent->screenPos();
+        touchPoint.setPressure(1);
+
+        QEvent::Type touchType = QEvent::None;
+
         switch (mouseEvent->type()) {
         case QEvent::MouseButtonPress:
         case QEvent::MouseButtonDblClick:
-            touchPoint.id = mouseEvent->button();
-            if (m_touchPoints.contains(touchPoint.id))
-                touchPoint.state = Qt::TouchPointMoved;
-            else
-                touchPoint.state = Qt::TouchPointPressed;
+            touchPoint.setId(mouseEvent->button());
+            if (m_touchPoints.contains(touchPoint.id())) {
+                touchPoint.setState(Qt::TouchPointMoved);
+                touchType = QEvent::TouchUpdate;
+            } else {
+                touchPoint.setState(Qt::TouchPointPressed);
+                touchType = QEvent::TouchBegin;
+            }
             break;
         case QEvent::MouseMove:
-            if (!mouseEvent->buttons() || !m_touchPoints.contains(mouseEvent->buttons()))
-                return QGuiApplication::notify(target, event);
-            touchPoint.id = mouseEvent->buttons();
-            touchPoint.state = Qt::TouchPointMoved;
+            if (!mouseEvent->buttons() || !m_touchPoints.contains(mouseEvent->buttons())) {
+                // We have to swallow the event instead of propagating it,
+                // since we avoid sending the mouse release events and if the
+                // Flickable is the mouse grabber it would receive the event
+                // and would move the content.
+                event->accept();
+                return true;
+            }
+            touchType = QEvent::TouchUpdate;
+            touchPoint.setId(mouseEvent->buttons());
+            touchPoint.setState(Qt::TouchPointMoved);
             break;
         case QEvent::MouseButtonRelease:
-            touchPoint.state = Qt::TouchPointReleased;
-            touchPoint.id = mouseEvent->button();
+            touchType = QEvent::TouchEnd;
+            touchPoint.setState(Qt::TouchPointReleased);
+            touchPoint.setId(mouseEvent->button());
             if (m_holdingControl) {
-                m_heldTouchPoints.insert(touchPoint.id);
-                return QGuiApplication::notify(target, event);
+                m_heldTouchPoints.insert(touchPoint.id());
+
+                // We avoid sending the release event because the Flickable is
+                // listening to mouse events and would start a bounce-back
+                // animation if it received a mouse release.
+                event->accept();
+                return true;
             }
             break;
         default:
@@ -161,21 +193,27 @@
         }
 
         // Update current touch-point
-        m_touchPoints.insert(touchPoint.id, touchPoint);
+        m_touchPoints.insert(touchPoint.id(), touchPoint);
 
         // Update states for all other touch-points
-        for (QHash<int, QWindowSystemInterface::TouchPoint>::iterator it = m_touchPoints.begin(), end = m_touchPoints.end(); it != end; ++it) {
-            if (it.value().id != touchPoint.id)
-                it.value().state = Qt::TouchPointStationary;
+        for (QHash<int, QTouchEvent::TouchPoint>::iterator it = m_touchPoints.begin(), end = m_touchPoints.end(); it != end; ++it) {
+            if (it.value().id() != touchPoint.id())
+                it.value().setState(Qt::TouchPointStationary);
         }
 
-        sendTouchEvent(browserWindow);
+        Q_ASSERT(touchType != QEvent::None);
+
+        if (!sendTouchEvent(browserWindow, touchType, mouseEvent->timestamp()))
+            return QGuiApplication::notify(target, event);
+
+        event->accept();
+        return true;
     }
 
     return QGuiApplication::notify(target, event);
 }
 
-void MiniBrowserApplication::sendTouchEvent(BrowserWindow* browserWindow)
+bool MiniBrowserApplication::sendTouchEvent(BrowserWindow* browserWindow, QEvent::Type type, ulong timestamp)
 {
     static QTouchDevice* device = 0;
     if (!device) {
@@ -185,16 +223,28 @@
     }
 
     m_pendingFakeTouchEventCount++;
-    QWindowSystemInterface::handleTouchEvent(browserWindow, device, m_touchPoints.values());
 
+    const QList<QTouchEvent::TouchPoint>& currentTouchPoints = m_touchPoints.values();
+    Qt::TouchPointStates touchPointStates = 0;
+    foreach (const QTouchEvent::TouchPoint& touchPoint, currentTouchPoints)
+        touchPointStates |= touchPoint.state();
+
+    QTouchEvent event(type, device, Qt::NoModifier, touchPointStates, currentTouchPoints);
+    event.setTimestamp(timestamp);
+    event.setAccepted(false);
+
+    QGuiApplication::notify(browserWindow, &event);
+
     if (QQuickWebViewExperimental::flickableViewportEnabled())
-        browserWindow->updateVisualMockTouchPoints(m_holdingControl ? m_touchPoints.values() : QList<QWindowSystemInterface::TouchPoint>());
+        browserWindow->updateVisualMockTouchPoints(m_holdingControl ? currentTouchPoints : QList<QTouchEvent::TouchPoint>());
 
     // Get rid of touch-points that are no longer valid
-    foreach (const QWindowSystemInterface::TouchPoint& touchPoint, m_touchPoints) {
-        if (touchPoint.state ==  Qt::TouchPointReleased)
-            m_touchPoints.remove(touchPoint.id);
+    foreach (const QTouchEvent::TouchPoint& touchPoint, currentTouchPoints) {
+        if (touchPoint.state() ==  Qt::TouchPointReleased)
+            m_touchPoints.remove(touchPoint.id());
     }
+
+    return event.isAccepted();
 }
 
 static void printHelp(const QString& programName)

Modified: trunk/Tools/MiniBrowser/qt/MiniBrowserApplication.h (109574 => 109575)


--- trunk/Tools/MiniBrowser/qt/MiniBrowserApplication.h	2012-03-02 15:14:47 UTC (rev 109574)
+++ trunk/Tools/MiniBrowser/qt/MiniBrowserApplication.h	2012-03-02 15:27:33 UTC (rev 109575)
@@ -98,7 +98,7 @@
     virtual bool notify(QObject*, QEvent*);
 
 private:
-    void sendTouchEvent(BrowserWindow*);
+    bool sendTouchEvent(BrowserWindow*, QEvent::Type, ulong timestamp);
     void handleUserOptions();
 
 private:
@@ -109,7 +109,10 @@
     int m_robotExtraTimeSeconds;
     QStringList m_urls;
 
-    QHash<int, QWindowSystemInterface::TouchPoint> m_touchPoints;
+    QPointF m_lastPos;
+    QPointF m_lastScreenPos;
+
+    QHash<int, QTouchEvent::TouchPoint> m_touchPoints;
     QSet<int> m_heldTouchPoints;
 
     WindowOptions m_windowOptions;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to