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

Side by Side Diff: third_party/WebKit/Source/core/dom/Document.cpp

Issue 2787943002: [WIP] Use the flat tree for hover handling.
Patch Set: Created 3 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 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012 Apple Inc. All
7 * rights reserved. 7 * rights reserved.
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
9 * (http://www.torchmobile.com/) 9 * (http://www.torchmobile.com/)
10 * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved. 10 * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved.
(...skipping 2011 matching lines...) Expand 10 before | Expand all | Expand 10 after
2022 // SecurityOrigin. 2022 // SecurityOrigin.
2023 2023
2024 updateStyle(); 2024 updateStyle();
2025 2025
2026 notifyLayoutTreeOfSubtreeChanges(); 2026 notifyLayoutTreeOfSubtreeChanges();
2027 2027
2028 // As a result of the style recalculation, the currently hovered element might 2028 // As a result of the style recalculation, the currently hovered element might
2029 // have been detached (for example, by setting display:none in the :hover 2029 // have been detached (for example, by setting display:none in the :hover
2030 // style), schedule another mouseMove event to check if any other elements 2030 // style), schedule another mouseMove event to check if any other elements
2031 // ended up under the mouse pointer due to re-layout. 2031 // ended up under the mouse pointer due to re-layout.
2032 if (hoverNode() && !hoverNode()->layoutObject() && frame()) 2032 if (hoverElement() && hoverElement()->layoutObject() && frame())
2033 frame()->eventHandler().dispatchFakeMouseMoveEventSoon(); 2033 frame()->eventHandler().dispatchFakeMouseMoveEventSoon();
2034 2034
2035 if (m_focusedElement && !m_focusedElement->isFocusable()) 2035 if (m_focusedElement && !m_focusedElement->isFocusable())
2036 clearFocusedElementSoon(); 2036 clearFocusedElementSoon();
2037 layoutViewItem().clearHitTestCache(); 2037 layoutViewItem().clearHitTestCache();
2038 2038
2039 DCHECK(!DocumentAnimations::needsAnimationTimingUpdate(*this)); 2039 DCHECK(!DocumentAnimations::needsAnimationTimingUpdate(*this));
2040 2040
2041 unsigned elementCount = 2041 unsigned elementCount =
2042 styleEngine().styleForElementCount() - startElementCount; 2042 styleEngine().styleForElementCount() - startElementCount;
(...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after
2509 m_domWindow->clearEventQueue(); 2509 m_domWindow->clearEventQueue();
2510 2510
2511 if (m_layoutView) 2511 if (m_layoutView)
2512 m_layoutView->setIsInWindow(false); 2512 m_layoutView->setIsInWindow(false);
2513 2513
2514 if (registrationContext()) 2514 if (registrationContext())
2515 registrationContext()->documentWasDetached(); 2515 registrationContext()->documentWasDetached();
2516 2516
2517 MutationObserver::cleanSlotChangeList(*this); 2517 MutationObserver::cleanSlotChangeList(*this);
2518 2518
2519 m_hoverNode = nullptr; 2519 m_hoverElement = nullptr;
2520 m_activeHoverElement = nullptr; 2520 m_activeHoverElement = nullptr;
2521 m_autofocusElement = nullptr; 2521 m_autofocusElement = nullptr;
2522 2522
2523 if (m_focusedElement.get()) { 2523 if (m_focusedElement.get()) {
2524 Element* oldFocusedElement = m_focusedElement; 2524 Element* oldFocusedElement = m_focusedElement;
2525 m_focusedElement = nullptr; 2525 m_focusedElement = nullptr;
2526 if (page()) 2526 if (page())
2527 page()->chromeClient().focusedNodeChanged(oldFocusedElement, nullptr); 2527 page()->chromeClient().focusedNodeChanged(oldFocusedElement, nullptr);
2528 } 2528 }
2529 m_sequentialFocusNavigationStartingPoint = nullptr; 2529 m_sequentialFocusNavigationStartingPoint = nullptr;
(...skipping 1380 matching lines...) Expand 10 before | Expand all | Expand 10 after
3910 // We need to manually repaint because we avoid doing all repaints in layout 3910 // We need to manually repaint because we avoid doing all repaints in layout
3911 // or style recalc while sheets are still loading to avoid FOUC. 3911 // or style recalc while sheets are still loading to avoid FOUC.
3912 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets; 3912 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets;
3913 3913
3914 DCHECK(!layoutViewItem().isNull() || importsController()); 3914 DCHECK(!layoutViewItem().isNull() || importsController());
3915 if (!layoutViewItem().isNull()) 3915 if (!layoutViewItem().isNull())
3916 layoutViewItem().invalidatePaintForViewAndCompositedLayers(); 3916 layoutViewItem().invalidatePaintForViewAndCompositedLayers();
3917 } 3917 }
3918 } 3918 }
3919 3919
3920 void Document::setHoverNode(Node* newHoverNode) { 3920 void Document::setHoverElement(Element* newHoverElement) {
3921 m_hoverNode = newHoverNode; 3921 m_hoverElement = newHoverElement;
3922 } 3922 }
3923 3923
3924 void Document::setActiveHoverElement(Element* newActiveElement) { 3924 void Document::setActiveHoverElement(Element* newActiveElement) {
3925 if (!newActiveElement) { 3925 if (!newActiveElement) {
3926 m_activeHoverElement.clear(); 3926 m_activeHoverElement.clear();
3927 return; 3927 return;
3928 } 3928 }
3929 3929
3930 m_activeHoverElement = newActiveElement; 3930 m_activeHoverElement = newActiveElement;
3931 } 3931 }
3932 3932
3933 void Document::removeFocusedElementOfSubtree(Node* node, 3933 void Document::removeFocusedElementOfSubtree(Node* node,
3934 bool amongChildrenOnly) { 3934 bool amongChildrenOnly) {
3935 if (!m_focusedElement) 3935 if (!m_focusedElement)
3936 return; 3936 return;
3937 3937
3938 // We can't be focused if we're not in the document. 3938 // We can't be focused if we're not in the document.
3939 if (!node->isConnected()) 3939 if (!node->isConnected())
3940 return; 3940 return;
3941 bool contains = 3941 bool contains =
3942 node->isShadowIncludingInclusiveAncestorOf(m_focusedElement.get()); 3942 node->isShadowIncludingInclusiveAncestorOf(m_focusedElement.get());
3943 if (contains && (m_focusedElement != node || !amongChildrenOnly)) 3943 if (contains && (m_focusedElement != node || !amongChildrenOnly))
3944 clearFocusedElement(); 3944 clearFocusedElement();
3945 } 3945 }
3946 3946
3947 void Document::hoveredNodeDetached(Element& element) { 3947 void Document::hoveredNodeDetached(Element& element) {
3948 if (!m_hoverNode) 3948 if (!m_hoverElement)
3949 return; 3949 return;
3950 3950
3951 m_hoverNode->updateDistribution(); 3951 m_hoverElement->updateDistribution();
3952 if (element != m_hoverNode && 3952 if (element != m_hoverElement)
3953 (!m_hoverNode->isTextNode() ||
3954 element != FlatTreeTraversal::parent(*m_hoverNode)))
3955 return; 3953 return;
3956 3954
3957 m_hoverNode = FlatTreeTraversal::parent(element); 3955 m_hoverElement = FlatTreeTraversal::parentElement(element);
3958 while (m_hoverNode && !m_hoverNode->layoutObject()) 3956 while (m_hoverElement &&
3959 m_hoverNode = FlatTreeTraversal::parent(*m_hoverNode); 3957 !(m_hoverElement->layoutObject() && m_hoverElement->isHovered()))
3958 m_hoverElement = FlatTreeTraversal::parentElement(*m_hoverElement);
3960 3959
3961 // If the mouse cursor is not visible, do not clear existing 3960 // If the mouse cursor is not visible, do not clear existing
3962 // hover effects on the ancestors of |element| and do not invoke 3961 // hover effects on the ancestors of |element| and do not invoke
3963 // new hover effects on any other element. 3962 // new hover effects on any other element.
3964 if (!page()->isCursorVisible()) 3963 if (!page()->isCursorVisible())
3965 return; 3964 return;
3966 3965
3967 if (frame()) 3966 if (frame())
3968 frame()->eventHandler().scheduleHoverStateUpdate(); 3967 frame()->eventHandler().scheduleHoverStateUpdate();
3969 } 3968 }
(...skipping 2168 matching lines...) Expand 10 before | Expand all | Expand 10 after
6138 !m_snapCoordinator) 6137 !m_snapCoordinator)
6139 m_snapCoordinator = SnapCoordinator::create(); 6138 m_snapCoordinator = SnapCoordinator::create();
6140 6139
6141 return m_snapCoordinator.get(); 6140 return m_snapCoordinator.get();
6142 } 6141 }
6143 6142
6144 void Document::setContextFeatures(ContextFeatures& features) { 6143 void Document::setContextFeatures(ContextFeatures& features) {
6145 m_contextFeatures = &features; 6144 m_contextFeatures = &features;
6146 } 6145 }
6147 6146
6148 static LayoutObject* nearestCommonHoverAncestor(LayoutObject* obj1,
6149 LayoutObject* obj2) {
6150 if (!obj1 || !obj2)
6151 return 0;
6152
6153 for (LayoutObject* currObj1 = obj1; currObj1;
6154 currObj1 = currObj1->hoverAncestor()) {
6155 for (LayoutObject* currObj2 = obj2; currObj2;
6156 currObj2 = currObj2->hoverAncestor()) {
6157 if (currObj1 == currObj2)
6158 return currObj1;
6159 }
6160 }
6161
6162 return 0;
6163 }
6164
6165 // TODO(mustaq) |request| parameter maybe a misuse of HitTestRequest in 6147 // TODO(mustaq) |request| parameter maybe a misuse of HitTestRequest in
6166 // updateHoverActiveState() since the function doesn't bother with hit-testing. 6148 // updateHoverActiveState() since the function doesn't bother with hit-testing.
6167 void Document::updateHoverActiveState(const HitTestRequest& request, 6149 void Document::updateHoverActiveState(const HitTestRequest& request,
6168 Element* innerElement, 6150 Element* innerElement,
6169 Scrollbar* hitScrollbar) { 6151 Scrollbar* hitScrollbar) {
6170 DCHECK(!request.readOnly()); 6152 DCHECK(!request.readOnly());
6171 6153
6172 if (request.active() && m_frame) 6154 if (request.active() && m_frame)
6173 m_frame->eventHandler().notifyElementActivated(); 6155 m_frame->eventHandler().notifyElementActivated();
6174 6156
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
6217 m_userActionElements.setInActiveChain(node, true); 6199 m_userActionElements.setInActiveChain(node, true);
6218 } 6200 }
6219 setActiveHoverElement(newActiveElement); 6201 setActiveHoverElement(newActiveElement);
6220 } 6202 }
6221 } 6203 }
6222 // If the mouse has just been pressed, set :active on the chain. Those (and 6204 // If the mouse has just been pressed, set :active on the chain. Those (and
6223 // only those) nodes should remain :active until the mouse is released. 6205 // only those) nodes should remain :active until the mouse is released.
6224 bool allowActiveChanges = !oldActiveElement && activeHoverElement(); 6206 bool allowActiveChanges = !oldActiveElement && activeHoverElement();
6225 6207
6226 // If the mouse is down and if this is a mouse move event, we want to restrict 6208 // If the mouse is down and if this is a mouse move event, we want to restrict
6227 // changes in :hover/:active to only apply to elements that are in the :active 6209 // changes in :active to only apply to elements that are in the :active chain
6228 // chain that we froze at the time the mouse went down. 6210 // that we froze at the time the mouse went down.
6229 bool mustBeInActiveChain = request.active() && request.move(); 6211 bool mustBeInActiveChain = request.active() && request.move();
6230 6212
6231 Node* oldHoverNode = hoverNode(); 6213 Element* oldHoverElement = hoverElement();
6232 6214
6233 // Check to see if the hovered node has changed. 6215 // Check to see if the hovered node has changed.
6234 // If it hasn't, we do not need to do anything. 6216 // If it hasn't, we do not need to do anything.
6235 Node* newHoverNode = innerElementInDocument; 6217 Element* newHoverElement = innerElementInDocument;
6236 while (newHoverNode && !newHoverNode->layoutObject()) 6218 while (newHoverElement && !newHoverElement->layoutObject()) {
6237 newHoverNode = newHoverNode->parentOrShadowHostNode(); 6219 newHoverElement =
6220 LayoutTreeBuilderTraversal::parentElement(*newHoverElement);
6221 }
6222
6223 DCHECK(!oldHoverElement || oldHoverElement->isConnected());
6224 DCHECK(!oldHoverElement || oldHoverElement->isHovered());
6238 6225
6239 // Update our current hover node. 6226 // Update our current hover node.
6240 setHoverNode(newHoverNode); 6227 setHoverElement(newHoverElement);
6241 6228
6242 // We have two different objects. Fetch their layoutObjects. 6229 Node* ancestor = (oldHoverElement && newHoverElement)
6243 LayoutObject* oldHoverObj = 6230 ? FlatTreeTraversal::commonAncestor(*oldHoverElement,
6244 oldHoverNode ? oldHoverNode->layoutObject() : nullptr; 6231 *newHoverElement)
6245 LayoutObject* newHoverObj = 6232 : nullptr;
6246 newHoverNode ? newHoverNode->layoutObject() : nullptr;
6247 6233
6248 // Locate the common ancestor layout object for the two layoutObjects. 6234 HeapVector<Member<Element>, 32> elementsToRemoveFromChain;
6249 LayoutObject* ancestor = nearestCommonHoverAncestor(oldHoverObj, newHoverObj); 6235 HeapVector<Member<Element>, 32> elementsToAddToChain;
6250 Node* ancestorNode(ancestor ? ancestor->node() : nullptr);
6251 6236
6252 HeapVector<Member<Node>, 32> nodesToRemoveFromChain; 6237 if (oldHoverElement != newHoverElement) {
6253 HeapVector<Member<Node>, 32> nodesToAddToChain;
6254
6255 if (oldHoverObj != newHoverObj) {
6256 // If the old hovered node is not nil but it's layoutObject is, it was
6257 // probably detached as part of the :hover style (for instance by setting
6258 // display:none in the :hover pseudo-class). In this case, the old hovered
6259 // element (and its ancestors) must be updated, to ensure it's normal style
6260 // is re-applied.
6261 if (oldHoverNode && !oldHoverObj) {
6262 for (Node& node : NodeTraversal::inclusiveAncestorsOf(*oldHoverNode)) {
6263 if (!mustBeInActiveChain ||
6264 (node.isElementNode() && toElement(node).inActiveChain()))
6265 nodesToRemoveFromChain.push_back(node);
6266 }
6267 }
6268
6269 // The old hover path only needs to be cleared up to (and not including) the 6238 // The old hover path only needs to be cleared up to (and not including) the
6270 // common ancestor; 6239 // common ancestor;
6271 for (LayoutObject* curr = oldHoverObj; curr && curr != ancestor; 6240 for (Element* curr = oldHoverElement; curr && curr != ancestor;
6272 curr = curr->hoverAncestor()) { 6241 curr = FlatTreeTraversal::parentElement(*curr))
6273 if (curr->node() && !curr->isText() && 6242 elementsToRemoveFromChain.push_back(curr);
6274 (!mustBeInActiveChain || curr->node()->inActiveChain()))
6275 nodesToRemoveFromChain.push_back(curr->node());
6276 }
6277
6278 // TODO(mustaq): The two loops above may push a single node twice into
6279 // nodesToRemoveFromChain. There must be a better way.
6280 } 6243 }
6281 6244
6282 // Now set the hover state for our new object up to the root. 6245 // Now set the hover state for our new object up to the root.
6283 for (LayoutObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) { 6246 for (Element* curr = newHoverElement; curr;
6284 if (curr->node() && !curr->isText() && 6247 curr = FlatTreeTraversal::parentElement(*curr))
6285 (!mustBeInActiveChain || curr->node()->inActiveChain())) 6248 elementsToAddToChain.push_back(curr);
6286 nodesToAddToChain.push_back(curr->node());
6287 }
6288 6249
6289 size_t removeCount = nodesToRemoveFromChain.size(); 6250 for (Element* element : elementsToRemoveFromChain)
6290 for (size_t i = 0; i < removeCount; ++i) { 6251 element->setHovered(false);
6291 nodesToRemoveFromChain[i]->setHovered(false);
6292 }
6293 6252
6294 bool sawCommonAncestor = false; 6253 bool sawCommonAncestor = false;
6295 size_t addCount = nodesToAddToChain.size(); 6254 for (Element* element : elementsToAddToChain) {
6296 for (size_t i = 0; i < addCount; ++i) {
6297 // Elements past the common ancestor do not change hover state, but might 6255 // Elements past the common ancestor do not change hover state, but might
6298 // change active state. 6256 // change active state.
6299 if (ancestorNode && nodesToAddToChain[i] == ancestorNode) 6257 if (element == ancestor)
6300 sawCommonAncestor = true; 6258 sawCommonAncestor = true;
6301 if (allowActiveChanges) 6259 if (allowActiveChanges &&
6302 nodesToAddToChain[i]->setActive(true); 6260 (!mustBeInActiveChain || element->inActiveChain()))
6303 if (!sawCommonAncestor || nodesToAddToChain[i] == m_hoverNode) { 6261 element->setActive(true);
6304 nodesToAddToChain[i]->setHovered(true); 6262 if (!sawCommonAncestor || element == m_hoverElement)
6305 } 6263 element->setHovered(true);
6306 } 6264 }
6307 } 6265 }
6308 6266
6309 bool Document::haveScriptBlockingStylesheetsLoaded() const { 6267 bool Document::haveScriptBlockingStylesheetsLoaded() const {
6310 return m_styleEngine->haveScriptBlockingStylesheetsLoaded(); 6268 return m_styleEngine->haveScriptBlockingStylesheetsLoaded();
6311 } 6269 }
6312 6270
6313 bool Document::haveRenderBlockingStylesheetsLoaded() const { 6271 bool Document::haveRenderBlockingStylesheetsLoaded() const {
6314 if (RuntimeEnabledFeatures::cssInBodyDoesNotBlockPaintEnabled()) 6272 if (RuntimeEnabledFeatures::cssInBodyDoesNotBlockPaintEnabled())
6315 return m_styleEngine->haveRenderBlockingStylesheetsLoaded(); 6273 return m_styleEngine->haveRenderBlockingStylesheetsLoaded();
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
6550 sendSensitiveInputVisibility(); 6508 sendSensitiveInputVisibility();
6551 } 6509 }
6552 6510
6553 DEFINE_TRACE(Document) { 6511 DEFINE_TRACE(Document) {
6554 visitor->trace(m_importsController); 6512 visitor->trace(m_importsController);
6555 visitor->trace(m_docType); 6513 visitor->trace(m_docType);
6556 visitor->trace(m_implementation); 6514 visitor->trace(m_implementation);
6557 visitor->trace(m_autofocusElement); 6515 visitor->trace(m_autofocusElement);
6558 visitor->trace(m_focusedElement); 6516 visitor->trace(m_focusedElement);
6559 visitor->trace(m_sequentialFocusNavigationStartingPoint); 6517 visitor->trace(m_sequentialFocusNavigationStartingPoint);
6560 visitor->trace(m_hoverNode); 6518 visitor->trace(m_hoverElement);
6561 visitor->trace(m_activeHoverElement); 6519 visitor->trace(m_activeHoverElement);
6562 visitor->trace(m_documentElement); 6520 visitor->trace(m_documentElement);
6563 visitor->trace(m_rootScrollerController); 6521 visitor->trace(m_rootScrollerController);
6564 visitor->trace(m_titleElement); 6522 visitor->trace(m_titleElement);
6565 visitor->trace(m_axObjectCache); 6523 visitor->trace(m_axObjectCache);
6566 visitor->trace(m_markers); 6524 visitor->trace(m_markers);
6567 visitor->trace(m_cssTarget); 6525 visitor->trace(m_cssTarget);
6568 visitor->trace(m_currentScriptStack); 6526 visitor->trace(m_currentScriptStack);
6569 visitor->trace(m_scriptRunner); 6527 visitor->trace(m_scriptRunner);
6570 visitor->trace(m_listsInvalidatedAtDocument); 6528 visitor->trace(m_listsInvalidatedAtDocument);
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
6663 } 6621 }
6664 6622
6665 void showLiveDocumentInstances() { 6623 void showLiveDocumentInstances() {
6666 WeakDocumentSet& set = liveDocumentSet(); 6624 WeakDocumentSet& set = liveDocumentSet();
6667 fprintf(stderr, "There are %u documents currently alive:\n", set.size()); 6625 fprintf(stderr, "There are %u documents currently alive:\n", set.size());
6668 for (blink::Document* document : set) 6626 for (blink::Document* document : set)
6669 fprintf(stderr, "- Document %p URL: %s\n", document, 6627 fprintf(stderr, "- Document %p URL: %s\n", document,
6670 document->url().getString().utf8().data()); 6628 document->url().getString().utf8().data());
6671 } 6629 }
6672 #endif 6630 #endif
OLDNEW
« 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