initial import
[vuplus_webkit] / Source / 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 "CSSImportRule.h"
32 #include "CSSMutableStyleDeclaration.h"
33 #include "CSSPropertyNames.h"
34 #include "CSSPropertySourceData.h"
35 #include "CSSRule.h"
36 #include "CSSRuleList.h"
37 #include "CSSStyleRule.h"
38 #include "CSSStyleSelector.h"
39 #include "CSSStyleSheet.h"
40 #include "DOMWindow.h"
41 #include "HTMLHeadElement.h"
42 #include "InspectorDOMAgent.h"
43 #include "InspectorValues.h"
44 #include "InstrumentingAgents.h"
45 #include "Node.h"
46 #include "NodeList.h"
47 #include "StyleSheetList.h"
48
49 #include <wtf/HashSet.h>
50 #include <wtf/Vector.h>
51 #include <wtf/text/CString.h>
52
53 // Currently implemented model:
54 //
55 // cssProperty = {
56 //    name          : <string>,
57 //    value         : <string>,
58 //    priority      : <string>, // "" for non-parsedOk properties
59 //    implicit      : <boolean>,
60 //    parsedOk      : <boolean>, // whether property is understood by WebCore
61 //    status        : <string>, // "disabled" | "active" | "inactive" | "style"
62 //    shorthandName : <string>,
63 //    startOffset   : <number>, // Optional - property text start offset in enclosing style declaration. Absent for computed styles and such.
64 //    endOffset     : <number>, // Optional - property text end offset in enclosing style declaration. Absent for computed styles and such.
65 // }
66 //
67 // name + value + priority : present when the property is enabled
68 // text                    : present when the property is disabled
69 //
70 // For disabled properties, startOffset === endOffset === insertion point for the property.
71 //
72 // status:
73 // "disabled" == property disabled by user
74 // "active" == property participates in the computed style calculation
75 // "inactive" == property does no participate in the computed style calculation (i.e. overridden by a subsequent property with the same name)
76 // "style" == property is active and originates from the WebCore CSSStyleDeclaration rather than CSS source code (e.g. implicit longhand properties)
77 //
78 // cssStyle = {
79 //    styleId            : <string>, // Optional
80 //    cssProperties      : [
81 //                          #cssProperty,
82 //                          ...
83 //                          #cssProperty
84 //                         ],
85 //    shorthandEntries   : [
86 //                          #shorthandEntry,
87 //                          ...
88 //                          #shorthandEntry
89 //                         ],
90 //    cssText            : <string>, // Optional - declaration text
91 //    properties         : {
92 //                          width,
93 //                          height,
94 //                          startOffset, // Optional - for source-based styles only
95 //                          endOffset, // Optional - for source-based styles only
96 //                         }
97 // }
98 //
99 // shorthandEntry = {
100 //    name: <string>,
101 //    value: <string>
102 // }
103 //
104 // cssRule = {
105 //    ruleId       : <string>, // Optional
106 //    selectorText : <string>,
107 //    sourceURL    : <string>,
108 //    sourceLine   : <string>,
109 //    origin       : <string>, // "" || "user-agent" || "user" || "inspector"
110 //    style        : #cssStyle,
111 //    selectorRange: { start: <number>, end: <number> } // Optional - for source-based rules only
112 // }
113 //
114 // cssStyleSheetInfo = {
115 //    styleSheetId : <number>
116 //    sourceURL    : <string>
117 //    title        : <string>
118 //    disabled     : <boolean>
119 // }
120 //
121 // cssStyleSheet = {
122 //    styleSheetId : <number>
123 //    rules        : [
124 //                       #cssRule,
125 //                       ...
126 //                       #cssRule
127 //                   ]
128 //    text         : <string> // Optional - whenever the text is available for a text-based stylesheet
129 // }
130
131 namespace WebCore {
132
133 enum ForcePseudoClassFlags {
134     PseudoNone = 0,
135     PseudoHover = 1 << 0,
136     PseudoFocus = 1 << 1,
137     PseudoActive = 1 << 2,
138     PseudoVisited = 1 << 3
139 };
140
141 static unsigned computePseudoClassMask(InspectorArray* pseudoClassArray)
142 {
143     DEFINE_STATIC_LOCAL(String, active, ("active"));
144     DEFINE_STATIC_LOCAL(String, hover, ("hover"));
145     DEFINE_STATIC_LOCAL(String, focus, ("focus"));
146     DEFINE_STATIC_LOCAL(String, visited, ("visited"));
147     if (!pseudoClassArray || !pseudoClassArray->length())
148         return PseudoNone;
149
150     unsigned result = PseudoNone;
151     for (size_t i = 0; i < pseudoClassArray->length(); ++i) {
152         RefPtr<InspectorValue> pseudoClassValue = pseudoClassArray->get(i);
153         String pseudoClass;
154         bool success = pseudoClassValue->asString(&pseudoClass);
155         if (!success)
156             continue;
157         if (pseudoClass == active)
158             result |= PseudoActive;
159         else if (pseudoClass == hover)
160             result |= PseudoHover;
161         else if (pseudoClass == focus)
162             result |= PseudoFocus;
163         else if (pseudoClass == visited)
164             result |= PseudoVisited;
165     }
166
167     return result;
168 }
169
170 // static
171 CSSStyleSheet* InspectorCSSAgent::parentStyleSheet(StyleBase* styleBase)
172 {
173     if (!styleBase)
174         return 0;
175
176     StyleSheet* styleSheet = styleBase->stylesheet();
177     if (styleSheet && styleSheet->isCSSStyleSheet())
178         return static_cast<CSSStyleSheet*>(styleSheet);
179
180     return 0;
181 }
182
183 // static
184 CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(StyleBase* styleBase)
185 {
186     if (!styleBase->isStyleRule())
187         return 0;
188     CSSRule* rule = static_cast<CSSRule*>(styleBase);
189     if (rule->type() != CSSRule::STYLE_RULE)
190         return 0;
191     return static_cast<CSSStyleRule*>(rule);
192 }
193
194 InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorDOMAgent* domAgent)
195     : m_instrumentingAgents(instrumentingAgents)
196     , m_domAgent(domAgent)
197     , m_lastPseudoState(0)
198     , m_lastStyleSheetId(1)
199     , m_lastRuleId(1)
200     , m_lastStyleId(1)
201 {
202     m_domAgent->setDOMListener(this);
203     m_instrumentingAgents->setInspectorCSSAgent(this);
204 }
205
206 InspectorCSSAgent::~InspectorCSSAgent()
207 {
208     m_instrumentingAgents->setInspectorCSSAgent(0);
209     // DOM agent should be destroyed after CSS agent.
210     m_domAgent->setDOMListener(0);
211     m_domAgent = 0;
212     reset();
213 }
214
215 void InspectorCSSAgent::clearFrontend()
216 {
217     clearPseudoState(true);
218 }
219
220 void InspectorCSSAgent::reset()
221 {
222     m_idToInspectorStyleSheet.clear();
223     m_cssStyleSheetToInspectorStyleSheet.clear();
224     m_nodeToInspectorStyleSheet.clear();
225     m_documentToInspectorStyleSheet.clear();
226 }
227
228 bool InspectorCSSAgent::forcePseudoState(Element* element, CSSSelector::PseudoType pseudoType)
229 {
230     if (m_lastElementWithPseudoState != element)
231         return false;
232
233     switch (pseudoType) {
234     case CSSSelector::PseudoActive:
235         return m_lastPseudoState & PseudoActive;
236     case CSSSelector::PseudoFocus:
237         return m_lastPseudoState & PseudoFocus;
238     case CSSSelector::PseudoHover:
239         return m_lastPseudoState & PseudoHover;
240     case CSSSelector::PseudoVisited:
241         return m_lastPseudoState & PseudoVisited;
242     default:
243         return false;
244     }
245 }
246
247 void InspectorCSSAgent::getStylesForNode(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>* forcedPseudoClasses, RefPtr<InspectorObject>* result)
248 {
249     Element* element = elementForId(errorString, nodeId);
250     if (!element)
251         return;
252
253     RefPtr<InspectorObject> resultObject = InspectorObject::create();
254
255     InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
256     if (styleSheet)
257         resultObject->setObject("inlineStyle", styleSheet->buildObjectForStyle(element->style()));
258
259     RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = computedStyle(element, true); // Support the viewing of :visited information in computed style.
260     RefPtr<InspectorStyle> computedInspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
261     resultObject->setObject("computedStyle", computedInspectorStyle->buildObjectForStyle());
262
263     unsigned forcePseudoState = computePseudoClassMask(forcedPseudoClasses ? forcedPseudoClasses->get() : 0);
264     bool needStyleRecalc = element != m_lastElementWithPseudoState || forcePseudoState != m_lastPseudoState;
265     m_lastPseudoState = forcePseudoState;
266     m_lastElementWithPseudoState = element;
267     if (needStyleRecalc)
268         element->ownerDocument()->styleSelectorChanged(RecalcStyleImmediately);
269
270     CSSStyleSelector* selector = element->ownerDocument()->styleSelector();
271     RefPtr<CSSRuleList> matchedRules = selector->styleRulesForElement(element, CSSStyleSelector::AllCSSRules);
272     resultObject->setArray("matchedCSSRules", buildArrayForRuleList(matchedRules.get()));
273
274     resultObject->setArray("styleAttributes", buildArrayForAttributeStyles(element));
275
276     RefPtr<InspectorArray> pseudoElements = InspectorArray::create();
277     for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
278         RefPtr<CSSRuleList> matchedRules = selector->pseudoStyleRulesForElement(element, pseudoId, CSSStyleSelector::AllCSSRules);
279         if (matchedRules && matchedRules->length()) {
280             RefPtr<InspectorObject> pseudoStyles = InspectorObject::create();
281             pseudoStyles->setNumber("pseudoId", static_cast<int>(pseudoId));
282             pseudoStyles->setArray("rules", buildArrayForRuleList(matchedRules.get()));
283             pseudoElements->pushObject(pseudoStyles.release());
284         }
285     }
286     resultObject->setArray("pseudoElements", pseudoElements.release());
287
288     RefPtr<InspectorArray> inheritedStyles = InspectorArray::create();
289     Element* parentElement = element->parentElement();
290     while (parentElement) {
291         RefPtr<InspectorObject> parentStyle = InspectorObject::create();
292         if (parentElement->style() && parentElement->style()->length()) {
293             InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);
294             if (styleSheet)
295                 parentStyle->setObject("inlineStyle", styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
296         }
297
298         CSSStyleSelector* parentSelector = parentElement->ownerDocument()->styleSelector();
299         RefPtr<CSSRuleList> parentMatchedRules = parentSelector->styleRulesForElement(parentElement, CSSStyleSelector::AllCSSRules);
300         parentStyle->setArray("matchedCSSRules", buildArrayForRuleList(parentMatchedRules.get()));
301         inheritedStyles->pushObject(parentStyle.release());
302         parentElement = parentElement->parentElement();
303     }
304     resultObject->setArray("inherited", inheritedStyles.release());
305
306     *result = resultObject.release();
307 }
308
309 void InspectorCSSAgent::getInlineStyleForNode(ErrorString* errorString, int nodeId, RefPtr<InspectorObject>* style)
310 {
311     Element* element = elementForId(errorString, nodeId);
312     if (!element)
313         return;
314
315     InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
316     if (!styleSheet)
317         return;
318
319     *style = styleSheet->buildObjectForStyle(element->style());
320 }
321
322 void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, RefPtr<InspectorObject>* style)
323 {
324     Element* element = elementForId(errorString, nodeId);
325     if (!element)
326         return;
327
328     RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = computedStyle(element, true);
329     RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
330     *style = inspectorStyle->buildObjectForStyle();
331 }
332
333 void InspectorCSSAgent::getAllStyleSheets(ErrorString*, RefPtr<InspectorArray>* styleInfos)
334 {
335     Vector<Document*> documents = m_domAgent->documents();
336     for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) {
337         StyleSheetList* list = (*it)->styleSheets();
338         for (unsigned i = 0; i < list->length(); ++i) {
339             StyleSheet* styleSheet = list->item(i);
340             if (styleSheet->isCSSStyleSheet())
341                 collectStyleSheets(static_cast<CSSStyleSheet*>(styleSheet), styleInfos->get());
342         }
343     }
344 }
345
346 void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<InspectorObject>* styleSheetObject)
347 {
348     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
349     if (!inspectorStyleSheet)
350         return;
351
352     *styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
353 }
354
355 void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result)
356 {
357     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
358     if (!inspectorStyleSheet)
359         return;
360
361     inspectorStyleSheet->text(result);
362 }
363
364 void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text)
365 {
366     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
367     if (!inspectorStyleSheet)
368         return;
369
370     if (inspectorStyleSheet->setText(text))
371         inspectorStyleSheet->reparseStyleSheet(text);
372     else
373         *errorString = "Internal error setting style sheet text";
374 }
375
376 void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<InspectorObject>* result)
377 {
378     InspectorCSSId compoundId(fullStyleId);
379     ASSERT(!compoundId.isEmpty());
380
381     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
382     if (!inspectorStyleSheet)
383         return;
384
385     bool success = inspectorStyleSheet->setPropertyText(errorString, compoundId, propertyIndex, text, overwrite);
386     if (success)
387         *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
388 }
389
390 void InspectorCSSAgent::toggleProperty(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<InspectorObject>* result)
391 {
392     InspectorCSSId compoundId(fullStyleId);
393     ASSERT(!compoundId.isEmpty());
394
395     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
396     if (!inspectorStyleSheet)
397         return;
398
399     bool success = inspectorStyleSheet->toggleProperty(errorString, compoundId, propertyIndex, disable);
400     if (success)
401         *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
402 }
403
404 void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<InspectorObject>* result)
405 {
406     InspectorCSSId compoundId(fullRuleId);
407     ASSERT(!compoundId.isEmpty());
408
409     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
410     if (!inspectorStyleSheet)
411         return;
412
413     bool success = inspectorStyleSheet->setRuleSelector(compoundId, selector);
414     if (!success)
415         return;
416
417     *result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId));
418 }
419
420 void InspectorCSSAgent::addRule(ErrorString*, const int contextNodeId, const String& selector, RefPtr<InspectorObject>* result)
421 {
422     Node* node = m_domAgent->nodeForId(contextNodeId);
423     if (!node)
424         return;
425
426     InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true);
427     if (!inspectorStyleSheet)
428         return;
429     CSSStyleRule* newRule = inspectorStyleSheet->addRule(selector);
430     if (!newRule)
431         return;
432
433     *result = inspectorStyleSheet->buildObjectForRule(newRule);
434 }
435
436 void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<InspectorArray>* cssProperties)
437 {
438     RefPtr<InspectorArray> properties = InspectorArray::create();
439     for (int i = 0; i < numCSSProperties; ++i)
440         properties->pushString(propertyNameStrings[i]);
441
442     *cssProperties = properties.release();
443 }
444
445 // static
446 Element* InspectorCSSAgent::inlineStyleElement(CSSStyleDeclaration* style)
447 {
448     if (!style || !style->isMutableStyleDeclaration())
449         return 0;
450     Node* node = static_cast<CSSMutableStyleDeclaration*>(style)->node();
451     if (!node || !node->isStyledElement() || static_cast<StyledElement*>(node)->getInlineStyleDecl() != style)
452         return 0;
453     return static_cast<Element*>(node);
454 }
455
456 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
457 {
458     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
459     if (it == m_nodeToInspectorStyleSheet.end()) {
460         CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
461         if (!style)
462             return 0;
463
464         String newStyleSheetId = String::number(m_lastStyleSheetId++);
465         RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(newStyleSheetId, element, "");
466         m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
467         m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
468         return inspectorStyleSheet.get();
469     }
470
471     return it->second.get();
472 }
473
474 Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
475 {
476     Node* node = m_domAgent->nodeForId(nodeId);
477     if (!node) {
478         *errorString = "No node with given id found";
479         return 0;
480     }
481     if (node->nodeType() != Node::ELEMENT_NODE) {
482         *errorString = "Not an element node";
483         return 0;
484     }
485     return static_cast<Element*>(node);
486 }
487
488 void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, InspectorArray* result)
489 {
490     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet));
491     result->pushObject(inspectorStyleSheet->buildObjectForStyleSheetInfo());
492     for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
493         StyleBase* styleBase = styleSheet->item(i);
494         if (styleBase->isImportRule()) {
495             StyleBase* importedStyleSheet = static_cast<CSSImportRule*>(styleBase)->styleSheet();
496             if (importedStyleSheet && importedStyleSheet->isCSSStyleSheet())
497                 collectStyleSheets(static_cast<CSSStyleSheet*>(importedStyleSheet), result);
498         }
499     }
500 }
501
502 InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
503 {
504     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
505     if (!inspectorStyleSheet) {
506         String id = String::number(m_lastStyleSheetId++);
507         inspectorStyleSheet = InspectorStyleSheet::create(id, styleSheet, detectOrigin(styleSheet, styleSheet->document()), m_domAgent->documentURLString(styleSheet->document()));
508         m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
509         m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
510     }
511     return inspectorStyleSheet.get();
512 }
513
514 InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
515 {
516     if (!document) {
517         ASSERT(!createIfAbsent);
518         return 0;
519     }
520
521     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
522     if (inspectorStyleSheet || !createIfAbsent)
523         return inspectorStyleSheet.get();
524
525     ExceptionCode ec = 0;
526     RefPtr<Element> styleElement = document->createElement("style", ec);
527     if (!ec)
528         styleElement->setAttribute("type", "text/css", ec);
529     if (!ec) {
530         ContainerNode* targetNode;
531         // HEAD is absent in ImageDocuments, for example.
532         if (document->head())
533             targetNode = document->head();
534         else if (document->body())
535             targetNode = document->body();
536         else
537             return 0;
538         targetNode->appendChild(styleElement, ec);
539     }
540     if (ec)
541         return 0;
542     StyleSheetList* styleSheets = document->styleSheets();
543     StyleSheet* styleSheet = styleSheets->item(styleSheets->length() - 1);
544     if (!styleSheet->isCSSStyleSheet())
545         return 0;
546     CSSStyleSheet* cssStyleSheet = static_cast<CSSStyleSheet*>(styleSheet);
547     String id = String::number(m_lastStyleSheetId++);
548     inspectorStyleSheet = InspectorStyleSheet::create(id, cssStyleSheet, "inspector", m_domAgent->documentURLString(document));
549     m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
550     m_cssStyleSheetToInspectorStyleSheet.set(cssStyleSheet, inspectorStyleSheet);
551     m_documentToInspectorStyleSheet.set(document, inspectorStyleSheet);
552     return inspectorStyleSheet.get();
553 }
554
555 InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
556 {
557     IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
558     if (it == m_idToInspectorStyleSheet.end()) {
559         *errorString = "No style sheet with given id found";
560         return 0;
561     }
562     return it->second.get();
563 }
564
565 String InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
566 {
567     DEFINE_STATIC_LOCAL(String, userAgent, ("user-agent"));
568     DEFINE_STATIC_LOCAL(String, user, ("user"));
569     DEFINE_STATIC_LOCAL(String, inspector, ("inspector"));
570
571     String origin("");
572     if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
573         origin = userAgent;
574     else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
575         origin = user;
576     else {
577         InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
578         if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
579             origin = inspector;
580     }
581     return origin;
582 }
583
584 PassRefPtr<InspectorArray> InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList)
585 {
586     RefPtr<InspectorArray> result = InspectorArray::create();
587     if (!ruleList)
588         return result.release();
589
590     for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
591         CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
592         if (!rule)
593             continue;
594
595         InspectorStyleSheet* styleSheet = bindStyleSheet(parentStyleSheet(rule));
596         if (styleSheet)
597             result->pushObject(styleSheet->buildObjectForRule(rule));
598     }
599     return result.release();
600 }
601
602 PassRefPtr<InspectorArray> InspectorCSSAgent::buildArrayForAttributeStyles(Element* element)
603 {
604     RefPtr<InspectorArray> attrStyles = InspectorArray::create();
605     NamedNodeMap* attributes = element->attributes();
606     for (unsigned i = 0; attributes && i < attributes->length(); ++i) {
607         Attribute* attribute = attributes->attributeItem(i);
608         if (attribute->style()) {
609             RefPtr<InspectorObject> attrStyleObject = InspectorObject::create();
610             String attributeName = attribute->localName();
611             RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), attribute->style(), 0);
612             attrStyleObject->setString("name", attributeName.utf8().data());
613             attrStyleObject->setObject("style", inspectorStyle->buildObjectForStyle());
614             attrStyles->pushObject(attrStyleObject.release());
615         }
616     }
617
618     return attrStyles.release();
619 }
620
621 void InspectorCSSAgent::didRemoveDocument(Document* document)
622 {
623     if (document)
624         m_documentToInspectorStyleSheet.remove(document);
625     clearPseudoState(false);
626 }
627
628 void InspectorCSSAgent::didRemoveDOMNode(Node* node)
629 {
630     if (!node)
631         return;
632
633     if (m_lastElementWithPseudoState.get() == node) {
634         clearPseudoState(false);
635         return;
636     }
637
638     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
639     if (it == m_nodeToInspectorStyleSheet.end())
640         return;
641
642     m_idToInspectorStyleSheet.remove(it->second->id());
643     m_nodeToInspectorStyleSheet.remove(node);
644 }
645
646 void InspectorCSSAgent::didModifyDOMAttr(Element* element)
647 {
648     if (!element)
649         return;
650
651     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
652     if (it == m_nodeToInspectorStyleSheet.end())
653         return;
654
655     it->second->didModifyElementAttribute();
656 }
657
658 void InspectorCSSAgent::clearPseudoState(bool recalcStyles)
659 {
660     RefPtr<Element> element = m_lastElementWithPseudoState;
661     m_lastElementWithPseudoState = 0;
662     m_lastPseudoState = 0;
663     if (recalcStyles && element) {
664         Document* document = element->ownerDocument();
665         if (document)
666             document->styleSelectorChanged(RecalcStyleImmediately);
667     }
668 }
669
670 } // namespace WebCore
671
672 #endif // ENABLE(INSPECTOR)