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

Unified Diff: Source/core/dom/Document.cpp

Issue 18836002: Implement 'mouseenter' and 'mouseleave' from DOM Level 3 Events. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: Source/core/dom/Document.cpp
diff --git a/Source/core/dom/Document.cpp b/Source/core/dom/Document.cpp
index 30687207b4c4beb57bae8b01403e1cd1678204e4..6b6900f01ed739fa3930116e1ccf7daa40b4ca44 100644
--- a/Source/core/dom/Document.cpp
+++ b/Source/core/dom/Document.cpp
@@ -2895,7 +2895,7 @@ MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& r
renderView()->hitTest(request, result);
if (!request.readOnly())
- updateHoverActiveState(request, result.innerElement());
+ updateHoverActiveState(request, result.innerElement(), &event);
return MouseEventWithHitTestResults(event, result);
}
@@ -4990,13 +4990,13 @@ static RenderObject* nearestCommonHoverAncestor(RenderObject* obj1, RenderObject
return 0;
}
-void Document::updateHoverActiveState(const HitTestRequest& request, Element* innerElement)
+void Document::updateHoverActiveState(const HitTestRequest& request, Element* innerElement, const PlatformMouseEvent* event)
{
ASSERT(!request.readOnly());
Element* innerElementInDocument = innerElement;
while (innerElementInDocument && innerElementInDocument->document() != this) {
- innerElementInDocument->document()->updateHoverActiveState(request, innerElementInDocument);
+ innerElementInDocument->document()->updateHoverActiveState(request, innerElementInDocument, event);
innerElementInDocument = innerElementInDocument->document()->ownerElement();
}
@@ -5059,6 +5059,28 @@ void Document::updateHoverActiveState(const HitTestRequest& request, Element* in
Vector<RefPtr<Node>, 32> nodesToRemoveFromChain;
Vector<RefPtr<Node>, 32> nodesToAddToChain;
+ // mouseenter and mouseleave events do not bubble, so they are dispatched iff there is a capturing
PhistucK 2013/07/08 17:57:26 s/iff/if
Mike West 2013/07/09 09:37:00 "iff" is short for "if and only if" (e.g. "necessa
+ // event handler on an ancestor or a normal event handler on the element itself. This special
+ // handling is necessary to avoid O(n^2) capturing event handler checks.
+ bool hasCapturingMouseEnterListener = false;
+ bool hasCapturingMouseLeaveListener = false;
+ if (event && newHoverNode != oldHoverNode.get()) {
+ // Walk up the newly hovered node's ancestor tree for 'mouseenter' events, and the previously
+ // hovered node's ancestor tree for 'mouseleave' events.
+ for (Node* node = newHoverNode; node; node = node->parentOrShadowHostNode()) {
+ if (node->hasCapturingEventListeners(eventNames().mouseenterEvent)) {
+ hasCapturingMouseEnterListener = true;
+ break;
+ }
+ }
+ for (Node* node = oldHoverNode.get(); node; node = node->parentOrShadowHostNode()) {
+ if (node->hasCapturingEventListeners(eventNames().mouseleaveEvent)) {
+ hasCapturingMouseLeaveListener = true;
+ break;
+ }
+ }
+ }
+
if (oldHoverObj != newHoverObj) {
// If the old hovered node is not nil but it's renderer is, it was probably detached as part of the :hover style
// (for instance by setting display:none in the :hover pseudo-class). In this case, the old hovered element (and its ancestors)
@@ -5085,8 +5107,11 @@ void Document::updateHoverActiveState(const HitTestRequest& request, Element* in
}
size_t removeCount = nodesToRemoveFromChain.size();
- for (size_t i = 0; i < removeCount; ++i)
+ for (size_t i = 0; i < removeCount; ++i) {
nodesToRemoveFromChain[i]->setHovered(false);
+ if (event && (hasCapturingMouseLeaveListener || nodesToRemoveFromChain[i]->hasEventListeners(eventNames().mouseleaveEvent)))
+ nodesToRemoveFromChain[i]->dispatchMouseEvent(*event, eventNames().mouseleaveEvent, 0, newHoverNode);
+ }
bool sawCommonAncestor = false;
size_t addCount = nodesToAddToChain.size();
@@ -5096,8 +5121,11 @@ void Document::updateHoverActiveState(const HitTestRequest& request, Element* in
sawCommonAncestor = true;
if (allowActiveChanges)
nodesToAddToChain[i]->setActive(true);
- if (!sawCommonAncestor)
+ if (!sawCommonAncestor) {
nodesToAddToChain[i]->setHovered(true);
+ if (event && (hasCapturingMouseEnterListener || nodesToAddToChain[i]->hasEventListeners(eventNames().mouseenterEvent)))
esprehn 2013/07/08 18:13:02 This is not correct, I could add a listener inside
Mike West 2013/07/09 09:37:00 You're right; I didn't think of that case at all.
+ nodesToAddToChain[i]->dispatchMouseEvent(*event, eventNames().mouseenterEvent, 0, oldHoverNode.get());
+ }
}
updateStyleIfNeeded();

Powered by Google App Engine
This is Rietveld 408576698