initial import
[vuplus_webkit] / Source / WebCore / inspector / InspectorDOMAgent.cpp
1 /*
2  * Copyright (C) 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 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 "InspectorPageAgent.h"
68 #include "InspectorState.h"
69 #include "InstrumentingAgents.h"
70 #include "IntRect.h"
71 #include "MutationEvent.h"
72 #include "Node.h"
73 #include "NodeList.h"
74 #include "Page.h"
75 #include "Pasteboard.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/WTFString.h>
90 #include <wtf/HashSet.h>
91 #include <wtf/ListHashSet.h>
92 #include <wtf/OwnPtr.h>
93 #include <wtf/Vector.h>
94
95 namespace WebCore {
96
97 namespace DOMAgentState {
98 static const char documentRequested[] = "documentRequested";
99 };
100
101 static Color parseColor(const RefPtr<InspectorObject>* colorObject)
102 {
103     if (!colorObject || !(*colorObject))
104         return Color::transparent;
105
106     int r;
107     int g;
108     int b;
109     bool success = (*colorObject)->getNumber("r", &r);
110     success |= (*colorObject)->getNumber("g", &g);
111     success |= (*colorObject)->getNumber("b", &b);
112     if (!success)
113         return Color::transparent;
114
115     double a;
116     success = (*colorObject)->getNumber("a", &a);
117     if (!success)
118         return Color(r, g, b);
119
120     // Clamp alpha to the [0..1] range.
121     if (a < 0)
122         a = 0;
123     else if (a > 1)
124         a = 1;
125
126     return Color(r, g, b, static_cast<int>(a * 255));
127 }
128
129 static Color parseConfigColor(const String& fieldName, InspectorObject* configObject)
130 {
131     const RefPtr<InspectorObject> colorObject = configObject->getObject(fieldName);
132     return parseColor(&colorObject);
133 }
134
135 class MatchJob {
136 public:
137     virtual void match(ListHashSet<Node*>& resultCollector) = 0;
138     virtual ~MatchJob() { }
139
140 protected:
141     MatchJob(Document* document, const String& query)
142         : m_document(document)
143         , m_query(query) { }
144
145     void addNodesToResults(PassRefPtr<NodeList> nodes, ListHashSet<Node*>& resultCollector)
146     {
147         for (unsigned i = 0; nodes && i < nodes->length(); ++i)
148             resultCollector.add(nodes->item(i));
149     }
150
151     RefPtr<Document> m_document;
152     String m_query;
153 };
154
155 class RevalidateStyleAttributeTask {
156 public:
157     RevalidateStyleAttributeTask(InspectorDOMAgent*);
158     void scheduleFor(Element*);
159     void reset() { m_timer.stop(); }
160     void onTimer(Timer<RevalidateStyleAttributeTask>*);
161
162 private:
163     InspectorDOMAgent* m_domAgent;
164     Timer<RevalidateStyleAttributeTask> m_timer;
165     HashSet<RefPtr<Element> > m_elements;
166 };
167
168 namespace {
169
170 class MatchExactIdJob : public WebCore::MatchJob {
171 public:
172     MatchExactIdJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
173     virtual ~MatchExactIdJob() { }
174
175 protected:
176     virtual void match(ListHashSet<Node*>& resultCollector)
177     {
178         if (m_query.isEmpty())
179             return;
180
181         Element* element = m_document->getElementById(m_query);
182         if (element)
183             resultCollector.add(element);
184     }
185 };
186
187 class MatchExactClassNamesJob : public WebCore::MatchJob {
188 public:
189     MatchExactClassNamesJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
190     virtual ~MatchExactClassNamesJob() { }
191
192     virtual void match(ListHashSet<Node*>& resultCollector)
193     {
194         if (!m_query.isEmpty())
195             addNodesToResults(m_document->getElementsByClassName(m_query), resultCollector);
196     }
197 };
198
199 class MatchExactTagNamesJob : public WebCore::MatchJob {
200 public:
201     MatchExactTagNamesJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
202     virtual ~MatchExactTagNamesJob() { }
203
204     virtual void match(ListHashSet<Node*>& resultCollector)
205     {
206         if (!m_query.isEmpty())
207             addNodesToResults(m_document->getElementsByName(m_query), resultCollector);
208     }
209 };
210
211 class MatchQuerySelectorAllJob : public WebCore::MatchJob {
212 public:
213     MatchQuerySelectorAllJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
214     virtual ~MatchQuerySelectorAllJob() { }
215
216     virtual void match(ListHashSet<Node*>& resultCollector)
217     {
218         if (m_query.isEmpty())
219             return;
220
221         ExceptionCode ec = 0;
222         RefPtr<NodeList> list = m_document->querySelectorAll(m_query, ec);
223         if (!ec)
224             addNodesToResults(list, resultCollector);
225     }
226 };
227
228 class MatchXPathJob : public WebCore::MatchJob {
229 public:
230     MatchXPathJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
231     virtual ~MatchXPathJob() { }
232
233     virtual void match(ListHashSet<Node*>& resultCollector)
234     {
235 #if ENABLE(XPATH)
236         if (m_query.isEmpty())
237             return;
238
239         ExceptionCode ec = 0;
240         RefPtr<XPathResult> result = m_document->evaluate(m_query, m_document.get(), 0, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, 0, ec);
241         if (ec || !result)
242             return;
243
244         unsigned long size = result->snapshotLength(ec);
245         for (unsigned long i = 0; !ec && i < size; ++i) {
246             Node* node = result->snapshotItem(i, ec);
247             if (ec)
248                 break;
249
250             if (node->nodeType() == Node::ATTRIBUTE_NODE)
251                 node = static_cast<Attr*>(node)->ownerElement();
252             resultCollector.add(node);
253         }
254 #else
255         UNUSED_PARAM(resultCollector);
256 #endif
257     }
258 };
259
260 class MatchPlainTextJob : public MatchXPathJob {
261 public:
262     MatchPlainTextJob(Document* document, const String& query) : MatchXPathJob(document, query)
263     {
264         m_query = "//text()[contains(., '" + m_query + "')] | //comment()[contains(., '" + m_query + "')]";
265     }
266     virtual ~MatchPlainTextJob() { }
267 };
268
269 }
270
271 RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent)
272     : m_domAgent(domAgent)
273     , m_timer(this, &RevalidateStyleAttributeTask::onTimer)
274 {
275 }
276
277 void RevalidateStyleAttributeTask::scheduleFor(Element* element)
278 {
279     m_elements.add(element);
280     if (!m_timer.isActive())
281         m_timer.startOneShot(0);
282 }
283
284 void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*)
285 {
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);
291
292     m_elements.clear();
293 }
294
295 InspectorDOMAgent::InspectorDOMAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorClient* client, InspectorState* inspectorState, InjectedScriptManager* injectedScriptManager)
296     : m_instrumentingAgents(instrumentingAgents)
297     , m_pageAgent(pageAgent)
298     , m_client(client)
299     , m_inspectorState(inspectorState)
300     , m_injectedScriptManager(injectedScriptManager)
301     , m_frontend(0)
302     , m_domListener(0)
303     , m_lastNodeId(1)
304     , m_matchJobsTimer(this, &InspectorDOMAgent::onMatchJobsTimer)
305     , m_searchingForNode(false)
306 {
307 }
308
309 InspectorDOMAgent::~InspectorDOMAgent()
310 {
311     reset();
312     ASSERT(!m_highlightData || (!m_highlightData->node && !m_highlightData->rect));
313     ASSERT(!m_searchingForNode);
314 }
315
316 void InspectorDOMAgent::setFrontend(InspectorFrontend* frontend)
317 {
318     ASSERT(!m_frontend);
319     m_frontend = frontend->dom();
320     m_instrumentingAgents->setInspectorDOMAgent(this);
321     m_document = m_pageAgent->mainFrame()->document();
322
323     if (m_nodeToFocus)
324         focusNode();
325 }
326
327 void InspectorDOMAgent::clearFrontend()
328 {
329     ASSERT(m_frontend);
330     setSearchingForNode(false, 0);
331
332     ErrorString error;
333     hideHighlight(&error);
334
335     m_frontend = 0;
336     m_instrumentingAgents->setInspectorDOMAgent(0);
337     m_inspectorState->setBoolean(DOMAgentState::documentRequested, false);
338     reset();
339 }
340
341 void InspectorDOMAgent::restore()
342 {
343     // Reset document to avoid early return from setDocument.
344     m_document = 0;
345     setDocument(m_pageAgent->mainFrame()->document());
346 }
347
348 Vector<Document*> InspectorDOMAgent::documents()
349 {
350     Vector<Document*> result;
351     for (Frame* frame = m_document->frame(); frame; frame = frame->tree()->traverseNext()) {
352         Document* document = frame->document();
353         if (!document)
354             continue;
355         result.append(document);
356     }
357     return result;
358 }
359
360 Node* InspectorDOMAgent::highlightedNode() const
361 {
362     return m_highlightData ? m_highlightData->node.get() : 0;
363 }
364
365 void InspectorDOMAgent::reset()
366 {
367     ErrorString error;
368     cancelSearch(&error);
369     discardBindings();
370     if (m_revalidateStyleAttrTask)
371         m_revalidateStyleAttrTask->reset();
372     m_document = 0;
373 }
374
375 void InspectorDOMAgent::setDOMListener(DOMListener* listener)
376 {
377     m_domListener = listener;
378 }
379
380 void InspectorDOMAgent::setDocument(Document* doc)
381 {
382     if (doc == m_document.get())
383         return;
384
385     reset();
386
387     m_document = doc;
388
389     if (!m_inspectorState->getBoolean(DOMAgentState::documentRequested))
390         return;
391
392     // Immediately communicate 0 document or document that has finished loading.
393     if (!doc || !doc->parsing())
394         m_frontend->documentUpdated();
395 }
396
397 void InspectorDOMAgent::releaseDanglingNodes()
398 {
399     deleteAllValues(m_danglingNodeToIdMaps);
400     m_danglingNodeToIdMaps.clear();
401 }
402
403 int InspectorDOMAgent::bind(Node* node, NodeToIdMap* nodesMap)
404 {
405     int id = nodesMap->get(node);
406     if (id)
407         return id;
408     id = m_lastNodeId++;
409     nodesMap->set(node, id);
410     m_idToNode.set(id, node);
411     m_idToNodesMap.set(id, nodesMap);
412     return id;
413 }
414
415 void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap)
416 {
417     if (node->isFrameOwnerElement()) {
418         const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>(node);
419         if (m_domListener)
420             m_domListener->didRemoveDocument(frameOwner->contentDocument());
421     }
422
423     int id = nodesMap->get(node);
424     if (!id)
425         return;
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);
433         while (child) {
434             unbind(child, nodesMap);
435             child = innerNextSibling(child);
436         }
437     }
438 }
439
440 Node* InspectorDOMAgent::assertNode(ErrorString* errorString, int nodeId)
441 {
442     Node* node = nodeForId(nodeId);
443     if (!node) {
444         *errorString = "Could not find node with given id";
445         return 0;
446     }
447     return node;
448 }
449
450 Element* InspectorDOMAgent::assertElement(ErrorString* errorString, int nodeId)
451 {
452     Node* node = assertNode(errorString, nodeId);
453     if (!node)
454         return 0;
455
456     if (node->nodeType() != Node::ELEMENT_NODE) {
457         *errorString = "Node is not an Element";
458         return 0;
459     }
460     return toElement(node);
461 }
462
463
464 HTMLElement* InspectorDOMAgent::assertHTMLElement(ErrorString* errorString, int nodeId)
465 {
466     Element* element = assertElement(errorString, nodeId);
467     if (!element)
468         return 0;
469
470     if (!element->isHTMLElement()) {
471         *errorString = "Node is not an HTML Element";
472         return 0;
473     }
474     return toHTMLElement(element);
475 }
476
477 void InspectorDOMAgent::getDocument(ErrorString*, RefPtr<InspectorObject>* root)
478 {
479     m_inspectorState->setBoolean(DOMAgentState::documentRequested, true);
480
481     if (!m_document)
482         return;
483
484     // Reset backend state.
485     RefPtr<Document> doc = m_document;
486     reset();
487     m_document = doc;
488
489     *root = buildObjectForNode(m_document.get(), 2, &m_documentNodeToIdMap);
490 }
491
492 void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId)
493 {
494     Node* node = nodeForId(nodeId);
495     if (!node || (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE && node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE))
496         return;
497     if (m_childrenRequested.contains(nodeId))
498         return;
499
500     NodeToIdMap* nodeMap = m_idToNodesMap.get(nodeId);
501     RefPtr<InspectorArray> children = buildArrayForContainerChildren(node, 1, nodeMap);
502     m_frontend->setChildNodes(nodeId, children.release());
503 }
504
505 void InspectorDOMAgent::discardBindings()
506 {
507     m_documentNodeToIdMap.clear();
508     m_idToNode.clear();
509     releaseDanglingNodes();
510     m_childrenRequested.clear();
511 }
512
513 Node* InspectorDOMAgent::nodeForId(int id)
514 {
515     if (!id)
516         return 0;
517
518     HashMap<int, Node*>::iterator it = m_idToNode.find(id);
519     if (it != m_idToNode.end())
520         return it->second;
521     return 0;
522 }
523
524 void InspectorDOMAgent::requestChildNodes(ErrorString*, int nodeId)
525 {
526     pushChildNodesToFrontend(nodeId);
527 }
528
529 void InspectorDOMAgent::querySelector(ErrorString* errorString, int nodeId, const String& selectors, int* elementId)
530 {
531     *elementId = 0;
532     Node* node = assertNode(errorString, nodeId);
533     if (!node)
534         return;
535
536     ExceptionCode ec = 0;
537     RefPtr<Element> element = node->querySelector(selectors, ec);
538     if (ec) {
539         *errorString = "DOM Error while querying";
540         return;
541     }
542
543     if (element)
544         *elementId = pushNodePathToFrontend(element.get());
545 }
546
547 void InspectorDOMAgent::querySelectorAll(ErrorString* errorString, int nodeId, const String& selectors, RefPtr<InspectorArray>* result)
548 {
549     Node* node = assertNode(errorString, nodeId);
550     if (!node)
551         return;
552
553     ExceptionCode ec = 0;
554     RefPtr<NodeList> nodes = node->querySelectorAll(selectors, ec);
555     if (ec) {
556         *errorString = "DOM Error while querying";
557         return;
558     }
559
560     for (unsigned i = 0; i < nodes->length(); ++i)
561         (*result)->pushNumber(pushNodePathToFrontend(nodes->item(i)));
562 }
563
564 int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush)
565 {
566     ASSERT(nodeToPush);  // Invalid input
567
568     if (!m_document)
569         return 0;
570     if (!m_documentNodeToIdMap.contains(m_document))
571         return 0;
572
573     // Return id in case the node is known.
574     int result = m_documentNodeToIdMap.get(nodeToPush);
575     if (result)
576         return result;
577
578     Node* node = nodeToPush;
579     Vector<Node*> path;
580     NodeToIdMap* danglingMap = 0;
581
582     while (true) {
583         Node* parent = innerParentNode(node);
584         if (!parent) {
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);
591             break;
592         } else {
593             path.append(parent);
594             if (m_documentNodeToIdMap.get(parent))
595                 break;
596             else
597                 node = parent;
598         }
599     }
600
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));
604         ASSERT(nodeId);
605         pushChildNodesToFrontend(nodeId);
606     }
607     return map->get(nodeToPush);
608 }
609
610 int InspectorDOMAgent::boundNodeId(Node* node)
611 {
612     return m_documentNodeToIdMap.get(node);
613 }
614
615 void InspectorDOMAgent::setAttributeValue(ErrorString* errorString, int elementId, const String& name, const String& value)
616 {
617     Element* element = assertElement(errorString, elementId);
618     if (!element)
619         return;
620
621     ExceptionCode ec = 0;
622     element->setAttribute(name, value, ec);
623     if (ec)
624         *errorString = "Internal error: could not set attribute value.";
625 }
626
627 void InspectorDOMAgent::setAttributesText(ErrorString* errorString, int elementId, const String& text, const String* const name)
628 {
629     Element* element = assertElement(errorString, elementId);
630     if (!element)
631         return;
632
633     ExceptionCode ec = 0;
634     RefPtr<Element> parsedElement = element->document()->createElement("span", ec);
635     if (ec) {
636         *errorString = "Internal error: could not set attribute value.";
637         return;
638     }
639
640     toHTMLElement(parsedElement.get())->setInnerHTML("<span " + text + "></span>", ec);
641     if (ec) {
642         *errorString = "Could not parse value as attributes.";
643         return;
644     }
645
646     Node* child = parsedElement->firstChild();
647     if (!child) {
648         *errorString = "Could not parse value as attributes.";
649         return;
650     }
651
652     const NamedNodeMap* attrMap = toHTMLElement(child)->attributes(true);
653     if (!attrMap && name) {
654         element->removeAttribute(*name, ec);
655         if (ec)
656             *errorString = "Could not remove attribute.";
657         return;
658     }
659
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);
667         if (ec) {
668             *errorString = "Internal error: could not set attribute value.";
669             return;
670         }
671     }
672
673     if (!foundOriginalAttribute && name) {
674         element->removeAttribute(*name, ec);
675         if (ec)
676             *errorString = "Could not remove attribute.";
677         return;
678     }
679 }
680
681 void InspectorDOMAgent::removeAttribute(ErrorString* errorString, int elementId, const String& name)
682 {
683     Element* element = assertElement(errorString, elementId);
684     if (element) {
685         ExceptionCode ec = 0;
686         element->removeAttribute(name, ec);
687         if (ec)
688             *errorString = "Exception while removing attribute";
689     }
690 }
691
692 void InspectorDOMAgent::removeNode(ErrorString* errorString, int nodeId)
693 {
694     Node* node = assertNode(errorString, nodeId);
695     if (!node)
696         return;
697
698     ContainerNode* parentNode = node->parentNode();
699     if (!parentNode) {
700         *errorString = "Can not remove detached node";
701         return;
702     }
703
704     ExceptionCode ec = 0;
705     parentNode->removeChild(node, ec);
706     if (ec)
707         *errorString = "Could not remove node due to DOM exception";
708 }
709
710 void InspectorDOMAgent::setNodeName(ErrorString*, int nodeId, const String& tagName, int* newId)
711 {
712     *newId = 0;
713
714     Node* oldNode = nodeForId(nodeId);
715     if (!oldNode || !oldNode->isElementNode())
716         return;
717
718     ExceptionCode ec = 0;
719     RefPtr<Element> newElem = oldNode->document()->createElement(tagName, ec);
720     if (ec)
721         return;
722
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)));
727
728     // Copy over the original node's children.
729     Node* child;
730     while ((child = oldNode->firstChild()))
731         newElem->appendChild(child, ec);
732
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);
737
738     if (ec)
739         return;
740
741     *newId = pushNodePathToFrontend(newElem.get());
742     if (m_childrenRequested.contains(nodeId))
743         pushChildNodesToFrontend(*newId);
744 }
745
746 void InspectorDOMAgent::getOuterHTML(ErrorString* errorString, int nodeId, WTF::String* outerHTML)
747 {
748     HTMLElement* element = assertHTMLElement(errorString, nodeId);
749     if (element)
750         *outerHTML = element->outerHTML();
751 }
752
753 void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const String& outerHTML, int* newId)
754 {
755     HTMLElement* htmlElement = assertHTMLElement(errorString, nodeId);
756     if (!htmlElement)
757         return;
758
759     bool requiresTotalUpdate = htmlElement->tagName() == "HTML" || htmlElement->tagName() == "BODY" || htmlElement->tagName() == "HEAD";
760
761     bool childrenRequested = m_childrenRequested.contains(nodeId);
762     Node* previousSibling = htmlElement->previousSibling();
763     ContainerNode* parentNode = htmlElement->parentNode();
764
765     ExceptionCode ec = 0;
766     htmlElement->setOuterHTML(outerHTML, ec);
767     if (ec)
768         return;
769
770     if (requiresTotalUpdate) {
771         RefPtr<Document> document = m_document;
772         reset();
773         setDocument(document.get());
774         *newId = 0;
775         return;
776     }
777
778     Node* newNode = previousSibling ? previousSibling->nextSibling() : parentNode->firstChild();
779     if (!newNode) {
780         // The only child node has been deleted.
781         *newId = 0;
782         return;
783     }
784
785     *newId = pushNodePathToFrontend(newNode);
786     if (childrenRequested)
787         pushChildNodesToFrontend(*newId);
788 }
789
790 void InspectorDOMAgent::setNodeValue(ErrorString* errorString, int nodeId, const String& value)
791 {
792     Node* node = assertNode(errorString, nodeId);
793     if (!node)
794         return;
795
796     if (node->nodeType() != Node::TEXT_NODE) {
797         *errorString = "Can only set value of text nodes";
798         return;
799     }
800
801     Text* textNode = static_cast<Text*>(node);
802     ExceptionCode ec = 0;
803     textNode->replaceWholeText(value, ec);
804     if (ec)
805         *errorString = "DOM Error while setting the node value";
806 }
807
808 void InspectorDOMAgent::getEventListenersForNode(ErrorString*, int nodeId, RefPtr<InspectorArray>* listenersArray)
809 {
810     Node* node = nodeForId(nodeId);
811     EventTargetData* d;
812
813     // Quick break if a null node or no listeners at all
814     if (!node || !(d = node->eventTargetData()))
815         return;
816
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);
823
824     // Quick break if no useful listeners
825     size_t eventTypesLength = eventTypes.size();
826     if (!eventTypesLength)
827         return;
828
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);
833
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)));
842         }
843     }
844
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)));
849     }
850
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));
860         }
861     }
862
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));
871         }
872     }
873 }
874
875 void InspectorDOMAgent::performSearch(ErrorString* error, const String& whitespaceTrimmedQuery, const bool* const runSynchronously)
876 {
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
880     //    is sufficient.
881
882     unsigned queryLength = whitespaceTrimmedQuery.length();
883     bool startTagFound = !whitespaceTrimmedQuery.find('<');
884     bool endTagFound = whitespaceTrimmedQuery.reverseFind('>') + 1 == queryLength;
885
886     String tagNameQuery = whitespaceTrimmedQuery;
887     if (startTagFound || endTagFound)
888         tagNameQuery = tagNameQuery.substring(startTagFound ? 1 : 0, endTagFound ? queryLength - 1 : queryLength);
889     if (!Document::isValidName(tagNameQuery))
890         tagNameQuery = "";
891
892     String attributeNameQuery = whitespaceTrimmedQuery;
893     if (!Document::isValidName(attributeNameQuery))
894         attributeNameQuery = "";
895
896     String escapedQuery = whitespaceTrimmedQuery;
897     escapedQuery.replace("'", "\\'");
898     String escapedTagNameQuery = tagNameQuery;
899     escapedTagNameQuery.replace("'", "\\'");
900
901     // Clear pending jobs.
902     cancelSearch(error);
903
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;
908
909         if (!tagNameQuery.isEmpty() && startTagFound && endTagFound) {
910             m_pendingMatchJobs.append(new MatchExactTagNamesJob(document, tagNameQuery));
911             m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
912             continue;
913         }
914
915         if (!tagNameQuery.isEmpty() && startTagFound) {
916             m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[starts-with(name(), '" + escapedTagNameQuery + "')]"));
917             m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
918             continue;
919         }
920
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));
926             continue;
927         }
928
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));
935             continue;
936         }
937
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));
948     }
949
950     if (runSynchronously && *runSynchronously) {
951         // For tests.
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);
956         cancelSearch(error);
957         return;
958     }
959     m_matchJobsTimer.startOneShot(0);
960 }
961
962 void InspectorDOMAgent::cancelSearch(ErrorString*)
963 {
964     if (m_matchJobsTimer.isActive())
965         m_matchJobsTimer.stop();
966     deleteAllValues(m_pendingMatchJobs);
967     m_pendingMatchJobs.clear();
968     m_searchResults.clear();
969 }
970
971 bool InspectorDOMAgent::handleMousePress()
972 {
973     if (!m_searchingForNode)
974         return false;
975
976     if (m_highlightData && m_highlightData->node) {
977         RefPtr<Node> node = m_highlightData->node;
978         setSearchingForNode(false, 0);
979         inspect(node.get());
980     }
981     return true;
982 }
983
984 void InspectorDOMAgent::inspect(Node* node)
985 {
986     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
987         node = node->parentNode();
988     m_nodeToFocus = node;
989
990     focusNode();
991 }
992
993 void InspectorDOMAgent::focusNode()
994 {
995     if (!m_frontend)
996         return;
997
998     ASSERT(m_nodeToFocus);
999
1000     RefPtr<Node> node = m_nodeToFocus.get();
1001     m_nodeToFocus = 0;
1002
1003     Document* document = node->ownerDocument();
1004     if (!document)
1005         return;
1006     Frame* frame = document->frame();
1007     if (!frame)
1008         return;
1009
1010     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
1011     if (injectedScript.hasNoValue())
1012         return;
1013
1014     injectedScript.inspectNode(node.get());
1015 }
1016
1017 void InspectorDOMAgent::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
1018 {
1019     if (!m_searchingForNode || !m_highlightData)
1020         return;
1021
1022     Node* node = result.innerNode();
1023     while (node && node->nodeType() == Node::TEXT_NODE)
1024         node = node->parentNode();
1025     if (node) {
1026         m_highlightData->node = node;
1027         highlight();
1028     }
1029 }
1030
1031 void InspectorDOMAgent::setSearchingForNode(bool enabled, InspectorObject* highlightConfig)
1032 {
1033     if (m_searchingForNode == enabled)
1034         return;
1035     m_searchingForNode = enabled;
1036     if (enabled)
1037         setHighlightDataFromConfig(highlightConfig);
1038     else {
1039         ErrorString error;
1040         hideHighlight(&error);
1041         m_highlightData.clear();
1042     }
1043 }
1044
1045 void InspectorDOMAgent::setInspectModeEnabled(ErrorString*, bool enabled, const RefPtr<InspectorObject>* highlightConfig)
1046 {
1047     setSearchingForNode(enabled, highlightConfig ? highlightConfig->get() : 0);
1048 }
1049
1050 bool InspectorDOMAgent::setHighlightDataFromConfig(InspectorObject* highlightConfig)
1051 {
1052     if (!highlightConfig) {
1053         m_highlightData.clear();
1054         return false;
1055     }
1056
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);
1069     return true;
1070 }
1071
1072 void InspectorDOMAgent::highlight()
1073 {
1074     // This method requires m_highlightData to have been filled in by its client.
1075     ASSERT(m_highlightData);
1076     m_client->highlight();
1077 }
1078
1079 void InspectorDOMAgent::highlightRect(ErrorString*, int x, int y, int width, int height, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor)
1080 {
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();
1086 }
1087
1088 void InspectorDOMAgent::highlightNode(
1089     ErrorString*,
1090     int nodeId,
1091     const RefPtr<InspectorObject> highlightConfig)
1092 {
1093     if (Node* node = nodeForId(nodeId)) {
1094         if (setHighlightDataFromConfig(highlightConfig.get())) {
1095             m_highlightData->node = node;
1096             highlight();
1097         }
1098     }
1099 }
1100
1101 void InspectorDOMAgent::highlightFrame(
1102     ErrorString*,
1103     const String& frameId,
1104     const RefPtr<InspectorObject>* color,
1105     const RefPtr<InspectorObject>* outlineColor)
1106 {
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);
1114         highlight();
1115     }
1116 }
1117
1118 void InspectorDOMAgent::hideHighlight(ErrorString*)
1119 {
1120     if (m_highlightData) {
1121         m_highlightData->node.clear();
1122         m_highlightData->rect.clear();
1123     }
1124     m_client->hideHighlight();
1125 }
1126
1127 void InspectorDOMAgent::moveTo(ErrorString* error, int nodeId, int targetElementId, const int* const anchorNodeId, int* newNodeId)
1128 {
1129     Node* node = assertNode(error, nodeId);
1130     if (!node)
1131         return;
1132
1133     Element* targetElement = assertElement(error, targetElementId);
1134     if (!targetElement)
1135         return;
1136
1137     Node* anchorNode = 0;
1138     if (anchorNodeId && *anchorNodeId) {
1139         anchorNode = assertNode(error, *anchorNodeId);
1140         if (!anchorNode)
1141             return;
1142         if (anchorNode->parentNode() != targetElement) {
1143             *error = "Anchor node must be child of the target element.";
1144             return;
1145         }
1146     }
1147
1148     ExceptionCode ec = 0;
1149     bool success = targetElement->insertBefore(node, anchorNode, ec);
1150     if (ec || !success) {
1151         *error = "Could not drop node.";
1152         return;
1153     }
1154     *newNodeId = pushNodePathToFrontend(node);
1155 }
1156
1157 void InspectorDOMAgent::resolveNode(ErrorString* error, int nodeId, const String* const objectGroup, RefPtr<InspectorObject>* result)
1158 {
1159     String objectGroupName = objectGroup ? *objectGroup : "";
1160     Node* node = nodeForId(nodeId);
1161     if (!node) {
1162         *error = "No node with given id found.";
1163         return;
1164     }
1165     *result = resolveNode(node, objectGroupName);
1166 }
1167
1168 void InspectorDOMAgent::getAttributes(ErrorString* errorString, int nodeId, RefPtr<InspectorArray>* result)
1169 {
1170     Element* element = assertElement(errorString, nodeId);
1171     if (!element)
1172         return;
1173
1174     *result = buildArrayForElementAttributes(element);
1175 }
1176
1177 void InspectorDOMAgent::requestNode(ErrorString*, const String& objectId, int* nodeId)
1178 {
1179     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
1180     Node* node = injectedScript.nodeForObjectId(objectId);
1181     if (node)
1182         *nodeId = pushNodePathToFrontend(node);
1183     else
1184         *nodeId = 0;
1185 }
1186
1187 String InspectorDOMAgent::documentURLString(Document* document) const
1188 {
1189     if (!document || document->url().isNull())
1190         return "";
1191     return document->url().string();
1192 }
1193
1194 PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap)
1195 {
1196     RefPtr<InspectorObject> value = InspectorObject::create();
1197
1198     int id = bind(node, nodesMap);
1199     String nodeName;
1200     String localName;
1201     String nodeValue;
1202
1203     switch (node->nodeType()) {
1204         case Node::TEXT_NODE:
1205         case Node::COMMENT_NODE:
1206         case Node::CDATA_SECTION_NODE:
1207             nodeValue = node->nodeValue();
1208             break;
1209         case Node::ATTRIBUTE_NODE:
1210             localName = node->localName();
1211             break;
1212         case Node::DOCUMENT_FRAGMENT_NODE:
1213             break;
1214         case Node::DOCUMENT_NODE:
1215         case Node::ELEMENT_NODE:
1216         default:
1217             nodeName = node->nodeName();
1218             localName = node->localName();
1219             break;
1220     }
1221
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);
1227
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());
1234
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()));
1241             }
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());
1246         }
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());
1256     }
1257     return value.release();
1258 }
1259
1260 PassRefPtr<InspectorArray> InspectorDOMAgent::buildArrayForElementAttributes(Element* element)
1261 {
1262     RefPtr<InspectorArray> attributesValue = InspectorArray::create();
1263     // Go through all attributes and serialize them.
1264     const NamedNodeMap* attrMap = element->attributes(true);
1265     if (!attrMap)
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());
1273     }
1274     return attributesValue.release();
1275 }
1276
1277 PassRefPtr<InspectorArray> InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap)
1278 {
1279     RefPtr<InspectorArray> children = InspectorArray::create();
1280     Node* child = innerFirstChild(container);
1281
1282     if (depth == 0) {
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();
1287     }
1288
1289     depth--;
1290     m_childrenRequested.add(bind(container, nodesMap));
1291
1292     while (child) {
1293         children->pushObject(buildObjectForNode(child, depth, nodesMap));
1294         child = innerNextSibling(child);
1295     }
1296     return children.release();
1297 }
1298
1299 PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node)
1300 {
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()));
1308     String sourceName;
1309     int lineNumber;
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);
1315     }
1316     return value.release();
1317 }
1318
1319 Node* InspectorDOMAgent::innerFirstChild(Node* node)
1320 {
1321     if (node->isFrameOwnerElement()) {
1322         HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node);
1323         Document* doc = frameOwner->contentDocument();
1324         if (doc)
1325             return doc->firstChild();
1326     }
1327     node = node->firstChild();
1328     while (isWhitespace(node))
1329         node = node->nextSibling();
1330     return node;
1331 }
1332
1333 Node* InspectorDOMAgent::innerNextSibling(Node* node)
1334 {
1335     do {
1336         node = node->nextSibling();
1337     } while (isWhitespace(node));
1338     return node;
1339 }
1340
1341 Node* InspectorDOMAgent::innerPreviousSibling(Node* node)
1342 {
1343     do {
1344         node = node->previousSibling();
1345     } while (isWhitespace(node));
1346     return node;
1347 }
1348
1349 unsigned InspectorDOMAgent::innerChildNodeCount(Node* node)
1350 {
1351     unsigned count = 0;
1352     Node* child = innerFirstChild(node);
1353     while (child) {
1354         count++;
1355         child = innerNextSibling(child);
1356     }
1357     return count;
1358 }
1359
1360 Node* InspectorDOMAgent::innerParentNode(Node* node)
1361 {
1362     ContainerNode* parent = node->parentNode();
1363     if (parent && parent->isDocumentNode())
1364         return static_cast<Document*>(parent)->ownerElement();
1365     return parent;
1366 }
1367
1368 bool InspectorDOMAgent::isWhitespace(Node* node)
1369 {
1370     //TODO: pull ignoreWhitespace setting from the frontend and use here.
1371     return node && node->nodeType() == Node::TEXT_NODE && node->nodeValue().stripWhiteSpace().length() == 0;
1372 }
1373
1374 void InspectorDOMAgent::mainFrameDOMContentLoaded()
1375 {
1376     // Re-push document once it is loaded.
1377     discardBindings();
1378     if (m_inspectorState->getBoolean(DOMAgentState::documentRequested))
1379         m_frontend->documentUpdated();
1380 }
1381
1382 void InspectorDOMAgent::loadEventFired(Document* document)
1383 {
1384     Element* frameOwner = document->ownerElement();
1385     if (!frameOwner)
1386         return;
1387
1388     int frameOwnerId = m_documentNodeToIdMap.get(frameOwner);
1389     if (!frameOwnerId)
1390         return;
1391
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));
1395     } else {
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));
1405     }
1406 }
1407
1408 void InspectorDOMAgent::didInsertDOMNode(Node* node)
1409 {
1410     if (isWhitespace(node))
1411         return;
1412
1413     // We could be attaching existing subtree. Forget the bindings.
1414     unbind(node, &m_documentNodeToIdMap);
1415
1416     ContainerNode* parent = node->parentNode();
1417     int parentId = m_documentNodeToIdMap.get(parent);
1418     // Return if parent is not mapped yet.
1419     if (!parentId)
1420         return;
1421
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));
1425     } else {
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());
1431     }
1432 }
1433
1434 void InspectorDOMAgent::didRemoveDOMNode(Node* node)
1435 {
1436     if (isWhitespace(node))
1437         return;
1438
1439     ContainerNode* parent = node->parentNode();
1440     int parentId = m_documentNodeToIdMap.get(parent);
1441     // If parent is not mapped yet -> ignore the event.
1442     if (!parentId)
1443         return;
1444
1445     if (m_domListener)
1446         m_domListener->didRemoveDOMNode(node);
1447
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);
1452     } else
1453         m_frontend->childNodeRemoved(parentId, m_documentNodeToIdMap.get(node));
1454     unbind(node, &m_documentNodeToIdMap);
1455 }
1456
1457 void InspectorDOMAgent::didModifyDOMAttr(Element* element)
1458 {
1459     int id = boundNodeId(element);
1460     // If node is not mapped yet -> ignore the event.
1461     if (!id)
1462         return;
1463
1464     if (m_domListener)
1465         m_domListener->didModifyDOMAttr(element);
1466
1467     m_frontend->attributesUpdated(id);
1468 }
1469
1470 void InspectorDOMAgent::styleAttributeInvalidated(const Vector<Element*>& elements)
1471 {
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.
1477         if (!id)
1478             continue;
1479
1480         if (m_domListener)
1481             m_domListener->didModifyDOMAttr(element);
1482         nodeIds->pushNumber(id);
1483     }
1484     m_frontend->inlineStyleInvalidated(nodeIds.release());
1485 }
1486
1487 void InspectorDOMAgent::characterDataModified(CharacterData* characterData)
1488 {
1489     int id = m_documentNodeToIdMap.get(characterData);
1490     if (!id)
1491         return;
1492     m_frontend->characterDataModified(id, characterData->data());
1493 }
1494
1495 void InspectorDOMAgent::didInvalidateStyleAttr(Node* node)
1496 {
1497     int id = m_documentNodeToIdMap.get(node);
1498     // If node is not mapped yet -> ignore the event.
1499     if (!id)
1500         return;
1501
1502     if (!m_revalidateStyleAttrTask)
1503         m_revalidateStyleAttrTask = adoptPtr(new RevalidateStyleAttributeTask(this));
1504     m_revalidateStyleAttrTask->scheduleFor(static_cast<Element*>(node));
1505 }
1506
1507 Node* InspectorDOMAgent::nodeForPath(const String& path)
1508 {
1509     // The path is of form "1,HTML,2,BODY,1,DIV"
1510     if (!m_document)
1511         return 0;
1512
1513     Node* node = m_document.get();
1514     Vector<String> pathTokens;
1515     path.split(",", false, pathTokens);
1516     if (!pathTokens.size())
1517         return 0;
1518     for (size_t i = 0; i < pathTokens.size() - 1; i += 2) {
1519         bool success = true;
1520         unsigned childNumber = pathTokens[i].toUInt(&success);
1521         if (!success)
1522             return 0;
1523         if (childNumber >= innerChildNodeCount(node))
1524             return 0;
1525
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);
1530
1531         if (!child || child->nodeName() != childName)
1532             return 0;
1533         node = child;
1534     }
1535     return node;
1536 }
1537
1538 void InspectorDOMAgent::onMatchJobsTimer(Timer<InspectorDOMAgent>*)
1539 {
1540     if (!m_pendingMatchJobs.size()) {
1541         ErrorString error;
1542         cancelSearch(&error);
1543         return;
1544     }
1545
1546     ListHashSet<Node*> resultCollector;
1547     MatchJob* job = m_pendingMatchJobs.takeFirst();
1548     job->match(resultCollector);
1549     delete job;
1550
1551     reportNodesAsSearchResults(resultCollector);
1552
1553     m_matchJobsTimer.startOneShot(0.025);
1554 }
1555
1556 void InspectorDOMAgent::reportNodesAsSearchResults(ListHashSet<Node*>& resultCollector)
1557 {
1558     RefPtr<InspectorArray> nodeIds = InspectorArray::create();
1559     for (ListHashSet<Node*>::iterator it = resultCollector.begin(); it != resultCollector.end(); ++it) {
1560         if (m_searchResults.contains(*it))
1561             continue;
1562         m_searchResults.add(*it);
1563         nodeIds->pushNumber(pushNodePathToFrontend(*it));
1564     }
1565     m_frontend->searchResults(nodeIds.release());
1566 }
1567
1568 void InspectorDOMAgent::copyNode(ErrorString*, int nodeId)
1569 {
1570     Node* node = nodeForId(nodeId);
1571     if (!node)
1572         return;
1573     String markup = createMarkup(node);
1574     Pasteboard::generalPasteboard()->writePlainText(markup);
1575 }
1576
1577 void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString*, const String& path, int* nodeId)
1578 {
1579     if (Node* node = nodeForPath(path))
1580         *nodeId = pushNodePathToFrontend(node);
1581 }
1582
1583 PassRefPtr<InspectorObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup)
1584 {
1585     Document* document = node->isDocumentNode() ? node->document() : node->ownerDocument();
1586     Frame* frame = document ? document->frame() : 0;
1587     if (!frame)
1588         return 0;
1589
1590     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
1591     if (injectedScript.hasNoValue())
1592         return 0;
1593
1594     return injectedScript.wrapNode(node, objectGroup);
1595 }
1596
1597 void InspectorDOMAgent::drawHighlight(GraphicsContext& context) const
1598 {
1599     if (!m_highlightData)
1600         return;
1601
1602     DOMNodeHighlighter::drawHighlight(context, m_highlightData->node ? m_highlightData->node->document() : m_document.get(), m_highlightData.get());
1603 }
1604
1605 } // namespace WebCore
1606
1607 #endif // ENABLE(INSPECTOR)