| 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);
|
|
|