Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Side by Side Diff: Source/core/page/EventHandler.cpp

Issue 1047733002: Fixed mouseenter/mouseleave event firing order. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Fixed tests. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed. 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) 3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) 4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 1428 matching lines...) Expand 10 before | Expand all | Expand 10 after
1439 1439
1440 // Treat any mouse move events as readonly if the user is currently touching the screen. 1440 // Treat any mouse move events as readonly if the user is currently touching the screen.
1441 if (m_touchPressed) 1441 if (m_touchPressed)
1442 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly; 1442 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1443 HitTestRequest request(hitType); 1443 HitTestRequest request(hitType);
1444 MouseEventWithHitTestResults mev = MouseEventWithHitTestResults(mouseEvent, HitTestResult(LayoutPoint())); 1444 MouseEventWithHitTestResults mev = MouseEventWithHitTestResults(mouseEvent, HitTestResult(LayoutPoint()));
1445 1445
1446 // We don't want to do a hit-test in forceLeave scenarios because there migh t actually be some other frame above this one at the specified co-ordinate. 1446 // We don't want to do a hit-test in forceLeave scenarios because there migh t actually be some other frame above this one at the specified co-ordinate.
1447 // So we must force the hit-test to fail, while still clearing hover/active state. 1447 // So we must force the hit-test to fail, while still clearing hover/active state.
1448 if (forceLeave) 1448 if (forceLeave)
1449 m_frame->document()->updateHoverActiveState(request, 0, &mouseEvent); 1449 m_frame->document()->updateHoverActiveState(request, 0);
1450 else 1450 else
1451 mev = prepareMouseEvent(request, mouseEvent); 1451 mev = prepareMouseEvent(request, mouseEvent);
1452 1452
1453 if (hoveredNode) 1453 if (hoveredNode)
1454 *hoveredNode = mev.hitTestResult(); 1454 *hoveredNode = mev.hitTestResult();
1455 1455
1456 Scrollbar* scrollbar = nullptr; 1456 Scrollbar* scrollbar = nullptr;
1457 1457
1458 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) 1458 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1459 m_resizeScrollableArea->resize(mouseEvent, m_offsetFromResizeCorner); 1459 m_resizeScrollableArea->resize(mouseEvent, m_offsetFromResizeCorner);
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
1549 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->ro otFrameToContents(m_lastKnownMousePosition)); 1549 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->ro otFrameToContents(m_lastKnownMousePosition));
1550 return true; 1550 return true;
1551 } 1551 }
1552 1552
1553 if (m_frameSetBeingResized) 1553 if (m_frameSetBeingResized)
1554 return !dispatchMouseEvent(EventTypeNames::mouseup, m_frameSetBeingResiz ed.get(), m_clickCount, mouseEvent, false); 1554 return !dispatchMouseEvent(EventTypeNames::mouseup, m_frameSetBeingResiz ed.get(), m_clickCount, mouseEvent, false);
1555 1555
1556 if (m_lastScrollbarUnderMouse) { 1556 if (m_lastScrollbarUnderMouse) {
1557 invalidateClick(); 1557 invalidateClick();
1558 m_lastScrollbarUnderMouse->mouseUp(mouseEvent); 1558 m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1559 bool setUnder = false; 1559 return !dispatchMouseEvent(EventTypeNames::mouseup, m_nodeUnderMouse.get (), m_clickCount, mouseEvent, false);
Mike West 2015/03/31 11:45:33 Nit: We should change `dispatchMouseEvent` to acce
mustaq 2015/03/31 14:08:31 My main complain was the name setUnder. Added a FI
1560 return !dispatchMouseEvent(EventTypeNames::mouseup, m_lastNodeUnderMouse .get(), m_clickCount, mouseEvent, setUnder);
1561 } 1560 }
1562 1561
1563 // Mouse events simulated from touch should not hit-test again. 1562 // Mouse events simulated from touch should not hit-test again.
1564 ASSERT(!mouseEvent.fromTouch()); 1563 ASSERT(!mouseEvent.fromTouch());
1565 1564
1566 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Release; 1565 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Release;
1567 HitTestRequest request(hitType); 1566 HitTestRequest request(hitType);
1568 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); 1567 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1569 LocalFrame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetN ode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev); 1568 LocalFrame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetN ode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1570 if (m_eventHandlerWillResetCapturingMouseEventsNode) 1569 if (m_eventHandlerWillResetCapturingMouseEventsNode)
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after
1840 // If we're capturing, we always go right to that node. 1839 // If we're capturing, we always go right to that node.
1841 if (m_capturingMouseEventsNode) 1840 if (m_capturingMouseEventsNode)
1842 result = m_capturingMouseEventsNode.get(); 1841 result = m_capturingMouseEventsNode.get();
1843 else { 1842 else {
1844 // If the target node is a text node, dispatch on the parent node - rdar ://4196646 1843 // If the target node is a text node, dispatch on the parent node - rdar ://4196646
1845 if (result && result->isTextNode()) 1844 if (result && result->isTextNode())
1846 result = NodeRenderingTraversal::parent(*result); 1845 result = NodeRenderingTraversal::parent(*result);
1847 } 1846 }
1848 m_nodeUnderMouse = result; 1847 m_nodeUnderMouse = result;
1849 1848
1850 // Fire mouseout/mouseover if the mouse has shifted to a different node.
1851 if (fireMouseOverOut) { 1849 if (fireMouseOverOut) {
1852 DeprecatedPaintLayer* layerForLastNode = layerForNode(m_lastNodeUnderMou se.get()); 1850 DeprecatedPaintLayer* layerForLastNode = layerForNode(m_lastNodeUnderMou se.get());
1853 DeprecatedPaintLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderM ouse.get()); 1851 DeprecatedPaintLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderM ouse.get());
1854 Page* page = m_frame->page(); 1852 Page* page = m_frame->page();
1855 1853
1856 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->docu ment() != m_frame->document())) { 1854 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->docu ment() != m_frame->document())) {
1857 // The mouse has moved between frames. 1855 // The mouse has moved between frames.
1858 if (LocalFrame* frame = m_lastNodeUnderMouse->document().frame()) { 1856 if (LocalFrame* frame = m_lastNodeUnderMouse->document().frame()) {
1859 if (FrameView* frameView = frame->view()) 1857 if (FrameView* frameView = frame->view())
1860 frameView->mouseExitedContentArea(); 1858 frameView->mouseExitedContentArea();
(...skipping 14 matching lines...) Expand all
1875 // The mouse has moved between layers. 1873 // The mouse has moved between layers.
1876 if (ScrollableArea* scrollableAreaForNodeUnderMouse = associatedScro llableArea(layerForNodeUnderMouse)) 1874 if (ScrollableArea* scrollableAreaForNodeUnderMouse = associatedScro llableArea(layerForNodeUnderMouse))
1877 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea(); 1875 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea();
1878 } 1876 }
1879 1877
1880 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame- >document()) { 1878 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame- >document()) {
1881 m_lastNodeUnderMouse = nullptr; 1879 m_lastNodeUnderMouse = nullptr;
1882 m_lastScrollbarUnderMouse = nullptr; 1880 m_lastScrollbarUnderMouse = nullptr;
1883 } 1881 }
1884 1882
1885 if (m_lastNodeUnderMouse != m_nodeUnderMouse) { 1883 if (m_lastNodeUnderMouse != m_nodeUnderMouse)
1886 // send mouseout event to the old node 1884 sendMouseEventsForNodeTransition(m_lastNodeUnderMouse.get(), m_nodeU nderMouse.get(), mouseEvent);
1887 if (m_lastNodeUnderMouse) 1885
1888 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNa mes::mouseout, 0, m_nodeUnderMouse.get()); 1886 m_lastNodeUnderMouse = m_nodeUnderMouse;
1889 // send mouseover event to the new node 1887 }
1890 if (m_nodeUnderMouse) 1888 }
1891 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames: :mouseover, 0, m_lastNodeUnderMouse.get()); 1889
1890 void EventHandler::sendMouseEventsForNodeTransition(Node* exitedNode, Node* ente redNode, const PlatformMouseEvent& mouseEvent)
1891 {
1892 ASSERT(exitedNode != enteredNode);
1893
1894 // First, send the mouseout and mouseover events (which bubble to ancestors)
1895 if (exitedNode) {
1896 exitedNode->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseout, 0, enteredNode);
1897 }
1898 if (enteredNode) {
1899 enteredNode->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseover, 0 , exitedNode);
1900 }
Mike West 2015/03/31 11:45:33 Nit: Drop {} in these two one-line `if`s.
mustaq 2015/03/31 14:08:31 Done.
1901
1902 // Then send mouseenter and mouseleave events. Since these are non-bubbling events, @@@
Mike West 2015/03/31 11:45:33 Nit: "@@@"?
mustaq 2015/03/31 14:08:31 Ooops, used this temp marker to update the comment
1903 // they are dispatched iff there is a capturing
1904 // event handler on an ancestor or a normal event handler on the element its elf. This special
1905 // handling is necessary to avoid O(n^2) capturing event handler checks. We' ll check the previously
1906 // hovered node's ancestor tree for 'mouseleave' handlers here, then check t he newly hovered node's
1907 // ancestor tree for 'mouseenter' handlers after dispatching the 'mouseleave ' events (as the handler
1908 // for 'mouseleave' might set a capturing 'mouseenter' handler, odd as that might be).
Mike West 2015/03/31 11:45:34 What about other mutations? I think we had some is
mustaq 2015/03/31 18:06:27 You are right but this CL is not introducing any n
1909
1910 // Create lists of all exited/entered ancestors, and mark the presence of ca pturing listeners for
1911 // mouseenter and mouseleave.
1912 WillBeHeapVector<RefPtrWillBeMember<Node>, 32> exitedAncestors;
1913 WillBeHeapVector<RefPtrWillBeMember<Node>, 32> enteredAncestors;
1914 bool exitedHasCapturingAncestor = false;
1915 bool enteredHasCapturingAncestor = false;
1916
1917 for (Node* node = exitedNode; node; node = NodeRenderingTraversal::parent(*n ode)) {
1918 exitedAncestors.append(node);
1919 if (node->hasCapturingEventListeners(EventTypeNames::mouseleave))
1920 exitedHasCapturingAncestor = true;
1921 }
1922
1923 for (Node* node = enteredNode; node; node = NodeRenderingTraversal::parent(* node)) {
1924 enteredAncestors.append(node);
1925 if (node->hasCapturingEventListeners(EventTypeNames::mouseenter))
1926 enteredHasCapturingAncestor = true;
1927 }
1928
1929 size_t numExitedAncestors = exitedAncestors.size();
1930 size_t numEnteredAncestors = enteredAncestors.size();
1931
1932 // Locate the common ancestor in the two lists. Start with the assumption th at it's off both the lists.
1933 size_t exitedAncestorIndex = numExitedAncestors;
1934 size_t enteredAncestorIndex = numEnteredAncestors;
1935 for (size_t j = 0; j < numExitedAncestors; j++) {
1936 for (size_t i = 0; i < numEnteredAncestors; i++) {
1937 if (exitedAncestors[j] == enteredAncestors[i]) {
1938 exitedAncestorIndex = j;
1939 enteredAncestorIndex = i;
1940 break;
1941 }
1892 } 1942 }
1893 m_lastNodeUnderMouse = m_nodeUnderMouse; 1943 if (exitedAncestorIndex < numExitedAncestors)
1944 break;
1945 }
1946
1947 // Send mouseleave events to appropriate exited ancestors
1948 for (size_t j = 0; j < exitedAncestorIndex; j++) {
1949 if (exitedHasCapturingAncestor || exitedAncestors[j]->hasEventListeners( EventTypeNames::mouseleave))
1950 exitedAncestors[j]->dispatchMouseEvent(mouseEvent, EventTypeNames::m ouseleave, 0, enteredNode);
1951 }
1952
1953 // Send mouseenter events to appropriate entered ancestors
1954 for (size_t i = enteredAncestorIndex; i > 0; i--) {
Mike West 2015/03/31 11:45:33 Why count backwards here?
mustaq 2015/03/31 14:08:31 We want to fire mouseenter in parent-to-child orde
1955 if (enteredHasCapturingAncestor || enteredAncestors[i-1]->hasEventListen ers(EventTypeNames::mouseenter))
1956 enteredAncestors[i-1]->dispatchMouseEvent(mouseEvent, EventTypeNames ::mouseenter, 0, exitedNode);
1894 } 1957 }
1895 } 1958 }
1896 1959
1897 // The return value means 'continue default handling.' 1960 // The return value means 'continue default handling.'
1898 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe tNode, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder) 1961 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe tNode, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
1899 { 1962 {
1900 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder); 1963 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
1901 return !m_nodeUnderMouse || m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount); 1964 return !m_nodeUnderMouse || m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
1902 } 1965 }
1903 1966
(...skipping 2045 matching lines...) Expand 10 before | Expand all | Expand 10 after
3949 4012
3950 // If it's in the direction to hide the top controls, only consume when the frame can also scroll. 4013 // If it's in the direction to hide the top controls, only consume when the frame can also scroll.
3951 if (m_frame->view()->scrollPosition().y() < m_frame->view()->maximumScrollPo sition().y()) 4014 if (m_frame->view()->scrollPosition().y() < m_frame->view()->maximumScrollPo sition().y())
3952 return true; 4015 return true;
3953 4016
3954 return false; 4017 return false;
3955 } 4018 }
3956 4019
3957 4020
3958 } // namespace blink 4021 } // namespace blink
OLDNEW
« Source/core/dom/Document.cpp ('K') | « Source/core/page/EventHandler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698