2011-03-29 Ilya Tikhonovsky <loislo@chromium.org>
[WebKit-https.git] / Source / WebCore / inspector / InspectorDOMAgent.cpp
1 /*
2  * Copyright (C) 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2009-2011 Google Inc. All rights reserved.
4  * Copyright (C) 2009 Joseph Pecoraro
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
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.
18  *
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.
29  */
30
31 #include "config.h"
32 #include "InspectorDOMAgent.h"
33
34 #if ENABLE(INSPECTOR)
35
36 #include "Attr.h"
37 #include "CSSComputedStyleDeclaration.h"
38 #include "CSSMutableStyleDeclaration.h"
39 #include "CSSPropertyNames.h"
40 #include "CSSPropertySourceData.h"
41 #include "CSSRule.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"
48 #include "Cookie.h"
49 #include "CookieJar.h"
50 #include "DOMNodeHighlighter.h"
51 #include "DOMWindow.h"
52 #include "Document.h"
53 #include "DocumentType.h"
54 #include "Event.h"
55 #include "EventContext.h"
56 #include "EventListener.h"
57 #include "EventNames.h"
58 #include "EventTarget.h"
59 #include "Frame.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 "InspectorResourceAgent.h"
68 #include "InspectorState.h"
69 #include "InstrumentingAgents.h"
70 #include "MutationEvent.h"
71 #include "Node.h"
72 #include "NodeList.h"
73 #include "Page.h"
74 #include "Pasteboard.h"
75 #include "PlatformString.h"
76 #include "RenderStyle.h"
77 #include "RenderStyleConstants.h"
78 #include "ScriptEventListener.h"
79 #include "StyleSheetList.h"
80 #include "Text.h"
81
82 #if ENABLE(XPATH)
83 #include "XPathResult.h"
84 #endif
85
86 #include "markup.h"
87
88 #include <wtf/text/CString.h>
89 #include <wtf/text/StringConcatenate.h>
90 #include <wtf/HashSet.h>
91 #include <wtf/ListHashSet.h>
92 #include <wtf/OwnPtr.h>
93 #include <wtf/Vector.h>
94 #include <wtf/text/AtomicString.h>
95
96 namespace WebCore {
97
98 namespace DOMAgentState {
99 static const char documentRequested[] = "documentRequested";
100 };
101
102 class MatchJob {
103 public:
104     virtual void match(ListHashSet<Node*>& resultCollector) = 0;
105     virtual ~MatchJob() { }
106
107 protected:
108     MatchJob(Document* document, const String& query)
109         : m_document(document)
110         , m_query(query) { }
111
112     void addNodesToResults(PassRefPtr<NodeList> nodes, ListHashSet<Node*>& resultCollector)
113     {
114         for (unsigned i = 0; nodes && i < nodes->length(); ++i)
115             resultCollector.add(nodes->item(i));
116     }
117
118     RefPtr<Document> m_document;
119     String m_query;
120 };
121
122 class RevalidateStyleAttributeTask {
123 public:
124     RevalidateStyleAttributeTask(InspectorDOMAgent*);
125     void scheduleFor(Element*);
126     void reset() { m_timer.stop(); }
127     void onTimer(Timer<RevalidateStyleAttributeTask>*);
128
129 private:
130     InspectorDOMAgent* m_domAgent;
131     Timer<RevalidateStyleAttributeTask> m_timer;
132     HashSet<RefPtr<Element> > m_elements;
133 };
134
135 namespace {
136
137 class MatchExactIdJob : public WebCore::MatchJob {
138 public:
139     MatchExactIdJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
140     virtual ~MatchExactIdJob() { }
141
142 protected:
143     virtual void match(ListHashSet<Node*>& resultCollector)
144     {
145         if (m_query.isEmpty())
146             return;
147
148         Element* element = m_document->getElementById(m_query);
149         if (element)
150             resultCollector.add(element);
151     }
152 };
153
154 class MatchExactClassNamesJob : public WebCore::MatchJob {
155 public:
156     MatchExactClassNamesJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
157     virtual ~MatchExactClassNamesJob() { }
158
159     virtual void match(ListHashSet<Node*>& resultCollector)
160     {
161         if (!m_query.isEmpty())
162             addNodesToResults(m_document->getElementsByClassName(m_query), resultCollector);
163     }
164 };
165
166 class MatchExactTagNamesJob : public WebCore::MatchJob {
167 public:
168     MatchExactTagNamesJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
169     virtual ~MatchExactTagNamesJob() { }
170
171     virtual void match(ListHashSet<Node*>& resultCollector)
172     {
173         if (!m_query.isEmpty())
174             addNodesToResults(m_document->getElementsByName(m_query), resultCollector);
175     }
176 };
177
178 class MatchQuerySelectorAllJob : public WebCore::MatchJob {
179 public:
180     MatchQuerySelectorAllJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
181     virtual ~MatchQuerySelectorAllJob() { }
182
183     virtual void match(ListHashSet<Node*>& resultCollector)
184     {
185         if (m_query.isEmpty())
186             return;
187
188         ExceptionCode ec = 0;
189         RefPtr<NodeList> list = m_document->querySelectorAll(m_query, ec);
190         if (!ec)
191             addNodesToResults(list, resultCollector);
192     }
193 };
194
195 class MatchXPathJob : public WebCore::MatchJob {
196 public:
197     MatchXPathJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
198     virtual ~MatchXPathJob() { }
199
200     virtual void match(ListHashSet<Node*>& resultCollector)
201     {
202 #if ENABLE(XPATH)
203         if (m_query.isEmpty())
204             return;
205
206         ExceptionCode ec = 0;
207         RefPtr<XPathResult> result = m_document->evaluate(m_query, m_document.get(), 0, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, 0, ec);
208         if (ec || !result)
209             return;
210
211         unsigned long size = result->snapshotLength(ec);
212         for (unsigned long i = 0; !ec && i < size; ++i) {
213             Node* node = result->snapshotItem(i, ec);
214             if (ec)
215                 break;
216
217             if (node->nodeType() == Node::ATTRIBUTE_NODE)
218                 node = static_cast<Attr*>(node)->ownerElement();
219             resultCollector.add(node);
220         }
221 #else
222         UNUSED_PARAM(resultCollector);
223 #endif
224     }
225 };
226
227 class MatchPlainTextJob : public MatchXPathJob {
228 public:
229     MatchPlainTextJob(Document* document, const String& query) : MatchXPathJob(document, query)
230     {
231         m_query = "//text()[contains(., '" + m_query + "')] | //comment()[contains(., '" + m_query + "')]";
232     }
233     virtual ~MatchPlainTextJob() { }
234 };
235
236 }
237
238 RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent)
239     : m_domAgent(domAgent)
240     , m_timer(this, &RevalidateStyleAttributeTask::onTimer)
241 {
242 }
243
244 void RevalidateStyleAttributeTask::scheduleFor(Element* element)
245 {
246     m_elements.add(element);
247     if (!m_timer.isActive())
248         m_timer.startOneShot(0);
249 }
250
251 void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*)
252 {
253     // The timer is stopped on m_domAgent destruction, so this method will never be called after m_domAgent has been destroyed.
254     for (HashSet<RefPtr<Element> >::iterator it = m_elements.begin(), end = m_elements.end(); it != end; ++it)
255         m_domAgent->didModifyDOMAttr(it->get());
256
257     m_elements.clear();
258 }
259
260 InspectorDOMAgent::InspectorDOMAgent(InstrumentingAgents* instrumentingAgents, Page* inspectedPage, InspectorClient* client, InspectorState* inspectorState, InjectedScriptManager* injectedScriptManager)
261     : m_instrumentingAgents(instrumentingAgents)
262     , m_inspectedPage(inspectedPage)
263     , m_client(client)
264     , m_inspectorState(inspectorState)
265     , m_injectedScriptManager(injectedScriptManager)
266     , m_frontend(0)
267     , m_domListener(0)
268     , m_lastNodeId(1)
269     , m_matchJobsTimer(this, &InspectorDOMAgent::onMatchJobsTimer)
270     , m_searchingForNode(false)
271 {
272 }
273
274 InspectorDOMAgent::~InspectorDOMAgent()
275 {
276     reset();
277     ASSERT(!m_highlightedNode);
278     ASSERT(!m_searchingForNode);
279 }
280
281 void InspectorDOMAgent::setFrontend(InspectorFrontend* frontend)
282 {
283     ASSERT(!m_frontend);
284     m_frontend = frontend->dom();
285     m_instrumentingAgents->setInspectorDOMAgent(this);
286     m_document = m_inspectedPage->mainFrame()->document();
287
288     if (m_nodeToFocus)
289         focusNode();
290 }
291
292 void InspectorDOMAgent::clearFrontend()
293 {
294     ASSERT(m_frontend);
295     setSearchingForNode(false);
296
297     ErrorString error;
298     hideHighlight(&error);
299
300     m_frontend = 0;
301     m_instrumentingAgents->setInspectorDOMAgent(0);
302     m_inspectorState->setBoolean(DOMAgentState::documentRequested, false);
303     reset();
304 }
305
306 void InspectorDOMAgent::restore()
307 {
308     // Reset document to avoid early return from setDocument.
309     m_document = 0;
310     setDocument(m_inspectedPage->mainFrame()->document());
311 }
312
313 Vector<Document*> InspectorDOMAgent::documents()
314 {
315     Vector<Document*> result;
316     for (Frame* frame = m_document->frame(); frame; frame = frame->tree()->traverseNext()) {
317         Document* document = frame->document();
318         if (!document)
319             continue;
320         result.append(document);
321     }
322     return result;
323 }
324
325 void InspectorDOMAgent::reset()
326 {
327     ErrorString error;
328     cancelSearch(&error);
329     discardBindings();
330     if (m_revalidateStyleAttrTask)
331         m_revalidateStyleAttrTask->reset();
332     m_document = 0;
333 }
334
335 void InspectorDOMAgent::setDOMListener(DOMListener* listener)
336 {
337     m_domListener = listener;
338 }
339
340 void InspectorDOMAgent::setDocument(Document* doc)
341 {
342     if (doc == m_document.get())
343         return;
344
345     reset();
346
347     m_document = doc;
348
349     if (!doc && m_inspectorState->getBoolean(DOMAgentState::documentRequested))
350         m_frontend->documentUpdated();
351 }
352
353 void InspectorDOMAgent::releaseDanglingNodes()
354 {
355     deleteAllValues(m_danglingNodeToIdMaps);
356     m_danglingNodeToIdMaps.clear();
357 }
358
359 int InspectorDOMAgent::bind(Node* node, NodeToIdMap* nodesMap)
360 {
361     int id = nodesMap->get(node);
362     if (id)
363         return id;
364     id = m_lastNodeId++;
365     nodesMap->set(node, id);
366     m_idToNode.set(id, node);
367     m_idToNodesMap.set(id, nodesMap);
368     return id;
369 }
370
371 void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap)
372 {
373     if (node->isFrameOwnerElement()) {
374         const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>(node);
375         if (m_domListener)
376             m_domListener->didRemoveDocument(frameOwner->contentDocument());
377     }
378
379     int id = nodesMap->get(node);
380     if (!id)
381         return;
382     m_idToNode.remove(id);
383     nodesMap->remove(node);
384     bool childrenRequested = m_childrenRequested.contains(id);
385     if (childrenRequested) {
386         // Unbind subtree known to client recursively.
387         m_childrenRequested.remove(id);
388         Node* child = innerFirstChild(node);
389         while (child) {
390             unbind(child, nodesMap);
391             child = innerNextSibling(child);
392         }
393     }
394 }
395
396 Node* InspectorDOMAgent::assertNode(ErrorString* errorString, int nodeId)
397 {
398     Node* node = nodeForId(nodeId);
399     if (!node) {
400         *errorString = "Could not find node with given id.";
401         return 0;
402     }
403     return node;
404 }
405
406 Element* InspectorDOMAgent::assertElement(ErrorString* errorString, int nodeId)
407 {
408     Node* node = assertNode(errorString, nodeId);
409     if (!node)
410         return 0;
411
412     if (node->nodeType() != Node::ELEMENT_NODE) {
413         *errorString = "Node is not an Element.";
414         return 0;
415     }
416     return toElement(node);
417 }
418
419
420 HTMLElement* InspectorDOMAgent::assertHTMLElement(ErrorString* errorString, int nodeId)
421 {
422     Element* element = assertElement(errorString, nodeId);
423     if (!element)
424         return 0;
425
426     if (!element->isHTMLElement()) {
427         *errorString = "Node is not an HTML Element.";
428         return 0;
429     }
430     return toHTMLElement(element);
431 }
432
433 Node* InspectorDOMAgent::nodeToSelectOn(ErrorString* errorString, int nodeId, bool documentWide)
434 {
435     Node* node;
436     if (!nodeId) {
437         node = m_document.get();
438         if (!node)
439             *errorString = "No document to query on.";
440     } else
441         node = assertNode(errorString, nodeId);
442
443     if (!node)
444         return 0;
445
446     if (documentWide && nodeId)
447         node = node->ownerDocument();
448     return node;
449 }
450
451 void InspectorDOMAgent::getDocument(ErrorString*, RefPtr<InspectorObject>* root)
452 {
453     m_inspectorState->setBoolean(DOMAgentState::documentRequested, true);
454
455     if (!m_document)
456         return;
457
458     // Reset backend state.
459     RefPtr<Document> doc = m_document;
460     reset();
461     m_document = doc;
462
463     if (!m_documentNodeToIdMap.contains(m_document))
464         *root = buildObjectForNode(m_document.get(), 2, &m_documentNodeToIdMap);
465 }
466
467 void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId)
468 {
469     Node* node = nodeForId(nodeId);
470     if (!node || (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE && node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE))
471         return;
472     if (m_childrenRequested.contains(nodeId))
473         return;
474
475     NodeToIdMap* nodeMap = m_idToNodesMap.get(nodeId);
476     RefPtr<InspectorArray> children = buildArrayForContainerChildren(node, 1, nodeMap);
477     m_childrenRequested.add(nodeId);
478     m_frontend->setChildNodes(nodeId, children.release());
479 }
480
481 void InspectorDOMAgent::discardBindings()
482 {
483     m_documentNodeToIdMap.clear();
484     m_idToNode.clear();
485     releaseDanglingNodes();
486     m_childrenRequested.clear();
487 }
488
489 Node* InspectorDOMAgent::nodeForId(int id)
490 {
491     if (!id)
492         return 0;
493
494     HashMap<int, Node*>::iterator it = m_idToNode.find(id);
495     if (it != m_idToNode.end())
496         return it->second;
497     return 0;
498 }
499
500 void InspectorDOMAgent::getChildNodes(ErrorString*, int nodeId)
501 {
502     pushChildNodesToFrontend(nodeId);
503 }
504
505 void InspectorDOMAgent::querySelector(ErrorString* errorString, int nodeId, const String& selectors, bool documentWide, int* elementId)
506 {
507     *elementId = 0;
508     Node* node = nodeToSelectOn(errorString, nodeId, documentWide);
509     if (!node)
510         return;
511
512     ExceptionCode ec = 0;
513     RefPtr<Element> element = node->querySelector(selectors, ec);
514     if (ec) {
515         *errorString = "DOM Error while querying.";
516         return;
517     }
518
519     if (element)
520         *elementId = pushNodePathToFrontend(element.get());
521 }
522
523 void InspectorDOMAgent::querySelectorAll(ErrorString* errorString, int nodeId, const String& selectors, bool documentWide, RefPtr<InspectorArray>* result)
524 {
525     Node* node = nodeToSelectOn(errorString, nodeId, documentWide);
526     if (!node)
527         return;
528
529     ExceptionCode ec = 0;
530     RefPtr<NodeList> nodes = node->querySelectorAll(selectors, ec);
531     if (ec) {
532         *errorString = "DOM Error while querying.";
533         return;
534     }
535
536     for (unsigned i = 0; i < nodes->length(); ++i)
537         (*result)->pushNumber(pushNodePathToFrontend(nodes->item(i)));
538 }
539
540 int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush)
541 {
542     ASSERT(nodeToPush);  // Invalid input
543
544     if (!m_document)
545         return 0;
546     if (!m_documentNodeToIdMap.contains(m_document))
547         return 0;
548
549     // Return id in case the node is known.
550     int result = m_documentNodeToIdMap.get(nodeToPush);
551     if (result)
552         return result;
553
554     Node* node = nodeToPush;
555     Vector<Node*> path;
556     NodeToIdMap* danglingMap = 0;
557
558     while (true) {
559         Node* parent = innerParentNode(node);
560         if (!parent) {
561             // Node being pushed is detached -> push subtree root.
562             danglingMap = new NodeToIdMap();
563             m_danglingNodeToIdMaps.append(danglingMap);
564             RefPtr<InspectorArray> children = InspectorArray::create();
565             children->pushObject(buildObjectForNode(node, 0, danglingMap));
566             m_frontend->setChildNodes(0, children);
567             break;
568         } else {
569             path.append(parent);
570             if (m_documentNodeToIdMap.get(parent))
571                 break;
572             else
573                 node = parent;
574         }
575     }
576
577     NodeToIdMap* map = danglingMap ? danglingMap : &m_documentNodeToIdMap;
578     for (int i = path.size() - 1; i >= 0; --i) {
579         int nodeId = map->get(path.at(i));
580         ASSERT(nodeId);
581         pushChildNodesToFrontend(nodeId);
582     }
583     return map->get(nodeToPush);
584 }
585
586 int InspectorDOMAgent::boundNodeId(Node* node)
587 {
588     return m_documentNodeToIdMap.get(node);
589 }
590
591 void InspectorDOMAgent::setAttribute(ErrorString* errorString, int elementId, const String& name, const String& value)
592 {
593     Element* element = assertElement(errorString, elementId);
594     if (element) {
595         ExceptionCode ec = 0;
596         element->setAttribute(name, value, ec);
597         if (ec)
598             *errorString = "Exception while setting attribute value.";
599     }
600 }
601
602 void InspectorDOMAgent::removeAttribute(ErrorString* errorString, int elementId, const String& name)
603 {
604     Element* element = assertElement(errorString, elementId);
605     if (element) {
606         ExceptionCode ec = 0;
607         element->removeAttribute(name, ec);
608         if (ec)
609             *errorString = "Exception while removing attribute.";
610     }
611 }
612
613 void InspectorDOMAgent::removeNode(ErrorString* errorString, int nodeId)
614 {
615     Node* node = assertNode(errorString, nodeId);
616     if (!node)
617         return;
618
619     ContainerNode* parentNode = node->parentNode();
620     if (!parentNode) {
621         *errorString = "Can not remove detached node.";
622         return;
623     }
624
625     ExceptionCode ec = 0;
626     parentNode->removeChild(node, ec);
627     if (ec)
628         *errorString = "Could not remove node due to DOM exception.";
629 }
630
631 void InspectorDOMAgent::setNodeName(ErrorString*, int nodeId, const String& tagName, int* newId)
632 {
633     *newId = 0;
634
635     Node* oldNode = nodeForId(nodeId);
636     if (!oldNode || !oldNode->isElementNode())
637         return;
638
639     ExceptionCode ec = 0;
640     RefPtr<Element> newElem = oldNode->document()->createElement(tagName, ec);
641     if (ec)
642         return;
643
644     // Copy over the original node's attributes.
645     Element* oldElem = static_cast<Element*>(oldNode);
646     newElem->copyNonAttributeProperties(oldElem);
647     if (oldElem->attributes())
648         newElem->attributes()->setAttributes(*(oldElem->attributes(true)));
649
650     // Copy over the original node's children.
651     Node* child;
652     while ((child = oldNode->firstChild()))
653         newElem->appendChild(child, ec);
654
655     // Replace the old node with the new node
656     ContainerNode* parent = oldNode->parentNode();
657     parent->insertBefore(newElem, oldNode->nextSibling(), ec);
658     parent->removeChild(oldNode, ec);
659
660     if (ec)
661         return;
662
663     *newId = pushNodePathToFrontend(newElem.get());
664     if (m_childrenRequested.contains(nodeId))
665         pushChildNodesToFrontend(*newId);
666 }
667
668 void InspectorDOMAgent::getOuterHTML(ErrorString* errorString, int nodeId, WTF::String* outerHTML)
669 {
670     HTMLElement* element = assertHTMLElement(errorString, nodeId);
671     if (element)
672         *outerHTML = element->outerHTML();
673 }
674
675 void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const String& outerHTML, int* newId)
676 {
677     HTMLElement* htmlElement = assertHTMLElement(errorString, nodeId);
678     if (!htmlElement)
679         return;
680
681     bool requiresTotalUpdate = htmlElement->tagName() == "HTML" || htmlElement->tagName() == "BODY" || htmlElement->tagName() == "HEAD";
682
683     bool childrenRequested = m_childrenRequested.contains(nodeId);
684     Node* previousSibling = htmlElement->previousSibling();
685     ContainerNode* parentNode = htmlElement->parentNode();
686
687     ExceptionCode ec = 0;
688     htmlElement->setOuterHTML(outerHTML, ec);
689     if (ec)
690         return;
691
692     if (requiresTotalUpdate) {
693         RefPtr<Document> document = m_document;
694         reset();
695         setDocument(document.get());
696         *newId = 0;
697         return;
698     }
699
700     Node* newNode = previousSibling ? previousSibling->nextSibling() : parentNode->firstChild();
701     if (!newNode) {
702         // The only child node has been deleted.
703         *newId = 0;
704         return;
705     }
706
707     *newId = pushNodePathToFrontend(newNode);
708     if (childrenRequested)
709         pushChildNodesToFrontend(*newId);
710 }
711
712 void InspectorDOMAgent::setNodeValue(ErrorString* errorString, int nodeId, const String& value)
713 {
714     Node* node = assertNode(errorString, nodeId);
715     if (!node)
716         return;
717
718     if (node->nodeType() != Node::TEXT_NODE) {
719         *errorString = "Can only set value of text nodes.";
720         return;
721     }
722
723     Text* textNode = static_cast<Text*>(node);
724     ExceptionCode ec = 0;
725     textNode->replaceWholeText(value, ec);
726     if (ec)
727         *errorString = "DOM Error while setting the node value.";
728 }
729
730 void InspectorDOMAgent::getEventListenersForNode(ErrorString*, int nodeId, RefPtr<InspectorArray>* listenersArray)
731 {
732     Node* node = nodeForId(nodeId);
733     EventTargetData* d;
734
735     // Quick break if a null node or no listeners at all
736     if (!node || !(d = node->eventTargetData()))
737         return;
738
739     // Get the list of event types this Node is concerned with
740     Vector<AtomicString> eventTypes;
741     const EventListenerMap& listenerMap = d->eventListenerMap;
742     EventListenerMap::const_iterator end = listenerMap.end();
743     for (EventListenerMap::const_iterator iter = listenerMap.begin(); iter != end; ++iter)
744         eventTypes.append(iter->first);
745
746     // Quick break if no useful listeners
747     size_t eventTypesLength = eventTypes.size();
748     if (!eventTypesLength)
749         return;
750
751     // The Node's Ancestors (not including self)
752     Vector<ContainerNode*> ancestors;
753     for (ContainerNode* ancestor = node->parentOrHostNode(); ancestor; ancestor = ancestor->parentOrHostNode())
754         ancestors.append(ancestor);
755
756     // Nodes and their Listeners for the concerned event types (order is top to bottom)
757     Vector<EventListenerInfo> eventInformation;
758     for (size_t i = ancestors.size(); i; --i) {
759         ContainerNode* ancestor = ancestors[i - 1];
760         for (size_t j = 0; j < eventTypesLength; ++j) {
761             AtomicString& type = eventTypes[j];
762             if (ancestor->hasEventListeners(type))
763                 eventInformation.append(EventListenerInfo(ancestor, type, ancestor->getEventListeners(type)));
764         }
765     }
766
767     // Insert the Current Node at the end of that list (last in capturing, first in bubbling)
768     for (size_t i = 0; i < eventTypesLength; ++i) {
769         const AtomicString& type = eventTypes[i];
770         eventInformation.append(EventListenerInfo(node, type, node->getEventListeners(type)));
771     }
772
773     // Get Capturing Listeners (in this order)
774     size_t eventInformationLength = eventInformation.size();
775     for (size_t i = 0; i < eventInformationLength; ++i) {
776         const EventListenerInfo& info = eventInformation[i];
777         const EventListenerVector& vector = info.eventListenerVector;
778         for (size_t j = 0; j < vector.size(); ++j) {
779             const RegisteredEventListener& listener = vector[j];
780             if (listener.useCapture)
781                 (*listenersArray)->pushObject(buildObjectForEventListener(listener, info.eventType, info.node));
782         }
783     }
784
785     // Get Bubbling Listeners (reverse order)
786     for (size_t i = eventInformationLength; i; --i) {
787         const EventListenerInfo& info = eventInformation[i - 1];
788         const EventListenerVector& vector = info.eventListenerVector;
789         for (size_t j = 0; j < vector.size(); ++j) {
790             const RegisteredEventListener& listener = vector[j];
791             if (!listener.useCapture)
792                 (*listenersArray)->pushObject(buildObjectForEventListener(listener, info.eventType, info.node));
793         }
794     }
795 }
796
797 void InspectorDOMAgent::performSearch(ErrorString* error, const String& whitespaceTrimmedQuery, bool runSynchronously)
798 {
799     // FIXME: Few things are missing here:
800     // 1) Search works with node granularity - number of matches within node is not calculated.
801     // 2) There is no need to push all search results to the front-end at a time, pushing next / previous result
802     //    is sufficient.
803
804     unsigned queryLength = whitespaceTrimmedQuery.length();
805     bool startTagFound = !whitespaceTrimmedQuery.find('<');
806     bool endTagFound = whitespaceTrimmedQuery.reverseFind('>') + 1 == queryLength;
807
808     String tagNameQuery = whitespaceTrimmedQuery;
809     if (startTagFound || endTagFound)
810         tagNameQuery = tagNameQuery.substring(startTagFound ? 1 : 0, endTagFound ? queryLength - 1 : queryLength);
811     if (!Document::isValidName(tagNameQuery))
812         tagNameQuery = "";
813
814     String attributeNameQuery = whitespaceTrimmedQuery;
815     if (!Document::isValidName(attributeNameQuery))
816         attributeNameQuery = "";
817
818     String escapedQuery = whitespaceTrimmedQuery;
819     escapedQuery.replace("'", "\\'");
820     String escapedTagNameQuery = tagNameQuery;
821     escapedTagNameQuery.replace("'", "\\'");
822
823     // Clear pending jobs.
824     cancelSearch(error);
825
826     // Find all frames, iframes and object elements to search their documents.
827     Vector<Document*> docs = documents();
828     for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
829         Document* document = *it;
830
831         if (!tagNameQuery.isEmpty() && startTagFound && endTagFound) {
832             m_pendingMatchJobs.append(new MatchExactTagNamesJob(document, tagNameQuery));
833             m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
834             continue;
835         }
836
837         if (!tagNameQuery.isEmpty() && startTagFound) {
838             m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[starts-with(name(), '" + escapedTagNameQuery + "')]"));
839             m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
840             continue;
841         }
842
843         if (!tagNameQuery.isEmpty() && endTagFound) {
844             // FIXME: we should have a matchEndOfTagNames search function if endTagFound is true but not startTagFound.
845             // This requires ends-with() support in XPath, WebKit only supports starts-with() and contains().
846             m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(name(), '" + escapedTagNameQuery + "')]"));
847             m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
848             continue;
849         }
850
851         bool matchesEveryNode = whitespaceTrimmedQuery == "//*" || whitespaceTrimmedQuery == "*";
852         if (matchesEveryNode) {
853             // These queries will match every node. Matching everything isn't useful and can be slow for large pages,
854             // so limit the search functions list to plain text and attribute matching for these.
855             m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(@*, '" + escapedQuery + "')]"));
856             m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
857             continue;
858         }
859
860         m_pendingMatchJobs.append(new MatchExactIdJob(document, whitespaceTrimmedQuery));
861         m_pendingMatchJobs.append(new MatchExactClassNamesJob(document, whitespaceTrimmedQuery));
862         m_pendingMatchJobs.append(new MatchExactTagNamesJob(document, tagNameQuery));
863         m_pendingMatchJobs.append(new MatchQuerySelectorAllJob(document, "[" + attributeNameQuery + "]"));
864         m_pendingMatchJobs.append(new MatchQuerySelectorAllJob(document, whitespaceTrimmedQuery));
865         m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(@*, '" + escapedQuery + "')]"));
866         if (!tagNameQuery.isEmpty())
867             m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(name(), '" + escapedTagNameQuery + "')]"));
868         m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
869         m_pendingMatchJobs.append(new MatchXPathJob(document, whitespaceTrimmedQuery));
870     }
871
872     if (runSynchronously) {
873         // For tests.
874         ListHashSet<Node*> resultCollector;
875         for (Deque<MatchJob*>::iterator it = m_pendingMatchJobs.begin(); it != m_pendingMatchJobs.end(); ++it)
876             (*it)->match(resultCollector);
877         reportNodesAsSearchResults(resultCollector);
878         cancelSearch(error);
879         return;
880     }
881     m_matchJobsTimer.startOneShot(0);
882 }
883
884 void InspectorDOMAgent::cancelSearch(ErrorString*)
885 {
886     if (m_matchJobsTimer.isActive())
887         m_matchJobsTimer.stop();
888     deleteAllValues(m_pendingMatchJobs);
889     m_pendingMatchJobs.clear();
890     m_searchResults.clear();
891 }
892
893 bool InspectorDOMAgent::handleMousePress()
894 {
895     if (!m_searchingForNode)
896         return false;
897
898     if (m_highlightedNode) {
899         RefPtr<Node> node = m_highlightedNode;
900         setSearchingForNode(false);
901         inspect(node.get());
902     }
903     return true;
904 }
905
906 void InspectorDOMAgent::inspect(Node* node)
907 {
908     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
909         node = node->parentNode();
910     m_nodeToFocus = node;
911
912     focusNode();
913 }
914
915 void InspectorDOMAgent::focusNode()
916 {
917     if (!m_frontend)
918         return;
919
920     ASSERT(m_nodeToFocus);
921
922     RefPtr<Node> node = m_nodeToFocus.get();
923     m_nodeToFocus = 0;
924
925     Document* document = node->ownerDocument();
926     if (!document)
927         return;
928     Frame* frame = document->frame();
929     if (!frame)
930         return;
931
932     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
933     if (injectedScript.hasNoValue())
934         return;
935
936     injectedScript.inspectNode(node.get());
937 }
938
939 void InspectorDOMAgent::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
940 {
941     if (!m_searchingForNode)
942         return;
943
944     Node* node = result.innerNode();
945     while (node && node->nodeType() == Node::TEXT_NODE)
946         node = node->parentNode();
947     if (node) {
948         ErrorString error;
949         highlight(&error, node);
950     }
951 }
952
953 void InspectorDOMAgent::setSearchingForNode(bool enabled)
954 {
955     if (m_searchingForNode == enabled)
956         return;
957     m_searchingForNode = enabled;
958     if (!enabled) {
959         ErrorString error;
960         hideHighlight(&error);
961     }
962 }
963
964 void InspectorDOMAgent::setSearchingForNode(ErrorString*, bool enabled, bool* newState)
965 {
966     *newState = enabled;
967     setSearchingForNode(enabled);
968 }
969
970 void InspectorDOMAgent::highlight(ErrorString*, Node* node)
971 {
972     ASSERT_ARG(node, node);
973     m_highlightedNode = node;
974     m_client->highlight(node);
975 }
976
977 void InspectorDOMAgent::highlightDOMNode(ErrorString* error, int nodeId)
978 {
979     if (Node* node = nodeForId(nodeId))
980         highlight(error, node);
981 }
982
983 void InspectorDOMAgent::highlightFrame(ErrorString* error, const String& frameId)
984 {
985     Frame* frame = m_instrumentingAgents->inspectorResourceAgent()->frameForId(frameId);
986     if (frame && frame->ownerElement())
987         highlight(error, frame->ownerElement());
988 }
989
990 void InspectorDOMAgent::hideHighlight(ErrorString*)
991 {
992     m_highlightedNode = 0;
993     m_client->hideHighlight();
994 }
995
996 void InspectorDOMAgent::resolveNode(ErrorString* error, int nodeId, RefPtr<InspectorObject>* result)
997 {
998     Node* node = nodeForId(nodeId);
999     if (!node) {
1000         *error = "No node with given id found.";
1001         return;
1002     }
1003     *result = resolveNode(node);
1004 }
1005
1006 void InspectorDOMAgent::pushNodeToFrontend(ErrorString*, const String& objectId, int* nodeId)
1007 {
1008     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
1009     Node* node = injectedScript.nodeForObjectId(objectId);
1010     if (node)
1011         *nodeId = pushNodePathToFrontend(node);
1012     else
1013         *nodeId = 0;
1014 }
1015
1016 String InspectorDOMAgent::documentURLString(Document* document) const
1017 {
1018     if (!document || document->url().isNull())
1019         return "";
1020     return document->url().string();
1021 }
1022
1023 PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap)
1024 {
1025     RefPtr<InspectorObject> value = InspectorObject::create();
1026
1027     int id = bind(node, nodesMap);
1028     String nodeName;
1029     String localName;
1030     String nodeValue;
1031
1032     switch (node->nodeType()) {
1033         case Node::TEXT_NODE:
1034         case Node::COMMENT_NODE:
1035         case Node::CDATA_SECTION_NODE:
1036             nodeValue = node->nodeValue();
1037             break;
1038         case Node::ATTRIBUTE_NODE:
1039             localName = node->localName();
1040             break;
1041         case Node::DOCUMENT_FRAGMENT_NODE:
1042             break;
1043         case Node::DOCUMENT_NODE:
1044         case Node::ELEMENT_NODE:
1045         default:
1046             nodeName = node->nodeName();
1047             localName = node->localName();
1048             break;
1049     }
1050
1051     value->setNumber("id", id);
1052     value->setNumber("nodeType", node->nodeType());
1053     value->setString("nodeName", nodeName);
1054     value->setString("localName", localName);
1055     value->setString("nodeValue", nodeValue);
1056
1057     if (node->nodeType() == Node::ELEMENT_NODE || node->nodeType() == Node::DOCUMENT_NODE || node->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
1058         int nodeCount = innerChildNodeCount(node);
1059         value->setNumber("childNodeCount", nodeCount);
1060         RefPtr<InspectorArray> children = buildArrayForContainerChildren(node, depth, nodesMap);
1061         if (children->length() > 0)
1062             value->setArray("children", children.release());
1063
1064         if (node->nodeType() == Node::ELEMENT_NODE) {
1065             Element* element = static_cast<Element*>(node);
1066             value->setArray("attributes", buildArrayForElementAttributes(element));
1067             if (node->isFrameOwnerElement()) {
1068                 HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node);
1069                 value->setString("documentURL", documentURLString(frameOwner->contentDocument()));
1070             }
1071         } else if (node->nodeType() == Node::DOCUMENT_NODE) {
1072             Document* document = static_cast<Document*>(node);
1073             value->setString("documentURL", documentURLString(document));
1074         }
1075     } else if (node->nodeType() == Node::DOCUMENT_TYPE_NODE) {
1076         DocumentType* docType = static_cast<DocumentType*>(node);
1077         value->setString("publicId", docType->publicId());
1078         value->setString("systemId", docType->systemId());
1079         value->setString("internalSubset", docType->internalSubset());
1080     } else if (node->nodeType() == Node::ATTRIBUTE_NODE) {
1081         Attr* attribute = static_cast<Attr*>(node);
1082         value->setString("name", attribute->name());
1083         value->setString("value", attribute->value());
1084     }
1085     return value.release();
1086 }
1087
1088 PassRefPtr<InspectorArray> InspectorDOMAgent::buildArrayForElementAttributes(Element* element)
1089 {
1090     RefPtr<InspectorArray> attributesValue = InspectorArray::create();
1091     // Go through all attributes and serialize them.
1092     const NamedNodeMap* attrMap = element->attributes(true);
1093     if (!attrMap)
1094         return attributesValue.release();
1095     unsigned numAttrs = attrMap->length();
1096     for (unsigned i = 0; i < numAttrs; ++i) {
1097         // Add attribute pair
1098         const Attribute *attribute = attrMap->attributeItem(i);
1099         attributesValue->pushString(attribute->name().toString());
1100         attributesValue->pushString(attribute->value());
1101     }
1102     return attributesValue.release();
1103 }
1104
1105 PassRefPtr<InspectorArray> InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap)
1106 {
1107     RefPtr<InspectorArray> children = InspectorArray::create();
1108     Node* child = innerFirstChild(container);
1109
1110     if (depth == 0) {
1111         // Special case the_only text child.
1112         if (child && child->nodeType() == Node::TEXT_NODE && !innerNextSibling(child))
1113             children->pushObject(buildObjectForNode(child, 0, nodesMap));
1114         return children.release();
1115     } else if (depth > 0) {
1116         depth--;
1117     }
1118
1119     while (child) {
1120         children->pushObject(buildObjectForNode(child, depth, nodesMap));
1121         child = innerNextSibling(child);
1122     }
1123     return children.release();
1124 }
1125
1126 PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node)
1127 {
1128     RefPtr<EventListener> eventListener = registeredEventListener.listener;
1129     RefPtr<InspectorObject> value = InspectorObject::create();
1130     value->setString("type", eventType);
1131     value->setBoolean("useCapture", registeredEventListener.useCapture);
1132     value->setBoolean("isAttribute", eventListener->isAttribute());
1133     value->setNumber("nodeId", pushNodePathToFrontend(node));
1134     value->setString("listenerBody", eventListenerHandlerBody(node->document(), eventListener.get()));
1135     String sourceName;
1136     int lineNumber;
1137     if (eventListenerHandlerLocation(node->document(), eventListener.get(), sourceName, lineNumber)) {
1138         value->setString("sourceName", sourceName);
1139         value->setNumber("lineNumber", lineNumber);
1140     }
1141     return value.release();
1142 }
1143
1144 Node* InspectorDOMAgent::innerFirstChild(Node* node)
1145 {
1146     if (node->isFrameOwnerElement()) {
1147         HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node);
1148         Document* doc = frameOwner->contentDocument();
1149         if (doc)
1150             return doc->firstChild();
1151     }
1152     node = node->firstChild();
1153     while (isWhitespace(node))
1154         node = node->nextSibling();
1155     return node;
1156 }
1157
1158 Node* InspectorDOMAgent::innerNextSibling(Node* node)
1159 {
1160     do {
1161         node = node->nextSibling();
1162     } while (isWhitespace(node));
1163     return node;
1164 }
1165
1166 Node* InspectorDOMAgent::innerPreviousSibling(Node* node)
1167 {
1168     do {
1169         node = node->previousSibling();
1170     } while (isWhitespace(node));
1171     return node;
1172 }
1173
1174 unsigned InspectorDOMAgent::innerChildNodeCount(Node* node)
1175 {
1176     unsigned count = 0;
1177     Node* child = innerFirstChild(node);
1178     while (child) {
1179         count++;
1180         child = innerNextSibling(child);
1181     }
1182     return count;
1183 }
1184
1185 Node* InspectorDOMAgent::innerParentNode(Node* node)
1186 {
1187     ContainerNode* parent = node->parentNode();
1188     if (parent && parent->isDocumentNode())
1189         return static_cast<Document*>(parent)->ownerElement();
1190     return parent;
1191 }
1192
1193 bool InspectorDOMAgent::isWhitespace(Node* node)
1194 {
1195     //TODO: pull ignoreWhitespace setting from the frontend and use here.
1196     return node && node->nodeType() == Node::TEXT_NODE && node->nodeValue().stripWhiteSpace().length() == 0;
1197 }
1198
1199 void InspectorDOMAgent::mainFrameDOMContentLoaded()
1200 {
1201     // Re-push document once it is loaded.
1202     discardBindings();
1203     if (m_inspectorState->getBoolean(DOMAgentState::documentRequested))
1204         m_frontend->documentUpdated();
1205 }
1206
1207 void InspectorDOMAgent::loadEventFired(Document* document)
1208 {
1209     Element* frameOwner = document->ownerElement();
1210     if (!frameOwner)
1211         return;
1212
1213     int frameOwnerId = m_documentNodeToIdMap.get(frameOwner);
1214     if (!frameOwnerId)
1215         return;
1216
1217     if (!m_childrenRequested.contains(frameOwnerId)) {
1218         // No children are mapped yet -> only notify on changes of hasChildren.
1219         m_frontend->childNodeCountUpdated(frameOwnerId, innerChildNodeCount(frameOwner));
1220     } else {
1221         // Re-add frame owner element together with its new children.
1222         int parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner));
1223         m_frontend->childNodeRemoved(parentId, frameOwnerId);
1224         RefPtr<InspectorObject> value = buildObjectForNode(frameOwner, 0, &m_documentNodeToIdMap);
1225         Node* previousSibling = innerPreviousSibling(frameOwner);
1226         int prevId = previousSibling ? m_documentNodeToIdMap.get(previousSibling) : 0;
1227         m_frontend->childNodeInserted(parentId, prevId, value.release());
1228         // Invalidate children requested flag for the element.
1229         m_childrenRequested.remove(m_childrenRequested.find(frameOwnerId));
1230     }
1231 }
1232
1233 void InspectorDOMAgent::didInsertDOMNode(Node* node)
1234 {
1235     if (isWhitespace(node))
1236         return;
1237
1238     // We could be attaching existing subtree. Forget the bindings.
1239     unbind(node, &m_documentNodeToIdMap);
1240
1241     ContainerNode* parent = node->parentNode();
1242     int parentId = m_documentNodeToIdMap.get(parent);
1243     // Return if parent is not mapped yet.
1244     if (!parentId)
1245         return;
1246
1247     if (!m_childrenRequested.contains(parentId)) {
1248         // No children are mapped yet -> only notify on changes of hasChildren.
1249         m_frontend->childNodeCountUpdated(parentId, innerChildNodeCount(parent));
1250     } else {
1251         // Children have been requested -> return value of a new child.
1252         Node* prevSibling = innerPreviousSibling(node);
1253         int prevId = prevSibling ? m_documentNodeToIdMap.get(prevSibling) : 0;
1254         RefPtr<InspectorObject> value = buildObjectForNode(node, 0, &m_documentNodeToIdMap);
1255         m_frontend->childNodeInserted(parentId, prevId, value.release());
1256     }
1257 }
1258
1259 void InspectorDOMAgent::didRemoveDOMNode(Node* node)
1260 {
1261     if (isWhitespace(node))
1262         return;
1263
1264     ContainerNode* parent = node->parentNode();
1265     int parentId = m_documentNodeToIdMap.get(parent);
1266     // If parent is not mapped yet -> ignore the event.
1267     if (!parentId)
1268         return;
1269
1270     if (m_domListener)
1271         m_domListener->didRemoveDOMNode(node);
1272
1273     if (!m_childrenRequested.contains(parentId)) {
1274         // No children are mapped yet -> only notify on changes of hasChildren.
1275         if (innerChildNodeCount(parent) == 1)
1276             m_frontend->childNodeCountUpdated(parentId, 0);
1277     } else
1278         m_frontend->childNodeRemoved(parentId, m_documentNodeToIdMap.get(node));
1279     unbind(node, &m_documentNodeToIdMap);
1280 }
1281
1282 void InspectorDOMAgent::didModifyDOMAttr(Element* element)
1283 {
1284     int id = m_documentNodeToIdMap.get(element);
1285     // If node is not mapped yet -> ignore the event.
1286     if (!id)
1287         return;
1288
1289     if (m_domListener)
1290         m_domListener->didModifyDOMAttr(element);
1291
1292     m_frontend->attributesUpdated(id, buildArrayForElementAttributes(element));
1293 }
1294
1295 void InspectorDOMAgent::characterDataModified(CharacterData* characterData)
1296 {
1297     int id = m_documentNodeToIdMap.get(characterData);
1298     if (!id)
1299         return;
1300     m_frontend->characterDataModified(id, characterData->data());
1301 }
1302
1303 void InspectorDOMAgent::didInvalidateStyleAttr(Node* node)
1304 {
1305     int id = m_documentNodeToIdMap.get(node);
1306     // If node is not mapped yet -> ignore the event.
1307     if (!id)
1308         return;
1309
1310     if (!m_revalidateStyleAttrTask)
1311         m_revalidateStyleAttrTask = new RevalidateStyleAttributeTask(this);
1312     m_revalidateStyleAttrTask->scheduleFor(static_cast<Element*>(node));
1313 }
1314
1315 Node* InspectorDOMAgent::nodeForPath(const String& path)
1316 {
1317     // The path is of form "1,HTML,2,BODY,1,DIV"
1318     if (!m_document)
1319         return 0;
1320
1321     Node* node = m_document.get();
1322     Vector<String> pathTokens;
1323     path.split(",", false, pathTokens);
1324     if (!pathTokens.size())
1325         return 0;
1326     for (size_t i = 0; i < pathTokens.size() - 1; i += 2) {
1327         bool success = true;
1328         unsigned childNumber = pathTokens[i].toUInt(&success);
1329         if (!success)
1330             return 0;
1331         if (childNumber >= innerChildNodeCount(node))
1332             return 0;
1333
1334         Node* child = innerFirstChild(node);
1335         String childName = pathTokens[i + 1];
1336         for (size_t j = 0; child && j < childNumber; ++j)
1337             child = innerNextSibling(child);
1338
1339         if (!child || child->nodeName() != childName)
1340             return 0;
1341         node = child;
1342     }
1343     return node;
1344 }
1345
1346 PassRefPtr<InspectorArray> InspectorDOMAgent::toArray(const Vector<String>& data)
1347 {
1348     RefPtr<InspectorArray> result = InspectorArray::create();
1349     for (unsigned i = 0; i < data.size(); ++i)
1350         result->pushString(data[i]);
1351     return result.release();
1352 }
1353
1354 void InspectorDOMAgent::onMatchJobsTimer(Timer<InspectorDOMAgent>*)
1355 {
1356     if (!m_pendingMatchJobs.size()) {
1357         ErrorString error;
1358         cancelSearch(&error);
1359         return;
1360     }
1361
1362     ListHashSet<Node*> resultCollector;
1363     MatchJob* job = m_pendingMatchJobs.takeFirst();
1364     job->match(resultCollector);
1365     delete job;
1366
1367     reportNodesAsSearchResults(resultCollector);
1368
1369     m_matchJobsTimer.startOneShot(0.025);
1370 }
1371
1372 void InspectorDOMAgent::reportNodesAsSearchResults(ListHashSet<Node*>& resultCollector)
1373 {
1374     RefPtr<InspectorArray> nodeIds = InspectorArray::create();
1375     for (ListHashSet<Node*>::iterator it = resultCollector.begin(); it != resultCollector.end(); ++it) {
1376         if (m_searchResults.contains(*it))
1377             continue;
1378         m_searchResults.add(*it);
1379         nodeIds->pushNumber(pushNodePathToFrontend(*it));
1380     }
1381     m_frontend->searchResults(nodeIds.release());
1382 }
1383
1384 void InspectorDOMAgent::copyNode(ErrorString*, int nodeId)
1385 {
1386     Node* node = nodeForId(nodeId);
1387     if (!node)
1388         return;
1389     String markup = createMarkup(node);
1390     Pasteboard::generalPasteboard()->writePlainText(markup);
1391 }
1392
1393 void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString*, const String& path, int* nodeId)
1394 {
1395     if (Node* node = nodeForPath(path))
1396         *nodeId = pushNodePathToFrontend(node);
1397 }
1398
1399 PassRefPtr<InspectorObject> InspectorDOMAgent::resolveNode(Node* node)
1400 {
1401     Document* document = node->ownerDocument();
1402     Frame* frame = document ? document->frame() : 0;
1403     if (!frame)
1404         return 0;
1405
1406     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
1407     if (injectedScript.hasNoValue())
1408         return 0;
1409
1410     return injectedScript.wrapNode(node);
1411 }
1412
1413 void InspectorDOMAgent::drawNodeHighlight(GraphicsContext& context) const
1414 {
1415     if (!m_highlightedNode)
1416         return;
1417
1418     DOMNodeHighlighter::DrawNodeHighlight(context, m_highlightedNode.get());
1419 }
1420
1421 } // namespace WebCore
1422
1423 #endif // ENABLE(INSPECTOR)