Diff
Modified: trunk/LayoutTests/ChangeLog (106641 => 106642)
--- trunk/LayoutTests/ChangeLog 2012-02-03 10:04:15 UTC (rev 106641)
+++ trunk/LayoutTests/ChangeLog 2012-02-03 10:10:54 UTC (rev 106642)
@@ -1,3 +1,13 @@
+2012-01-27 Alexander Pavlov <[email protected]>
+
+ Implement touch event emulation in the WebCore layer
+ https://bugs.webkit.org/show_bug.cgi?id=77105
+
+ Reviewed by Ryosuke Niwa.
+
+ * fast/events/touch/emulate-touch-events-expected.txt: Added.
+ * fast/events/touch/emulate-touch-events.html: Added.
+
2012-02-03 Adam Barth <[email protected]>
Group all the security failures together.
Added: trunk/LayoutTests/fast/events/touch/emulate-touch-events-expected.txt (0 => 106642)
--- trunk/LayoutTests/fast/events/touch/emulate-touch-events-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/events/touch/emulate-touch-events-expected.txt 2012-02-03 10:10:54 UTC (rev 106642)
@@ -0,0 +1,61 @@
+This tests single touch event emulation using mouse events.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS lastEvent.type is "touchstart"
+PASS lastEvent.touches.length is 1
+PASS lastEvent.changedTouches.length is 1
+PASS lastEvent.targetTouches.length is 1
+PASS lastEvent.pageX is 0
+PASS lastEvent.pageY is 0
+PASS lastEvent.shiftKey is true
+PASS lastEvent.altKey is true
+PASS lastEvent.ctrlKey is false
+PASS lastEvent.metaKey is false
+PASS lastEvent.touches[0].target.id is "touchtarget"
+PASS lastEvent.touches[0].pageX is 10
+PASS lastEvent.touches[0].pageY is 10
+PASS lastEvent.touches[0].clientX is 10
+PASS lastEvent.touches[0].clientY is 10
+PASS lastEvent.touches[0].identifier is 0
+PASS lastEvent.changedTouches[0].pageX is 10
+PASS lastEvent.changedTouches[0].pageY is 10
+PASS lastEvent.changedTouches[0].clientX is 10
+PASS lastEvent.changedTouches[0].clientY is 10
+PASS lastEvent.changedTouches[0].identifier is 0
+PASS lastEvent.targetTouches[0].pageX is 10
+PASS lastEvent.targetTouches[0].pageY is 10
+PASS lastEvent.targetTouches[0].clientX is 10
+PASS lastEvent.targetTouches[0].clientY is 10
+PASS lastEvent.targetTouches[0].identifier is 0
+PASS lastEvent.type is "touchmove"
+PASS lastEvent.touches.length is 1
+PASS lastEvent.changedTouches.length is 1
+PASS lastEvent.targetTouches.length is 1
+PASS lastEvent.pageX is 0
+PASS lastEvent.pageY is 0
+PASS lastEvent.touches[0].pageX is 20
+PASS lastEvent.touches[0].pageY is 30
+PASS lastEvent.touches[0].clientX is 20
+PASS lastEvent.touches[0].clientY is 30
+PASS lastEvent.touches[0].identifier is 0
+PASS lastEvent.type is "touchend"
+PASS lastEvent.touches.length is 0
+PASS lastEvent.changedTouches.length is 1
+PASS lastEvent.targetTouches.length is 0
+PASS lastEvent.pageX is 0
+PASS lastEvent.pageY is 0
+PASS lastEvent.changedTouches[0].pageX is 20
+PASS lastEvent.changedTouches[0].pageY is 30
+PASS lastEvent.changedTouches[0].clientX is 20
+PASS lastEvent.changedTouches[0].clientY is 30
+PASS lastEvent.changedTouches[0].identifier is 0
+PASS lastEvent.shiftKey is false
+PASS lastEvent.altKey is true
+PASS lastEvent.ctrlKey is true
+PASS lastEvent.metaKey is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Property changes on: trunk/LayoutTests/fast/events/touch/emulate-touch-events-expected.txt
___________________________________________________________________
Added: svn:eol-style
Added: trunk/LayoutTests/fast/events/touch/emulate-touch-events.html (0 => 106642)
--- trunk/LayoutTests/fast/events/touch/emulate-touch-events.html (rev 0)
+++ trunk/LayoutTests/fast/events/touch/emulate-touch-events.html 2012-02-03 10:10:54 UTC (rev 106642)
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<div id="touchtarget" style="width: 100px; height: 100px; background-color: blue"></div>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+var div = document.getElementById("touchtarget");
+var lastEvent = null;
+var touchEventsReceived = 0;
+var EXPECTED_TOUCH_EVENTS_TOTAL = 3;
+
+function touchEventCallback() {
+ if (window.eventSender) {
+ lastEvent = event;
+ verifyTouch(touchEventsReceived++);
+ } else
+ debug(event.type);
+
+ if (window.layoutTestController && touchEventsReceived == EXPECTED_TOUCH_EVENTS_TOTAL)
+ finishJSTest();
+}
+
+div.addEventListener("touchstart", touchEventCallback, false);
+div.addEventListener("touchmove", touchEventCallback, false);
+div.addEventListener("touchend", touchEventCallback, false);
+
+function verifyTouchEvent(type, totalTouchCount, changedTouchCount, targetTouchCount)
+{
+ shouldBeEqualToString("lastEvent.type", type);
+ shouldBe("lastEvent.touches.length", totalTouchCount.toString());
+ shouldBe("lastEvent.changedTouches.length", changedTouchCount.toString());
+ shouldBe("lastEvent.targetTouches.length", targetTouchCount.toString());
+ shouldBe("lastEvent.pageX", "0");
+ shouldBe("lastEvent.pageY", "0");
+}
+
+function verifyTouchPoint(list, point, x, y, id)
+{
+ shouldBe("lastEvent." + list + "[" + point + "].pageX", x.toString());
+ shouldBe("lastEvent." + list + "[" + point + "].pageY", y.toString());
+ shouldBe("lastEvent." + list + "[" + point + "].clientX", x.toString());
+ shouldBe("lastEvent." + list + "[" + point + "].clientY", y.toString());
+ shouldBe("lastEvent." + list + "[" + point + "].identifier", id.toString());
+}
+
+function verifyTouch(which) {
+ switch (which) {
+ case 0:
+ verifyTouchEvent("touchstart", 1, 1, 1);
+ shouldBe("lastEvent.shiftKey", "true");
+ shouldBe("lastEvent.altKey", "true");
+ shouldBe("lastEvent.ctrlKey", "false");
+ shouldBe("lastEvent.metaKey", "false");
+ shouldBeEqualToString("lastEvent.touches[0].target.id", "touchtarget");
+ verifyTouchPoint("touches", 0, 10, 10, 0);
+ verifyTouchPoint("changedTouches", 0, 10, 10, 0);
+ verifyTouchPoint("targetTouches", 0, 10, 10, 0);
+ break;
+ case 1:
+ verifyTouchEvent("touchmove", 1, 1, 1);
+ verifyTouchPoint("touches", 0, 20, 30, 0);
+ break;
+ case 2:
+ verifyTouchEvent("touchend", 0, 1, 0);
+ verifyTouchPoint("changedTouches", 0, 20, 30, 0);
+ shouldBe("lastEvent.shiftKey", "false");
+ shouldBe("lastEvent.altKey", "true");
+ shouldBe("lastEvent.ctrlKey", "true");
+ shouldBe("lastEvent.metaKey", "false");
+ break;
+ default:
+ testFailed("Wrong number of touch events! (" + which + ")");
+ }
+}
+
+function mouseEventSequence()
+{
+ eventSender.mouseMoveTo(10, 10);
+ eventSender.mouseDown(0, ["shiftKey", "altKey"]);
+ eventSender.mouseMoveTo(20, 30);
+ eventSender.mouseUp(0, ["altKey", "ctrlKey"]);
+}
+
+if (window.eventSender && window.internals && window.internals.settings) {
+ description("This tests single touch event emulation using mouse events.");
+
+ window.eventSender.dragMode = false;
+ window.jsTestIsAsync = true;
+ window.internals.settings.setTouchEventEmulationEnabled(true);
+ mouseEventSequence();
+} else
+ debug("This test requires DumpRenderTree. Tap on the blue rect to log.");
+</script>
+<script src=""
+</body>
+</html>
Property changes on: trunk/LayoutTests/fast/events/touch/emulate-touch-events.html
___________________________________________________________________
Added: svn:eol-style
Modified: trunk/Source/WebCore/ChangeLog (106641 => 106642)
--- trunk/Source/WebCore/ChangeLog 2012-02-03 10:04:15 UTC (rev 106641)
+++ trunk/Source/WebCore/ChangeLog 2012-02-03 10:10:54 UTC (rev 106642)
@@ -1,3 +1,39 @@
+2012-01-27 Alexander Pavlov <[email protected]>
+
+ Implement touch event emulation in the WebCore layer
+ https://bugs.webkit.org/show_bug.cgi?id=77105
+
+ Reviewed by Ryosuke Niwa.
+
+ This change essentially maps mouse events into single-touch events in the following way:
+ - mousedown -> touchstart
+ - mouseup -> touchend
+ - mousemove -> touchmove (between mousedown and mouseup).
+
+ Test: fast/events/touch/emulate-touch-events.html
+
+ * page/EventHandler.cpp:
+ (SyntheticTouchPoint): A synthetic touch point built from PlatformMouseEvent.
+ (WebCore::SyntheticTouchPoint::SyntheticTouchPoint):
+ (SyntheticSingleTouchEvent): A synthetic touch point event built from PlatformMouseEvent.
+ (WebCore::SyntheticSingleTouchEvent::SyntheticSingleTouchEvent):
+ (WebCore::EventHandler::handleMouseReleaseEvent): Invoke maybeDispatchSyntheticTouchEvent() and bail out if necessary.
+ (WebCore::EventHandler::handleMousePressEvent): Invoke maybeDispatchSyntheticTouchEvent() and bail out if necessary.
+ (WebCore::EventHandler::mouseMoved): Invoke maybeDispatchSyntheticTouchEvent() and bail out if necessary.
+ (WebCore::EventHandler::dispatchSyntheticTouchEventIfEnabled): Dispatch a synthetic touch event if necessary.
+ * page/EventHandler.h: Added new method.
+ * page/Settings.cpp:
+ (WebCore::Settings::Settings): Added m_touchEventEmulationEnabled initializer.
+ * page/Settings.h: Added m_touchEventEmulationEnabled, getter, and setter.
+ (WebCore::Settings::setTouchEventEmulationEnabled): Added.
+ (WebCore::Settings::isTouchEventEmulationEnabled): Added.
+ * platform/PlatformTouchPoint.h:
+ (WebCore::PlatformTouchPoint::PlatformTouchPoint): Unconditionally compile the parameterless ctor.
+ * testing/InternalSettings.cpp:
+ (WebCore::InternalSettings::setTouchEventEmulationEnabled): Added for testing.
+ * testing/InternalSettings.h: Added setTouchEventEmulationEnabled() for testing.
+ * testing/InternalSettings.idl: Added setTouchEventEmulationEnabled() for testing.
+
2012-02-03 Kentaro Hara <[email protected]>
Remove [NoCPPCustom] IDL
Modified: trunk/Source/WebCore/page/EventHandler.cpp (106641 => 106642)
--- trunk/Source/WebCore/page/EventHandler.cpp 2012-02-03 10:04:15 UTC (rev 106641)
+++ trunk/Source/WebCore/page/EventHandler.cpp 2012-02-03 10:10:54 UTC (rev 106642)
@@ -60,6 +60,7 @@
#include "MouseEvent.h"
#include "MouseEventWithHitTestResults.h"
#include "Page.h"
+#include "PlatformEvent.h"
#include "PlatformKeyboardEvent.h"
#include "PlatformWheelEvent.h"
#include "PluginDocument.h"
@@ -142,6 +143,73 @@
Cursor m_cursor;
};
+#if ENABLE(TOUCH_EVENTS)
+class SyntheticTouchPoint : public PlatformTouchPoint {
+public:
+
+ // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
+ explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
+ {
+ const static int idDefaultValue = 0;
+ const static int radiusYDefaultValue = 1;
+ const static int radiusXDefaultValue = 1;
+ const static float rotationAngleDefaultValue = 0.0f;
+ const static float forceDefaultValue = 1.0f;
+
+ m_id = idDefaultValue; // There is only one active TouchPoint.
+ m_screenPos = event.globalPosition();
+ m_pos = event.position();
+ m_radiusY = radiusYDefaultValue;
+ m_radiusX = radiusXDefaultValue;
+ m_rotationAngle = rotationAngleDefaultValue;
+ m_force = forceDefaultValue;
+
+ PlatformEvent::Type type = event.type();
+ ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
+
+ switch (type) {
+ case PlatformEvent::MouseMoved:
+ m_state = TouchMoved;
+ break;
+ case PlatformEvent::MousePressed:
+ m_state = TouchPressed;
+ break;
+ case PlatformEvent::MouseReleased:
+ m_state = TouchReleased;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+};
+
+class SyntheticSingleTouchEvent : public PlatformTouchEvent {
+public:
+ explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
+ {
+ switch (event.type()) {
+ case PlatformEvent::MouseMoved:
+ m_type = TouchMove;
+ break;
+ case PlatformEvent::MousePressed:
+ m_type = TouchStart;
+ break;
+ case PlatformEvent::MouseReleased:
+ m_type = TouchEnd;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ m_type = NoType;
+ break;
+ }
+ m_timestamp = event.timestamp();
+ m_modifiers = event.modifiers();
+ m_touchPoints.append(SyntheticTouchPoint(event));
+ }
+};
+#endif
+
static inline bool scrollNode(float delta, WheelEvent::Granularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode)
{
if (!delta)
@@ -739,6 +807,12 @@
bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
{
+#if ENABLE(TOUCH_EVENTS)
+ bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(event.event());
+ if (defaultPrevented)
+ return true;
+#endif
+
if (m_autoscrollInProgress)
stopAutoscrollTimer();
@@ -1375,6 +1449,12 @@
{
RefPtr<FrameView> protector(m_frame->view());
+#if ENABLE(TOUCH_EVENTS)
+ bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
+ if (defaultPrevented)
+ return true;
+#endif
+
UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
// FIXME (bug 68185): this call should be made at another abstraction layer
@@ -1561,6 +1641,13 @@
{
RefPtr<FrameView> protector(m_frame->view());
+#if ENABLE(TOUCH_EVENTS)
+ // FIXME: this should be moved elsewhere to also be able to dispatch touchcancel events.
+ bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(event);
+ if (defaultPrevented)
+ return true;
+#endif
+
HitTestResult hoveredNode = HitTestResult(LayoutPoint());
bool result = handleMouseMoveEvent(event, &hoveredNode);
@@ -3362,8 +3449,22 @@
return defaultPrevented;
}
+bool EventHandler::dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent& event)
+{
+ if (!m_frame->document()->settings()->isTouchEventEmulationEnabled())
+ return false;
+ PlatformEvent::Type eventType = event.type();
+ if (eventType != PlatformEvent::MouseMoved && eventType != PlatformEvent::MousePressed && eventType != PlatformEvent::MouseReleased)
+ return false;
+ if (eventType == PlatformEvent::MouseMoved && !m_touchPressed)
+ return false;
+
+ SyntheticSingleTouchEvent touchEvent(event);
+ return handleTouchEvent(touchEvent);
+}
+
#endif
}
Modified: trunk/Source/WebCore/page/EventHandler.h (106641 => 106642)
--- trunk/Source/WebCore/page/EventHandler.h 2012-02-03 10:04:15 UTC (rev 106641)
+++ trunk/Source/WebCore/page/EventHandler.h 2012-02-03 10:10:54 UTC (rev 106642)
@@ -264,6 +264,10 @@
void fakeMouseMoveEventTimerFired(Timer<EventHandler>*);
void cancelFakeMouseMoveEvent();
+#if ENABLE(TOUCH_EVENTS)
+ bool dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent&);
+#endif
+
void invalidateClick();
Node* nodeUnderMouse() const;
Modified: trunk/Source/WebCore/page/Settings.cpp (106641 => 106642)
--- trunk/Source/WebCore/page/Settings.cpp 2012-02-03 10:04:15 UTC (rev 106641)
+++ trunk/Source/WebCore/page/Settings.cpp 2012-02-03 10:10:54 UTC (rev 106642)
@@ -240,6 +240,9 @@
, m_scrollingCoordinatorEnabled(false)
#endif
, m_notificationsEnabled(true)
+#if ENABLE(TOUCH_EVENTS)
+ , m_touchEventEmulationEnabled(false)
+#endif
, m_loadsImagesAutomaticallyTimer(this, &Settings::loadsImagesAutomaticallyTimerFired)
{
// A Frame may not have been created yet, so we initialize the AtomicString
Modified: trunk/Source/WebCore/page/Settings.h (106641 => 106642)
--- trunk/Source/WebCore/page/Settings.h 2012-02-03 10:04:15 UTC (rev 106641)
+++ trunk/Source/WebCore/page/Settings.h 2012-02-03 10:10:54 UTC (rev 106642)
@@ -523,6 +523,11 @@
void setNotificationsEnabled(bool enabled) { m_notificationsEnabled = enabled; }
bool notificationsEnabled() const { return m_notificationsEnabled; }
+#if ENABLE(TOUCH_EVENTS)
+ void setTouchEventEmulationEnabled(bool enabled) { m_touchEventEmulationEnabled = enabled; }
+ bool isTouchEventEmulationEnabled() const { return m_touchEventEmulationEnabled; }
+#endif
+
private:
Settings(Page*);
@@ -669,6 +674,10 @@
bool m_notificationsEnabled : 1;
+#if ENABLE(TOUCH_EVENTS)
+ bool m_touchEventEmulationEnabled : 1;
+#endif
+
Timer<Settings> m_loadsImagesAutomaticallyTimer;
void loadsImagesAutomaticallyTimerFired(Timer<Settings>*);
Modified: trunk/Source/WebCore/platform/PlatformTouchPoint.h (106641 => 106642)
--- trunk/Source/WebCore/platform/PlatformTouchPoint.h 2012-02-03 10:04:15 UTC (rev 106641)
+++ trunk/Source/WebCore/platform/PlatformTouchPoint.h 2012-02-03 10:10:54 UTC (rev 106642)
@@ -44,9 +44,11 @@
TouchStateEnd // Placeholder: must remain the last item.
};
+ // This is necessary for us to be able to build synthetic events.
+ PlatformTouchPoint() { };
+
#if PLATFORM(QT)
PlatformTouchPoint(const QTouchEvent::TouchPoint&);
- PlatformTouchPoint() {};
#elif PLATFORM(EFL)
PlatformTouchPoint(unsigned id, const IntPoint& windowPos, State);
#endif
Modified: trunk/Source/WebCore/testing/InternalSettings.cpp (106641 => 106642)
--- trunk/Source/WebCore/testing/InternalSettings.cpp 2012-02-03 10:04:15 UTC (rev 106641)
+++ trunk/Source/WebCore/testing/InternalSettings.cpp 2012-02-03 10:10:54 UTC (rev 106642)
@@ -271,4 +271,15 @@
settings()->setPerTileDrawingEnabled(enabled);
}
+void InternalSettings::setTouchEventEmulationEnabled(bool enabled, ExceptionCode& ec)
+{
+#if ENABLE(TOUCH_EVENTS)
+ InternalSettingsGuardForSettings();
+ settings()->setTouchEventEmulationEnabled(enabled);
+#else
+ UNUSED_PARAM(enabled);
+ UNUSED_PARAM(ec);
+#endif
}
+
+}
Modified: trunk/Source/WebCore/testing/InternalSettings.h (106641 => 106642)
--- trunk/Source/WebCore/testing/InternalSettings.h 2012-02-03 10:04:15 UTC (rev 106641)
+++ trunk/Source/WebCore/testing/InternalSettings.h 2012-02-03 10:10:54 UTC (rev 106642)
@@ -64,6 +64,7 @@
float pageScaleFactor(ExceptionCode&);
void setPageScaleFactor(float scaleFactor, int x, int y, ExceptionCode&);
void setPerTileDrawingEnabled(bool enabled, ExceptionCode&);
+ void setTouchEventEmulationEnabled(bool enabled, ExceptionCode&);
private:
InternalSettings(Frame*, InternalSettings* old);
Modified: trunk/Source/WebCore/testing/InternalSettings.idl (106641 => 106642)
--- trunk/Source/WebCore/testing/InternalSettings.idl 2012-02-03 10:04:15 UTC (rev 106641)
+++ trunk/Source/WebCore/testing/InternalSettings.idl 2012-02-03 10:10:54 UTC (rev 106642)
@@ -44,6 +44,7 @@
boolean unifiedTextCheckingEnabled() raises (DOMException);
float pageScaleFactor() raises(DOMException);
void setPageScaleFactor(in float scaleFactor, in long x, in long y) raises(DOMException);
+ void setTouchEventEmulationEnabled(in boolean enabled) raises(DOMException);
};
}