2010-10-14 Hayato Ito <hayato@chromium.org>
[WebKit-https.git] / WebCore / inspector / InspectorCSSAgent.cpp
1 /*
2  * Copyright (C) 2010, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26 #include "InspectorCSSAgent.h"
27
28 #if ENABLE(INSPECTOR)
29
30 #include "CSSComputedStyleDeclaration.h"
31 #include "CSSMutableStyleDeclaration.h"
32 #include "CSSPropertyNames.h"
33 #include "CSSPropertySourceData.h"
34 #include "CSSRule.h"
35 #include "CSSRuleList.h"
36 #include "CSSStyleRule.h"
37 #include "CSSStyleSelector.h"
38 #include "CSSStyleSheet.h"
39 #include "DOMWindow.h"
40 #include "HTMLHeadElement.h"
41 #include "InspectorDOMAgent.h"
42 #include "InspectorFrontend.h"
43 #include "InspectorUtilities.h"
44 #include "InspectorValues.h"
45 #include "Node.h"
46 #include "StyleSheetList.h"
47
48 #include <wtf/HashSet.h>
49 #include <wtf/ListHashSet.h>
50 #include <wtf/Vector.h>
51 #include <wtf/text/CString.h>
52
53
54 // cssProperty = {
55 //    name          : <string>,
56 //    value         : <string>,
57 //    priority      : <string>, // "" for non-parsedOk properties
58 //    implicit      : <boolean>,
59 //    parsedOk      : <boolean>, // whether property is understood by WebCore
60 //    status        : <string>, // "disabled" | "active" | "inactive" | "style"
61 //    shorthandName : <string>,
62 //    startOffset   : <number>, // Optional - property text start offset in enclosing style declaration. Absent for computed styles and such.
63 //    endOffset     : <number>, // Optional - property text end offset in enclosing style declaration. Absent for computed styles and such.
64 // }
65 //
66 // status:
67 // "disabled" == property disabled by user
68 // "active" == property participates in the computed style calculation
69 // "inactive" == property does no participate in the computed style calculation (i.e. overridden by a subsequent property with the same name)
70 // "style" == property is active and originates from the WebCore CSSStyleDeclaration rather than CSS source code (e.g. implicit longhand properties)
71 //
72 //
73 // cssStyle = {
74 //    styleId         : <number>, // Optional
75 //    styleSheetId    : <number>, // Parent: -1 for inline styles (<foo style="..">)
76 //    cssProperties   : [
77 //                          #cssProperty,
78 //                          ...
79 //                          #cssProperty
80 //                    ],
81 //    shorthandValues : {
82 //                          shorthandName1 : shorthandValue1,
83 //                          shorthandName2 : shorthandValue2
84 //                      },
85 //    cssText         : <string>, // declaration text
86 //    properties      : { } // ???
87 // }
88 //
89 // // TODO:
90 // // - convert disabledProperties to enabled flag.
91 // // - convert width, height to properties
92 //
93 // cssRule = {
94 //    ruleId       : <number>,
95 //    selectorText : <string>
96 //    sourceURL    : <string>
97 //    sourceLine   : <string>
98 //    styleSheetId : <number> // also found in style
99 //    origin       : <string> // "" || "user-agent" || "user" || "inspector"
100 //    style        : #cssStyle
101 // }
102 //
103 // // TODO:
104 // // - fix origin
105 // // - add sourceURL
106 // // - fix parentStyleSheetId
107 //
108 // cssStyleSheet = {
109 //    styleSheetId   : <number>
110 //    href           : <string>
111 //    title          : <string>
112 //    disabled       : <boolean>
113 //    documentNodeId : <number>
114 //    rules          : [
115 //                         #cssRule,
116 //                         ...
117 //                         #cssRule
118 //                     ]
119 // }
120
121 namespace WebCore {
122
123 // static
124 PassRefPtr<InspectorObject> InspectorCSSAgent::buildObjectForStyle(CSSStyleDeclaration* style, const String& fullStyleId, CSSStyleSourceData* sourceData)
125 {
126     RefPtr<InspectorObject> result = InspectorObject::create();
127     if (!fullStyleId.isEmpty())
128         result->setString("id", fullStyleId);
129
130     result->setString("width", style->getPropertyValue("width"));
131     result->setString("height", style->getPropertyValue("height"));
132     Vector<CSSPropertySourceData>* propertyData = 0;
133
134     if (sourceData) {
135         result->setNumber("startOffset", sourceData->styleBodyRange.start);
136         result->setNumber("endOffset", sourceData->styleBodyRange.end);
137         propertyData = &sourceData->propertyData;
138     }
139     populateObjectWithStyleProperties(style, result.get(), propertyData);
140
141     return result.release();
142 }
143
144 // static
145 CSSStyleSheet* InspectorCSSAgent::parentStyleSheet(StyleBase* styleBase)
146 {
147     if (!styleBase)
148         return 0;
149
150     StyleSheet* styleSheet = styleBase->stylesheet();
151     if (styleSheet && styleSheet->isCSSStyleSheet())
152         return static_cast<CSSStyleSheet*>(styleSheet);
153
154     return 0;
155 }
156
157 // static
158 CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(StyleBase* styleBase)
159 {
160     if (!styleBase->isStyleRule())
161         return 0;
162     CSSRule* rule = static_cast<CSSRule*>(styleBase);
163     if (rule->type() != CSSRule::STYLE_RULE)
164         return 0;
165     return static_cast<CSSStyleRule*>(rule);
166 }
167
168
169 InspectorCSSAgent::InspectorCSSAgent(InspectorDOMAgent* domAgent, InspectorFrontend* frontend)
170     : m_domAgent(domAgent)
171     , m_frontend(frontend)
172     , m_lastStyleSheetId(1)
173     , m_lastRuleId(1)
174     , m_lastStyleId(1)
175 {
176     m_domAgent->setDOMListener(this);
177 }
178
179 InspectorCSSAgent::~InspectorCSSAgent()
180 {
181     reset();
182 }
183
184 void InspectorCSSAgent::reset()
185 {
186     m_domAgent->setDOMListener(0);
187 }
188
189 void InspectorCSSAgent::getMatchedRulesForNode2(long nodeId, RefPtr<InspectorArray>* result)
190 {
191     Element* element = elementForId(nodeId);
192     if (!element)
193         return;
194
195     CSSStyleSelector* selector = element->ownerDocument()->styleSelector();
196     RefPtr<CSSRuleList> matchedRules = selector->styleRulesForElement(element, false, true);
197     *result = buildArrayForRuleList(matchedRules.get());
198 }
199
200 void InspectorCSSAgent::getMatchedPseudoRulesForNode2(long nodeId, RefPtr<InspectorArray>* result)
201 {
202     Element* element = elementForId(nodeId);
203     if (!element)
204         return;
205
206     CSSStyleSelector* selector = element->ownerDocument()->styleSelector();
207     for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
208         RefPtr<CSSRuleList> matchedRules = selector->pseudoStyleRulesForElement(element, pseudoId, false, true);
209         if (matchedRules && matchedRules->length()) {
210             RefPtr<InspectorObject> pseudoStyles = InspectorObject::create();
211             pseudoStyles->setNumber("pseudoId", static_cast<int>(pseudoId));
212             pseudoStyles->setArray("rules", buildArrayForRuleList(matchedRules.get()));
213             (*result)->pushObject(pseudoStyles.release());
214         }
215     }
216 }
217
218 void InspectorCSSAgent::getAttributeStylesForNode2(long nodeId, RefPtr<InspectorValue>* result)
219 {
220     Element* element = elementForId(nodeId);
221     if (!element)
222         return;
223
224     *result = buildObjectForAttributeStyles(element);
225 }
226
227 void InspectorCSSAgent::getInlineStyleForNode2(long nodeId, RefPtr<InspectorValue>* style)
228 {
229     Element* element = elementForId(nodeId);
230     if (!element)
231         return;
232
233     InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
234     if (!styleSheet)
235         return;
236
237     *style = styleSheet->buildObjectForStyle(element->style());
238 }
239
240 void InspectorCSSAgent::getComputedStyleForNode2(long nodeId, RefPtr<InspectorValue>* style)
241 {
242     Element* element = elementForId(nodeId);
243     if (!element)
244         return;
245
246     DOMWindow* defaultView = element->ownerDocument()->defaultView();
247     if (!defaultView)
248         return;
249
250     *style = buildObjectForStyle(defaultView->getComputedStyle(element, "").get(), "");
251 }
252
253 void InspectorCSSAgent::getInheritedStylesForNode2(long nodeId, RefPtr<InspectorArray>* style)
254 {
255     Element* element = elementForId(nodeId);
256     if (!element) {
257         *style = InspectorArray::create();
258         return;
259     }
260     RefPtr<InspectorArray> inheritedStyles = InspectorArray::create();
261     Element* parentElement = element->parentElement();
262     while (parentElement) {
263         RefPtr<InspectorObject> parentStyle = InspectorObject::create();
264         if (parentElement->style() && parentElement->style()->length()) {
265             InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
266             if (styleSheet)
267                 parentStyle->setObject("inlineStyle", styleSheet->buildObjectForStyle(styleSheet->styleForId("0")));
268         }
269
270         CSSStyleSelector* parentSelector = parentElement->ownerDocument()->styleSelector();
271         RefPtr<CSSRuleList> parentMatchedRules = parentSelector->styleRulesForElement(parentElement, false, true);
272         parentStyle->setArray("matchedCSSRules", buildArrayForRuleList(parentMatchedRules.get()));
273         inheritedStyles->pushObject(parentStyle.release());
274         parentElement = parentElement->parentElement();
275     }
276     *style = inheritedStyles.release();
277 }
278
279 void InspectorCSSAgent::getAllStyles2(RefPtr<InspectorArray>* styles)
280 {
281     const ListHashSet<RefPtr<Document> >& documents = m_domAgent->documents();
282     for (ListHashSet<RefPtr<Document> >::const_iterator it = documents.begin(); it != documents.end(); ++it) {
283         StyleSheetList* list = (*it)->styleSheets();
284         for (unsigned i = 0; i < list->length(); ++i) {
285             StyleSheet* styleSheet = list->item(i);
286             if (styleSheet->isCSSStyleSheet()) {
287                 InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet));
288                 (*styles)->pushString(inspectorStyleSheet->id());
289             }
290         }
291     }
292 }
293
294 void InspectorCSSAgent::getStyleSheet2(const String& styleSheetId, RefPtr<InspectorValue>* styleSheetObject)
295 {
296     InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(styleSheetId);
297     if (!inspectorStyleSheet)
298         return;
299
300     *styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
301 }
302
303 void InspectorCSSAgent::setStyleSheetText2(const String& styleSheetId, const String& text)
304 {
305     InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(styleSheetId);
306     if (!inspectorStyleSheet)
307         return;
308
309     inspectorStyleSheet->setText(text);
310 }
311
312 void InspectorCSSAgent::setStyleText2(const String& fullStyleId, const String& text, RefPtr<InspectorValue>* result)
313 {
314     Vector<String> idParts;
315     fullStyleId.split(':', idParts);
316     ASSERT(idParts.size() == 2);
317
318     InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(idParts.at(0));
319     if (!inspectorStyleSheet)
320         return;
321
322     if (!inspectorStyleSheet->setStyleText(idParts.at(1), text))
323         return;
324
325     *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(idParts.at(1)));
326 }
327
328 void InspectorCSSAgent::toggleProperty2(const String&, long, bool)
329 {
330     // FIXME(apavlov): implement
331 }
332
333 void InspectorCSSAgent::setRuleSelector2(const String& fullRuleId, const String& selector, RefPtr<InspectorValue>* result)
334 {
335     Vector<String> idParts;
336     fullRuleId.split(':', idParts);
337     ASSERT(idParts.size() == 2);
338
339     InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(idParts.at(0));
340     if (!inspectorStyleSheet)
341         return;
342
343     const String& ruleId = idParts.at(1);
344     bool success = inspectorStyleSheet->setRuleSelector(ruleId, selector);
345     if (!success)
346         return;
347
348     *result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(ruleId));
349 }
350
351 void InspectorCSSAgent::addRule2(const long contextNodeId, const String& selector, RefPtr<InspectorValue>* result)
352 {
353     Node* node = m_domAgent->nodeForId(contextNodeId);
354     if (!node)
355         return;
356
357     InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true);
358     CSSStyleRule* newRule = inspectorStyleSheet->addRule(selector);
359     if (newRule)
360         *result = inspectorStyleSheet->buildObjectForRule(newRule);
361 }
362
363 void InspectorCSSAgent::getSupportedCSSProperties(RefPtr<InspectorArray>* cssProperties)
364 {
365     RefPtr<InspectorArray> properties = InspectorArray::create();
366     for (int i = 0; i < numCSSProperties; ++i)
367         properties->pushString(propertyNameStrings[i]);
368
369     *cssProperties = properties.release();
370 }
371
372 // static
373 Element* InspectorCSSAgent::inlineStyleElement(CSSStyleDeclaration* style)
374 {
375     if (!style || !style->isMutableStyleDeclaration())
376         return 0;
377     Node* node = static_cast<CSSMutableStyleDeclaration*>(style)->node();
378     if (!node || !node->isStyledElement() || static_cast<StyledElement*>(node)->getInlineStyleDecl() != style)
379         return 0;
380     return static_cast<Element*>(node);
381 }
382
383 // static
384 void InspectorCSSAgent::populateObjectWithStyleProperties(CSSStyleDeclaration* style, InspectorObject* result, Vector<CSSPropertySourceData>* propertyData)
385 {
386     RefPtr<InspectorArray> properties = InspectorArray::create();
387     RefPtr<InspectorObject> shorthandValues = InspectorObject::create();
388     HashMap<String, RefPtr<InspectorObject> > propertyNameToPreviousActiveProperty;
389     HashSet<String> foundShorthands;
390     HashSet<String> sourcePropertyNames;
391     if (propertyData) {
392         for (Vector<CSSPropertySourceData>::const_iterator it = propertyData->begin(); it != propertyData->end(); ++it) {
393             const CSSPropertySourceData& propertyEntry = *it;
394             RefPtr<InspectorObject> property = InspectorObject::create();
395             properties->pushObject(property);
396             const String& name = propertyEntry.name;
397             sourcePropertyNames.add(name);
398             property->setString("name", name);
399             property->setString("value", propertyEntry.value);
400             property->setString("priority", propertyEntry.important ? "important" : "");
401             property->setString("status", "active");
402             property->setBoolean("parsedOk", propertyEntry.parsedOk);
403             property->setNumber("startOffset", propertyEntry.range.start);
404             property->setNumber("endOffset", propertyEntry.range.end);
405             if (propertyEntry.parsedOk) {
406                 property->setBoolean("implicit", false);
407                 String shorthand = style->getPropertyShorthand(name);
408                 property->setString("shorthandName", shorthand);
409                 if (!shorthand.isEmpty() && !foundShorthands.contains(shorthand)) {
410                     foundShorthands.add(shorthand);
411                     shorthandValues->setString(shorthand, shorthandValue(style, shorthand));
412                 }
413             } else {
414                 property->setBoolean("implicit", false);
415                 property->setString("shorthandName", "");
416             }
417             HashMap<String, RefPtr<InspectorObject> >::iterator activeIt = propertyNameToPreviousActiveProperty.find(name);
418             if (activeIt != propertyNameToPreviousActiveProperty.end()) {
419                 activeIt->second->setString("status", "inactive");
420                 activeIt->second->setString("shorthandName", "");
421             }
422             propertyNameToPreviousActiveProperty.set(name, property);
423         }
424     }
425
426     for (int i = 0, size = style->length(); i < size; ++i) {
427         String name = style->item(i);
428         if (sourcePropertyNames.contains(name))
429             continue;
430
431         sourcePropertyNames.add(name);
432         RefPtr<InspectorObject> property = InspectorObject::create();
433         properties->pushObject(property);
434         property->setString("name", name);
435         property->setString("value", style->getPropertyValue(name));
436         property->setString("priority", style->getPropertyPriority("name"));
437         property->setBoolean("implicit", style->isPropertyImplicit(name));
438         property->setBoolean("parsedOk", true);
439         property->setString("status", "style");
440         String shorthand = style->getPropertyShorthand(name);
441         property->setString("shorthandName", shorthand);
442         if (!shorthand.isEmpty() && !foundShorthands.contains(shorthand)) {
443             foundShorthands.add(shorthand);
444             shorthandValues->setString(shorthand, shorthandValue(style, shorthand));
445         }
446     }
447
448     result->setArray("properties", properties);
449     result->setObject("shorthandValues", shorthandValues);
450 }
451
452 // static
453 String InspectorCSSAgent::shorthandValue(CSSStyleDeclaration* style, const String& shorthandProperty)
454 {
455     String value = style->getPropertyValue(shorthandProperty);
456     if (value.isEmpty()) {
457         for (unsigned i = 0; i < style->length(); ++i) {
458             String individualProperty = style->item(i);
459             if (style->getPropertyShorthand(individualProperty) != shorthandProperty)
460                 continue;
461             if (style->isPropertyImplicit(individualProperty))
462                 continue;
463             String individualValue = style->getPropertyValue(individualProperty);
464             if (individualValue == "initial")
465                 continue;
466             if (value.length())
467                 value.append(" ");
468             value.append(individualValue);
469         }
470     }
471     return value;
472 }
473
474 // static
475 String InspectorCSSAgent::shorthandPriority(CSSStyleDeclaration* style, const String& shorthandProperty)
476 {
477     String priority = style->getPropertyPriority(shorthandProperty);
478     if (priority.isEmpty()) {
479         for (unsigned i = 0; i < style->length(); ++i) {
480             String individualProperty = style->item(i);
481             if (style->getPropertyShorthand(individualProperty) != shorthandProperty)
482                 continue;
483             priority = style->getPropertyPriority(individualProperty);
484             break;
485         }
486     }
487     return priority;
488 }
489
490
491 // static
492 Vector<String> InspectorCSSAgent::longhandProperties(CSSStyleDeclaration* style, const String& shorthandProperty)
493 {
494     Vector<String> properties;
495     HashSet<String> foundProperties;
496     for (unsigned i = 0; i < style->length(); ++i) {
497         String individualProperty = style->item(i);
498         if (foundProperties.contains(individualProperty) || style->getPropertyShorthand(individualProperty) != shorthandProperty)
499             continue;
500
501         foundProperties.add(individualProperty);
502         properties.append(individualProperty);
503     }
504     return properties;
505 }
506
507 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
508 {
509     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
510     if (it == m_nodeToInspectorStyleSheet.end()) {
511         CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
512         if (!style)
513             return 0;
514
515         String newStyleSheetId = String::number(m_lastStyleSheetId++);
516         RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(newStyleSheetId, element, "");
517         m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
518         m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
519         return inspectorStyleSheet.get();
520     }
521
522     return it->second.get();
523 }
524
525 Element* InspectorCSSAgent::elementForId(long nodeId)
526 {
527     Node* node = m_domAgent->nodeForId(nodeId);
528     return (!node || node->nodeType() != Node::ELEMENT_NODE) ? 0 : static_cast<Element*>(node);
529 }
530
531 InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
532 {
533     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
534     if (!inspectorStyleSheet) {
535         String id = String::number(m_lastStyleSheetId++);
536         inspectorStyleSheet = InspectorStyleSheet::create(id, styleSheet, detectOrigin(styleSheet, styleSheet->document()), m_domAgent->documentURLString(styleSheet->document()));
537         m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
538         m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
539     }
540     return inspectorStyleSheet.get();
541 }
542
543 InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
544 {
545     if (!document) {
546         ASSERT(!createIfAbsent);
547         return 0;
548     }
549
550     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
551     if (inspectorStyleSheet || !createIfAbsent)
552         return inspectorStyleSheet.get();
553
554     ExceptionCode ec = 0;
555     RefPtr<Element> styleElement = document->createElement("style", ec);
556     if (!ec)
557         styleElement->setAttribute("type", "text/css", ec);
558     if (!ec)
559         document->head()->appendChild(styleElement, ec);
560     if (ec)
561         return 0;
562     StyleSheetList* styleSheets = document->styleSheets();
563     StyleSheet* styleSheet = styleSheets->item(styleSheets->length() - 1);
564     if (!styleSheet->isCSSStyleSheet())
565         return 0;
566     CSSStyleSheet* cssStyleSheet = static_cast<CSSStyleSheet*>(styleSheet);
567     String id = String::number(m_lastStyleSheetId++);
568     inspectorStyleSheet = InspectorStyleSheet::create(id, cssStyleSheet, "inspector", m_domAgent->documentURLString(document));
569     m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
570     m_cssStyleSheetToInspectorStyleSheet.set(cssStyleSheet, inspectorStyleSheet);
571     m_documentToInspectorStyleSheet.set(document, inspectorStyleSheet);
572     return inspectorStyleSheet.get();
573 }
574
575 InspectorStyleSheet* InspectorCSSAgent::styleSheetForId(const String& styleSheetId)
576 {
577     IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
578     return it == m_idToInspectorStyleSheet.end() ? 0 : it->second.get();
579 }
580
581 String InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
582 {
583     DEFINE_STATIC_LOCAL(String, userAgent, ("user-agent"));
584     DEFINE_STATIC_LOCAL(String, user, ("user"));
585     DEFINE_STATIC_LOCAL(String, inspector, ("inspector"));
586
587     String origin("");
588     if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
589         origin = userAgent;
590     else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
591         origin = user;
592     else {
593         InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
594         if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
595             origin = inspector;
596     }
597     return origin;
598 }
599
600 PassRefPtr<InspectorArray> InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList)
601 {
602     RefPtr<InspectorArray> result = InspectorArray::create();
603     if (!ruleList)
604         return result.release();
605
606     for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
607         CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
608         if (!rule)
609             continue;
610
611         InspectorStyleSheet* styleSheet = bindStyleSheet(parentStyleSheet(rule));
612         if (styleSheet)
613             result->pushObject(styleSheet->buildObjectForRule(rule));
614     }
615     return result.release();
616 }
617
618 PassRefPtr<InspectorObject> InspectorCSSAgent::buildObjectForAttributeStyles(Element* element)
619 {
620     RefPtr<InspectorObject> styleAttributes = InspectorObject::create();
621     NamedNodeMap* attributes = element->attributes();
622     for (unsigned i = 0; attributes && i < attributes->length(); ++i) {
623         Attribute* attribute = attributes->attributeItem(i);
624         if (attribute->style()) {
625             String attributeName = attribute->localName();
626             styleAttributes->setObject(attributeName.utf8().data(), buildObjectForStyle(attribute->style(), ""));
627         }
628     }
629
630     return styleAttributes;
631 }
632
633 void InspectorCSSAgent::didRemoveDocument(Document* document)
634 {
635     m_documentToInspectorStyleSheet.remove(document);
636 }
637
638 void InspectorCSSAgent::didRemoveDOMNode(Node* node)
639 {
640     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
641     if (it == m_nodeToInspectorStyleSheet.end())
642         return;
643
644     m_idToInspectorStyleSheet.remove(it->second->id());
645     m_nodeToInspectorStyleSheet.remove(node);
646 }
647
648 } // namespace WebCore
649
650 #endif // ENABLE(INSPECTOR)