Chromium Code Reviews| Index: Source/core/page/EventHandler.cpp |
| diff --git a/Source/core/page/EventHandler.cpp b/Source/core/page/EventHandler.cpp |
| index d26cd614a18903911ad11f4746158ee73bb540f4..e6f3638ca43c15d221843eb900419d2ab8182821 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,57 @@ 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; |
| + |
| + // Iterate the changedTouches list and m_targets within it, sending PointerEvents |
| + // to the targets as required. |
|
Rick Byers
2015/05/25 18:24:26
I think you'll want to skip all this if your Runti
mustaq
2015/05/26 15:00:09
Done. See my next comment on cleanup.
|
| + 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); |
|
Rick Byers
2015/05/25 18:24:26
I think this would be simpler if you didn't use th
mustaq
2015/05/26 15:00:09
I agree on your first point. I will isolate the in
|
| + 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(); |