Chromium Code Reviews| Index: Source/core/page/EventHandler.cpp |
| diff --git a/Source/core/page/EventHandler.cpp b/Source/core/page/EventHandler.cpp |
| index 6cfb5ac4da40857cf04b2ad674cc0e7b2891759a..8e842b41eee0e3edbeee93b75b5f52fe75e9edb0 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" |
| @@ -244,11 +245,13 @@ EventHandler::EventHandler(LocalFrame* frame) |
| , m_lastShowPressTimestamp(0) |
| , m_deltaConsumedForScrollSequence(false) |
| { |
| + m_primaryIdByPointerType.clear(); |
| } |
| EventHandler::~EventHandler() |
| { |
| ASSERT(!m_fakeMouseMoveEventTimer.isActive()); |
| + m_primaryIdByPointerType.clear(); |
| } |
| DEFINE_TRACE(EventHandler) |
| @@ -316,6 +319,7 @@ void EventHandler::clear() |
| m_scrollbarHandlingScrollGesture = nullptr; |
| m_maxMouseMovedDuration = 0; |
| m_touchPressed = false; |
| + m_primaryIdByPointerType.clear(); |
| m_mouseDownMayStartSelect = false; |
| m_mouseDownMayStartDrag = false; |
| m_lastShowPressTimestamp = 0; |
| @@ -3777,7 +3781,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: |
| @@ -3796,6 +3800,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. |
|
Rick Byers
2015/06/11 04:14:56
remove incorrect (and otherwise fairly useless) co
mustaq
2015/06/12 16:05:23
Done.
|
| + default: |
| + ASSERT_NOT_REACHED(); |
| + return emptyAtom; |
| + } |
| +} |
| + |
| HitTestResult EventHandler::hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType) |
| { |
| HitTestResult result(HitTestRequest(hitType), point); |
| @@ -3815,13 +3838,14 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) |
| { |
| TRACE_EVENT0("blink", "EventHandler::handleTouchEvent"); |
| + const String& PointerTypeTouch("touch"); |
| 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; |
| if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled) |
| @@ -3854,7 +3878,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 |
| @@ -3916,30 +3940,18 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) |
| return false; |
| } |
| - // Build up the lists to use for the 'touches', 'targetTouches' and |
| - // 'changedTouches' attributes in the JS event. See |
| - // http://www.w3.org/TR/touch-events/#touchevent-interface for how these |
| - // lists fit together. |
| - |
| - // Holds the complete set of touches on the screen. |
| - RefPtrWillBeRawPtr<TouchList> touches = TouchList::create(); |
| - |
| - // A different view on the 'touches' list above, filtered and grouped by |
| - // event target. Used for the 'targetTouches' list in the JS event. |
| - using TargetTouchesHeapMap = WillBeHeapHashMap<EventTarget*, RefPtrWillBeMember<TouchList>>; |
| - TargetTouchesHeapMap touchesByTarget; |
| - |
| - // Array of touches per state, used to assemble the 'changedTouches' list. |
| - using EventTargetSet = WillBeHeapHashSet<RefPtrWillBeMember<EventTarget>>; |
| - struct { |
| - // The touches corresponding to the particular change state this struct |
| - // instance represents. |
| - RefPtrWillBeMember<TouchList> m_touches; |
| - // Set of targets involved in m_touches. |
| - EventTargetSet m_targets; |
| - } changedTouches[PlatformTouchPoint::TouchStateEnd]; |
| - |
| - for (i = 0; i < points.size(); ++i) { |
| + // Compute and store the common info used by both PointerEvent and TouchEvent. |
| + using TouchInfo = struct { |
|
Rick Byers
2015/06/11 04:14:56
curious: how is this syntax different from the sim
mustaq
2015/06/12 16:05:24
I need to use 'typedef struct {...} TouchInfo' her
Rick Byers
2015/06/16 17:25:38
Ah, cool - thanks!
|
| + EventTarget* touchTarget; |
| + LocalFrame* targetFrame; |
| + FloatPoint adjustedPagePoint; |
| + FloatSize adjustedRadius; |
| + bool knownTarget; |
| + bool consumed; |
| + }; |
| + Vector<TouchInfo> touchInfos(points.size()); |
| + |
| + for (unsigned i = 0; i < points.size(); ++i) { |
| const PlatformTouchPoint& point = points[i]; |
| PlatformTouchPoint::State pointState = point.state(); |
| RefPtrWillBeRawPtr<EventTarget> touchTarget = nullptr; |
| @@ -3988,21 +4000,127 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) |
| // pagePoint should always be in the target element's document coordinates. |
| FloatPoint pagePoint = targetFrame->view()->rootFrameToContents(point.pos()); |
| - |
| float scaleFactor = 1.0f / targetFrame->pageZoomFactor(); |
| FloatPoint adjustedPagePoint = pagePoint.scaledBy(scaleFactor); |
|
Rick Byers
2015/06/11 04:14:56
kind of silly to create these locals just to assig
mustaq
2015/06/12 16:05:24
Done.
|
| FloatSize adjustedRadius = point.radius().scaledBy(scaleFactor); |
| + TouchInfo& touchInfo = touchInfos[i]; |
| + touchInfo.touchTarget = touchTarget.get(); |
| + touchInfo.targetFrame = targetFrame; |
| + touchInfo.adjustedPagePoint = adjustedPagePoint; |
| + touchInfo.adjustedRadius = adjustedRadius; |
| + touchInfo.knownTarget = knownTarget; |
| + touchInfo.consumed = false; |
| + } |
| + |
| + if (RuntimeEnabledFeatures::pointerEventEnabled()) { |
|
Rick Byers
2015/06/11 04:14:56
could some of this be factored out to another func
mustaq
2015/06/12 16:05:23
Done.
|
| + bool hasPrimaryIdForTouch = m_primaryIdByPointerType.contains(PointerTypeTouch); |
| + unsigned primaryIdForTouch = hasPrimaryIdForTouch? m_primaryIdByPointerType.get(PointerTypeTouch) : 0; |
|
Rick Byers
2015/06/11 04:14:56
nit: space before ?
mustaq
2015/06/12 16:05:24
Done.
|
| + |
| + // Iterate through the touch points, sending PointerEvents to the targets as required. |
| + for (unsigned i = 0; i < points.size(); ++i) { |
| + const PlatformTouchPoint& point = points[i]; |
| + TouchInfo& touchInfo = touchInfos[i]; |
| + |
| + const PlatformTouchPoint::State pointState = point.state(); |
| + const AtomicString& eventName(pointerEventNameForTouchPointState(pointState)); |
|
USE eero AT chromium.org
2015/06/11 11:12:42
This does not handle correctly touch points whose
mustaq
2015/06/12 16:05:23
Done.
|
| + |
| + if (pointState == PlatformTouchPoint::TouchPressed && !hasPrimaryIdForTouch) { |
| + primaryIdForTouch = point.id(); |
| + m_primaryIdByPointerType.set(PointerTypeTouch, primaryIdForTouch); |
| + hasPrimaryIdForTouch = true; |
| + } |
| + |
| + bool isEnterOrLeave = false; |
| + bool isCancelable = !(isEnterOrLeave || pointState == PlatformTouchPoint::TouchCancelled); |
| + bool isBubbling = !isEnterOrLeave; |
| + |
| + PointerEventInit pointerEventInit; |
| + pointerEventInit.setPointerId(point.id()); |
| + pointerEventInit.setWidth(touchInfo.adjustedRadius.width()); |
| + pointerEventInit.setHeight(touchInfo.adjustedRadius.height()); |
| + pointerEventInit.setPressure(point.force()); |
| + pointerEventInit.setTiltX(0.0); |
| + pointerEventInit.setTiltY(0.0); |
| + pointerEventInit.setPointerType(PointerTypeTouch); |
| + pointerEventInit.setIsPrimary(hasPrimaryIdForTouch && primaryIdForTouch == point.id()); |
| + pointerEventInit.setScreenX(point.screenPos().x()); |
| + pointerEventInit.setScreenY(point.screenPos().y()); |
| + pointerEventInit.setClientX(0); |
| + pointerEventInit.setClientY(0); |
|
Rick Byers
2015/06/11 04:14:56
These are wrong - it should have client co-ordinat
mustaq
2015/06/12 16:05:23
Done.
|
| + pointerEventInit.setMovementX(0); |
| + pointerEventInit.setMovementY(0); |
| + pointerEventInit.setButton(0); |
| + pointerEventInit.setButtons(0); |
|
Rick Byers
2015/06/11 04:14:56
This is wrong, should be 1
http://w3c.github.io/po
mustaq
2015/06/12 16:05:23
Done.
|
| + pointerEventInit.setRelatedTarget(nullptr); |
| + |
| + pointerEventInit.setCtrlKey(event.ctrlKey()); |
| + pointerEventInit.setShiftKey(event.shiftKey()); |
| + pointerEventInit.setAltKey(event.altKey()); |
| + pointerEventInit.setMetaKey(event.metaKey()); |
| + |
| + pointerEventInit.setBubbles(isBubbling); |
| + pointerEventInit.setCancelable(isCancelable); |
| + |
| + RefPtrWillBeRawPtr<PointerEvent> pointerEvent = PointerEvent::create(eventName, pointerEventInit); |
| + touchInfo.touchTarget->toNode()->dispatchPointerEvent(pointerEvent.get()); |
| + touchInfo.consumed = pointerEvent->defaultPrevented() || pointerEvent->defaultHandled(); |
| + } |
| + |
| + if (allTouchReleased) |
| + m_primaryIdByPointerType.remove(PointerTypeTouch); |
|
Rick Byers
2015/06/11 04:14:56
This logic deserves a test (at first I thought it
mustaq
2015/06/12 16:05:23
Done.
mustaq
2015/06/12 20:37:18
Just discovered that Chrome reuses 'retired' point
|
| + } |
| + |
| + bool swallowedEvent = false; |
| + |
| + // Build up the lists to use for the 'touches', 'targetTouches' and |
| + // 'changedTouches' attributes in the JS event. See |
| + // http://www.w3.org/TR/touch-events/#touchevent-interface for how these |
| + // lists fit together. |
| + |
| + // Holds the complete set of touches on the screen. |
| + RefPtrWillBeRawPtr<TouchList> touches = TouchList::create(); |
| + |
| + // A different view on the 'touches' list above, filtered and grouped by |
| + // event target. Used for the 'targetTouches' list in the JS event. |
| + using TargetTouchesHeapMap = WillBeHeapHashMap<EventTarget*, RefPtrWillBeMember<TouchList>>; |
| + TargetTouchesHeapMap touchesByTarget; |
| + |
| + // Array of touches per state, used to assemble the 'changedTouches' list. |
| + using EventTargetSet = WillBeHeapHashSet<RefPtrWillBeMember<EventTarget>>; |
| + struct { |
| + // The touches corresponding to the particular change state this struct |
| + // instance represents. |
| + RefPtrWillBeMember<TouchList> m_touches; |
| + // Set of targets involved in m_touches. |
| + EventTargetSet m_targets; |
| + } changedTouches[PlatformTouchPoint::TouchStateEnd]; |
| + |
| + for (unsigned i = 0; i < points.size(); ++i) { |
| + const PlatformTouchPoint& point = points[i]; |
| + const TouchInfo& touchInfo = touchInfos[i]; |
| + PlatformTouchPoint::State pointState = point.state(); |
| + |
| + if (touchInfo.consumed) |
| + continue; |
| + |
| RefPtrWillBeRawPtr<Touch> touch = Touch::create( |
| - targetFrame, touchTarget.get(), point.id(), point.screenPos(), adjustedPagePoint, adjustedRadius, point.rotationAngle(), point.force()); |
| + touchInfo.targetFrame, |
| + touchInfo.touchTarget, |
| + point.id(), |
| + point.screenPos(), |
| + touchInfo.adjustedPagePoint, |
| + touchInfo.adjustedRadius, |
| + point.rotationAngle(), |
| + point.force()); |
| // Ensure this target's touch list exists, even if it ends up empty, so |
| // it can always be passed to TouchEvent::Create below. |
| - TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get()); |
| + TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.find(touchInfo.touchTarget); |
| if (targetTouchesIterator == touchesByTarget.end()) { |
| - touchesByTarget.set(touchTarget.get(), TouchList::create()); |
| - targetTouchesIterator = touchesByTarget.find(touchTarget.get()); |
| + touchesByTarget.set(touchInfo.touchTarget, TouchList::create()); |
| + targetTouchesIterator = touchesByTarget.find(touchInfo.touchTarget); |
| } |
| // touches and targetTouches should only contain information about |
| @@ -4019,12 +4137,12 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) |
| // never be in the changedTouches list so we do not handle them |
| // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609 |
| // for further discussion about the TouchStationary state. |
| - if (pointState != PlatformTouchPoint::TouchStationary && knownTarget) { |
| + if (pointState != PlatformTouchPoint::TouchStationary && touchInfo.knownTarget) { |
| ASSERT(pointState < PlatformTouchPoint::TouchStateEnd); |
| if (!changedTouches[pointState].m_touches) |
| changedTouches[pointState].m_touches = TouchList::create(); |
| changedTouches[pointState].m_touches->append(touch); |
| - changedTouches[pointState].m_targets.add(touchTarget); |
| + changedTouches[pointState].m_targets.add(touchInfo.touchTarget); |
| } |
| } |
| if (allTouchReleased) { |
| @@ -4032,20 +4150,19 @@ 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; |
| + // Now iterate through 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(); |