Index: third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp |
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp |
index 5412baed6b920b849264a4b8eff25754b339e212..c57637994f6d9add95a77cd4317b6145724d38fc 100644 |
--- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp |
+++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp |
@@ -496,6 +496,30 @@ Response InspectorDOMAgent::getDocument( |
return Response::OK(); |
} |
+Response InspectorDOMAgent::getFlatDocument( |
+ Maybe<int> depth, |
+ Maybe<bool> pierce, |
+ std::unique_ptr<protocol::Array<protocol::DOM::Node>>* nodes) { |
+ // Backward compatibility. Mark agent as enabled when it requests document. |
+ if (!enabled()) |
+ innerEnable(); |
+ |
+ if (!m_document) |
+ return Response::Error("Document is not available"); |
+ |
+ discardFrontendBindings(); |
+ |
+ int sanitizedDepth = depth.fromMaybe(2); |
Sami
2017/01/17 17:57:43
The comment says the default is 1. Should this be
alex clarke (OOO till 29th)
2017/01/18 16:31:08
Just copying the above - I assume that's right?
Sami
2017/01/18 18:10:46
Ah, I see. A little surprising to me at least :)
|
+ if (sanitizedDepth == -1) |
+ sanitizedDepth = INT_MAX; |
+ |
+ nodes->reset(new protocol::Array<protocol::DOM::Node>()); |
+ buildFlatObjectsForNode(m_document.get(), sanitizedDepth, |
+ pierce.fromMaybe(false), m_documentNodeToIdMap.get(), |
+ nodes->get()); |
+ return Response::OK(); |
+} |
+ |
void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId, |
int depth, |
bool pierce) { |
@@ -1691,6 +1715,191 @@ std::unique_ptr<protocol::DOM::Node> InspectorDOMAgent::buildObjectForNode( |
return value; |
} |
+void InspectorDOMAgent::buildFlatObjectsForNode( |
+ Node* node, |
+ int depth, |
+ bool pierce, |
+ NodeToIdMap* nodesMap, |
+ protocol::Array<protocol::DOM::Node>* result) { |
+ int id = bind(node, nodesMap); |
Sami
2017/01/17 17:57:43
Are we missing a termination condition on |depth|
alex clarke (OOO till 29th)
2017/01/18 16:31:08
Acknowledged.
|
+ String localName; |
+ String nodeValue; |
+ |
+ switch (node->getNodeType()) { |
pfeldman
2017/01/17 18:34:58
Can we extract some (all) code here to be reused w
alex clarke (OOO till 29th)
2017/01/18 16:31:08
Done.
|
+ case Node::kTextNode: |
+ case Node::kCommentNode: |
+ case Node::kCdataSectionNode: |
+ nodeValue = node->nodeValue(); |
+ if (nodeValue.length() > maxTextSize) |
+ nodeValue = nodeValue.left(maxTextSize) + ellipsisUChar; |
+ break; |
+ case Node::kAttributeNode: |
+ localName = toAttr(node)->localName(); |
+ break; |
+ case Node::kElementNode: |
+ localName = toElement(node)->localName(); |
+ break; |
+ default: |
+ break; |
+ } |
+ |
+ std::unique_ptr<protocol::DOM::Node> value = |
+ protocol::DOM::Node::create() |
+ .setNodeId(id) |
+ .setBackendNodeId(DOMNodeIds::idForNode(node)) |
+ .setNodeType(static_cast<int>(node->getNodeType())) |
+ .setNodeName(node->nodeName()) |
+ .setLocalName(localName) |
+ .setNodeValue(nodeValue) |
+ .build(); |
+ |
+ if (node->isSVGElement()) |
+ value->setIsSVG(true); |
+ |
+ bool forcePushChildren = false; |
+ if (node->isElementNode()) { |
+ Element* element = toElement(node); |
+ value->setAttributes(buildArrayForElementAttributes(element)); |
+ |
+ if (node->isFrameOwnerElement()) { |
+ HTMLFrameOwnerElement* frameOwner = toHTMLFrameOwnerElement(node); |
+ if (LocalFrame* frame = frameOwner->contentFrame() && |
+ frameOwner->contentFrame()->isLocalFrame() |
+ ? toLocalFrame(frameOwner->contentFrame()) |
+ : nullptr) |
+ value->setFrameId(IdentifiersFactory::frameId(frame)); |
+ if (Document* doc = frameOwner->contentDocument()) { |
+ size_t nextIndex = result->length(); |
+ buildFlatObjectsForNode(doc, pierce ? depth : 0, pierce, nodesMap, |
+ result); |
+ value->setContentDocument(minimalCopy(result->get(nextIndex))); |
+ } |
+ } |
+ |
+ if (node->parentNode() && node->parentNode()->isDocumentNode()) { |
+ LocalFrame* frame = node->document().frame(); |
+ if (frame) |
+ value->setFrameId(IdentifiersFactory::frameId(frame)); |
+ } |
+ |
+ ElementShadow* shadow = element->shadow(); |
+ if (shadow) { |
+ std::unique_ptr<protocol::Array<protocol::DOM::Node>> shadowRoots = |
+ protocol::Array<protocol::DOM::Node>::create(); |
+ for (ShadowRoot* root = &shadow->youngestShadowRoot(); root; |
+ root = root->olderShadowRoot()) { |
+ size_t nextIndex = result->length(); |
+ buildFlatObjectsForNode(root, pierce ? depth : 0, pierce, nodesMap, |
+ result); |
+ shadowRoots->addItem(minimalCopy(result->get(nextIndex))); |
+ } |
+ value->setShadowRoots(std::move(shadowRoots)); |
+ forcePushChildren = true; |
+ } |
+ |
+ if (isHTMLLinkElement(*element)) { |
+ HTMLLinkElement& linkElement = toHTMLLinkElement(*element); |
+ if (linkElement.isImport() && linkElement.import() && |
+ innerParentNode(linkElement.import()) == linkElement) { |
+ value->setImportedDocument( |
+ buildObjectForNode(linkElement.import(), 0, pierce, nodesMap)); |
+ } |
+ forcePushChildren = true; |
+ } |
+ |
+ if (isHTMLTemplateElement(*element)) { |
+ value->setTemplateContent(buildObjectForNode( |
+ toHTMLTemplateElement(*element).content(), 0, pierce, nodesMap)); |
+ forcePushChildren = true; |
+ } |
+ |
+ if (element->getPseudoId()) { |
+ protocol::DOM::PseudoType pseudoType; |
+ if (InspectorDOMAgent::getPseudoElementType(element->getPseudoId(), |
+ &pseudoType)) |
+ value->setPseudoType(pseudoType); |
+ } else { |
+ std::unique_ptr<protocol::Array<protocol::DOM::Node>> pseudoElements = |
+ buildArrayForPseudoElements(element, nodesMap); |
+ if (pseudoElements) { |
+ value->setPseudoElements(std::move(pseudoElements)); |
+ forcePushChildren = true; |
+ } |
+ if (!element->ownerDocument()->xmlVersion().isEmpty()) |
+ value->setXmlVersion(element->ownerDocument()->xmlVersion()); |
+ } |
+ |
+ if (element->isInsertionPoint()) { |
+ value->setDistributedNodes( |
+ buildArrayForDistributedNodes(toInsertionPoint(element))); |
+ forcePushChildren = true; |
+ } |
+ if (isHTMLSlotElement(*element)) { |
+ value->setDistributedNodes( |
+ buildDistributedNodesForSlot(toHTMLSlotElement(element))); |
+ forcePushChildren = true; |
+ } |
+ } else if (node->isDocumentNode()) { |
+ Document* document = toDocument(node); |
+ value->setDocumentURL(documentURLString(document)); |
+ value->setBaseURL(documentBaseURLString(document)); |
+ value->setXmlVersion(document->xmlVersion()); |
+ } else if (node->isDocumentTypeNode()) { |
+ DocumentType* docType = toDocumentType(node); |
+ value->setPublicId(docType->publicId()); |
+ value->setSystemId(docType->systemId()); |
+ } else if (node->isAttributeNode()) { |
+ Attr* attribute = toAttr(node); |
+ value->setName(attribute->name()); |
+ value->setValue(attribute->value()); |
+ } else if (node->isShadowRoot()) { |
+ value->setShadowRootType(shadowRootType(toShadowRoot(node))); |
+ } |
+ |
+ if (node->isContainerNode()) { |
+ int nodeCount = innerChildNodeCount(node); |
+ value->setChildNodeCount(nodeCount); |
+ if (nodesMap == m_documentNodeToIdMap) |
+ m_cachedChildCount.set(id, nodeCount); |
+ if (forcePushChildren && !depth) |
+ depth = 1; |
+ |
+ std::unique_ptr<protocol::Array<protocol::DOM::Node>> children( |
+ new protocol::Array<protocol::DOM::Node>); |
+ |
+ Node* child = innerFirstChild(node); |
+ m_childrenRequested.add(bind(node, nodesMap)); |
+ |
+ while (child) { |
+ size_t nextIndex = result->length(); |
+ buildFlatObjectsForNode(child, depth - 1, pierce, nodesMap, result); |
+ children->addItem(minimalCopy(result->get(nextIndex))); |
+ child = innerNextSibling(child); |
+ } |
+ |
+ if (children->length() > 0 || |
+ depth) // Push children along with shadow in any case. |
+ value->setChildren(std::move(children)); |
+ } |
+ |
+ result->addItem(std::move(value)); |
+} |
+ |
+std::unique_ptr<protocol::DOM::Node> InspectorDOMAgent::minimalCopy( |
+ protocol::DOM::Node* node) const { |
+ // This is intended for use by buildFlatObjectsForNode where a Node's shadow |
+ // nodes, child nodes etc only point to the ID of the real full object which |
+ // is returned in the array of nodes. |
+ return protocol::DOM::Node::create() |
+ .setNodeId(node->getNodeId()) |
+ .setBackendNodeId(node->getBackendNodeId()) |
+ .setNodeType(node->getNodeType()) |
+ .setNodeName("") |
+ .setLocalName("") |
+ .setNodeValue("") |
+ .build(); |
+} |
+ |
std::unique_ptr<protocol::Array<String>> |
InspectorDOMAgent::buildArrayForElementAttributes(Element* element) { |
std::unique_ptr<protocol::Array<String>> attributesValue = |