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); |