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