summaryrefslogtreecommitdiffstats
path: root/WebCore/inspector/InspectorCSSAgent.cpp
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-10-22 13:02:20 +0100
committerBen Murdoch <benm@google.com>2010-10-26 15:21:41 +0100
commita94275402997c11dd2e778633dacf4b7e630a35d (patch)
treee66f56c67e3b01f22c9c23cd932271ee9ac558ed /WebCore/inspector/InspectorCSSAgent.cpp
parent09e26c78506587b3f5d930d7bc72a23287ffbec0 (diff)
downloadexternal_webkit-a94275402997c11dd2e778633dacf4b7e630a35d.zip
external_webkit-a94275402997c11dd2e778633dacf4b7e630a35d.tar.gz
external_webkit-a94275402997c11dd2e778633dacf4b7e630a35d.tar.bz2
Merge WebKit at r70209: Initial merge by Git
Change-Id: Id23a68efa36e9d1126bcce0b137872db00892c8e
Diffstat (limited to 'WebCore/inspector/InspectorCSSAgent.cpp')
-rw-r--r--WebCore/inspector/InspectorCSSAgent.cpp649
1 files changed, 649 insertions, 0 deletions
diff --git a/WebCore/inspector/InspectorCSSAgent.cpp b/WebCore/inspector/InspectorCSSAgent.cpp
new file mode 100644
index 0000000..e0fab85
--- /dev/null
+++ b/WebCore/inspector/InspectorCSSAgent.cpp
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 2010, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorCSSAgent.h"
+
+#if ENABLE(INSPECTOR)
+
+#include "CSSComputedStyleDeclaration.h"
+#include "CSSMutableStyleDeclaration.h"
+#include "CSSPropertyNames.h"
+#include "CSSPropertySourceData.h"
+#include "CSSRule.h"
+#include "CSSRuleList.h"
+#include "CSSStyleRule.h"
+#include "CSSStyleSelector.h"
+#include "CSSStyleSheet.h"
+#include "DOMWindow.h"
+#include "HTMLHeadElement.h"
+#include "InspectorDOMAgent.h"
+#include "InspectorFrontend.h"
+#include "InspectorValues.h"
+#include "Node.h"
+#include "StyleSheetList.h"
+
+#include <wtf/HashSet.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/Vector.h>
+#include <wtf/text/CString.h>
+
+
+// cssProperty = {
+// name : <string>,
+// value : <string>,
+// priority : <string>, // "" for non-parsedOk properties
+// implicit : <boolean>,
+// parsedOk : <boolean>, // whether property is understood by WebCore
+// status : <string>, // "disabled" | "active" | "inactive" | "style"
+// shorthandName : <string>,
+// startOffset : <number>, // Optional - property text start offset in enclosing style declaration. Absent for computed styles and such.
+// endOffset : <number>, // Optional - property text end offset in enclosing style declaration. Absent for computed styles and such.
+// }
+//
+// status:
+// "disabled" == property disabled by user
+// "active" == property participates in the computed style calculation
+// "inactive" == property does no participate in the computed style calculation (i.e. overridden by a subsequent property with the same name)
+// "style" == property is active and originates from the WebCore CSSStyleDeclaration rather than CSS source code (e.g. implicit longhand properties)
+//
+//
+// cssStyle = {
+// styleId : <number>, // Optional
+// styleSheetId : <number>, // Parent: -1 for inline styles (<foo style="..">)
+// cssProperties : [
+// #cssProperty,
+// ...
+// #cssProperty
+// ],
+// shorthandValues : {
+// shorthandName1 : shorthandValue1,
+// shorthandName2 : shorthandValue2
+// },
+// cssText : <string>, // declaration text
+// properties : { } // ???
+// }
+//
+// // TODO:
+// // - convert disabledProperties to enabled flag.
+// // - convert width, height to properties
+//
+// cssRule = {
+// ruleId : <number>,
+// selectorText : <string>
+// sourceURL : <string>
+// sourceLine : <string>
+// styleSheetId : <number> // also found in style
+// origin : <string> // "" || "user-agent" || "user" || "inspector"
+// style : #cssStyle
+// }
+//
+// // TODO:
+// // - fix origin
+// // - add sourceURL
+// // - fix parentStyleSheetId
+//
+// cssStyleSheet = {
+// styleSheetId : <number>
+// href : <string>
+// title : <string>
+// disabled : <boolean>
+// documentNodeId : <number>
+// rules : [
+// #cssRule,
+// ...
+// #cssRule
+// ]
+// }
+
+namespace WebCore {
+
+// static
+PassRefPtr<InspectorObject> InspectorCSSAgent::buildObjectForStyle(CSSStyleDeclaration* style, const String& fullStyleId, CSSStyleSourceData* sourceData)
+{
+ RefPtr<InspectorObject> result = InspectorObject::create();
+ if (!fullStyleId.isEmpty())
+ result->setString("id", fullStyleId);
+
+ result->setString("width", style->getPropertyValue("width"));
+ result->setString("height", style->getPropertyValue("height"));
+ Vector<CSSPropertySourceData>* propertyData = 0;
+
+ if (sourceData) {
+ result->setNumber("startOffset", sourceData->styleBodyRange.start);
+ result->setNumber("endOffset", sourceData->styleBodyRange.end);
+ propertyData = &sourceData->propertyData;
+ }
+ populateObjectWithStyleProperties(style, result.get(), propertyData);
+
+ return result.release();
+}
+
+// static
+CSSStyleSheet* InspectorCSSAgent::parentStyleSheet(StyleBase* styleBase)
+{
+ if (!styleBase)
+ return 0;
+
+ StyleSheet* styleSheet = styleBase->stylesheet();
+ if (styleSheet && styleSheet->isCSSStyleSheet())
+ return static_cast<CSSStyleSheet*>(styleSheet);
+
+ return 0;
+}
+
+// static
+CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(StyleBase* styleBase)
+{
+ if (!styleBase->isStyleRule())
+ return 0;
+ CSSRule* rule = static_cast<CSSRule*>(styleBase);
+ if (rule->type() != CSSRule::STYLE_RULE)
+ return 0;
+ return static_cast<CSSStyleRule*>(rule);
+}
+
+
+InspectorCSSAgent::InspectorCSSAgent(InspectorDOMAgent* domAgent, InspectorFrontend* frontend)
+ : m_domAgent(domAgent)
+ , m_frontend(frontend)
+ , m_lastStyleSheetId(1)
+ , m_lastRuleId(1)
+ , m_lastStyleId(1)
+{
+ m_domAgent->setDOMListener(this);
+}
+
+InspectorCSSAgent::~InspectorCSSAgent()
+{
+ reset();
+}
+
+void InspectorCSSAgent::reset()
+{
+ m_domAgent->setDOMListener(0);
+}
+
+void InspectorCSSAgent::getMatchedRulesForNode2(long nodeId, RefPtr<InspectorArray>* result)
+{
+ Element* element = elementForId(nodeId);
+ if (!element)
+ return;
+
+ CSSStyleSelector* selector = element->ownerDocument()->styleSelector();
+ RefPtr<CSSRuleList> matchedRules = selector->styleRulesForElement(element, false, true);
+ *result = buildArrayForRuleList(matchedRules.get());
+}
+
+void InspectorCSSAgent::getMatchedPseudoRulesForNode2(long nodeId, RefPtr<InspectorArray>* result)
+{
+ Element* element = elementForId(nodeId);
+ if (!element)
+ return;
+
+ CSSStyleSelector* selector = element->ownerDocument()->styleSelector();
+ for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
+ RefPtr<CSSRuleList> matchedRules = selector->pseudoStyleRulesForElement(element, pseudoId, false, true);
+ if (matchedRules && matchedRules->length()) {
+ RefPtr<InspectorObject> pseudoStyles = InspectorObject::create();
+ pseudoStyles->setNumber("pseudoId", static_cast<int>(pseudoId));
+ pseudoStyles->setArray("rules", buildArrayForRuleList(matchedRules.get()));
+ (*result)->pushObject(pseudoStyles.release());
+ }
+ }
+}
+
+void InspectorCSSAgent::getAttributeStylesForNode2(long nodeId, RefPtr<InspectorValue>* result)
+{
+ Element* element = elementForId(nodeId);
+ if (!element)
+ return;
+
+ *result = buildObjectForAttributeStyles(element);
+}
+
+void InspectorCSSAgent::getInlineStyleForNode2(long nodeId, RefPtr<InspectorValue>* style)
+{
+ Element* element = elementForId(nodeId);
+ if (!element)
+ return;
+
+ InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
+ if (!styleSheet)
+ return;
+
+ *style = styleSheet->buildObjectForStyle(element->style());
+}
+
+void InspectorCSSAgent::getComputedStyleForNode2(long nodeId, RefPtr<InspectorValue>* style)
+{
+ Element* element = elementForId(nodeId);
+ if (!element)
+ return;
+
+ DOMWindow* defaultView = element->ownerDocument()->defaultView();
+ if (!defaultView)
+ return;
+
+ *style = buildObjectForStyle(defaultView->getComputedStyle(element, "").get(), "");
+}
+
+void InspectorCSSAgent::getInheritedStylesForNode2(long nodeId, RefPtr<InspectorArray>* style)
+{
+ Element* element = elementForId(nodeId);
+ if (!element) {
+ *style = InspectorArray::create();
+ return;
+ }
+ RefPtr<InspectorArray> inheritedStyles = InspectorArray::create();
+ Element* parentElement = element->parentElement();
+ while (parentElement) {
+ RefPtr<InspectorObject> parentStyle = InspectorObject::create();
+ if (parentElement->style() && parentElement->style()->length()) {
+ InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
+ if (styleSheet)
+ parentStyle->setObject("inlineStyle", styleSheet->buildObjectForStyle(styleSheet->styleForId("0")));
+ }
+
+ CSSStyleSelector* parentSelector = parentElement->ownerDocument()->styleSelector();
+ RefPtr<CSSRuleList> parentMatchedRules = parentSelector->styleRulesForElement(parentElement, false, true);
+ parentStyle->setArray("matchedCSSRules", buildArrayForRuleList(parentMatchedRules.get()));
+ inheritedStyles->pushObject(parentStyle.release());
+ parentElement = parentElement->parentElement();
+ }
+ *style = inheritedStyles.release();
+}
+
+void InspectorCSSAgent::getAllStyles2(RefPtr<InspectorArray>* styles)
+{
+ const ListHashSet<RefPtr<Document> >& documents = m_domAgent->documents();
+ for (ListHashSet<RefPtr<Document> >::const_iterator it = documents.begin(); it != documents.end(); ++it) {
+ StyleSheetList* list = (*it)->styleSheets();
+ for (unsigned i = 0; i < list->length(); ++i) {
+ StyleSheet* styleSheet = list->item(i);
+ if (styleSheet->isCSSStyleSheet()) {
+ InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet));
+ (*styles)->pushString(inspectorStyleSheet->id());
+ }
+ }
+ }
+}
+
+void InspectorCSSAgent::getStyleSheet2(const String& styleSheetId, RefPtr<InspectorValue>* styleSheetObject)
+{
+ InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(styleSheetId);
+ if (!inspectorStyleSheet)
+ return;
+
+ *styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
+}
+
+void InspectorCSSAgent::setStyleSheetText2(const String& styleSheetId, const String& text)
+{
+ InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(styleSheetId);
+ if (!inspectorStyleSheet)
+ return;
+
+ inspectorStyleSheet->setText(text);
+}
+
+void InspectorCSSAgent::setStyleText2(const String& fullStyleId, const String& text, RefPtr<InspectorValue>* result)
+{
+ Vector<String> idParts;
+ fullStyleId.split(':', idParts);
+ ASSERT(idParts.size() == 2);
+
+ InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(idParts.at(0));
+ if (!inspectorStyleSheet)
+ return;
+
+ if (!inspectorStyleSheet->setStyleText(idParts.at(1), text))
+ return;
+
+ *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(idParts.at(1)));
+}
+
+void InspectorCSSAgent::toggleProperty2(const String&, long, bool)
+{
+ // FIXME(apavlov): implement
+}
+
+void InspectorCSSAgent::setRuleSelector2(const String& fullRuleId, const String& selector, RefPtr<InspectorValue>* result)
+{
+ Vector<String> idParts;
+ fullRuleId.split(':', idParts);
+ ASSERT(idParts.size() == 2);
+
+ InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(idParts.at(0));
+ if (!inspectorStyleSheet)
+ return;
+
+ const String& ruleId = idParts.at(1);
+ bool success = inspectorStyleSheet->setRuleSelector(ruleId, selector);
+ if (!success)
+ return;
+
+ *result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(ruleId));
+}
+
+void InspectorCSSAgent::addRule2(const long contextNodeId, const String& selector, RefPtr<InspectorValue>* result)
+{
+ Node* node = m_domAgent->nodeForId(contextNodeId);
+ if (!node)
+ return;
+
+ InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true);
+ CSSStyleRule* newRule = inspectorStyleSheet->addRule(selector);
+ if (newRule)
+ *result = inspectorStyleSheet->buildObjectForRule(newRule);
+}
+
+void InspectorCSSAgent::getSupportedCSSProperties(RefPtr<InspectorArray>* cssProperties)
+{
+ RefPtr<InspectorArray> properties = InspectorArray::create();
+ for (int i = 0; i < numCSSProperties; ++i)
+ properties->pushString(propertyNameStrings[i]);
+
+ *cssProperties = properties.release();
+}
+
+// static
+Element* InspectorCSSAgent::inlineStyleElement(CSSStyleDeclaration* style)
+{
+ if (!style || !style->isMutableStyleDeclaration())
+ return 0;
+ Node* node = static_cast<CSSMutableStyleDeclaration*>(style)->node();
+ if (!node || !node->isStyledElement() || static_cast<StyledElement*>(node)->getInlineStyleDecl() != style)
+ return 0;
+ return static_cast<Element*>(node);
+}
+
+// static
+void InspectorCSSAgent::populateObjectWithStyleProperties(CSSStyleDeclaration* style, InspectorObject* result, Vector<CSSPropertySourceData>* propertyData)
+{
+ RefPtr<InspectorArray> properties = InspectorArray::create();
+ RefPtr<InspectorObject> shorthandValues = InspectorObject::create();
+ HashMap<String, RefPtr<InspectorObject> > propertyNameToPreviousActiveProperty;
+ HashSet<String> foundShorthands;
+ HashSet<String> sourcePropertyNames;
+ if (propertyData) {
+ for (Vector<CSSPropertySourceData>::const_iterator it = propertyData->begin(); it != propertyData->end(); ++it) {
+ const CSSPropertySourceData& propertyEntry = *it;
+ RefPtr<InspectorObject> property = InspectorObject::create();
+ properties->pushObject(property);
+ const String& name = propertyEntry.name;
+ sourcePropertyNames.add(name);
+ property->setString("name", name);
+ property->setString("value", propertyEntry.value);
+ property->setString("priority", propertyEntry.important ? "important" : "");
+ property->setString("status", "active");
+ property->setBoolean("parsedOk", propertyEntry.parsedOk);
+ property->setNumber("startOffset", propertyEntry.range.start);
+ property->setNumber("endOffset", propertyEntry.range.end);
+ if (propertyEntry.parsedOk) {
+ property->setBoolean("implicit", false);
+ String shorthand = style->getPropertyShorthand(name);
+ property->setString("shorthandName", shorthand);
+ if (!shorthand.isEmpty() && !foundShorthands.contains(shorthand)) {
+ foundShorthands.add(shorthand);
+ shorthandValues->setString(shorthand, shorthandValue(style, shorthand));
+ }
+ } else {
+ property->setBoolean("implicit", false);
+ property->setString("shorthandName", "");
+ }
+ HashMap<String, RefPtr<InspectorObject> >::iterator activeIt = propertyNameToPreviousActiveProperty.find(name);
+ if (activeIt != propertyNameToPreviousActiveProperty.end()) {
+ activeIt->second->setString("status", "inactive");
+ activeIt->second->setString("shorthandName", "");
+ }
+ propertyNameToPreviousActiveProperty.set(name, property);
+ }
+ }
+
+ for (int i = 0, size = style->length(); i < size; ++i) {
+ String name = style->item(i);
+ if (sourcePropertyNames.contains(name))
+ continue;
+
+ sourcePropertyNames.add(name);
+ RefPtr<InspectorObject> property = InspectorObject::create();
+ properties->pushObject(property);
+ property->setString("name", name);
+ property->setString("value", style->getPropertyValue(name));
+ property->setString("priority", style->getPropertyPriority("name"));
+ property->setBoolean("implicit", style->isPropertyImplicit(name));
+ property->setBoolean("parsedOk", true);
+ property->setString("status", "style");
+ String shorthand = style->getPropertyShorthand(name);
+ property->setString("shorthandName", shorthand);
+ if (!shorthand.isEmpty() && !foundShorthands.contains(shorthand)) {
+ foundShorthands.add(shorthand);
+ shorthandValues->setString(shorthand, shorthandValue(style, shorthand));
+ }
+ }
+
+ result->setArray("properties", properties);
+ result->setObject("shorthandValues", shorthandValues);
+}
+
+// static
+String InspectorCSSAgent::shorthandValue(CSSStyleDeclaration* style, const String& shorthandProperty)
+{
+ String value = style->getPropertyValue(shorthandProperty);
+ if (value.isEmpty()) {
+ for (unsigned i = 0; i < style->length(); ++i) {
+ String individualProperty = style->item(i);
+ if (style->getPropertyShorthand(individualProperty) != shorthandProperty)
+ continue;
+ if (style->isPropertyImplicit(individualProperty))
+ continue;
+ String individualValue = style->getPropertyValue(individualProperty);
+ if (individualValue == "initial")
+ continue;
+ if (value.length())
+ value.append(" ");
+ value.append(individualValue);
+ }
+ }
+ return value;
+}
+
+// static
+String InspectorCSSAgent::shorthandPriority(CSSStyleDeclaration* style, const String& shorthandProperty)
+{
+ String priority = style->getPropertyPriority(shorthandProperty);
+ if (priority.isEmpty()) {
+ for (unsigned i = 0; i < style->length(); ++i) {
+ String individualProperty = style->item(i);
+ if (style->getPropertyShorthand(individualProperty) != shorthandProperty)
+ continue;
+ priority = style->getPropertyPriority(individualProperty);
+ break;
+ }
+ }
+ return priority;
+}
+
+
+// static
+Vector<String> InspectorCSSAgent::longhandProperties(CSSStyleDeclaration* style, const String& shorthandProperty)
+{
+ Vector<String> properties;
+ HashSet<String> foundProperties;
+ for (unsigned i = 0; i < style->length(); ++i) {
+ String individualProperty = style->item(i);
+ if (foundProperties.contains(individualProperty) || style->getPropertyShorthand(individualProperty) != shorthandProperty)
+ continue;
+
+ foundProperties.add(individualProperty);
+ properties.append(individualProperty);
+ }
+ return properties;
+}
+
+InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
+{
+ NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
+ if (it == m_nodeToInspectorStyleSheet.end()) {
+ CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
+ if (!style)
+ return 0;
+
+ String newStyleSheetId = String::number(m_lastStyleSheetId++);
+ RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(newStyleSheetId, element, "");
+ m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
+ m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
+ return inspectorStyleSheet.get();
+ }
+
+ return it->second.get();
+}
+
+Element* InspectorCSSAgent::elementForId(long nodeId)
+{
+ Node* node = m_domAgent->nodeForId(nodeId);
+ return (!node || node->nodeType() != Node::ELEMENT_NODE) ? 0 : static_cast<Element*>(node);
+}
+
+InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
+{
+ RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
+ if (!inspectorStyleSheet) {
+ String id = String::number(m_lastStyleSheetId++);
+ inspectorStyleSheet = InspectorStyleSheet::create(id, styleSheet, detectOrigin(styleSheet, styleSheet->document()), m_domAgent->documentURLString(styleSheet->document()));
+ m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
+ m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
+ }
+ return inspectorStyleSheet.get();
+}
+
+InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
+{
+ if (!document) {
+ ASSERT(!createIfAbsent);
+ return 0;
+ }
+
+ RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
+ if (inspectorStyleSheet || !createIfAbsent)
+ return inspectorStyleSheet.get();
+
+ ExceptionCode ec = 0;
+ RefPtr<Element> styleElement = document->createElement("style", ec);
+ if (!ec)
+ styleElement->setAttribute("type", "text/css", ec);
+ if (!ec)
+ document->head()->appendChild(styleElement, ec);
+ if (ec)
+ return 0;
+ StyleSheetList* styleSheets = document->styleSheets();
+ StyleSheet* styleSheet = styleSheets->item(styleSheets->length() - 1);
+ if (!styleSheet->isCSSStyleSheet())
+ return 0;
+ CSSStyleSheet* cssStyleSheet = static_cast<CSSStyleSheet*>(styleSheet);
+ String id = String::number(m_lastStyleSheetId++);
+ inspectorStyleSheet = InspectorStyleSheet::create(id, cssStyleSheet, "inspector", m_domAgent->documentURLString(document));
+ m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
+ m_cssStyleSheetToInspectorStyleSheet.set(cssStyleSheet, inspectorStyleSheet);
+ m_documentToInspectorStyleSheet.set(document, inspectorStyleSheet);
+ return inspectorStyleSheet.get();
+}
+
+InspectorStyleSheet* InspectorCSSAgent::styleSheetForId(const String& styleSheetId)
+{
+ IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
+ return it == m_idToInspectorStyleSheet.end() ? 0 : it->second.get();
+}
+
+String InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
+{
+ DEFINE_STATIC_LOCAL(String, userAgent, ("user-agent"));
+ DEFINE_STATIC_LOCAL(String, user, ("user"));
+ DEFINE_STATIC_LOCAL(String, inspector, ("inspector"));
+
+ String origin("");
+ if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
+ origin = userAgent;
+ else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
+ origin = user;
+ else {
+ InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
+ if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
+ origin = inspector;
+ }
+ return origin;
+}
+
+PassRefPtr<InspectorArray> InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList)
+{
+ RefPtr<InspectorArray> result = InspectorArray::create();
+ if (!ruleList)
+ return result.release();
+
+ for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
+ CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
+ if (!rule)
+ continue;
+
+ InspectorStyleSheet* styleSheet = bindStyleSheet(parentStyleSheet(rule));
+ if (styleSheet)
+ result->pushObject(styleSheet->buildObjectForRule(rule));
+ }
+ return result.release();
+}
+
+PassRefPtr<InspectorObject> InspectorCSSAgent::buildObjectForAttributeStyles(Element* element)
+{
+ RefPtr<InspectorObject> styleAttributes = InspectorObject::create();
+ NamedNodeMap* attributes = element->attributes();
+ for (unsigned i = 0; attributes && i < attributes->length(); ++i) {
+ Attribute* attribute = attributes->attributeItem(i);
+ if (attribute->style()) {
+ String attributeName = attribute->localName();
+ styleAttributes->setObject(attributeName.utf8().data(), buildObjectForStyle(attribute->style(), ""));
+ }
+ }
+
+ return styleAttributes;
+}
+
+void InspectorCSSAgent::didRemoveDocument(Document* document)
+{
+ m_documentToInspectorStyleSheet.remove(document);
+}
+
+void InspectorCSSAgent::didRemoveDOMNode(Node* node)
+{
+ NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
+ if (it == m_nodeToInspectorStyleSheet.end())
+ return;
+
+ m_idToInspectorStyleSheet.remove(it->second->id());
+ m_nodeToInspectorStyleSheet.remove(node);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INSPECTOR)