| /* |
| * 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) |