diff options
Diffstat (limited to 'Source/WebCore/inspector/InspectorDOMAgent.cpp')
-rw-r--r-- | Source/WebCore/inspector/InspectorDOMAgent.cpp | 1364 |
1 files changed, 934 insertions, 430 deletions
diff --git a/Source/WebCore/inspector/InspectorDOMAgent.cpp b/Source/WebCore/inspector/InspectorDOMAgent.cpp index f24caaa74..69331f427 100644 --- a/Source/WebCore/inspector/InspectorDOMAgent.cpp +++ b/Source/WebCore/inspector/InspectorDOMAgent.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2015-2016 Apple Inc. All rights reserved. * Copyright (C) 2011 Google Inc. All rights reserved. * Copyright (C) 2009 Joseph Pecoraro * @@ -12,7 +12,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -29,11 +29,10 @@ */ #include "config.h" - -#if ENABLE(INSPECTOR) - #include "InspectorDOMAgent.h" +#include "AXObjectCache.h" +#include "AccessibilityNodeObject.h" #include "Attr.h" #include "CSSComputedStyleDeclaration.h" #include "CSSPropertyNames.h" @@ -50,27 +49,28 @@ #include "DOMPatchSupport.h" #include "DOMWindow.h" #include "Document.h" -#include "DocumentFragment.h" #include "DocumentType.h" #include "Element.h" #include "Event.h" #include "EventListener.h" -#include "EventNames.h" -#include "EventTarget.h" +#include "ExceptionCodeDescription.h" #include "FrameTree.h" #include "HTMLElement.h" #include "HTMLFrameOwnerElement.h" #include "HTMLNames.h" +#include "HTMLScriptElement.h" +#include "HTMLStyleElement.h" #include "HTMLTemplateElement.h" #include "HitTestResult.h" -#include "IdentifiersFactory.h" +#include "InspectorClient.h" +#include "InspectorController.h" #include "InspectorHistory.h" #include "InspectorNodeFinder.h" #include "InspectorOverlay.h" #include "InspectorPageAgent.h" -#include "InspectorWebFrontendDispatchers.h" #include "InstrumentingAgents.h" #include "IntRect.h" +#include "JSDOMBindingSecurity.h" #include "JSEventListener.h" #include "JSNode.h" #include "MainFrame.h" @@ -79,23 +79,26 @@ #include "NodeList.h" #include "Page.h" #include "Pasteboard.h" +#include "PseudoElement.h" #include "RenderStyle.h" #include "RenderStyleConstants.h" #include "ScriptState.h" -#include "Settings.h" #include "ShadowRoot.h" #include "StyleProperties.h" #include "StyleResolver.h" #include "StyleSheetList.h" #include "Text.h" +#include "TextNodeTraversal.h" +#include "Timer.h" #include "XPathResult.h" #include "htmlediting.h" #include "markup.h" +#include <inspector/IdentifiersFactory.h> #include <inspector/InjectedScript.h> #include <inspector/InjectedScriptManager.h> -#include <wtf/HashSet.h> -#include <wtf/OwnPtr.h> -#include <wtf/Vector.h> +#include <pal/crypto/CryptoDigest.h> +#include <runtime/JSCInlines.h> +#include <wtf/text/Base64.h> #include <wtf/text/CString.h> #include <wtf/text/WTFString.h> @@ -108,23 +111,19 @@ using namespace HTMLNames; static const size_t maxTextSize = 10000; static const UChar ellipsisUChar[] = { 0x2026, 0 }; -static Color parseColor(const RefPtr<InspectorObject>* colorObject) +static Color parseColor(const InspectorObject* colorObject) { - if (!colorObject || !(*colorObject)) + if (!colorObject) return Color::transparent; - int r; - int g; - int b; - bool success = (*colorObject)->getNumber("r", &r); - success |= (*colorObject)->getNumber("g", &g); - success |= (*colorObject)->getNumber("b", &b); - if (!success) + int r = 0; + int g = 0; + int b = 0; + if (!colorObject->getInteger("r", r) || !colorObject->getInteger("g", g) || !colorObject->getInteger("b", b)) return Color::transparent; - double a; - success = (*colorObject)->getNumber("a", &a); - if (!success) + double a = 1.0; + if (!colorObject->getDouble("a", a)) return Color(r, g, b); // Clamp alpha to the [0..1] range. @@ -136,22 +135,22 @@ static Color parseColor(const RefPtr<InspectorObject>* colorObject) return Color(r, g, b, static_cast<int>(a * 255)); } -static Color parseConfigColor(const String& fieldName, InspectorObject* configObject) +static Color parseConfigColor(const String& fieldName, const InspectorObject* configObject) { - const RefPtr<InspectorObject> colorObject = configObject->getObject(fieldName); - return parseColor(&colorObject); + RefPtr<InspectorObject> colorObject; + configObject->getObject(fieldName, colorObject); + + return parseColor(colorObject.get()); } -static bool parseQuad(const RefPtr<InspectorArray>& quadArray, FloatQuad* quad) +static bool parseQuad(const InspectorArray& quadArray, FloatQuad* quad) { - if (!quadArray) - return false; const size_t coordinatesInQuad = 8; double coordinates[coordinatesInQuad]; - if (quadArray->length() != coordinatesInQuad) + if (quadArray.length() != coordinatesInQuad) return false; for (size_t i = 0; i < coordinatesInQuad; ++i) { - if (!quadArray->get(i)->asNumber(coordinates + i)) + if (!quadArray.get(i)->asDouble(*(coordinates + i))) return false; } quad->setP1(FloatPoint(coordinates[0], coordinates[1])); @@ -168,17 +167,17 @@ public: RevalidateStyleAttributeTask(InspectorDOMAgent*); void scheduleFor(Element*); void reset() { m_timer.stop(); } - void timerFired(Timer<RevalidateStyleAttributeTask>&); + void timerFired(); private: InspectorDOMAgent* m_domAgent; - Timer<RevalidateStyleAttributeTask> m_timer; + Timer m_timer; HashSet<RefPtr<Element>> m_elements; }; RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent) : m_domAgent(domAgent) - , m_timer(this, &RevalidateStyleAttributeTask::timerFired) + , m_timer(*this, &RevalidateStyleAttributeTask::timerFired) { } @@ -189,37 +188,38 @@ void RevalidateStyleAttributeTask::scheduleFor(Element* element) m_timer.startOneShot(0); } -void RevalidateStyleAttributeTask::timerFired(Timer<RevalidateStyleAttributeTask>&) +void RevalidateStyleAttributeTask::timerFired() { // The timer is stopped on m_domAgent destruction, so this method will never be called after m_domAgent has been destroyed. Vector<Element*> elements; - for (HashSet<RefPtr<Element>>::iterator it = m_elements.begin(), end = m_elements.end(); it != end; ++it) - elements.append(it->get()); + for (auto& element : m_elements) + elements.append(element.get()); m_domAgent->styleAttributeInvalidated(elements); m_elements.clear(); } -String InspectorDOMAgent::toErrorString(const ExceptionCode& ec) +String InspectorDOMAgent::toErrorString(ExceptionCode ec) { if (ec) { ExceptionCodeDescription description(ec); return description.name; } - return ""; + return emptyString(); } -InspectorDOMAgent::InspectorDOMAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InjectedScriptManager* injectedScriptManager, InspectorOverlay* overlay) - : InspectorAgentBase(ASCIILiteral("DOM"), instrumentingAgents) +String InspectorDOMAgent::toErrorString(Exception&& exception) +{ + return ExceptionCodeDescription { exception.code() }.name; +} + +InspectorDOMAgent::InspectorDOMAgent(WebAgentContext& context, InspectorPageAgent* pageAgent, InspectorOverlay* overlay) + : InspectorAgentBase(ASCIILiteral("DOM"), context) + , m_injectedScriptManager(context.injectedScriptManager) + , m_frontendDispatcher(std::make_unique<Inspector::DOMFrontendDispatcher>(context.frontendRouter)) + , m_backendDispatcher(Inspector::DOMBackendDispatcher::create(context.backendDispatcher, this)) , m_pageAgent(pageAgent) - , m_injectedScriptManager(injectedScriptManager) , m_overlay(overlay) - , m_domListener(0) - , m_lastNodeId(1) - , m_lastBackendNodeId(-1) - , m_searchingForNode(false) - , m_suppressAttributeModifiedEvent(false) - , m_documentRequested(false) { } @@ -229,34 +229,29 @@ InspectorDOMAgent::~InspectorDOMAgent() ASSERT(!m_searchingForNode); } -void InspectorDOMAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher) +void InspectorDOMAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) { - m_frontendDispatcher = std::make_unique<InspectorDOMFrontendDispatcher>(frontendChannel); - m_backendDispatcher = InspectorDOMBackendDispatcher::create(backendDispatcher, this); - - m_history = adoptPtr(new InspectorHistory()); - m_domEditor = adoptPtr(new DOMEditor(m_history.get())); + m_history = std::make_unique<InspectorHistory>(); + m_domEditor = std::make_unique<DOMEditor>(*m_history); - m_instrumentingAgents->setInspectorDOMAgent(this); - m_document = m_pageAgent->mainFrame()->document(); + m_instrumentingAgents.setInspectorDOMAgent(this); + m_document = m_pageAgent->mainFrame().document(); if (m_nodeToFocus) focusNode(); } -void InspectorDOMAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason) +void InspectorDOMAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason) { - m_frontendDispatcher = nullptr; - m_backendDispatcher.clear(); - - m_history.clear(); - m_domEditor.clear(); + m_history.reset(); + m_domEditor.reset(); + m_mousedOverNode = nullptr; - ErrorString error; - setSearchingForNode(&error, false, 0); - hideHighlight(&error); + ErrorString unused; + setSearchingForNode(unused, false, nullptr); + hideHighlight(unused); - m_instrumentingAgents->setInspectorDOMAgent(0); + m_instrumentingAgents.setInspectorDOMAgent(nullptr); m_documentRequested = false; reset(); } @@ -281,7 +276,7 @@ void InspectorDOMAgent::reset() discardBindings(); if (m_revalidateStyleAttrTask) m_revalidateStyleAttrTask->reset(); - m_document = 0; + m_document = nullptr; } void InspectorDOMAgent::setDOMListener(DOMListener* listener) @@ -289,20 +284,20 @@ void InspectorDOMAgent::setDOMListener(DOMListener* listener) m_domListener = listener; } -void InspectorDOMAgent::setDocument(Document* doc) +void InspectorDOMAgent::setDocument(Document* document) { - if (doc == m_document.get()) + if (document == m_document.get()) return; reset(); - m_document = doc; + m_document = document; if (!m_documentRequested) return; - // Immediately communicate 0 document or document that has finished loading. - if (!doc || !doc->parsing()) + // Immediately communicate null document or document that has finished loading. + if (!document || !document->parsing()) m_frontendDispatcher->documentUpdated(); } @@ -333,21 +328,23 @@ void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap) if (node->isFrameOwnerElement()) { const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>(node); - Document* contentDocument = frameOwner->contentDocument(); - if (m_domListener) - m_domListener->didRemoveDocument(contentDocument); - if (contentDocument) + if (Document* contentDocument = frameOwner->contentDocument()) unbind(contentDocument, nodesMap); } - if (node->isElementNode()) { - if (ShadowRoot* root = toElement(node)->shadowRoot()) + if (is<Element>(*node)) { + Element& element = downcast<Element>(*node); + if (ShadowRoot* root = element.shadowRoot()) unbind(root, nodesMap); + if (PseudoElement* beforeElement = element.beforePseudoElement()) + unbind(beforeElement, nodesMap); + if (PseudoElement* afterElement = element.afterPseudoElement()) + unbind(afterElement, nodesMap); } nodesMap->remove(node); if (m_domListener) - m_domListener->didRemoveDOMNode(node); + m_domListener->didRemoveDOMNode(*node, id); bool childrenRequested = m_childrenRequested.contains(id); if (childrenRequested) { @@ -361,70 +358,78 @@ void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap) } } -Node* InspectorDOMAgent::assertNode(ErrorString* errorString, int nodeId) +Node* InspectorDOMAgent::assertNode(ErrorString& errorString, int nodeId) { Node* node = nodeForId(nodeId); if (!node) { - *errorString = "Could not find node with given id"; + errorString = ASCIILiteral("Could not find node with given id"); return nullptr; } return node; } -Document* InspectorDOMAgent::assertDocument(ErrorString* errorString, int nodeId) +Document* InspectorDOMAgent::assertDocument(ErrorString& errorString, int nodeId) { Node* node = assertNode(errorString, nodeId); if (!node) return nullptr; - if (!node->isDocumentNode()) { - *errorString = "Document is not available"; + if (!is<Document>(*node)) { + errorString = ASCIILiteral("Document is not available"); return nullptr; } - return toDocument(node); + return downcast<Document>(node); } -Element* InspectorDOMAgent::assertElement(ErrorString* errorString, int nodeId) +Element* InspectorDOMAgent::assertElement(ErrorString& errorString, int nodeId) { Node* node = assertNode(errorString, nodeId); if (!node) return nullptr; - if (!node->isElementNode()) { - *errorString = "Node is not an Element"; + if (!is<Element>(*node)) { + errorString = ASCIILiteral("Node is not an Element"); return nullptr; } - return toElement(node); + return downcast<Element>(node); } -Node* InspectorDOMAgent::assertEditableNode(ErrorString* errorString, int nodeId) +Node* InspectorDOMAgent::assertEditableNode(ErrorString& errorString, int nodeId) { Node* node = assertNode(errorString, nodeId); if (!node) return nullptr; - if (node->isInShadowTree()) { - *errorString = "Can not edit nodes from shadow trees"; + if (node->isInUserAgentShadowTree()) { + errorString = ASCIILiteral("Cannot edit nodes in user agent shadow trees"); + return nullptr; + } + if (node->isPseudoElement()) { + errorString = ASCIILiteral("Cannot edit pseudo elements"); return nullptr; } return node; } -Element* InspectorDOMAgent::assertEditableElement(ErrorString* errorString, int nodeId) +Element* InspectorDOMAgent::assertEditableElement(ErrorString& errorString, int nodeId) { Element* element = assertElement(errorString, nodeId); if (!element) return nullptr; - if (element->isInShadowTree()) { - *errorString = "Can not edit elements from shadow trees"; + if (element->isInUserAgentShadowTree()) { + errorString = ASCIILiteral("Cannot edit elements in user agent shadow trees"); + return nullptr; + } + if (element->isPseudoElement()) { + errorString = ASCIILiteral("Cannot edit pseudo elements"); return nullptr; } return element; } -void InspectorDOMAgent::getDocument(ErrorString* errorString, RefPtr<Inspector::TypeBuilder::DOM::Node>& root) +void InspectorDOMAgent::getDocument(ErrorString& errorString, RefPtr<Inspector::Protocol::DOM::Node>& root) { m_documentRequested = true; if (!m_document) { - *errorString = "Document is not available"; + errorString = ASCIILiteral("Document is not available"); return; } @@ -459,8 +464,8 @@ void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId, int depth) return; } - RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::Node>> children = buildArrayForContainerChildren(node, depth, nodeMap); - m_frontendDispatcher->setChildNodes(nodeId, children.release()); + auto children = buildArrayForContainerChildren(node, depth, nodeMap); + m_frontendDispatcher->setChildNodes(nodeId, WTFMove(children)); } void InspectorDOMAgent::discardBindings() @@ -473,13 +478,13 @@ void InspectorDOMAgent::discardBindings() m_nodeGroupToBackendIdMap.clear(); } -int InspectorDOMAgent::pushNodeToFrontend(ErrorString* errorString, int documentNodeId, Node* nodeToPush) +int InspectorDOMAgent::pushNodeToFrontend(ErrorString& errorString, int documentNodeId, Node* nodeToPush) { Document* document = assertDocument(errorString, documentNodeId); if (!document) return 0; if (&nodeToPush->document() != document) { - *errorString = "Node is not part of the document with given id"; + errorString = ASCIILiteral("Node is not part of the document with given id"); return 0; } @@ -497,7 +502,7 @@ Node* InspectorDOMAgent::nodeForId(int id) return 0; } -void InspectorDOMAgent::requestChildNodes(ErrorString* errorString, int nodeId, const int* depth) +void InspectorDOMAgent::requestChildNodes(ErrorString& errorString, int nodeId, const int* depth) { int sanitizedDepth; @@ -508,54 +513,52 @@ void InspectorDOMAgent::requestChildNodes(ErrorString* errorString, int nodeId, else if (*depth > 0) sanitizedDepth = *depth; else { - *errorString = "Please provide a positive integer as a depth or -1 for entire subtree"; + errorString = ASCIILiteral("Please provide a positive integer as a depth or -1 for entire subtree"); return; } pushChildNodesToFrontend(nodeId, sanitizedDepth); } -void InspectorDOMAgent::querySelector(ErrorString* errorString, int nodeId, const String& selectors, int* elementId) +void InspectorDOMAgent::querySelector(ErrorString& errorString, int nodeId, const String& selectors, int* elementId) { *elementId = 0; Node* node = assertNode(errorString, nodeId); if (!node) return; - if (!node->isContainerNode()) { + if (!is<ContainerNode>(*node)) { assertElement(errorString, nodeId); return; } - ExceptionCode ec = 0; - RefPtr<Element> element = toContainerNode(node)->querySelector(selectors, ec); - if (ec) { - *errorString = "DOM Error while querying"; + auto queryResult = downcast<ContainerNode>(*node).querySelector(selectors); + if (queryResult.hasException()) { + errorString = ASCIILiteral("DOM Error while querying"); return; } - if (element) - *elementId = pushNodePathToFrontend(element.get()); + if (auto* element = queryResult.releaseReturnValue()) + *elementId = pushNodePathToFrontend(element); } -void InspectorDOMAgent::querySelectorAll(ErrorString* errorString, int nodeId, const String& selectors, RefPtr<Inspector::TypeBuilder::Array<int>>& result) +void InspectorDOMAgent::querySelectorAll(ErrorString& errorString, int nodeId, const String& selectors, RefPtr<Inspector::Protocol::Array<int>>& result) { Node* node = assertNode(errorString, nodeId); if (!node) return; - if (!node->isContainerNode()) { + if (!is<ContainerNode>(*node)) { assertElement(errorString, nodeId); return; } - ExceptionCode ec = 0; - RefPtr<NodeList> nodes = toContainerNode(node)->querySelectorAll(selectors, ec); - if (ec) { - *errorString = "DOM Error while querying"; + auto queryResult = downcast<ContainerNode>(*node).querySelectorAll(selectors); + if (queryResult.hasException()) { + errorString = ASCIILiteral("DOM Error while querying"); return; } - result = Inspector::TypeBuilder::Array<int>::create(); - + auto nodes = queryResult.releaseReturnValue(); + result = Inspector::Protocol::Array<int>::create(); for (unsigned i = 0; i < nodes->length(); ++i) result->addItem(pushNodePathToFrontend(nodes->item(i))); } @@ -582,12 +585,12 @@ int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush) Node* parent = innerParentNode(node); if (!parent) { // Node being pushed is detached -> push subtree root. - OwnPtr<NodeToIdMap> newMap = adoptPtr(new NodeToIdMap); + auto newMap = std::make_unique<NodeToIdMap>(); danglingMap = newMap.get(); m_danglingNodeToIdMaps.append(newMap.release()); - RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::Node>> children = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::Node>::create(); + auto children = Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>::create(); children->addItem(buildObjectForNode(node, 0, danglingMap)); - m_frontendDispatcher->setChildNodes(0, children); + m_frontendDispatcher->setChildNodes(0, WTFMove(children)); break; } else { path.append(parent); @@ -607,9 +610,9 @@ int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush) return map->get(nodeToPush); } -int InspectorDOMAgent::boundNodeId(Node* node) +int InspectorDOMAgent::boundNodeId(const Node* node) { - return m_documentNodeToIdMap.get(node); + return m_documentNodeToIdMap.get(const_cast<Node*>(node)); } BackendNodeId InspectorDOMAgent::backendNodeIdForNode(Node* node, const String& nodeGroup) @@ -631,50 +634,49 @@ BackendNodeId InspectorDOMAgent::backendNodeIdForNode(Node* node, const String& return id; } -void InspectorDOMAgent::releaseBackendNodeIds(ErrorString* errorString, const String& nodeGroup) +void InspectorDOMAgent::releaseBackendNodeIds(ErrorString& errorString, const String& nodeGroup) { if (m_nodeGroupToBackendIdMap.contains(nodeGroup)) { NodeToBackendIdMap& map = m_nodeGroupToBackendIdMap.find(nodeGroup)->value; - for (NodeToBackendIdMap::iterator it = map.begin(); it != map.end(); ++it) - m_backendIdToNode.remove(it->value); + for (auto& backendId : map.values()) + m_backendIdToNode.remove(backendId); m_nodeGroupToBackendIdMap.remove(nodeGroup); return; } - *errorString = "Group name not found"; + errorString = ASCIILiteral("Group name not found"); } -void InspectorDOMAgent::setAttributeValue(ErrorString* errorString, int elementId, const String& name, const String& value) +void InspectorDOMAgent::setAttributeValue(ErrorString& errorString, int elementId, const String& name, const String& value) { Element* element = assertEditableElement(errorString, elementId); if (!element) return; - m_domEditor->setAttribute(element, name, value, errorString); + m_domEditor->setAttribute(*element, name, value, errorString); } -void InspectorDOMAgent::setAttributesAsText(ErrorString* errorString, int elementId, const String& text, const String* const name) +void InspectorDOMAgent::setAttributesAsText(ErrorString& errorString, int elementId, const String& text, const String* const name) { Element* element = assertEditableElement(errorString, elementId); if (!element) return; - RefPtr<HTMLElement> parsedElement = createHTMLElement(element->document(), spanTag); - ExceptionCode ec = 0; - parsedElement.get()->setInnerHTML("<span " + text + "></span>", ec); - if (ec) { - *errorString = InspectorDOMAgent::toErrorString(ec); + auto parsedElement = createHTMLElement(element->document(), spanTag); + auto result = parsedElement.get().setInnerHTML("<span " + text + "></span>"); + if (result.hasException()) { + errorString = toErrorString(result.releaseException()); return; } Node* child = parsedElement->firstChild(); if (!child) { - *errorString = "Could not parse value as attributes"; + errorString = ASCIILiteral("Could not parse value as attributes"); return; } - Element* childElement = toElement(child); + Element* childElement = downcast<Element>(child); if (!childElement->hasAttributes() && name) { - m_domEditor->removeAttribute(element, *name, errorString); + m_domEditor->removeAttribute(*element, *name, errorString); return; } @@ -682,24 +684,24 @@ void InspectorDOMAgent::setAttributesAsText(ErrorString* errorString, int elemen for (const Attribute& attribute : childElement->attributesIterator()) { // Add attribute pair foundOriginalAttribute = foundOriginalAttribute || (name && attribute.name().toString() == *name); - if (!m_domEditor->setAttribute(element, attribute.name().toString(), attribute.value(), errorString)) + if (!m_domEditor->setAttribute(*element, attribute.name().toString(), attribute.value(), errorString)) return; } if (!foundOriginalAttribute && name && !name->stripWhiteSpace().isEmpty()) - m_domEditor->removeAttribute(element, *name, errorString); + m_domEditor->removeAttribute(*element, *name, errorString); } -void InspectorDOMAgent::removeAttribute(ErrorString* errorString, int elementId, const String& name) +void InspectorDOMAgent::removeAttribute(ErrorString& errorString, int elementId, const String& name) { Element* element = assertEditableElement(errorString, elementId); if (!element) return; - m_domEditor->removeAttribute(element, name, errorString); + m_domEditor->removeAttribute(*element, name, errorString); } -void InspectorDOMAgent::removeNode(ErrorString* errorString, int nodeId) +void InspectorDOMAgent::removeNode(ErrorString& errorString, int nodeId) { Node* node = assertEditableNode(errorString, nodeId); if (!node) @@ -707,49 +709,49 @@ void InspectorDOMAgent::removeNode(ErrorString* errorString, int nodeId) ContainerNode* parentNode = node->parentNode(); if (!parentNode) { - *errorString = "Can not remove detached node"; + errorString = ASCIILiteral("Cannot remove detached node"); return; } - m_domEditor->removeChild(parentNode, node, errorString); + m_domEditor->removeChild(*parentNode, *node, errorString); } -void InspectorDOMAgent::setNodeName(ErrorString* errorString, int nodeId, const String& tagName, int* newId) +void InspectorDOMAgent::setNodeName(ErrorString& errorString, int nodeId, const String& tagName, int* newId) { *newId = 0; - Node* oldNode = nodeForId(nodeId); - if (!oldNode || !oldNode->isElementNode()) + RefPtr<Node> oldNode = nodeForId(nodeId); + if (!is<Element>(oldNode.get())) return; - ExceptionCode ec = 0; - RefPtr<Element> newElem = oldNode->document().createElement(tagName, ec); - if (ec) + auto createElementResult = oldNode->document().createElementForBindings(tagName); + if (createElementResult.hasException()) return; + auto newElement = createElementResult.releaseReturnValue(); // Copy over the original node's attributes. - newElem->cloneAttributesFromElement(*toElement(oldNode)); + newElement->cloneAttributesFromElement(downcast<Element>(*oldNode)); // Copy over the original node's children. - Node* child; + RefPtr<Node> child; while ((child = oldNode->firstChild())) { - if (!m_domEditor->insertBefore(newElem.get(), child, 0, errorString)) + if (!m_domEditor->insertBefore(newElement, *child, 0, errorString)) return; } // Replace the old node with the new node - ContainerNode* parent = oldNode->parentNode(); - if (!m_domEditor->insertBefore(parent, newElem.get(), oldNode->nextSibling(), errorString)) + RefPtr<ContainerNode> parent = oldNode->parentNode(); + if (!m_domEditor->insertBefore(*parent, newElement.copyRef(), oldNode->nextSibling(), errorString)) return; - if (!m_domEditor->removeChild(parent, oldNode, errorString)) + if (!m_domEditor->removeChild(*parent, *oldNode, errorString)) return; - *newId = pushNodePathToFrontend(newElem.get()); + *newId = pushNodePathToFrontend(newElement.ptr()); if (m_childrenRequested.contains(nodeId)) pushChildNodesToFrontend(*newId); } -void InspectorDOMAgent::getOuterHTML(ErrorString* errorString, int nodeId, WTF::String* outerHTML) +void InspectorDOMAgent::getOuterHTML(ErrorString& errorString, int nodeId, WTF::String* outerHTML) { Node* node = assertNode(errorString, nodeId); if (!node) @@ -758,11 +760,10 @@ void InspectorDOMAgent::getOuterHTML(ErrorString* errorString, int nodeId, WTF:: *outerHTML = createMarkup(*node); } -void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const String& outerHTML) +void InspectorDOMAgent::setOuterHTML(ErrorString& errorString, int nodeId, const String& outerHTML) { if (!nodeId) { - DOMPatchSupport domPatchSupport(m_domEditor.get(), m_document.get()); - domPatchSupport.patchDocument(outerHTML); + DOMPatchSupport { *m_domEditor, *m_document }.patchDocument(outerHTML); return; } @@ -771,17 +772,13 @@ void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const return; Document& document = node->document(); - if (!document.isHTMLDocument() && !document.isXHTMLDocument() -#if ENABLE(SVG) - && !document.isSVGDocument() -#endif - ) { - *errorString = "Not an HTML/XML document"; + if (!document.isHTMLDocument() && !document.isXMLDocument()) { + errorString = ASCIILiteral("Not an HTML/XML document"); return; } - Node* newNode = 0; - if (!m_domEditor->setOuterHTML(*node, outerHTML, &newNode, errorString)) + Node* newNode = nullptr; + if (!m_domEditor->setOuterHTML(*node, outerHTML, newNode, errorString)) return; if (!newNode) { @@ -796,23 +793,23 @@ void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const pushChildNodesToFrontend(newId); } -void InspectorDOMAgent::setNodeValue(ErrorString* errorString, int nodeId, const String& value) +void InspectorDOMAgent::setNodeValue(ErrorString& errorString, int nodeId, const String& value) { Node* node = assertEditableNode(errorString, nodeId); if (!node) return; - if (node->nodeType() != Node::TEXT_NODE) { - *errorString = "Can only set value of text nodes"; + if (!is<Text>(*node)) { + errorString = ASCIILiteral("Can only set value of text nodes"); return; } - m_domEditor->replaceWholeText(toText(node), value, errorString); + m_domEditor->replaceWholeText(downcast<Text>(*node), value, errorString); } -void InspectorDOMAgent::getEventListenersForNode(ErrorString* errorString, int nodeId, const String* objectGroup, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::EventListener>>& listenersArray) +void InspectorDOMAgent::getEventListenersForNode(ErrorString& errorString, int nodeId, const String* objectGroup, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::DOM::EventListener>>& listenersArray) { - listenersArray = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::EventListener>::create(); + listenersArray = Inspector::Protocol::Array<Inspector::Protocol::DOM::EventListener>::create(); Node* node = assertNode(errorString, nodeId); if (!node) return; @@ -821,24 +818,19 @@ void InspectorDOMAgent::getEventListenersForNode(ErrorString* errorString, int n // Get Capturing Listeners (in this order) size_t eventInformationLength = eventInformation.size(); - for (size_t i = 0; i < eventInformationLength; ++i) { - const EventListenerInfo& info = eventInformation[i]; - const EventListenerVector& vector = info.eventListenerVector; - for (size_t j = 0; j < vector.size(); ++j) { - const RegisteredEventListener& listener = vector[j]; - if (listener.useCapture) - listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup)); + for (auto& info : eventInformation) { + for (auto& listener : info.eventListenerVector) { + if (listener->useCapture()) + listenersArray->addItem(buildObjectForEventListener(*listener, info.eventType, info.node, objectGroup)); } } // Get Bubbling Listeners (reverse order) for (size_t i = eventInformationLength; i; --i) { const EventListenerInfo& info = eventInformation[i - 1]; - const EventListenerVector& vector = info.eventListenerVector; - for (size_t j = 0; j < vector.size(); ++j) { - const RegisteredEventListener& listener = vector[j]; - if (!listener.useCapture) - listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup)); + for (auto& listener : info.eventListenerVector) { + if (!listener->useCapture()) + listenersArray->addItem(buildObjectForEventListener(*listener, info.eventType, info.node, objectGroup)); } } } @@ -861,49 +853,54 @@ void InspectorDOMAgent::getEventListeners(Node* node, Vector<EventListenerInfo>& if (!d) continue; // Get the list of event types this Node is concerned with - Vector<AtomicString> eventTypes = d->eventListenerMap.eventTypes(); - for (size_t j = 0; j < eventTypes.size(); ++j) { - AtomicString& type = eventTypes[j]; - const EventListenerVector& listeners = ancestor->getEventListeners(type); + for (auto& type : d->eventListenerMap.eventTypes()) { + auto& listeners = ancestor->eventListeners(type); EventListenerVector filteredListeners; - filteredListeners.reserveCapacity(listeners.size()); - for (size_t k = 0; k < listeners.size(); ++k) { - if (listeners[k].listener->type() == EventListener::JSEventListenerType) - filteredListeners.append(listeners[k]); + filteredListeners.reserveInitialCapacity(listeners.size()); + for (auto& listener : listeners) { + if (listener->callback().type() == EventListener::JSEventListenerType) + filteredListeners.uncheckedAppend(listener); } if (!filteredListeners.isEmpty()) - eventInformation.append(EventListenerInfo(ancestor, type, filteredListeners)); + eventInformation.append(EventListenerInfo(ancestor, type, WTFMove(filteredListeners))); } } } -void InspectorDOMAgent::performSearch(ErrorString* errorString, const String& whitespaceTrimmedQuery, const RefPtr<InspectorArray>* nodeIds, String* searchId, int* resultCount) +void InspectorDOMAgent::getAccessibilityPropertiesForNode(ErrorString& errorString, int nodeId, RefPtr<Inspector::Protocol::DOM::AccessibilityProperties>& axProperties) +{ + Node* node = assertNode(errorString, nodeId); + if (!node) + return; + + axProperties = buildObjectForAccessibilityProperties(node); +} + +void InspectorDOMAgent::performSearch(ErrorString& errorString, const String& whitespaceTrimmedQuery, const InspectorArray* nodeIds, String* searchId, int* resultCount) { // FIXME: Search works with node granularity - number of matches within node is not calculated. InspectorNodeFinder finder(whitespaceTrimmedQuery); if (nodeIds) { - const RefPtr<InspectorArray>& nodeIdsRef = *nodeIds; - for (unsigned i = 0; i < nodeIdsRef->length(); ++i) { - RefPtr<InspectorValue> nodeValue = nodeIdsRef->get(i); + for (auto& nodeValue : *nodeIds) { if (!nodeValue) { - *errorString = "Invalid nodeIds item."; + errorString = ASCIILiteral("Invalid nodeIds item."); return; } int nodeId = 0; - if (!nodeValue->asNumber(&nodeId)) { - *errorString = "Invalid nodeIds item type. Expecting integer types."; + if (!nodeValue->asInteger(nodeId)) { + errorString = ASCIILiteral("Invalid nodeIds item type. Expecting integer types."); return; } Node* node = assertNode(errorString, nodeId); if (!node) { // assertNode should have filled the errorString for us. - ASSERT(errorString->length()); + ASSERT(errorString.length()); return; } finder.performSearch(node); } - } else if (m_document) { + } else { // There's no need to iterate the frames tree because // the search helper will go inside the frame owner elements. finder.performSearch(m_document.get()); @@ -912,32 +909,32 @@ void InspectorDOMAgent::performSearch(ErrorString* errorString, const String& wh *searchId = IdentifiersFactory::createIdentifier(); auto& resultsVector = m_searchResults.add(*searchId, Vector<RefPtr<Node>>()).iterator->value; - for (auto iterator = finder.results().begin(); iterator != finder.results().end(); ++iterator) - resultsVector.append(*iterator); + for (auto& result : finder.results()) + resultsVector.append(result); *resultCount = resultsVector.size(); } -void InspectorDOMAgent::getSearchResults(ErrorString* errorString, const String& searchId, int fromIndex, int toIndex, RefPtr<Inspector::TypeBuilder::Array<int>>& nodeIds) +void InspectorDOMAgent::getSearchResults(ErrorString& errorString, const String& searchId, int fromIndex, int toIndex, RefPtr<Inspector::Protocol::Array<int>>& nodeIds) { SearchResults::iterator it = m_searchResults.find(searchId); if (it == m_searchResults.end()) { - *errorString = "No search session with given id found"; + errorString = ASCIILiteral("No search session with given id found"); return; } int size = it->value.size(); if (fromIndex < 0 || toIndex > size || fromIndex >= toIndex) { - *errorString = "Invalid search result range"; + errorString = ASCIILiteral("Invalid search result range"); return; } - nodeIds = Inspector::TypeBuilder::Array<int>::create(); + nodeIds = Inspector::Protocol::Array<int>::create(); for (int i = fromIndex; i < toIndex; ++i) nodeIds->addItem(pushNodePathToFrontend((it->value)[i].get())); } -void InspectorDOMAgent::discardSearchResults(ErrorString*, const String& searchId) +void InspectorDOMAgent::discardSearchResults(ErrorString&, const String& searchId) { m_searchResults.remove(searchId); } @@ -954,13 +951,13 @@ bool InspectorDOMAgent::handleMousePress() return false; } -bool InspectorDOMAgent::handleTouchEvent(Node* node) +bool InspectorDOMAgent::handleTouchEvent(Node& node) { if (!m_searchingForNode) return false; - if (node && m_inspectModeHighlightConfig) { - m_overlay->highlightNode(node, *m_inspectModeHighlightConfig); - inspect(node); + if (m_inspectModeHighlightConfig) { + m_overlay->highlightNode(&node, *m_inspectModeHighlightConfig); + inspect(&node); return true; } return false; @@ -968,14 +965,17 @@ bool InspectorDOMAgent::handleTouchEvent(Node* node) void InspectorDOMAgent::inspect(Node* inspectedNode) { - ErrorString error; + ErrorString unused; RefPtr<Node> node = inspectedNode; - setSearchingForNode(&error, false, 0); + setSearchingForNode(unused, false, nullptr); if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE) node = node->parentNode(); m_nodeToFocus = node; + if (!m_nodeToFocus) + return; + focusNode(); } @@ -987,130 +987,173 @@ void InspectorDOMAgent::focusNode() ASSERT(m_nodeToFocus); RefPtr<Node> node = m_nodeToFocus.get(); - m_nodeToFocus = 0; + m_nodeToFocus = nullptr; Frame* frame = node->document().frame(); if (!frame) return; JSC::ExecState* scriptState = mainWorldExecState(frame); - InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState); + InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(scriptState); if (injectedScript.hasNoValue()) return; - injectedScript.inspectObject(InspectorDOMAgent::nodeAsScriptValue(scriptState, node.get())); + injectedScript.inspectObject(nodeAsScriptValue(*scriptState, node.get())); } void InspectorDOMAgent::mouseDidMoveOverElement(const HitTestResult& result, unsigned) { + m_mousedOverNode = result.innerNode(); + if (!m_searchingForNode) return; - Node* node = result.innerNode(); + highlightMousedOverNode(); +} + +void InspectorDOMAgent::highlightMousedOverNode() +{ + Node* node = m_mousedOverNode.get(); while (node && node->nodeType() == Node::TEXT_NODE) node = node->parentNode(); if (node && m_inspectModeHighlightConfig) m_overlay->highlightNode(node, *m_inspectModeHighlightConfig); } -void InspectorDOMAgent::setSearchingForNode(ErrorString* errorString, bool enabled, InspectorObject* highlightInspectorObject) +void InspectorDOMAgent::setSearchingForNode(ErrorString& errorString, bool enabled, const InspectorObject* highlightInspectorObject) { if (m_searchingForNode == enabled) return; + m_searchingForNode = enabled; + if (enabled) { m_inspectModeHighlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject); if (!m_inspectModeHighlightConfig) return; + highlightMousedOverNode(); } else hideHighlight(errorString); m_overlay->didSetSearchingForNode(m_searchingForNode); + + if (InspectorClient* client = m_pageAgent->page().inspectorController().inspectorClient()) + client->elementSelectionChanged(m_searchingForNode); } -PassOwnPtr<HighlightConfig> InspectorDOMAgent::highlightConfigFromInspectorObject(ErrorString* errorString, InspectorObject* highlightInspectorObject) +std::unique_ptr<HighlightConfig> InspectorDOMAgent::highlightConfigFromInspectorObject(ErrorString& errorString, const InspectorObject* highlightInspectorObject) { if (!highlightInspectorObject) { - *errorString = "Internal error: highlight configuration parameter is missing"; + errorString = ASCIILiteral("Internal error: highlight configuration parameter is missing"); return nullptr; } - OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig()); + auto highlightConfig = std::make_unique<HighlightConfig>(); bool showInfo = false; // Default: false (do not show a tooltip). - highlightInspectorObject->getBoolean("showInfo", &showInfo); + highlightInspectorObject->getBoolean("showInfo", showInfo); highlightConfig->showInfo = showInfo; - bool showRulers = false; // Default: false (do not show rulers). - highlightInspectorObject->getBoolean("showRulers", &showRulers); - highlightConfig->showRulers = showRulers; highlightConfig->content = parseConfigColor("contentColor", highlightInspectorObject); highlightConfig->contentOutline = parseConfigColor("contentOutlineColor", highlightInspectorObject); highlightConfig->padding = parseConfigColor("paddingColor", highlightInspectorObject); highlightConfig->border = parseConfigColor("borderColor", highlightInspectorObject); highlightConfig->margin = parseConfigColor("marginColor", highlightInspectorObject); - return highlightConfig.release(); + return highlightConfig; } -void InspectorDOMAgent::setInspectModeEnabled(ErrorString* errorString, bool enabled, const RefPtr<InspectorObject>* highlightConfig) +void InspectorDOMAgent::setInspectModeEnabled(ErrorString& errorString, bool enabled, const InspectorObject* highlightConfig) { - setSearchingForNode(errorString, enabled, highlightConfig ? highlightConfig->get() : 0); + setSearchingForNode(errorString, enabled, highlightConfig ? highlightConfig : nullptr); } -void InspectorDOMAgent::highlightRect(ErrorString*, int x, int y, int width, int height, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor, const bool* usePageCoordinates) +void InspectorDOMAgent::highlightRect(ErrorString&, int x, int y, int width, int height, const InspectorObject* color, const InspectorObject* outlineColor, const bool* usePageCoordinates) { - OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad(FloatRect(x, y, width, height))); - innerHighlightQuad(quad.release(), color, outlineColor, usePageCoordinates); + auto quad = std::make_unique<FloatQuad>(FloatRect(x, y, width, height)); + innerHighlightQuad(WTFMove(quad), color, outlineColor, usePageCoordinates); } -void InspectorDOMAgent::highlightQuad(ErrorString* errorString, const RefPtr<InspectorArray>& quadArray, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor, const bool* usePageCoordinates) +void InspectorDOMAgent::highlightQuad(ErrorString& errorString, const InspectorArray& quadArray, const InspectorObject* color, const InspectorObject* outlineColor, const bool* usePageCoordinates) { - OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad()); + auto quad = std::make_unique<FloatQuad>(); if (!parseQuad(quadArray, quad.get())) { - *errorString = "Invalid Quad format"; + errorString = ASCIILiteral("Invalid Quad format"); return; } - innerHighlightQuad(quad.release(), color, outlineColor, usePageCoordinates); + innerHighlightQuad(WTFMove(quad), color, outlineColor, usePageCoordinates); } -void InspectorDOMAgent::innerHighlightQuad(PassOwnPtr<FloatQuad> quad, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor, const bool* usePageCoordinates) +void InspectorDOMAgent::innerHighlightQuad(std::unique_ptr<FloatQuad> quad, const InspectorObject* color, const InspectorObject* outlineColor, const bool* usePageCoordinates) { - OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig()); + auto highlightConfig = std::make_unique<HighlightConfig>(); highlightConfig->content = parseColor(color); highlightConfig->contentOutline = parseColor(outlineColor); highlightConfig->usePageCoordinates = usePageCoordinates ? *usePageCoordinates : false; - m_overlay->highlightQuad(quad, *highlightConfig); + m_overlay->highlightQuad(WTFMove(quad), *highlightConfig); } -void InspectorDOMAgent::highlightNode(ErrorString* errorString, const RefPtr<InspectorObject>& highlightInspectorObject, const int* nodeId, const String* objectId) +void InspectorDOMAgent::highlightSelector(ErrorString& errorString, const InspectorObject& highlightInspectorObject, const String& selectorString, const String* frameId) { - Node* node = 0; - if (nodeId) { + RefPtr<Document> document; + + if (frameId) { + Frame* frame = m_pageAgent->frameForId(*frameId); + if (!frame) { + errorString = ASCIILiteral("No frame for given id found"); + return; + } + + document = frame->document(); + } else + document = m_document; + + if (!document) { + errorString = ASCIILiteral("Document could not be found"); + return; + } + + auto queryResult = document->querySelectorAll(selectorString); + // FIXME: <https://webkit.org/b/146161> Web Inspector: DOM.highlightSelector should work for "a:visited" + if (queryResult.hasException()) { + errorString = ASCIILiteral("DOM Error while querying"); + return; + } + + auto highlightConfig = highlightConfigFromInspectorObject(errorString, &highlightInspectorObject); + if (!highlightConfig) + return; + + m_overlay->highlightNodeList(queryResult.releaseReturnValue(), *highlightConfig); +} + +void InspectorDOMAgent::highlightNode(ErrorString& errorString, const InspectorObject& highlightInspectorObject, const int* nodeId, const String* objectId) +{ + Node* node = nullptr; + if (nodeId) node = assertNode(errorString, *nodeId); - } else if (objectId) { + else if (objectId) { node = nodeForObjectId(*objectId); if (!node) - *errorString = "Node for given objectId not found"; + errorString = ASCIILiteral("Node for given objectId not found"); } else - *errorString = "Either nodeId or objectId must be specified"; + errorString = ASCIILiteral("Either nodeId or objectId must be specified"); if (!node) return; - OwnPtr<HighlightConfig> highlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject.get()); + std::unique_ptr<HighlightConfig> highlightConfig = highlightConfigFromInspectorObject(errorString, &highlightInspectorObject); if (!highlightConfig) return; m_overlay->highlightNode(node, *highlightConfig); } -void InspectorDOMAgent::highlightFrame( - ErrorString*, - const String& frameId, - const RefPtr<InspectorObject>* color, - const RefPtr<InspectorObject>* outlineColor) +void InspectorDOMAgent::highlightFrame(ErrorString& errorString, const String& frameId, const InspectorObject* color, const InspectorObject* outlineColor) { - Frame* frame = m_pageAgent->frameForId(frameId); - if (frame && frame->ownerElement()) { - OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig()); + Frame* frame = m_pageAgent->assertFrame(errorString, frameId); + if (!frame) + return; + + if (frame->ownerElement()) { + auto highlightConfig = std::make_unique<HighlightConfig>(); highlightConfig->showInfo = true; // Always show tooltips for frames. highlightConfig->content = parseColor(color); highlightConfig->contentOutline = parseColor(outlineColor); @@ -1118,12 +1161,12 @@ void InspectorDOMAgent::highlightFrame( } } -void InspectorDOMAgent::hideHighlight(ErrorString*) +void InspectorDOMAgent::hideHighlight(ErrorString&) { m_overlay->hideHighlight(); } -void InspectorDOMAgent::moveTo(ErrorString* errorString, int nodeId, int targetElementId, const int* const anchorNodeId, int* newNodeId) +void InspectorDOMAgent::moveTo(ErrorString& errorString, int nodeId, int targetElementId, const int* const anchorNodeId, int* newNodeId) { Node* node = assertEditableNode(errorString, nodeId); if (!node) @@ -1139,65 +1182,65 @@ void InspectorDOMAgent::moveTo(ErrorString* errorString, int nodeId, int targetE if (!anchorNode) return; if (anchorNode->parentNode() != targetElement) { - *errorString = "Anchor node must be child of the target element"; + errorString = ASCIILiteral("Anchor node must be child of the target element"); return; } } - if (!m_domEditor->insertBefore(targetElement, node, anchorNode, errorString)) + if (!m_domEditor->insertBefore(*targetElement, *node, anchorNode, errorString)) return; *newNodeId = pushNodePathToFrontend(node); } -void InspectorDOMAgent::undo(ErrorString* errorString) +void InspectorDOMAgent::undo(ErrorString& errorString) { - ExceptionCode ec = 0; - m_history->undo(ec); - *errorString = InspectorDOMAgent::toErrorString(ec); + auto result = m_history->undo(); + if (result.hasException()) + errorString = toErrorString(result.releaseException()); } -void InspectorDOMAgent::redo(ErrorString* errorString) +void InspectorDOMAgent::redo(ErrorString& errorString) { - ExceptionCode ec = 0; - m_history->redo(ec); - *errorString = InspectorDOMAgent::toErrorString(ec); + auto result = m_history->redo(); + if (result.hasException()) + errorString = toErrorString(result.releaseException()); } -void InspectorDOMAgent::markUndoableState(ErrorString*) +void InspectorDOMAgent::markUndoableState(ErrorString&) { m_history->markUndoableState(); } -void InspectorDOMAgent::focus(ErrorString* errorString, int nodeId) +void InspectorDOMAgent::focus(ErrorString& errorString, int nodeId) { Element* element = assertElement(errorString, nodeId); if (!element) return; if (!element->isFocusable()) { - *errorString = "Element is not focusable"; + errorString = ASCIILiteral("Element is not focusable"); return; } element->focus(); } -void InspectorDOMAgent::resolveNode(ErrorString* errorString, int nodeId, const String* const objectGroup, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>& result) +void InspectorDOMAgent::resolveNode(ErrorString& errorString, int nodeId, const String* const objectGroup, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result) { - String objectGroupName = objectGroup ? *objectGroup : ""; + String objectGroupName = objectGroup ? *objectGroup : emptyString(); Node* node = nodeForId(nodeId); if (!node) { - *errorString = "No node with given id found"; + errorString = ASCIILiteral("No node with given id found"); return; } - RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject> object = resolveNode(node, objectGroupName); + RefPtr<Inspector::Protocol::Runtime::RemoteObject> object = resolveNode(node, objectGroupName); if (!object) { - *errorString = "Node with given id does not belong to the document"; + errorString = ASCIILiteral("Node with given id does not belong to the document"); return; } result = object; } -void InspectorDOMAgent::getAttributes(ErrorString* errorString, int nodeId, RefPtr<Inspector::TypeBuilder::Array<String>>& result) +void InspectorDOMAgent::getAttributes(ErrorString& errorString, int nodeId, RefPtr<Inspector::Protocol::Array<String>>& result) { Element* element = assertElement(errorString, nodeId); if (!element) @@ -1206,7 +1249,7 @@ void InspectorDOMAgent::getAttributes(ErrorString* errorString, int nodeId, RefP result = buildArrayForElementAttributes(element); } -void InspectorDOMAgent::requestNode(ErrorString*, const String& objectId, int* nodeId) +void InspectorDOMAgent::requestNode(ErrorString&, const String& objectId, int* nodeId) { Node* node = nodeForObjectId(objectId); if (node) @@ -1215,20 +1258,72 @@ void InspectorDOMAgent::requestNode(ErrorString*, const String& objectId, int* n *nodeId = 0; } -// static String InspectorDOMAgent::documentURLString(Document* document) { if (!document || document->url().isNull()) - return ""; + return emptyString(); return document->url().string(); } static String documentBaseURLString(Document* document) { - return document->completeURL("").string(); + return document->completeURL(emptyString()).string(); +} + +static bool pseudoElementType(PseudoId pseudoId, Inspector::Protocol::DOM::PseudoType* type) +{ + switch (pseudoId) { + case BEFORE: + *type = Inspector::Protocol::DOM::PseudoType::Before; + return true; + case AFTER: + *type = Inspector::Protocol::DOM::PseudoType::After; + return true; + default: + return false; + } +} + +static Inspector::Protocol::DOM::ShadowRootType shadowRootType(ShadowRootMode mode) +{ + switch (mode) { + case ShadowRootMode::UserAgent: + return Inspector::Protocol::DOM::ShadowRootType::UserAgent; + case ShadowRootMode::Closed: + return Inspector::Protocol::DOM::ShadowRootType::Closed; + case ShadowRootMode::Open: + return Inspector::Protocol::DOM::ShadowRootType::Open; + } + + ASSERT_NOT_REACHED(); + return Inspector::Protocol::DOM::ShadowRootType::UserAgent; +} + +static Inspector::Protocol::DOM::CustomElementState customElementState(const Element& element) +{ + if (element.isDefinedCustomElement()) + return Inspector::Protocol::DOM::CustomElementState::Custom; + if (element.isFailedCustomElement()) + return Inspector::Protocol::DOM::CustomElementState::Failed; + if (element.isUndefinedCustomElement() || element.isCustomElementUpgradeCandidate()) + return Inspector::Protocol::DOM::CustomElementState::Waiting; + return Inspector::Protocol::DOM::CustomElementState::Builtin; } -PassRefPtr<Inspector::TypeBuilder::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap) +static String computeContentSecurityPolicySHA256Hash(const Element& element) +{ + // FIXME: Compute the digest with respect to the raw bytes received from the page. + // See <https://bugs.webkit.org/show_bug.cgi?id=155184>. + TextEncoding documentEncoding = element.document().textEncoding(); + const TextEncoding& encodingToUse = documentEncoding.isValid() ? documentEncoding : UTF8Encoding(); + CString content = encodingToUse.encode(TextNodeTraversal::contentsAsString(element), EntitiesForUnencodables); + auto cryptoDigest = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256); + cryptoDigest->addBytes(content.data(), content.length()); + Vector<uint8_t> digest = cryptoDigest->computeHash(); + return makeString("sha256-", base64Encode(digest.data(), digest.size())); +} + +Ref<Inspector::Protocol::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap) { int id = bind(node, nodesMap); String nodeName; @@ -1236,6 +1331,10 @@ PassRefPtr<Inspector::TypeBuilder::DOM::Node> InspectorDOMAgent::buildObjectForN String nodeValue; switch (node->nodeType()) { + case Node::PROCESSING_INSTRUCTION_NODE: + nodeName = node->nodeName(); + localName = node->localName(); + FALLTHROUGH; case Node::TEXT_NODE: case Node::COMMENT_NODE: case Node::CDATA_SECTION_NODE: @@ -1257,80 +1356,108 @@ PassRefPtr<Inspector::TypeBuilder::DOM::Node> InspectorDOMAgent::buildObjectForN break; } - RefPtr<Inspector::TypeBuilder::DOM::Node> value = Inspector::TypeBuilder::DOM::Node::create() + auto value = Inspector::Protocol::DOM::Node::create() .setNodeId(id) .setNodeType(static_cast<int>(node->nodeType())) .setNodeName(nodeName) .setLocalName(localName) - .setNodeValue(nodeValue); + .setNodeValue(nodeValue) + .release(); if (node->isContainerNode()) { int nodeCount = innerChildNodeCount(node); value->setChildNodeCount(nodeCount); - RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::Node>> children = buildArrayForContainerChildren(node, depth, nodesMap); + Ref<Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>> children = buildArrayForContainerChildren(node, depth, nodesMap); if (children->length() > 0) - value->setChildren(children.release()); + value->setChildren(WTFMove(children)); } - if (node->isElementNode()) { - Element* element = toElement(node); - value->setAttributes(buildArrayForElementAttributes(element)); - if (node->isFrameOwnerElement()) { - HTMLFrameOwnerElement* frameOwner = toHTMLFrameOwnerElement(node); - Frame* frame = frameOwner->contentFrame(); + if (is<Element>(*node)) { + Element& element = downcast<Element>(*node); + value->setAttributes(buildArrayForElementAttributes(&element)); + if (is<HTMLFrameOwnerElement>(element)) { + HTMLFrameOwnerElement& frameOwner = downcast<HTMLFrameOwnerElement>(element); + Frame* frame = frameOwner.contentFrame(); if (frame) value->setFrameId(m_pageAgent->frameId(frame)); - Document* doc = frameOwner->contentDocument(); - if (doc) - value->setContentDocument(buildObjectForNode(doc, 0, nodesMap)); + Document* document = frameOwner.contentDocument(); + if (document) + value->setContentDocument(buildObjectForNode(document, 0, nodesMap)); } - if (ShadowRoot* root = element->shadowRoot()) { - RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::Node>> shadowRoots = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::Node>::create(); + if (ShadowRoot* root = element.shadowRoot()) { + auto shadowRoots = Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>::create(); shadowRoots->addItem(buildObjectForNode(root, 0, nodesMap)); - value->setShadowRoots(shadowRoots); + value->setShadowRoots(WTFMove(shadowRoots)); + } + + if (is<HTMLTemplateElement>(element)) + value->setTemplateContent(buildObjectForNode(&downcast<HTMLTemplateElement>(element).content(), 0, nodesMap)); + + if (is<HTMLStyleElement>(element) || (is<HTMLScriptElement>(element) && !element.hasAttributeWithoutSynchronization(HTMLNames::srcAttr))) + value->setContentSecurityPolicyHash(computeContentSecurityPolicySHA256Hash(element)); + + auto state = customElementState(element); + if (state != Inspector::Protocol::DOM::CustomElementState::Builtin) + value->setCustomElementState(state); + + if (element.pseudoId()) { + Inspector::Protocol::DOM::PseudoType pseudoType; + if (pseudoElementType(element.pseudoId(), &pseudoType)) + value->setPseudoType(pseudoType); + } else { + if (auto pseudoElements = buildArrayForPseudoElements(element, nodesMap)) + value->setPseudoElements(WTFMove(pseudoElements)); } -#if ENABLE(TEMPLATE_ELEMENT) - if (element->hasTagName(HTMLNames::templateTag)) - value->setTemplateContent(buildObjectForNode(toHTMLTemplateElement(element)->content(), 0, nodesMap)); -#endif + } else if (is<Document>(*node)) { + Document& document = downcast<Document>(*node); + value->setFrameId(m_pageAgent->frameId(document.frame())); + value->setDocumentURL(documentURLString(&document)); + value->setBaseURL(documentBaseURLString(&document)); + value->setXmlVersion(document.xmlVersion()); + } else if (is<DocumentType>(*node)) { + DocumentType& docType = downcast<DocumentType>(*node); + value->setPublicId(docType.publicId()); + value->setSystemId(docType.systemId()); + } else if (is<Attr>(*node)) { + Attr& attribute = downcast<Attr>(*node); + value->setName(attribute.name()); + value->setValue(attribute.value()); + } else if (is<ShadowRoot>(*node)) { + ShadowRoot& shadowRoot = downcast<ShadowRoot>(*node); + value->setShadowRootType(shadowRootType(shadowRoot.mode())); + } + + // Need to enable AX to get the computed role. + if (!WebCore::AXObjectCache::accessibilityEnabled()) + WebCore::AXObjectCache::enableAccessibility(); - } else if (node->isDocumentNode()) { - Document* document = toDocument(node); - value->setDocumentURL(documentURLString(document)); - value->setBaseURL(documentBaseURLString(document)); - value->setXmlVersion(document->xmlVersion()); - } else if (node->nodeType() == Node::DOCUMENT_TYPE_NODE) { - DocumentType* docType = toDocumentType(node); - value->setPublicId(docType->publicId()); - value->setSystemId(docType->systemId()); - value->setInternalSubset(docType->internalSubset()); - } else if (node->isAttributeNode()) { - Attr* attribute = toAttr(node); - value->setName(attribute->name()); - value->setValue(attribute->value()); + if (AXObjectCache* axObjectCache = node->document().axObjectCache()) { + if (AccessibilityObject* axObject = axObjectCache->getOrCreate(node)) + value->setRole(axObject->computedRoleString()); } - return value.release(); + + return value; } -PassRefPtr<Inspector::TypeBuilder::Array<String>> InspectorDOMAgent::buildArrayForElementAttributes(Element* element) +Ref<Inspector::Protocol::Array<String>> InspectorDOMAgent::buildArrayForElementAttributes(Element* element) { - RefPtr<Inspector::TypeBuilder::Array<String>> attributesValue = Inspector::TypeBuilder::Array<String>::create(); + auto attributesValue = Inspector::Protocol::Array<String>::create(); // Go through all attributes and serialize them. if (!element->hasAttributes()) - return attributesValue.release(); + return attributesValue; for (const Attribute& attribute : element->attributesIterator()) { // Add attribute pair attributesValue->addItem(attribute.name().toString()); attributesValue->addItem(attribute.value()); } - return attributesValue.release(); + return attributesValue; } -PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::Node>> InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap) +Ref<Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>> InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap) { - RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::Node>> children = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::Node>::create(); + auto children = Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>::create(); if (depth == 0) { // Special-case the only text child - pretend that container's children have been requested. Node* firstChild = container->firstChild(); @@ -1338,7 +1465,7 @@ PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::Node>> Ins children->addItem(buildObjectForNode(firstChild, 0, nodesMap)); m_childrenRequested.add(bind(container, nodesMap)); } - return children.release(); + return children; } Node* child = innerFirstChild(container); @@ -1349,29 +1476,46 @@ PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::DOM::Node>> Ins children->addItem(buildObjectForNode(child, depth, nodesMap)); child = innerNextSibling(child); } - return children.release(); + return children; } -PassRefPtr<Inspector::TypeBuilder::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node, const String* objectGroupId) +RefPtr<Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>> InspectorDOMAgent::buildArrayForPseudoElements(const Element& element, NodeToIdMap* nodesMap) { - RefPtr<EventListener> eventListener = registeredEventListener.listener; + PseudoElement* beforeElement = element.beforePseudoElement(); + PseudoElement* afterElement = element.afterPseudoElement(); + if (!beforeElement && !afterElement) + return nullptr; + + auto pseudoElements = Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>::create(); + if (beforeElement) + pseudoElements->addItem(buildObjectForNode(beforeElement, 0, nodesMap)); + if (afterElement) + pseudoElements->addItem(buildObjectForNode(afterElement, 0, nodesMap)); + return WTFMove(pseudoElements); +} + +Ref<Inspector::Protocol::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node, const String* objectGroupId) +{ + Ref<EventListener> eventListener = registeredEventListener.callback(); JSC::ExecState* state = nullptr; JSC::JSObject* handler = nullptr; String body; int lineNumber = 0; + int columnNumber = 0; String scriptID; String sourceName; - if (auto scriptListener = JSEventListener::cast(eventListener.get())) { + if (auto scriptListener = JSEventListener::cast(eventListener.ptr())) { JSC::JSLockHolder lock(scriptListener->isolatedWorld().vm()); state = execStateFromNode(scriptListener->isolatedWorld(), &node->document()); handler = scriptListener->jsFunction(&node->document()); - if (handler) { + if (handler && state) { body = handler->toString(state)->value(state); - if (auto function = JSC::jsDynamicCast<JSC::JSFunction*>(handler)) { - if (!function->isHostFunction()) { + if (auto function = jsDynamicDowncast<JSC::JSFunction*>(state->vm(), handler)) { + if (!function->isHostOrBuiltinFunction()) { if (auto executable = function->jsExecutable()) { - lineNumber = executable->lineNo() - 1; + lineNumber = executable->firstLine() - 1; + columnNumber = executable->startColumn() - 1; scriptID = executable->sourceID() == JSC::SourceProvider::nullID ? emptyString() : String::number(executable->sourceID()); sourceName = executable->sourceURL(); } @@ -1380,26 +1524,349 @@ PassRefPtr<Inspector::TypeBuilder::DOM::EventListener> InspectorDOMAgent::buildO } } - RefPtr<Inspector::TypeBuilder::DOM::EventListener> value = Inspector::TypeBuilder::DOM::EventListener::create() + auto value = Inspector::Protocol::DOM::EventListener::create() .setType(eventType) - .setUseCapture(registeredEventListener.useCapture) + .setUseCapture(registeredEventListener.useCapture()) .setIsAttribute(eventListener->isAttribute()) .setNodeId(pushNodePathToFrontend(node)) - .setHandlerBody(body); + .setHandlerBody(body) + .release(); if (objectGroupId && handler && state) { - InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(state); + InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(state); if (!injectedScript.hasNoValue()) - value->setHandler(injectedScript.wrapObject(Deprecated::ScriptValue(state->vm(), handler), *objectGroupId)); + value->setHandler(injectedScript.wrapObject(handler, *objectGroupId)); } if (!scriptID.isNull()) { - RefPtr<Inspector::TypeBuilder::Debugger::Location> location = Inspector::TypeBuilder::Debugger::Location::create() + auto location = Inspector::Protocol::Debugger::Location::create() .setScriptId(scriptID) - .setLineNumber(lineNumber); - value->setLocation(location.release()); + .setLineNumber(lineNumber) + .release(); + location->setColumnNumber(columnNumber); + value->setLocation(WTFMove(location)); if (!sourceName.isEmpty()) value->setSourceName(sourceName); } - return value.release(); + return value; +} + +void InspectorDOMAgent::processAccessibilityChildren(RefPtr<AccessibilityObject>&& axObject, RefPtr<Inspector::Protocol::Array<int>>&& childNodeIds) +{ + const auto& children = axObject->children(); + if (!children.size()) + return; + + if (!childNodeIds) + childNodeIds = Inspector::Protocol::Array<int>::create(); + + for (const auto& childObject : children) { + if (Node* childNode = childObject->node()) + childNodeIds->addItem(pushNodePathToFrontend(childNode)); + else + processAccessibilityChildren(childObject.copyRef(), childNodeIds.copyRef()); + } +} + +RefPtr<Inspector::Protocol::DOM::AccessibilityProperties> InspectorDOMAgent::buildObjectForAccessibilityProperties(Node* node) +{ + ASSERT(node); + if (!node) + return nullptr; + + if (!WebCore::AXObjectCache::accessibilityEnabled()) + WebCore::AXObjectCache::enableAccessibility(); + + Node* activeDescendantNode = nullptr; + bool busy = false; + auto checked = Inspector::Protocol::DOM::AccessibilityProperties::Checked::False; + RefPtr<Inspector::Protocol::Array<int>> childNodeIds; + RefPtr<Inspector::Protocol::Array<int>> controlledNodeIds; + auto currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::False; + bool exists = false; + bool expanded = false; + bool disabled = false; + RefPtr<Inspector::Protocol::Array<int>> flowedNodeIds; + bool focused = false; + bool ignored = true; + bool ignoredByDefault = false; + auto invalid = Inspector::Protocol::DOM::AccessibilityProperties::Invalid::False; + bool hidden = false; + String label; + bool liveRegionAtomic = false; + RefPtr<Inspector::Protocol::Array<String>> liveRegionRelevant; + auto liveRegionStatus = Inspector::Protocol::DOM::AccessibilityProperties::LiveRegionStatus::Off; + Node* mouseEventNode = nullptr; + RefPtr<Inspector::Protocol::Array<int>> ownedNodeIds; + Node* parentNode = nullptr; + bool pressed = false; + bool readonly = false; + bool required = false; + String role; + bool selected = false; + RefPtr<Inspector::Protocol::Array<int>> selectedChildNodeIds; + bool supportsChecked = false; + bool supportsExpanded = false; + bool supportsLiveRegion = false; + bool supportsPressed = false; + bool supportsRequired = false; + bool supportsFocused = false; + bool isPopupButton = false; + int headingLevel = 0; + unsigned hierarchicalLevel = 0; + unsigned level = 0; + + if (AXObjectCache* axObjectCache = node->document().axObjectCache()) { + if (AccessibilityObject* axObject = axObjectCache->getOrCreate(node)) { + + if (AccessibilityObject* activeDescendant = axObject->activeDescendant()) + activeDescendantNode = activeDescendant->node(); + + // An AX object is "busy" if it or any ancestor has aria-busy="true" set. + AccessibilityObject* current = axObject; + while (!busy && current) { + busy = current->isBusy(); + current = current->parentObject(); + } + + supportsChecked = axObject->supportsChecked(); + if (supportsChecked) { + int checkValue = axObject->checkboxOrRadioValue(); // Element using aria-checked. + if (checkValue == 1) + checked = Inspector::Protocol::DOM::AccessibilityProperties::Checked::True; + else if (checkValue == 2) + checked = Inspector::Protocol::DOM::AccessibilityProperties::Checked::Mixed; + else if (axObject->isChecked()) // Native checkbox. + checked = Inspector::Protocol::DOM::AccessibilityProperties::Checked::True; + } + + processAccessibilityChildren(axObject, WTFMove(childNodeIds)); + + Vector<Element*> controlledElements; + axObject->elementsFromAttribute(controlledElements, aria_controlsAttr); + if (controlledElements.size()) { + controlledNodeIds = Inspector::Protocol::Array<int>::create(); + for (Element* controlledElement : controlledElements) + controlledNodeIds->addItem(pushNodePathToFrontend(controlledElement)); + } + + switch (axObject->ariaCurrentState()) { + case ARIACurrentFalse: + currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::False; + break; + case ARIACurrentPage: + currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::Page; + break; + case ARIACurrentStep: + currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::Step; + break; + case ARIACurrentLocation: + currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::Location; + break; + case ARIACurrentDate: + currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::Date; + break; + case ARIACurrentTime: + currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::Time; + break; + default: + case ARIACurrentTrue: + currentState = Inspector::Protocol::DOM::AccessibilityProperties::Current::True; + break; + } + + disabled = !axObject->isEnabled(); + exists = true; + + supportsExpanded = axObject->supportsExpanded(); + if (supportsExpanded) + expanded = axObject->isExpanded(); + + Vector<Element*> flowedElements; + axObject->elementsFromAttribute(flowedElements, aria_flowtoAttr); + if (flowedElements.size()) { + flowedNodeIds = Inspector::Protocol::Array<int>::create(); + for (Element* flowedElement : flowedElements) + flowedNodeIds->addItem(pushNodePathToFrontend(flowedElement)); + } + + if (is<Element>(*node)) { + supportsFocused = axObject->canSetFocusAttribute(); + if (supportsFocused) + focused = axObject->isFocused(); + } + + ignored = axObject->accessibilityIsIgnored(); + ignoredByDefault = axObject->accessibilityIsIgnoredByDefault(); + + String invalidValue = axObject->invalidStatus(); + if (invalidValue == "false") + invalid = Inspector::Protocol::DOM::AccessibilityProperties::Invalid::False; + else if (invalidValue == "grammar") + invalid = Inspector::Protocol::DOM::AccessibilityProperties::Invalid::Grammar; + else if (invalidValue == "spelling") + invalid = Inspector::Protocol::DOM::AccessibilityProperties::Invalid::Spelling; + else // Future versions of ARIA may allow additional truthy values. Ex. format, order, or size. + invalid = Inspector::Protocol::DOM::AccessibilityProperties::Invalid::True; + + if (axObject->isARIAHidden() || axObject->isDOMHidden()) + hidden = true; + + label = axObject->computedLabel(); + + if (axObject->supportsARIALiveRegion()) { + supportsLiveRegion = true; + liveRegionAtomic = axObject->ariaLiveRegionAtomic(); + + String ariaRelevantAttrValue = axObject->ariaLiveRegionRelevant(); + if (!ariaRelevantAttrValue.isEmpty()) { + // FIXME: Pass enum values rather than strings once unblocked. http://webkit.org/b/133711 + String ariaRelevantAdditions = Inspector::Protocol::InspectorHelpers::getEnumConstantValue(Inspector::Protocol::DOM::LiveRegionRelevant::Additions); + String ariaRelevantRemovals = Inspector::Protocol::InspectorHelpers::getEnumConstantValue(Inspector::Protocol::DOM::LiveRegionRelevant::Removals); + String ariaRelevantText = Inspector::Protocol::InspectorHelpers::getEnumConstantValue(Inspector::Protocol::DOM::LiveRegionRelevant::Text); + liveRegionRelevant = Inspector::Protocol::Array<String>::create(); + const SpaceSplitString& values = SpaceSplitString(ariaRelevantAttrValue, true); + // @aria-relevant="all" is exposed as ["additions","removals","text"], in order. + // This order is controlled in WebCore and expected in WebInspectorUI. + if (values.contains("all")) { + liveRegionRelevant->addItem(ariaRelevantAdditions); + liveRegionRelevant->addItem(ariaRelevantRemovals); + liveRegionRelevant->addItem(ariaRelevantText); + } else { + if (values.contains(ariaRelevantAdditions)) + liveRegionRelevant->addItem(ariaRelevantAdditions); + if (values.contains(ariaRelevantRemovals)) + liveRegionRelevant->addItem(ariaRelevantRemovals); + if (values.contains(ariaRelevantText)) + liveRegionRelevant->addItem(ariaRelevantText); + } + } + + String ariaLive = axObject->ariaLiveRegionStatus(); + if (ariaLive == "assertive") + liveRegionStatus = Inspector::Protocol::DOM::AccessibilityProperties::LiveRegionStatus::Assertive; + else if (ariaLive == "polite") + liveRegionStatus = Inspector::Protocol::DOM::AccessibilityProperties::LiveRegionStatus::Polite; + } + + if (is<AccessibilityNodeObject>(*axObject)) + mouseEventNode = downcast<AccessibilityNodeObject>(*axObject).mouseButtonListener(MouseButtonListenerResultFilter::IncludeBodyElement); + + if (axObject->supportsARIAOwns()) { + Vector<Element*> ownedElements; + axObject->elementsFromAttribute(ownedElements, aria_ownsAttr); + if (ownedElements.size()) { + ownedNodeIds = Inspector::Protocol::Array<int>::create(); + for (Element* ownedElement : ownedElements) + ownedNodeIds->addItem(pushNodePathToFrontend(ownedElement)); + } + } + + if (AccessibilityObject* parentObject = axObject->parentObjectUnignored()) + parentNode = parentObject->node(); + + supportsPressed = axObject->ariaPressedIsPresent(); + if (supportsPressed) + pressed = axObject->isPressed(); + + if (axObject->isTextControl()) + readonly = !axObject->canSetValueAttribute(); + + supportsRequired = axObject->supportsRequiredAttribute(); + if (supportsRequired) + required = axObject->isRequired(); + + role = axObject->computedRoleString(); + selected = axObject->isSelected(); + + AccessibilityObject::AccessibilityChildrenVector selectedChildren; + axObject->selectedChildren(selectedChildren); + if (selectedChildren.size()) { + selectedChildNodeIds = Inspector::Protocol::Array<int>::create(); + for (auto& selectedChildObject : selectedChildren) { + if (Node* selectedChildNode = selectedChildObject->node()) + selectedChildNodeIds->addItem(pushNodePathToFrontend(selectedChildNode)); + } + } + + headingLevel = axObject->headingLevel(); + hierarchicalLevel = axObject->hierarchicalLevel(); + + level = hierarchicalLevel ? hierarchicalLevel : headingLevel; + isPopupButton = axObject->isPopUpButton() || axObject->ariaHasPopup(); + } + } + + Ref<Inspector::Protocol::DOM::AccessibilityProperties> value = Inspector::Protocol::DOM::AccessibilityProperties::create() + .setExists(exists) + .setLabel(label) + .setRole(role) + .setNodeId(pushNodePathToFrontend(node)) + .release(); + + if (exists) { + if (activeDescendantNode) + value->setActiveDescendantNodeId(pushNodePathToFrontend(activeDescendantNode)); + if (busy) + value->setBusy(busy); + if (supportsChecked) + value->setChecked(checked); + if (childNodeIds) + value->setChildNodeIds(childNodeIds); + if (controlledNodeIds) + value->setControlledNodeIds(controlledNodeIds); + if (currentState != Inspector::Protocol::DOM::AccessibilityProperties::Current::False) + value->setCurrent(currentState); + if (disabled) + value->setDisabled(disabled); + if (supportsExpanded) + value->setExpanded(expanded); + if (flowedNodeIds) + value->setFlowedNodeIds(flowedNodeIds); + if (supportsFocused) + value->setFocused(focused); + if (ignored) + value->setIgnored(ignored); + if (ignoredByDefault) + value->setIgnoredByDefault(ignoredByDefault); + if (invalid != Inspector::Protocol::DOM::AccessibilityProperties::Invalid::False) + value->setInvalid(invalid); + if (hidden) + value->setHidden(hidden); + if (supportsLiveRegion) { + value->setLiveRegionAtomic(liveRegionAtomic); + if (liveRegionRelevant->length()) + value->setLiveRegionRelevant(liveRegionRelevant); + value->setLiveRegionStatus(liveRegionStatus); + } + if (mouseEventNode) + value->setMouseEventNodeId(pushNodePathToFrontend(mouseEventNode)); + if (ownedNodeIds) + value->setOwnedNodeIds(ownedNodeIds); + if (parentNode) + value->setParentNodeId(pushNodePathToFrontend(parentNode)); + if (supportsPressed) + value->setPressed(pressed); + if (readonly) + value->setReadonly(readonly); + if (supportsRequired) + value->setRequired(required); + if (selected) + value->setSelected(selected); + if (selectedChildNodeIds) + value->setSelectedChildNodeIds(selectedChildNodeIds); + + // H1 -- H6 always have a headingLevel property that can be complimented by a hierarchicalLevel + // property when aria-level is set on the element, in which case we want to remain calling + // this value the "Heading Level" in the inspector. + // Also, we do not want it to say Hierarchy Level: 0 + if (headingLevel) + value->setHeadingLevel(level); + else if (level) + value->setHierarchyLevel(level); + if (isPopupButton) + value->setIsPopUpButton(isPopupButton); + } + + return WTFMove(value); } Node* InspectorDOMAgent::innerFirstChild(Node* node) @@ -1439,10 +1906,11 @@ unsigned InspectorDOMAgent::innerChildNodeCount(Node* node) Node* InspectorDOMAgent::innerParentNode(Node* node) { - if (node->isDocumentNode()) { - Document* document = toDocument(node); - return document->ownerElement(); - } + ASSERT(node); + if (is<Document>(*node)) + return downcast<Document>(*node).ownerElement(); + if (is<ShadowRoot>(*node)) + return downcast<ShadowRoot>(*node).host(); return node->parentNode(); } @@ -1462,7 +1930,7 @@ void InspectorDOMAgent::mainFrameDOMContentLoaded() void InspectorDOMAgent::didCommitLoad(Document* document) { - Element* frameOwner = document->ownerElement(); + RefPtr<Element> frameOwner = document->ownerElement(); if (!frameOwner) return; @@ -1471,25 +1939,25 @@ void InspectorDOMAgent::didCommitLoad(Document* document) return; // Re-add frame owner element together with its new children. - int parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner)); + int parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner.get())); m_frontendDispatcher->childNodeRemoved(parentId, frameOwnerId); - unbind(frameOwner, &m_documentNodeToIdMap); + unbind(frameOwner.get(), &m_documentNodeToIdMap); - RefPtr<Inspector::TypeBuilder::DOM::Node> value = buildObjectForNode(frameOwner, 0, &m_documentNodeToIdMap); - Node* previousSibling = innerPreviousSibling(frameOwner); + Ref<Inspector::Protocol::DOM::Node> value = buildObjectForNode(frameOwner.get(), 0, &m_documentNodeToIdMap); + Node* previousSibling = innerPreviousSibling(frameOwner.get()); int prevId = previousSibling ? m_documentNodeToIdMap.get(previousSibling) : 0; - m_frontendDispatcher->childNodeInserted(parentId, prevId, value.release()); + m_frontendDispatcher->childNodeInserted(parentId, prevId, WTFMove(value)); } -void InspectorDOMAgent::didInsertDOMNode(Node* node) +void InspectorDOMAgent::didInsertDOMNode(Node& node) { - if (isWhitespace(node)) + if (isWhitespace(&node)) return; // We could be attaching existing subtree. Forget the bindings. - unbind(node, &m_documentNodeToIdMap); + unbind(&node, &m_documentNodeToIdMap); - ContainerNode* parent = node->parentNode(); + ContainerNode* parent = node.parentNode(); if (!parent) return; @@ -1503,19 +1971,19 @@ void InspectorDOMAgent::didInsertDOMNode(Node* node) m_frontendDispatcher->childNodeCountUpdated(parentId, innerChildNodeCount(parent)); } else { // Children have been requested -> return value of a new child. - Node* prevSibling = innerPreviousSibling(node); + Node* prevSibling = innerPreviousSibling(&node); int prevId = prevSibling ? m_documentNodeToIdMap.get(prevSibling) : 0; - RefPtr<Inspector::TypeBuilder::DOM::Node> value = buildObjectForNode(node, 0, &m_documentNodeToIdMap); - m_frontendDispatcher->childNodeInserted(parentId, prevId, value.release()); + Ref<Inspector::Protocol::DOM::Node> value = buildObjectForNode(&node, 0, &m_documentNodeToIdMap); + m_frontendDispatcher->childNodeInserted(parentId, prevId, WTFMove(value)); } } -void InspectorDOMAgent::didRemoveDOMNode(Node* node) +void InspectorDOMAgent::didRemoveDOMNode(Node& node) { - if (isWhitespace(node)) + if (isWhitespace(&node)) return; - ContainerNode* parent = node->parentNode(); + ContainerNode* parent = node.parentNode(); // If parent is not mapped yet -> ignore the event. if (!m_documentNodeToIdMap.contains(parent)) @@ -1528,23 +1996,23 @@ void InspectorDOMAgent::didRemoveDOMNode(Node* node) if (innerChildNodeCount(parent) == 1) m_frontendDispatcher->childNodeCountUpdated(parentId, 0); } else - m_frontendDispatcher->childNodeRemoved(parentId, m_documentNodeToIdMap.get(node)); - unbind(node, &m_documentNodeToIdMap); + m_frontendDispatcher->childNodeRemoved(parentId, m_documentNodeToIdMap.get(&node)); + unbind(&node, &m_documentNodeToIdMap); } -void InspectorDOMAgent::willModifyDOMAttr(Element*, const AtomicString& oldValue, const AtomicString& newValue) +void InspectorDOMAgent::willModifyDOMAttr(Element&, const AtomicString& oldValue, const AtomicString& newValue) { m_suppressAttributeModifiedEvent = (oldValue == newValue); } -void InspectorDOMAgent::didModifyDOMAttr(Element* element, const AtomicString& name, const AtomicString& value) +void InspectorDOMAgent::didModifyDOMAttr(Element& element, const AtomicString& name, const AtomicString& value) { bool shouldSuppressEvent = m_suppressAttributeModifiedEvent; m_suppressAttributeModifiedEvent = false; if (shouldSuppressEvent) return; - int id = boundNodeId(element); + int id = boundNodeId(&element); // If node is not mapped yet -> ignore the event. if (!id) return; @@ -1555,9 +2023,9 @@ void InspectorDOMAgent::didModifyDOMAttr(Element* element, const AtomicString& n m_frontendDispatcher->attributeModified(id, name, value); } -void InspectorDOMAgent::didRemoveDOMAttr(Element* element, const AtomicString& name) +void InspectorDOMAgent::didRemoveDOMAttr(Element& element, const AtomicString& name) { - int id = boundNodeId(element); + int id = boundNodeId(&element); // If node is not mapped yet -> ignore the event. if (!id) return; @@ -1570,68 +2038,74 @@ void InspectorDOMAgent::didRemoveDOMAttr(Element* element, const AtomicString& n void InspectorDOMAgent::styleAttributeInvalidated(const Vector<Element*>& elements) { - RefPtr<Inspector::TypeBuilder::Array<int>> nodeIds = Inspector::TypeBuilder::Array<int>::create(); - for (unsigned i = 0, size = elements.size(); i < size; ++i) { - Element* element = elements.at(i); + auto nodeIds = Inspector::Protocol::Array<int>::create(); + for (auto& element : elements) { int id = boundNodeId(element); // If node is not mapped yet -> ignore the event. if (!id) continue; if (m_domListener) - m_domListener->didModifyDOMAttr(element); + m_domListener->didModifyDOMAttr(*element); nodeIds->addItem(id); } - m_frontendDispatcher->inlineStyleInvalidated(nodeIds.release()); + m_frontendDispatcher->inlineStyleInvalidated(WTFMove(nodeIds)); } -void InspectorDOMAgent::characterDataModified(CharacterData* characterData) +void InspectorDOMAgent::characterDataModified(CharacterData& characterData) { - int id = m_documentNodeToIdMap.get(characterData); + int id = m_documentNodeToIdMap.get(&characterData); if (!id) { // Push text node if it is being created. didInsertDOMNode(characterData); return; } - m_frontendDispatcher->characterDataModified(id, characterData->data()); + m_frontendDispatcher->characterDataModified(id, characterData.data()); } -void InspectorDOMAgent::didInvalidateStyleAttr(Node* node) +void InspectorDOMAgent::didInvalidateStyleAttr(Node& node) { - int id = m_documentNodeToIdMap.get(node); + int id = m_documentNodeToIdMap.get(&node); // If node is not mapped yet -> ignore the event. if (!id) return; if (!m_revalidateStyleAttrTask) - m_revalidateStyleAttrTask = adoptPtr(new RevalidateStyleAttributeTask(this)); - m_revalidateStyleAttrTask->scheduleFor(toElement(node)); + m_revalidateStyleAttrTask = std::make_unique<RevalidateStyleAttributeTask>(this); + m_revalidateStyleAttrTask->scheduleFor(downcast<Element>(&node)); } -void InspectorDOMAgent::didPushShadowRoot(Element* host, ShadowRoot* root) +void InspectorDOMAgent::didPushShadowRoot(Element& host, ShadowRoot& root) { - int hostId = m_documentNodeToIdMap.get(host); + int hostId = m_documentNodeToIdMap.get(&host); if (hostId) - m_frontendDispatcher->shadowRootPushed(hostId, buildObjectForNode(root, 0, &m_documentNodeToIdMap)); + m_frontendDispatcher->shadowRootPushed(hostId, buildObjectForNode(&root, 0, &m_documentNodeToIdMap)); } -void InspectorDOMAgent::willPopShadowRoot(Element* host, ShadowRoot* root) +void InspectorDOMAgent::willPopShadowRoot(Element& host, ShadowRoot& root) { - int hostId = m_documentNodeToIdMap.get(host); - int rootId = m_documentNodeToIdMap.get(root); + int hostId = m_documentNodeToIdMap.get(&host); + int rootId = m_documentNodeToIdMap.get(&root); if (hostId && rootId) m_frontendDispatcher->shadowRootPopped(hostId, rootId); } -void InspectorDOMAgent::frameDocumentUpdated(Frame* frame) +void InspectorDOMAgent::didChangeCustomElementState(Element& element) { - Document* document = frame->document(); + int elementId = m_documentNodeToIdMap.get(&element); + if (!elementId) + return; + + m_frontendDispatcher->customElementStateChanged(elementId, customElementState(element)); +} + +void InspectorDOMAgent::frameDocumentUpdated(Frame& frame) +{ + Document* document = frame.document(); if (!document) return; - Page* page = frame->page(); - ASSERT(page); - if (frame != &page->mainFrame()) + if (!frame.isMainFrame()) return; // Only update the main frame document, nested frame document updates are not required @@ -1639,6 +2113,36 @@ void InspectorDOMAgent::frameDocumentUpdated(Frame* frame) setDocument(document); } +void InspectorDOMAgent::pseudoElementCreated(PseudoElement& pseudoElement) +{ + Element* parent = pseudoElement.hostElement(); + if (!parent) + return; + + int parentId = m_documentNodeToIdMap.get(parent); + if (!parentId) + return; + + pushChildNodesToFrontend(parentId, 1); + m_frontendDispatcher->pseudoElementAdded(parentId, buildObjectForNode(&pseudoElement, 0, &m_documentNodeToIdMap)); +} + +void InspectorDOMAgent::pseudoElementDestroyed(PseudoElement& pseudoElement) +{ + int pseudoElementId = m_documentNodeToIdMap.get(&pseudoElement); + if (!pseudoElementId) + return; + + // If a PseudoElement is bound, its parent element must have been bound. + Element* parent = pseudoElement.hostElement(); + ASSERT(parent); + int parentId = m_documentNodeToIdMap.get(parent); + ASSERT(parentId); + + unbind(&pseudoElement, &m_documentNodeToIdMap); + m_frontendDispatcher->pseudoElementRemoved(parentId, pseudoElementId); +} + Node* InspectorDOMAgent::nodeForPath(const String& path) { // The path is of form "1,HTML,2,BODY,1,DIV" @@ -1647,7 +2151,7 @@ Node* InspectorDOMAgent::nodeForPath(const String& path) Node* node = m_document.get(); Vector<String> pathTokens; - path.split(",", false, pathTokens); + path.split(',', false, pathTokens); if (!pathTokens.size()) return 0; for (size_t i = 0; i < pathTokens.size() - 1; i += 2) { @@ -1672,67 +2176,67 @@ Node* InspectorDOMAgent::nodeForPath(const String& path) Node* InspectorDOMAgent::nodeForObjectId(const String& objectId) { - InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId); - Deprecated::ScriptValue value = injectedScript.findObjectById(objectId); - return InspectorDOMAgent::scriptValueAsNode(value); + InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(objectId); + if (injectedScript.hasNoValue()) + return nullptr; + + return scriptValueAsNode(injectedScript.findObjectById(objectId)); } -void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString* errorString, const String& path, int* nodeId) +void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString& errorString, const String& path, int* nodeId) { if (Node* node = nodeForPath(path)) *nodeId = pushNodePathToFrontend(node); else - *errorString = "No node with given path found"; + errorString = ASCIILiteral("No node with given path found"); } -void InspectorDOMAgent::pushNodeByBackendIdToFrontend(ErrorString* errorString, BackendNodeId backendNodeId, int* nodeId) +void InspectorDOMAgent::pushNodeByBackendIdToFrontend(ErrorString& errorString, BackendNodeId backendNodeId, int* nodeId) { - if (!m_backendIdToNode.contains(backendNodeId)) { - *errorString = "No node with given backend id found"; + auto iterator = m_backendIdToNode.find(backendNodeId); + if (iterator == m_backendIdToNode.end()) { + errorString = ASCIILiteral("No node with given backend id found"); return; } - Node* node = m_backendIdToNode.get(backendNodeId).first; - String nodeGroup = m_backendIdToNode.get(backendNodeId).second; + Node* node = iterator->value.first; + String nodeGroup = iterator->value.second; + *nodeId = pushNodePathToFrontend(node); - if (nodeGroup == "") { - m_backendIdToNode.remove(backendNodeId); + if (nodeGroup.isEmpty()) { + m_backendIdToNode.remove(iterator); + // FIXME: We really do the following only when nodeGroup is the empty string? Seems wrong. + ASSERT(m_nodeGroupToBackendIdMap.contains(nodeGroup)); m_nodeGroupToBackendIdMap.find(nodeGroup)->value.remove(node); } } -PassRefPtr<Inspector::TypeBuilder::Runtime::RemoteObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup) +RefPtr<Inspector::Protocol::Runtime::RemoteObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup) { - Frame* frame = node->document().frame(); + auto* frame = node->document().frame(); if (!frame) - return 0; + return nullptr; - JSC::ExecState* scriptState = mainWorldExecState(frame); - InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState); + auto& state = *mainWorldExecState(frame); + auto injectedScript = m_injectedScriptManager.injectedScriptFor(&state); if (injectedScript.hasNoValue()) - return 0; + return nullptr; - return injectedScript.wrapObject(InspectorDOMAgent::nodeAsScriptValue(scriptState, node), objectGroup); + return injectedScript.wrapObject(nodeAsScriptValue(state, node), objectGroup); } -Node* InspectorDOMAgent::scriptValueAsNode(Deprecated::ScriptValue value) +Node* InspectorDOMAgent::scriptValueAsNode(JSC::JSValue value) { - if (!value.isObject() || value.isNull()) + if (!value || !value.isObject()) return nullptr; - - return toNode(value.jsValue()); + return JSNode::toWrapped(*value.getObject()->vm(), value.getObject()); } -Deprecated::ScriptValue InspectorDOMAgent::nodeAsScriptValue(JSC::ExecState* state, Node* node) +JSC::JSValue InspectorDOMAgent::nodeAsScriptValue(JSC::ExecState& state, Node* node) { - if (!shouldAllowAccessToNode(state, node)) - return Deprecated::ScriptValue(state->vm(), JSC::jsNull()); - - JSC::JSLockHolder lock(state); - return Deprecated::ScriptValue(state->vm(), toJS(state, deprecatedGlobalObjectForPrototype(state), node)); + JSC::JSLockHolder lock(&state); + return toJS(&state, deprecatedGlobalObjectForPrototype(&state), BindingSecurity::checkSecurityForNode(state, node)); } } // namespace WebCore - -#endif // ENABLE(INSPECTOR) |