Changeset 278785 in webkit
- Timestamp:
- Jun 11, 2021, 3:37:40 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 18 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/inspector/dom/willDestroyDOMNode-expected.txt (added)
-
LayoutTests/inspector/dom/willDestroyDOMNode.html (added)
-
Source/JavaScriptCore/ChangeLog (modified) (1 diff)
-
Source/JavaScriptCore/inspector/protocol/DOM.json (modified) (1 diff)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/dom/Node.cpp (modified) (2 diffs)
-
Source/WebCore/inspector/InspectorInstrumentation.cpp (modified) (1 diff)
-
Source/WebCore/inspector/InspectorInstrumentation.h (modified) (3 diffs)
-
Source/WebCore/inspector/agents/InspectorCSSAgent.cpp (modified) (1 diff)
-
Source/WebCore/inspector/agents/InspectorDOMAgent.cpp (modified) (32 diffs)
-
Source/WebCore/inspector/agents/InspectorDOMAgent.h (modified) (7 diffs)
-
Source/WebCore/inspector/agents/page/PageConsoleAgent.cpp (modified) (2 diffs)
-
Source/WebCore/inspector/agents/page/PageConsoleAgent.h (modified) (1 diff)
-
Source/WebCore/inspector/agents/page/PageDOMDebuggerAgent.cpp (modified) (1 diff)
-
Source/WebCore/inspector/agents/page/PageDOMDebuggerAgent.h (modified) (1 diff)
-
Source/WebInspectorUI/ChangeLog (modified) (1 diff)
-
Source/WebInspectorUI/UserInterface/Controllers/DOMManager.js (modified) (1 diff)
-
Source/WebInspectorUI/UserInterface/Protocol/DOMObserver.js (modified) (1 diff)
-
Source/WebInspectorUI/UserInterface/Views/DOMTreeUpdater.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r278777 r278785 1 2021-06-11 Patrick Angle <pangle@apple.com> 2 3 Web Inspector: Add instrumentation to node destruction for InspectorDOMAgent 4 https://bugs.webkit.org/show_bug.cgi?id=226624 5 6 Reviewed by Devin Rousso. 7 8 * inspector/dom/willDestroyDOMNode-expected.txt: Added. 9 * inspector/dom/willDestroyDOMNode.html: Added. 10 1 11 2021-06-11 Wenson Hsieh <wenson_hsieh@apple.com> 2 12 -
trunk/Source/JavaScriptCore/ChangeLog
r278769 r278785 1 2021-06-11 Patrick Angle <pangle@apple.com> 2 3 Web Inspector: Add instrumentation to node destruction for InspectorDOMAgent 4 https://bugs.webkit.org/show_bug.cgi?id=226624 5 6 Reviewed by Devin Rousso. 7 8 Add new `DOM.willDestroyDOMNode` event to inform the frontend of DOM nodes that no longer exist, even if they 9 weren't in the DOM tree. This work serves as a prelude to <https://webkit.org/b/189687> (Web Inspector: preserve 10 DOM.NodeId if a node is removed and re-added) to eventually only forget about nodes upon destruction, instead of 11 removal from the DOM tree. 12 13 * inspector/protocol/DOM.json: 14 1 15 2021-06-11 Yijia Huang <yijia_huang@apple.com> 2 16 -
trunk/Source/JavaScriptCore/inspector/protocol/DOM.json
r272768 r278785 680 680 }, 681 681 { 682 "name": "willDestroyDOMNode", 683 "description": "Fired when a detached DOM node is about to be destroyed. Currently, this event will only be fired when a DOM node that is detached is about to be destructed.", 684 "parameters": [ 685 { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node that will be destroyed." } 686 ] 687 }, 688 { 682 689 "name": "shadowRootPushed", 683 690 "description": "Called when shadow root is pushed into the element.", -
trunk/Source/WebCore/ChangeLog
r278782 r278785 1 2021-06-11 Patrick Angle <pangle@apple.com> 2 3 Web Inspector: Add instrumentation to node destruction for InspectorDOMAgent 4 https://bugs.webkit.org/show_bug.cgi?id=226624 5 6 Reviewed by Devin Rousso. 7 8 Test: inspector/dom/willDestroyDOMNode.html 9 10 Add instrumentation for destruction of nodes in order to cease instrumenting nodes and inform the frontend that 11 the node no longer exists. This work serves as a prelude to <https://webkit.org/b/189687> (Web Inspector: 12 preserve DOM.NodeId if a node is removed and re-added) to eventually only forget about nodes upon destruction, 13 instead of removal from the DOM tree. Additionally, the storage of nodes is simplified down to two inverse maps, 14 one that maps `Node` to `NodeId`, and another that maps `NodeId` to `Node`. These are kept in sync throughout, 15 and both attached and detached nodes are now handled as part of these two maps of Nodes. 16 17 * dom/Node.cpp: 18 (WebCore::Node::~Node): 19 * inspector/InspectorInstrumentation.cpp: 20 (WebCore::InspectorInstrumentation::willDestroyDOMNodeImpl): 21 * inspector/InspectorInstrumentation.h: 22 (WebCore::InspectorInstrumentation::didRemoveDOMNode): 23 (WebCore::InspectorInstrumentation::willDestroyDOMNode): 24 * inspector/agents/InspectorCSSAgent.cpp: 25 (WebCore::InspectorCSSAgent::didRemoveDOMNode): 26 * inspector/agents/InspectorDOMAgent.cpp: 27 (WebCore::InspectorDOMAgent::InspectorDOMAgent): 28 (WebCore::InspectorDOMAgent::reset): 29 (WebCore::InspectorDOMAgent::bind): 30 (WebCore::InspectorDOMAgent::unbind): 31 (WebCore::InspectorDOMAgent::getDocument): 32 (WebCore::InspectorDOMAgent::pushChildNodesToFrontend): 33 (WebCore::InspectorDOMAgent::discardBindings): 34 (WebCore::InspectorDOMAgent::pushNodePathToFrontend): 35 (WebCore::InspectorDOMAgent::boundNodeId): 36 - Add a check that the `Node*` is a valid key (not `nullptr`) before getting its id. 37 (WebCore::InspectorDOMAgent::buildObjectForNode): 38 (WebCore::InspectorDOMAgent::buildArrayForContainerChildren): 39 (WebCore::InspectorDOMAgent::buildArrayForPseudoElements): 40 (WebCore::InspectorDOMAgent::didCommitLoad): 41 (WebCore::InspectorDOMAgent::didInsertDOMNode): 42 (WebCore::InspectorDOMAgent::didRemoveDOMNode): 43 (WebCore::InspectorDOMAgent::willDestroyDOMNode): 44 (WebCore::InspectorDOMAgent::destroyedNodesTimerFired): 45 - Added instrumentation point for DOM nodes being destroyed so they can be removed from the agent, and the 46 frontend can also be informed of their ceasing to exist. 47 (WebCore::InspectorDOMAgent::characterDataModified): 48 (WebCore::InspectorDOMAgent::didInvalidateStyleAttr): 49 (WebCore::InspectorDOMAgent::didPushShadowRoot): 50 (WebCore::InspectorDOMAgent::willPopShadowRoot): 51 (WebCore::InspectorDOMAgent::didChangeCustomElementState): 52 (WebCore::InspectorDOMAgent::pseudoElementCreated): 53 (WebCore::InspectorDOMAgent::pseudoElementDestroyed): 54 (WebCore::InspectorDOMAgent::releaseDanglingNodes): Deleted. 55 - Removed usage of NodeToIdMap and nested maps of nodes throughout in favor of two inverse maps for relating 56 `Node`s and `NodeId`s. Because there is now a single set of canonical node maps, we no longer to to pass a 57 NodeToIdMap throughout the agent. 58 * inspector/agents/InspectorDOMAgent.h: 59 * inspector/agents/page/PageConsoleAgent.cpp: 60 (WebCore::PageConsoleAgent::PageConsoleAgent): 61 (WebCore::PageConsoleAgent::clearMessages): 62 * inspector/agents/page/PageConsoleAgent.h: 63 * inspector/agents/page/PageDOMDebuggerAgent.cpp: 64 (WebCore::PageDOMDebuggerAgent::willDestroyDOMNode): 65 * inspector/agents/page/PageDOMDebuggerAgent.h: 66 1 67 2021-06-11 Yusuke Suzuki <ysuzuki@apple.com> 2 68 -
trunk/Source/WebCore/dom/Node.cpp
r278619 r278785 51 51 #include "InputEvent.h" 52 52 #include "InspectorController.h" 53 #include "InspectorInstrumentation.h" 53 54 #include "KeyboardEvent.h" 54 55 #include "Logging.h" … … 350 351 ASSERT(!m_adoptionIsRequired); 351 352 353 InspectorInstrumentation::willDestroyDOMNode(*this); 354 352 355 #ifndef NDEBUG 353 356 if (!ignoreSet().remove(*this)) -
trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp
r278717 r278785 177 177 } 178 178 179 void InspectorInstrumentation::willDestroyDOMNodeImpl(InstrumentingAgents& instrumentingAgents, Node& node) 180 { 181 if (auto* pageDOMDebuggerAgent = instrumentingAgents.enabledPageDOMDebuggerAgent()) 182 pageDOMDebuggerAgent->willDestroyDOMNode(node); 183 if (auto* domAgent = instrumentingAgents.persistentDOMAgent()) 184 domAgent->willDestroyDOMNode(node); 185 } 186 179 187 void InspectorInstrumentation::nodeLayoutContextChangedImpl(InstrumentingAgents& instrumentingAgents, Node& node, RenderObject* newRenderer) 180 188 { -
trunk/Source/WebCore/inspector/InspectorInstrumentation.h
r278717 r278785 126 126 static void willRemoveDOMNode(Document&, Node&); 127 127 static void didRemoveDOMNode(Document&, Node&); 128 static void willDestroyDOMNode(Node&); 128 129 static void nodeLayoutContextChanged(Node&, RenderObject*); 129 130 static void willModifyDOMAttr(Document&, Element&, const AtomString& oldValue, const AtomString& newValue); … … 351 352 static void willRemoveDOMNodeImpl(InstrumentingAgents&, Node&); 352 353 static void didRemoveDOMNodeImpl(InstrumentingAgents&, Node&); 354 static void willDestroyDOMNodeImpl(InstrumentingAgents&, Node&); 353 355 static void nodeLayoutContextChangedImpl(InstrumentingAgents&, Node&, RenderObject*); 354 356 static void willModifyDOMAttrImpl(InstrumentingAgents&, Element&, const AtomString& oldValue, const AtomString& newValue); … … 602 604 } 603 605 606 inline void InspectorInstrumentation::willDestroyDOMNode(Node& node) 607 { 608 FAST_RETURN_IF_NO_FRONTENDS(void()); 609 if (auto* agents = instrumentingAgents(node.document())) 610 willDestroyDOMNodeImpl(*agents, node); 611 } 612 604 613 inline void InspectorInstrumentation::nodeLayoutContextChanged(Node& node, RenderObject* newRenderer) 605 614 { -
trunk/Source/WebCore/inspector/agents/InspectorCSSAgent.cpp
r278340 r278785 1160 1160 void InspectorCSSAgent::didRemoveDOMNode(Node& node, Protocol::DOM::NodeId nodeId) 1161 1161 { 1162 // This can be called in response to GC. 1162 1163 m_nodeIdToForcedPseudoState.remove(nodeId); 1163 1164 -
trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp
r278340 r278785 289 289 , m_inspectedPage(context.inspectedPage) 290 290 , m_overlay(overlay) 291 , m_destroyedNodesTimer(*this, &InspectorDOMAgent::destroyedNodesTimerFired) 291 292 #if ENABLE(VIDEO) 292 293 , m_mediaMetricsTimer(*this, &InspectorDOMAgent::mediaMetricsTimerFired) … … 354 355 m_revalidateStyleAttrTask->reset(); 355 356 m_document = nullptr; 357 358 m_destroyedDetachedNodeIdentifiers.clear(); 359 m_destroyedAttachedNodeIdentifiers.clear(); 360 if (m_destroyedNodesTimer.isActive()) 361 m_destroyedNodesTimer.stop(); 356 362 } 357 363 … … 373 379 } 374 380 375 void InspectorDOMAgent::releaseDanglingNodes() 376 { 377 m_danglingNodeToIdMaps.clear(); 378 } 379 380 Protocol::DOM::NodeId InspectorDOMAgent::bind(Node* node, NodeToIdMap* nodesMap) 381 { 382 auto id = nodesMap->get(node); 383 if (id) 381 Protocol::DOM::NodeId InspectorDOMAgent::bind(Node& node) 382 { 383 return m_nodeToId.ensure(&node, [&] { 384 auto id = m_lastNodeId++; 385 m_idToNode.set(id, &node); 384 386 return id; 385 id = m_lastNodeId++; 386 nodesMap->set(node, id); 387 m_idToNode.set(id, node); 388 m_idToNodesMap.set(id, nodesMap); 389 return id; 390 } 391 392 void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap) 393 { 394 auto id = nodesMap->get(node); 387 }).iterator->value; 388 } 389 390 void InspectorDOMAgent::unbind(Node& node) 391 { 392 auto id = m_nodeToId.take(&node); 395 393 if (!id) 396 394 return; … … 398 396 m_idToNode.remove(id); 399 397 400 if (node ->isFrameOwnerElement()) {401 const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>( node);398 if (node.isFrameOwnerElement()) { 399 const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>(&node); 402 400 if (Document* contentDocument = frameOwner->contentDocument()) 403 unbind( contentDocument, nodesMap);404 } 405 406 if (is<Element>( *node)) {407 Element& element = downcast<Element>( *node);401 unbind(*contentDocument); 402 } 403 404 if (is<Element>(node)) { 405 Element& element = downcast<Element>(node); 408 406 if (ShadowRoot* root = element.shadowRoot()) 409 unbind( root, nodesMap);407 unbind(*root); 410 408 if (PseudoElement* beforeElement = element.beforePseudoElement()) 411 unbind( beforeElement, nodesMap);409 unbind(*beforeElement); 412 410 if (PseudoElement* afterElement = element.afterPseudoElement()) 413 unbind(afterElement, nodesMap); 414 } 415 416 nodesMap->remove(node); 411 unbind(*afterElement); 412 } 417 413 418 414 if (auto* cssAgent = m_instrumentingAgents.enabledCSSAgent()) 419 cssAgent->didRemoveDOMNode( *node, id);415 cssAgent->didRemoveDOMNode(node, id); 420 416 421 417 if (m_childrenRequested.remove(id)) { 422 418 // FIXME: Would be better to do this iteratively rather than recursively. 423 for (Node* child = innerFirstChild( node); child; child = innerNextSibling(child))424 unbind( child, nodesMap);419 for (Node* child = innerFirstChild(&node); child; child = innerNextSibling(child)) 420 unbind(*child); 425 421 } 426 422 } … … 500 496 m_document = document; 501 497 502 auto root = buildObjectForNode(m_document.get(), 2 , &m_documentNodeToIdMap);498 auto root = buildObjectForNode(m_document.get(), 2); 503 499 504 500 if (m_nodeToFocus) … … 513 509 if (!node || (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE && node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE)) 514 510 return; 515 516 NodeToIdMap* nodeMap = m_idToNodesMap.get(nodeId);517 511 518 512 if (m_childrenRequested.contains(nodeId)) { … … 523 517 524 518 for (node = innerFirstChild(node); node; node = innerNextSibling(node)) { 525 auto childNodeId = nodeMap->get(node);519 auto childNodeId = boundNodeId(node); 526 520 ASSERT(childNodeId); 527 521 pushChildNodesToFrontend(childNodeId, depth); … … 531 525 } 532 526 533 auto children = buildArrayForContainerChildren(node, depth , nodeMap);527 auto children = buildArrayForContainerChildren(node, depth); 534 528 m_frontendDispatcher->setChildNodes(nodeId, WTFMove(children)); 535 529 } … … 537 531 void InspectorDOMAgent::discardBindings() 538 532 { 539 m_ documentNodeToIdMap.clear();533 m_nodeToId.clear(); 540 534 m_idToNode.clear(); 541 535 m_dispatchedEvents.clear(); 542 536 m_eventListenerEntries.clear(); 543 releaseDanglingNodes();544 537 m_childrenRequested.clear(); 545 538 } … … 654 647 655 648 // FIXME: <https://webkit.org/b/213499> Web Inspector: allow DOM nodes to be instrumented at any point, regardless of whether the main document has also been instrumented 656 if (!m_ documentNodeToIdMap.contains(m_document)) {649 if (!m_nodeToId.contains(m_document.get())) { 657 650 errorString = "Document must have been requested"_s; 658 651 return 0; … … 660 653 661 654 // Return id in case the node is known. 662 if (auto result = m_documentNodeToIdMap.get(nodeToPush))655 if (auto result = boundNodeId(nodeToPush)) 663 656 return result; 664 657 665 658 Node* node = nodeToPush; 666 659 Vector<Node*> path; 667 NodeToIdMap* danglingMap = 0;668 660 669 661 while (true) { … … 671 663 if (!parent) { 672 664 // Node being pushed is detached -> push subtree root. 673 auto newMap = makeUnique<NodeToIdMap>();674 danglingMap = newMap.get();675 m_danglingNodeToIdMaps.append(newMap.release());676 665 auto children = JSON::ArrayOf<Protocol::DOM::Node>::create(); 677 children->addItem(buildObjectForNode(node, 0 , danglingMap));666 children->addItem(buildObjectForNode(node, 0)); 678 667 m_frontendDispatcher->setChildNodes(0, WTFMove(children)); 679 668 break; 680 669 } else { 681 670 path.append(parent); 682 if ( m_documentNodeToIdMap.get(parent))671 if (boundNodeId(parent)) 683 672 break; 684 else 685 node = parent; 673 node = parent; 686 674 } 687 675 } 688 676 689 NodeToIdMap* map = danglingMap ? danglingMap : &m_documentNodeToIdMap;690 677 for (int i = path.size() - 1; i >= 0; --i) { 691 auto nodeId = map->get(path.at(i));678 auto nodeId = boundNodeId(path.at(i)); 692 679 ASSERT(nodeId); 693 680 pushChildNodesToFrontend(nodeId); 694 681 } 695 return map->get(nodeToPush);682 return boundNodeId(nodeToPush); 696 683 } 697 684 698 685 Protocol::DOM::NodeId InspectorDOMAgent::boundNodeId(const Node* node) 699 686 { 700 return m_documentNodeToIdMap.get(const_cast<Node*>(node)); 687 if (!m_nodeToId.isValidKey(node)) 688 return 0; 689 690 return m_nodeToId.get(node); 701 691 } 702 692 … … 1712 1702 } 1713 1703 1714 Ref<Protocol::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* node, int depth , NodeToIdMap* nodesMap)1715 { 1716 auto id = bind( node, nodesMap);1704 Ref<Protocol::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* node, int depth) 1705 { 1706 auto id = bind(*node); 1717 1707 String nodeName; 1718 1708 String localName; … … 1756 1746 int nodeCount = innerChildNodeCount(node); 1757 1747 value->setChildNodeCount(nodeCount); 1758 auto children = buildArrayForContainerChildren(node, depth , nodesMap);1748 auto children = buildArrayForContainerChildren(node, depth); 1759 1749 if (children->length() > 0) 1760 1750 value->setChildren(WTFMove(children)); … … 1775 1765 if (is<HTMLFrameOwnerElement>(element)) { 1776 1766 if (auto* document = downcast<HTMLFrameOwnerElement>(element).contentDocument()) 1777 value->setContentDocument(buildObjectForNode(document, 0 , nodesMap));1767 value->setContentDocument(buildObjectForNode(document, 0)); 1778 1768 } 1779 1769 1780 1770 if (ShadowRoot* root = element.shadowRoot()) { 1781 1771 auto shadowRoots = JSON::ArrayOf<Protocol::DOM::Node>::create(); 1782 shadowRoots->addItem(buildObjectForNode(root, 0 , nodesMap));1772 shadowRoots->addItem(buildObjectForNode(root, 0)); 1783 1773 value->setShadowRoots(WTFMove(shadowRoots)); 1784 1774 } 1785 1775 1786 1776 if (is<HTMLTemplateElement>(element)) 1787 value->setTemplateContent(buildObjectForNode(&downcast<HTMLTemplateElement>(element).content(), 0 , nodesMap));1777 value->setTemplateContent(buildObjectForNode(&downcast<HTMLTemplateElement>(element).content(), 0)); 1788 1778 1789 1779 if (is<HTMLStyleElement>(element) || (is<HTMLScriptElement>(element) && !element.hasAttributeWithoutSynchronization(HTMLNames::srcAttr))) … … 1799 1789 value->setPseudoType(pseudoType); 1800 1790 } else { 1801 if (auto pseudoElements = buildArrayForPseudoElements(element , nodesMap))1791 if (auto pseudoElements = buildArrayForPseudoElements(element)) 1802 1792 value->setPseudoElements(pseudoElements.releaseNonNull()); 1803 1793 } … … 1839 1829 } 1840 1830 1841 Ref<JSON::ArrayOf<Protocol::DOM::Node>> InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth , NodeToIdMap* nodesMap)1831 Ref<JSON::ArrayOf<Protocol::DOM::Node>> InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth) 1842 1832 { 1843 1833 auto children = JSON::ArrayOf<Protocol::DOM::Node>::create(); … … 1846 1836 Node* firstChild = container->firstChild(); 1847 1837 if (firstChild && firstChild->nodeType() == Node::TEXT_NODE && !firstChild->nextSibling()) { 1848 children->addItem(buildObjectForNode(firstChild, 0 , nodesMap));1849 m_childrenRequested.add(bind( container, nodesMap));1838 children->addItem(buildObjectForNode(firstChild, 0)); 1839 m_childrenRequested.add(bind(*container)); 1850 1840 } 1851 1841 return children; … … 1854 1844 Node* child = innerFirstChild(container); 1855 1845 depth--; 1856 m_childrenRequested.add(bind( container, nodesMap));1846 m_childrenRequested.add(bind(*container)); 1857 1847 1858 1848 while (child) { 1859 children->addItem(buildObjectForNode(child, depth , nodesMap));1849 children->addItem(buildObjectForNode(child, depth)); 1860 1850 child = innerNextSibling(child); 1861 1851 } … … 1863 1853 } 1864 1854 1865 RefPtr<JSON::ArrayOf<Protocol::DOM::Node>> InspectorDOMAgent::buildArrayForPseudoElements(const Element& element , NodeToIdMap* nodesMap)1855 RefPtr<JSON::ArrayOf<Protocol::DOM::Node>> InspectorDOMAgent::buildArrayForPseudoElements(const Element& element) 1866 1856 { 1867 1857 PseudoElement* beforeElement = element.beforePseudoElement(); … … 1872 1862 auto pseudoElements = JSON::ArrayOf<Protocol::DOM::Node>::create(); 1873 1863 if (beforeElement) 1874 pseudoElements->addItem(buildObjectForNode(beforeElement, 0 , nodesMap));1864 pseudoElements->addItem(buildObjectForNode(beforeElement, 0)); 1875 1865 if (afterElement) 1876 pseudoElements->addItem(buildObjectForNode(afterElement, 0 , nodesMap));1866 pseudoElements->addItem(buildObjectForNode(afterElement, 0)); 1877 1867 return pseudoElements; 1878 1868 } … … 2363 2353 return; 2364 2354 2365 auto frameOwnerId = m_documentNodeToIdMap.get(frameOwner);2355 auto frameOwnerId = boundNodeId(frameOwner.get()); 2366 2356 if (!frameOwnerId) 2367 2357 return; 2368 2358 2369 2359 // Re-add frame owner element together with its new children. 2370 auto parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner.get()));2360 auto parentId = boundNodeId(innerParentNode(frameOwner.get())); 2371 2361 m_frontendDispatcher->childNodeRemoved(parentId, frameOwnerId); 2372 unbind( frameOwner.get(), &m_documentNodeToIdMap);2373 2374 auto value = buildObjectForNode(frameOwner.get(), 0 , &m_documentNodeToIdMap);2362 unbind(*frameOwner); 2363 2364 auto value = buildObjectForNode(frameOwner.get(), 0); 2375 2365 Node* previousSibling = innerPreviousSibling(frameOwner.get()); 2376 auto prevId = previousSibling ? m_documentNodeToIdMap.get(previousSibling) : 0;2366 auto prevId = boundNodeId(previousSibling); 2377 2367 m_frontendDispatcher->childNodeInserted(parentId, prevId, WTFMove(value)); 2378 2368 } … … 2429 2419 2430 2420 // We could be attaching existing subtree. Forget the bindings. 2431 unbind( &node, &m_documentNodeToIdMap);2421 unbind(node); 2432 2422 2433 2423 ContainerNode* parent = node.parentNode(); 2434 if (!parent) 2435 return; 2436 2437 auto parentId = m_documentNodeToIdMap.get(parent); 2424 2425 auto parentId = boundNodeId(parent); 2438 2426 // Return if parent is not mapped yet. 2439 2427 if (!parentId) … … 2446 2434 // Children have been requested -> return value of a new child. 2447 2435 Node* prevSibling = innerPreviousSibling(&node); 2448 auto prevId = prevSibling ? m_documentNodeToIdMap.get(prevSibling) : 0;2449 auto value = buildObjectForNode(&node, 0 , &m_documentNodeToIdMap);2436 auto prevId = boundNodeId(prevSibling); 2437 auto value = buildObjectForNode(&node, 0); 2450 2438 m_frontendDispatcher->childNodeInserted(parentId, prevId, WTFMove(value)); 2451 2439 } … … 2459 2447 ContainerNode* parent = node.parentNode(); 2460 2448 2449 auto parentId = boundNodeId(parent); 2461 2450 // If parent is not mapped yet -> ignore the event. 2462 if (!m_documentNodeToIdMap.contains(parent)) 2463 return; 2464 2465 auto parentId = m_documentNodeToIdMap.get(parent); 2466 2451 if (!parentId) 2452 return; 2453 2454 // FIXME: <webkit.org/b/189687> Preserve DOM.NodeId if a node is removed and re-added 2467 2455 if (!m_childrenRequested.contains(parentId)) { 2468 2456 // No children are mapped yet -> only notify on changes of hasChildren. … … 2470 2458 m_frontendDispatcher->childNodeCountUpdated(parentId, 0); 2471 2459 } else 2472 m_frontendDispatcher->childNodeRemoved(parentId, m_documentNodeToIdMap.get(&node)); 2473 unbind(&node, &m_documentNodeToIdMap); 2460 m_frontendDispatcher->childNodeRemoved(parentId, boundNodeId(&node)); 2461 unbind(node); 2462 } 2463 2464 void InspectorDOMAgent::willDestroyDOMNode(Node& node) 2465 { 2466 if (containsOnlyHTMLWhitespace(&node)) 2467 return; 2468 2469 auto nodeId = m_nodeToId.take(&node); 2470 if (!nodeId) 2471 return; 2472 2473 m_idToNode.remove(nodeId); 2474 m_childrenRequested.remove(nodeId); 2475 2476 if (auto* cssAgent = m_instrumentingAgents.enabledCSSAgent()) 2477 cssAgent->didRemoveDOMNode(node, nodeId); 2478 2479 // This can be called in response to GC. Due to the single-process model used in WebKit1, the 2480 // event must be dispatched from a timer to prevent the frontend from making JS allocations 2481 // while the GC is still active. 2482 2483 // FIXME: <webkit.org/b/189687> Unify m_destroyedAttachedNodeIdentifiers and m_destroyedDetachedNodeIdentifiers. 2484 if (auto parentId = boundNodeId(node.parentNode())) 2485 m_destroyedAttachedNodeIdentifiers.append({ parentId, nodeId }); 2486 else 2487 m_destroyedDetachedNodeIdentifiers.append(nodeId); 2488 2489 if (!m_destroyedNodesTimer.isActive()) 2490 m_destroyedNodesTimer.startOneShot(0_s); 2491 } 2492 2493 void InspectorDOMAgent::destroyedNodesTimerFired() 2494 { 2495 for (auto& [parentId, nodeId] : std::exchange(m_destroyedAttachedNodeIdentifiers, { })) { 2496 if (!m_childrenRequested.contains(parentId)) { 2497 auto* parent = nodeForId(parentId); 2498 if (parent && innerChildNodeCount(parent) == 1) 2499 m_frontendDispatcher->childNodeCountUpdated(parentId, 0); 2500 } else 2501 m_frontendDispatcher->childNodeRemoved(parentId, nodeId); 2502 } 2503 2504 for (auto nodeId : std::exchange(m_destroyedDetachedNodeIdentifiers, { })) 2505 m_frontendDispatcher->willDestroyDOMNode(nodeId); 2474 2506 } 2475 2507 … … 2526 2558 void InspectorDOMAgent::characterDataModified(CharacterData& characterData) 2527 2559 { 2528 auto id = m_documentNodeToIdMap.get(&characterData);2560 auto id = boundNodeId(&characterData); 2529 2561 if (!id) { 2530 2562 // Push text node if it is being created. … … 2537 2569 void InspectorDOMAgent::didInvalidateStyleAttr(Element& element) 2538 2570 { 2539 auto id = m_documentNodeToIdMap.get(&element);2571 auto id = boundNodeId(&element); 2540 2572 if (!id) 2541 2573 return; … … 2548 2580 void InspectorDOMAgent::didPushShadowRoot(Element& host, ShadowRoot& root) 2549 2581 { 2550 auto hostId = m_documentNodeToIdMap.get(&host);2582 auto hostId = boundNodeId(&host); 2551 2583 if (hostId) 2552 m_frontendDispatcher->shadowRootPushed(hostId, buildObjectForNode(&root, 0 , &m_documentNodeToIdMap));2584 m_frontendDispatcher->shadowRootPushed(hostId, buildObjectForNode(&root, 0)); 2553 2585 } 2554 2586 2555 2587 void InspectorDOMAgent::willPopShadowRoot(Element& host, ShadowRoot& root) 2556 2588 { 2557 auto hostId = m_documentNodeToIdMap.get(&host);2558 auto rootId = m_documentNodeToIdMap.get(&root);2589 auto hostId = boundNodeId(&host); 2590 auto rootId = boundNodeId(&root); 2559 2591 if (hostId && rootId) 2560 2592 m_frontendDispatcher->shadowRootPopped(hostId, rootId); … … 2563 2595 void InspectorDOMAgent::didChangeCustomElementState(Element& element) 2564 2596 { 2565 auto elementId = m_documentNodeToIdMap.get(&element);2597 auto elementId = boundNodeId(&element); 2566 2598 if (!elementId) 2567 2599 return; … … 2590 2622 return; 2591 2623 2592 auto parentId = m_documentNodeToIdMap.get(parent);2624 auto parentId = boundNodeId(parent); 2593 2625 if (!parentId) 2594 2626 return; 2595 2627 2596 2628 pushChildNodesToFrontend(parentId, 1); 2597 m_frontendDispatcher->pseudoElementAdded(parentId, buildObjectForNode(&pseudoElement, 0 , &m_documentNodeToIdMap));2629 m_frontendDispatcher->pseudoElementAdded(parentId, buildObjectForNode(&pseudoElement, 0)); 2598 2630 } 2599 2631 2600 2632 void InspectorDOMAgent::pseudoElementDestroyed(PseudoElement& pseudoElement) 2601 2633 { 2602 auto pseudoElementId = m_documentNodeToIdMap.get(&pseudoElement);2634 auto pseudoElementId = boundNodeId(&pseudoElement); 2603 2635 if (!pseudoElementId) 2604 2636 return; … … 2607 2639 Element* parent = pseudoElement.hostElement(); 2608 2640 ASSERT(parent); 2609 auto parentId = m_documentNodeToIdMap.get(parent);2641 auto parentId = boundNodeId(parent); 2610 2642 ASSERT(parentId); 2611 2643 2612 unbind( &pseudoElement, &m_documentNodeToIdMap);2644 unbind(pseudoElement); 2613 2645 m_frontendDispatcher->pseudoElementRemoved(parentId, pseudoElementId); 2614 2646 } -
trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.h
r278253 r278785 160 160 void didInsertDOMNode(Node&); 161 161 void didRemoveDOMNode(Node&); 162 void willDestroyDOMNode(Node&); 162 163 void willModifyDOMAttr(Element&, const AtomString& oldValue, const AtomString& newValue); 163 164 void didModifyDOMAttr(Element&, const AtomString& name, const AtomString& value); … … 180 181 // Callbacks that don't directly correspond to an instrumentation entry point. 181 182 void setDocument(Document*); 182 void releaseDanglingNodes();183 183 184 184 void styleAttributeInvalidated(const Vector<Element*>& elements); … … 219 219 220 220 // Node-related methods. 221 typedef HashMap<RefPtr<Node>, Inspector::Protocol::DOM::NodeId> NodeToIdMap; 222 Inspector::Protocol::DOM::NodeId bind(Node*, NodeToIdMap*); 223 void unbind(Node*, NodeToIdMap*); 221 Inspector::Protocol::DOM::NodeId bind(Node&); 222 void unbind(Node&); 224 223 225 224 Node* assertEditableNode(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId); … … 228 227 void pushChildNodesToFrontend(Inspector::Protocol::DOM::NodeId, int depth = 1); 229 228 230 Ref<Inspector::Protocol::DOM::Node> buildObjectForNode(Node*, int depth , NodeToIdMap*);229 Ref<Inspector::Protocol::DOM::Node> buildObjectForNode(Node*, int depth); 231 230 Ref<JSON::ArrayOf<String>> buildArrayForElementAttributes(Element*); 232 Ref<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> buildArrayForContainerChildren(Node* container, int depth , NodeToIdMap* nodesMap);233 RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> buildArrayForPseudoElements(const Element& , NodeToIdMap* nodesMap);231 Ref<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> buildArrayForContainerChildren(Node* container, int depth); 232 RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> buildArrayForPseudoElements(const Element&); 234 233 Ref<Inspector::Protocol::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, Inspector::Protocol::DOM::EventListenerId identifier, EventTarget&, const AtomString& eventType, bool disabled, const RefPtr<JSC::Breakpoint>&); 235 234 Ref<Inspector::Protocol::DOM::AccessibilityProperties> buildObjectForAccessibilityProperties(Node&); … … 243 242 void innerHighlightQuad(std::unique_ptr<FloatQuad>, RefPtr<JSON::Object>&& color, RefPtr<JSON::Object>&& outlineColor, std::optional<bool>&& usePageCoordinates); 244 243 244 void destroyedNodesTimerFired(); 245 245 246 Inspector::InjectedScriptManager& m_injectedScriptManager; 246 247 std::unique_ptr<Inspector::DOMFrontendDispatcher> m_frontendDispatcher; … … 248 249 Page& m_inspectedPage; 249 250 InspectorOverlay* m_overlay { nullptr }; 250 NodeToIdMap m_documentNodeToIdMap; 251 // Owns node mappings for dangling nodes. 252 Vector<std::unique_ptr<NodeToIdMap>> m_danglingNodeToIdMaps; 251 HashMap<const Node*, Inspector::Protocol::DOM::NodeId> m_nodeToId; 253 252 HashMap<Inspector::Protocol::DOM::NodeId, Node*> m_idToNode; 254 HashMap<Inspector::Protocol::DOM::NodeId, NodeToIdMap*> m_idToNodesMap;255 253 HashSet<Inspector::Protocol::DOM::NodeId> m_childrenRequested; 256 254 Inspector::Protocol::DOM::NodeId m_lastNodeId { 1 }; … … 265 263 std::unique_ptr<InspectorHistory> m_history; 266 264 std::unique_ptr<DOMEditor> m_domEditor; 265 266 Vector<Inspector::Protocol::DOM::NodeId> m_destroyedDetachedNodeIdentifiers; 267 Vector<std::pair<Inspector::Protocol::DOM::NodeId, Inspector::Protocol::DOM::NodeId>> m_destroyedAttachedNodeIdentifiers; 268 Timer m_destroyedNodesTimer; 267 269 268 270 #if ENABLE(VIDEO) -
trunk/Source/WebCore/inspector/agents/page/PageConsoleAgent.cpp
r271735 r278785 48 48 PageConsoleAgent::PageConsoleAgent(PageAgentContext& context) 49 49 : WebConsoleAgent(context) 50 , m_instrumentingAgents(context.instrumentingAgents)51 50 , m_inspectedPage(context.inspectedPage) 52 51 { … … 54 53 55 54 PageConsoleAgent::~PageConsoleAgent() = default; 56 57 Protocol::ErrorStringOr<void> PageConsoleAgent::clearMessages()58 {59 if (auto* domAgent = m_instrumentingAgents.persistentDOMAgent())60 domAgent->releaseDanglingNodes();61 62 return WebConsoleAgent::clearMessages();63 }64 55 65 56 Protocol::ErrorStringOr<Ref<JSON::ArrayOf<Protocol::Console::Channel>>> PageConsoleAgent::getLoggingChannels() -
trunk/Source/WebCore/inspector/agents/page/PageConsoleAgent.h
r266885 r278785 45 45 46 46 // ConsoleBackendDispatcherHandler 47 Inspector::Protocol::ErrorStringOr<void> clearMessages();48 47 Inspector::Protocol::ErrorStringOr<Ref<JSON::ArrayOf<Inspector::Protocol::Console::Channel>>> getLoggingChannels(); 49 48 Inspector::Protocol::ErrorStringOr<void> setLoggingChannelLevel(Inspector::Protocol::Console::ChannelSource, Inspector::Protocol::Console::ChannelLevel); 50 49 51 50 private: 52 InstrumentingAgents& m_instrumentingAgents;53 51 Page& m_inspectedPage; 54 52 }; -
trunk/Source/WebCore/inspector/agents/page/PageDOMDebuggerAgent.cpp
r278340 r278785 277 277 } 278 278 279 void PageDOMDebuggerAgent::willDestroyDOMNode(Node& node) 280 { 281 // This can be called in response to GC. 282 // DOM Node destruction should be treated as if the node was removed from the DOM tree. 283 didRemoveDOMNode(node); 284 } 285 279 286 void PageDOMDebuggerAgent::willModifyDOMAttr(Element& element) 280 287 { -
trunk/Source/WebCore/inspector/agents/page/PageDOMDebuggerAgent.h
r266885 r278785 54 54 void willRemoveDOMNode(Node&); 55 55 void didRemoveDOMNode(Node&); 56 void willDestroyDOMNode(Node&); 56 57 void willModifyDOMAttr(Element&); 57 58 void willInvalidateStyleAttr(Element&); -
trunk/Source/WebInspectorUI/ChangeLog
r278607 r278785 1 2021-06-11 Patrick Angle <pangle@apple.com> 2 3 Web Inspector: Add instrumentation to node destruction for InspectorDOMAgent 4 https://bugs.webkit.org/show_bug.cgi?id=226624 5 6 Reviewed by Devin Rousso. 7 8 Listen for the new `DOM.willDestroyDOMNode` event in order to cleanup and remaining references to that Node. 9 This work serves as a prelude to <https://webkit.org/b/189687> (Web Inspector: preserve DOM.NodeId if a node is 10 removed and re-added) to eventually only forget about nodes upon destruction, instead of removal from the DOM 11 tree. 12 13 * UserInterface/Controllers/DOMManager.js: 14 (WI.DOMManager.prototype.willDestroyDOMNode): 15 * UserInterface/Protocol/DOMObserver.js: 16 (WI.DOMObserver.prototype.willDestroyDOMNode): 17 * UserInterface/Views/DOMTreeUpdater.js: 18 (WI.DOMTreeUpdater.prototype._nodeRemoved): 19 1 20 2021-06-08 Razvan Caliman <rcaliman@apple.com> 2 21 -
trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMManager.js
r272566 r278785 186 186 // DOMObserver 187 187 188 willDestroyDOMNode(nodeId) 189 { 190 let node = this._idToDOMNode[nodeId]; 191 node.markDestroyed(); 192 delete this._idToDOMNode[nodeId]; 193 194 this.dispatchEventToListeners(WI.DOMManager.Event.NodeRemoved, {node}); 195 } 196 188 197 didAddEventListener(nodeId) 189 198 { -
trunk/Source/WebInspectorUI/UserInterface/Protocol/DOMObserver.js
r251227 r278785 78 78 } 79 79 80 willDestroyDOMNode(nodeId) 81 { 82 WI.domManager.willDestroyDOMNode(nodeId); 83 } 84 80 85 shadowRootPushed(hostId, root) 81 86 { -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMTreeUpdater.js
r269359 r278785 104 104 _nodeRemoved: function(event) 105 105 { 106 this._recentlyDeletedNodes.set(event.data.node, {parent: event.data.parent}); 106 let parent = event.data.parent; 107 if (!parent) 108 return; 109 110 this._recentlyDeletedNodes.set(event.data.node, {parent}); 107 111 if (this._treeOutline._visible) 108 112 this._updateModifiedNodesDebouncer.delayForFrame();
Note:
See TracChangeset
for help on using the changeset viewer.