4319a996b689707cc929356d10fc28df1141095e
[WebKit-https.git] / 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::setAttributesAsText(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 = d->eventListenerMap.eventTypes();
819
820     // Quick break if no useful listeners
821     size_t eventTypesLength = eventTypes.size();
822     if (!eventTypesLength)
823         return;
824
825     // The Node's Ancestors (not including self)
826     Vector<ContainerNode*> ancestors;
827     for (ContainerNode* ancestor = node->parentOrHostNode(); ancestor; ancestor = ancestor->parentOrHostNode())
828         ancestors.append(ancestor);
829
830     // Nodes and their Listeners for the concerned event types (order is top to bottom)
831     Vector<EventListenerInfo> eventInformation;
832     for (size_t i = ancestors.size(); i; --i) {
833         ContainerNode* ancestor = ancestors[i - 1];
834         for (size_t j = 0; j < eventTypesLength; ++j) {
835             AtomicString& type = eventTypes[j];
836             if (ancestor->hasEventListeners(type))
837                 eventInformation.append(EventListenerInfo(ancestor, type, ancestor->getEventListeners(type)));
838         }
839     }
840
841     // Insert the Current Node at the end of that list (last in capturing, first in bubbling)
842     for (size_t i = 0; i < eventTypesLength; ++i) {
843         const AtomicString& type = eventTypes[i];
844         eventInformation.append(EventListenerInfo(node, type, node->getEventListeners(type)));
845     }
846
847     // Get Capturing Listeners (in this order)
848     size_t eventInformationLength = eventInformation.size();
849     for (size_t i = 0; i < eventInformationLength; ++i) {
850         const EventListenerInfo& info = eventInformation[i];
851         const EventListenerVector& vector = info.eventListenerVector;
852         for (size_t j = 0; j < vector.size(); ++j) {
853             const RegisteredEventListener& listener = vector[j];
854             if (listener.useCapture)
855                 (*listenersArray)->pushObject(buildObjectForEventListener(listener, info.eventType, info.node));
856         }
857     }
858
859     // Get Bubbling Listeners (reverse order)
860     for (size_t i = eventInformationLength; i; --i) {
861         const EventListenerInfo& info = eventInformation[i - 1];
862         const EventListenerVector& vector = info.eventListenerVector;
863         for (size_t j = 0; j < vector.size(); ++j) {
864             const RegisteredEventListener& listener = vector[j];
865             if (!listener.useCapture)
866                 (*listenersArray)->pushObject(buildObjectForEventListener(listener, info.eventType, info.node));
867         }
868     }
869 }
870
871 void InspectorDOMAgent::performSearch(ErrorString* error, const String& whitespaceTrimmedQuery, const bool* const runSynchronously)
872 {
873     // FIXME: Few things are missing here:
874     // 1) Search works with node granularity - number of matches within node is not calculated.
875     // 2) There is no need to push all search results to the front-end at a time, pushing next / previous result
876     //    is sufficient.
877
878     unsigned queryLength = whitespaceTrimmedQuery.length();
879     bool startTagFound = !whitespaceTrimmedQuery.find('<');
880     bool endTagFound = whitespaceTrimmedQuery.reverseFind('>') + 1 == queryLength;
881
882     String tagNameQuery = whitespaceTrimmedQuery;
883     if (startTagFound || endTagFound)
884         tagNameQuery = tagNameQuery.substring(startTagFound ? 1 : 0, endTagFound ? queryLength - 1 : queryLength);
885     if (!Document::isValidName(tagNameQuery))
886         tagNameQuery = "";
887
888     String attributeNameQuery = whitespaceTrimmedQuery;
889     if (!Document::isValidName(attributeNameQuery))
890         attributeNameQuery = "";
891
892     String escapedQuery = whitespaceTrimmedQuery;
893     escapedQuery.replace("'", "\\'");
894     String escapedTagNameQuery = tagNameQuery;
895     escapedTagNameQuery.replace("'", "\\'");
896
897     // Clear pending jobs.
898     cancelSearch(error);
899
900     // Find all frames, iframes and object elements to search their documents.
901     Vector<Document*> docs = documents();
902     for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
903         Document* document = *it;
904
905         if (!tagNameQuery.isEmpty() && startTagFound && endTagFound) {
906             m_pendingMatchJobs.append(new MatchExactTagNamesJob(document, tagNameQuery));
907             m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
908             continue;
909         }
910
911         if (!tagNameQuery.isEmpty() && startTagFound) {
912             m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[starts-with(name(), '" + escapedTagNameQuery + "')]"));
913             m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
914             continue;
915         }
916
917         if (!tagNameQuery.isEmpty() && endTagFound) {
918             // FIXME: we should have a matchEndOfTagNames search function if endTagFound is true but not startTagFound.
919             // This requires ends-with() support in XPath, WebKit only supports starts-with() and contains().
920             m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(name(), '" + escapedTagNameQuery + "')]"));
921             m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
922             continue;
923         }
924
925         bool matchesEveryNode = whitespaceTrimmedQuery == "//*" || whitespaceTrimmedQuery == "*";
926         if (matchesEveryNode) {
927             // These queries will match every node. Matching everything isn't useful and can be slow for large pages,
928             // so limit the search functions list to plain text and attribute matching for these.
929             m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(@*, '" + escapedQuery + "')]"));
930             m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
931             continue;
932         }
933
934         m_pendingMatchJobs.append(new MatchExactIdJob(document, whitespaceTrimmedQuery));
935         m_pendingMatchJobs.append(new MatchExactClassNamesJob(document, whitespaceTrimmedQuery));
936         m_pendingMatchJobs.append(new MatchExactTagNamesJob(document, tagNameQuery));
937         m_pendingMatchJobs.append(new MatchQuerySelectorAllJob(document, "[" + attributeNameQuery + "]"));
938         m_pendingMatchJobs.append(new MatchQuerySelectorAllJob(document, whitespaceTrimmedQuery));
939         m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(@*, '" + escapedQuery + "')]"));
940         if (!tagNameQuery.isEmpty())
941             m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(name(), '" + escapedTagNameQuery + "')]"));
942         m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
943         m_pendingMatchJobs.append(new MatchXPathJob(document, whitespaceTrimmedQuery));
944     }
945
946     if (runSynchronously && *runSynchronously) {
947         // For tests.
948         ListHashSet<Node*> resultCollector;
949         for (Deque<MatchJob*>::iterator it = m_pendingMatchJobs.begin(); it != m_pendingMatchJobs.end(); ++it)
950             (*it)->match(resultCollector);
951         reportNodesAsSearchResults(resultCollector);
952         cancelSearch(error);
953         return;
954     }
955     m_matchJobsTimer.startOneShot(0);
956 }
957
958 void InspectorDOMAgent::cancelSearch(ErrorString*)
959 {
960     if (m_matchJobsTimer.isActive())
961         m_matchJobsTimer.stop();
962     deleteAllValues(m_pendingMatchJobs);
963     m_pendingMatchJobs.clear();
964     m_searchResults.clear();
965 }
966
967 bool InspectorDOMAgent::handleMousePress()
968 {
969     if (!m_searchingForNode)
970         return false;
971
972     if (m_highlightData && m_highlightData->node) {
973         RefPtr<Node> node = m_highlightData->node;
974         setSearchingForNode(false, 0);
975         inspect(node.get());
976     }
977     return true;
978 }
979
980 void InspectorDOMAgent::inspect(Node* node)
981 {
982     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
983         node = node->parentNode();
984     m_nodeToFocus = node;
985
986     focusNode();
987 }
988
989 void InspectorDOMAgent::focusNode()
990 {
991     if (!m_frontend)
992         return;
993
994     ASSERT(m_nodeToFocus);
995
996     RefPtr<Node> node = m_nodeToFocus.get();
997     m_nodeToFocus = 0;
998
999     Document* document = node->ownerDocument();
1000     if (!document)
1001         return;
1002     Frame* frame = document->frame();
1003     if (!frame)
1004         return;
1005
1006     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
1007     if (injectedScript.hasNoValue())
1008         return;
1009
1010     injectedScript.inspectNode(node.get());
1011 }
1012
1013 void InspectorDOMAgent::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
1014 {
1015     if (!m_searchingForNode || !m_highlightData)
1016         return;
1017
1018     Node* node = result.innerNode();
1019     while (node && node->nodeType() == Node::TEXT_NODE)
1020         node = node->parentNode();
1021     if (node) {
1022         m_highlightData->node = node;
1023         highlight();
1024     }
1025 }
1026
1027 void InspectorDOMAgent::setSearchingForNode(bool enabled, InspectorObject* highlightConfig)
1028 {
1029     if (m_searchingForNode == enabled)
1030         return;
1031     m_searchingForNode = enabled;
1032     if (enabled)
1033         setHighlightDataFromConfig(highlightConfig);
1034     else {
1035         ErrorString error;
1036         hideHighlight(&error);
1037         m_highlightData.clear();
1038     }
1039 }
1040
1041 void InspectorDOMAgent::setInspectModeEnabled(ErrorString*, bool enabled, const RefPtr<InspectorObject>* highlightConfig)
1042 {
1043     setSearchingForNode(enabled, highlightConfig ? highlightConfig->get() : 0);
1044 }
1045
1046 bool InspectorDOMAgent::setHighlightDataFromConfig(InspectorObject* highlightConfig)
1047 {
1048     if (!highlightConfig) {
1049         m_highlightData.clear();
1050         return false;
1051     }
1052
1053     m_highlightData = adoptPtr(new HighlightData());
1054     bool showInfo = false; // Default: false (do not show a tooltip).
1055     highlightConfig->getBoolean("showInfo", &showInfo);
1056     m_highlightData->showInfo = showInfo;
1057     m_highlightData->content = parseConfigColor("contentColor", highlightConfig);
1058     m_highlightData->contentOutline = parseConfigColor("contentOutlineColor", highlightConfig);
1059     m_highlightData->padding = parseConfigColor("paddingColor", highlightConfig);
1060     m_highlightData->border = parseConfigColor("borderColor", highlightConfig);
1061     m_highlightData->margin = parseConfigColor("marginColor", highlightConfig);
1062     return true;
1063 }
1064
1065 void InspectorDOMAgent::highlight()
1066 {
1067     // This method requires m_highlightData to have been filled in by its client.
1068     ASSERT(m_highlightData);
1069     m_client->highlight();
1070 }
1071
1072 void InspectorDOMAgent::highlightRect(ErrorString*, int x, int y, int width, int height, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor)
1073 {
1074     m_highlightData = adoptPtr(new HighlightData());
1075     m_highlightData->rect = adoptPtr(new IntRect(x, y, width, height));
1076     m_highlightData->content = parseColor(color);
1077     m_highlightData->contentOutline = parseColor(outlineColor);
1078     m_client->highlight();
1079 }
1080
1081 void InspectorDOMAgent::highlightNode(
1082     ErrorString*,
1083     int nodeId,
1084     const RefPtr<InspectorObject> highlightConfig)
1085 {
1086     if (Node* node = nodeForId(nodeId)) {
1087         if (setHighlightDataFromConfig(highlightConfig.get())) {
1088             m_highlightData->node = node;
1089             highlight();
1090         }
1091     }
1092 }
1093
1094 void InspectorDOMAgent::highlightFrame(
1095     ErrorString*,
1096     const String& frameId,
1097     const RefPtr<InspectorObject>* color,
1098     const RefPtr<InspectorObject>* outlineColor)
1099 {
1100     Frame* frame = m_pageAgent->frameForId(frameId);
1101     if (frame && frame->ownerElement()) {
1102         m_highlightData = adoptPtr(new HighlightData());
1103         m_highlightData->node = frame->ownerElement();
1104         m_highlightData->showInfo = true; // Always show tooltips for frames.
1105         m_highlightData->content = parseColor(color);
1106         m_highlightData->contentOutline = parseColor(outlineColor);
1107         highlight();
1108     }
1109 }
1110
1111 void InspectorDOMAgent::hideHighlight(ErrorString*)
1112 {
1113     if (m_highlightData) {
1114         m_highlightData->node.clear();
1115         m_highlightData->rect.clear();
1116     }
1117     m_client->hideHighlight();
1118 }
1119
1120 void InspectorDOMAgent::moveTo(ErrorString* error, int nodeId, int targetElementId, const int* const anchorNodeId, int* newNodeId)
1121 {
1122     Node* node = assertNode(error, nodeId);
1123     if (!node)
1124         return;
1125
1126     Element* targetElement = assertElement(error, targetElementId);
1127     if (!targetElement)
1128         return;
1129
1130     Node* anchorNode = 0;
1131     if (anchorNodeId && *anchorNodeId) {
1132         anchorNode = assertNode(error, *anchorNodeId);
1133         if (!anchorNode)
1134             return;
1135         if (anchorNode->parentNode() != targetElement) {
1136             *error = "Anchor node must be child of the target element.";
1137             return;
1138         }
1139     }
1140
1141     ExceptionCode ec = 0;
1142     bool success = targetElement->insertBefore(node, anchorNode, ec);
1143     if (ec || !success) {
1144         *error = "Could not drop node.";
1145         return;
1146     }
1147     *newNodeId = pushNodePathToFrontend(node);
1148 }
1149
1150 void InspectorDOMAgent::resolveNode(ErrorString* error, int nodeId, const String* const objectGroup, RefPtr<InspectorObject>* result)
1151 {
1152     String objectGroupName = objectGroup ? *objectGroup : "";
1153     Node* node = nodeForId(nodeId);
1154     if (!node) {
1155         *error = "No node with given id found.";
1156         return;
1157     }
1158     *result = resolveNode(node, objectGroupName);
1159 }
1160
1161 void InspectorDOMAgent::getAttributes(ErrorString* errorString, int nodeId, RefPtr<InspectorArray>* result)
1162 {
1163     Element* element = assertElement(errorString, nodeId);
1164     if (!element)
1165         return;
1166
1167     *result = buildArrayForElementAttributes(element);
1168 }
1169
1170 void InspectorDOMAgent::requestNode(ErrorString*, const String& objectId, int* nodeId)
1171 {
1172     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
1173     Node* node = injectedScript.nodeForObjectId(objectId);
1174     if (node)
1175         *nodeId = pushNodePathToFrontend(node);
1176     else
1177         *nodeId = 0;
1178 }
1179
1180 String InspectorDOMAgent::documentURLString(Document* document) const
1181 {
1182     if (!document || document->url().isNull())
1183         return "";
1184     return document->url().string();
1185 }
1186
1187 PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap)
1188 {
1189     RefPtr<InspectorObject> value = InspectorObject::create();
1190
1191     int id = bind(node, nodesMap);
1192     String nodeName;
1193     String localName;
1194     String nodeValue;
1195
1196     switch (node->nodeType()) {
1197         case Node::TEXT_NODE:
1198         case Node::COMMENT_NODE:
1199         case Node::CDATA_SECTION_NODE:
1200             nodeValue = node->nodeValue();
1201             break;
1202         case Node::ATTRIBUTE_NODE:
1203             localName = node->localName();
1204             break;
1205         case Node::DOCUMENT_FRAGMENT_NODE:
1206             break;
1207         case Node::DOCUMENT_NODE:
1208         case Node::ELEMENT_NODE:
1209         default:
1210             nodeName = node->nodeName();
1211             localName = node->localName();
1212             break;
1213     }
1214
1215     value->setNumber("nodeId", id);
1216     value->setNumber("nodeType", node->nodeType());
1217     value->setString("nodeName", nodeName);
1218     value->setString("localName", localName);
1219     value->setString("nodeValue", nodeValue);
1220
1221     if (node->nodeType() == Node::ELEMENT_NODE || node->nodeType() == Node::DOCUMENT_NODE || node->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
1222         int nodeCount = innerChildNodeCount(node);
1223         value->setNumber("childNodeCount", nodeCount);
1224         RefPtr<InspectorArray> children = buildArrayForContainerChildren(node, depth, nodesMap);
1225         if (children->length() > 0)
1226             value->setArray("children", children.release());
1227
1228         if (node->nodeType() == Node::ELEMENT_NODE) {
1229             Element* element = static_cast<Element*>(node);
1230             value->setArray("attributes", buildArrayForElementAttributes(element));
1231             if (node->isFrameOwnerElement()) {
1232                 HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node);
1233                 value->setString("documentURL", documentURLString(frameOwner->contentDocument()));
1234             }
1235         } else if (node->nodeType() == Node::DOCUMENT_NODE) {
1236             Document* document = static_cast<Document*>(node);
1237             value->setString("documentURL", documentURLString(document));
1238             value->setString("xmlVersion", document->xmlVersion());
1239         }
1240     } else if (node->nodeType() == Node::DOCUMENT_TYPE_NODE) {
1241         DocumentType* docType = static_cast<DocumentType*>(node);
1242         value->setString("publicId", docType->publicId());
1243         value->setString("systemId", docType->systemId());
1244         value->setString("internalSubset", docType->internalSubset());
1245     } else if (node->nodeType() == Node::ATTRIBUTE_NODE) {
1246         Attr* attribute = static_cast<Attr*>(node);
1247         value->setString("name", attribute->name());
1248         value->setString("value", attribute->value());
1249     }
1250     return value.release();
1251 }
1252
1253 PassRefPtr<InspectorArray> InspectorDOMAgent::buildArrayForElementAttributes(Element* element)
1254 {
1255     RefPtr<InspectorArray> attributesValue = InspectorArray::create();
1256     // Go through all attributes and serialize them.
1257     const NamedNodeMap* attrMap = element->attributes(true);
1258     if (!attrMap)
1259         return attributesValue.release();
1260     unsigned numAttrs = attrMap->length();
1261     for (unsigned i = 0; i < numAttrs; ++i) {
1262         // Add attribute pair
1263         const Attribute *attribute = attrMap->attributeItem(i);
1264         attributesValue->pushString(attribute->name().toString());
1265         attributesValue->pushString(attribute->value());
1266     }
1267     return attributesValue.release();
1268 }
1269
1270 PassRefPtr<InspectorArray> InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap)
1271 {
1272     RefPtr<InspectorArray> children = InspectorArray::create();
1273     Node* child = innerFirstChild(container);
1274
1275     if (depth == 0) {
1276         // Special-case the only text child - pretend that container's children have been requested.
1277         if (child && child->nodeType() == Node::TEXT_NODE && !innerNextSibling(child))
1278             return buildArrayForContainerChildren(container, 1, nodesMap);
1279         return children.release();
1280     }
1281
1282     depth--;
1283     m_childrenRequested.add(bind(container, nodesMap));
1284
1285     while (child) {
1286         children->pushObject(buildObjectForNode(child, depth, nodesMap));
1287         child = innerNextSibling(child);
1288     }
1289     return children.release();
1290 }
1291
1292 PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node)
1293 {
1294     RefPtr<EventListener> eventListener = registeredEventListener.listener;
1295     RefPtr<InspectorObject> value = InspectorObject::create();
1296     value->setString("type", eventType);
1297     value->setBoolean("useCapture", registeredEventListener.useCapture);
1298     value->setBoolean("isAttribute", eventListener->isAttribute());
1299     value->setNumber("nodeId", pushNodePathToFrontend(node));
1300     value->setString("handlerBody", eventListenerHandlerBody(node->document(), eventListener.get()));
1301     String sourceName;
1302     int lineNumber;
1303     if (eventListenerHandlerLocation(node->document(), eventListener.get(), sourceName, lineNumber)) {
1304         RefPtr<InspectorObject> location = InspectorObject::create();
1305         location->setString("scriptId", sourceName);
1306         location->setNumber("lineNumber", lineNumber);
1307         value->setObject("location", location);
1308     }
1309     return value.release();
1310 }
1311
1312 Node* InspectorDOMAgent::innerFirstChild(Node* node)
1313 {
1314     if (node->isFrameOwnerElement()) {
1315         HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node);
1316         Document* doc = frameOwner->contentDocument();
1317         if (doc)
1318             return doc->firstChild();
1319     }
1320     node = node->firstChild();
1321     while (isWhitespace(node))
1322         node = node->nextSibling();
1323     return node;
1324 }
1325
1326 Node* InspectorDOMAgent::innerNextSibling(Node* node)
1327 {
1328     do {
1329         node = node->nextSibling();
1330     } while (isWhitespace(node));
1331     return node;
1332 }
1333
1334 Node* InspectorDOMAgent::innerPreviousSibling(Node* node)
1335 {
1336     do {
1337         node = node->previousSibling();
1338     } while (isWhitespace(node));
1339     return node;
1340 }
1341
1342 unsigned InspectorDOMAgent::innerChildNodeCount(Node* node)
1343 {
1344     unsigned count = 0;
1345     Node* child = innerFirstChild(node);
1346     while (child) {
1347         count++;
1348         child = innerNextSibling(child);
1349     }
1350     return count;
1351 }
1352
1353 Node* InspectorDOMAgent::innerParentNode(Node* node)
1354 {
1355     ContainerNode* parent = node->parentNode();
1356     if (parent && parent->isDocumentNode())
1357         return static_cast<Document*>(parent)->ownerElement();
1358     return parent;
1359 }
1360
1361 bool InspectorDOMAgent::isWhitespace(Node* node)
1362 {
1363     //TODO: pull ignoreWhitespace setting from the frontend and use here.
1364     return node && node->nodeType() == Node::TEXT_NODE && node->nodeValue().stripWhiteSpace().length() == 0;
1365 }
1366
1367 void InspectorDOMAgent::mainFrameDOMContentLoaded()
1368 {
1369     // Re-push document once it is loaded.
1370     discardBindings();
1371     if (m_inspectorState->getBoolean(DOMAgentState::documentRequested))
1372         m_frontend->documentUpdated();
1373 }
1374
1375 void InspectorDOMAgent::loadEventFired(Document* document)
1376 {
1377     Element* frameOwner = document->ownerElement();
1378     if (!frameOwner)
1379         return;
1380
1381     int frameOwnerId = m_documentNodeToIdMap.get(frameOwner);
1382     if (!frameOwnerId)
1383         return;
1384
1385     if (!m_childrenRequested.contains(frameOwnerId)) {
1386         // No children are mapped yet -> only notify on changes of hasChildren.
1387         m_frontend->childNodeCountUpdated(frameOwnerId, innerChildNodeCount(frameOwner));
1388     } else {
1389         // Re-add frame owner element together with its new children.
1390         int parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner));
1391         m_frontend->childNodeRemoved(parentId, frameOwnerId);
1392         RefPtr<InspectorObject> value = buildObjectForNode(frameOwner, 0, &m_documentNodeToIdMap);
1393         Node* previousSibling = innerPreviousSibling(frameOwner);
1394         int prevId = previousSibling ? m_documentNodeToIdMap.get(previousSibling) : 0;
1395         m_frontend->childNodeInserted(parentId, prevId, value.release());
1396         // Invalidate children requested flag for the element.
1397         m_childrenRequested.remove(m_childrenRequested.find(frameOwnerId));
1398     }
1399 }
1400
1401 void InspectorDOMAgent::didInsertDOMNode(Node* node)
1402 {
1403     if (isWhitespace(node))
1404         return;
1405
1406     // We could be attaching existing subtree. Forget the bindings.
1407     unbind(node, &m_documentNodeToIdMap);
1408
1409     ContainerNode* parent = node->parentNode();
1410     int parentId = m_documentNodeToIdMap.get(parent);
1411     // Return if parent is not mapped yet.
1412     if (!parentId)
1413         return;
1414
1415     if (!m_childrenRequested.contains(parentId)) {
1416         // No children are mapped yet -> only notify on changes of hasChildren.
1417         m_frontend->childNodeCountUpdated(parentId, innerChildNodeCount(parent));
1418     } else {
1419         // Children have been requested -> return value of a new child.
1420         Node* prevSibling = innerPreviousSibling(node);
1421         int prevId = prevSibling ? m_documentNodeToIdMap.get(prevSibling) : 0;
1422         RefPtr<InspectorObject> value = buildObjectForNode(node, 0, &m_documentNodeToIdMap);
1423         m_frontend->childNodeInserted(parentId, prevId, value.release());
1424     }
1425 }
1426
1427 void InspectorDOMAgent::didRemoveDOMNode(Node* node)
1428 {
1429     if (isWhitespace(node))
1430         return;
1431
1432     ContainerNode* parent = node->parentNode();
1433     int parentId = m_documentNodeToIdMap.get(parent);
1434     // If parent is not mapped yet -> ignore the event.
1435     if (!parentId)
1436         return;
1437
1438     if (m_domListener)
1439         m_domListener->didRemoveDOMNode(node);
1440
1441     if (!m_childrenRequested.contains(parentId)) {
1442         // No children are mapped yet -> only notify on changes of hasChildren.
1443         if (innerChildNodeCount(parent) == 1)
1444             m_frontend->childNodeCountUpdated(parentId, 0);
1445     } else
1446         m_frontend->childNodeRemoved(parentId, m_documentNodeToIdMap.get(node));
1447     unbind(node, &m_documentNodeToIdMap);
1448 }
1449
1450 void InspectorDOMAgent::didModifyDOMAttr(Element* element, const AtomicString& name, const AtomicString& value)
1451 {
1452     int id = boundNodeId(element);
1453     // If node is not mapped yet -> ignore the event.
1454     if (!id)
1455         return;
1456
1457     if (m_domListener)
1458         m_domListener->didModifyDOMAttr(element);
1459
1460     m_frontend->attributeModified(id, name, value);
1461 }
1462
1463 void InspectorDOMAgent::didRemoveDOMAttr(Element* element, const AtomicString& name)
1464 {
1465     int id = boundNodeId(element);
1466     // If node is not mapped yet -> ignore the event.
1467     if (!id)
1468         return;
1469
1470     if (m_domListener)
1471         m_domListener->didModifyDOMAttr(element);
1472
1473     m_frontend->attributeRemoved(id, name);
1474 }
1475
1476 void InspectorDOMAgent::styleAttributeInvalidated(const Vector<Element*>& elements)
1477 {
1478     RefPtr<InspectorArray> nodeIds = InspectorArray::create();
1479     for (unsigned i = 0, size = elements.size(); i < size; ++i) {
1480         Element* element = elements.at(i);
1481         int id = boundNodeId(element);
1482         // If node is not mapped yet -> ignore the event.
1483         if (!id)
1484             continue;
1485
1486         if (m_domListener)
1487             m_domListener->didModifyDOMAttr(element);
1488         nodeIds->pushNumber(id);
1489     }
1490     m_frontend->inlineStyleInvalidated(nodeIds.release());
1491 }
1492
1493 void InspectorDOMAgent::characterDataModified(CharacterData* characterData)
1494 {
1495     int id = m_documentNodeToIdMap.get(characterData);
1496     if (!id)
1497         return;
1498     m_frontend->characterDataModified(id, characterData->data());
1499 }
1500
1501 void InspectorDOMAgent::didInvalidateStyleAttr(Node* node)
1502 {
1503     int id = m_documentNodeToIdMap.get(node);
1504     // If node is not mapped yet -> ignore the event.
1505     if (!id)
1506         return;
1507
1508     if (!m_revalidateStyleAttrTask)
1509         m_revalidateStyleAttrTask = adoptPtr(new RevalidateStyleAttributeTask(this));
1510     m_revalidateStyleAttrTask->scheduleFor(static_cast<Element*>(node));
1511 }
1512
1513 Node* InspectorDOMAgent::nodeForPath(const String& path)
1514 {
1515     // The path is of form "1,HTML,2,BODY,1,DIV"
1516     if (!m_document)
1517         return 0;
1518
1519     Node* node = m_document.get();
1520     Vector<String> pathTokens;
1521     path.split(",", false, pathTokens);
1522     if (!pathTokens.size())
1523         return 0;
1524     for (size_t i = 0; i < pathTokens.size() - 1; i += 2) {
1525         bool success = true;
1526         unsigned childNumber = pathTokens[i].toUInt(&success);
1527         if (!success)
1528             return 0;
1529         if (childNumber >= innerChildNodeCount(node))
1530             return 0;
1531
1532         Node* child = innerFirstChild(node);
1533         String childName = pathTokens[i + 1];
1534         for (size_t j = 0; child && j < childNumber; ++j)
1535             child = innerNextSibling(child);
1536
1537         if (!child || child->nodeName() != childName)
1538             return 0;
1539         node = child;
1540     }
1541     return node;
1542 }
1543
1544 void InspectorDOMAgent::onMatchJobsTimer(Timer<InspectorDOMAgent>*)
1545 {
1546     if (!m_pendingMatchJobs.size()) {
1547         ErrorString error;
1548         cancelSearch(&error);
1549         return;
1550     }
1551
1552     ListHashSet<Node*> resultCollector;
1553     MatchJob* job = m_pendingMatchJobs.takeFirst();
1554     job->match(resultCollector);
1555     delete job;
1556
1557     reportNodesAsSearchResults(resultCollector);
1558
1559     m_matchJobsTimer.startOneShot(0.025);
1560 }
1561
1562 void InspectorDOMAgent::reportNodesAsSearchResults(ListHashSet<Node*>& resultCollector)
1563 {
1564     RefPtr<InspectorArray> nodeIds = InspectorArray::create();
1565     for (ListHashSet<Node*>::iterator it = resultCollector.begin(); it != resultCollector.end(); ++it) {
1566         if (m_searchResults.contains(*it))
1567             continue;
1568         m_searchResults.add(*it);
1569         nodeIds->pushNumber(pushNodePathToFrontend(*it));
1570     }
1571     m_frontend->searchResults(nodeIds.release());
1572 }
1573
1574 void InspectorDOMAgent::copyNode(ErrorString*, int nodeId)
1575 {
1576     Node* node = nodeForId(nodeId);
1577     if (!node)
1578         return;
1579     String markup = createMarkup(node);
1580     Pasteboard::generalPasteboard()->writePlainText(markup);
1581 }
1582
1583 void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString*, const String& path, int* nodeId)
1584 {
1585     if (Node* node = nodeForPath(path))
1586         *nodeId = pushNodePathToFrontend(node);
1587 }
1588
1589 PassRefPtr<InspectorObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup)
1590 {
1591     Document* document = node->isDocumentNode() ? node->document() : node->ownerDocument();
1592     Frame* frame = document ? document->frame() : 0;
1593     if (!frame)
1594         return 0;
1595
1596     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
1597     if (injectedScript.hasNoValue())
1598         return 0;
1599
1600     return injectedScript.wrapNode(node, objectGroup);
1601 }
1602
1603 void InspectorDOMAgent::drawHighlight(GraphicsContext& context) const
1604 {
1605     if (!m_highlightData)
1606         return;
1607
1608     DOMNodeHighlighter::drawHighlight(context, m_highlightData->node ? m_highlightData->node->document() : m_document.get(), m_highlightData.get());
1609 }
1610
1611 } // namespace WebCore
1612
1613 #endif // ENABLE(INSPECTOR)