Index: third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp |
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp |
index bf6db7c68e5d0e4a4668cb857a642c318dde2334..c02151fa90407b36ee8d2c2c3a97e1f41638a982 100644 |
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp |
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp |
@@ -52,10 +52,12 @@ |
#include "core/css/StyleSheetList.h" |
#include "core/css/parser/CSSParser.h" |
#include "core/css/resolver/StyleResolver.h" |
+#include "core/dom/DOMNodeIds.h" |
#include "core/dom/Node.h" |
#include "core/dom/StyleChangeReason.h" |
#include "core/dom/StyleEngine.h" |
#include "core/dom/Text.h" |
+#include "core/dom/shadow/ElementShadow.h" |
#include "core/frame/FrameView.h" |
#include "core/frame/LocalFrame.h" |
#include "core/html/HTMLFrameOwnerElement.h" |
@@ -286,6 +288,16 @@ bool getColorsFromRect(LayoutRect rect, |
return foundOpaqueColor; |
} |
+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(); |
+} |
+ |
} // namespace |
namespace CSSAgentState { |
@@ -340,6 +352,42 @@ class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action { |
} |
}; |
+struct InspectorCSSAgent::VectorStringHashTraits |
+ : public WTF::GenericHashTraits<Vector<String>> { |
+ static unsigned hash(const Vector<String>& vec) { |
+ unsigned h = DefaultHash<String>::Hash::hash(vec[0]); |
+ for (size_t i = 1; i < vec.size(); i++) { |
+ h = WTF::hashInts(h, DefaultHash<String>::Hash::hash(vec[i])); |
+ } |
+ return h; |
+ } |
+ |
+ static bool equal(const Vector<String>& a, const Vector<String>& b) { |
+ if (a.size() != b.size()) |
+ return false; |
+ for (size_t i = 0; i < a.size(); i++) { |
+ if (a[i] != b[i]) |
+ return false; |
+ } |
+ return true; |
+ } |
+ |
+ static void constructDeletedValue(Vector<String>& vec, bool) { |
+ vec.clear(); |
+ vec.append(String(WTF::HashTableDeletedValue)); |
+ } |
+ |
+ static bool isDeletedValue(const Vector<String>& vec) { |
+ return !vec.isEmpty() && vec[0].isHashTableDeletedValue(); |
+ } |
+ |
+ static bool isEmptyValue(const Vector<String>& vec) { return vec.isEmpty(); } |
+ |
+ static const bool emptyValueIsZero = false; |
+ static const bool safeToCompareToEmptyOrDeleted = false; |
+ static const bool hasIsEmptyValueFunction = true; |
+}; |
+ |
class InspectorCSSAgent::SetStyleSheetTextAction final |
: public InspectorCSSAgent::StyleSheetAction { |
WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction); |
@@ -2290,6 +2338,142 @@ void InspectorCSSAgent::getBackgroundColors( |
result->fromJust()->addItem(color.serializedAsCSSComponentValue()); |
} |
+void InspectorCSSAgent::getLayoutTreeAndStyles( |
+ ErrorString* errorString, |
+ std::unique_ptr<protocol::Array<String>> styleWhitelist, |
+ std::unique_ptr<protocol::Array<protocol::CSS::LayoutTreeNode>>* |
+ layoutTreeNodes, |
+ std::unique_ptr<protocol::Array<protocol::CSS::ComputedStyle>>* |
+ computedStyles) { |
+ m_domAgent->document()->updateStyleAndLayoutTree(); |
+ |
+ // Look up the CSSPropertyIDs for each entry in |styleWhitelist|. |
+ Vector<std::pair<String, CSSPropertyID>> cssPropertyWhitelist; |
+ for (size_t i = 0; i < styleWhitelist->length(); i++) { |
+ CSSPropertyID propertyId = cssPropertyID(styleWhitelist->get(i)); |
+ if (propertyId == CSSPropertyInvalid) |
+ continue; |
+ cssPropertyWhitelist.append( |
+ std::make_pair(styleWhitelist->get(i), propertyId)); |
+ } |
+ |
+ *layoutTreeNodes = protocol::Array<protocol::CSS::LayoutTreeNode>::create(); |
+ *computedStyles = protocol::Array<protocol::CSS::ComputedStyle>::create(); |
+ |
+ ComputedStylesMap styleToIndexMap; |
+ visitLayoutTreeNodes(m_domAgent->document(), *layoutTreeNodes->get(), |
+ cssPropertyWhitelist, styleToIndexMap, |
+ *computedStyles->get()); |
+} |
+ |
+int InspectorCSSAgent::getStyleIndexForNode( |
+ Node* node, |
+ const Vector<std::pair<String, CSSPropertyID>>& cssPropertyWhitelist, |
+ ComputedStylesMap& styleToIndexMap, |
+ protocol::Array<protocol::CSS::ComputedStyle>& computedStyles) { |
+ CSSComputedStyleDeclaration* computedStyleInfo = |
+ CSSComputedStyleDeclaration::create(node, true); |
+ |
+ Vector<String> style; |
+ for (const auto& pair : cssPropertyWhitelist) { |
+ style.append(computedStyleInfo->getPropertyValue(pair.second)); |
+ } |
+ |
+ ComputedStylesMap::iterator it = styleToIndexMap.find(style); |
+ if (it != styleToIndexMap.end()) |
+ return it->value; |
+ |
+ // It's a distinct style, so append to |computedStyles|. |
+ std::unique_ptr<protocol::Array<protocol::CSS::CSSComputedStyleProperty>> |
+ styleProperties = |
+ protocol::Array<protocol::CSS::CSSComputedStyleProperty>::create(); |
+ for (size_t i = 0; i < style.size(); i++) { |
+ styleProperties->addItem(protocol::CSS::CSSComputedStyleProperty::create() |
+ .setName(cssPropertyWhitelist[i].first) |
+ .setValue(style[i]) |
+ .build()); |
+ } |
+ computedStyles.addItem(protocol::CSS::ComputedStyle::create() |
+ .setProperties(std::move(styleProperties)) |
+ .build()); |
+ |
+ size_t index = styleToIndexMap.size(); |
+ styleToIndexMap.add(std::move(style), index); |
+ return index; |
+} |
+ |
+void InspectorCSSAgent::visitLayoutTreeNodes( |
+ Node* node, |
+ protocol::Array<protocol::CSS::LayoutTreeNode>& layoutTreeNodes, |
+ const Vector<std::pair<String, CSSPropertyID>>& cssPropertyWhitelist, |
+ ComputedStylesMap& styleToIndexMap, |
+ protocol::Array<protocol::CSS::ComputedStyle>& computedStyles) { |
+ for (; node; node = NodeTraversal::next(*node)) { |
+ // Visit shadow dom nodes. |
+ if (node->isElementNode()) { |
+ const Element* element = toElement(node); |
+ ElementShadow* elementShadow = element->shadow(); |
+ if (elementShadow) { |
+ visitLayoutTreeNodes(&elementShadow->youngestShadowRoot(), |
+ layoutTreeNodes, cssPropertyWhitelist, |
+ styleToIndexMap, computedStyles); |
+ } |
+ } |
+ |
+ // Pierce iframe boundaries. |
+ if (node->isFrameOwnerElement()) { |
+ Document* contentDocument = |
+ toHTMLFrameOwnerElement(node)->contentDocument(); |
+ contentDocument->updateStyleAndLayoutTree(); |
+ visitLayoutTreeNodes(contentDocument->documentElement(), layoutTreeNodes, |
+ cssPropertyWhitelist, styleToIndexMap, |
+ computedStyles); |
+ } |
+ |
+ LayoutObject* layoutObject = node->layoutObject(); |
+ if (!layoutObject) |
+ continue; |
+ |
+ int backendNodeId = DOMNodeIds::idForNode(node); |
+ std::unique_ptr<protocol::CSS::LayoutTreeNode> layoutTreeNode = |
+ protocol::CSS::LayoutTreeNode::create() |
+ .setBackendNodeId(backendNodeId) |
+ .setStyleIndex(getStyleIndexForNode( |
+ node, cssPropertyWhitelist, styleToIndexMap, computedStyles)) |
+ .setBoundingBox(buildRectForFloatRect( |
+ node->isElementNode() |
+ ? FloatRect(toElement(node)->boundsInViewport()) |
+ : layoutObject->absoluteBoundingBoxRect())) |
+ .build(); |
+ |
+ if (layoutObject->isText()) { |
+ LayoutText* layoutText = toLayoutText(layoutObject); |
+ layoutTreeNode->setLayoutText(layoutText->text()); |
+ if (layoutText->hasTextBoxes()) { |
+ std::unique_ptr<protocol::Array<protocol::CSS::InlineTextBox>> |
+ inlineTextNodes = |
+ protocol::Array<protocol::CSS::InlineTextBox>::create(); |
+ for (const InlineTextBox* textBox = layoutText->firstTextBox(); textBox; |
+ textBox = textBox->nextTextBox()) { |
+ FloatRect localCoordsTextBoxRect(textBox->calculateBoundaries()); |
+ FloatRect absoluteCoordsTextBoxRect = |
+ layoutObject->localToAbsoluteQuad(localCoordsTextBoxRect) |
+ .boundingBox(); |
+ inlineTextNodes->addItem(protocol::CSS::InlineTextBox::create() |
+ .setStartCharacterIndex(textBox->start()) |
+ .setNumCharacters(textBox->len()) |
+ .setBoundingBox(buildRectForFloatRect( |
+ absoluteCoordsTextBoxRect)) |
+ .build()); |
+ } |
+ layoutTreeNode->setInlineTextNodes(std::move(inlineTextNodes)); |
+ } |
+ } |
+ |
+ layoutTreeNodes.addItem(std::move(layoutTreeNode)); |
+ } |
+} |
+ |
DEFINE_TRACE(InspectorCSSAgent) { |
visitor->trace(m_domAgent); |
visitor->trace(m_inspectedFrames); |