2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Copyright (C) 2009 Joseph Pecoraro
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "InspectorDOMAgent.h"
37 #include "CSSComputedStyleDeclaration.h"
38 #include "CSSMutableStyleDeclaration.h"
39 #include "CSSPropertyNames.h"
40 #include "CSSPropertySourceData.h"
42 #include "CSSRuleList.h"
43 #include "CSSStyleRule.h"
44 #include "CSSStyleSelector.h"
45 #include "CSSStyleSheet.h"
46 #include "CharacterData.h"
47 #include "ContainerNode.h"
49 #include "CookieJar.h"
50 #include "DOMNodeHighlighter.h"
51 #include "DOMWindow.h"
53 #include "DocumentType.h"
55 #include "EventContext.h"
56 #include "EventListener.h"
57 #include "EventNames.h"
58 #include "EventTarget.h"
60 #include "FrameTree.h"
61 #include "HitTestResult.h"
62 #include "HTMLElement.h"
63 #include "HTMLFrameOwnerElement.h"
64 #include "InjectedScriptManager.h"
65 #include "InspectorClient.h"
66 #include "InspectorFrontend.h"
67 #include "InspectorPageAgent.h"
68 #include "InspectorState.h"
69 #include "InstrumentingAgents.h"
71 #include "MutationEvent.h"
75 #include "Pasteboard.h"
76 #include "RenderStyle.h"
77 #include "RenderStyleConstants.h"
78 #include "ScriptEventListener.h"
79 #include "StyleSheetList.h"
83 #include "XPathResult.h"
88 #include <wtf/text/CString.h>
89 #include <wtf/text/WTFString.h>
90 #include <wtf/HashSet.h>
91 #include <wtf/ListHashSet.h>
92 #include <wtf/OwnPtr.h>
93 #include <wtf/Vector.h>
97 namespace DOMAgentState {
98 static const char documentRequested[] = "documentRequested";
101 static Color parseColor(const RefPtr<InspectorObject>* colorObject)
103 if (!colorObject || !(*colorObject))
104 return Color::transparent;
109 bool success = (*colorObject)->getNumber("r", &r);
110 success |= (*colorObject)->getNumber("g", &g);
111 success |= (*colorObject)->getNumber("b", &b);
113 return Color::transparent;
116 success = (*colorObject)->getNumber("a", &a);
118 return Color(r, g, b);
120 // Clamp alpha to the [0..1] range.
126 return Color(r, g, b, static_cast<int>(a * 255));
129 static Color parseConfigColor(const String& fieldName, InspectorObject* configObject)
131 const RefPtr<InspectorObject> colorObject = configObject->getObject(fieldName);
132 return parseColor(&colorObject);
137 virtual void match(ListHashSet<Node*>& resultCollector) = 0;
138 virtual ~MatchJob() { }
141 MatchJob(Document* document, const String& query)
142 : m_document(document)
145 void addNodesToResults(PassRefPtr<NodeList> nodes, ListHashSet<Node*>& resultCollector)
147 for (unsigned i = 0; nodes && i < nodes->length(); ++i)
148 resultCollector.add(nodes->item(i));
151 RefPtr<Document> m_document;
155 class RevalidateStyleAttributeTask {
157 RevalidateStyleAttributeTask(InspectorDOMAgent*);
158 void scheduleFor(Element*);
159 void reset() { m_timer.stop(); }
160 void onTimer(Timer<RevalidateStyleAttributeTask>*);
163 InspectorDOMAgent* m_domAgent;
164 Timer<RevalidateStyleAttributeTask> m_timer;
165 HashSet<RefPtr<Element> > m_elements;
170 class MatchExactIdJob : public WebCore::MatchJob {
172 MatchExactIdJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
173 virtual ~MatchExactIdJob() { }
176 virtual void match(ListHashSet<Node*>& resultCollector)
178 if (m_query.isEmpty())
181 Element* element = m_document->getElementById(m_query);
183 resultCollector.add(element);
187 class MatchExactClassNamesJob : public WebCore::MatchJob {
189 MatchExactClassNamesJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
190 virtual ~MatchExactClassNamesJob() { }
192 virtual void match(ListHashSet<Node*>& resultCollector)
194 if (!m_query.isEmpty())
195 addNodesToResults(m_document->getElementsByClassName(m_query), resultCollector);
199 class MatchExactTagNamesJob : public WebCore::MatchJob {
201 MatchExactTagNamesJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
202 virtual ~MatchExactTagNamesJob() { }
204 virtual void match(ListHashSet<Node*>& resultCollector)
206 if (!m_query.isEmpty())
207 addNodesToResults(m_document->getElementsByName(m_query), resultCollector);
211 class MatchQuerySelectorAllJob : public WebCore::MatchJob {
213 MatchQuerySelectorAllJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
214 virtual ~MatchQuerySelectorAllJob() { }
216 virtual void match(ListHashSet<Node*>& resultCollector)
218 if (m_query.isEmpty())
221 ExceptionCode ec = 0;
222 RefPtr<NodeList> list = m_document->querySelectorAll(m_query, ec);
224 addNodesToResults(list, resultCollector);
228 class MatchXPathJob : public WebCore::MatchJob {
230 MatchXPathJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
231 virtual ~MatchXPathJob() { }
233 virtual void match(ListHashSet<Node*>& resultCollector)
236 if (m_query.isEmpty())
239 ExceptionCode ec = 0;
240 RefPtr<XPathResult> result = m_document->evaluate(m_query, m_document.get(), 0, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, 0, ec);
244 unsigned long size = result->snapshotLength(ec);
245 for (unsigned long i = 0; !ec && i < size; ++i) {
246 Node* node = result->snapshotItem(i, ec);
250 if (node->nodeType() == Node::ATTRIBUTE_NODE)
251 node = static_cast<Attr*>(node)->ownerElement();
252 resultCollector.add(node);
255 UNUSED_PARAM(resultCollector);
260 class MatchPlainTextJob : public MatchXPathJob {
262 MatchPlainTextJob(Document* document, const String& query) : MatchXPathJob(document, query)
264 m_query = "//text()[contains(., '" + m_query + "')] | //comment()[contains(., '" + m_query + "')]";
266 virtual ~MatchPlainTextJob() { }
271 RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent)
272 : m_domAgent(domAgent)
273 , m_timer(this, &RevalidateStyleAttributeTask::onTimer)
277 void RevalidateStyleAttributeTask::scheduleFor(Element* element)
279 m_elements.add(element);
280 if (!m_timer.isActive())
281 m_timer.startOneShot(0);
284 void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*)
286 // The timer is stopped on m_domAgent destruction, so this method will never be called after m_domAgent has been destroyed.
287 Vector<Element*> elements;
288 for (HashSet<RefPtr<Element> >::iterator it = m_elements.begin(), end = m_elements.end(); it != end; ++it)
289 elements.append(it->get());
290 m_domAgent->styleAttributeInvalidated(elements);
295 InspectorDOMAgent::InspectorDOMAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorClient* client, InspectorState* inspectorState, InjectedScriptManager* injectedScriptManager)
296 : m_instrumentingAgents(instrumentingAgents)
297 , m_pageAgent(pageAgent)
299 , m_inspectorState(inspectorState)
300 , m_injectedScriptManager(injectedScriptManager)
304 , m_matchJobsTimer(this, &InspectorDOMAgent::onMatchJobsTimer)
305 , m_searchingForNode(false)
309 InspectorDOMAgent::~InspectorDOMAgent()
312 ASSERT(!m_highlightData || (!m_highlightData->node && !m_highlightData->rect));
313 ASSERT(!m_searchingForNode);
316 void InspectorDOMAgent::setFrontend(InspectorFrontend* frontend)
319 m_frontend = frontend->dom();
320 m_instrumentingAgents->setInspectorDOMAgent(this);
321 m_document = m_pageAgent->mainFrame()->document();
327 void InspectorDOMAgent::clearFrontend()
330 setSearchingForNode(false, 0);
333 hideHighlight(&error);
336 m_instrumentingAgents->setInspectorDOMAgent(0);
337 m_inspectorState->setBoolean(DOMAgentState::documentRequested, false);
341 void InspectorDOMAgent::restore()
343 // Reset document to avoid early return from setDocument.
345 setDocument(m_pageAgent->mainFrame()->document());
348 Vector<Document*> InspectorDOMAgent::documents()
350 Vector<Document*> result;
351 for (Frame* frame = m_document->frame(); frame; frame = frame->tree()->traverseNext()) {
352 Document* document = frame->document();
355 result.append(document);
360 Node* InspectorDOMAgent::highlightedNode() const
362 return m_highlightData ? m_highlightData->node.get() : 0;
365 void InspectorDOMAgent::reset()
368 cancelSearch(&error);
370 if (m_revalidateStyleAttrTask)
371 m_revalidateStyleAttrTask->reset();
375 void InspectorDOMAgent::setDOMListener(DOMListener* listener)
377 m_domListener = listener;
380 void InspectorDOMAgent::setDocument(Document* doc)
382 if (doc == m_document.get())
389 if (!m_inspectorState->getBoolean(DOMAgentState::documentRequested))
392 // Immediately communicate 0 document or document that has finished loading.
393 if (!doc || !doc->parsing())
394 m_frontend->documentUpdated();
397 void InspectorDOMAgent::releaseDanglingNodes()
399 deleteAllValues(m_danglingNodeToIdMaps);
400 m_danglingNodeToIdMaps.clear();
403 int InspectorDOMAgent::bind(Node* node, NodeToIdMap* nodesMap)
405 int id = nodesMap->get(node);
409 nodesMap->set(node, id);
410 m_idToNode.set(id, node);
411 m_idToNodesMap.set(id, nodesMap);
415 void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap)
417 if (node->isFrameOwnerElement()) {
418 const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>(node);
420 m_domListener->didRemoveDocument(frameOwner->contentDocument());
423 int id = nodesMap->get(node);
426 m_idToNode.remove(id);
427 nodesMap->remove(node);
428 bool childrenRequested = m_childrenRequested.contains(id);
429 if (childrenRequested) {
430 // Unbind subtree known to client recursively.
431 m_childrenRequested.remove(id);
432 Node* child = innerFirstChild(node);
434 unbind(child, nodesMap);
435 child = innerNextSibling(child);
440 Node* InspectorDOMAgent::assertNode(ErrorString* errorString, int nodeId)
442 Node* node = nodeForId(nodeId);
444 *errorString = "Could not find node with given id";
450 Element* InspectorDOMAgent::assertElement(ErrorString* errorString, int nodeId)
452 Node* node = assertNode(errorString, nodeId);
456 if (node->nodeType() != Node::ELEMENT_NODE) {
457 *errorString = "Node is not an Element";
460 return toElement(node);
464 HTMLElement* InspectorDOMAgent::assertHTMLElement(ErrorString* errorString, int nodeId)
466 Element* element = assertElement(errorString, nodeId);
470 if (!element->isHTMLElement()) {
471 *errorString = "Node is not an HTML Element";
474 return toHTMLElement(element);
477 void InspectorDOMAgent::getDocument(ErrorString*, RefPtr<InspectorObject>* root)
479 m_inspectorState->setBoolean(DOMAgentState::documentRequested, true);
484 // Reset backend state.
485 RefPtr<Document> doc = m_document;
489 *root = buildObjectForNode(m_document.get(), 2, &m_documentNodeToIdMap);
492 void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId)
494 Node* node = nodeForId(nodeId);
495 if (!node || (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE && node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE))
497 if (m_childrenRequested.contains(nodeId))
500 NodeToIdMap* nodeMap = m_idToNodesMap.get(nodeId);
501 RefPtr<InspectorArray> children = buildArrayForContainerChildren(node, 1, nodeMap);
502 m_frontend->setChildNodes(nodeId, children.release());
505 void InspectorDOMAgent::discardBindings()
507 m_documentNodeToIdMap.clear();
509 releaseDanglingNodes();
510 m_childrenRequested.clear();
513 Node* InspectorDOMAgent::nodeForId(int id)
518 HashMap<int, Node*>::iterator it = m_idToNode.find(id);
519 if (it != m_idToNode.end())
524 void InspectorDOMAgent::requestChildNodes(ErrorString*, int nodeId)
526 pushChildNodesToFrontend(nodeId);
529 void InspectorDOMAgent::querySelector(ErrorString* errorString, int nodeId, const String& selectors, int* elementId)
532 Node* node = assertNode(errorString, nodeId);
536 ExceptionCode ec = 0;
537 RefPtr<Element> element = node->querySelector(selectors, ec);
539 *errorString = "DOM Error while querying";
544 *elementId = pushNodePathToFrontend(element.get());
547 void InspectorDOMAgent::querySelectorAll(ErrorString* errorString, int nodeId, const String& selectors, RefPtr<InspectorArray>* result)
549 Node* node = assertNode(errorString, nodeId);
553 ExceptionCode ec = 0;
554 RefPtr<NodeList> nodes = node->querySelectorAll(selectors, ec);
556 *errorString = "DOM Error while querying";
560 for (unsigned i = 0; i < nodes->length(); ++i)
561 (*result)->pushNumber(pushNodePathToFrontend(nodes->item(i)));
564 int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush)
566 ASSERT(nodeToPush); // Invalid input
570 if (!m_documentNodeToIdMap.contains(m_document))
573 // Return id in case the node is known.
574 int result = m_documentNodeToIdMap.get(nodeToPush);
578 Node* node = nodeToPush;
580 NodeToIdMap* danglingMap = 0;
583 Node* parent = innerParentNode(node);
585 // Node being pushed is detached -> push subtree root.
586 danglingMap = new NodeToIdMap();
587 m_danglingNodeToIdMaps.append(danglingMap);
588 RefPtr<InspectorArray> children = InspectorArray::create();
589 children->pushObject(buildObjectForNode(node, 0, danglingMap));
590 m_frontend->setChildNodes(0, children);
594 if (m_documentNodeToIdMap.get(parent))
601 NodeToIdMap* map = danglingMap ? danglingMap : &m_documentNodeToIdMap;
602 for (int i = path.size() - 1; i >= 0; --i) {
603 int nodeId = map->get(path.at(i));
605 pushChildNodesToFrontend(nodeId);
607 return map->get(nodeToPush);
610 int InspectorDOMAgent::boundNodeId(Node* node)
612 return m_documentNodeToIdMap.get(node);
615 void InspectorDOMAgent::setAttributeValue(ErrorString* errorString, int elementId, const String& name, const String& value)
617 Element* element = assertElement(errorString, elementId);
621 ExceptionCode ec = 0;
622 element->setAttribute(name, value, ec);
624 *errorString = "Internal error: could not set attribute value.";
627 void InspectorDOMAgent::setAttributesText(ErrorString* errorString, int elementId, const String& text, const String* const name)
629 Element* element = assertElement(errorString, elementId);
633 ExceptionCode ec = 0;
634 RefPtr<Element> parsedElement = element->document()->createElement("span", ec);
636 *errorString = "Internal error: could not set attribute value.";
640 toHTMLElement(parsedElement.get())->setInnerHTML("<span " + text + "></span>", ec);
642 *errorString = "Could not parse value as attributes.";
646 Node* child = parsedElement->firstChild();
648 *errorString = "Could not parse value as attributes.";
652 const NamedNodeMap* attrMap = toHTMLElement(child)->attributes(true);
653 if (!attrMap && name) {
654 element->removeAttribute(*name, ec);
656 *errorString = "Could not remove attribute.";
660 bool foundOriginalAttribute = false;
661 unsigned numAttrs = attrMap->length();
662 for (unsigned i = 0; i < numAttrs; ++i) {
663 // Add attribute pair
664 const Attribute *attribute = attrMap->attributeItem(i);
665 foundOriginalAttribute = foundOriginalAttribute || (name && attribute->name().toString() == *name);
666 element->setAttribute(attribute->name(), attribute->value(), ec);
668 *errorString = "Internal error: could not set attribute value.";
673 if (!foundOriginalAttribute && name) {
674 element->removeAttribute(*name, ec);
676 *errorString = "Could not remove attribute.";
681 void InspectorDOMAgent::removeAttribute(ErrorString* errorString, int elementId, const String& name)
683 Element* element = assertElement(errorString, elementId);
685 ExceptionCode ec = 0;
686 element->removeAttribute(name, ec);
688 *errorString = "Exception while removing attribute";
692 void InspectorDOMAgent::removeNode(ErrorString* errorString, int nodeId)
694 Node* node = assertNode(errorString, nodeId);
698 ContainerNode* parentNode = node->parentNode();
700 *errorString = "Can not remove detached node";
704 ExceptionCode ec = 0;
705 parentNode->removeChild(node, ec);
707 *errorString = "Could not remove node due to DOM exception";
710 void InspectorDOMAgent::setNodeName(ErrorString*, int nodeId, const String& tagName, int* newId)
714 Node* oldNode = nodeForId(nodeId);
715 if (!oldNode || !oldNode->isElementNode())
718 ExceptionCode ec = 0;
719 RefPtr<Element> newElem = oldNode->document()->createElement(tagName, ec);
723 // Copy over the original node's attributes.
724 Element* oldElem = static_cast<Element*>(oldNode);
725 if (oldElem->attributes())
726 newElem->attributes()->setAttributes(*(oldElem->attributes(true)));
728 // Copy over the original node's children.
730 while ((child = oldNode->firstChild()))
731 newElem->appendChild(child, ec);
733 // Replace the old node with the new node
734 ContainerNode* parent = oldNode->parentNode();
735 parent->insertBefore(newElem, oldNode->nextSibling(), ec);
736 parent->removeChild(oldNode, ec);
741 *newId = pushNodePathToFrontend(newElem.get());
742 if (m_childrenRequested.contains(nodeId))
743 pushChildNodesToFrontend(*newId);
746 void InspectorDOMAgent::getOuterHTML(ErrorString* errorString, int nodeId, WTF::String* outerHTML)
748 HTMLElement* element = assertHTMLElement(errorString, nodeId);
750 *outerHTML = element->outerHTML();
753 void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const String& outerHTML, int* newId)
755 HTMLElement* htmlElement = assertHTMLElement(errorString, nodeId);
759 bool requiresTotalUpdate = htmlElement->tagName() == "HTML" || htmlElement->tagName() == "BODY" || htmlElement->tagName() == "HEAD";
761 bool childrenRequested = m_childrenRequested.contains(nodeId);
762 Node* previousSibling = htmlElement->previousSibling();
763 ContainerNode* parentNode = htmlElement->parentNode();
765 ExceptionCode ec = 0;
766 htmlElement->setOuterHTML(outerHTML, ec);
770 if (requiresTotalUpdate) {
771 RefPtr<Document> document = m_document;
773 setDocument(document.get());
778 Node* newNode = previousSibling ? previousSibling->nextSibling() : parentNode->firstChild();
780 // The only child node has been deleted.
785 *newId = pushNodePathToFrontend(newNode);
786 if (childrenRequested)
787 pushChildNodesToFrontend(*newId);
790 void InspectorDOMAgent::setNodeValue(ErrorString* errorString, int nodeId, const String& value)
792 Node* node = assertNode(errorString, nodeId);
796 if (node->nodeType() != Node::TEXT_NODE) {
797 *errorString = "Can only set value of text nodes";
801 Text* textNode = static_cast<Text*>(node);
802 ExceptionCode ec = 0;
803 textNode->replaceWholeText(value, ec);
805 *errorString = "DOM Error while setting the node value";
808 void InspectorDOMAgent::getEventListenersForNode(ErrorString*, int nodeId, RefPtr<InspectorArray>* listenersArray)
810 Node* node = nodeForId(nodeId);
813 // Quick break if a null node or no listeners at all
814 if (!node || !(d = node->eventTargetData()))
817 // Get the list of event types this Node is concerned with
818 Vector<AtomicString> eventTypes;
819 const EventListenerMap& listenerMap = d->eventListenerMap;
820 EventListenerMap::const_iterator end = listenerMap.end();
821 for (EventListenerMap::const_iterator iter = listenerMap.begin(); iter != end; ++iter)
822 eventTypes.append(iter->first);
824 // Quick break if no useful listeners
825 size_t eventTypesLength = eventTypes.size();
826 if (!eventTypesLength)
829 // The Node's Ancestors (not including self)
830 Vector<ContainerNode*> ancestors;
831 for (ContainerNode* ancestor = node->parentOrHostNode(); ancestor; ancestor = ancestor->parentOrHostNode())
832 ancestors.append(ancestor);
834 // Nodes and their Listeners for the concerned event types (order is top to bottom)
835 Vector<EventListenerInfo> eventInformation;
836 for (size_t i = ancestors.size(); i; --i) {
837 ContainerNode* ancestor = ancestors[i - 1];
838 for (size_t j = 0; j < eventTypesLength; ++j) {
839 AtomicString& type = eventTypes[j];
840 if (ancestor->hasEventListeners(type))
841 eventInformation.append(EventListenerInfo(ancestor, type, ancestor->getEventListeners(type)));
845 // Insert the Current Node at the end of that list (last in capturing, first in bubbling)
846 for (size_t i = 0; i < eventTypesLength; ++i) {
847 const AtomicString& type = eventTypes[i];
848 eventInformation.append(EventListenerInfo(node, type, node->getEventListeners(type)));
851 // Get Capturing Listeners (in this order)
852 size_t eventInformationLength = eventInformation.size();
853 for (size_t i = 0; i < eventInformationLength; ++i) {
854 const EventListenerInfo& info = eventInformation[i];
855 const EventListenerVector& vector = info.eventListenerVector;
856 for (size_t j = 0; j < vector.size(); ++j) {
857 const RegisteredEventListener& listener = vector[j];
858 if (listener.useCapture)
859 (*listenersArray)->pushObject(buildObjectForEventListener(listener, info.eventType, info.node));
863 // Get Bubbling Listeners (reverse order)
864 for (size_t i = eventInformationLength; i; --i) {
865 const EventListenerInfo& info = eventInformation[i - 1];
866 const EventListenerVector& vector = info.eventListenerVector;
867 for (size_t j = 0; j < vector.size(); ++j) {
868 const RegisteredEventListener& listener = vector[j];
869 if (!listener.useCapture)
870 (*listenersArray)->pushObject(buildObjectForEventListener(listener, info.eventType, info.node));
875 void InspectorDOMAgent::performSearch(ErrorString* error, const String& whitespaceTrimmedQuery, const bool* const runSynchronously)
877 // FIXME: Few things are missing here:
878 // 1) Search works with node granularity - number of matches within node is not calculated.
879 // 2) There is no need to push all search results to the front-end at a time, pushing next / previous result
882 unsigned queryLength = whitespaceTrimmedQuery.length();
883 bool startTagFound = !whitespaceTrimmedQuery.find('<');
884 bool endTagFound = whitespaceTrimmedQuery.reverseFind('>') + 1 == queryLength;
886 String tagNameQuery = whitespaceTrimmedQuery;
887 if (startTagFound || endTagFound)
888 tagNameQuery = tagNameQuery.substring(startTagFound ? 1 : 0, endTagFound ? queryLength - 1 : queryLength);
889 if (!Document::isValidName(tagNameQuery))
892 String attributeNameQuery = whitespaceTrimmedQuery;
893 if (!Document::isValidName(attributeNameQuery))
894 attributeNameQuery = "";
896 String escapedQuery = whitespaceTrimmedQuery;
897 escapedQuery.replace("'", "\\'");
898 String escapedTagNameQuery = tagNameQuery;
899 escapedTagNameQuery.replace("'", "\\'");
901 // Clear pending jobs.
904 // Find all frames, iframes and object elements to search their documents.
905 Vector<Document*> docs = documents();
906 for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
907 Document* document = *it;
909 if (!tagNameQuery.isEmpty() && startTagFound && endTagFound) {
910 m_pendingMatchJobs.append(new MatchExactTagNamesJob(document, tagNameQuery));
911 m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
915 if (!tagNameQuery.isEmpty() && startTagFound) {
916 m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[starts-with(name(), '" + escapedTagNameQuery + "')]"));
917 m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
921 if (!tagNameQuery.isEmpty() && endTagFound) {
922 // FIXME: we should have a matchEndOfTagNames search function if endTagFound is true but not startTagFound.
923 // This requires ends-with() support in XPath, WebKit only supports starts-with() and contains().
924 m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(name(), '" + escapedTagNameQuery + "')]"));
925 m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
929 bool matchesEveryNode = whitespaceTrimmedQuery == "//*" || whitespaceTrimmedQuery == "*";
930 if (matchesEveryNode) {
931 // These queries will match every node. Matching everything isn't useful and can be slow for large pages,
932 // so limit the search functions list to plain text and attribute matching for these.
933 m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(@*, '" + escapedQuery + "')]"));
934 m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
938 m_pendingMatchJobs.append(new MatchExactIdJob(document, whitespaceTrimmedQuery));
939 m_pendingMatchJobs.append(new MatchExactClassNamesJob(document, whitespaceTrimmedQuery));
940 m_pendingMatchJobs.append(new MatchExactTagNamesJob(document, tagNameQuery));
941 m_pendingMatchJobs.append(new MatchQuerySelectorAllJob(document, "[" + attributeNameQuery + "]"));
942 m_pendingMatchJobs.append(new MatchQuerySelectorAllJob(document, whitespaceTrimmedQuery));
943 m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(@*, '" + escapedQuery + "')]"));
944 if (!tagNameQuery.isEmpty())
945 m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(name(), '" + escapedTagNameQuery + "')]"));
946 m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
947 m_pendingMatchJobs.append(new MatchXPathJob(document, whitespaceTrimmedQuery));
950 if (runSynchronously && *runSynchronously) {
952 ListHashSet<Node*> resultCollector;
953 for (Deque<MatchJob*>::iterator it = m_pendingMatchJobs.begin(); it != m_pendingMatchJobs.end(); ++it)
954 (*it)->match(resultCollector);
955 reportNodesAsSearchResults(resultCollector);
959 m_matchJobsTimer.startOneShot(0);
962 void InspectorDOMAgent::cancelSearch(ErrorString*)
964 if (m_matchJobsTimer.isActive())
965 m_matchJobsTimer.stop();
966 deleteAllValues(m_pendingMatchJobs);
967 m_pendingMatchJobs.clear();
968 m_searchResults.clear();
971 bool InspectorDOMAgent::handleMousePress()
973 if (!m_searchingForNode)
976 if (m_highlightData && m_highlightData->node) {
977 RefPtr<Node> node = m_highlightData->node;
978 setSearchingForNode(false, 0);
984 void InspectorDOMAgent::inspect(Node* node)
986 if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
987 node = node->parentNode();
988 m_nodeToFocus = node;
993 void InspectorDOMAgent::focusNode()
998 ASSERT(m_nodeToFocus);
1000 RefPtr<Node> node = m_nodeToFocus.get();
1003 Document* document = node->ownerDocument();
1006 Frame* frame = document->frame();
1010 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
1011 if (injectedScript.hasNoValue())
1014 injectedScript.inspectNode(node.get());
1017 void InspectorDOMAgent::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
1019 if (!m_searchingForNode || !m_highlightData)
1022 Node* node = result.innerNode();
1023 while (node && node->nodeType() == Node::TEXT_NODE)
1024 node = node->parentNode();
1026 m_highlightData->node = node;
1031 void InspectorDOMAgent::setSearchingForNode(bool enabled, InspectorObject* highlightConfig)
1033 if (m_searchingForNode == enabled)
1035 m_searchingForNode = enabled;
1037 setHighlightDataFromConfig(highlightConfig);
1040 hideHighlight(&error);
1041 m_highlightData.clear();
1045 void InspectorDOMAgent::setInspectModeEnabled(ErrorString*, bool enabled, const RefPtr<InspectorObject>* highlightConfig)
1047 setSearchingForNode(enabled, highlightConfig ? highlightConfig->get() : 0);
1050 bool InspectorDOMAgent::setHighlightDataFromConfig(InspectorObject* highlightConfig)
1052 if (!highlightConfig) {
1053 m_highlightData.clear();
1057 m_highlightData = adoptPtr(new HighlightData());
1058 bool showInfo = false; // Default: false (do not show a tooltip).
1059 highlightConfig->getBoolean("showInfo", &showInfo);
1060 m_highlightData->showInfo = showInfo;
1061 m_highlightData->content = parseConfigColor("contentColor", highlightConfig);
1062 m_highlightData->contentOutline = parseConfigColor("contentOutlineColor", highlightConfig);
1063 m_highlightData->padding = parseConfigColor("paddingColor", highlightConfig);
1064 m_highlightData->paddingOutline = parseConfigColor("paddingOutlineColor", highlightConfig);
1065 m_highlightData->border = parseConfigColor("borderColor", highlightConfig);
1066 m_highlightData->borderOutline = parseConfigColor("borderOutlineColor", highlightConfig);
1067 m_highlightData->margin = parseConfigColor("marginColor", highlightConfig);
1068 m_highlightData->marginOutline = parseConfigColor("marginOutlineColor", highlightConfig);
1072 void InspectorDOMAgent::highlight()
1074 // This method requires m_highlightData to have been filled in by its client.
1075 ASSERT(m_highlightData);
1076 m_client->highlight();
1079 void InspectorDOMAgent::highlightRect(ErrorString*, int x, int y, int width, int height, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor)
1081 m_highlightData = adoptPtr(new HighlightData());
1082 m_highlightData->rect = adoptPtr(new IntRect(x, y, width, height));
1083 m_highlightData->content = parseColor(color);
1084 m_highlightData->contentOutline = parseColor(outlineColor);
1085 m_client->highlight();
1088 void InspectorDOMAgent::highlightNode(
1091 const RefPtr<InspectorObject> highlightConfig)
1093 if (Node* node = nodeForId(nodeId)) {
1094 if (setHighlightDataFromConfig(highlightConfig.get())) {
1095 m_highlightData->node = node;
1101 void InspectorDOMAgent::highlightFrame(
1103 const String& frameId,
1104 const RefPtr<InspectorObject>* color,
1105 const RefPtr<InspectorObject>* outlineColor)
1107 Frame* frame = m_pageAgent->frameForId(frameId);
1108 if (frame && frame->ownerElement()) {
1109 m_highlightData = adoptPtr(new HighlightData());
1110 m_highlightData->node = frame->ownerElement();
1111 m_highlightData->showInfo = true; // Always show tooltips for frames.
1112 m_highlightData->content = parseColor(color);
1113 m_highlightData->contentOutline = parseColor(outlineColor);
1118 void InspectorDOMAgent::hideHighlight(ErrorString*)
1120 if (m_highlightData) {
1121 m_highlightData->node.clear();
1122 m_highlightData->rect.clear();
1124 m_client->hideHighlight();
1127 void InspectorDOMAgent::moveTo(ErrorString* error, int nodeId, int targetElementId, const int* const anchorNodeId, int* newNodeId)
1129 Node* node = assertNode(error, nodeId);
1133 Element* targetElement = assertElement(error, targetElementId);
1137 Node* anchorNode = 0;
1138 if (anchorNodeId && *anchorNodeId) {
1139 anchorNode = assertNode(error, *anchorNodeId);
1142 if (anchorNode->parentNode() != targetElement) {
1143 *error = "Anchor node must be child of the target element.";
1148 ExceptionCode ec = 0;
1149 bool success = targetElement->insertBefore(node, anchorNode, ec);
1150 if (ec || !success) {
1151 *error = "Could not drop node.";
1154 *newNodeId = pushNodePathToFrontend(node);
1157 void InspectorDOMAgent::resolveNode(ErrorString* error, int nodeId, const String* const objectGroup, RefPtr<InspectorObject>* result)
1159 String objectGroupName = objectGroup ? *objectGroup : "";
1160 Node* node = nodeForId(nodeId);
1162 *error = "No node with given id found.";
1165 *result = resolveNode(node, objectGroupName);
1168 void InspectorDOMAgent::getAttributes(ErrorString* errorString, int nodeId, RefPtr<InspectorArray>* result)
1170 Element* element = assertElement(errorString, nodeId);
1174 *result = buildArrayForElementAttributes(element);
1177 void InspectorDOMAgent::requestNode(ErrorString*, const String& objectId, int* nodeId)
1179 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
1180 Node* node = injectedScript.nodeForObjectId(objectId);
1182 *nodeId = pushNodePathToFrontend(node);
1187 String InspectorDOMAgent::documentURLString(Document* document) const
1189 if (!document || document->url().isNull())
1191 return document->url().string();
1194 PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap)
1196 RefPtr<InspectorObject> value = InspectorObject::create();
1198 int id = bind(node, nodesMap);
1203 switch (node->nodeType()) {
1204 case Node::TEXT_NODE:
1205 case Node::COMMENT_NODE:
1206 case Node::CDATA_SECTION_NODE:
1207 nodeValue = node->nodeValue();
1209 case Node::ATTRIBUTE_NODE:
1210 localName = node->localName();
1212 case Node::DOCUMENT_FRAGMENT_NODE:
1214 case Node::DOCUMENT_NODE:
1215 case Node::ELEMENT_NODE:
1217 nodeName = node->nodeName();
1218 localName = node->localName();
1222 value->setNumber("nodeId", id);
1223 value->setNumber("nodeType", node->nodeType());
1224 value->setString("nodeName", nodeName);
1225 value->setString("localName", localName);
1226 value->setString("nodeValue", nodeValue);
1228 if (node->nodeType() == Node::ELEMENT_NODE || node->nodeType() == Node::DOCUMENT_NODE || node->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
1229 int nodeCount = innerChildNodeCount(node);
1230 value->setNumber("childNodeCount", nodeCount);
1231 RefPtr<InspectorArray> children = buildArrayForContainerChildren(node, depth, nodesMap);
1232 if (children->length() > 0)
1233 value->setArray("children", children.release());
1235 if (node->nodeType() == Node::ELEMENT_NODE) {
1236 Element* element = static_cast<Element*>(node);
1237 value->setArray("attributes", buildArrayForElementAttributes(element));
1238 if (node->isFrameOwnerElement()) {
1239 HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node);
1240 value->setString("documentURL", documentURLString(frameOwner->contentDocument()));
1242 } else if (node->nodeType() == Node::DOCUMENT_NODE) {
1243 Document* document = static_cast<Document*>(node);
1244 value->setString("documentURL", documentURLString(document));
1245 value->setString("xmlVersion", document->xmlVersion());
1247 } else if (node->nodeType() == Node::DOCUMENT_TYPE_NODE) {
1248 DocumentType* docType = static_cast<DocumentType*>(node);
1249 value->setString("publicId", docType->publicId());
1250 value->setString("systemId", docType->systemId());
1251 value->setString("internalSubset", docType->internalSubset());
1252 } else if (node->nodeType() == Node::ATTRIBUTE_NODE) {
1253 Attr* attribute = static_cast<Attr*>(node);
1254 value->setString("name", attribute->name());
1255 value->setString("value", attribute->value());
1257 return value.release();
1260 PassRefPtr<InspectorArray> InspectorDOMAgent::buildArrayForElementAttributes(Element* element)
1262 RefPtr<InspectorArray> attributesValue = InspectorArray::create();
1263 // Go through all attributes and serialize them.
1264 const NamedNodeMap* attrMap = element->attributes(true);
1266 return attributesValue.release();
1267 unsigned numAttrs = attrMap->length();
1268 for (unsigned i = 0; i < numAttrs; ++i) {
1269 // Add attribute pair
1270 const Attribute *attribute = attrMap->attributeItem(i);
1271 attributesValue->pushString(attribute->name().toString());
1272 attributesValue->pushString(attribute->value());
1274 return attributesValue.release();
1277 PassRefPtr<InspectorArray> InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap)
1279 RefPtr<InspectorArray> children = InspectorArray::create();
1280 Node* child = innerFirstChild(container);
1283 // Special-case the only text child - pretend that container's children have been requested.
1284 if (child && child->nodeType() == Node::TEXT_NODE && !innerNextSibling(child))
1285 return buildArrayForContainerChildren(container, 1, nodesMap);
1286 return children.release();
1290 m_childrenRequested.add(bind(container, nodesMap));
1293 children->pushObject(buildObjectForNode(child, depth, nodesMap));
1294 child = innerNextSibling(child);
1296 return children.release();
1299 PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node)
1301 RefPtr<EventListener> eventListener = registeredEventListener.listener;
1302 RefPtr<InspectorObject> value = InspectorObject::create();
1303 value->setString("type", eventType);
1304 value->setBoolean("useCapture", registeredEventListener.useCapture);
1305 value->setBoolean("isAttribute", eventListener->isAttribute());
1306 value->setNumber("nodeId", pushNodePathToFrontend(node));
1307 value->setString("handlerBody", eventListenerHandlerBody(node->document(), eventListener.get()));
1310 if (eventListenerHandlerLocation(node->document(), eventListener.get(), sourceName, lineNumber)) {
1311 RefPtr<InspectorObject> location = InspectorObject::create();
1312 location->setString("scriptId", sourceName);
1313 location->setNumber("lineNumber", lineNumber);
1314 value->setObject("location", location);
1316 return value.release();
1319 Node* InspectorDOMAgent::innerFirstChild(Node* node)
1321 if (node->isFrameOwnerElement()) {
1322 HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node);
1323 Document* doc = frameOwner->contentDocument();
1325 return doc->firstChild();
1327 node = node->firstChild();
1328 while (isWhitespace(node))
1329 node = node->nextSibling();
1333 Node* InspectorDOMAgent::innerNextSibling(Node* node)
1336 node = node->nextSibling();
1337 } while (isWhitespace(node));
1341 Node* InspectorDOMAgent::innerPreviousSibling(Node* node)
1344 node = node->previousSibling();
1345 } while (isWhitespace(node));
1349 unsigned InspectorDOMAgent::innerChildNodeCount(Node* node)
1352 Node* child = innerFirstChild(node);
1355 child = innerNextSibling(child);
1360 Node* InspectorDOMAgent::innerParentNode(Node* node)
1362 ContainerNode* parent = node->parentNode();
1363 if (parent && parent->isDocumentNode())
1364 return static_cast<Document*>(parent)->ownerElement();
1368 bool InspectorDOMAgent::isWhitespace(Node* node)
1370 //TODO: pull ignoreWhitespace setting from the frontend and use here.
1371 return node && node->nodeType() == Node::TEXT_NODE && node->nodeValue().stripWhiteSpace().length() == 0;
1374 void InspectorDOMAgent::mainFrameDOMContentLoaded()
1376 // Re-push document once it is loaded.
1378 if (m_inspectorState->getBoolean(DOMAgentState::documentRequested))
1379 m_frontend->documentUpdated();
1382 void InspectorDOMAgent::loadEventFired(Document* document)
1384 Element* frameOwner = document->ownerElement();
1388 int frameOwnerId = m_documentNodeToIdMap.get(frameOwner);
1392 if (!m_childrenRequested.contains(frameOwnerId)) {
1393 // No children are mapped yet -> only notify on changes of hasChildren.
1394 m_frontend->childNodeCountUpdated(frameOwnerId, innerChildNodeCount(frameOwner));
1396 // Re-add frame owner element together with its new children.
1397 int parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner));
1398 m_frontend->childNodeRemoved(parentId, frameOwnerId);
1399 RefPtr<InspectorObject> value = buildObjectForNode(frameOwner, 0, &m_documentNodeToIdMap);
1400 Node* previousSibling = innerPreviousSibling(frameOwner);
1401 int prevId = previousSibling ? m_documentNodeToIdMap.get(previousSibling) : 0;
1402 m_frontend->childNodeInserted(parentId, prevId, value.release());
1403 // Invalidate children requested flag for the element.
1404 m_childrenRequested.remove(m_childrenRequested.find(frameOwnerId));
1408 void InspectorDOMAgent::didInsertDOMNode(Node* node)
1410 if (isWhitespace(node))
1413 // We could be attaching existing subtree. Forget the bindings.
1414 unbind(node, &m_documentNodeToIdMap);
1416 ContainerNode* parent = node->parentNode();
1417 int parentId = m_documentNodeToIdMap.get(parent);
1418 // Return if parent is not mapped yet.
1422 if (!m_childrenRequested.contains(parentId)) {
1423 // No children are mapped yet -> only notify on changes of hasChildren.
1424 m_frontend->childNodeCountUpdated(parentId, innerChildNodeCount(parent));
1426 // Children have been requested -> return value of a new child.
1427 Node* prevSibling = innerPreviousSibling(node);
1428 int prevId = prevSibling ? m_documentNodeToIdMap.get(prevSibling) : 0;
1429 RefPtr<InspectorObject> value = buildObjectForNode(node, 0, &m_documentNodeToIdMap);
1430 m_frontend->childNodeInserted(parentId, prevId, value.release());
1434 void InspectorDOMAgent::didRemoveDOMNode(Node* node)
1436 if (isWhitespace(node))
1439 ContainerNode* parent = node->parentNode();
1440 int parentId = m_documentNodeToIdMap.get(parent);
1441 // If parent is not mapped yet -> ignore the event.
1446 m_domListener->didRemoveDOMNode(node);
1448 if (!m_childrenRequested.contains(parentId)) {
1449 // No children are mapped yet -> only notify on changes of hasChildren.
1450 if (innerChildNodeCount(parent) == 1)
1451 m_frontend->childNodeCountUpdated(parentId, 0);
1453 m_frontend->childNodeRemoved(parentId, m_documentNodeToIdMap.get(node));
1454 unbind(node, &m_documentNodeToIdMap);
1457 void InspectorDOMAgent::didModifyDOMAttr(Element* element)
1459 int id = boundNodeId(element);
1460 // If node is not mapped yet -> ignore the event.
1465 m_domListener->didModifyDOMAttr(element);
1467 m_frontend->attributesUpdated(id);
1470 void InspectorDOMAgent::styleAttributeInvalidated(const Vector<Element*>& elements)
1472 RefPtr<InspectorArray> nodeIds = InspectorArray::create();
1473 for (unsigned i = 0, size = elements.size(); i < size; ++i) {
1474 Element* element = elements.at(i);
1475 int id = boundNodeId(element);
1476 // If node is not mapped yet -> ignore the event.
1481 m_domListener->didModifyDOMAttr(element);
1482 nodeIds->pushNumber(id);
1484 m_frontend->inlineStyleInvalidated(nodeIds.release());
1487 void InspectorDOMAgent::characterDataModified(CharacterData* characterData)
1489 int id = m_documentNodeToIdMap.get(characterData);
1492 m_frontend->characterDataModified(id, characterData->data());
1495 void InspectorDOMAgent::didInvalidateStyleAttr(Node* node)
1497 int id = m_documentNodeToIdMap.get(node);
1498 // If node is not mapped yet -> ignore the event.
1502 if (!m_revalidateStyleAttrTask)
1503 m_revalidateStyleAttrTask = adoptPtr(new RevalidateStyleAttributeTask(this));
1504 m_revalidateStyleAttrTask->scheduleFor(static_cast<Element*>(node));
1507 Node* InspectorDOMAgent::nodeForPath(const String& path)
1509 // The path is of form "1,HTML,2,BODY,1,DIV"
1513 Node* node = m_document.get();
1514 Vector<String> pathTokens;
1515 path.split(",", false, pathTokens);
1516 if (!pathTokens.size())
1518 for (size_t i = 0; i < pathTokens.size() - 1; i += 2) {
1519 bool success = true;
1520 unsigned childNumber = pathTokens[i].toUInt(&success);
1523 if (childNumber >= innerChildNodeCount(node))
1526 Node* child = innerFirstChild(node);
1527 String childName = pathTokens[i + 1];
1528 for (size_t j = 0; child && j < childNumber; ++j)
1529 child = innerNextSibling(child);
1531 if (!child || child->nodeName() != childName)
1538 void InspectorDOMAgent::onMatchJobsTimer(Timer<InspectorDOMAgent>*)
1540 if (!m_pendingMatchJobs.size()) {
1542 cancelSearch(&error);
1546 ListHashSet<Node*> resultCollector;
1547 MatchJob* job = m_pendingMatchJobs.takeFirst();
1548 job->match(resultCollector);
1551 reportNodesAsSearchResults(resultCollector);
1553 m_matchJobsTimer.startOneShot(0.025);
1556 void InspectorDOMAgent::reportNodesAsSearchResults(ListHashSet<Node*>& resultCollector)
1558 RefPtr<InspectorArray> nodeIds = InspectorArray::create();
1559 for (ListHashSet<Node*>::iterator it = resultCollector.begin(); it != resultCollector.end(); ++it) {
1560 if (m_searchResults.contains(*it))
1562 m_searchResults.add(*it);
1563 nodeIds->pushNumber(pushNodePathToFrontend(*it));
1565 m_frontend->searchResults(nodeIds.release());
1568 void InspectorDOMAgent::copyNode(ErrorString*, int nodeId)
1570 Node* node = nodeForId(nodeId);
1573 String markup = createMarkup(node);
1574 Pasteboard::generalPasteboard()->writePlainText(markup);
1577 void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString*, const String& path, int* nodeId)
1579 if (Node* node = nodeForPath(path))
1580 *nodeId = pushNodePathToFrontend(node);
1583 PassRefPtr<InspectorObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup)
1585 Document* document = node->isDocumentNode() ? node->document() : node->ownerDocument();
1586 Frame* frame = document ? document->frame() : 0;
1590 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
1591 if (injectedScript.hasNoValue())
1594 return injectedScript.wrapNode(node, objectGroup);
1597 void InspectorDOMAgent::drawHighlight(GraphicsContext& context) const
1599 if (!m_highlightData)
1602 DOMNodeHighlighter::drawHighlight(context, m_highlightData->node ? m_highlightData->node->document() : m_document.get(), m_highlightData.get());
1605 } // namespace WebCore
1607 #endif // ENABLE(INSPECTOR)