dd4a120d51caf0dd74a57af285278b6e8c432f60
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/inspector/InspectorDOMAgent.h"
33
34 #include "HTMLNames.h"
35 #include "bindings/v8/ExceptionState.h"
36 #include "bindings/v8/ScriptEventListener.h"
37 #include "core/dom/Attr.h"
38 #include "core/dom/CharacterData.h"
39 #include "core/dom/ContainerNode.h"
40 #include "core/dom/DOMException.h"
41 #include "core/dom/Document.h"
42 #include "core/dom/DocumentFragment.h"
43 #include "core/dom/DocumentType.h"
44 #include "core/dom/Element.h"
45 #include "core/events/EventListener.h"
46 #include "core/events/EventTarget.h"
47 #include "core/dom/Node.h"
48 #include "core/dom/NodeList.h"
49 #include "core/dom/NodeTraversal.h"
50 #include "core/dom/PseudoElement.h"
51 #include "core/dom/Text.h"
52 #include "core/dom/shadow/ElementShadow.h"
53 #include "core/dom/shadow/ShadowRoot.h"
54 #include "core/editing/markup.h"
55 #include "core/fileapi/File.h"
56 #include "core/fileapi/FileList.h"
57 #include "core/html/HTMLFrameOwnerElement.h"
58 #include "core/html/HTMLInputElement.h"
59 #include "core/html/HTMLTemplateElement.h"
60 #include "core/inspector/DOMEditor.h"
61 #include "core/inspector/DOMPatchSupport.h"
62 #include "core/inspector/IdentifiersFactory.h"
63 #include "core/inspector/InspectorHistory.h"
64 #include "core/inspector/InspectorOverlay.h"
65 #include "core/inspector/InspectorPageAgent.h"
66 #include "core/inspector/InspectorState.h"
67 #include "core/inspector/InstrumentingAgents.h"
68 #include "core/loader/DocumentLoader.h"
69 #include "core/frame/Frame.h"
70 #include "core/page/FrameTree.h"
71 #include "core/page/Page.h"
72 #include "core/rendering/HitTestResult.h"
73 #include "core/rendering/RenderView.h"
74 #include "core/xml/DocumentXPathEvaluator.h"
75 #include "core/xml/XPathResult.h"
76 #include "platform/PlatformGestureEvent.h"
77 #include "platform/PlatformMouseEvent.h"
78 #include "platform/PlatformTouchEvent.h"
79 #include "wtf/ListHashSet.h"
80 #include "wtf/text/CString.h"
81 #include "wtf/text/WTFString.h"
82
83 namespace WebCore {
84
85 using namespace HTMLNames;
86
87 namespace DOMAgentState {
88 static const char documentRequested[] = "documentRequested";
89 };
90
91 static const size_t maxTextSize = 10000;
92 static const UChar ellipsisUChar[] = { 0x2026, 0 };
93
94 static Color parseColor(const RefPtr<JSONObject>* colorObject)
95 {
96     if (!colorObject || !(*colorObject))
97         return Color::transparent;
98
99     int r;
100     int g;
101     int b;
102     bool success = (*colorObject)->getNumber("r", &r);
103     success |= (*colorObject)->getNumber("g", &g);
104     success |= (*colorObject)->getNumber("b", &b);
105     if (!success)
106         return Color::transparent;
107
108     double a;
109     success = (*colorObject)->getNumber("a", &a);
110     if (!success)
111         return Color(r, g, b);
112
113     // Clamp alpha to the [0..1] range.
114     if (a < 0)
115         a = 0;
116     else if (a > 1)
117         a = 1;
118
119     return Color(r, g, b, static_cast<int>(a * 255));
120 }
121
122 static Color parseConfigColor(const String& fieldName, JSONObject* configObject)
123 {
124     const RefPtr<JSONObject> colorObject = configObject->getObject(fieldName);
125     return parseColor(&colorObject);
126 }
127
128 static bool parseQuad(const RefPtr<JSONArray>& quadArray, FloatQuad* quad)
129 {
130     if (!quadArray)
131         return false;
132     const size_t coordinatesInQuad = 8;
133     double coordinates[coordinatesInQuad];
134     if (quadArray->length() != coordinatesInQuad)
135         return false;
136     for (size_t i = 0; i < coordinatesInQuad; ++i) {
137         if (!quadArray->get(i)->asNumber(coordinates + i))
138             return false;
139     }
140     quad->setP1(FloatPoint(coordinates[0], coordinates[1]));
141     quad->setP2(FloatPoint(coordinates[2], coordinates[3]));
142     quad->setP3(FloatPoint(coordinates[4], coordinates[5]));
143     quad->setP4(FloatPoint(coordinates[6], coordinates[7]));
144
145     return true;
146 }
147
148 static Node* hoveredNodeForPoint(Frame* frame, const IntPoint& point, bool ignorePointerEventsNone)
149 {
150     HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ReadOnly | HitTestRequest::AllowChildFrameContent;
151     if (ignorePointerEventsNone)
152         hitType |= HitTestRequest::IgnorePointerEventsNone;
153     HitTestRequest request(hitType);
154     HitTestResult result(frame->view()->windowToContents(point));
155     frame->contentRenderer()->hitTest(request, result);
156     Node* node = result.innerPossiblyPseudoNode();
157     while (node && node->nodeType() == Node::TEXT_NODE)
158         node = node->parentNode();
159     return node;
160 }
161
162 static Node* hoveredNodeForEvent(Frame* frame, const PlatformGestureEvent& event, bool ignorePointerEventsNone)
163 {
164     return hoveredNodeForPoint(frame, event.position(), ignorePointerEventsNone);
165 }
166
167 static Node* hoveredNodeForEvent(Frame* frame, const PlatformMouseEvent& event, bool ignorePointerEventsNone)
168 {
169     return hoveredNodeForPoint(frame, event.position(), ignorePointerEventsNone);
170 }
171
172 static Node* hoveredNodeForEvent(Frame* frame, const PlatformTouchEvent& event, bool ignorePointerEventsNone)
173 {
174     const Vector<PlatformTouchPoint>& points = event.touchPoints();
175     if (!points.size())
176         return 0;
177     return hoveredNodeForPoint(frame, points[0].pos(), ignorePointerEventsNone);
178 }
179
180 class RevalidateStyleAttributeTask {
181     WTF_MAKE_FAST_ALLOCATED;
182 public:
183     RevalidateStyleAttributeTask(InspectorDOMAgent*);
184     void scheduleFor(Element*);
185     void reset() { m_timer.stop(); }
186     void onTimer(Timer<RevalidateStyleAttributeTask>*);
187
188 private:
189     InspectorDOMAgent* m_domAgent;
190     Timer<RevalidateStyleAttributeTask> m_timer;
191     HashSet<RefPtr<Element> > m_elements;
192 };
193
194 RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent)
195     : m_domAgent(domAgent)
196     , m_timer(this, &RevalidateStyleAttributeTask::onTimer)
197 {
198 }
199
200 void RevalidateStyleAttributeTask::scheduleFor(Element* element)
201 {
202     m_elements.add(element);
203     if (!m_timer.isActive())
204         m_timer.startOneShot(0);
205 }
206
207 void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*)
208 {
209     // The timer is stopped on m_domAgent destruction, so this method will never be called after m_domAgent has been destroyed.
210     Vector<Element*> elements;
211     for (HashSet<RefPtr<Element> >::iterator it = m_elements.begin(), end = m_elements.end(); it != end; ++it)
212         elements.append(it->get());
213     m_domAgent->styleAttributeInvalidated(elements);
214
215     m_elements.clear();
216 }
217
218 String InspectorDOMAgent::toErrorString(ExceptionState& exceptionState)
219 {
220     if (exceptionState.hadException())
221         return DOMException::getErrorName(exceptionState.code());
222     return "";
223 }
224
225 InspectorDOMAgent::InspectorDOMAgent(InspectorPageAgent* pageAgent, InjectedScriptManager* injectedScriptManager, InspectorOverlay* overlay)
226     : InspectorBaseAgent<InspectorDOMAgent>("DOM")
227     , m_pageAgent(pageAgent)
228     , m_injectedScriptManager(injectedScriptManager)
229     , m_overlay(overlay)
230     , m_frontend(0)
231     , m_domListener(0)
232     , m_lastNodeId(1)
233     , m_lastBackendNodeId(-1)
234     , m_searchingForNode(NotSearching)
235     , m_suppressAttributeModifiedEvent(false)
236 {
237 }
238
239 InspectorDOMAgent::~InspectorDOMAgent()
240 {
241     reset();
242     ASSERT(m_searchingForNode == NotSearching);
243 }
244
245 void InspectorDOMAgent::setFrontend(InspectorFrontend* frontend)
246 {
247     ASSERT(!m_frontend);
248     m_history = adoptPtr(new InspectorHistory());
249     m_domEditor = adoptPtr(new DOMEditor(m_history.get()));
250
251     m_frontend = frontend->dom();
252     m_instrumentingAgents->setInspectorDOMAgent(this);
253     m_document = m_pageAgent->mainFrame()->document();
254 }
255
256 void InspectorDOMAgent::clearFrontend()
257 {
258     ASSERT(m_frontend);
259
260     m_history.clear();
261     m_domEditor.clear();
262
263     ErrorString error;
264     setSearchingForNode(&error, NotSearching, 0);
265     hideHighlight(&error);
266
267     m_frontend = 0;
268     m_instrumentingAgents->setInspectorDOMAgent(0);
269     m_state->setBoolean(DOMAgentState::documentRequested, false);
270     reset();
271 }
272
273 void InspectorDOMAgent::restore()
274 {
275     // Reset document to avoid early return from setDocument.
276     m_document = 0;
277     setDocument(m_pageAgent->mainFrame()->document());
278 }
279
280 Vector<Document*> InspectorDOMAgent::documents()
281 {
282     Vector<Document*> result;
283     for (Frame* frame = m_document->frame(); frame; frame = frame->tree().traverseNext()) {
284         Document* document = frame->document();
285         if (!document)
286             continue;
287         result.append(document);
288     }
289     return result;
290 }
291
292 void InspectorDOMAgent::reset()
293 {
294     discardFrontendBindings();
295     discardBackendBindings();
296     m_document = 0;
297 }
298
299 void InspectorDOMAgent::setDOMListener(DOMListener* listener)
300 {
301     m_domListener = listener;
302 }
303
304 void InspectorDOMAgent::setDocument(Document* doc)
305 {
306     if (doc == m_document.get())
307         return;
308
309     reset();
310
311     m_document = doc;
312
313     if (!m_state->getBoolean(DOMAgentState::documentRequested))
314         return;
315
316     // Immediately communicate 0 document or document that has finished loading.
317     if (!doc || !doc->parsing())
318         m_frontend->documentUpdated();
319 }
320
321 void InspectorDOMAgent::releaseDanglingNodes()
322 {
323     m_danglingNodeToIdMaps.clear();
324 }
325
326 int InspectorDOMAgent::bind(Node* node, NodeToIdMap* nodesMap)
327 {
328     int id = nodesMap->get(node);
329     if (id)
330         return id;
331     id = m_lastNodeId++;
332     nodesMap->set(node, id);
333     m_idToNode.set(id, node);
334     m_idToNodesMap.set(id, nodesMap);
335     return id;
336 }
337
338 void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap)
339 {
340     int id = nodesMap->get(node);
341     if (!id)
342         return;
343
344     m_idToNode.remove(id);
345
346     if (node->isFrameOwnerElement()) {
347         Document* contentDocument = toHTMLFrameOwnerElement(node)->contentDocument();
348         if (m_domListener)
349             m_domListener->didRemoveDocument(contentDocument);
350         if (contentDocument)
351             unbind(contentDocument, nodesMap);
352     }
353
354     for (ShadowRoot* root = node->youngestShadowRoot(); root; root = root->olderShadowRoot())
355         unbind(root, nodesMap);
356
357     if (node->isElementNode()) {
358         Element* element = toElement(node);
359         if (element->pseudoElement(BEFORE))
360             unbind(element->pseudoElement(BEFORE), nodesMap);
361         if (element->pseudoElement(AFTER))
362             unbind(element->pseudoElement(AFTER), nodesMap);
363     }
364
365     nodesMap->remove(node);
366     if (m_domListener)
367         m_domListener->didRemoveDOMNode(node);
368
369     bool childrenRequested = m_childrenRequested.contains(id);
370     if (childrenRequested) {
371         // Unbind subtree known to client recursively.
372         m_childrenRequested.remove(id);
373         Node* child = innerFirstChild(node);
374         while (child) {
375             unbind(child, nodesMap);
376             child = innerNextSibling(child);
377         }
378     }
379 }
380
381 Node* InspectorDOMAgent::assertNode(ErrorString* errorString, int nodeId)
382 {
383     Node* node = nodeForId(nodeId);
384     if (!node) {
385         *errorString = "Could not find node with given id";
386         return 0;
387     }
388     return node;
389 }
390
391 Document* InspectorDOMAgent::assertDocument(ErrorString* errorString, int nodeId)
392 {
393     Node* node = assertNode(errorString, nodeId);
394     if (!node)
395         return 0;
396
397     if (!(node->isDocumentNode())) {
398         *errorString = "Document is not available";
399         return 0;
400     }
401     return toDocument(node);
402 }
403
404 Element* InspectorDOMAgent::assertElement(ErrorString* errorString, int nodeId)
405 {
406     Node* node = assertNode(errorString, nodeId);
407     if (!node)
408         return 0;
409
410     if (node->nodeType() != Node::ELEMENT_NODE) {
411         *errorString = "Node is not an Element";
412         return 0;
413     }
414     return toElement(node);
415 }
416
417 Node* InspectorDOMAgent::assertEditableNode(ErrorString* errorString, int nodeId)
418 {
419     Node* node = assertNode(errorString, nodeId);
420     if (!node)
421         return 0;
422
423     if (node->isInShadowTree()) {
424         *errorString = "Cannot edit nodes from shadow trees";
425         return 0;
426     }
427
428     if (node->isPseudoElement()) {
429         *errorString = "Cannot edit pseudo elements";
430         return 0;
431     }
432
433     return node;
434 }
435
436 Element* InspectorDOMAgent::assertEditableElement(ErrorString* errorString, int nodeId)
437 {
438     Element* element = assertElement(errorString, nodeId);
439     if (!element)
440         return 0;
441
442     if (element->isInShadowTree()) {
443         *errorString = "Cannot edit elements from shadow trees";
444         return 0;
445     }
446
447     if (element->isPseudoElement()) {
448         *errorString = "Cannot edit pseudo elements";
449         return 0;
450     }
451
452     return element;
453 }
454
455 void InspectorDOMAgent::getDocument(ErrorString* errorString, RefPtr<TypeBuilder::DOM::Node>& root)
456 {
457     m_state->setBoolean(DOMAgentState::documentRequested, true);
458
459     if (!m_document) {
460         *errorString = "Document is not available";
461         return;
462     }
463
464     discardFrontendBindings();
465
466     root = buildObjectForNode(m_document.get(), 2, &m_documentNodeToIdMap);
467 }
468
469 void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId, int depth)
470 {
471     Node* node = nodeForId(nodeId);
472     if (!node || (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE && node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE))
473         return;
474
475     NodeToIdMap* nodeMap = m_idToNodesMap.get(nodeId);
476
477     if (m_childrenRequested.contains(nodeId)) {
478         if (depth <= 1)
479             return;
480
481         depth--;
482
483         for (node = innerFirstChild(node); node; node = innerNextSibling(node)) {
484             int childNodeId = nodeMap->get(node);
485             ASSERT(childNodeId);
486             pushChildNodesToFrontend(childNodeId, depth);
487         }
488
489         return;
490     }
491
492     RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = buildArrayForContainerChildren(node, depth, nodeMap);
493     m_frontend->setChildNodes(nodeId, children.release());
494 }
495
496 void InspectorDOMAgent::discardFrontendBindings()
497 {
498     if (m_history)
499         m_history->reset();
500     m_searchResults.clear();
501     m_documentNodeToIdMap.clear();
502     m_idToNode.clear();
503     releaseDanglingNodes();
504     m_childrenRequested.clear();
505     if (m_revalidateStyleAttrTask)
506         m_revalidateStyleAttrTask->reset();
507 }
508
509 void InspectorDOMAgent::discardBackendBindings()
510 {
511     m_backendIdToNode.clear();
512     m_nodeGroupToBackendIdMap.clear();
513 }
514
515 int InspectorDOMAgent::pushNodeToFrontend(ErrorString* errorString, int documentNodeId, Node* nodeToPush)
516 {
517     Document* document = assertDocument(errorString, documentNodeId);
518     if (!document)
519         return 0;
520     if (nodeToPush->document() != document) {
521         *errorString = "Node is not part of the document with given id";
522         return 0;
523     }
524
525     return pushNodePathToFrontend(nodeToPush);
526 }
527
528 Node* InspectorDOMAgent::nodeForId(int id)
529 {
530     if (!id)
531         return 0;
532
533     HashMap<int, Node*>::iterator it = m_idToNode.find(id);
534     if (it != m_idToNode.end())
535         return it->value;
536     return 0;
537 }
538
539 void InspectorDOMAgent::requestChildNodes(ErrorString* errorString, int nodeId, const int* depth)
540 {
541     int sanitizedDepth;
542
543     if (!depth)
544         sanitizedDepth = 1;
545     else if (*depth == -1)
546         sanitizedDepth = INT_MAX;
547     else if (*depth > 0)
548         sanitizedDepth = *depth;
549     else {
550         *errorString = "Please provide a positive integer as a depth or -1 for entire subtree";
551         return;
552     }
553
554     pushChildNodesToFrontend(nodeId, sanitizedDepth);
555 }
556
557 void InspectorDOMAgent::querySelector(ErrorString* errorString, int nodeId, const String& selectors, int* elementId)
558 {
559     *elementId = 0;
560     Node* node = assertNode(errorString, nodeId);
561     if (!node || !node->isContainerNode())
562         return;
563
564     TrackExceptionState exceptionState;
565     RefPtr<Element> element = toContainerNode(node)->querySelector(AtomicString(selectors), exceptionState);
566     if (exceptionState.hadException()) {
567         *errorString = "DOM Error while querying";
568         return;
569     }
570
571     if (element)
572         *elementId = pushNodePathToFrontend(element.get());
573 }
574
575 void InspectorDOMAgent::querySelectorAll(ErrorString* errorString, int nodeId, const String& selectors, RefPtr<TypeBuilder::Array<int> >& result)
576 {
577     Node* node = assertNode(errorString, nodeId);
578     if (!node || !node->isContainerNode())
579         return;
580
581     TrackExceptionState exceptionState;
582     RefPtr<NodeList> nodes = toContainerNode(node)->querySelectorAll(AtomicString(selectors), exceptionState);
583     if (exceptionState.hadException()) {
584         *errorString = "DOM Error while querying";
585         return;
586     }
587
588     result = TypeBuilder::Array<int>::create();
589
590     for (unsigned i = 0; i < nodes->length(); ++i)
591         result->addItem(pushNodePathToFrontend(nodes->item(i)));
592 }
593
594 int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush)
595 {
596     ASSERT(nodeToPush);  // Invalid input
597
598     if (!m_document)
599         return 0;
600     if (!m_documentNodeToIdMap.contains(m_document))
601         return 0;
602
603     // Return id in case the node is known.
604     int result = m_documentNodeToIdMap.get(nodeToPush);
605     if (result)
606         return result;
607
608     Node* node = nodeToPush;
609     Vector<Node*> path;
610     NodeToIdMap* danglingMap = 0;
611
612     while (true) {
613         Node* parent = innerParentNode(node);
614         if (!parent) {
615             // Node being pushed is detached -> push subtree root.
616             OwnPtr<NodeToIdMap> newMap = adoptPtr(new NodeToIdMap);
617             danglingMap = newMap.get();
618             m_danglingNodeToIdMaps.append(newMap.release());
619             RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
620             children->addItem(buildObjectForNode(node, 0, danglingMap));
621             m_frontend->setChildNodes(0, children);
622             break;
623         } else {
624             path.append(parent);
625             if (m_documentNodeToIdMap.get(parent))
626                 break;
627             else
628                 node = parent;
629         }
630     }
631
632     NodeToIdMap* map = danglingMap ? danglingMap : &m_documentNodeToIdMap;
633     for (int i = path.size() - 1; i >= 0; --i) {
634         int nodeId = map->get(path.at(i));
635         ASSERT(nodeId);
636         pushChildNodesToFrontend(nodeId);
637     }
638     return map->get(nodeToPush);
639 }
640
641 int InspectorDOMAgent::boundNodeId(Node* node)
642 {
643     return m_documentNodeToIdMap.get(node);
644 }
645
646 BackendNodeId InspectorDOMAgent::backendNodeIdForNode(Node* node, const String& nodeGroup)
647 {
648     if (!node)
649         return 0;
650
651     if (!m_nodeGroupToBackendIdMap.contains(nodeGroup))
652         m_nodeGroupToBackendIdMap.set(nodeGroup, NodeToBackendIdMap());
653
654     NodeToBackendIdMap& map = m_nodeGroupToBackendIdMap.find(nodeGroup)->value;
655     BackendNodeId id = map.get(node);
656     if (!id) {
657         id = --m_lastBackendNodeId;
658         map.set(node, id);
659         m_backendIdToNode.set(id, std::make_pair(node, nodeGroup));
660     }
661
662     return id;
663 }
664
665 void InspectorDOMAgent::releaseBackendNodeIds(ErrorString* errorString, const String& nodeGroup)
666 {
667     if (m_nodeGroupToBackendIdMap.contains(nodeGroup)) {
668         NodeToBackendIdMap& map = m_nodeGroupToBackendIdMap.find(nodeGroup)->value;
669         for (NodeToBackendIdMap::iterator it = map.begin(); it != map.end(); ++it)
670             m_backendIdToNode.remove(it->value);
671         m_nodeGroupToBackendIdMap.remove(nodeGroup);
672         return;
673     }
674     *errorString = "Group name not found";
675 }
676
677 void InspectorDOMAgent::setAttributeValue(ErrorString* errorString, int elementId, const String& name, const String& value)
678 {
679     Element* element = assertEditableElement(errorString, elementId);
680     if (!element)
681         return;
682
683     m_domEditor->setAttribute(element, name, value, errorString);
684 }
685
686 void InspectorDOMAgent::setAttributesAsText(ErrorString* errorString, int elementId, const String& text, const String* const name)
687 {
688     Element* element = assertEditableElement(errorString, elementId);
689     if (!element)
690         return;
691
692     String markup = "<span " + text + "></span>";
693     RefPtr<DocumentFragment> fragment = element->document().createDocumentFragment();
694
695     bool shouldIgnoreCase = element->document().isHTMLDocument() && element->isHTMLElement();
696     // Not all elements can represent the context (i.e. IFRAME), hence using document.body.
697     if (shouldIgnoreCase && element->document().body())
698         fragment->parseHTML(markup, element->document().body(), DisallowScriptingContent);
699     else
700         fragment->parseXML(markup, 0, DisallowScriptingContent);
701
702     Element* parsedElement = fragment->firstChild() && fragment->firstChild()->isElementNode() ? toElement(fragment->firstChild()) : 0;
703     if (!parsedElement) {
704         *errorString = "Could not parse value as attributes";
705         return;
706     }
707
708     String caseAdjustedName = name ? (shouldIgnoreCase ? name->lower() : *name) : String();
709
710     if (!parsedElement->hasAttributes() && name) {
711         m_domEditor->removeAttribute(element, caseAdjustedName, errorString);
712         return;
713     }
714
715     bool foundOriginalAttribute = false;
716     unsigned numAttrs = parsedElement->attributeCount();
717     for (unsigned i = 0; i < numAttrs; ++i) {
718         // Add attribute pair
719         const Attribute* attribute = parsedElement->attributeItem(i);
720         String attributeName = attribute->name().toString();
721         if (shouldIgnoreCase)
722             attributeName = attributeName.lower();
723         foundOriginalAttribute |= name && attributeName == caseAdjustedName;
724         if (!m_domEditor->setAttribute(element, attributeName, attribute->value(), errorString))
725             return;
726     }
727
728     if (!foundOriginalAttribute && name && !name->stripWhiteSpace().isEmpty())
729         m_domEditor->removeAttribute(element, caseAdjustedName, errorString);
730 }
731
732 void InspectorDOMAgent::removeAttribute(ErrorString* errorString, int elementId, const String& name)
733 {
734     Element* element = assertEditableElement(errorString, elementId);
735     if (!element)
736         return;
737
738     m_domEditor->removeAttribute(element, name, errorString);
739 }
740
741 void InspectorDOMAgent::removeNode(ErrorString* errorString, int nodeId)
742 {
743     Node* node = assertEditableNode(errorString, nodeId);
744     if (!node)
745         return;
746
747     ContainerNode* parentNode = node->parentNode();
748     if (!parentNode) {
749         *errorString = "Cannot remove detached node";
750         return;
751     }
752
753     m_domEditor->removeChild(parentNode, node, errorString);
754 }
755
756 void InspectorDOMAgent::setNodeName(ErrorString* errorString, int nodeId, const String& tagName, int* newId)
757 {
758     *newId = 0;
759
760     Node* oldNode = nodeForId(nodeId);
761     if (!oldNode || !oldNode->isElementNode())
762         return;
763
764     TrackExceptionState exceptionState;
765     RefPtr<Element> newElem = oldNode->document().createElement(AtomicString(tagName), exceptionState);
766     if (exceptionState.hadException())
767         return;
768
769     // Copy over the original node's attributes.
770     newElem->cloneAttributesFromElement(*toElement(oldNode));
771
772     // Copy over the original node's children.
773     Node* child;
774     while ((child = oldNode->firstChild())) {
775         if (!m_domEditor->insertBefore(newElem.get(), child, 0, errorString))
776             return;
777     }
778
779     // Replace the old node with the new node
780     ContainerNode* parent = oldNode->parentNode();
781     if (!m_domEditor->insertBefore(parent, newElem.get(), oldNode->nextSibling(), errorString))
782         return;
783     if (!m_domEditor->removeChild(parent, oldNode, errorString))
784         return;
785
786     *newId = pushNodePathToFrontend(newElem.get());
787     if (m_childrenRequested.contains(nodeId))
788         pushChildNodesToFrontend(*newId);
789 }
790
791 void InspectorDOMAgent::getOuterHTML(ErrorString* errorString, int nodeId, WTF::String* outerHTML)
792 {
793     Node* node = assertNode(errorString, nodeId);
794     if (!node)
795         return;
796
797     *outerHTML = createMarkup(node);
798 }
799
800 void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const String& outerHTML)
801 {
802     if (!nodeId) {
803         ASSERT(m_document);
804         DOMPatchSupport domPatchSupport(m_domEditor.get(), *m_document.get());
805         domPatchSupport.patchDocument(outerHTML);
806         return;
807     }
808
809     Node* node = assertEditableNode(errorString, nodeId);
810     if (!node)
811         return;
812
813     Document* document = node->isDocumentNode() ? toDocument(node) : node->ownerDocument();
814     if (!document || (!document->isHTMLDocument() && !document->isXMLDocument())) {
815         *errorString = "Not an HTML/XML document";
816         return;
817     }
818
819     Node* newNode = 0;
820     if (!m_domEditor->setOuterHTML(node, outerHTML, &newNode, errorString))
821         return;
822
823     if (!newNode) {
824         // The only child node has been deleted.
825         return;
826     }
827
828     int newId = pushNodePathToFrontend(newNode);
829
830     bool childrenRequested = m_childrenRequested.contains(nodeId);
831     if (childrenRequested)
832         pushChildNodesToFrontend(newId);
833 }
834
835 void InspectorDOMAgent::setNodeValue(ErrorString* errorString, int nodeId, const String& value)
836 {
837     Node* node = assertEditableNode(errorString, nodeId);
838     if (!node)
839         return;
840
841     if (node->nodeType() != Node::TEXT_NODE) {
842         *errorString = "Can only set value of text nodes";
843         return;
844     }
845
846     m_domEditor->replaceWholeText(toText(node), value, errorString);
847 }
848
849 void InspectorDOMAgent::getEventListenersForNode(ErrorString* errorString, int nodeId, const String* objectGroup, RefPtr<TypeBuilder::Array<TypeBuilder::DOM::EventListener> >& listenersArray)
850 {
851     listenersArray = TypeBuilder::Array<TypeBuilder::DOM::EventListener>::create();
852     Node* node = assertNode(errorString, nodeId);
853     if (!node)
854         return;
855     Vector<EventListenerInfo> eventInformation;
856     getEventListeners(node, eventInformation, true);
857
858     // Get Capturing Listeners (in this order)
859     size_t eventInformationLength = eventInformation.size();
860     for (size_t i = 0; i < eventInformationLength; ++i) {
861         const EventListenerInfo& info = eventInformation[i];
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->addItem(buildObjectForEventListener(listener, info.eventType, info.eventTarget->toNode(), objectGroup));
867         }
868     }
869
870     // Get Bubbling Listeners (reverse order)
871     for (size_t i = eventInformationLength; i; --i) {
872         const EventListenerInfo& info = eventInformation[i - 1];
873         const EventListenerVector& vector = info.eventListenerVector;
874         for (size_t j = 0; j < vector.size(); ++j) {
875             const RegisteredEventListener& listener = vector[j];
876             if (!listener.useCapture)
877                 listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.eventTarget->toNode(), objectGroup));
878         }
879     }
880 }
881
882 void InspectorDOMAgent::getEventListeners(EventTarget* target, Vector<EventListenerInfo>& eventInformation, bool includeAncestors)
883 {
884     // The Node's Ancestors including self.
885     Vector<EventTarget*> ancestors;
886     ancestors.append(target);
887     if (includeAncestors) {
888         Node* node = target->toNode();
889         for (ContainerNode* ancestor = node ? node->parentOrShadowHostNode() : 0; ancestor; ancestor = ancestor->parentOrShadowHostNode())
890             ancestors.append(ancestor);
891     }
892
893     // Nodes and their Listeners for the concerned event types (order is top to bottom)
894     for (size_t i = ancestors.size(); i; --i) {
895         EventTarget* ancestor = ancestors[i - 1];
896         Vector<AtomicString> eventTypes = ancestor->eventTypes();
897         for (size_t j = 0; j < eventTypes.size(); ++j) {
898             AtomicString& type = eventTypes[j];
899             const EventListenerVector& listeners = ancestor->getEventListeners(type);
900             EventListenerVector filteredListeners;
901             filteredListeners.reserveCapacity(listeners.size());
902             for (size_t k = 0; k < listeners.size(); ++k) {
903                 if (listeners[k].listener->type() == EventListener::JSEventListenerType)
904                     filteredListeners.append(listeners[k]);
905             }
906             if (!filteredListeners.isEmpty())
907                 eventInformation.append(EventListenerInfo(ancestor, type, filteredListeners));
908         }
909     }
910 }
911
912 void InspectorDOMAgent::performSearch(ErrorString*, const String& whitespaceTrimmedQuery, String* searchId, int* resultCount)
913 {
914     // FIXME: Few things are missing here:
915     // 1) Search works with node granularity - number of matches within node is not calculated.
916     // 2) There is no need to push all search results to the front-end at a time, pushing next / previous result
917     //    is sufficient.
918
919     unsigned queryLength = whitespaceTrimmedQuery.length();
920     bool startTagFound = !whitespaceTrimmedQuery.find('<');
921     bool endTagFound = whitespaceTrimmedQuery.reverseFind('>') + 1 == queryLength;
922     bool startQuoteFound = !whitespaceTrimmedQuery.find('"');
923     bool endQuoteFound = whitespaceTrimmedQuery.reverseFind('"') + 1 == queryLength;
924     bool exactAttributeMatch = startQuoteFound && endQuoteFound;
925
926     String tagNameQuery = whitespaceTrimmedQuery;
927     String attributeQuery = whitespaceTrimmedQuery;
928     if (startTagFound)
929         tagNameQuery = tagNameQuery.right(tagNameQuery.length() - 1);
930     if (endTagFound)
931         tagNameQuery = tagNameQuery.left(tagNameQuery.length() - 1);
932     if (startQuoteFound)
933         attributeQuery = attributeQuery.right(attributeQuery.length() - 1);
934     if (endQuoteFound)
935         attributeQuery = attributeQuery.left(attributeQuery.length() - 1);
936
937     Vector<Document*> docs = documents();
938     ListHashSet<Node*> resultCollector;
939
940     for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
941         Document* document = *it;
942         Node* node = document->documentElement();
943         if (!node)
944             continue;
945
946         // Manual plain text search.
947         while ((node = NodeTraversal::next(*node, document->documentElement()))) {
948             switch (node->nodeType()) {
949             case Node::TEXT_NODE:
950             case Node::COMMENT_NODE:
951             case Node::CDATA_SECTION_NODE: {
952                 String text = node->nodeValue();
953                 if (text.findIgnoringCase(whitespaceTrimmedQuery) != kNotFound)
954                     resultCollector.add(node);
955                 break;
956             }
957             case Node::ELEMENT_NODE: {
958                 if ((!startTagFound && !endTagFound && (node->nodeName().findIgnoringCase(tagNameQuery) != kNotFound))
959                     || (startTagFound && endTagFound && equalIgnoringCase(node->nodeName(), tagNameQuery))
960                     || (startTagFound && !endTagFound && node->nodeName().startsWith(tagNameQuery, false))
961                     || (!startTagFound && endTagFound && node->nodeName().endsWith(tagNameQuery, false))) {
962                     resultCollector.add(node);
963                     break;
964                 }
965                 // Go through all attributes and serialize them.
966                 const Element* element = toElement(node);
967                 if (!element->hasAttributes())
968                     break;
969
970                 unsigned numAttrs = element->attributeCount();
971                 for (unsigned i = 0; i < numAttrs; ++i) {
972                     // Add attribute pair
973                     const Attribute* attribute = element->attributeItem(i);
974                     if (attribute->localName().find(whitespaceTrimmedQuery, 0, false) != kNotFound) {
975                         resultCollector.add(node);
976                         break;
977                     }
978                     size_t foundPosition = attribute->value().find(attributeQuery, 0, false);
979                     if (foundPosition != kNotFound) {
980                         if (!exactAttributeMatch || (!foundPosition && attribute->value().length() == attributeQuery.length())) {
981                             resultCollector.add(node);
982                             break;
983                         }
984                     }
985                 }
986                 break;
987             }
988             default:
989                 break;
990             }
991         }
992
993         // XPath evaluation
994         for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
995             Document* document = *it;
996             TrackExceptionState exceptionState;
997             RefPtr<XPathResult> result = DocumentXPathEvaluator::evaluate(document, whitespaceTrimmedQuery, document, 0, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, 0, exceptionState);
998             if (exceptionState.hadException() || !result)
999                 continue;
1000
1001             unsigned long size = result->snapshotLength(exceptionState);
1002             for (unsigned long i = 0; !exceptionState.hadException() && i < size; ++i) {
1003                 Node* node = result->snapshotItem(i, exceptionState);
1004                 if (exceptionState.hadException())
1005                     break;
1006
1007                 if (node->nodeType() == Node::ATTRIBUTE_NODE)
1008                     node = toAttr(node)->ownerElement();
1009                 resultCollector.add(node);
1010             }
1011         }
1012
1013         // Selector evaluation
1014         for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
1015             Document* document = *it;
1016             TrackExceptionState exceptionState;
1017             RefPtr<NodeList> nodeList = document->querySelectorAll(AtomicString(whitespaceTrimmedQuery), exceptionState);
1018             if (exceptionState.hadException() || !nodeList)
1019                 continue;
1020
1021             unsigned size = nodeList->length();
1022             for (unsigned i = 0; i < size; ++i)
1023                 resultCollector.add(nodeList->item(i));
1024         }
1025     }
1026
1027     *searchId = IdentifiersFactory::createIdentifier();
1028     SearchResults::iterator resultsIt = m_searchResults.add(*searchId, Vector<RefPtr<Node> >()).iterator;
1029
1030     for (ListHashSet<Node*>::iterator it = resultCollector.begin(); it != resultCollector.end(); ++it)
1031         resultsIt->value.append(*it);
1032
1033     *resultCount = resultsIt->value.size();
1034 }
1035
1036 void InspectorDOMAgent::getSearchResults(ErrorString* errorString, const String& searchId, int fromIndex, int toIndex, RefPtr<TypeBuilder::Array<int> >& nodeIds)
1037 {
1038     SearchResults::iterator it = m_searchResults.find(searchId);
1039     if (it == m_searchResults.end()) {
1040         *errorString = "No search session with given id found";
1041         return;
1042     }
1043
1044     int size = it->value.size();
1045     if (fromIndex < 0 || toIndex > size || fromIndex >= toIndex) {
1046         *errorString = "Invalid search result range";
1047         return;
1048     }
1049
1050     nodeIds = TypeBuilder::Array<int>::create();
1051     for (int i = fromIndex; i < toIndex; ++i)
1052         nodeIds->addItem(pushNodePathToFrontend((it->value)[i].get()));
1053 }
1054
1055 void InspectorDOMAgent::discardSearchResults(ErrorString*, const String& searchId)
1056 {
1057     m_searchResults.remove(searchId);
1058 }
1059
1060 bool InspectorDOMAgent::handleMousePress()
1061 {
1062     if (m_searchingForNode == NotSearching)
1063         return false;
1064
1065     if (Node* node = m_overlay->highlightedNode()) {
1066         inspect(node);
1067         return true;
1068     }
1069     return false;
1070 }
1071
1072 bool InspectorDOMAgent::handleGestureEvent(Frame* frame, const PlatformGestureEvent& event)
1073 {
1074     if (m_searchingForNode == NotSearching || event.type() != PlatformEvent::GestureTap)
1075         return false;
1076     Node* node = hoveredNodeForEvent(frame, event, false);
1077     if (node && m_inspectModeHighlightConfig) {
1078         m_overlay->highlightNode(node, 0 /* eventTarget */, *m_inspectModeHighlightConfig);
1079         inspect(node);
1080         return true;
1081     }
1082     return false;
1083 }
1084
1085 bool InspectorDOMAgent::handleTouchEvent(Frame* frame, const PlatformTouchEvent& event)
1086 {
1087     if (m_searchingForNode == NotSearching)
1088         return false;
1089     Node* node = hoveredNodeForEvent(frame, event, false);
1090     if (node && m_inspectModeHighlightConfig) {
1091         m_overlay->highlightNode(node, 0 /* eventTarget */, *m_inspectModeHighlightConfig);
1092         inspect(node);
1093         return true;
1094     }
1095     return false;
1096 }
1097
1098 void InspectorDOMAgent::inspect(Node* inspectedNode)
1099 {
1100     if (!m_frontend || !inspectedNode)
1101         return;
1102
1103     Node* node = inspectedNode;
1104     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
1105         node = node->parentNode();
1106
1107     int nodeId = pushNodePathToFrontend(node);
1108     if (nodeId)
1109         m_frontend->inspectNodeRequested(nodeId);
1110 }
1111
1112 void InspectorDOMAgent::handleMouseMove(Frame* frame, const PlatformMouseEvent& event)
1113 {
1114     if (m_searchingForNode == NotSearching)
1115         return;
1116
1117     if (!frame->view() || !frame->contentRenderer())
1118         return;
1119     Node* node = hoveredNodeForEvent(frame, event, event.shiftKey());
1120
1121     while (m_searchingForNode != SearchingForShadow && node && node->isInShadowTree())
1122         node = node->parentOrShadowHostNode();
1123
1124     Node* eventTarget = event.shiftKey() ? hoveredNodeForEvent(frame, event, false) : 0;
1125     if (eventTarget == node)
1126         eventTarget = 0;
1127
1128     if (node && m_inspectModeHighlightConfig)
1129         m_overlay->highlightNode(node, eventTarget, *m_inspectModeHighlightConfig);
1130 }
1131
1132 void InspectorDOMAgent::setSearchingForNode(ErrorString* errorString, SearchMode searchMode, JSONObject* highlightInspectorObject)
1133 {
1134     if (m_searchingForNode == searchMode)
1135         return;
1136
1137     m_searchingForNode = searchMode;
1138     m_overlay->setInspectModeEnabled(searchMode != NotSearching);
1139     if (searchMode != NotSearching) {
1140         m_inspectModeHighlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject);
1141         if (!m_inspectModeHighlightConfig)
1142             return;
1143     } else
1144         hideHighlight(errorString);
1145 }
1146
1147 PassOwnPtr<HighlightConfig> InspectorDOMAgent::highlightConfigFromInspectorObject(ErrorString* errorString, JSONObject* highlightInspectorObject)
1148 {
1149     if (!highlightInspectorObject) {
1150         *errorString = "Internal error: highlight configuration parameter is missing";
1151         return nullptr;
1152     }
1153
1154     OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
1155     bool showInfo = false; // Default: false (do not show a tooltip).
1156     highlightInspectorObject->getBoolean("showInfo", &showInfo);
1157     highlightConfig->showInfo = showInfo;
1158     bool showRulers = false; // Default: false (do not show rulers).
1159     highlightInspectorObject->getBoolean("showRulers", &showRulers);
1160     highlightConfig->showRulers = showRulers;
1161     highlightConfig->content = parseConfigColor("contentColor", highlightInspectorObject);
1162     highlightConfig->contentOutline = parseConfigColor("contentOutlineColor", highlightInspectorObject);
1163     highlightConfig->padding = parseConfigColor("paddingColor", highlightInspectorObject);
1164     highlightConfig->border = parseConfigColor("borderColor", highlightInspectorObject);
1165     highlightConfig->margin = parseConfigColor("marginColor", highlightInspectorObject);
1166     highlightConfig->eventTarget = parseConfigColor("eventTargetColor", highlightInspectorObject);
1167     return highlightConfig.release();
1168 }
1169
1170 void InspectorDOMAgent::setInspectModeEnabled(ErrorString* errorString, bool enabled, const bool* inspectShadowDOM, const RefPtr<JSONObject>* highlightConfig)
1171 {
1172     if (enabled && !pushDocumentUponHandlelessOperation(errorString))
1173         return;
1174     SearchMode searchMode = enabled ? (inspectShadowDOM && *inspectShadowDOM ? SearchingForShadow : SearchingForNormal) : NotSearching;
1175     setSearchingForNode(errorString, searchMode, highlightConfig ? highlightConfig->get() : 0);
1176 }
1177
1178 void InspectorDOMAgent::highlightRect(ErrorString*, int x, int y, int width, int height, const RefPtr<JSONObject>* color, const RefPtr<JSONObject>* outlineColor)
1179 {
1180     OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad(FloatRect(x, y, width, height)));
1181     innerHighlightQuad(quad.release(), color, outlineColor);
1182 }
1183
1184 void InspectorDOMAgent::highlightQuad(ErrorString* errorString, const RefPtr<JSONArray>& quadArray, const RefPtr<JSONObject>* color, const RefPtr<JSONObject>* outlineColor)
1185 {
1186     OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad());
1187     if (!parseQuad(quadArray, quad.get())) {
1188         *errorString = "Invalid Quad format";
1189         return;
1190     }
1191     innerHighlightQuad(quad.release(), color, outlineColor);
1192 }
1193
1194 void InspectorDOMAgent::innerHighlightQuad(PassOwnPtr<FloatQuad> quad, const RefPtr<JSONObject>* color, const RefPtr<JSONObject>* outlineColor)
1195 {
1196     OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
1197     highlightConfig->content = parseColor(color);
1198     highlightConfig->contentOutline = parseColor(outlineColor);
1199     m_overlay->highlightQuad(quad, *highlightConfig);
1200 }
1201
1202 void InspectorDOMAgent::highlightNode(ErrorString* errorString, const RefPtr<JSONObject>& highlightInspectorObject, const int* nodeId, const String* objectId)
1203 {
1204     Node* node = 0;
1205     if (nodeId) {
1206         node = assertNode(errorString, *nodeId);
1207     } else if (objectId) {
1208         InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*objectId);
1209         node = injectedScript.nodeForObjectId(*objectId);
1210         if (!node)
1211             *errorString = "Node for given objectId not found";
1212     } else
1213         *errorString = "Either nodeId or objectId must be specified";
1214
1215     if (!node)
1216         return;
1217
1218     OwnPtr<HighlightConfig> highlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject.get());
1219     if (!highlightConfig)
1220         return;
1221
1222     m_overlay->highlightNode(node, 0 /* eventTarget */, *highlightConfig);
1223 }
1224
1225 void InspectorDOMAgent::highlightFrame(
1226     ErrorString*,
1227     const String& frameId,
1228     const RefPtr<JSONObject>* color,
1229     const RefPtr<JSONObject>* outlineColor)
1230 {
1231     Frame* frame = m_pageAgent->frameForId(frameId);
1232     if (frame && frame->ownerElement()) {
1233         OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
1234         highlightConfig->showInfo = true; // Always show tooltips for frames.
1235         highlightConfig->content = parseColor(color);
1236         highlightConfig->contentOutline = parseColor(outlineColor);
1237         m_overlay->highlightNode(frame->ownerElement(), 0 /* eventTarget */, *highlightConfig);
1238     }
1239 }
1240
1241 void InspectorDOMAgent::hideHighlight(ErrorString*)
1242 {
1243     m_overlay->hideHighlight();
1244 }
1245
1246 void InspectorDOMAgent::moveTo(ErrorString* errorString, int nodeId, int targetElementId, const int* const anchorNodeId, int* newNodeId)
1247 {
1248     Node* node = assertEditableNode(errorString, nodeId);
1249     if (!node)
1250         return;
1251
1252     Element* targetElement = assertEditableElement(errorString, targetElementId);
1253     if (!targetElement)
1254         return;
1255
1256     Node* anchorNode = 0;
1257     if (anchorNodeId && *anchorNodeId) {
1258         anchorNode = assertEditableNode(errorString, *anchorNodeId);
1259         if (!anchorNode)
1260             return;
1261         if (anchorNode->parentNode() != targetElement) {
1262             *errorString = "Anchor node must be child of the target element";
1263             return;
1264         }
1265     }
1266
1267     if (!m_domEditor->insertBefore(targetElement, node, anchorNode, errorString))
1268         return;
1269
1270     *newNodeId = pushNodePathToFrontend(node);
1271 }
1272
1273 void InspectorDOMAgent::undo(ErrorString* errorString)
1274 {
1275     TrackExceptionState exceptionState;
1276     m_history->undo(exceptionState);
1277     *errorString = InspectorDOMAgent::toErrorString(exceptionState);
1278 }
1279
1280 void InspectorDOMAgent::redo(ErrorString* errorString)
1281 {
1282     TrackExceptionState exceptionState;
1283     m_history->redo(exceptionState);
1284     *errorString = InspectorDOMAgent::toErrorString(exceptionState);
1285 }
1286
1287 void InspectorDOMAgent::markUndoableState(ErrorString*)
1288 {
1289     m_history->markUndoableState();
1290 }
1291
1292 void InspectorDOMAgent::focus(ErrorString* errorString, int nodeId)
1293 {
1294     Element* element = assertElement(errorString, nodeId);
1295     if (!element)
1296         return;
1297
1298     element->document().updateLayoutIgnorePendingStylesheets();
1299     if (!element->isFocusable()) {
1300         *errorString = "Element is not focusable";
1301         return;
1302     }
1303     element->focus();
1304 }
1305
1306 void InspectorDOMAgent::setFileInputFiles(ErrorString* errorString, int nodeId, const RefPtr<JSONArray>& files)
1307 {
1308     Node* node = assertNode(errorString, nodeId);
1309     if (!node)
1310         return;
1311     if (!node->hasTagName(inputTag) || !toHTMLInputElement(node)->isFileUpload()) {
1312         *errorString = "Node is not a file input element";
1313         return;
1314     }
1315
1316     RefPtr<FileList> fileList = FileList::create();
1317     for (JSONArray::const_iterator iter = files->begin(); iter != files->end(); ++iter) {
1318         String path;
1319         if (!(*iter)->asString(&path)) {
1320             *errorString = "Files must be strings";
1321             return;
1322         }
1323         fileList->append(File::create(path));
1324     }
1325     toHTMLInputElement(node)->setFiles(fileList);
1326 }
1327
1328 static RefPtr<TypeBuilder::Array<double> > buildArrayForQuad(const FloatQuad& quad)
1329 {
1330     RefPtr<TypeBuilder::Array<double> > array = TypeBuilder::Array<double>::create();
1331     array->addItem(quad.p1().x());
1332     array->addItem(quad.p1().y());
1333     array->addItem(quad.p2().x());
1334     array->addItem(quad.p2().y());
1335     array->addItem(quad.p3().x());
1336     array->addItem(quad.p3().y());
1337     array->addItem(quad.p4().x());
1338     array->addItem(quad.p4().y());
1339     return array.release();
1340 }
1341
1342 void InspectorDOMAgent::getBoxModel(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::DOM::BoxModel>& model)
1343 {
1344     Node* node = assertNode(errorString, nodeId);
1345     if (!node)
1346         return;
1347
1348     Vector<FloatQuad> quads;
1349     bool isInlineOrBox = m_overlay->getBoxModel(node, &quads);
1350     if (!isInlineOrBox) {
1351         *errorString = "Could not compute box model.";
1352         return;
1353     }
1354
1355     RenderObject* renderer = node->renderer();
1356     Frame* frame = node->document().frame();
1357     FrameView* view = frame->view();
1358
1359     IntRect boundingBox = pixelSnappedIntRect(view->contentsToRootView(renderer->absoluteBoundingBoxRect()));
1360     RenderBoxModelObject* modelObject = renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : 0;
1361
1362     model = TypeBuilder::DOM::BoxModel::create()
1363         .setContent(buildArrayForQuad(quads.at(3)))
1364         .setPadding(buildArrayForQuad(quads.at(2)))
1365         .setBorder(buildArrayForQuad(quads.at(1)))
1366         .setMargin(buildArrayForQuad(quads.at(0)))
1367         .setWidth(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetWidth(), modelObject) : boundingBox.width())
1368         .setHeight(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetHeight(), modelObject) : boundingBox.height());
1369 }
1370
1371 void InspectorDOMAgent::getNodeForLocation(ErrorString* errorString, int x, int y, int* nodeId)
1372 {
1373     if (!pushDocumentUponHandlelessOperation(errorString))
1374         return;
1375
1376     Node* node = hoveredNodeForPoint(m_document->frame(), IntPoint(x, y), false);
1377     if (!node) {
1378         *errorString = "No node found at given location";
1379         return;
1380     }
1381     *nodeId = pushNodePathToFrontend(node);
1382 }
1383
1384 void InspectorDOMAgent::resolveNode(ErrorString* errorString, int nodeId, const String* const objectGroup, RefPtr<TypeBuilder::Runtime::RemoteObject>& result)
1385 {
1386     String objectGroupName = objectGroup ? *objectGroup : "";
1387     Node* node = nodeForId(nodeId);
1388     if (!node) {
1389         *errorString = "No node with given id found";
1390         return;
1391     }
1392     RefPtr<TypeBuilder::Runtime::RemoteObject> object = resolveNode(node, objectGroupName);
1393     if (!object) {
1394         *errorString = "Node with given id does not belong to the document";
1395         return;
1396     }
1397     result = object;
1398 }
1399
1400 void InspectorDOMAgent::getAttributes(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<String> >& result)
1401 {
1402     Element* element = assertElement(errorString, nodeId);
1403     if (!element)
1404         return;
1405
1406     result = buildArrayForElementAttributes(element);
1407 }
1408
1409 void InspectorDOMAgent::requestNode(ErrorString*, const String& objectId, int* nodeId)
1410 {
1411     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
1412     Node* node = injectedScript.nodeForObjectId(objectId);
1413     if (node)
1414         *nodeId = pushNodePathToFrontend(node);
1415     else
1416         *nodeId = 0;
1417 }
1418
1419 // static
1420 String InspectorDOMAgent::documentURLString(Document* document)
1421 {
1422     if (!document || document->url().isNull())
1423         return "";
1424     return document->url().string();
1425 }
1426
1427 static String documentBaseURLString(Document* document)
1428 {
1429     return document->completeURL("").string();
1430 }
1431
1432 static TypeBuilder::DOM::ShadowRootType::Enum shadowRootType(ShadowRoot* shadowRoot)
1433 {
1434     switch (shadowRoot->type()) {
1435     case ShadowRoot::UserAgentShadowRoot:
1436         return TypeBuilder::DOM::ShadowRootType::User_agent;
1437     case ShadowRoot::AuthorShadowRoot:
1438         return TypeBuilder::DOM::ShadowRootType::Author;
1439     }
1440     ASSERT_NOT_REACHED();
1441     return TypeBuilder::DOM::ShadowRootType::User_agent;
1442 }
1443
1444 PassRefPtr<TypeBuilder::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap)
1445 {
1446     int id = bind(node, nodesMap);
1447     String nodeName;
1448     String localName;
1449     String nodeValue;
1450
1451     switch (node->nodeType()) {
1452     case Node::TEXT_NODE:
1453     case Node::COMMENT_NODE:
1454     case Node::CDATA_SECTION_NODE:
1455         nodeValue = node->nodeValue();
1456         if (nodeValue.length() > maxTextSize)
1457             nodeValue = nodeValue.left(maxTextSize) + ellipsisUChar;
1458         break;
1459     case Node::ATTRIBUTE_NODE:
1460         localName = node->localName();
1461         break;
1462     case Node::DOCUMENT_FRAGMENT_NODE:
1463     case Node::DOCUMENT_NODE:
1464     case Node::ELEMENT_NODE:
1465     default:
1466         nodeName = node->nodeName();
1467         localName = node->localName();
1468         break;
1469     }
1470
1471     RefPtr<TypeBuilder::DOM::Node> value = TypeBuilder::DOM::Node::create()
1472         .setNodeId(id)
1473         .setNodeType(static_cast<int>(node->nodeType()))
1474         .setNodeName(nodeName)
1475         .setLocalName(localName)
1476         .setNodeValue(nodeValue);
1477
1478     bool forcePushChildren = false;
1479     if (node->isElementNode()) {
1480         Element* element = toElement(node);
1481         value->setAttributes(buildArrayForElementAttributes(element));
1482         if (node->isFrameOwnerElement()) {
1483             HTMLFrameOwnerElement* frameOwner = toHTMLFrameOwnerElement(node);
1484             if (Frame* frame = frameOwner->contentFrame())
1485                 value->setFrameId(m_pageAgent->frameId(frame));
1486             if (Document* doc = frameOwner->contentDocument())
1487                 value->setContentDocument(buildObjectForNode(doc, 0, nodesMap));
1488         }
1489
1490         ElementShadow* shadow = element->shadow();
1491         if (shadow) {
1492             RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > shadowRoots = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
1493             for (ShadowRoot* root = shadow->youngestShadowRoot(); root; root = root->olderShadowRoot())
1494                 shadowRoots->addItem(buildObjectForNode(root, 0, nodesMap));
1495             value->setShadowRoots(shadowRoots);
1496             forcePushChildren = true;
1497         }
1498
1499         if (element->hasTagName(templateTag)) {
1500             value->setTemplateContent(buildObjectForNode(toHTMLTemplateElement(element)->content(), 0, nodesMap));
1501             forcePushChildren = true;
1502         }
1503
1504         switch (element->pseudoId()) {
1505         case BEFORE:
1506             value->setPseudoType(TypeBuilder::DOM::PseudoType::Before);
1507             break;
1508         case AFTER:
1509             value->setPseudoType(TypeBuilder::DOM::PseudoType::After);
1510             break;
1511         default: {
1512             RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > pseudoElements = buildArrayForPseudoElements(element, nodesMap);
1513             if (pseudoElements) {
1514                 value->setPseudoElements(pseudoElements.release());
1515                 forcePushChildren = true;
1516             }
1517             break;
1518         }
1519         }
1520     } else if (node->isDocumentNode()) {
1521         Document* document = toDocument(node);
1522         value->setDocumentURL(documentURLString(document));
1523         value->setBaseURL(documentBaseURLString(document));
1524         value->setXmlVersion(document->xmlVersion());
1525     } else if (node->isDocumentTypeNode()) {
1526         DocumentType* docType = toDocumentType(node);
1527         value->setPublicId(docType->publicId());
1528         value->setSystemId(docType->systemId());
1529         value->setInternalSubset(docType->internalSubset());
1530     } else if (node->isAttributeNode()) {
1531         Attr* attribute = toAttr(node);
1532         value->setName(attribute->name());
1533         value->setValue(attribute->value());
1534     } else if (node->isShadowRoot()) {
1535         value->setShadowRootType(shadowRootType(toShadowRoot(node)));
1536     }
1537
1538     if (node->isContainerNode()) {
1539         int nodeCount = innerChildNodeCount(node);
1540         value->setChildNodeCount(nodeCount);
1541         if (forcePushChildren && !depth)
1542             depth = 1;
1543         RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = buildArrayForContainerChildren(node, depth, nodesMap);
1544         if (children->length() > 0 || depth) // Push children along with shadow in any case.
1545             value->setChildren(children.release());
1546     }
1547
1548     return value.release();
1549 }
1550
1551 PassRefPtr<TypeBuilder::Array<String> > InspectorDOMAgent::buildArrayForElementAttributes(Element* element)
1552 {
1553     RefPtr<TypeBuilder::Array<String> > attributesValue = TypeBuilder::Array<String>::create();
1554     // Go through all attributes and serialize them.
1555     if (!element->hasAttributes())
1556         return attributesValue.release();
1557     unsigned numAttrs = element->attributeCount();
1558     for (unsigned i = 0; i < numAttrs; ++i) {
1559         // Add attribute pair
1560         const Attribute* attribute = element->attributeItem(i);
1561         attributesValue->addItem(attribute->name().toString());
1562         attributesValue->addItem(attribute->value());
1563     }
1564     return attributesValue.release();
1565 }
1566
1567 PassRefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap)
1568 {
1569     RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
1570     if (depth == 0) {
1571         // Special-case the only text child - pretend that container's children have been requested.
1572         Node* firstChild = container->firstChild();
1573         if (firstChild && firstChild->nodeType() == Node::TEXT_NODE && !firstChild->nextSibling()) {
1574             children->addItem(buildObjectForNode(firstChild, 0, nodesMap));
1575             m_childrenRequested.add(bind(container, nodesMap));
1576         }
1577         return children.release();
1578     }
1579
1580     Node* child = innerFirstChild(container);
1581     depth--;
1582     m_childrenRequested.add(bind(container, nodesMap));
1583
1584     while (child) {
1585         children->addItem(buildObjectForNode(child, depth, nodesMap));
1586         child = innerNextSibling(child);
1587     }
1588     return children.release();
1589 }
1590
1591 PassRefPtr<TypeBuilder::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node, const String* objectGroupId)
1592 {
1593     RefPtr<EventListener> eventListener = registeredEventListener.listener;
1594     Document& document = node->document();
1595     RefPtr<TypeBuilder::DOM::EventListener> value = TypeBuilder::DOM::EventListener::create()
1596         .setType(eventType)
1597         .setUseCapture(registeredEventListener.useCapture)
1598         .setIsAttribute(eventListener->isAttribute())
1599         .setNodeId(pushNodePathToFrontend(node))
1600         .setHandlerBody(eventListenerHandlerBody(&document, eventListener.get()));
1601     if (objectGroupId) {
1602         ScriptValue functionValue = eventListenerHandler(&document, eventListener.get());
1603         if (!functionValue.hasNoValue()) {
1604             Frame* frame = document.frame();
1605             if (frame) {
1606                 ScriptState* scriptState = eventListenerHandlerScriptState(frame, eventListener.get());
1607                 if (scriptState) {
1608                     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
1609                     if (!injectedScript.hasNoValue()) {
1610                         RefPtr<TypeBuilder::Runtime::RemoteObject> valueJson = injectedScript.wrapObject(functionValue, *objectGroupId);
1611                         value->setHandler(valueJson);
1612                     }
1613                 }
1614             }
1615         }
1616     }
1617     String sourceName;
1618     String scriptId;
1619     int lineNumber;
1620     if (eventListenerHandlerLocation(&node->document(), eventListener.get(), sourceName, scriptId, lineNumber)) {
1621         RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
1622             .setScriptId(scriptId)
1623             .setLineNumber(lineNumber);
1624         value->setLocation(location);
1625         if (!sourceName.isEmpty())
1626             value->setSourceName(sourceName);
1627     }
1628     return value.release();
1629 }
1630
1631 PassRefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > InspectorDOMAgent::buildArrayForPseudoElements(Element* element, NodeToIdMap* nodesMap)
1632 {
1633     if (!element->pseudoElement(BEFORE) && !element->pseudoElement(AFTER))
1634         return 0;
1635
1636     RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > pseudoElements = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
1637     if (element->pseudoElement(BEFORE))
1638         pseudoElements->addItem(buildObjectForNode(element->pseudoElement(BEFORE), 0, nodesMap));
1639     if (element->pseudoElement(AFTER))
1640         pseudoElements->addItem(buildObjectForNode(element->pseudoElement(AFTER), 0, nodesMap));
1641     return pseudoElements.release();
1642 }
1643
1644 Node* InspectorDOMAgent::innerFirstChild(Node* node)
1645 {
1646     node = node->firstChild();
1647     while (isWhitespace(node))
1648         node = node->nextSibling();
1649     return node;
1650 }
1651
1652 Node* InspectorDOMAgent::innerNextSibling(Node* node)
1653 {
1654     do {
1655         node = node->nextSibling();
1656     } while (isWhitespace(node));
1657     return node;
1658 }
1659
1660 Node* InspectorDOMAgent::innerPreviousSibling(Node* node)
1661 {
1662     do {
1663         node = node->previousSibling();
1664     } while (isWhitespace(node));
1665     return node;
1666 }
1667
1668 unsigned InspectorDOMAgent::innerChildNodeCount(Node* node)
1669 {
1670     unsigned count = 0;
1671     Node* child = innerFirstChild(node);
1672     while (child) {
1673         count++;
1674         child = innerNextSibling(child);
1675     }
1676     return count;
1677 }
1678
1679 Node* InspectorDOMAgent::innerParentNode(Node* node)
1680 {
1681     if (node->isDocumentNode()) {
1682         Document* document = toDocument(node);
1683         return document->ownerElement();
1684     }
1685     return node->parentOrShadowHostNode();
1686 }
1687
1688 bool InspectorDOMAgent::isWhitespace(Node* node)
1689 {
1690     //TODO: pull ignoreWhitespace setting from the frontend and use here.
1691     return node && node->nodeType() == Node::TEXT_NODE && node->nodeValue().stripWhiteSpace().length() == 0;
1692 }
1693
1694 void InspectorDOMAgent::domContentLoadedEventFired(Frame* frame)
1695 {
1696     if (!frame->isMainFrame())
1697         return;
1698
1699     // Re-push document once it is loaded.
1700     discardFrontendBindings();
1701     if (m_state->getBoolean(DOMAgentState::documentRequested))
1702         m_frontend->documentUpdated();
1703 }
1704
1705 void InspectorDOMAgent::invalidateFrameOwnerElement(Frame* frame)
1706 {
1707     Element* frameOwner = frame->document()->ownerElement();
1708     if (!frameOwner)
1709         return;
1710
1711     int frameOwnerId = m_documentNodeToIdMap.get(frameOwner);
1712     if (!frameOwnerId)
1713         return;
1714
1715     // Re-add frame owner element together with its new children.
1716     int parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner));
1717     m_frontend->childNodeRemoved(parentId, frameOwnerId);
1718     unbind(frameOwner, &m_documentNodeToIdMap);
1719
1720     RefPtr<TypeBuilder::DOM::Node> value = buildObjectForNode(frameOwner, 0, &m_documentNodeToIdMap);
1721     Node* previousSibling = innerPreviousSibling(frameOwner);
1722     int prevId = previousSibling ? m_documentNodeToIdMap.get(previousSibling) : 0;
1723     m_frontend->childNodeInserted(parentId, prevId, value.release());
1724 }
1725
1726 void InspectorDOMAgent::didCommitLoad(Frame* frame, DocumentLoader* loader)
1727 {
1728     // FIXME: If "frame" is always guarenteed to be in the same Page as loader->frame()
1729     // then all we need to check here is loader->frame()->isMainFrame()
1730     // and we don't need "frame" at all.
1731     Frame* mainFrame = frame->page()->mainFrame();
1732     if (loader->frame() != mainFrame) {
1733         invalidateFrameOwnerElement(loader->frame());
1734         return;
1735     }
1736
1737     setDocument(mainFrame->document());
1738 }
1739
1740 void InspectorDOMAgent::didInsertDOMNode(Node* node)
1741 {
1742     if (isWhitespace(node))
1743         return;
1744
1745     // We could be attaching existing subtree. Forget the bindings.
1746     unbind(node, &m_documentNodeToIdMap);
1747
1748     ContainerNode* parent = node->parentNode();
1749     if (!parent)
1750         return;
1751
1752     int parentId = m_documentNodeToIdMap.get(parent);
1753     // Return if parent is not mapped yet.
1754     if (!parentId)
1755         return;
1756
1757     if (!m_childrenRequested.contains(parentId)) {
1758         // No children are mapped yet -> only notify on changes of hasChildren.
1759         m_frontend->childNodeCountUpdated(parentId, innerChildNodeCount(parent));
1760     } else {
1761         // Children have been requested -> return value of a new child.
1762         Node* prevSibling = innerPreviousSibling(node);
1763         int prevId = prevSibling ? m_documentNodeToIdMap.get(prevSibling) : 0;
1764         RefPtr<TypeBuilder::DOM::Node> value = buildObjectForNode(node, 0, &m_documentNodeToIdMap);
1765         m_frontend->childNodeInserted(parentId, prevId, value.release());
1766     }
1767 }
1768
1769 void InspectorDOMAgent::willRemoveDOMNode(Node* node)
1770 {
1771     if (isWhitespace(node))
1772         return;
1773
1774     ContainerNode* parent = node->parentNode();
1775
1776     // If parent is not mapped yet -> ignore the event.
1777     if (!m_documentNodeToIdMap.contains(parent))
1778         return;
1779
1780     int parentId = m_documentNodeToIdMap.get(parent);
1781
1782     if (!m_childrenRequested.contains(parentId)) {
1783         // No children are mapped yet -> only notify on changes of hasChildren.
1784         if (innerChildNodeCount(parent) == 1)
1785             m_frontend->childNodeCountUpdated(parentId, 0);
1786     } else
1787         m_frontend->childNodeRemoved(parentId, m_documentNodeToIdMap.get(node));
1788     unbind(node, &m_documentNodeToIdMap);
1789 }
1790
1791 void InspectorDOMAgent::willModifyDOMAttr(Element*, const AtomicString& oldValue, const AtomicString& newValue)
1792 {
1793     m_suppressAttributeModifiedEvent = (oldValue == newValue);
1794 }
1795
1796 void InspectorDOMAgent::didModifyDOMAttr(Element* element, const AtomicString& name, const AtomicString& value)
1797 {
1798     bool shouldSuppressEvent = m_suppressAttributeModifiedEvent;
1799     m_suppressAttributeModifiedEvent = false;
1800     if (shouldSuppressEvent)
1801         return;
1802
1803     int id = boundNodeId(element);
1804     // If node is not mapped yet -> ignore the event.
1805     if (!id)
1806         return;
1807
1808     if (m_domListener)
1809         m_domListener->didModifyDOMAttr(element);
1810
1811     m_frontend->attributeModified(id, name, value);
1812 }
1813
1814 void InspectorDOMAgent::didRemoveDOMAttr(Element* element, const AtomicString& name)
1815 {
1816     int id = boundNodeId(element);
1817     // If node is not mapped yet -> ignore the event.
1818     if (!id)
1819         return;
1820
1821     if (m_domListener)
1822         m_domListener->didModifyDOMAttr(element);
1823
1824     m_frontend->attributeRemoved(id, name);
1825 }
1826
1827 void InspectorDOMAgent::styleAttributeInvalidated(const Vector<Element*>& elements)
1828 {
1829     RefPtr<TypeBuilder::Array<int> > nodeIds = TypeBuilder::Array<int>::create();
1830     for (unsigned i = 0, size = elements.size(); i < size; ++i) {
1831         Element* element = elements.at(i);
1832         int id = boundNodeId(element);
1833         // If node is not mapped yet -> ignore the event.
1834         if (!id)
1835             continue;
1836
1837         if (m_domListener)
1838             m_domListener->didModifyDOMAttr(element);
1839         nodeIds->addItem(id);
1840     }
1841     m_frontend->inlineStyleInvalidated(nodeIds.release());
1842 }
1843
1844 void InspectorDOMAgent::characterDataModified(CharacterData* characterData)
1845 {
1846     int id = m_documentNodeToIdMap.get(characterData);
1847     if (!id) {
1848         // Push text node if it is being created.
1849         didInsertDOMNode(characterData);
1850         return;
1851     }
1852     m_frontend->characterDataModified(id, characterData->data());
1853 }
1854
1855 void InspectorDOMAgent::didInvalidateStyleAttr(Node* node)
1856 {
1857     int id = m_documentNodeToIdMap.get(node);
1858     // If node is not mapped yet -> ignore the event.
1859     if (!id)
1860         return;
1861
1862     if (!m_revalidateStyleAttrTask)
1863         m_revalidateStyleAttrTask = adoptPtr(new RevalidateStyleAttributeTask(this));
1864     m_revalidateStyleAttrTask->scheduleFor(toElement(node));
1865 }
1866
1867 void InspectorDOMAgent::didPushShadowRoot(Element* host, ShadowRoot* root)
1868 {
1869     if (!host->ownerDocument())
1870         return;
1871
1872     int hostId = m_documentNodeToIdMap.get(host);
1873     if (!hostId)
1874         return;
1875
1876     pushChildNodesToFrontend(hostId, 1);
1877     m_frontend->shadowRootPushed(hostId, buildObjectForNode(root, 0, &m_documentNodeToIdMap));
1878 }
1879
1880 void InspectorDOMAgent::willPopShadowRoot(Element* host, ShadowRoot* root)
1881 {
1882     if (!host->ownerDocument())
1883         return;
1884
1885     int hostId = m_documentNodeToIdMap.get(host);
1886     int rootId = m_documentNodeToIdMap.get(root);
1887     if (hostId && rootId)
1888         m_frontend->shadowRootPopped(hostId, rootId);
1889 }
1890
1891 void InspectorDOMAgent::frameDocumentUpdated(Frame* frame)
1892 {
1893     Document* document = frame->document();
1894     if (!document)
1895         return;
1896
1897     Page* page = frame->page();
1898     ASSERT(page);
1899     if (frame != page->mainFrame())
1900         return;
1901
1902     // Only update the main frame document, nested frame document updates are not required
1903     // (will be handled by invalidateFrameOwnerElement()).
1904     setDocument(document);
1905 }
1906
1907 void InspectorDOMAgent::pseudoElementCreated(PseudoElement* pseudoElement)
1908 {
1909     Element* parent = pseudoElement->parentOrShadowHostElement();
1910     if (!parent)
1911         return;
1912     int parentId = m_documentNodeToIdMap.get(parent);
1913     if (!parentId)
1914         return;
1915
1916     pushChildNodesToFrontend(parentId, 1);
1917     m_frontend->pseudoElementAdded(parentId, buildObjectForNode(pseudoElement, 0, &m_documentNodeToIdMap));
1918 }
1919
1920 void InspectorDOMAgent::pseudoElementDestroyed(PseudoElement* pseudoElement)
1921 {
1922     int pseudoElementId = m_documentNodeToIdMap.get(pseudoElement);
1923     if (!pseudoElementId)
1924         return;
1925
1926     // If a PseudoElement is bound, its parent element must be bound, too.
1927     Element* parent = pseudoElement->parentOrShadowHostElement();
1928     ASSERT(parent);
1929     int parentId = m_documentNodeToIdMap.get(parent);
1930     ASSERT(parentId);
1931
1932     unbind(pseudoElement, &m_documentNodeToIdMap);
1933     m_frontend->pseudoElementRemoved(parentId, pseudoElementId);
1934 }
1935
1936 Node* InspectorDOMAgent::nodeForPath(const String& path)
1937 {
1938     // The path is of form "1,HTML,2,BODY,1,DIV"
1939     if (!m_document)
1940         return 0;
1941
1942     Node* node = m_document.get();
1943     Vector<String> pathTokens;
1944     path.split(",", false, pathTokens);
1945     if (!pathTokens.size())
1946         return 0;
1947     for (size_t i = 0; i < pathTokens.size() - 1; i += 2) {
1948         bool success = true;
1949         unsigned childNumber = pathTokens[i].toUInt(&success);
1950         if (!success)
1951             return 0;
1952         if (childNumber >= innerChildNodeCount(node))
1953             return 0;
1954
1955         Node* child = innerFirstChild(node);
1956         String childName = pathTokens[i + 1];
1957         for (size_t j = 0; child && j < childNumber; ++j)
1958             child = innerNextSibling(child);
1959
1960         if (!child || child->nodeName() != childName)
1961             return 0;
1962         node = child;
1963     }
1964     return node;
1965 }
1966
1967 void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString* errorString, const String& path, int* nodeId)
1968 {
1969     if (Node* node = nodeForPath(path))
1970         *nodeId = pushNodePathToFrontend(node);
1971     else
1972         *errorString = "No node with given path found";
1973 }
1974
1975 void InspectorDOMAgent::pushNodeByBackendIdToFrontend(ErrorString* errorString, BackendNodeId backendNodeId, int* nodeId)
1976 {
1977     if (!m_backendIdToNode.contains(backendNodeId)) {
1978         *errorString = "No node with given backend id found";
1979         return;
1980     }
1981
1982     Node* node = m_backendIdToNode.get(backendNodeId).first;
1983     String nodeGroup = m_backendIdToNode.get(backendNodeId).second;
1984     *nodeId = pushNodePathToFrontend(node);
1985
1986     if (nodeGroup == "") {
1987         m_backendIdToNode.remove(backendNodeId);
1988         m_nodeGroupToBackendIdMap.find(nodeGroup)->value.remove(node);
1989     }
1990 }
1991
1992 void InspectorDOMAgent::getRelayoutBoundary(ErrorString* errorString, int nodeId, int* relayoutBoundaryNodeId)
1993 {
1994     Node* node = assertNode(errorString, nodeId);
1995     if (!node)
1996         return;
1997     RenderObject* renderer = node->renderer();
1998     if (!renderer) {
1999         *errorString = "No renderer for node, perhaps orphan or hidden node";
2000         return;
2001     }
2002     while (renderer && !renderer->isRoot() && !renderer->isRelayoutBoundaryForInspector())
2003         renderer = renderer->container();
2004     Node* resultNode = renderer ? renderer->generatingNode() : node->ownerDocument();
2005     *relayoutBoundaryNodeId = pushNodePathToFrontend(resultNode);
2006 }
2007
2008 PassRefPtr<TypeBuilder::Runtime::RemoteObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup)
2009 {
2010     Document* document = node->isDocumentNode() ? &node->document() : node->ownerDocument();
2011     Frame* frame = document ? document->frame() : 0;
2012     if (!frame)
2013         return 0;
2014
2015     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
2016     if (injectedScript.hasNoValue())
2017         return 0;
2018
2019     return injectedScript.wrapNode(node, objectGroup);
2020 }
2021
2022 bool InspectorDOMAgent::pushDocumentUponHandlelessOperation(ErrorString* errorString)
2023 {
2024     if (!m_documentNodeToIdMap.contains(m_document)) {
2025         RefPtr<TypeBuilder::DOM::Node> root;
2026         getDocument(errorString, root);
2027         return errorString->isEmpty();
2028     }
2029     return true;
2030 }
2031
2032 } // namespace WebCore
2033