Chromium Code Reviews| Index: Source/core/input/EventHandler.cpp |
| diff --git a/Source/core/input/EventHandler.cpp b/Source/core/input/EventHandler.cpp |
| index 19698b6bf5a0b587896378adc6a5058273c8515d..c16f5978c0c9aa417745a9d35dfb942737aee58f 100644 |
| --- a/Source/core/input/EventHandler.cpp |
| +++ b/Source/core/input/EventHandler.cpp |
| @@ -1857,6 +1857,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); |
| @@ -2476,6 +2480,97 @@ 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; |
|
mustaq
2015/07/02 20:37:29
Please avoid duplicate variable names with overlap
Miyoung Shin(c)
2015/07/05 12:39:33
I changed the name to lastEnteredFrameInDocument.
|
| + // Avoid that unnecessary mouse events are fired on tapping across the frames |
| + // 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. |
| + // In A frame we should update mouseout and mouseover events, and in main 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) { |
| + Frame* parent = enteredFrameChain[--indexEnteredFrameChain]->tree().parent(); |
| + if (parent && parent->isLocalFrame()) { |
| + enteredFrameInDocument = toLocalFrame(parent); |
| + enteredFrameInDocument->eventHandler().updateMouseEventTargetNode(toHTMLFrameOwnerElement(enteredFrameChain[indexEnteredFrameChain]->owner()), fakeMouseMove, true); |
| + } |
| + } |
| +} |
| + |
| GestureEventWithHitTestResults EventHandler::targetGestureEvent(const PlatformGestureEvent& gestureEvent, bool readOnly) |
| { |
| TRACE_EVENT0("input", "EventHandler::targetGestureEvent"); |