Index: Source/core/page/EventHandler.cpp |
diff --git a/Source/core/page/EventHandler.cpp b/Source/core/page/EventHandler.cpp |
index d26cd614a18903911ad11f4746158ee73bb540f4..f97079e68754f5e22c0bd6f4e9f23afdce63f9c2 100644 |
--- a/Source/core/page/EventHandler.cpp |
+++ b/Source/core/page/EventHandler.cpp |
@@ -45,6 +45,7 @@ |
#include "core/events/EventPath.h" |
#include "core/events/KeyboardEvent.h" |
#include "core/events/MouseEvent.h" |
+#include "core/events/PointerEvent.h" |
#include "core/events/TextEvent.h" |
#include "core/events/TouchEvent.h" |
#include "core/events/WheelEvent.h" |
@@ -237,6 +238,7 @@ EventHandler::EventHandler(LocalFrame* frame) |
, m_mouseDownTimestamp(0) |
, m_widgetIsLatched(false) |
, m_touchPressed(false) |
+ , m_primaryPointerId(0) |
, m_scrollGestureHandlingNode(nullptr) |
, m_lastGestureScrollOverWidget(false) |
, m_maxMouseMovedDuration(0) |
@@ -317,6 +319,7 @@ void EventHandler::clear() |
m_scrollbarHandlingScrollGesture = nullptr; |
m_maxMouseMovedDuration = 0; |
m_touchPressed = false; |
+ m_primaryPointerId = 0; |
m_mouseDownMayStartSelect = false; |
m_mouseDownMayStartDrag = false; |
m_lastShowPressTimestamp = 0; |
@@ -3776,7 +3779,7 @@ void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setL |
} |
} |
-static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state) |
+static const AtomicString& touchEventNameForTouchPointState(PlatformTouchPoint::State state) |
{ |
switch (state) { |
case PlatformTouchPoint::TouchReleased: |
@@ -3795,6 +3798,25 @@ static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State |
} |
} |
+static const AtomicString& pointerEventNameForTouchPointState(PlatformTouchPoint::State state) |
+{ |
+ switch (state) { |
+ case PlatformTouchPoint::TouchReleased: |
+ return EventTypeNames::pointerup; |
+ case PlatformTouchPoint::TouchCancelled: |
+ return EventTypeNames::pointercancel; |
+ case PlatformTouchPoint::TouchPressed: |
+ return EventTypeNames::pointerdown; |
+ case PlatformTouchPoint::TouchMoved: |
+ return EventTypeNames::pointermove; |
+ case PlatformTouchPoint::TouchStationary: |
+ // TouchStationary state is not converted to touch events, so fall through to assert. |
+ default: |
+ ASSERT_NOT_REACHED(); |
+ return emptyAtom; |
+ } |
+} |
+ |
HitTestResult EventHandler::hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType) |
{ |
HitTestResult result(HitTestRequest(hitType), point); |
@@ -3816,10 +3838,9 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) |
const Vector<PlatformTouchPoint>& points = event.touchPoints(); |
- unsigned i; |
bool freshTouchEvents = true; |
bool allTouchReleased = true; |
- for (i = 0; i < points.size(); ++i) { |
+ for (unsigned i = 0; i < points.size(); ++i) { |
const PlatformTouchPoint& point = points[i]; |
if (point.state() != PlatformTouchPoint::TouchPressed) |
freshTouchEvents = false; |
@@ -3853,7 +3874,7 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) |
} |
// First do hit tests for any new touch points. |
- for (i = 0; i < points.size(); ++i) { |
+ for (unsigned i = 0; i < points.size(); ++i) { |
const PlatformTouchPoint& point = points[i]; |
// Touch events implicitly capture to the touched node, and don't change |
@@ -3888,6 +3909,10 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) |
ASSERT(m_touchSequenceDocument->frame()->view()); |
} |
+ // If it is the first TouchPressed we have seen so far, we will consider it primary. |
+ if (!m_primaryPointerId) |
+ m_primaryPointerId = point.id(); |
+ |
// Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id()) |
// since we shouldn't get a touchstart for a touch that's already |
// down. However EventSender allows this to be violated and there's |
@@ -3904,6 +3929,10 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) |
m_touchPressed = !allTouchReleased; |
+ unsigned lastPrimaryPointerId = m_primaryPointerId; |
+ if (allTouchReleased) |
+ m_primaryPointerId = 0; |
+ |
// If there's no document receiving touch events, or no handlers on the |
// document set to receive the events, then we can skip all the rest of |
// this work. |
@@ -3938,7 +3967,7 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) |
EventTargetSet m_targets; |
} changedTouches[PlatformTouchPoint::TouchStateEnd]; |
- for (i = 0; i < points.size(); ++i) { |
+ for (unsigned i = 0; i < points.size(); ++i) { |
const PlatformTouchPoint& point = points[i]; |
PlatformTouchPoint::State pointState = point.state(); |
RefPtrWillBeRawPtr<EventTarget> touchTarget = nullptr; |
@@ -4031,20 +4060,59 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) |
m_touchSequenceUserGestureToken.clear(); |
} |
- // Now iterate the changedTouches list and m_targets within it, sending |
- // events to the targets as required. |
bool swallowedEvent = false; |
+ |
+ if (RuntimeEnabledFeatures::pointerEventEnabled()) { |
+ // Iterate the changedTouches list and m_targets within it, sending PointerEvents |
+ // to the targets as required. |
+ for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) { |
+ if (!changedTouches[state].m_touches) |
+ continue; |
+ |
+ const AtomicString& eventName(pointerEventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state))); |
+ const EventTargetSet& targetsForState = changedTouches[state].m_targets; |
+ |
+ for (const RefPtrWillBeMember<EventTarget>& eventTarget : targetsForState) { |
+ EventTarget* pointerEventTarget = eventTarget.get(); |
+ TouchList* touchesForTarget = touchesByTarget.get(pointerEventTarget); |
+ for (unsigned i = 0; i < touchesForTarget->length(); i++) { |
+ Touch* touch = touchesForTarget->item(i); |
+ |
+ PointerEventInit pointerEventInit; |
+ pointerEventInit.setPointerId(touch->identifier()); |
+ pointerEventInit.setWidth(touch->radiusX()); |
+ pointerEventInit.setHeight(touch->radiusY()); |
+ pointerEventInit.setPressure(touch->force()); |
+ pointerEventInit.setTiltX(0.0); |
+ pointerEventInit.setTiltY(0.0); |
+ pointerEventInit.setPointerType(eventName); |
+ pointerEventInit.setIsPrimary(lastPrimaryPointerId == touch->identifier()); |
+ |
+ RefPtrWillBeRawPtr<PointerEvent> pointerEvent = PointerEvent::create(eventName, pointerEventInit); |
+ pointerEventTarget->toNode()->dispatchPointerEvent(pointerEvent.get()); |
+ swallowedEvent = swallowedEvent || pointerEvent->defaultPrevented() || pointerEvent->defaultHandled(); |
+ } |
+ } |
+ } |
+ |
+ // Skip firing TouchEvent's if any PointerEvent was consumed. |
+ if (swallowedEvent) |
+ return true; |
+ } |
+ |
+ // Now iterate the changedTouches list and m_targets within it, sending |
+ // TouchEvents to the targets as required. |
for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) { |
if (!changedTouches[state].m_touches) |
continue; |
- const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state))); |
+ const AtomicString& eventName(touchEventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state))); |
const EventTargetSet& targetsForState = changedTouches[state].m_targets; |
for (const RefPtrWillBeMember<EventTarget>& eventTarget : targetsForState) { |
EventTarget* touchEventTarget = eventTarget.get(); |
RefPtrWillBeRawPtr<TouchEvent> touchEvent = TouchEvent::create( |
touches.get(), touchesByTarget.get(touchEventTarget), changedTouches[state].m_touches.get(), |
- stateName, touchEventTarget->toNode()->document().domWindow(), |
+ eventName, touchEventTarget->toNode()->document().domWindow(), |
event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), event.cancelable(), event.causesScrollingIfUncanceled(), event.timestamp()); |
touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get()); |
swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled(); |