Index: Source/core/input/EventHandler.cpp |
diff --git a/Source/core/input/EventHandler.cpp b/Source/core/input/EventHandler.cpp |
index 2385b4e685d715befd987ef797187d68381080ab..10501de8d7eadc2fb78f985b28404da9a007791e 100644 |
--- a/Source/core/input/EventHandler.cpp |
+++ b/Source/core/input/EventHandler.cpp |
@@ -2237,6 +2237,10 @@ bool EventHandler::handleGestureEvent(const GestureEventWithHitTestResults& targ |
// directly to the inner most frame. This matches handleMousePressEvent etc. |
ASSERT(!targetedEvent.event().isScrollEvent()); |
+ // update mouseout/leave/over/enter events before jumping directly to the inner most frame |
+ if (targetedEvent.event().type() == PlatformEvent::GestureTap) |
+ updateGestureTargetNodeForMouseEvent(targetedEvent); |
+ |
// Route to the correct frame. |
if (LocalFrame* innerFrame = targetedEvent.hitTestResult().innerNodeFrame()) |
return innerFrame->eventHandler().handleGestureEventInFrame(targetedEvent); |
@@ -2838,6 +2842,95 @@ void EventHandler::updateGestureHoverActiveState(const HitTestRequest& request, |
m_frame->document()->updateHoverActiveState(request, innerElement); |
} |
+// Update the mouseover/mouseenter/mouseout/mouseleave events across all frames for this gesture, |
+// before passing the targeted gesture event directly to a hit frame. |
+void EventHandler::updateGestureTargetNodeForMouseEvent(const GestureEventWithHitTestResults& targetedEvent) |
+{ |
+ ASSERT(m_frame == m_frame->localFrameRoot()); |
+ |
+ // Behaviour of this function is as follows: |
+ // - Create the chain of all entered frames. |
+ // - Compare the last frame chain under the gesture to newly entered frame chain from the main frame one by one. |
+ // - If the last frame doesn't match with the entered frame, then create the chain of exited frames from the last frame chain. |
+ // - Dispatch mouseout/mouseleave events of the exited frames from the inside out. |
+ // - Dispatch mouseover/mouseenter events of the entered frames into the inside. |
+ |
+ // Insert the ancestors of the frame having the new target node to the entered frame chain |
+ WillBeHeapVector<LocalFrame*> enteredFrameChain; |
+ LocalFrame* enteredFrameInDocument = targetedEvent.hitTestResult().innerNodeFrame(); |
+ while (enteredFrameInDocument) { |
+ enteredFrameChain.append(enteredFrameInDocument); |
+ Frame* parentFrame = enteredFrameInDocument->tree().parent(); |
+ enteredFrameInDocument = parentFrame && parentFrame->isLocalFrame() ? toLocalFrame(parentFrame) : nullptr; |
+ } |
+ |
+ size_t indexEnteredFrameChain = enteredFrameChain.size(); |
+ LocalFrame* exitedFrameInDocument = m_frame; |
+ WillBeHeapVector<LocalFrame*> exitedFrameChain; |
+ // Insert the frame from the disagreement between last frames and entered frames |
+ while (exitedFrameInDocument) { |
+ Node* lastNodeUnderTap = exitedFrameInDocument->eventHandler().m_lastNodeUnderMouse.get(); |
+ if (!lastNodeUnderTap) |
+ break; |
+ |
+ LocalFrame* nextExitedFrameInDocument = nullptr; |
+ if (lastNodeUnderTap->isFrameOwnerElement()) { |
+ HTMLFrameOwnerElement* owner = toHTMLFrameOwnerElement(lastNodeUnderTap); |
+ if (owner->contentFrame() && owner->contentFrame()->isLocalFrame()) |
+ nextExitedFrameInDocument = toLocalFrame(owner->contentFrame()); |
+ } |
+ |
+ if (exitedFrameChain.size() > 0) { |
+ exitedFrameChain.append(exitedFrameInDocument); |
+ } else { |
+ LocalFrame* enteredFrameInDocument = indexEnteredFrameChain ? enteredFrameChain[indexEnteredFrameChain-1] : nullptr; |
+ // Avoid that unnecessary mouse events are fired on tapping across the frames |
mustaq
2015/06/16 14:50:44
Thanks Miyoung, I was thinking about a scenario ex
Miyoung Shin(c)
2015/06/20 21:08:29
The iteration of this loop is to check frames from
mustaq
2015/07/02 20:37:29
Thanks for clarifying, and also for adding the ela
|
+ // If tapping is moved x1 to x2 , the last frame chains is, |
+ // Main frame-> A frame -> B frame -> C frame |
+ // and the new frame chains is, |
+ // Main frame -> A frame -> D frame -> E frame |
+ // |------Main frame--------------------| |
+ // | |----------------A---------------| | |
+ // | | |-----B-----| |-----D------| | | |
+ // | | | |---C---| | | |---E----| | | | |
+ // | | | | x1 | | | | x2 | | | | |
+ // | | | |-------| | | |--------| | | | |
+ // | | |-----------| |------------| | | |
+ // | |--------------------------------| | |
+ // |------------------------------------| |
+ // For mouseout/mouseleave events, we should make the exited frame chain like B frame -> C frame. |
+ // For mouseover/mouseenter events, we should make the entered frame chain like D frame -> E frame. |
+ // And in main frame and A sub-frame we shouldn't fire any mouse events. |
+ if (exitedFrameInDocument != enteredFrameInDocument) |
+ exitedFrameChain.append(exitedFrameInDocument); |
+ else if (nextExitedFrameInDocument && indexEnteredFrameChain) |
+ --indexEnteredFrameChain; |
+ } |
+ exitedFrameInDocument = nextExitedFrameInDocument; |
+ } |
+ |
+ const PlatformGestureEvent& gestureEvent = targetedEvent.event(); |
+ unsigned modifiers = gestureEvent.modifiers(); |
+ PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(), |
+ NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0, |
+ static_cast<PlatformEvent::Modifiers>(modifiers), |
+ PlatformMouseEvent::FromTouch, gestureEvent.timestamp()); |
+ |
+ // Update the mouseout/mouseleave event |
+ size_t indexExitedFrameChain = exitedFrameChain.size(); |
+ while (indexExitedFrameChain) { |
+ LocalFrame* exitedFrameInDocument = exitedFrameChain[--indexExitedFrameChain]; |
+ exitedFrameInDocument->eventHandler().updateMouseEventTargetNode(nullptr, fakeMouseMove, true); |
+ } |
+ |
+ // update the mouseover/mouseenter event |
+ while (indexEnteredFrameChain > 1) { |
Miyoung Shin(c)
2015/06/20 21:08:29
After updating the test, I found A sub frame didn'
mustaq
2015/07/02 20:37:29
The change makes sense. But this shouldn't influen
Miyoung Shin(c)
2015/07/05 12:39:33
Yes I got rid of A from list, but A is the parent
mustaq
2015/07/06 17:14:50
I think A shouldn't get any bubbling events from c
|
+ LocalFrame* enteredFrameInDocument = enteredFrameChain[--indexEnteredFrameChain]; |
+ Node* enteredFrameNode = enteredFrameChain[indexEnteredFrameChain-1]->deprecatedLocalOwner(); |
+ enteredFrameInDocument->eventHandler().updateMouseEventTargetNode(enteredFrameNode, fakeMouseMove, true); |
+ } |
+} |
+ |
GestureEventWithHitTestResults EventHandler::targetGestureEvent(const PlatformGestureEvent& gestureEvent, bool readOnly) |
{ |
TRACE_EVENT0("input", "EventHandler::targetGestureEvent"); |