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

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

Issue 2787943002: [WIP] Use the flat tree for hover handling.
Patch Set: Created 3 years, 9 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: 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);
« no previous file with comments | « third_party/WebKit/Source/core/dom/Document.h ('k') | third_party/WebKit/Source/core/input/EventHandler.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698