27d960f725f059fcd73e9e141f7f0d27757561d2
[WebKit-https.git] / Source / WebCore / inspector / agents / InspectorDOMAgent.cpp
1 /*
2  * Copyright (C) 2009-2017 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 #include "InspectorDOMAgent.h"
33
34 #include "AXObjectCache.h"
35 #include "AccessibilityNodeObject.h"
36 #include "Attr.h"
37 #include "CSSComputedStyleDeclaration.h"
38 #include "CSSPropertyNames.h"
39 #include "CSSPropertySourceData.h"
40 #include "CSSRule.h"
41 #include "CSSRuleList.h"
42 #include "CSSStyleRule.h"
43 #include "CSSStyleSheet.h"
44 #include "CharacterData.h"
45 #include "CommandLineAPIHost.h"
46 #include "ContainerNode.h"
47 #include "Cookie.h"
48 #include "CookieJar.h"
49 #include "DOMEditor.h"
50 #include "DOMException.h"
51 #include "DOMPatchSupport.h"
52 #include "DOMWindow.h"
53 #include "Document.h"
54 #include "DocumentType.h"
55 #include "Editing.h"
56 #include "Element.h"
57 #include "Event.h"
58 #include "EventListener.h"
59 #include "EventNames.h"
60 #include "Frame.h"
61 #include "FrameTree.h"
62 #include "HTMLElement.h"
63 #include "HTMLFrameOwnerElement.h"
64 #include "HTMLMediaElement.h"
65 #include "HTMLNames.h"
66 #include "HTMLParserIdioms.h"
67 #include "HTMLScriptElement.h"
68 #include "HTMLStyleElement.h"
69 #include "HTMLTemplateElement.h"
70 #include "HTMLVideoElement.h"
71 #include "HitTestResult.h"
72 #include "InspectorCSSAgent.h"
73 #include "InspectorClient.h"
74 #include "InspectorController.h"
75 #include "InspectorHistory.h"
76 #include "InspectorNodeFinder.h"
77 #include "InspectorOverlay.h"
78 #include "InspectorPageAgent.h"
79 #include "InstrumentingAgents.h"
80 #include "IntRect.h"
81 #include "JSDOMBindingSecurity.h"
82 #include "JSEventListener.h"
83 #include "JSNode.h"
84 #include "MutationEvent.h"
85 #include "Node.h"
86 #include "NodeList.h"
87 #include "Page.h"
88 #include "Pasteboard.h"
89 #include "PseudoElement.h"
90 #include "RenderStyle.h"
91 #include "RenderStyleConstants.h"
92 #include "ScriptState.h"
93 #include "ShadowRoot.h"
94 #include "StaticNodeList.h"
95 #include "StyleProperties.h"
96 #include "StyleResolver.h"
97 #include "StyleSheetList.h"
98 #include "Text.h"
99 #include "TextNodeTraversal.h"
100 #include "Timer.h"
101 #include "VideoPlaybackQuality.h"
102 #include "WebInjectedScriptManager.h"
103 #include "XPathResult.h"
104 #include "markup.h"
105 #include <JavaScriptCore/IdentifiersFactory.h>
106 #include <JavaScriptCore/InjectedScript.h>
107 #include <JavaScriptCore/InjectedScriptManager.h>
108 #include <JavaScriptCore/JSCInlines.h>
109 #include <pal/crypto/CryptoDigest.h>
110 #include <wtf/text/Base64.h>
111 #include <wtf/text/CString.h>
112 #include <wtf/text/WTFString.h>
113
114 namespace WebCore {
115
116 using namespace Inspector;
117
118 using namespace HTMLNames;
119
120 static const size_t maxTextSize = 10000;
121 static const UChar ellipsisUChar[] = { 0x2026, 0 };
122
123 static Color parseColor(const JSON::Object* colorObject)
124 {
125     if (!colorObject)
126         return Color::transparent;
127
128     int r = 0;
129     int g = 0;
130     int b = 0;
131     if (!colorObject->getInteger("r", r) || !colorObject->getInteger("g", g) || !colorObject->getInteger("b", b))
132         return Color::transparent;
133
134     double a = 1.0;
135     if (!colorObject->getDouble("a", a))
136         return Color(r, g, b);
137
138     // Clamp alpha to the [0..1] range.
139     if (a < 0)
140         a = 0;
141     else if (a > 1)
142         a = 1;
143
144     return Color(r, g, b, static_cast<int>(a * 255));
145 }
146
147 static Color parseConfigColor(const String& fieldName, const JSON::Object* configObject)
148 {
149     RefPtr<JSON::Object> colorObject;
150     configObject->getObject(fieldName, colorObject);
151
152     return parseColor(colorObject.get());
153 }
154
155 static bool parseQuad(const JSON::Array& quadArray, FloatQuad* quad)
156 {
157     const size_t coordinatesInQuad = 8;
158     double coordinates[coordinatesInQuad];
159     if (quadArray.length() != coordinatesInQuad)
160         return false;
161     for (size_t i = 0; i < coordinatesInQuad; ++i) {
162         if (!quadArray.get(i)->asDouble(*(coordinates + i)))
163             return false;
164     }
165     quad->setP1(FloatPoint(coordinates[0], coordinates[1]));
166     quad->setP2(FloatPoint(coordinates[2], coordinates[3]));
167     quad->setP3(FloatPoint(coordinates[4], coordinates[5]));
168     quad->setP4(FloatPoint(coordinates[6], coordinates[7]));
169
170     return true;
171 }
172
173 class RevalidateStyleAttributeTask {
174     WTF_MAKE_FAST_ALLOCATED;
175 public:
176     RevalidateStyleAttributeTask(InspectorDOMAgent*);
177     void scheduleFor(Element*);
178     void reset() { m_timer.stop(); }
179     void timerFired();
180
181 private:
182     InspectorDOMAgent* m_domAgent;
183     Timer m_timer;
184     HashSet<RefPtr<Element>> m_elements;
185 };
186
187 RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent)
188     : m_domAgent(domAgent)
189     , m_timer(*this, &RevalidateStyleAttributeTask::timerFired)
190 {
191 }
192
193 void RevalidateStyleAttributeTask::scheduleFor(Element* element)
194 {
195     m_elements.add(element);
196     if (!m_timer.isActive())
197         m_timer.startOneShot(0_s);
198 }
199
200 void RevalidateStyleAttributeTask::timerFired()
201 {
202     // The timer is stopped on m_domAgent destruction, so this method will never be called after m_domAgent has been destroyed.
203     Vector<Element*> elements;
204     for (auto& element : m_elements)
205         elements.append(element.get());
206     m_domAgent->styleAttributeInvalidated(elements);
207
208     m_elements.clear();
209 }
210
211 class InspectableNode final : public CommandLineAPIHost::InspectableObject {
212 public:
213     explicit InspectableNode(Node* node)
214         : m_node(node)
215     {
216     }
217
218     JSC::JSValue get(JSC::ExecState& state) final
219     {
220         return InspectorDOMAgent::nodeAsScriptValue(state, m_node.get());
221     }
222 private:
223     RefPtr<Node> m_node;
224 };
225
226 class EventFiredCallback final : public EventListener {
227 public:
228     static Ref<EventFiredCallback> create(InspectorDOMAgent& domAgent)
229     {
230         return adoptRef(*new EventFiredCallback(domAgent));
231     }
232
233     bool operator==(const EventListener& other) const final
234     {
235         return this == &other;
236     }
237
238     void handleEvent(ScriptExecutionContext&, Event& event) final
239     {
240         if (!is<Node>(event.target()) || m_domAgent.m_dispatchedEvents.contains(&event))
241             return;
242
243         auto* node = downcast<Node>(event.target());
244         int nodeId = m_domAgent.pushNodePathToFrontend(node);
245         if (!nodeId)
246             return;
247
248         m_domAgent.m_dispatchedEvents.add(&event);
249
250         RefPtr<JSON::Object> data = JSON::Object::create();
251
252 #if ENABLE(FULLSCREEN_API)
253         if (event.type() == eventNames().webkitfullscreenchangeEvent)
254             data->setBoolean("enabled"_s, !!node->document().webkitFullscreenElement());
255 #endif // ENABLE(FULLSCREEN_API)
256
257         auto timestamp = m_domAgent.m_environment.executionStopwatch()->elapsedTime().seconds();
258         m_domAgent.m_frontendDispatcher->didFireEvent(nodeId, event.type(), timestamp, data->size() ? WTFMove(data) : nullptr);
259     }
260
261 private:
262     EventFiredCallback(InspectorDOMAgent& domAgent)
263         : EventListener(EventListener::CPPEventListenerType)
264         , m_domAgent(domAgent)
265     {
266     }
267
268     InspectorDOMAgent& m_domAgent;
269 };
270
271 String InspectorDOMAgent::toErrorString(ExceptionCode ec)
272 {
273     return ec ? String(DOMException::name(ec)) : emptyString();
274 }
275
276 String InspectorDOMAgent::toErrorString(Exception&& exception)
277 {
278     return DOMException::name(exception.code());
279 }
280
281 InspectorDOMAgent::InspectorDOMAgent(PageAgentContext& context, InspectorOverlay* overlay)
282     : InspectorAgentBase("DOM"_s, context)
283     , m_injectedScriptManager(context.injectedScriptManager)
284     , m_frontendDispatcher(std::make_unique<Inspector::DOMFrontendDispatcher>(context.frontendRouter))
285     , m_backendDispatcher(Inspector::DOMBackendDispatcher::create(context.backendDispatcher, this))
286     , m_inspectedPage(context.inspectedPage)
287     , m_overlay(overlay)
288 #if ENABLE(VIDEO)
289     , m_mediaMetricsTimer(*this, &InspectorDOMAgent::mediaMetricsTimerFired)
290 #endif
291 {
292 }
293
294 InspectorDOMAgent::~InspectorDOMAgent()
295 {
296     reset();
297     ASSERT(!m_searchingForNode);
298 }
299
300 void InspectorDOMAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
301 {
302     m_history = std::make_unique<InspectorHistory>();
303     m_domEditor = std::make_unique<DOMEditor>(*m_history);
304
305     m_instrumentingAgents.setInspectorDOMAgent(this);
306     m_document = m_inspectedPage.mainFrame().document();
307
308 #if ENABLE(VIDEO)
309     if (m_document)
310         addEventListenersToNode(*m_document);
311
312     for (auto* mediaElement : HTMLMediaElement::allMediaElements())
313         addEventListenersToNode(*mediaElement);
314 #endif
315
316     if (m_nodeToFocus)
317         focusNode();
318 }
319
320 void InspectorDOMAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
321 {
322     m_history.reset();
323     m_domEditor.reset();
324     m_mousedOverNode = nullptr;
325
326     ErrorString unused;
327     setSearchingForNode(unused, false, nullptr);
328     hideHighlight(unused);
329
330     m_instrumentingAgents.setInspectorDOMAgent(nullptr);
331     m_documentRequested = false;
332     reset();
333 }
334
335 Vector<Document*> InspectorDOMAgent::documents()
336 {
337     Vector<Document*> result;
338     for (Frame* frame = m_document->frame(); frame; frame = frame->tree().traverseNext()) {
339         Document* document = frame->document();
340         if (!document)
341             continue;
342         result.append(document);
343     }
344     return result;
345 }
346
347 void InspectorDOMAgent::reset()
348 {
349     if (m_history)
350         m_history->reset();
351     m_searchResults.clear();
352     discardBindings();
353     if (m_revalidateStyleAttrTask)
354         m_revalidateStyleAttrTask->reset();
355     m_document = nullptr;
356 }
357
358 void InspectorDOMAgent::setDocument(Document* document)
359 {
360     if (document == m_document.get())
361         return;
362
363     reset();
364
365     m_document = document;
366
367     if (!m_documentRequested)
368         return;
369
370     // Immediately communicate null document or document that has finished loading.
371     if (!document || !document->parsing())
372         m_frontendDispatcher->documentUpdated();
373 }
374
375 void InspectorDOMAgent::releaseDanglingNodes()
376 {
377     m_danglingNodeToIdMaps.clear();
378 }
379
380 int InspectorDOMAgent::bind(Node* node, NodeToIdMap* nodesMap)
381 {
382     int id = nodesMap->get(node);
383     if (id)
384         return id;
385     id = m_lastNodeId++;
386     nodesMap->set(node, id);
387     m_idToNode.set(id, node);
388     m_idToNodesMap.set(id, nodesMap);
389     return id;
390 }
391
392 void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap)
393 {
394     int id = nodesMap->get(node);
395     if (!id)
396         return;
397
398     m_idToNode.remove(id);
399
400     if (node->isFrameOwnerElement()) {
401         const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>(node);
402         if (Document* contentDocument = frameOwner->contentDocument())
403             unbind(contentDocument, nodesMap);
404     }
405
406     if (is<Element>(*node)) {
407         Element& element = downcast<Element>(*node);
408         if (ShadowRoot* root = element.shadowRoot())
409             unbind(root, nodesMap);
410         if (PseudoElement* beforeElement = element.beforePseudoElement())
411             unbind(beforeElement, nodesMap);
412         if (PseudoElement* afterElement = element.afterPseudoElement())
413             unbind(afterElement, nodesMap);
414     }
415
416     nodesMap->remove(node);
417
418     if (auto* cssAgent = m_instrumentingAgents.inspectorCSSAgent())
419         cssAgent->didRemoveDOMNode(*node, id);
420
421     if (m_childrenRequested.remove(id)) {
422         // FIXME: Would be better to do this iteratively rather than recursively.
423         for (Node* child = innerFirstChild(node); child; child = innerNextSibling(child))
424             unbind(child, nodesMap);
425     }
426 }
427
428 Node* InspectorDOMAgent::assertNode(ErrorString& errorString, int nodeId)
429 {
430     Node* node = nodeForId(nodeId);
431     if (!node) {
432         errorString = "Could not find node with given id"_s;
433         return nullptr;
434     }
435     return node;
436 }
437
438 Document* InspectorDOMAgent::assertDocument(ErrorString& errorString, int nodeId)
439 {
440     Node* node = assertNode(errorString, nodeId);
441     if (!node)
442         return nullptr;
443     if (!is<Document>(*node)) {
444         errorString = "Document is not available"_s;
445         return nullptr;
446     }
447     return downcast<Document>(node);
448 }
449
450 Element* InspectorDOMAgent::assertElement(ErrorString& errorString, int nodeId)
451 {
452     Node* node = assertNode(errorString, nodeId);
453     if (!node)
454         return nullptr;
455     if (!is<Element>(*node)) {
456         errorString = "Node is not an Element"_s;
457         return nullptr;
458     }
459     return downcast<Element>(node);
460 }
461
462 Node* InspectorDOMAgent::assertEditableNode(ErrorString& errorString, int nodeId)
463 {
464     Node* node = assertNode(errorString, nodeId);
465     if (!node)
466         return nullptr;
467     if (node->isInUserAgentShadowTree()) {
468         errorString = "Cannot edit nodes in user agent shadow trees"_s;
469         return nullptr;
470     }
471     if (node->isPseudoElement()) {
472         errorString = "Cannot edit pseudo elements"_s;
473         return nullptr;
474     }
475     return node;
476 }
477
478 Element* InspectorDOMAgent::assertEditableElement(ErrorString& errorString, int nodeId)
479 {
480     Element* element = assertElement(errorString, nodeId);
481     if (!element)
482         return nullptr;
483     if (element->isInUserAgentShadowTree()) {
484         errorString = "Cannot edit elements in user agent shadow trees"_s;
485         return nullptr;
486     }
487     if (element->isPseudoElement()) {
488         errorString = "Cannot edit pseudo elements"_s;
489         return nullptr;
490     }
491     return element;
492 }
493
494 void InspectorDOMAgent::getDocument(ErrorString& errorString, RefPtr<Inspector::Protocol::DOM::Node>& root)
495 {
496     m_documentRequested = true;
497
498     if (!m_document) {
499         errorString = "Document is not available"_s;
500         return;
501     }
502
503     // Reset backend state.
504     RefPtr<Document> document = m_document;
505     reset();
506     m_document = document;
507
508     root = buildObjectForNode(m_document.get(), 2, &m_documentNodeToIdMap);
509 }
510
511 void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId, int depth)
512 {
513     Node* node = nodeForId(nodeId);
514     if (!node || (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE && node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE))
515         return;
516
517     NodeToIdMap* nodeMap = m_idToNodesMap.get(nodeId);
518
519     if (m_childrenRequested.contains(nodeId)) {
520         if (depth <= 1)
521             return;
522
523         depth--;
524
525         for (node = innerFirstChild(node); node; node = innerNextSibling(node)) {
526             int childNodeId = nodeMap->get(node);
527             ASSERT(childNodeId);
528             pushChildNodesToFrontend(childNodeId, depth);
529         }
530
531         return;
532     }
533
534     auto children = buildArrayForContainerChildren(node, depth, nodeMap);
535     m_frontendDispatcher->setChildNodes(nodeId, WTFMove(children));
536 }
537
538 void InspectorDOMAgent::discardBindings()
539 {
540     m_documentNodeToIdMap.clear();
541     m_idToNode.clear();
542     m_dispatchedEvents.clear();
543     m_eventListenerEntries.clear();
544     releaseDanglingNodes();
545     m_childrenRequested.clear();
546 }
547
548 int InspectorDOMAgent::pushNodeToFrontend(ErrorString& errorString, int documentNodeId, Node* nodeToPush)
549 {
550     Document* document = assertDocument(errorString, documentNodeId);
551     if (!document)
552         return 0;
553     if (&nodeToPush->document() != document) {
554         errorString = "Node is not part of the document with given id"_s;
555         return 0;
556     }
557
558     return pushNodePathToFrontend(nodeToPush);
559 }
560
561 Node* InspectorDOMAgent::nodeForId(int id)
562 {
563     if (!m_idToNode.isValidKey(id))
564         return nullptr;
565
566     return m_idToNode.get(id);
567 }
568
569 void InspectorDOMAgent::requestChildNodes(ErrorString& errorString, int nodeId, const int* depth)
570 {
571     int sanitizedDepth;
572
573     if (!depth)
574         sanitizedDepth = 1;
575     else if (*depth == -1)
576         sanitizedDepth = INT_MAX;
577     else if (*depth > 0)
578         sanitizedDepth = *depth;
579     else {
580         errorString = "Please provide a positive integer as a depth or -1 for entire subtree"_s;
581         return;
582     }
583
584     pushChildNodesToFrontend(nodeId, sanitizedDepth);
585 }
586
587 void InspectorDOMAgent::querySelector(ErrorString& errorString, int nodeId, const String& selectors, int* elementId)
588 {
589     *elementId = 0;
590     Node* node = assertNode(errorString, nodeId);
591     if (!node)
592         return;
593     if (!is<ContainerNode>(*node)) {
594         assertElement(errorString, nodeId);
595         return;
596     }
597
598     auto queryResult = downcast<ContainerNode>(*node).querySelector(selectors);
599     if (queryResult.hasException()) {
600         errorString = "DOM Error while querying"_s;
601         return;
602     }
603
604     if (auto* element = queryResult.releaseReturnValue())
605         *elementId = pushNodePathToFrontend(element);
606 }
607
608 void InspectorDOMAgent::querySelectorAll(ErrorString& errorString, int nodeId, const String& selectors, RefPtr<JSON::ArrayOf<int>>& result)
609 {
610     Node* node = assertNode(errorString, nodeId);
611     if (!node)
612         return;
613     if (!is<ContainerNode>(*node)) {
614         assertElement(errorString, nodeId);
615         return;
616     }
617
618     auto queryResult = downcast<ContainerNode>(*node).querySelectorAll(selectors);
619     if (queryResult.hasException()) {
620         errorString = "DOM Error while querying"_s;
621         return;
622     }
623
624     auto nodes = queryResult.releaseReturnValue();
625     result = JSON::ArrayOf<int>::create();
626     for (unsigned i = 0; i < nodes->length(); ++i)
627         result->addItem(pushNodePathToFrontend(nodes->item(i)));
628 }
629
630 int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush)
631 {
632     ASSERT(nodeToPush);  // Invalid input
633
634     if (!m_document)
635         return 0;
636     if (!m_documentNodeToIdMap.contains(m_document))
637         return 0;
638
639     // Return id in case the node is known.
640     int result = m_documentNodeToIdMap.get(nodeToPush);
641     if (result)
642         return result;
643
644     Node* node = nodeToPush;
645     Vector<Node*> path;
646     NodeToIdMap* danglingMap = 0;
647
648     while (true) {
649         Node* parent = innerParentNode(node);
650         if (!parent) {
651             // Node being pushed is detached -> push subtree root.
652             auto newMap = std::make_unique<NodeToIdMap>();
653             danglingMap = newMap.get();
654             m_danglingNodeToIdMaps.append(newMap.release());
655             auto children = JSON::ArrayOf<Inspector::Protocol::DOM::Node>::create();
656             children->addItem(buildObjectForNode(node, 0, danglingMap));
657             m_frontendDispatcher->setChildNodes(0, WTFMove(children));
658             break;
659         } else {
660             path.append(parent);
661             if (m_documentNodeToIdMap.get(parent))
662                 break;
663             else
664                 node = parent;
665         }
666     }
667
668     NodeToIdMap* map = danglingMap ? danglingMap : &m_documentNodeToIdMap;
669     for (int i = path.size() - 1; i >= 0; --i) {
670         int nodeId = map->get(path.at(i));
671         ASSERT(nodeId);
672         pushChildNodesToFrontend(nodeId);
673     }
674     return map->get(nodeToPush);
675 }
676
677 int InspectorDOMAgent::boundNodeId(const Node* node)
678 {
679     return m_documentNodeToIdMap.get(const_cast<Node*>(node));
680 }
681
682 void InspectorDOMAgent::setAttributeValue(ErrorString& errorString, int elementId, const String& name, const String& value)
683 {
684     Element* element = assertEditableElement(errorString, elementId);
685     if (!element)
686         return;
687
688     m_domEditor->setAttribute(*element, name, value, errorString);
689 }
690
691 void InspectorDOMAgent::setAttributesAsText(ErrorString& errorString, int elementId, const String& text, const String* name)
692 {
693     Element* element = assertEditableElement(errorString, elementId);
694     if (!element)
695         return;
696
697     auto parsedElement = createHTMLElement(element->document(), spanTag);
698     auto result = parsedElement.get().setInnerHTML("<span " + text + "></span>");
699     if (result.hasException()) {
700         errorString = toErrorString(result.releaseException());
701         return;
702     }
703
704     Node* child = parsedElement->firstChild();
705     if (!child) {
706         errorString = "Could not parse value as attributes"_s;
707         return;
708     }
709
710     Element* childElement = downcast<Element>(child);
711     if (!childElement->hasAttributes() && name) {
712         m_domEditor->removeAttribute(*element, *name, errorString);
713         return;
714     }
715
716     bool foundOriginalAttribute = false;
717     for (const Attribute& attribute : childElement->attributesIterator()) {
718         // Add attribute pair
719         foundOriginalAttribute = foundOriginalAttribute || (name && attribute.name().toString() == *name);
720         if (!m_domEditor->setAttribute(*element, attribute.name().toString(), attribute.value(), errorString))
721             return;
722     }
723
724     if (!foundOriginalAttribute && name && !name->stripWhiteSpace().isEmpty())
725         m_domEditor->removeAttribute(*element, *name, errorString);
726 }
727
728 void InspectorDOMAgent::removeAttribute(ErrorString& errorString, int elementId, const String& name)
729 {
730     Element* element = assertEditableElement(errorString, elementId);
731     if (!element)
732         return;
733
734     m_domEditor->removeAttribute(*element, name, errorString);
735 }
736
737 void InspectorDOMAgent::removeNode(ErrorString& errorString, int nodeId)
738 {
739     Node* node = assertEditableNode(errorString, nodeId);
740     if (!node)
741         return;
742
743     ContainerNode* parentNode = node->parentNode();
744     if (!parentNode) {
745         errorString = "Cannot remove detached node"_s;
746         return;
747     }
748
749     m_domEditor->removeChild(*parentNode, *node, errorString);
750 }
751
752 void InspectorDOMAgent::setNodeName(ErrorString& errorString, int nodeId, const String& tagName, int* newId)
753 {
754     *newId = 0;
755
756     RefPtr<Node> oldNode = nodeForId(nodeId);
757     if (!is<Element>(oldNode))
758         return;
759
760     auto createElementResult = oldNode->document().createElementForBindings(tagName);
761     if (createElementResult.hasException())
762         return;
763     auto newElement = createElementResult.releaseReturnValue();
764
765     // Copy over the original node's attributes.
766     newElement->cloneAttributesFromElement(downcast<Element>(*oldNode));
767
768     // Copy over the original node's children.
769     RefPtr<Node> child;
770     while ((child = oldNode->firstChild())) {
771         if (!m_domEditor->insertBefore(newElement, *child, 0, errorString))
772             return;
773     }
774
775     // Replace the old node with the new node
776     RefPtr<ContainerNode> parent = oldNode->parentNode();
777     if (!m_domEditor->insertBefore(*parent, newElement.copyRef(), oldNode->nextSibling(), errorString))
778         return;
779     if (!m_domEditor->removeChild(*parent, *oldNode, errorString))
780         return;
781
782     *newId = pushNodePathToFrontend(newElement.ptr());
783     if (m_childrenRequested.contains(nodeId))
784         pushChildNodesToFrontend(*newId);
785 }
786
787 void InspectorDOMAgent::getOuterHTML(ErrorString& errorString, int nodeId, WTF::String* outerHTML)
788 {
789     Node* node = assertNode(errorString, nodeId);
790     if (!node)
791         return;
792
793     *outerHTML = serializeFragment(*node, SerializedNodes::SubtreeIncludingNode);
794 }
795
796 void InspectorDOMAgent::setOuterHTML(ErrorString& errorString, int nodeId, const String& outerHTML)
797 {
798     if (!nodeId) {
799         DOMPatchSupport { *m_domEditor, *m_document }.patchDocument(outerHTML);
800         return;
801     }
802
803     Node* node = assertEditableNode(errorString, nodeId);
804     if (!node)
805         return;
806
807     Document& document = node->document();
808     if (!document.isHTMLDocument() && !document.isXMLDocument()) {
809         errorString = "Not an HTML/XML document"_s;
810         return;
811     }
812
813     Node* newNode = nullptr;
814     if (!m_domEditor->setOuterHTML(*node, outerHTML, newNode, errorString))
815         return;
816
817     if (!newNode) {
818         // The only child node has been deleted.
819         return;
820     }
821
822     int newId = pushNodePathToFrontend(newNode);
823
824     bool childrenRequested = m_childrenRequested.contains(nodeId);
825     if (childrenRequested)
826         pushChildNodesToFrontend(newId);
827 }
828
829 void InspectorDOMAgent::insertAdjacentHTML(ErrorString& errorString, int nodeId, const String& position, const String& html)
830 {
831     Node* node = assertEditableNode(errorString, nodeId);
832     if (!node)
833         return;
834
835     if (!is<Element>(node)) {
836         errorString = "Can only call insertAdjacentHTML on Elements."_s;
837         return;
838     }
839
840     m_domEditor->insertAdjacentHTML(downcast<Element>(*node), position, html, errorString);
841 }
842
843 void InspectorDOMAgent::setNodeValue(ErrorString& errorString, int nodeId, const String& value)
844 {
845     Node* node = assertEditableNode(errorString, nodeId);
846     if (!node)
847         return;
848
849     if (!is<Text>(*node)) {
850         errorString = "Can only set value of text nodes"_s;
851         return;
852     }
853
854     m_domEditor->replaceWholeText(downcast<Text>(*node), value, errorString);
855 }
856
857 void InspectorDOMAgent::getSupportedEventNames(ErrorString&, RefPtr<JSON::ArrayOf<String>>& eventNames)
858 {
859     eventNames = JSON::ArrayOf<String>::create();
860
861 #define DOM_EVENT_NAMES_ADD(name) eventNames->addItem(#name);
862     DOM_EVENT_NAMES_FOR_EACH(DOM_EVENT_NAMES_ADD)
863 #undef DOM_EVENT_NAMES_ADD
864 }
865
866 void InspectorDOMAgent::getDataBindingsForNode(ErrorString& errorString, int /* nodeId */, RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::DataBinding>>& /* dataBindings */)
867 {
868     errorString = "Not supported"_s;
869 }
870
871 void InspectorDOMAgent::getAssociatedDataForNode(ErrorString& errorString, int /* nodeId */, Optional<String>& /* associatedData */)
872 {
873     errorString = "Not supported"_s;
874 }
875
876 void InspectorDOMAgent::getEventListenersForNode(ErrorString& errorString, int nodeId, RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::EventListener>>& listenersArray)
877 {
878     listenersArray = JSON::ArrayOf<Inspector::Protocol::DOM::EventListener>::create();
879
880     auto* node = assertNode(errorString, nodeId);
881     if (!node)
882         return;
883
884     Vector<RefPtr<EventTarget>> ancestors;
885     ancestors.append(node);
886     for (auto* ancestor = node->parentOrShadowHostNode(); ancestor; ancestor = ancestor->parentOrShadowHostNode())
887         ancestors.append(ancestor);
888     if (auto* window = node->document().domWindow())
889         ancestors.append(window);
890
891     struct EventListenerInfo {
892         RefPtr<EventTarget> eventTarget;
893         const AtomicString eventType;
894         const EventListenerVector eventListeners;
895     };
896
897     Vector<EventListenerInfo> eventInformation;
898     for (size_t i = ancestors.size(); i; --i) {
899         auto& ancestor = ancestors[i - 1];
900         for (auto& eventType : ancestor->eventTypes()) {
901             EventListenerVector filteredListeners;
902             for (auto& listener : ancestor->eventListeners(eventType)) {
903                 if (listener->callback().type() == EventListener::JSEventListenerType)
904                     filteredListeners.append(listener);
905             }
906             if (!filteredListeners.isEmpty())
907                 eventInformation.append({ ancestor, eventType, WTFMove(filteredListeners) });
908         }
909     }
910
911     auto addListener = [&] (RegisteredEventListener& listener, const EventListenerInfo& info) {
912         int identifier = 0;
913         bool disabled = false;
914         bool hasBreakpoint = false;
915
916         for (auto& inspectorEventListener : m_eventListenerEntries.values()) {
917             if (inspectorEventListener.matches(*info.eventTarget, info.eventType, listener.callback(), listener.useCapture())) {
918                 identifier = inspectorEventListener.identifier;
919                 disabled = inspectorEventListener.disabled;
920                 hasBreakpoint = inspectorEventListener.hasBreakpoint;
921                 break;
922             }
923         }
924
925         if (!identifier) {
926             InspectorEventListener inspectorEventListener(m_lastEventListenerId++, *info.eventTarget, info.eventType, listener.callback(), listener.useCapture());
927
928             identifier = inspectorEventListener.identifier;
929             disabled = inspectorEventListener.disabled;
930             hasBreakpoint = inspectorEventListener.hasBreakpoint;
931
932             m_eventListenerEntries.add(identifier, inspectorEventListener);
933         }
934
935         listenersArray->addItem(buildObjectForEventListener(listener, identifier, *info.eventTarget, info.eventType, disabled, hasBreakpoint));
936     };
937
938     // Get Capturing Listeners (in this order)
939     size_t eventInformationLength = eventInformation.size();
940     for (auto& info : eventInformation) {
941         for (auto& listener : info.eventListeners) {
942             if (listener->useCapture())
943                 addListener(*listener, info);
944         }
945     }
946
947     // Get Bubbling Listeners (reverse order)
948     for (size_t i = eventInformationLength; i; --i) {
949         const EventListenerInfo& info = eventInformation[i - 1];
950         for (auto& listener : info.eventListeners) {
951             if (!listener->useCapture())
952                 addListener(*listener, info);
953         }
954     }
955
956     if (m_inspectedNode == node)
957         m_suppressEventListenerChangedEvent = false;
958 }
959
960 void InspectorDOMAgent::setEventListenerDisabled(ErrorString& errorString, int eventListenerId, bool disabled)
961 {
962     auto it = m_eventListenerEntries.find(eventListenerId);
963     if (it == m_eventListenerEntries.end()) {
964         errorString = "No event listener for given identifier."_s;
965         return;
966     }
967
968     it->value.disabled = disabled;
969 }
970
971 void InspectorDOMAgent::setBreakpointForEventListener(ErrorString& errorString, int eventListenerId)
972 {
973     auto it = m_eventListenerEntries.find(eventListenerId);
974     if (it == m_eventListenerEntries.end()) {
975         errorString = "No event listener for given identifier."_s;
976         return;
977     }
978
979     it->value.hasBreakpoint = true;
980 }
981
982 void InspectorDOMAgent::removeBreakpointForEventListener(ErrorString& errorString, int eventListenerId)
983 {
984     auto it = m_eventListenerEntries.find(eventListenerId);
985     if (it == m_eventListenerEntries.end()) {
986         errorString = "No event listener for given identifier."_s;
987         return;
988     }
989
990     it->value.hasBreakpoint = false;
991 }
992
993 void InspectorDOMAgent::getAccessibilityPropertiesForNode(ErrorString& errorString, int nodeId, RefPtr<Inspector::Protocol::DOM::AccessibilityProperties>& axProperties)
994 {
995     Node* node = assertNode(errorString, nodeId);
996     if (!node)
997         return;
998
999     axProperties = buildObjectForAccessibilityProperties(node);
1000 }
1001
1002 void InspectorDOMAgent::performSearch(ErrorString& errorString, const String& query, const JSON::Array* nodeIds, const bool* caseSensitive, String* searchId, int* resultCount)
1003 {
1004     // FIXME: Search works with node granularity - number of matches within node is not calculated.
1005     InspectorNodeFinder finder(query, caseSensitive && *caseSensitive);
1006
1007     if (nodeIds) {
1008         for (auto& nodeValue : *nodeIds) {
1009             if (!nodeValue) {
1010                 errorString = "Invalid nodeIds item."_s;
1011                 return;
1012             }
1013             int nodeId = 0;
1014             if (!nodeValue->asInteger(nodeId)) {
1015                 errorString = "Invalid nodeIds item type. Expecting integer types."_s;
1016                 return;
1017             }
1018             Node* node = assertNode(errorString, nodeId);
1019             if (!node) {
1020                 // assertNode should have filled the errorString for us.
1021                 ASSERT(errorString.length());
1022                 return;
1023             }
1024             finder.performSearch(node);
1025         }
1026     } else {
1027         // There's no need to iterate the frames tree because
1028         // the search helper will go inside the frame owner elements.
1029         finder.performSearch(m_document.get());
1030     }
1031
1032     *searchId = IdentifiersFactory::createIdentifier();
1033
1034     auto& resultsVector = m_searchResults.add(*searchId, Vector<RefPtr<Node>>()).iterator->value;
1035     for (auto& result : finder.results())
1036         resultsVector.append(result);
1037
1038     *resultCount = resultsVector.size();
1039 }
1040
1041 void InspectorDOMAgent::getSearchResults(ErrorString& errorString, const String& searchId, int fromIndex, int toIndex, RefPtr<JSON::ArrayOf<int>>& nodeIds)
1042 {
1043     SearchResults::iterator it = m_searchResults.find(searchId);
1044     if (it == m_searchResults.end()) {
1045         errorString = "No search session with given id found"_s;
1046         return;
1047     }
1048
1049     int size = it->value.size();
1050     if (fromIndex < 0 || toIndex > size || fromIndex >= toIndex) {
1051         errorString = "Invalid search result range"_s;
1052         return;
1053     }
1054
1055     nodeIds = JSON::ArrayOf<int>::create();
1056     for (int i = fromIndex; i < toIndex; ++i)
1057         nodeIds->addItem(pushNodePathToFrontend((it->value)[i].get()));
1058 }
1059
1060 void InspectorDOMAgent::discardSearchResults(ErrorString&, const String& searchId)
1061 {
1062     m_searchResults.remove(searchId);
1063 }
1064
1065 bool InspectorDOMAgent::handleMousePress()
1066 {
1067     if (!m_searchingForNode)
1068         return false;
1069
1070     if (Node* node = m_overlay->highlightedNode()) {
1071         inspect(node);
1072         return true;
1073     }
1074     return false;
1075 }
1076
1077 bool InspectorDOMAgent::handleTouchEvent(Node& node)
1078 {
1079     if (!m_searchingForNode)
1080         return false;
1081     if (m_inspectModeHighlightConfig) {
1082         m_overlay->highlightNode(&node, *m_inspectModeHighlightConfig);
1083         inspect(&node);
1084         return true;
1085     }
1086     return false;
1087 }
1088
1089 void InspectorDOMAgent::inspect(Node* inspectedNode)
1090 {
1091     ErrorString unused;
1092     RefPtr<Node> node = inspectedNode;
1093     setSearchingForNode(unused, false, nullptr);
1094
1095     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
1096         node = node->parentNode();
1097     m_nodeToFocus = node;
1098
1099     if (!m_nodeToFocus)
1100         return;
1101
1102     focusNode();
1103 }
1104
1105 void InspectorDOMAgent::focusNode()
1106 {
1107     if (!m_frontendDispatcher)
1108         return;
1109
1110     ASSERT(m_nodeToFocus);
1111
1112     RefPtr<Node> node = m_nodeToFocus.get();
1113     m_nodeToFocus = nullptr;
1114
1115     Frame* frame = node->document().frame();
1116     if (!frame)
1117         return;
1118
1119     JSC::ExecState* scriptState = mainWorldExecState(frame);
1120     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(scriptState);
1121     if (injectedScript.hasNoValue())
1122         return;
1123
1124     injectedScript.inspectObject(nodeAsScriptValue(*scriptState, node.get()));
1125 }
1126
1127 void InspectorDOMAgent::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
1128 {
1129     m_mousedOverNode = result.innerNode();
1130
1131     if (!m_searchingForNode)
1132         return;
1133
1134     highlightMousedOverNode();
1135 }
1136
1137 void InspectorDOMAgent::highlightMousedOverNode()
1138 {
1139     Node* node = m_mousedOverNode.get();
1140     while (node && node->nodeType() == Node::TEXT_NODE)
1141         node = node->parentNode();
1142     if (node && m_inspectModeHighlightConfig)
1143         m_overlay->highlightNode(node, *m_inspectModeHighlightConfig);
1144 }
1145
1146 void InspectorDOMAgent::setSearchingForNode(ErrorString& errorString, bool enabled, const JSON::Object* highlightInspectorObject)
1147 {
1148     if (m_searchingForNode == enabled)
1149         return;
1150
1151     m_searchingForNode = enabled;
1152
1153     if (enabled) {
1154         m_inspectModeHighlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject);
1155         if (!m_inspectModeHighlightConfig)
1156             return;
1157         highlightMousedOverNode();
1158     } else
1159         hideHighlight(errorString);
1160
1161     m_overlay->didSetSearchingForNode(m_searchingForNode);
1162
1163     if (InspectorClient* client = m_inspectedPage.inspectorController().inspectorClient())
1164         client->elementSelectionChanged(m_searchingForNode);
1165 }
1166
1167 std::unique_ptr<HighlightConfig> InspectorDOMAgent::highlightConfigFromInspectorObject(ErrorString& errorString, const JSON::Object* highlightInspectorObject)
1168 {
1169     if (!highlightInspectorObject) {
1170         errorString = "Internal error: highlight configuration parameter is missing"_s;
1171         return nullptr;
1172     }
1173
1174     auto highlightConfig = std::make_unique<HighlightConfig>();
1175     bool showInfo = false; // Default: false (do not show a tooltip).
1176     highlightInspectorObject->getBoolean("showInfo", showInfo);
1177     highlightConfig->showInfo = showInfo;
1178     highlightConfig->content = parseConfigColor("contentColor", highlightInspectorObject);
1179     highlightConfig->contentOutline = parseConfigColor("contentOutlineColor", highlightInspectorObject);
1180     highlightConfig->padding = parseConfigColor("paddingColor", highlightInspectorObject);
1181     highlightConfig->border = parseConfigColor("borderColor", highlightInspectorObject);
1182     highlightConfig->margin = parseConfigColor("marginColor", highlightInspectorObject);
1183     return highlightConfig;
1184 }
1185
1186 void InspectorDOMAgent::setInspectModeEnabled(ErrorString& errorString, bool enabled, const JSON::Object* highlightConfig)
1187 {
1188     setSearchingForNode(errorString, enabled, highlightConfig ? highlightConfig : nullptr);
1189 }
1190
1191 void InspectorDOMAgent::highlightRect(ErrorString&, int x, int y, int width, int height, const JSON::Object* color, const JSON::Object* outlineColor, const bool* usePageCoordinates)
1192 {
1193     auto quad = std::make_unique<FloatQuad>(FloatRect(x, y, width, height));
1194     innerHighlightQuad(WTFMove(quad), color, outlineColor, usePageCoordinates);
1195 }
1196
1197 void InspectorDOMAgent::highlightQuad(ErrorString& errorString, const JSON::Array& quadArray, const JSON::Object* color, const JSON::Object* outlineColor, const bool* usePageCoordinates)
1198 {
1199     auto quad = std::make_unique<FloatQuad>();
1200     if (!parseQuad(quadArray, quad.get())) {
1201         errorString = "Invalid Quad format"_s;
1202         return;
1203     }
1204     innerHighlightQuad(WTFMove(quad), color, outlineColor, usePageCoordinates);
1205 }
1206
1207 void InspectorDOMAgent::innerHighlightQuad(std::unique_ptr<FloatQuad> quad, const JSON::Object* color, const JSON::Object* outlineColor, const bool* usePageCoordinates)
1208 {
1209     auto highlightConfig = std::make_unique<HighlightConfig>();
1210     highlightConfig->content = parseColor(color);
1211     highlightConfig->contentOutline = parseColor(outlineColor);
1212     highlightConfig->usePageCoordinates = usePageCoordinates ? *usePageCoordinates : false;
1213     m_overlay->highlightQuad(WTFMove(quad), *highlightConfig);
1214 }
1215
1216 void InspectorDOMAgent::highlightSelector(ErrorString& errorString, const JSON::Object& highlightInspectorObject, const String& selectorString, const String* frameId)
1217 {
1218     RefPtr<Document> document;
1219
1220     if (frameId) {
1221         auto* pageAgent = m_instrumentingAgents.inspectorPageAgent();
1222         if (!pageAgent) {
1223             errorString = "Missing Page agent"_s;
1224             return;
1225         }
1226
1227         Frame* frame = pageAgent->frameForId(*frameId);
1228         if (!frame) {
1229             errorString = "No frame for given id found"_s;
1230             return;
1231         }
1232
1233         document = frame->document();
1234     } else
1235         document = m_document;
1236
1237     if (!document) {
1238         errorString = "Document could not be found"_s;
1239         return;
1240     }
1241
1242     auto queryResult = document->querySelectorAll(selectorString);
1243     // FIXME: <https://webkit.org/b/146161> Web Inspector: DOM.highlightSelector should work for "a:visited"
1244     if (queryResult.hasException()) {
1245         errorString = "DOM Error while querying"_s;
1246         return;
1247     }
1248
1249     auto highlightConfig = highlightConfigFromInspectorObject(errorString, &highlightInspectorObject);
1250     if (!highlightConfig)
1251         return;
1252
1253     m_overlay->highlightNodeList(queryResult.releaseReturnValue(), *highlightConfig);
1254 }
1255
1256 void InspectorDOMAgent::highlightNode(ErrorString& errorString, const JSON::Object& highlightInspectorObject, const int* nodeId, const String* objectId)
1257 {
1258     Node* node = nullptr;
1259     if (nodeId)
1260         node = assertNode(errorString, *nodeId);
1261     else if (objectId) {
1262         node = nodeForObjectId(*objectId);
1263         if (!node)
1264             errorString = "Node for given objectId not found"_s;
1265     } else
1266         errorString = "Either nodeId or objectId must be specified"_s;
1267
1268     if (!node)
1269         return;
1270
1271     std::unique_ptr<HighlightConfig> highlightConfig = highlightConfigFromInspectorObject(errorString, &highlightInspectorObject);
1272     if (!highlightConfig)
1273         return;
1274
1275     m_overlay->highlightNode(node, *highlightConfig);
1276 }
1277
1278 void InspectorDOMAgent::highlightNodeList(ErrorString& errorString, const JSON::Array& nodeIds, const JSON::Object& highlightInspectorObject)
1279 {
1280     Vector<Ref<Node>> nodes;
1281     for (auto& nodeValue : nodeIds) {
1282         if (!nodeValue) {
1283             errorString = "Invalid nodeIds item."_s;
1284             return;
1285         }
1286
1287         int nodeId = 0;
1288         if (!nodeValue->asInteger(nodeId)) {
1289             errorString = "Invalid nodeIds item type. Expecting integer types."_s;
1290             return;
1291         }
1292
1293         // In the case that a node is removed in the time between when highlightNodeList is invoked
1294         // by the frontend and it is executed by the backend, we should still attempt to highlight
1295         // as many nodes as possible. As such, we should ignore any errors generated when attempting
1296         // to get a Node from a given nodeId. 
1297         ErrorString ignored;
1298         Node* node = assertNode(ignored, nodeId);
1299         if (!node)
1300             continue;
1301
1302         nodes.append(*node);
1303     }
1304
1305     std::unique_ptr<HighlightConfig> highlightConfig = highlightConfigFromInspectorObject(errorString, &highlightInspectorObject);
1306     if (!highlightConfig)
1307         return;
1308
1309     m_overlay->highlightNodeList(StaticNodeList::create(WTFMove(nodes)), *highlightConfig);
1310 }
1311
1312 void InspectorDOMAgent::highlightFrame(ErrorString& errorString, const String& frameId, const JSON::Object* color, const JSON::Object* outlineColor)
1313 {
1314     auto* pageAgent = m_instrumentingAgents.inspectorPageAgent();
1315     if (!pageAgent) {
1316         errorString = "Missing Page agent"_s;
1317         return;
1318     }
1319
1320     Frame* frame = pageAgent->assertFrame(errorString, frameId);
1321     if (!frame)
1322         return;
1323
1324     if (frame->ownerElement()) {
1325         auto highlightConfig = std::make_unique<HighlightConfig>();
1326         highlightConfig->showInfo = true; // Always show tooltips for frames.
1327         highlightConfig->content = parseColor(color);
1328         highlightConfig->contentOutline = parseColor(outlineColor);
1329         m_overlay->highlightNode(frame->ownerElement(), *highlightConfig);
1330     }
1331 }
1332
1333 void InspectorDOMAgent::hideHighlight(ErrorString&)
1334 {
1335     m_overlay->hideHighlight();
1336 }
1337
1338 void InspectorDOMAgent::moveTo(ErrorString& errorString, int nodeId, int targetElementId, const int* anchorNodeId, int* newNodeId)
1339 {
1340     Node* node = assertEditableNode(errorString, nodeId);
1341     if (!node)
1342         return;
1343
1344     Element* targetElement = assertEditableElement(errorString, targetElementId);
1345     if (!targetElement)
1346         return;
1347
1348     Node* anchorNode = 0;
1349     if (anchorNodeId && *anchorNodeId) {
1350         anchorNode = assertEditableNode(errorString, *anchorNodeId);
1351         if (!anchorNode)
1352             return;
1353         if (anchorNode->parentNode() != targetElement) {
1354             errorString = "Anchor node must be child of the target element"_s;
1355             return;
1356         }
1357     }
1358
1359     if (!m_domEditor->insertBefore(*targetElement, *node, anchorNode, errorString))
1360         return;
1361
1362     *newNodeId = pushNodePathToFrontend(node);
1363 }
1364
1365 void InspectorDOMAgent::undo(ErrorString& errorString)
1366 {
1367     auto result = m_history->undo();
1368     if (result.hasException())
1369         errorString = toErrorString(result.releaseException());
1370 }
1371
1372 void InspectorDOMAgent::redo(ErrorString& errorString)
1373 {
1374     auto result = m_history->redo();
1375     if (result.hasException())
1376         errorString = toErrorString(result.releaseException());
1377 }
1378
1379 void InspectorDOMAgent::markUndoableState(ErrorString&)
1380 {
1381     m_history->markUndoableState();
1382 }
1383
1384 void InspectorDOMAgent::focus(ErrorString& errorString, int nodeId)
1385 {
1386     Element* element = assertElement(errorString, nodeId);
1387     if (!element)
1388         return;
1389     if (!element->isFocusable()) {
1390         errorString = "Element is not focusable"_s;
1391         return;
1392     }
1393     element->focus();
1394 }
1395
1396 void InspectorDOMAgent::setInspectedNode(ErrorString& errorString, int nodeId)
1397 {
1398     Node* node = nodeForId(nodeId);
1399     if (!node || node->isInUserAgentShadowTree()) {
1400         errorString = "No node with given id found"_s;
1401         return;
1402     }
1403
1404     m_inspectedNode = node;
1405
1406     if (CommandLineAPIHost* commandLineAPIHost = static_cast<WebInjectedScriptManager&>(m_injectedScriptManager).commandLineAPIHost())
1407         commandLineAPIHost->addInspectedObject(std::make_unique<InspectableNode>(node));
1408
1409     m_suppressEventListenerChangedEvent = false;
1410 }
1411
1412 void InspectorDOMAgent::resolveNode(ErrorString& errorString, int nodeId, const String* objectGroup, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result)
1413 {
1414     String objectGroupName = objectGroup ? *objectGroup : emptyString();
1415     Node* node = nodeForId(nodeId);
1416     if (!node) {
1417         errorString = "No node with given id found"_s;
1418         return;
1419     }
1420     RefPtr<Inspector::Protocol::Runtime::RemoteObject> object = resolveNode(node, objectGroupName);
1421     if (!object) {
1422         errorString = "Node with given id does not belong to the document"_s;
1423         return;
1424     }
1425     result = object;
1426 }
1427
1428 void InspectorDOMAgent::getAttributes(ErrorString& errorString, int nodeId, RefPtr<JSON::ArrayOf<String>>& result)
1429 {
1430     Element* element = assertElement(errorString, nodeId);
1431     if (!element)
1432         return;
1433
1434     result = buildArrayForElementAttributes(element);
1435 }
1436
1437 void InspectorDOMAgent::requestNode(ErrorString&, const String& objectId, int* nodeId)
1438 {
1439     Node* node = nodeForObjectId(objectId);
1440     if (node)
1441         *nodeId = pushNodePathToFrontend(node);
1442     else
1443         *nodeId = 0;
1444 }
1445
1446 String InspectorDOMAgent::documentURLString(Document* document)
1447 {
1448     if (!document || document->url().isNull())
1449         return emptyString();
1450     return document->url().string();
1451 }
1452
1453 static String documentBaseURLString(Document* document)
1454 {
1455     return document->completeURL(emptyString()).string();
1456 }
1457
1458 static bool pseudoElementType(PseudoId pseudoId, Inspector::Protocol::DOM::PseudoType* type)
1459 {
1460     switch (pseudoId) {
1461     case PseudoId::Before:
1462         *type = Inspector::Protocol::DOM::PseudoType::Before;
1463         return true;
1464     case PseudoId::After:
1465         *type = Inspector::Protocol::DOM::PseudoType::After;
1466         return true;
1467     default:
1468         return false;
1469     }
1470 }
1471
1472 static Inspector::Protocol::DOM::ShadowRootType shadowRootType(ShadowRootMode mode)
1473 {
1474     switch (mode) {
1475     case ShadowRootMode::UserAgent:
1476         return Inspector::Protocol::DOM::ShadowRootType::UserAgent;
1477     case ShadowRootMode::Closed:
1478         return Inspector::Protocol::DOM::ShadowRootType::Closed;
1479     case ShadowRootMode::Open:
1480         return Inspector::Protocol::DOM::ShadowRootType::Open;
1481     }
1482
1483     ASSERT_NOT_REACHED();
1484     return Inspector::Protocol::DOM::ShadowRootType::UserAgent;
1485 }
1486
1487 static Inspector::Protocol::DOM::CustomElementState customElementState(const Element& element)
1488 {
1489     if (element.isDefinedCustomElement())
1490         return Inspector::Protocol::DOM::CustomElementState::Custom;
1491     if (element.isFailedCustomElement())
1492         return Inspector::Protocol::DOM::CustomElementState::Failed;
1493     if (element.isUndefinedCustomElement() || element.isCustomElementUpgradeCandidate())
1494         return Inspector::Protocol::DOM::CustomElementState::Waiting;
1495     return Inspector::Protocol::DOM::CustomElementState::Builtin;
1496 }
1497
1498 static String computeContentSecurityPolicySHA256Hash(const Element& element)
1499 {
1500     // FIXME: Compute the digest with respect to the raw bytes received from the page.
1501     // See <https://bugs.webkit.org/show_bug.cgi?id=155184>.
1502     TextEncoding documentEncoding = element.document().textEncoding();
1503     const TextEncoding& encodingToUse = documentEncoding.isValid() ? documentEncoding : UTF8Encoding();
1504     auto content = encodingToUse.encode(TextNodeTraversal::contentsAsString(element), UnencodableHandling::Entities);
1505     auto cryptoDigest = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256);
1506     cryptoDigest->addBytes(content.data(), content.size());
1507     auto digest = cryptoDigest->computeHash();
1508     return makeString("sha256-", base64Encode(digest.data(), digest.size()));
1509 }
1510
1511 Ref<Inspector::Protocol::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap)
1512 {
1513     int id = bind(node, nodesMap);
1514     String nodeName;
1515     String localName;
1516     String nodeValue;
1517
1518     switch (node->nodeType()) {
1519     case Node::PROCESSING_INSTRUCTION_NODE:
1520         nodeName = node->nodeName();
1521         localName = node->localName();
1522         FALLTHROUGH;
1523     case Node::TEXT_NODE:
1524     case Node::COMMENT_NODE:
1525     case Node::CDATA_SECTION_NODE:
1526         nodeValue = node->nodeValue();
1527         if (nodeValue.length() > maxTextSize) {
1528             nodeValue = nodeValue.left(maxTextSize);
1529             nodeValue.append(ellipsisUChar);
1530         }
1531         break;
1532     case Node::ATTRIBUTE_NODE:
1533         localName = node->localName();
1534         break;
1535     case Node::DOCUMENT_FRAGMENT_NODE:
1536     case Node::DOCUMENT_NODE:
1537     case Node::ELEMENT_NODE:
1538     default:
1539         nodeName = node->nodeName();
1540         localName = node->localName();
1541         break;
1542     }
1543
1544     auto value = Inspector::Protocol::DOM::Node::create()
1545         .setNodeId(id)
1546         .setNodeType(static_cast<int>(node->nodeType()))
1547         .setNodeName(nodeName)
1548         .setLocalName(localName)
1549         .setNodeValue(nodeValue)
1550         .release();
1551
1552     if (node->isContainerNode()) {
1553         int nodeCount = innerChildNodeCount(node);
1554         value->setChildNodeCount(nodeCount);
1555         Ref<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> children = buildArrayForContainerChildren(node, depth, nodesMap);
1556         if (children->length() > 0)
1557             value->setChildren(WTFMove(children));
1558     }
1559
1560     auto* pageAgent = m_instrumentingAgents.inspectorPageAgent();
1561
1562     if (is<Element>(*node)) {
1563         Element& element = downcast<Element>(*node);
1564         value->setAttributes(buildArrayForElementAttributes(&element));
1565         if (is<HTMLFrameOwnerElement>(element)) {
1566             HTMLFrameOwnerElement& frameOwner = downcast<HTMLFrameOwnerElement>(element);
1567             if (pageAgent) {
1568                 Frame* frame = frameOwner.contentFrame();
1569                 if (frame)
1570                     value->setFrameId(pageAgent->frameId(frame));
1571             }
1572             Document* document = frameOwner.contentDocument();
1573             if (document)
1574                 value->setContentDocument(buildObjectForNode(document, 0, nodesMap));
1575         }
1576
1577         if (ShadowRoot* root = element.shadowRoot()) {
1578             auto shadowRoots = JSON::ArrayOf<Inspector::Protocol::DOM::Node>::create();
1579             shadowRoots->addItem(buildObjectForNode(root, 0, nodesMap));
1580             value->setShadowRoots(WTFMove(shadowRoots));
1581         }
1582
1583         if (is<HTMLTemplateElement>(element))
1584             value->setTemplateContent(buildObjectForNode(&downcast<HTMLTemplateElement>(element).content(), 0, nodesMap));
1585
1586         if (is<HTMLStyleElement>(element) || (is<HTMLScriptElement>(element) && !element.hasAttributeWithoutSynchronization(HTMLNames::srcAttr)))
1587             value->setContentSecurityPolicyHash(computeContentSecurityPolicySHA256Hash(element));
1588
1589         auto state = customElementState(element);
1590         if (state != Inspector::Protocol::DOM::CustomElementState::Builtin)
1591             value->setCustomElementState(state);
1592
1593         if (element.pseudoId() != PseudoId::None) {
1594             Inspector::Protocol::DOM::PseudoType pseudoType;
1595             if (pseudoElementType(element.pseudoId(), &pseudoType))
1596                 value->setPseudoType(pseudoType);
1597         } else {
1598             if (auto pseudoElements = buildArrayForPseudoElements(element, nodesMap))
1599                 value->setPseudoElements(WTFMove(pseudoElements));
1600         }
1601     } else if (is<Document>(*node)) {
1602         Document& document = downcast<Document>(*node);
1603         if (pageAgent)
1604             value->setFrameId(pageAgent->frameId(document.frame()));
1605         value->setDocumentURL(documentURLString(&document));
1606         value->setBaseURL(documentBaseURLString(&document));
1607         value->setXmlVersion(document.xmlVersion());
1608     } else if (is<DocumentType>(*node)) {
1609         DocumentType& docType = downcast<DocumentType>(*node);
1610         value->setPublicId(docType.publicId());
1611         value->setSystemId(docType.systemId());
1612     } else if (is<Attr>(*node)) {
1613         Attr& attribute = downcast<Attr>(*node);
1614         value->setName(attribute.name());
1615         value->setValue(attribute.value());
1616     } else if (is<ShadowRoot>(*node)) {
1617         ShadowRoot& shadowRoot = downcast<ShadowRoot>(*node);
1618         value->setShadowRootType(shadowRootType(shadowRoot.mode()));
1619     }
1620
1621     return value;
1622 }
1623
1624 Ref<JSON::ArrayOf<String>> InspectorDOMAgent::buildArrayForElementAttributes(Element* element)
1625 {
1626     auto attributesValue = JSON::ArrayOf<String>::create();
1627     // Go through all attributes and serialize them.
1628     if (!element->hasAttributes())
1629         return attributesValue;
1630     for (const Attribute& attribute : element->attributesIterator()) {
1631         // Add attribute pair
1632         attributesValue->addItem(attribute.name().toString());
1633         attributesValue->addItem(attribute.value());
1634     }
1635     return attributesValue;
1636 }
1637
1638 Ref<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap)
1639 {
1640     auto children = JSON::ArrayOf<Inspector::Protocol::DOM::Node>::create();
1641     if (depth == 0) {
1642         // Special-case the only text child - pretend that container's children have been requested.
1643         Node* firstChild = container->firstChild();
1644         if (firstChild && firstChild->nodeType() == Node::TEXT_NODE && !firstChild->nextSibling()) {
1645             children->addItem(buildObjectForNode(firstChild, 0, nodesMap));
1646             m_childrenRequested.add(bind(container, nodesMap));
1647         }
1648         return children;
1649     }
1650
1651     Node* child = innerFirstChild(container);
1652     depth--;
1653     m_childrenRequested.add(bind(container, nodesMap));
1654
1655     while (child) {
1656         children->addItem(buildObjectForNode(child, depth, nodesMap));
1657         child = innerNextSibling(child);
1658     }
1659     return children;
1660 }
1661
1662 RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> InspectorDOMAgent::buildArrayForPseudoElements(const Element& element, NodeToIdMap* nodesMap)
1663 {
1664     PseudoElement* beforeElement = element.beforePseudoElement();
1665     PseudoElement* afterElement = element.afterPseudoElement();
1666     if (!beforeElement && !afterElement)
1667         return nullptr;
1668
1669     auto pseudoElements = JSON::ArrayOf<Inspector::Protocol::DOM::Node>::create();
1670     if (beforeElement)
1671         pseudoElements->addItem(buildObjectForNode(beforeElement, 0, nodesMap));
1672     if (afterElement)
1673         pseudoElements->addItem(buildObjectForNode(afterElement, 0, nodesMap));
1674     return pseudoElements;
1675 }
1676
1677 Ref<Inspector::Protocol::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, int identifier, EventTarget& eventTarget, const AtomicString& eventType, bool disabled, bool hasBreakpoint)
1678 {
1679     Ref<EventListener> eventListener = registeredEventListener.callback();
1680
1681     String handlerName;
1682     int lineNumber = 0;
1683     int columnNumber = 0;
1684     String scriptID;
1685     if (is<JSEventListener>(eventListener.get())) {
1686         auto& scriptListener = downcast<JSEventListener>(eventListener.get());
1687
1688         Document* document = nullptr;
1689         if (auto* scriptExecutionContext = eventTarget.scriptExecutionContext()) {
1690             if (is<Document>(scriptExecutionContext))
1691                 document = downcast<Document>(scriptExecutionContext);
1692         } else if (is<Node>(eventTarget))
1693             document = &downcast<Node>(eventTarget).document();
1694
1695         JSC::JSObject* handlerObject = nullptr;
1696         JSC::ExecState* exec = nullptr;
1697
1698         JSC::JSLockHolder lock(scriptListener.isolatedWorld().vm());
1699
1700         if (document) {
1701             handlerObject = scriptListener.jsFunction(*document);
1702             exec = execStateFromNode(scriptListener.isolatedWorld(), document);
1703         }
1704
1705         if (handlerObject && exec) {
1706             JSC::JSFunction* handlerFunction = JSC::jsDynamicCast<JSC::JSFunction*>(exec->vm(), handlerObject);
1707
1708             if (!handlerFunction) {
1709                 auto scope = DECLARE_CATCH_SCOPE(exec->vm());
1710
1711                 // If the handler is not actually a function, see if it implements the EventListener interface and use that.
1712                 auto handleEventValue = handlerObject->get(exec, JSC::Identifier::fromString(exec, "handleEvent"));
1713
1714                 if (UNLIKELY(scope.exception()))
1715                     scope.clearException();
1716
1717                 if (handleEventValue)
1718                     handlerFunction = JSC::jsDynamicCast<JSC::JSFunction*>(exec->vm(), handleEventValue);
1719             }
1720
1721             if (handlerFunction && !handlerFunction->isHostOrBuiltinFunction()) {
1722                 // If the listener implements the EventListener interface, use the class name instead of
1723                 // "handleEvent", unless it is a plain object.
1724                 if (handlerFunction != handlerObject)
1725                     handlerName = JSC::JSObject::calculatedClassName(handlerObject);
1726                 if (handlerName.isEmpty() || handlerName == "Object"_s)
1727                     handlerName = handlerFunction->calculatedDisplayName(exec->vm());
1728
1729                 if (auto executable = handlerFunction->jsExecutable()) {
1730                     lineNumber = executable->firstLine() - 1;
1731                     columnNumber = executable->startColumn() - 1;
1732                     scriptID = executable->sourceID() == JSC::SourceProvider::nullID ? emptyString() : String::number(executable->sourceID());
1733                 }
1734             }
1735         }
1736     }
1737
1738     auto value = Inspector::Protocol::DOM::EventListener::create()
1739         .setEventListenerId(identifier)
1740         .setType(eventType)
1741         .setUseCapture(registeredEventListener.useCapture())
1742         .setIsAttribute(eventListener->isAttribute())
1743         .release();
1744     if (is<Node>(eventTarget))
1745         value->setNodeId(pushNodePathToFrontend(&downcast<Node>(eventTarget)));
1746     else if (is<DOMWindow>(eventTarget))
1747         value->setOnWindow(true);
1748     if (!scriptID.isNull()) {
1749         auto location = Inspector::Protocol::Debugger::Location::create()
1750             .setScriptId(scriptID)
1751             .setLineNumber(lineNumber)
1752             .release();
1753         location->setColumnNumber(columnNumber);
1754         value->setLocation(WTFMove(location));
1755     }
1756     if (!handlerName.isEmpty())
1757         value->setHandlerName(handlerName);
1758     if (registeredEventListener.isPassive())
1759         value->setPassive(true);
1760     if (registeredEventListener.isOnce())
1761         value->setOnce(true);
1762     if (disabled)
1763         value->setDisabled(disabled);
1764     if (hasBreakpoint)
1765         value->setHasBreakpoint(hasBreakpoint);
1766     return value;
1767 }
1768
1769 void InspectorDOMAgent::processAccessibilityChildren(AccessibilityObject& axObject, JSON::ArrayOf<int>& childNodeIds)
1770 {
1771     const auto& children = axObject.children();
1772     if (!children.size())
1773         return;
1774
1775     for (const auto& childObject : children) {
1776         if (Node* childNode = childObject->node())
1777             childNodeIds.addItem(pushNodePathToFrontend(childNode));
1778         else
1779             processAccessibilityChildren(*childObject, childNodeIds);
1780     }
1781 }
1782     
1783 RefPtr<Inspector::Protocol::DOM::AccessibilityProperties> InspectorDOMAgent::buildObjectForAccessibilityProperties(Node* node)
1784 {
1785     ASSERT(node);
1786     if (!node)
1787         return nullptr;
1788
1789     if (!WebCore::AXObjectCache::accessibilityEnabled())
1790         WebCore::AXObjectCache::enableAccessibility();
1791
1792     Node* activeDescendantNode = nullptr;
1793     bool busy = false;
1794     auto checked = Inspector::Protocol::DOM::AccessibilityProperties::Checked::False;
1795     RefPtr<JSON::ArrayOf<int>> childNodeIds;
1796     RefPtr<JSON::ArrayOf<int>> controlledNodeIds;
1797     auto currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::False;
1798     bool exists = false;
1799     bool expanded = false;
1800     bool disabled = false;
1801     RefPtr<JSON::ArrayOf<int>> flowedNodeIds;
1802     bool focused = false;
1803     bool ignored = true;
1804     bool ignoredByDefault = false;
1805     auto invalid = Inspector::Protocol::DOM::AccessibilityProperties::Invalid::False;
1806     bool hidden = false;
1807     String label;
1808     bool liveRegionAtomic = false;
1809     RefPtr<JSON::ArrayOf<String>> liveRegionRelevant;
1810     auto liveRegionStatus = Inspector::Protocol::DOM::AccessibilityProperties::LiveRegionStatus::Off;
1811     Node* mouseEventNode = nullptr;
1812     RefPtr<JSON::ArrayOf<int>> ownedNodeIds;
1813     Node* parentNode = nullptr;
1814     bool pressed = false;
1815     bool readonly = false;
1816     bool required = false;
1817     String role;
1818     bool selected = false;
1819     RefPtr<JSON::ArrayOf<int>> selectedChildNodeIds;
1820     bool supportsChecked = false;
1821     bool supportsExpanded = false;
1822     bool supportsLiveRegion = false;
1823     bool supportsPressed = false;
1824     bool supportsRequired = false;
1825     bool supportsFocused = false;
1826     bool isPopupButton = false;
1827     int headingLevel = 0;
1828     unsigned hierarchicalLevel = 0;
1829     unsigned level = 0;
1830
1831     if (AXObjectCache* axObjectCache = node->document().axObjectCache()) {
1832         if (AccessibilityObject* axObject = axObjectCache->getOrCreate(node)) {
1833
1834             if (AccessibilityObject* activeDescendant = axObject->activeDescendant())
1835                 activeDescendantNode = activeDescendant->node();
1836
1837             // An AX object is "busy" if it or any ancestor has aria-busy="true" set.
1838             AccessibilityObject* current = axObject;
1839             while (!busy && current) {
1840                 busy = current->isBusy();
1841                 current = current->parentObject();
1842             }
1843
1844             supportsChecked = axObject->supportsChecked();
1845             if (supportsChecked) {
1846                 AccessibilityButtonState checkValue = axObject->checkboxOrRadioValue(); // Element using aria-checked.
1847                 if (checkValue == AccessibilityButtonState::On)
1848                     checked = Inspector::Protocol::DOM::AccessibilityProperties::Checked::True;
1849                 else if (checkValue == AccessibilityButtonState::Mixed)
1850                     checked = Inspector::Protocol::DOM::AccessibilityProperties::Checked::Mixed;
1851                 else if (axObject->isChecked()) // Native checkbox.
1852                     checked = Inspector::Protocol::DOM::AccessibilityProperties::Checked::True;
1853             }
1854             
1855             if (!axObject->children().isEmpty()) {
1856                 childNodeIds = JSON::ArrayOf<int>::create();
1857                 processAccessibilityChildren(*axObject, *childNodeIds);
1858             }
1859             
1860             Vector<Element*> controlledElements;
1861             axObject->elementsFromAttribute(controlledElements, aria_controlsAttr);
1862             if (controlledElements.size()) {
1863                 controlledNodeIds = JSON::ArrayOf<int>::create();
1864                 for (Element* controlledElement : controlledElements)
1865                     controlledNodeIds->addItem(pushNodePathToFrontend(controlledElement));
1866             }
1867             
1868             switch (axObject->currentState()) {
1869             case AccessibilityCurrentState::False:
1870                 currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::False;
1871                 break;
1872             case AccessibilityCurrentState::Page:
1873                 currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::Page;
1874                 break;
1875             case AccessibilityCurrentState::Step:
1876                 currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::Step;
1877                 break;
1878             case AccessibilityCurrentState::Location:
1879                 currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::Location;
1880                 break;
1881             case AccessibilityCurrentState::Date:
1882                 currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::Date;
1883                 break;
1884             case AccessibilityCurrentState::Time:
1885                 currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::Time;
1886                 break;
1887             case AccessibilityCurrentState::True:
1888                 currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::True;
1889                 break;
1890             }
1891
1892             disabled = !axObject->isEnabled();
1893             exists = true;
1894             
1895             supportsExpanded = axObject->supportsExpanded();
1896             if (supportsExpanded)
1897                 expanded = axObject->isExpanded();
1898
1899             Vector<Element*> flowedElements;
1900             axObject->elementsFromAttribute(flowedElements, aria_flowtoAttr);
1901             if (flowedElements.size()) {
1902                 flowedNodeIds = JSON::ArrayOf<int>::create();
1903                 for (Element* flowedElement : flowedElements)
1904                     flowedNodeIds->addItem(pushNodePathToFrontend(flowedElement));
1905             }
1906             
1907             if (is<Element>(*node)) {
1908                 supportsFocused = axObject->canSetFocusAttribute();
1909                 if (supportsFocused)
1910                     focused = axObject->isFocused();
1911             }
1912
1913             ignored = axObject->accessibilityIsIgnored();
1914             ignoredByDefault = axObject->accessibilityIsIgnoredByDefault();
1915             
1916             String invalidValue = axObject->invalidStatus();
1917             if (invalidValue == "false")
1918                 invalid = Inspector::Protocol::DOM::AccessibilityProperties::Invalid::False;
1919             else if (invalidValue == "grammar")
1920                 invalid = Inspector::Protocol::DOM::AccessibilityProperties::Invalid::Grammar;
1921             else if (invalidValue == "spelling")
1922                 invalid = Inspector::Protocol::DOM::AccessibilityProperties::Invalid::Spelling;
1923             else // Future versions of ARIA may allow additional truthy values. Ex. format, order, or size.
1924                 invalid = Inspector::Protocol::DOM::AccessibilityProperties::Invalid::True;
1925             
1926             if (axObject->isAXHidden() || axObject->isDOMHidden())
1927                 hidden = true;
1928             
1929             label = axObject->computedLabel();
1930
1931             if (axObject->supportsLiveRegion()) {
1932                 supportsLiveRegion = true;
1933                 liveRegionAtomic = axObject->liveRegionAtomic();
1934
1935                 String ariaRelevantAttrValue = axObject->liveRegionRelevant();
1936                 if (!ariaRelevantAttrValue.isEmpty()) {
1937                     // FIXME: Pass enum values rather than strings once unblocked. http://webkit.org/b/133711
1938                     String ariaRelevantAdditions = Inspector::Protocol::InspectorHelpers::getEnumConstantValue(Inspector::Protocol::DOM::LiveRegionRelevant::Additions);
1939                     String ariaRelevantRemovals = Inspector::Protocol::InspectorHelpers::getEnumConstantValue(Inspector::Protocol::DOM::LiveRegionRelevant::Removals);
1940                     String ariaRelevantText = Inspector::Protocol::InspectorHelpers::getEnumConstantValue(Inspector::Protocol::DOM::LiveRegionRelevant::Text);
1941                     liveRegionRelevant = JSON::ArrayOf<String>::create();
1942                     const SpaceSplitString& values = SpaceSplitString(ariaRelevantAttrValue, true);
1943                     // @aria-relevant="all" is exposed as ["additions","removals","text"], in order.
1944                     // This order is controlled in WebCore and expected in WebInspectorUI.
1945                     if (values.contains("all")) {
1946                         liveRegionRelevant->addItem(ariaRelevantAdditions);
1947                         liveRegionRelevant->addItem(ariaRelevantRemovals);
1948                         liveRegionRelevant->addItem(ariaRelevantText);
1949                     } else {
1950                         if (values.contains(ariaRelevantAdditions))
1951                             liveRegionRelevant->addItem(ariaRelevantAdditions);
1952                         if (values.contains(ariaRelevantRemovals))
1953                             liveRegionRelevant->addItem(ariaRelevantRemovals);
1954                         if (values.contains(ariaRelevantText))
1955                             liveRegionRelevant->addItem(ariaRelevantText);
1956                     }
1957                 }
1958
1959                 String ariaLive = axObject->liveRegionStatus();
1960                 if (ariaLive == "assertive")
1961                     liveRegionStatus = Inspector::Protocol::DOM::AccessibilityProperties::LiveRegionStatus::Assertive;
1962                 else if (ariaLive == "polite")
1963                     liveRegionStatus = Inspector::Protocol::DOM::AccessibilityProperties::LiveRegionStatus::Polite;
1964             }
1965
1966             if (is<AccessibilityNodeObject>(*axObject))
1967                 mouseEventNode = downcast<AccessibilityNodeObject>(*axObject).mouseButtonListener(MouseButtonListenerResultFilter::IncludeBodyElement);
1968
1969             if (axObject->supportsARIAOwns()) {
1970                 Vector<Element*> ownedElements;
1971                 axObject->elementsFromAttribute(ownedElements, aria_ownsAttr);
1972                 if (ownedElements.size()) {
1973                     ownedNodeIds = JSON::ArrayOf<int>::create();
1974                     for (Element* ownedElement : ownedElements)
1975                         ownedNodeIds->addItem(pushNodePathToFrontend(ownedElement));
1976                 }
1977             }
1978
1979             if (AccessibilityObject* parentObject = axObject->parentObjectUnignored())
1980                 parentNode = parentObject->node();
1981
1982             supportsPressed = axObject->pressedIsPresent();
1983             if (supportsPressed)
1984                 pressed = axObject->isPressed();
1985             
1986             if (axObject->isTextControl())
1987                 readonly = !axObject->canSetValueAttribute();
1988
1989             supportsRequired = axObject->supportsRequiredAttribute();
1990             if (supportsRequired)
1991                 required = axObject->isRequired();
1992             
1993             role = axObject->computedRoleString();
1994             selected = axObject->isSelected();
1995
1996             AccessibilityObject::AccessibilityChildrenVector selectedChildren;
1997             axObject->selectedChildren(selectedChildren);
1998             if (selectedChildren.size()) {
1999                 selectedChildNodeIds = JSON::ArrayOf<int>::create();
2000                 for (auto& selectedChildObject : selectedChildren) {
2001                     if (Node* selectedChildNode = selectedChildObject->node())
2002                         selectedChildNodeIds->addItem(pushNodePathToFrontend(selectedChildNode));
2003                 }
2004             }
2005             
2006             headingLevel = axObject->headingLevel();
2007             hierarchicalLevel = axObject->hierarchicalLevel();
2008             
2009             level = hierarchicalLevel ? hierarchicalLevel : headingLevel;
2010             isPopupButton = axObject->isPopUpButton() || axObject->hasPopup();
2011         }
2012     }
2013     
2014     Ref<Inspector::Protocol::DOM::AccessibilityProperties> value = Inspector::Protocol::DOM::AccessibilityProperties::create()
2015         .setExists(exists)
2016         .setLabel(label)
2017         .setRole(role)
2018         .setNodeId(pushNodePathToFrontend(node))
2019         .release();
2020
2021     if (exists) {
2022         if (activeDescendantNode)
2023             value->setActiveDescendantNodeId(pushNodePathToFrontend(activeDescendantNode));
2024         if (busy)
2025             value->setBusy(busy);
2026         if (supportsChecked)
2027             value->setChecked(checked);
2028         if (childNodeIds)
2029             value->setChildNodeIds(childNodeIds);
2030         if (controlledNodeIds)
2031             value->setControlledNodeIds(controlledNodeIds);
2032         if (currentState != Inspector::Protocol::DOM::AccessibilityProperties::Current::False)
2033             value->setCurrent(currentState);
2034         if (disabled)
2035             value->setDisabled(disabled);
2036         if (supportsExpanded)
2037             value->setExpanded(expanded);
2038         if (flowedNodeIds)
2039             value->setFlowedNodeIds(flowedNodeIds);
2040         if (supportsFocused)
2041             value->setFocused(focused);
2042         if (ignored)
2043             value->setIgnored(ignored);
2044         if (ignoredByDefault)
2045             value->setIgnoredByDefault(ignoredByDefault);
2046         if (invalid != Inspector::Protocol::DOM::AccessibilityProperties::Invalid::False)
2047             value->setInvalid(invalid);
2048         if (hidden)
2049             value->setHidden(hidden);
2050         if (supportsLiveRegion) {
2051             value->setLiveRegionAtomic(liveRegionAtomic);
2052             if (liveRegionRelevant->length())
2053                 value->setLiveRegionRelevant(liveRegionRelevant);
2054             value->setLiveRegionStatus(liveRegionStatus);
2055         }
2056         if (mouseEventNode)
2057             value->setMouseEventNodeId(pushNodePathToFrontend(mouseEventNode));
2058         if (ownedNodeIds)
2059             value->setOwnedNodeIds(ownedNodeIds);
2060         if (parentNode)
2061             value->setParentNodeId(pushNodePathToFrontend(parentNode));
2062         if (supportsPressed)
2063             value->setPressed(pressed);
2064         if (readonly)
2065             value->setReadonly(readonly);
2066         if (supportsRequired)
2067             value->setRequired(required);
2068         if (selected)
2069             value->setSelected(selected);
2070         if (selectedChildNodeIds)
2071             value->setSelectedChildNodeIds(selectedChildNodeIds);
2072         
2073         // H1 -- H6 always have a headingLevel property that can be complimented by a hierarchicalLevel
2074         // property when aria-level is set on the element, in which case we want to remain calling
2075         // this value the "Heading Level" in the inspector.
2076         // Also, we do not want it to say Hierarchy Level: 0
2077         if (headingLevel)
2078             value->setHeadingLevel(level);
2079         else if (level)
2080             value->setHierarchyLevel(level);
2081         if (isPopupButton)
2082             value->setIsPopUpButton(isPopupButton);
2083     }
2084
2085     return value;
2086 }
2087
2088 static bool containsOnlyHTMLWhitespace(Node* node)
2089 {
2090     // FIXME: Respect ignoreWhitespace setting from inspector front end?
2091     return is<Text>(node) && downcast<Text>(*node).data().isAllSpecialCharacters<isHTMLSpace>();
2092 }
2093
2094 Node* InspectorDOMAgent::innerFirstChild(Node* node)
2095 {
2096     node = node->firstChild();
2097     while (containsOnlyHTMLWhitespace(node))
2098         node = node->nextSibling();
2099     return node;
2100 }
2101
2102 Node* InspectorDOMAgent::innerNextSibling(Node* node)
2103 {
2104     do {
2105         node = node->nextSibling();
2106     } while (containsOnlyHTMLWhitespace(node));
2107     return node;
2108 }
2109
2110 Node* InspectorDOMAgent::innerPreviousSibling(Node* node)
2111 {
2112     do {
2113         node = node->previousSibling();
2114     } while (containsOnlyHTMLWhitespace(node));
2115     return node;
2116 }
2117
2118 unsigned InspectorDOMAgent::innerChildNodeCount(Node* node)
2119 {
2120     unsigned count = 0;
2121     for (Node* child = innerFirstChild(node); child; child = innerNextSibling(child))
2122         ++count;
2123     return count;
2124 }
2125
2126 Node* InspectorDOMAgent::innerParentNode(Node* node)
2127 {
2128     ASSERT(node);
2129     if (is<Document>(*node))
2130         return downcast<Document>(*node).ownerElement();
2131     if (is<ShadowRoot>(*node))
2132         return downcast<ShadowRoot>(*node).host();
2133     return node->parentNode();
2134 }
2135
2136 void InspectorDOMAgent::didCommitLoad(Document* document)
2137 {
2138     RefPtr<Element> frameOwner = document->ownerElement();
2139     if (!frameOwner)
2140         return;
2141
2142     int frameOwnerId = m_documentNodeToIdMap.get(frameOwner);
2143     if (!frameOwnerId)
2144         return;
2145
2146     // Re-add frame owner element together with its new children.
2147     int parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner.get()));
2148     m_frontendDispatcher->childNodeRemoved(parentId, frameOwnerId);
2149     unbind(frameOwner.get(), &m_documentNodeToIdMap);
2150
2151     Ref<Inspector::Protocol::DOM::Node> value = buildObjectForNode(frameOwner.get(), 0, &m_documentNodeToIdMap);
2152     Node* previousSibling = innerPreviousSibling(frameOwner.get());
2153     int prevId = previousSibling ? m_documentNodeToIdMap.get(previousSibling) : 0;
2154     m_frontendDispatcher->childNodeInserted(parentId, prevId, WTFMove(value));
2155 }
2156
2157 int InspectorDOMAgent::identifierForNode(Node& node)
2158 {
2159     return pushNodePathToFrontend(&node);
2160 }
2161
2162 void InspectorDOMAgent::addEventListenersToNode(Node& node)
2163 {
2164 #if ENABLE(VIDEO)
2165     auto callback = EventFiredCallback::create(*this);
2166
2167     auto createEventListener = [&] (const AtomicString& eventName) {
2168         node.addEventListener(eventName, callback.copyRef(), false);
2169     };
2170
2171 #if ENABLE(FULLSCREEN_API)
2172     if (is<Document>(node) || is<HTMLMediaElement>(node))
2173         createEventListener(eventNames().webkitfullscreenchangeEvent);
2174 #endif // ENABLE(FULLSCREEN_API)
2175
2176     if (is<HTMLMediaElement>(node)) {
2177         createEventListener(eventNames().abortEvent);
2178         createEventListener(eventNames().canplayEvent);
2179         createEventListener(eventNames().canplaythroughEvent);
2180         createEventListener(eventNames().emptiedEvent);
2181         createEventListener(eventNames().endedEvent);
2182         createEventListener(eventNames().loadeddataEvent);
2183         createEventListener(eventNames().loadedmetadataEvent);
2184         createEventListener(eventNames().loadstartEvent);
2185         createEventListener(eventNames().pauseEvent);
2186         createEventListener(eventNames().playEvent);
2187         createEventListener(eventNames().playingEvent);
2188         createEventListener(eventNames().seekedEvent);
2189         createEventListener(eventNames().seekingEvent);
2190         createEventListener(eventNames().stalledEvent);
2191         createEventListener(eventNames().suspendEvent);
2192         createEventListener(eventNames().waitingEvent);
2193
2194         if (!m_mediaMetricsTimer.isActive())
2195             m_mediaMetricsTimer.start(0_s, 1_s / 15.);
2196     }
2197 #else
2198     UNUSED_PARAM(node);
2199 #endif // ENABLE(VIDEO)
2200 }
2201
2202 void InspectorDOMAgent::didInsertDOMNode(Node& node)
2203 {
2204     if (containsOnlyHTMLWhitespace(&node))
2205         return;
2206
2207     // We could be attaching existing subtree. Forget the bindings.
2208     unbind(&node, &m_documentNodeToIdMap);
2209
2210     ContainerNode* parent = node.parentNode();
2211     if (!parent)
2212         return;
2213
2214     int parentId = m_documentNodeToIdMap.get(parent);
2215     // Return if parent is not mapped yet.
2216     if (!parentId)
2217         return;
2218
2219     if (!m_childrenRequested.contains(parentId)) {
2220         // No children are mapped yet -> only notify on changes of hasChildren.
2221         m_frontendDispatcher->childNodeCountUpdated(parentId, innerChildNodeCount(parent));
2222     } else {
2223         // Children have been requested -> return value of a new child.
2224         Node* prevSibling = innerPreviousSibling(&node);
2225         int prevId = prevSibling ? m_documentNodeToIdMap.get(prevSibling) : 0;
2226         Ref<Inspector::Protocol::DOM::Node> value = buildObjectForNode(&node, 0, &m_documentNodeToIdMap);
2227         m_frontendDispatcher->childNodeInserted(parentId, prevId, WTFMove(value));
2228     }
2229 }
2230
2231 void InspectorDOMAgent::didRemoveDOMNode(Node& node)
2232 {
2233     if (containsOnlyHTMLWhitespace(&node))
2234         return;
2235
2236     ContainerNode* parent = node.parentNode();
2237
2238     // If parent is not mapped yet -> ignore the event.
2239     if (!m_documentNodeToIdMap.contains(parent))
2240         return;
2241
2242     int parentId = m_documentNodeToIdMap.get(parent);
2243
2244     if (!m_childrenRequested.contains(parentId)) {
2245         // No children are mapped yet -> only notify on changes of hasChildren.
2246         if (innerChildNodeCount(parent) == 1)
2247             m_frontendDispatcher->childNodeCountUpdated(parentId, 0);
2248     } else
2249         m_frontendDispatcher->childNodeRemoved(parentId, m_documentNodeToIdMap.get(&node));
2250     unbind(&node, &m_documentNodeToIdMap);
2251 }
2252
2253 void InspectorDOMAgent::willModifyDOMAttr(Element&, const AtomicString& oldValue, const AtomicString& newValue)
2254 {
2255     m_suppressAttributeModifiedEvent = (oldValue == newValue);
2256 }
2257
2258 void InspectorDOMAgent::didModifyDOMAttr(Element& element, const AtomicString& name, const AtomicString& value)
2259 {
2260     bool shouldSuppressEvent = m_suppressAttributeModifiedEvent;
2261     m_suppressAttributeModifiedEvent = false;
2262     if (shouldSuppressEvent)
2263         return;
2264
2265     int id = boundNodeId(&element);
2266     if (!id)
2267         return;
2268
2269     if (auto* cssAgent = m_instrumentingAgents.inspectorCSSAgent())
2270         cssAgent->didModifyDOMAttr(element);
2271
2272     m_frontendDispatcher->attributeModified(id, name, value);
2273 }
2274
2275 void InspectorDOMAgent::didRemoveDOMAttr(Element& element, const AtomicString& name)
2276 {
2277     int id = boundNodeId(&element);
2278     if (!id)
2279         return;
2280
2281     if (auto* cssAgent = m_instrumentingAgents.inspectorCSSAgent())
2282         cssAgent->didModifyDOMAttr(element);
2283
2284     m_frontendDispatcher->attributeRemoved(id, name);
2285 }
2286
2287 void InspectorDOMAgent::styleAttributeInvalidated(const Vector<Element*>& elements)
2288 {
2289     auto nodeIds = JSON::ArrayOf<int>::create();
2290     for (auto& element : elements) {
2291         int id = boundNodeId(element);
2292         if (!id)
2293             continue;
2294
2295         if (auto* cssAgent = m_instrumentingAgents.inspectorCSSAgent())
2296             cssAgent->didModifyDOMAttr(*element);
2297
2298         nodeIds->addItem(id);
2299     }
2300     m_frontendDispatcher->inlineStyleInvalidated(WTFMove(nodeIds));
2301 }
2302
2303 void InspectorDOMAgent::characterDataModified(CharacterData& characterData)
2304 {
2305     int id = m_documentNodeToIdMap.get(&characterData);
2306     if (!id) {
2307         // Push text node if it is being created.
2308         didInsertDOMNode(characterData);
2309         return;
2310     }
2311     m_frontendDispatcher->characterDataModified(id, characterData.data());
2312 }
2313
2314 void InspectorDOMAgent::didInvalidateStyleAttr(Node& node)
2315 {
2316     int id = m_documentNodeToIdMap.get(&node);
2317     if (!id)
2318         return;
2319
2320     if (!m_revalidateStyleAttrTask)
2321         m_revalidateStyleAttrTask = std::make_unique<RevalidateStyleAttributeTask>(this);
2322     m_revalidateStyleAttrTask->scheduleFor(downcast<Element>(&node));
2323 }
2324
2325 void InspectorDOMAgent::didPushShadowRoot(Element& host, ShadowRoot& root)
2326 {
2327     int hostId = m_documentNodeToIdMap.get(&host);
2328     if (hostId)
2329         m_frontendDispatcher->shadowRootPushed(hostId, buildObjectForNode(&root, 0, &m_documentNodeToIdMap));
2330 }
2331
2332 void InspectorDOMAgent::willPopShadowRoot(Element& host, ShadowRoot& root)
2333 {
2334     int hostId = m_documentNodeToIdMap.get(&host);
2335     int rootId = m_documentNodeToIdMap.get(&root);
2336     if (hostId && rootId)
2337         m_frontendDispatcher->shadowRootPopped(hostId, rootId);
2338 }
2339
2340 void InspectorDOMAgent::didChangeCustomElementState(Element& element)
2341 {
2342     int elementId = m_documentNodeToIdMap.get(&element);
2343     if (!elementId)
2344         return;
2345
2346     m_frontendDispatcher->customElementStateChanged(elementId, customElementState(element));
2347 }
2348
2349 void InspectorDOMAgent::frameDocumentUpdated(Frame& frame)
2350 {
2351     Document* document = frame.document();
2352     if (!document)
2353         return;
2354
2355     if (!frame.isMainFrame())
2356         return;
2357
2358     // Only update the main frame document, nested frame document updates are not required
2359     // (will be handled by didCommitLoad()).
2360     setDocument(document);
2361 }
2362
2363 void InspectorDOMAgent::pseudoElementCreated(PseudoElement& pseudoElement)
2364 {
2365     Element* parent = pseudoElement.hostElement();
2366     if (!parent)
2367         return;
2368
2369     int parentId = m_documentNodeToIdMap.get(parent);
2370     if (!parentId)
2371         return;
2372
2373     pushChildNodesToFrontend(parentId, 1);
2374     m_frontendDispatcher->pseudoElementAdded(parentId, buildObjectForNode(&pseudoElement, 0, &m_documentNodeToIdMap));
2375 }
2376
2377 void InspectorDOMAgent::pseudoElementDestroyed(PseudoElement& pseudoElement)
2378 {
2379     int pseudoElementId = m_documentNodeToIdMap.get(&pseudoElement);
2380     if (!pseudoElementId)
2381         return;
2382
2383     // If a PseudoElement is bound, its parent element must have been bound.
2384     Element* parent = pseudoElement.hostElement();
2385     ASSERT(parent);
2386     int parentId = m_documentNodeToIdMap.get(parent);
2387     ASSERT(parentId);
2388
2389     unbind(&pseudoElement, &m_documentNodeToIdMap);
2390     m_frontendDispatcher->pseudoElementRemoved(parentId, pseudoElementId);
2391 }
2392
2393 void InspectorDOMAgent::didAddEventListener(EventTarget& target)
2394 {
2395     if (!is<Node>(target))
2396         return;
2397
2398     auto& node = downcast<Node>(target);
2399     if (!node.contains(m_inspectedNode.get()))
2400         return;
2401
2402     int nodeId = boundNodeId(&node);
2403     if (!nodeId)
2404         return;
2405
2406     if (m_suppressEventListenerChangedEvent)
2407         return;
2408
2409     m_suppressEventListenerChangedEvent = true;
2410
2411     m_frontendDispatcher->didAddEventListener(nodeId);
2412 }
2413
2414 void InspectorDOMAgent::willRemoveEventListener(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture)
2415 {
2416     if (!is<Node>(target))
2417         return;
2418
2419     auto& node = downcast<Node>(target);
2420     if (!node.contains(m_inspectedNode.get()))
2421         return;
2422
2423     int nodeId = boundNodeId(&node);
2424     if (!nodeId)
2425         return;
2426
2427     bool listenerExists = false;
2428     for (auto& item : node.eventListeners(eventType)) {
2429         if (item->callback() == listener && item->useCapture() == capture) {
2430             listenerExists = true;
2431             break;
2432         }
2433     }
2434
2435     if (!listenerExists)
2436         return;
2437
2438     m_eventListenerEntries.removeIf([&] (auto& entry) {
2439         return entry.value.matches(target, eventType, listener, capture);
2440     });
2441
2442     if (m_suppressEventListenerChangedEvent)
2443         return;
2444
2445     m_suppressEventListenerChangedEvent = true;
2446
2447     m_frontendDispatcher->willRemoveEventListener(nodeId);
2448 }
2449
2450 bool InspectorDOMAgent::isEventListenerDisabled(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture)
2451 {
2452     for (auto& inspectorEventListener : m_eventListenerEntries.values()) {
2453         if (inspectorEventListener.matches(target, eventType, listener, capture))
2454             return inspectorEventListener.disabled;
2455     }
2456     return false;
2457 }
2458
2459 void InspectorDOMAgent::eventDidResetAfterDispatch(const Event& event)
2460 {
2461     m_dispatchedEvents.remove(&event);
2462 }
2463
2464 bool InspectorDOMAgent::hasBreakpointForEventListener(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture)
2465 {
2466     for (auto& inspectorEventListener : m_eventListenerEntries.values()) {
2467         if (inspectorEventListener.matches(target, eventType, listener, capture))
2468             return inspectorEventListener.hasBreakpoint;
2469     }
2470     return false;
2471 }
2472
2473 int InspectorDOMAgent::idForEventListener(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture)
2474 {
2475     for (auto& inspectorEventListener : m_eventListenerEntries.values()) {
2476         if (inspectorEventListener.matches(target, eventType, listener, capture))
2477             return inspectorEventListener.identifier;
2478     }
2479     return 0;
2480 }
2481
2482 #if ENABLE(VIDEO)
2483 void InspectorDOMAgent::mediaMetricsTimerFired()
2484 {
2485     // FIXME: remove metrics information for any media element when it's destroyed
2486
2487     if (HTMLMediaElement::allMediaElements().isEmpty()) {
2488         if (m_mediaMetricsTimer.isActive())
2489             m_mediaMetricsTimer.stop();
2490         m_mediaMetrics.clear();
2491         return;
2492     }
2493
2494     for (auto* mediaElement : HTMLMediaElement::allMediaElements()) {
2495         if (!is<HTMLVideoElement>(mediaElement) || !mediaElement->isPlaying())
2496             continue;
2497
2498         auto videoPlaybackQuality = mediaElement->getVideoPlaybackQuality();
2499         unsigned displayCompositedVideoFrames = videoPlaybackQuality->displayCompositedVideoFrames();
2500
2501         auto iterator = m_mediaMetrics.find(mediaElement);
2502         if (iterator == m_mediaMetrics.end()) {
2503             m_mediaMetrics.set(mediaElement, MediaMetrics(displayCompositedVideoFrames));
2504             continue;
2505         }
2506
2507         bool isLowPower = (displayCompositedVideoFrames - iterator->value.displayCompositedFrames) > 0;
2508         if (iterator->value.isLowPower != isLowPower) {
2509             iterator->value.isLowPower = isLowPower;
2510
2511             int nodeId = pushNodePathToFrontend(mediaElement);
2512             if (nodeId) {
2513                 auto timestamp = m_environment.executionStopwatch()->elapsedTime().seconds();
2514                 m_frontendDispatcher->videoLowPowerChanged(nodeId, timestamp, iterator->value.isLowPower);
2515             }
2516         }
2517
2518         iterator->value.displayCompositedFrames = displayCompositedVideoFrames;
2519     }
2520
2521     m_mediaMetrics.removeIf([&] (auto& entry) {
2522         return !HTMLMediaElement::allMediaElements().contains(entry.key);
2523     });
2524 }
2525 #endif
2526
2527 Node* InspectorDOMAgent::nodeForPath(const String& path)
2528 {
2529     // The path is of form "1,HTML,2,BODY,1,DIV"
2530     if (!m_document)
2531         return nullptr;
2532
2533     Node* node = m_document.get();
2534     Vector<String> pathTokens = path.split(',');
2535     if (!pathTokens.size())
2536         return nullptr;
2537
2538     for (size_t i = 0; i < pathTokens.size() - 1; i += 2) {
2539         bool success = true;
2540         unsigned childNumber = pathTokens[i].toUInt(&success);
2541         if (!success)
2542             return nullptr;
2543
2544         Node* child;
2545         if (is<HTMLFrameOwnerElement>(*node)) {
2546             ASSERT(!childNumber);
2547             auto& frameOwner = downcast<HTMLFrameOwnerElement>(*node);
2548             child = frameOwner.contentDocument();
2549         } else {
2550             if (childNumber >= innerChildNodeCount(node))
2551                 return nullptr;
2552
2553             child = innerFirstChild(node);
2554             for (size_t j = 0; child && j < childNumber; ++j)
2555                 child = innerNextSibling(child);
2556         }
2557
2558         const auto& childName = pathTokens[i + 1];
2559         if (!child || child->nodeName() != childName)
2560             return nullptr;
2561         node = child;
2562     }
2563     return node;
2564 }
2565
2566 Node* InspectorDOMAgent::nodeForObjectId(const String& objectId)
2567 {
2568     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(objectId);
2569     if (injectedScript.hasNoValue())
2570         return nullptr;
2571
2572     return scriptValueAsNode(injectedScript.findObjectById(objectId));
2573 }
2574
2575 void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString& errorString, const String& path, int* nodeId)
2576 {
2577     if (Node* node = nodeForPath(path))
2578         *nodeId = pushNodePathToFrontend(node);
2579     else
2580         errorString = "No node with given path found"_s;
2581 }
2582
2583 RefPtr<Inspector::Protocol::Runtime::RemoteObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup)
2584 {
2585     auto* frame = node->document().frame();
2586     if (!frame)
2587         return nullptr;
2588
2589     auto& state = *mainWorldExecState(frame);
2590     auto injectedScript = m_injectedScriptManager.injectedScriptFor(&state);
2591     if (injectedScript.hasNoValue())
2592         return nullptr;
2593
2594     return injectedScript.wrapObject(nodeAsScriptValue(state, node), objectGroup);
2595 }
2596
2597 Node* InspectorDOMAgent::scriptValueAsNode(JSC::JSValue value)
2598 {
2599     if (!value || !value.isObject())
2600         return nullptr;
2601     return JSNode::toWrapped(*value.getObject()->vm(), value.getObject());
2602 }
2603
2604 JSC::JSValue InspectorDOMAgent::nodeAsScriptValue(JSC::ExecState& state, Node* node)
2605 {
2606     JSC::JSLockHolder lock(&state);
2607     return toJS(&state, deprecatedGlobalObjectForPrototype(&state), BindingSecurity::checkSecurityForNode(state, node));
2608 }
2609
2610 } // namespace WebCore