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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org) 5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012 Apple Inc. All r ights reserved. 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012 Apple Inc. All r ights reserved.
7 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/) 7 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/)
8 * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved. 8 * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved.
9 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 9 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
10 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved. 10 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
(...skipping 2877 matching lines...) Expand 10 before | Expand all | Expand 10 after
2888 // mousemove events before the first layout should not lead to a premature l ayout() 2888 // mousemove events before the first layout should not lead to a premature l ayout()
2889 // happening, which could show a flash of white. 2889 // happening, which could show a flash of white.
2890 // See also the similar code in EventHandler::hitTestResultAtPoint. 2890 // See also the similar code in EventHandler::hitTestResultAtPoint.
2891 if (!renderer() || !view() || !view()->didFirstLayout()) 2891 if (!renderer() || !view() || !view()->didFirstLayout())
2892 return MouseEventWithHitTestResults(event, HitTestResult(LayoutPoint())) ; 2892 return MouseEventWithHitTestResults(event, HitTestResult(LayoutPoint())) ;
2893 2893
2894 HitTestResult result(documentPoint); 2894 HitTestResult result(documentPoint);
2895 renderView()->hitTest(request, result); 2895 renderView()->hitTest(request, result);
2896 2896
2897 if (!request.readOnly()) 2897 if (!request.readOnly())
2898 updateHoverActiveState(request, result.innerElement()); 2898 updateHoverActiveState(request, result.innerElement(), &event);
2899 2899
2900 return MouseEventWithHitTestResults(event, result); 2900 return MouseEventWithHitTestResults(event, result);
2901 } 2901 }
2902 2902
2903 // DOM Section 1.1.1 2903 // DOM Section 1.1.1
2904 bool Document::childTypeAllowed(NodeType type) const 2904 bool Document::childTypeAllowed(NodeType type) const
2905 { 2905 {
2906 switch (type) { 2906 switch (type) {
2907 case ATTRIBUTE_NODE: 2907 case ATTRIBUTE_NODE:
2908 case CDATA_SECTION_NODE: 2908 case CDATA_SECTION_NODE:
(...skipping 2074 matching lines...) Expand 10 before | Expand all | Expand 10 after
4983 for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAnce stor()) { 4983 for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAnce stor()) {
4984 for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hover Ancestor()) { 4984 for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hover Ancestor()) {
4985 if (currObj1 == currObj2) 4985 if (currObj1 == currObj2)
4986 return currObj1; 4986 return currObj1;
4987 } 4987 }
4988 } 4988 }
4989 4989
4990 return 0; 4990 return 0;
4991 } 4991 }
4992 4992
4993 void Document::updateHoverActiveState(const HitTestRequest& request, Element* in nerElement) 4993 void Document::updateHoverActiveState(const HitTestRequest& request, Element* in nerElement, const PlatformMouseEvent* event)
4994 { 4994 {
4995 ASSERT(!request.readOnly()); 4995 ASSERT(!request.readOnly());
4996 4996
4997 Element* innerElementInDocument = innerElement; 4997 Element* innerElementInDocument = innerElement;
4998 while (innerElementInDocument && innerElementInDocument->document() != this) { 4998 while (innerElementInDocument && innerElementInDocument->document() != this) {
4999 innerElementInDocument->document()->updateHoverActiveState(request, inne rElementInDocument); 4999 innerElementInDocument->document()->updateHoverActiveState(request, inne rElementInDocument, event);
5000 innerElementInDocument = innerElementInDocument->document()->ownerElemen t(); 5000 innerElementInDocument = innerElementInDocument->document()->ownerElemen t();
5001 } 5001 }
5002 5002
5003 Element* oldActiveElement = activeElement(); 5003 Element* oldActiveElement = activeElement();
5004 if (oldActiveElement && !request.active()) { 5004 if (oldActiveElement && !request.active()) {
5005 // We are clearing the :active chain because the mouse has been released . 5005 // We are clearing the :active chain because the mouse has been released .
5006 for (RenderObject* curr = oldActiveElement->renderer(); curr; curr = cur r->parent()) { 5006 for (RenderObject* curr = oldActiveElement->renderer(); curr; curr = cur r->parent()) {
5007 if (curr->node()) { 5007 if (curr->node()) {
5008 ASSERT(!curr->node()->isTextNode()); 5008 ASSERT(!curr->node()->isTextNode());
5009 curr->node()->setActive(false); 5009 curr->node()->setActive(false);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
5052 // We have two different objects. Fetch their renderers. 5052 // We have two different objects. Fetch their renderers.
5053 RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0; 5053 RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
5054 RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0; 5054 RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
5055 5055
5056 // Locate the common ancestor render object for the two renderers. 5056 // Locate the common ancestor render object for the two renderers.
5057 RenderObject* ancestor = nearestCommonHoverAncestor(oldHoverObj, newHoverObj ); 5057 RenderObject* ancestor = nearestCommonHoverAncestor(oldHoverObj, newHoverObj );
5058 5058
5059 Vector<RefPtr<Node>, 32> nodesToRemoveFromChain; 5059 Vector<RefPtr<Node>, 32> nodesToRemoveFromChain;
5060 Vector<RefPtr<Node>, 32> nodesToAddToChain; 5060 Vector<RefPtr<Node>, 32> nodesToAddToChain;
5061 5061
5062 // mouseenter and mouseleave events do not bubble, so they are dispatched if f 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
5063 // event handler on an ancestor or a normal event handler on the element its elf. This special
5064 // handling is necessary to avoid O(n^2) capturing event handler checks.
5065 bool hasCapturingMouseEnterListener = false;
5066 bool hasCapturingMouseLeaveListener = false;
5067 if (event && newHoverNode != oldHoverNode.get()) {
5068 // Walk up the newly hovered node's ancestor tree for 'mouseenter' event s, and the previously
5069 // hovered node's ancestor tree for 'mouseleave' events.
5070 for (Node* node = newHoverNode; node; node = node->parentOrShadowHostNod e()) {
5071 if (node->hasCapturingEventListeners(eventNames().mouseenterEvent)) {
5072 hasCapturingMouseEnterListener = true;
5073 break;
5074 }
5075 }
5076 for (Node* node = oldHoverNode.get(); node; node = node->parentOrShadowH ostNode()) {
5077 if (node->hasCapturingEventListeners(eventNames().mouseleaveEvent)) {
5078 hasCapturingMouseLeaveListener = true;
5079 break;
5080 }
5081 }
5082 }
5083
5062 if (oldHoverObj != newHoverObj) { 5084 if (oldHoverObj != newHoverObj) {
5063 // If the old hovered node is not nil but it's renderer is, it was proba bly detached as part of the :hover style 5085 // If the old hovered node is not nil but it's renderer is, it was proba bly detached as part of the :hover style
5064 // (for instance by setting display:none in the :hover pseudo-class). In this case, the old hovered element (and its ancestors) 5086 // (for instance by setting display:none in the :hover pseudo-class). In this case, the old hovered element (and its ancestors)
5065 // must be updated, to ensure it's normal style is re-applied. 5087 // must be updated, to ensure it's normal style is re-applied.
5066 if (oldHoverNode && !oldHoverObj) { 5088 if (oldHoverNode && !oldHoverObj) {
5067 for (Node* node = oldHoverNode.get(); node; node = node->parentNode( )) { 5089 for (Node* node = oldHoverNode.get(); node; node = node->parentNode( )) {
5068 if (!mustBeInActiveChain || (node->isElementNode() && toElement( node)->inActiveChain())) 5090 if (!mustBeInActiveChain || (node->isElementNode() && toElement( node)->inActiveChain()))
5069 nodesToRemoveFromChain.append(node); 5091 nodesToRemoveFromChain.append(node);
5070 } 5092 }
5071 5093
5072 } 5094 }
5073 5095
5074 // The old hover path only needs to be cleared up to (and not including) the common ancestor; 5096 // The old hover path only needs to be cleared up to (and not including) the common ancestor;
5075 for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) { 5097 for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
5076 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr ->node()->inActiveChain())) 5098 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr ->node()->inActiveChain()))
5077 nodesToRemoveFromChain.append(curr->node()); 5099 nodesToRemoveFromChain.append(curr->node());
5078 } 5100 }
5079 } 5101 }
5080 5102
5081 // Now set the hover state for our new object up to the root. 5103 // Now set the hover state for our new object up to the root.
5082 for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) { 5104 for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
5083 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->no de()->inActiveChain())) 5105 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->no de()->inActiveChain()))
5084 nodesToAddToChain.append(curr->node()); 5106 nodesToAddToChain.append(curr->node());
5085 } 5107 }
5086 5108
5087 size_t removeCount = nodesToRemoveFromChain.size(); 5109 size_t removeCount = nodesToRemoveFromChain.size();
5088 for (size_t i = 0; i < removeCount; ++i) 5110 for (size_t i = 0; i < removeCount; ++i) {
5089 nodesToRemoveFromChain[i]->setHovered(false); 5111 nodesToRemoveFromChain[i]->setHovered(false);
5112 if (event && (hasCapturingMouseLeaveListener || nodesToRemoveFromChain[i ]->hasEventListeners(eventNames().mouseleaveEvent)))
5113 nodesToRemoveFromChain[i]->dispatchMouseEvent(*event, eventNames().m ouseleaveEvent, 0, newHoverNode);
5114 }
5090 5115
5091 bool sawCommonAncestor = false; 5116 bool sawCommonAncestor = false;
5092 size_t addCount = nodesToAddToChain.size(); 5117 size_t addCount = nodesToAddToChain.size();
5093 for (size_t i = 0; i < addCount; ++i) { 5118 for (size_t i = 0; i < addCount; ++i) {
5094 // Elements past the common ancestor do not change hover state, but migh t change active state. 5119 // Elements past the common ancestor do not change hover state, but migh t change active state.
5095 if (ancestor && nodesToAddToChain[i] == ancestor->node()) 5120 if (ancestor && nodesToAddToChain[i] == ancestor->node())
5096 sawCommonAncestor = true; 5121 sawCommonAncestor = true;
5097 if (allowActiveChanges) 5122 if (allowActiveChanges)
5098 nodesToAddToChain[i]->setActive(true); 5123 nodesToAddToChain[i]->setActive(true);
5099 if (!sawCommonAncestor) 5124 if (!sawCommonAncestor) {
5100 nodesToAddToChain[i]->setHovered(true); 5125 nodesToAddToChain[i]->setHovered(true);
5126 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.
5127 nodesToAddToChain[i]->dispatchMouseEvent(*event, eventNames().mo useenterEvent, 0, oldHoverNode.get());
5128 }
5101 } 5129 }
5102 5130
5103 updateStyleIfNeeded(); 5131 updateStyleIfNeeded();
5104 } 5132 }
5105 5133
5106 void Document::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const 5134 void Document::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
5107 { 5135 {
5108 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM); 5136 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
5109 ContainerNode::reportMemoryUsage(memoryObjectInfo); 5137 ContainerNode::reportMemoryUsage(memoryObjectInfo);
5110 TreeScope::reportMemoryUsage(memoryObjectInfo); 5138 TreeScope::reportMemoryUsage(memoryObjectInfo);
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
5249 { 5277 {
5250 return DocumentLifecycleNotifier::create(this); 5278 return DocumentLifecycleNotifier::create(this);
5251 } 5279 }
5252 5280
5253 DocumentLifecycleNotifier* Document::lifecycleNotifier() 5281 DocumentLifecycleNotifier* Document::lifecycleNotifier()
5254 { 5282 {
5255 return static_cast<DocumentLifecycleNotifier*>(ScriptExecutionContext::lifec ycleNotifier()); 5283 return static_cast<DocumentLifecycleNotifier*>(ScriptExecutionContext::lifec ycleNotifier());
5256 } 5284 }
5257 5285
5258 } // namespace WebCore 5286 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698