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