 Chromium Code Reviews
 Chromium Code Reviews Issue 2346853002:
  Add a DOM.getLayoutTreeNodes devtools command  (Closed)
    
  
    Issue 2346853002:
  Add a DOM.getLayoutTreeNodes devtools command  (Closed) 
  | 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 0ceb294c59525ae7a89873664d29373976394f87..0e84a8739a25a05b9db64f193acfbed5496abe4a 100644 | 
| --- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp | 
| +++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp | 
| @@ -67,7 +67,9 @@ | 
| #include "core/inspector/InspectorHistory.h" | 
| #include "core/inspector/V8InspectorString.h" | 
| #include "core/layout/HitTestResult.h" | 
| +#include "core/layout/LayoutInline.h" | 
| #include "core/layout/api/LayoutViewItem.h" | 
| +#include "core/layout/line/InlineTextBox.h" | 
| #include "core/loader/DocumentLoader.h" | 
| #include "core/page/FrameTree.h" | 
| #include "core/page/Page.h" | 
| @@ -136,8 +138,36 @@ v8::Local<v8::Value> nodeV8Value(v8::Local<v8::Context> context, Node* node) | 
| return toV8(node, context->Global(), isolate); | 
| } | 
| +std::unique_ptr<protocol::DOM::Rect> buildRectForFloatRect(const FloatRect& rect) | 
| +{ | 
| + return protocol::DOM::Rect::create() | 
| + .setX(rect.x()) | 
| + .setY(rect.y()) | 
| + .setWidth(rect.width()) | 
| + .setHeight(rect.height()) | 
| + .build(); | 
| +} | 
| + | 
| +FloatRect buildAbsoluteBoundingBox(LayoutObject* layoutObject) | 
| 
esprehn
2016/09/28 04:02:49
I think you want to use boundsInViewport() from th
 
alex clarke (OOO till 29th)
2016/09/28 17:15:20
Done.
 | 
| +{ | 
| + if (layoutObject->isText()) { | 
| + FloatRect localRect(toLayoutText(layoutObject)->linesBoundingBox()); | 
| + return layoutObject->localToAbsoluteQuad(localRect).boundingBox(); | 
| + } | 
| + if (layoutObject->isLayoutInline()) { | 
| + FloatRect localRect(toLayoutInline(layoutObject)->linesBoundingBox()); | 
| + return layoutObject->localToAbsoluteQuad(localRect).boundingBox(); | 
| + } | 
| + if (layoutObject->isBox()) { | 
| + FloatRect localRect(toLayoutBox(layoutObject)->borderBoxRect()); | 
| + return layoutObject->localToAbsoluteQuad(localRect).boundingBox(); | 
| + } | 
| + return layoutObject->absoluteBoundingBoxRect(); | 
| +} | 
| + | 
| } // namespace | 
| + | 
| class InspectorRevalidateDOMTask final : public GarbageCollectedFinalized<InspectorRevalidateDOMTask> { | 
| public: | 
| explicit InspectorRevalidateDOMTask(InspectorDOMAgent*); | 
| @@ -529,6 +559,67 @@ void InspectorDOMAgent::getDocument(ErrorString* errorString, std::unique_ptr<pr | 
| *root = buildObjectForNode(m_document.get(), 2, m_documentNodeToIdMap.get()); | 
| } | 
| +void InspectorDOMAgent::getLayoutTreeNodes(ErrorString* errorString, std::unique_ptr<protocol::Array<protocol::DOM::LayoutTreeNode>>* layoutTreeNodes) | 
| +{ | 
| + layoutTreeNodes->reset(new protocol::Array<protocol::DOM::LayoutTreeNode>); | 
| + | 
| + std::vector<Node*> unvisited; // Neither WTF::Vector or HeapVector allow Node* :( | 
| 
esprehn
2016/09/28 04:02:49
HeapVector<Member<Node>>, you probably want a big
 
alex clarke (OOO till 29th)
2016/09/28 17:15:20
Done.
 | 
| + unvisited.push_back(m_document.get()); | 
| + | 
| + while (!unvisited.empty()) { | 
| 
esprehn
2016/09/28 04:02:49
this is very strange to put everything into a vect
 
alex clarke (OOO till 29th)
2016/09/28 17:15:20
Done.
 | 
| + Node* node = unvisited.back(); | 
| + unvisited.pop_back(); | 
| + | 
| + // Visit shadow dom nodes. | 
| + if (node->isElementNode()) { | 
| + const Element* element = toElement(node); | 
| + ElementShadow* elementShadow = element->shadow(); | 
| + if (elementShadow) | 
| + unvisited.push_back(&elementShadow->youngestShadowRoot()); | 
| + } | 
| + | 
| + // Pierce iframe boundaries. | 
| + if (node->isFrameOwnerElement()) { | 
| + unvisited.push_back(toHTMLFrameOwnerElement(node)->contentDocument()->documentElement()); | 
| + } | 
| + | 
| + for (Node* child = innerFirstChild(node); child; child = innerNextSibling(child)) { | 
| + unvisited.push_back(child); | 
| + } | 
| + | 
| + LayoutObject* layoutObject = node->layoutObject(); | 
| + if (!layoutObject) | 
| + continue; | 
| + | 
| + int backendNodeId = DOMNodeIds::idForNode(node); | 
| + std::unique_ptr<protocol::DOM::LayoutTreeNode> layoutTreeNode = | 
| + protocol::DOM::LayoutTreeNode::create() | 
| + .setBackendNodeId(backendNodeId) | 
| + .setBoundingBox(buildRectForFloatRect(buildAbsoluteBoundingBox(layoutObject))) | 
| + .build(); | 
| + | 
| + if (layoutObject->isText()) { | 
| + LayoutText* layoutText = toLayoutText(layoutObject); | 
| + layoutTreeNode->setLayoutText(layoutText->text()); | 
| + if (layoutText->hasTextBoxes()) { | 
| + std::unique_ptr<protocol::Array<protocol::DOM::InlineTextBox>> inlineTextNodes(new protocol::Array<protocol::DOM::InlineTextBox>()); | 
| + for (const InlineTextBox* itb = layoutText->firstTextBox(); itb; itb = itb->nextTextBox()) { | 
| 
esprehn
2016/09/28 04:02:49
box or textBox
 
alex clarke (OOO till 29th)
2016/09/28 17:15:20
Done.
 | 
| + FloatRect localItbRect(itb->calculateBoundaries()); | 
| + FloatRect absoluteItbRect = layoutObject->localToAbsoluteQuad(localItbRect).boundingBox(); | 
| 
esprehn
2016/09/28 04:02:49
what is Itb? Don't abbreciate in blink
 
alex clarke (OOO till 29th)
2016/09/28 17:15:20
Done.
 | 
| + inlineTextNodes->addItem( | 
| + protocol::DOM::InlineTextBox::create() | 
| + .setText(layoutText->text().substring(itb->start(), itb->len()).utf8().data()) | 
| 
esprehn
2016/09/28 04:02:49
this is allocating tons of strings and will be slo
 
alex clarke (OOO till 29th)
2016/09/28 17:15:20
We don't really need the substring, the offset and
 | 
| + .setBoundingBox(buildRectForFloatRect(absoluteItbRect)) | 
| + .build()); | 
| + } | 
| + layoutTreeNode->setInlineTextNodes(std::move(inlineTextNodes)); | 
| + } | 
| + } | 
| + | 
| + (*layoutTreeNodes)->addItem(std::move(layoutTreeNode)); | 
| + } | 
| +} | 
| + | 
| void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId, int depth) | 
| { | 
| Node* node = nodeForId(nodeId); |