Chromium Code Reviews| Index: third_party/WebKit/Source/core/input/PointerEventManager.cpp |
| diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.cpp b/third_party/WebKit/Source/core/input/PointerEventManager.cpp |
| index c3cb5b770a9521f9937ea289373426c9127a9dcf..73f1e870e793bc26e0699d466514d7405530a2bb 100644 |
| --- a/third_party/WebKit/Source/core/input/PointerEventManager.cpp |
| +++ b/third_party/WebKit/Source/core/input/PointerEventManager.cpp |
| @@ -5,6 +5,7 @@ |
| #include "core/input/PointerEventManager.h" |
| #include "core/dom/ElementTraversal.h" |
| +#include "core/dom/ExecutionContextTask.h" |
| #include "core/dom/shadow/FlatTreeTraversal.h" |
| #include "core/events/MouseEvent.h" |
| #include "core/frame/FrameView.h" |
| @@ -366,7 +367,7 @@ void PointerEventManager::blockTouchPointers() |
| getEffectiveTargetForPointerEvent(target, pointerEvent->pointerId()), |
| pointerEvent); |
| - releasePointerCapture(pointerEvent->pointerId()); |
| + modifyPendingPointerCapture(pointerEvent->pointerId(), nullptr); |
| // Sending the leave/out events and lostpointercapture |
| // because the next touch event will have a different id. So delayed |
| @@ -512,7 +513,7 @@ WebInputEventResult PointerEventManager::sendTouchPointerEvent( |
| if (pointerEvent->type() == EventTypeNames::pointerup |
| || pointerEvent->type() == EventTypeNames::pointercancel) { |
| - releasePointerCapture(pointerEvent->pointerId()); |
| + modifyPendingPointerCapture(pointerEvent->pointerId(), nullptr); |
| // Sending the leave/out events and lostpointercapture |
| // because the next touch event will have a different id. So delayed |
| @@ -578,7 +579,7 @@ WebInputEventResult PointerEventManager::sendMousePointerEvent( |
| } |
| if (pointerEvent->buttons() == 0) { |
| - releasePointerCapture(pointerEvent->pointerId()); |
| + modifyPendingPointerCapture(pointerEvent->pointerId(), nullptr); |
| if (pointerEvent->isPrimary()) { |
| m_preventMouseEventForPointerType[toPointerTypeIndex( |
| mouseEvent.pointerProperties().pointerType)] = false; |
| @@ -612,6 +613,25 @@ void PointerEventManager::clear() |
| m_pendingPointerCaptureTarget.clear(); |
| } |
| +bool PointerEventManager::getPointerCaptureState(int pointerId, |
| + EventTarget** pointerCaptureTarget, |
| + EventTarget** pendingPointerCaptureTarget) |
| +{ |
| + PointerCapturingMap::iterator it; |
| + |
| + it = m_pointerCaptureTarget.find(pointerId); |
| + EventTarget* pct = (it != m_pointerCaptureTarget.end()) ? it->value : nullptr; |
|
haraken
2016/07/21 15:08:09
pct => target
Blink prefers fully-qualified varia
Navid Zolghadr
2016/07/21 19:17:22
Done.
|
| + it = m_pendingPointerCaptureTarget.find(pointerId); |
| + EventTarget* ppct = (it != m_pendingPointerCaptureTarget.end()) ? it->value : nullptr; |
| + |
| + if (pointerCaptureTarget) |
| + *pointerCaptureTarget = pct; |
| + if (pendingPointerCaptureTarget) |
| + *pendingPointerCaptureTarget = ppct; |
| + |
| + return pct != ppct; |
| +} |
| + |
| void PointerEventManager::processCaptureAndPositionOfPointerEvent( |
| PointerEvent* pointerEvent, |
| EventTarget* hitTestTarget, |
| @@ -636,23 +656,56 @@ void PointerEventManager::processCaptureAndPositionOfPointerEvent( |
| } |
| } |
| +void PointerEventManager::immediatelyProcessPendingPointerCapture(int pointerId) |
| +{ |
| + EventTarget* pointerCaptureTarget; |
| + EventTarget* pendingPointerCaptureTarget; |
| + const bool isCaptureChanged = getPointerCaptureState(pointerId, |
| + &pointerCaptureTarget, &pendingPointerCaptureTarget); |
| + |
| + if (!isCaptureChanged) |
| + return; |
| + |
| + if (pointerCaptureTarget) { |
| + // Re-target lostpointercapture to the document when the element is |
| + // no longer participating in the tree. |
| + EventTarget* target = pointerCaptureTarget; |
| + if (target->toNode() |
| + && !target->toNode()->isConnected()) { |
| + target = target->toNode()->ownerDocument(); |
| + } |
| + dispatchPointerEvent(target, |
| + m_pointerEventFactory.createPointerCaptureEvent( |
| + pointerId, EventTypeNames::lostpointercapture)); |
| + } |
| + dispatchPointerEvent(pendingPointerCaptureTarget, |
| + m_pointerEventFactory.createPointerCaptureEvent( |
| + pointerId, EventTypeNames::gotpointercapture)); |
| + |
| + // Setting |m_pointerCaptureTarget| comes at the end to prevent the infinite |
| + // loop if js calls set/releasepointercapture in got/lostpointercapture |
| + // handlers. |
| + if (pendingPointerCaptureTarget) |
| + m_pointerCaptureTarget.set(pointerId, pendingPointerCaptureTarget); |
| + else |
| + m_pointerCaptureTarget.remove(pointerId); |
| +} |
| + |
| +// TODO(crbug.com/629921): This function should be merged with |immediatelyProcessPendingPointerCapture| |
| +// when we stop hit-testing while a pointer is captured. |
| bool PointerEventManager::processPendingPointerCapture( |
| PointerEvent* pointerEvent, |
| EventTarget* hitTestTarget, |
| const PlatformMouseEvent& mouseEvent, bool sendMouseEvent) |
| { |
| int pointerId = pointerEvent->pointerId(); |
| - EventTarget* pointerCaptureTarget = |
| - m_pointerCaptureTarget.contains(pointerId) |
| - ? m_pointerCaptureTarget.get(pointerId) : nullptr; |
| - EventTarget* pendingPointerCaptureTarget = |
| - m_pendingPointerCaptureTarget.contains(pointerId) |
| - ? m_pendingPointerCaptureTarget.get(pointerId) : nullptr; |
| + EventTarget* pointerCaptureTarget; |
| + EventTarget* pendingPointerCaptureTarget; |
| + const bool isCaptureChanged = getPointerCaptureState(pointerId, |
| + &pointerCaptureTarget, &pendingPointerCaptureTarget); |
| const EventTargetAttributes &nodeUnderPointerAtt = |
| m_nodeUnderPointer.contains(pointerId) |
| ? m_nodeUnderPointer.get(pointerId) : EventTargetAttributes(); |
| - const bool isCaptureChanged = |
| - pointerCaptureTarget != pendingPointerCaptureTarget; |
| if (isCaptureChanged) { |
| if ((hitTestTarget != nodeUnderPointerAtt.target |
| @@ -678,7 +731,7 @@ bool PointerEventManager::processPendingPointerCapture( |
| } |
| dispatchPointerEvent(target, |
| m_pointerEventFactory.createPointerCaptureEvent( |
| - pointerEvent, EventTypeNames::lostpointercapture)); |
| + pointerId, EventTypeNames::lostpointercapture)); |
| } |
| } |
| @@ -694,7 +747,7 @@ bool PointerEventManager::processPendingPointerCapture( |
| if (isCaptureChanged) { |
| dispatchPointerEvent(pendingPointerCaptureTarget, |
| m_pointerEventFactory.createPointerCaptureEvent( |
| - pointerEvent, EventTypeNames::gotpointercapture)); |
| + pointerId, EventTypeNames::gotpointercapture)); |
| if ((pendingPointerCaptureTarget == hitTestTarget |
| || !pendingPointerCaptureTarget) |
| && (nodeUnderPointerAtt.target != hitTestTarget |
| @@ -751,8 +804,9 @@ void PointerEventManager::elementRemoved(EventTarget* target) |
| void PointerEventManager::setPointerCapture(int pointerId, EventTarget* target) |
| { |
| UseCounter::count(m_frame->document(), UseCounter::PointerEventSetCapture); |
| - if (m_pointerEventFactory.isActiveButtonsState(pointerId)) |
| - m_pendingPointerCaptureTarget.set(pointerId, target); |
| + if (m_pointerEventFactory.isActiveButtonsState(pointerId)) { |
| + modifyPendingPointerCapture(pointerId, target); |
| + } |
| } |
| void PointerEventManager::releasePointerCapture(int pointerId, EventTarget* target) |
| @@ -765,12 +819,30 @@ void PointerEventManager::releasePointerCapture(int pointerId, EventTarget* targ |
| // very next pointer event. They will be the same if there was no change in |
| // capturing of a particular |pointerId|. See crbug.com/614481. |
| if (m_pendingPointerCaptureTarget.get(pointerId) == target) |
| - releasePointerCapture(pointerId); |
| + modifyPendingPointerCapture(pointerId, nullptr); |
| } |
| -void PointerEventManager::releasePointerCapture(int pointerId) |
| +void PointerEventManager::modifyPendingPointerCapture( |
| + int pointerId, EventTarget* target) |
| { |
| - m_pendingPointerCaptureTarget.remove(pointerId); |
| + bool wasCaptureStationary = !getPointerCaptureState(pointerId, nullptr, nullptr); |
| + |
| + if (target) |
| + m_pendingPointerCaptureTarget.set(pointerId, target); |
| + else |
| + m_pendingPointerCaptureTarget.remove(pointerId); |
| + |
| + // Only queue the processing pending pointer capture if the pending |
| + // capture target and capture target were the same to prevent infinite |
| + // got/lostpointercapture event sequence. |
| + // See https://github.com/w3c/pointerevents/issues/32. |
| + if (wasCaptureStationary) { |
| + m_frame->document()->postTask( |
| + BLINK_FROM_HERE, |
| + createSameThreadTask( |
| + &EventHandler::immediatelyProcessPendingPointerCapture, |
| + wrapWeakPersistent(&m_frame->eventHandler()), pointerId)); |
| + } |
| } |
| bool PointerEventManager::isActive(const int pointerId) const |