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