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