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