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