Index: Source/core/input/EventHandler.cpp |
diff --git a/Source/core/input/EventHandler.cpp b/Source/core/input/EventHandler.cpp |
index d16e9e2e4ef679e408209463115845eef5fa68ce..281c51c160717a3e14a079d24aeb21a18b7ff424 100644 |
--- a/Source/core/input/EventHandler.cpp |
+++ b/Source/core/input/EventHandler.cpp |
@@ -1852,6 +1852,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); |
@@ -2481,6 +2485,78 @@ 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* lastEnteredFrameInDocument = indexEnteredFrameChain ? enteredFrameChain[indexEnteredFrameChain-1] : nullptr; |
+ if (exitedFrameInDocument != lastEnteredFrameInDocument) |
+ 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* leaveFrame = exitedFrameChain[--indexExitedFrameChain]; |
+ leaveFrame->eventHandler().updateMouseEventTargetNode(nullptr, fakeMouseMove, true); |
+ } |
+ |
+ // update the mouseover/mouseenter event |
+ while (indexEnteredFrameChain) { |
+ Frame* parentFrame = enteredFrameChain[--indexEnteredFrameChain]->tree().parent(); |
+ if (parentFrame && parentFrame->isLocalFrame()) |
+ toLocalFrame(parentFrame)->eventHandler().updateMouseEventTargetNode(toHTMLFrameOwnerElement(enteredFrameChain[indexEnteredFrameChain]->owner()), fakeMouseMove, true); |
+ } |
+} |
+ |
GestureEventWithHitTestResults EventHandler::targetGestureEvent(const PlatformGestureEvent& gestureEvent, bool readOnly) |
{ |
TRACE_EVENT0("input", "EventHandler::targetGestureEvent"); |