Index: third_party/WebKit/Source/core/dom/Document.cpp |
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp |
index 68087f991ebb1d778611d24a272d02756d4bbcdf..e9341545c5784a2603fca850b165a063827c8168 100644 |
--- a/third_party/WebKit/Source/core/dom/Document.cpp |
+++ b/third_party/WebKit/Source/core/dom/Document.cpp |
@@ -2029,7 +2029,7 @@ void Document::updateStyleAndLayoutTree() { |
// have been detached (for example, by setting display:none in the :hover |
// style), schedule another mouseMove event to check if any other elements |
// ended up under the mouse pointer due to re-layout. |
- if (hoverNode() && !hoverNode()->layoutObject() && frame()) |
+ if (hoverElement() && hoverElement()->layoutObject() && frame()) |
frame()->eventHandler().dispatchFakeMouseMoveEventSoon(); |
if (m_focusedElement && !m_focusedElement->isFocusable()) |
@@ -2516,7 +2516,7 @@ void Document::shutdown() { |
MutationObserver::cleanSlotChangeList(*this); |
- m_hoverNode = nullptr; |
+ m_hoverElement = nullptr; |
m_activeHoverElement = nullptr; |
m_autofocusElement = nullptr; |
@@ -3917,8 +3917,8 @@ void Document::styleResolverMayHaveChanged() { |
} |
} |
-void Document::setHoverNode(Node* newHoverNode) { |
- m_hoverNode = newHoverNode; |
+void Document::setHoverElement(Element* newHoverElement) { |
+ m_hoverElement = newHoverElement; |
} |
void Document::setActiveHoverElement(Element* newActiveElement) { |
@@ -3945,18 +3945,17 @@ void Document::removeFocusedElementOfSubtree(Node* node, |
} |
void Document::hoveredNodeDetached(Element& element) { |
- if (!m_hoverNode) |
+ if (!m_hoverElement) |
return; |
- m_hoverNode->updateDistribution(); |
- if (element != m_hoverNode && |
- (!m_hoverNode->isTextNode() || |
- element != FlatTreeTraversal::parent(*m_hoverNode))) |
+ m_hoverElement->updateDistribution(); |
+ if (element != m_hoverElement) |
return; |
- m_hoverNode = FlatTreeTraversal::parent(element); |
- while (m_hoverNode && !m_hoverNode->layoutObject()) |
- m_hoverNode = FlatTreeTraversal::parent(*m_hoverNode); |
+ m_hoverElement = FlatTreeTraversal::parentElement(element); |
+ while (m_hoverElement && |
+ !(m_hoverElement->layoutObject() && m_hoverElement->isHovered())) |
+ m_hoverElement = FlatTreeTraversal::parentElement(*m_hoverElement); |
// If the mouse cursor is not visible, do not clear existing |
// hover effects on the ancestors of |element| and do not invoke |
@@ -6145,23 +6144,6 @@ void Document::setContextFeatures(ContextFeatures& features) { |
m_contextFeatures = &features; |
} |
-static LayoutObject* nearestCommonHoverAncestor(LayoutObject* obj1, |
- LayoutObject* obj2) { |
- if (!obj1 || !obj2) |
- return 0; |
- |
- for (LayoutObject* currObj1 = obj1; currObj1; |
- currObj1 = currObj1->hoverAncestor()) { |
- for (LayoutObject* currObj2 = obj2; currObj2; |
- currObj2 = currObj2->hoverAncestor()) { |
- if (currObj1 == currObj2) |
- return currObj1; |
- } |
- } |
- |
- return 0; |
-} |
- |
// TODO(mustaq) |request| parameter maybe a misuse of HitTestRequest in |
// updateHoverActiveState() since the function doesn't bother with hit-testing. |
void Document::updateHoverActiveState(const HitTestRequest& request, |
@@ -6224,85 +6206,61 @@ void Document::updateHoverActiveState(const HitTestRequest& request, |
bool allowActiveChanges = !oldActiveElement && activeHoverElement(); |
// If the mouse is down and if this is a mouse move event, we want to restrict |
- // changes in :hover/:active to only apply to elements that are in the :active |
- // chain that we froze at the time the mouse went down. |
+ // changes in :active to only apply to elements that are in the :active chain |
+ // that we froze at the time the mouse went down. |
bool mustBeInActiveChain = request.active() && request.move(); |
- Node* oldHoverNode = hoverNode(); |
+ Element* oldHoverElement = hoverElement(); |
// Check to see if the hovered node has changed. |
// If it hasn't, we do not need to do anything. |
- Node* newHoverNode = innerElementInDocument; |
- while (newHoverNode && !newHoverNode->layoutObject()) |
- newHoverNode = newHoverNode->parentOrShadowHostNode(); |
+ Element* newHoverElement = innerElementInDocument; |
+ while (newHoverElement && !newHoverElement->layoutObject()) { |
+ newHoverElement = |
+ LayoutTreeBuilderTraversal::parentElement(*newHoverElement); |
+ } |
+ |
+ DCHECK(!oldHoverElement || oldHoverElement->isConnected()); |
+ DCHECK(!oldHoverElement || oldHoverElement->isHovered()); |
// Update our current hover node. |
- setHoverNode(newHoverNode); |
- |
- // We have two different objects. Fetch their layoutObjects. |
- LayoutObject* oldHoverObj = |
- oldHoverNode ? oldHoverNode->layoutObject() : nullptr; |
- LayoutObject* newHoverObj = |
- newHoverNode ? newHoverNode->layoutObject() : nullptr; |
- |
- // Locate the common ancestor layout object for the two layoutObjects. |
- LayoutObject* ancestor = nearestCommonHoverAncestor(oldHoverObj, newHoverObj); |
- Node* ancestorNode(ancestor ? ancestor->node() : nullptr); |
- |
- HeapVector<Member<Node>, 32> nodesToRemoveFromChain; |
- HeapVector<Member<Node>, 32> nodesToAddToChain; |
- |
- if (oldHoverObj != newHoverObj) { |
- // If the old hovered node is not nil but it's layoutObject 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) must be updated, to ensure it's normal style |
- // is re-applied. |
- if (oldHoverNode && !oldHoverObj) { |
- for (Node& node : NodeTraversal::inclusiveAncestorsOf(*oldHoverNode)) { |
- if (!mustBeInActiveChain || |
- (node.isElementNode() && toElement(node).inActiveChain())) |
- nodesToRemoveFromChain.push_back(node); |
- } |
- } |
+ setHoverElement(newHoverElement); |
+ |
+ Node* ancestor = (oldHoverElement && newHoverElement) |
+ ? FlatTreeTraversal::commonAncestor(*oldHoverElement, |
+ *newHoverElement) |
+ : nullptr; |
+ HeapVector<Member<Element>, 32> elementsToRemoveFromChain; |
+ HeapVector<Member<Element>, 32> elementsToAddToChain; |
+ |
+ if (oldHoverElement != newHoverElement) { |
// The old hover path only needs to be cleared up to (and not including) the |
// common ancestor; |
- for (LayoutObject* curr = oldHoverObj; curr && curr != ancestor; |
- curr = curr->hoverAncestor()) { |
- if (curr->node() && !curr->isText() && |
- (!mustBeInActiveChain || curr->node()->inActiveChain())) |
- nodesToRemoveFromChain.push_back(curr->node()); |
- } |
- |
- // TODO(mustaq): The two loops above may push a single node twice into |
- // nodesToRemoveFromChain. There must be a better way. |
+ for (Element* curr = oldHoverElement; curr && curr != ancestor; |
+ curr = FlatTreeTraversal::parentElement(*curr)) |
+ elementsToRemoveFromChain.push_back(curr); |
} |
// Now set the hover state for our new object up to the root. |
- for (LayoutObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) { |
- if (curr->node() && !curr->isText() && |
- (!mustBeInActiveChain || curr->node()->inActiveChain())) |
- nodesToAddToChain.push_back(curr->node()); |
- } |
+ for (Element* curr = newHoverElement; curr; |
+ curr = FlatTreeTraversal::parentElement(*curr)) |
+ elementsToAddToChain.push_back(curr); |
- size_t removeCount = nodesToRemoveFromChain.size(); |
- for (size_t i = 0; i < removeCount; ++i) { |
- nodesToRemoveFromChain[i]->setHovered(false); |
- } |
+ for (Element* element : elementsToRemoveFromChain) |
+ element->setHovered(false); |
bool sawCommonAncestor = false; |
- size_t addCount = nodesToAddToChain.size(); |
- for (size_t i = 0; i < addCount; ++i) { |
+ for (Element* element : elementsToAddToChain) { |
// Elements past the common ancestor do not change hover state, but might |
// change active state. |
- if (ancestorNode && nodesToAddToChain[i] == ancestorNode) |
+ if (element == ancestor) |
sawCommonAncestor = true; |
- if (allowActiveChanges) |
- nodesToAddToChain[i]->setActive(true); |
- if (!sawCommonAncestor || nodesToAddToChain[i] == m_hoverNode) { |
- nodesToAddToChain[i]->setHovered(true); |
- } |
+ if (allowActiveChanges && |
+ (!mustBeInActiveChain || element->inActiveChain())) |
+ element->setActive(true); |
+ if (!sawCommonAncestor || element == m_hoverElement) |
+ element->setHovered(true); |
} |
} |
@@ -6557,7 +6515,7 @@ DEFINE_TRACE(Document) { |
visitor->trace(m_autofocusElement); |
visitor->trace(m_focusedElement); |
visitor->trace(m_sequentialFocusNavigationStartingPoint); |
- visitor->trace(m_hoverNode); |
+ visitor->trace(m_hoverElement); |
visitor->trace(m_activeHoverElement); |
visitor->trace(m_documentElement); |
visitor->trace(m_rootScrollerController); |