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

Side by Side Diff: Source/core/dom/Document.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) 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 3100 matching lines...) Expand 10 before | Expand all | Expand 10 after
3111 // mousemove events before the first layout should not lead to a premature l ayout() 3111 // mousemove events before the first layout should not lead to a premature l ayout()
3112 // happening, which could show a flash of white. 3112 // happening, which could show a flash of white.
3113 // See also the similar code in EventHandler::hitTestResultAtPoint. 3113 // See also the similar code in EventHandler::hitTestResultAtPoint.
3114 if (!layoutView() || !view() || !view()->didFirstLayout()) 3114 if (!layoutView() || !view() || !view()->didFirstLayout())
3115 return MouseEventWithHitTestResults(event, HitTestResult(LayoutPoint())) ; 3115 return MouseEventWithHitTestResults(event, HitTestResult(LayoutPoint())) ;
3116 3116
3117 HitTestResult result(documentPoint); 3117 HitTestResult result(documentPoint);
3118 layoutView()->hitTest(request, result); 3118 layoutView()->hitTest(request, result);
3119 3119
3120 if (!request.readOnly()) 3120 if (!request.readOnly())
3121 updateHoverActiveState(request, result.innerElement(), &event); 3121 updateHoverActiveState(request, result.innerElement());
3122 3122
3123 return MouseEventWithHitTestResults(event, result); 3123 return MouseEventWithHitTestResults(event, result);
3124 } 3124 }
3125 3125
3126 // DOM Section 1.1.1 3126 // DOM Section 1.1.1
3127 bool Document::childTypeAllowed(NodeType type) const 3127 bool Document::childTypeAllowed(NodeType type) const
3128 { 3128 {
3129 switch (type) { 3129 switch (type) {
3130 case ATTRIBUTE_NODE: 3130 case ATTRIBUTE_NODE:
3131 case CDATA_SECTION_NODE: 3131 case CDATA_SECTION_NODE:
(...skipping 2100 matching lines...) Expand 10 before | Expand all | Expand 10 after
5232 for (LayoutObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAnce stor()) { 5232 for (LayoutObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAnce stor()) {
5233 for (LayoutObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hover Ancestor()) { 5233 for (LayoutObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hover Ancestor()) {
5234 if (currObj1 == currObj2) 5234 if (currObj1 == currObj2)
5235 return currObj1; 5235 return currObj1;
5236 } 5236 }
5237 } 5237 }
5238 5238
5239 return 0; 5239 return 0;
5240 } 5240 }
5241 5241
5242 void Document::updateHoverActiveState(const HitTestRequest& request, Element* in nerElement, const PlatformMouseEvent* event) 5242 void Document::updateHoverActiveState(const HitTestRequest& request, Element* in nerElement)
5243 { 5243 {
5244 ASSERT(!request.readOnly()); 5244 ASSERT(!request.readOnly());
5245 5245
5246 if (request.active() && m_frame) 5246 if (request.active() && m_frame)
5247 m_frame->eventHandler().notifyElementActivated(); 5247 m_frame->eventHandler().notifyElementActivated();
5248 5248
5249 Element* innerElementInDocument = innerElement; 5249 Element* innerElementInDocument = innerElement;
5250 while (innerElementInDocument && innerElementInDocument->document() != this) { 5250 while (innerElementInDocument && innerElementInDocument->document() != this) {
5251 innerElementInDocument->document().updateHoverActiveState(request, inner ElementInDocument, event); 5251 innerElementInDocument->document().updateHoverActiveState(request, inner ElementInDocument);
5252 innerElementInDocument = innerElementInDocument->document().ownerElement (); 5252 innerElementInDocument = innerElementInDocument->document().ownerElement ();
5253 } 5253 }
5254 5254
5255 Element* oldActiveElement = activeHoverElement(); 5255 Element* oldActiveElement = activeHoverElement();
5256 if (oldActiveElement && !request.active()) { 5256 if (oldActiveElement && !request.active()) {
5257 // The oldActiveElement renderer is null, dropped on :active by setting display: none, 5257 // The oldActiveElement renderer is null, dropped on :active by setting display: none,
5258 // for instance. We still need to clear the ActiveChain as the mouse is released. 5258 // for instance. We still need to clear the ActiveChain as the mouse is released.
5259 for (Node* node = oldActiveElement; node; node = NodeRenderingTraversal: :parent(*node)) { 5259 for (Node* node = oldActiveElement; node; node = NodeRenderingTraversal: :parent(*node)) {
5260 ASSERT(!node->isTextNode()); 5260 ASSERT(!node->isTextNode());
5261 node->setActive(false); 5261 node->setActive(false);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
5315 nodesToRemoveFromChain.append(node); 5315 nodesToRemoveFromChain.append(node);
5316 } 5316 }
5317 5317
5318 } 5318 }
5319 5319
5320 // The old hover path only needs to be cleared up to (and not including) the common ancestor; 5320 // The old hover path only needs to be cleared up to (and not including) the common ancestor;
5321 for (LayoutObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) { 5321 for (LayoutObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
5322 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr ->node()->inActiveChain())) 5322 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr ->node()->inActiveChain()))
5323 nodesToRemoveFromChain.append(curr->node()); 5323 nodesToRemoveFromChain.append(curr->node());
5324 } 5324 }
5325
5326 // FIXME: It seems the two loops above can push a single node twice into nodesToRemoveFromChain. There must be a better way.
Mike West 2015/03/31 11:45:33 Nit: Blink is now writing these as "// TODO(mustaq
mustaq 2015/03/31 14:08:31 Done.
5325 } 5327 }
5326 5328
5327 // Now set the hover state for our new object up to the root. 5329 // Now set the hover state for our new object up to the root.
5328 for (LayoutObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) { 5330 for (LayoutObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
5329 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->no de()->inActiveChain())) 5331 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->no de()->inActiveChain()))
5330 nodesToAddToChain.append(curr->node()); 5332 nodesToAddToChain.append(curr->node());
5331 } 5333 }
5332 5334
5333 // mouseenter and mouseleave events do not bubble, so they are dispatched if f there is a capturing
5334 // event handler on an ancestor or a normal event handler on the element its elf. This special
5335 // handling is necessary to avoid O(n^2) capturing event handler checks. We' ll check the previously
5336 // hovered node's ancestor tree for 'mouseleave' handlers here, then check t he newly hovered node's
5337 // ancestor tree for 'mouseenter' handlers after dispatching the 'mouseleave ' events (as the handler
5338 // for 'mouseleave' might set a capturing 'mouseenter' handler, odd as that might be).
5339 bool ancestorHasCapturingMouseleaveListener = false;
5340 if (event && newHoverNode != oldHoverNode.get()) {
5341 for (Node* node = oldHoverNode.get(); node; node = node->parentOrShadowH ostNode()) {
5342 if (node->hasCapturingEventListeners(EventTypeNames::mouseleave)) {
5343 ancestorHasCapturingMouseleaveListener = true;
5344 break;
5345 }
5346 }
5347 }
5348
5349 size_t removeCount = nodesToRemoveFromChain.size(); 5335 size_t removeCount = nodesToRemoveFromChain.size();
5350 for (size_t i = 0; i < removeCount; ++i) { 5336 for (size_t i = 0; i < removeCount; ++i) {
5351 nodesToRemoveFromChain[i]->setHovered(false); 5337 nodesToRemoveFromChain[i]->setHovered(false);
5352 if (event && (ancestorHasCapturingMouseleaveListener || nodesToRemoveFro mChain[i]->hasEventListeners(EventTypeNames::mouseleave)))
5353 nodesToRemoveFromChain[i]->dispatchMouseEvent(*event, EventTypeNames ::mouseleave, 0, newHoverNode);
5354 }
5355
5356 bool ancestorHasCapturingMouseenterListener = false;
5357 if (event && newHoverNode != oldHoverNode.get()) {
5358 for (Node* node = newHoverNode; node; node = node->parentOrShadowHostNod e()) {
5359 if (node->hasCapturingEventListeners(EventTypeNames::mouseenter)) {
5360 ancestorHasCapturingMouseenterListener = true;
5361 break;
5362 }
5363 }
5364 } 5338 }
5365 5339
5366 bool sawCommonAncestor = false; 5340 bool sawCommonAncestor = false;
5367 size_t addCount = nodesToAddToChain.size(); 5341 size_t addCount = nodesToAddToChain.size();
5368 for (size_t i = 0; i < addCount; ++i) { 5342 for (size_t i = 0; i < addCount; ++i) {
5369 // Elements past the common ancestor do not change hover state, but migh t change active state. 5343 // Elements past the common ancestor do not change hover state, but migh t change active state.
5370 if (ancestorNode && nodesToAddToChain[i] == ancestorNode) 5344 if (ancestorNode && nodesToAddToChain[i] == ancestorNode)
5371 sawCommonAncestor = true; 5345 sawCommonAncestor = true;
5372 if (allowActiveChanges) 5346 if (allowActiveChanges)
5373 nodesToAddToChain[i]->setActive(true); 5347 nodesToAddToChain[i]->setActive(true);
5374 if (!sawCommonAncestor) { 5348 if (!sawCommonAncestor) {
5375 nodesToAddToChain[i]->setHovered(true); 5349 nodesToAddToChain[i]->setHovered(true);
5376 if (event && (ancestorHasCapturingMouseenterListener || nodesToAddTo Chain[i]->hasEventListeners(EventTypeNames::mouseenter)))
5377 nodesToAddToChain[i]->dispatchMouseEvent(*event, EventTypeNames: :mouseenter, 0, oldHoverNode.get());
5378 } 5350 }
5379 } 5351 }
5380 } 5352 }
5381 5353
5382 bool Document::haveStylesheetsLoaded() const 5354 bool Document::haveStylesheetsLoaded() const
5383 { 5355 {
5384 return m_styleEngine->haveStylesheetsLoaded(); 5356 return m_styleEngine->haveStylesheetsLoaded();
5385 } 5357 }
5386 5358
5387 Locale& Document::getCachedLocale(const AtomicString& locale) 5359 Locale& Document::getCachedLocale(const AtomicString& locale)
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after
5756 #ifndef NDEBUG 5728 #ifndef NDEBUG
5757 using namespace blink; 5729 using namespace blink;
5758 void showLiveDocumentInstances() 5730 void showLiveDocumentInstances()
5759 { 5731 {
5760 WeakDocumentSet& set = liveDocumentSet(); 5732 WeakDocumentSet& set = liveDocumentSet();
5761 fprintf(stderr, "There are %u documents currently alive:\n", set.size()); 5733 fprintf(stderr, "There are %u documents currently alive:\n", set.size());
5762 for (Document* document : set) 5734 for (Document* document : set)
5763 fprintf(stderr, "- Document %p URL: %s\n", document, document->url().str ing().utf8().data()); 5735 fprintf(stderr, "- Document %p URL: %s\n", document, document->url().str ing().utf8().data());
5764 } 5736 }
5765 #endif 5737 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698