tizen beta release
[profile/ivi/webkit-efl.git] / Source / WebCore / inspector / InspectorStyleSheet.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 "InspectorStyleSheet.h"
27
28 #if ENABLE(INSPECTOR)
29
30 #include "CSSImportRule.h"
31 #include "CSSMediaRule.h"
32 #include "CSSParser.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 "Document.h"
40 #include "Element.h"
41 #include "HTMLHeadElement.h"
42 #include "HTMLNames.h"
43 #include "HTMLParserIdioms.h"
44 #include "InspectorCSSAgent.h"
45 #include "InspectorPageAgent.h"
46 #include "InspectorValues.h"
47 #include "Node.h"
48 #include "SVGNames.h"
49 #include "StyleSheetList.h"
50 #include "WebKitCSSKeyframesRule.h"
51
52 #include <wtf/OwnPtr.h>
53 #include <wtf/PassOwnPtr.h>
54 #include <wtf/Vector.h>
55
56 class ParsedStyleSheet {
57 public:
58     typedef Vector<RefPtr<WebCore::CSSRuleSourceData> > SourceData;
59     ParsedStyleSheet();
60
61     WebCore::CSSStyleSheet* cssStyleSheet() const { return m_parserOutput; }
62     const String& text() const { return m_text; }
63     void setText(const String& text);
64     bool hasText() const { return m_hasText; }
65     SourceData* sourceData() const { return m_sourceData.get(); }
66     void setSourceData(PassOwnPtr<SourceData> sourceData);
67     bool hasSourceData() const { return m_sourceData; }
68     RefPtr<WebCore::CSSRuleSourceData> ruleSourceDataAt(unsigned index) const;
69
70 private:
71
72     // StyleSheet constructed while parsing m_text.
73     WebCore::CSSStyleSheet* m_parserOutput;
74     String m_text;
75     bool m_hasText;
76     OwnPtr<SourceData> m_sourceData;
77 };
78
79 ParsedStyleSheet::ParsedStyleSheet()
80     : m_parserOutput(0)
81     , m_hasText(false)
82 {
83 }
84
85 void ParsedStyleSheet::setText(const String& text)
86 {
87     m_hasText = true;
88     m_text = text;
89     setSourceData(nullptr);
90 }
91
92 void ParsedStyleSheet::setSourceData(PassOwnPtr<SourceData> sourceData)
93 {
94     m_sourceData = sourceData;
95 }
96
97 RefPtr<WebCore::CSSRuleSourceData> ParsedStyleSheet::ruleSourceDataAt(unsigned index) const
98 {
99     if (!hasSourceData() || index >= m_sourceData->size())
100         return 0;
101
102     return m_sourceData->at(index);
103 }
104
105 namespace WebCore {
106
107 enum MediaListSource {
108     MediaListSourceLinkedSheet,
109     MediaListSourceInlineSheet,
110     MediaListSourceMediaRule,
111     MediaListSourceImportRule
112 };
113
114 static PassRefPtr<InspectorObject> buildSourceRangeObject(const SourceRange& range)
115 {
116     RefPtr<InspectorObject> result = InspectorObject::create();
117     result->setNumber("start", range.start);
118     result->setNumber("end", range.end);
119     return result.release();
120 }
121
122 static PassRefPtr<InspectorObject> buildMediaObject(const MediaList* media, MediaListSource mediaListSource, const String& sourceURL)
123 {
124     RefPtr<InspectorObject> mediaObject = InspectorObject::create();
125     switch (mediaListSource) {
126     case MediaListSourceMediaRule:
127         mediaObject->setString("source", "mediaRule");
128         break;
129     case MediaListSourceImportRule:
130         mediaObject->setString("source", "importRule");
131         break;
132     case MediaListSourceLinkedSheet:
133         mediaObject->setString("source", "linkedSheet");
134         break;
135     case MediaListSourceInlineSheet:
136         mediaObject->setString("source", "inlineSheet");
137         break;
138     }
139     if (!sourceURL.isEmpty()) {
140         mediaObject->setString("sourceURL", sourceURL);
141         mediaObject->setNumber("sourceLine", media->lastLine());
142     }
143     mediaObject->setString("text", media->mediaText());
144     return mediaObject.release();
145 }
146
147 static PassRefPtr<CSSRuleList> asCSSRuleList(CSSStyleSheet* styleSheet)
148 {
149     if (!styleSheet)
150         return 0;
151
152     return CSSRuleList::create(styleSheet, true);
153 }
154
155 static PassRefPtr<CSSRuleList> asCSSRuleList(CSSRule* rule)
156 {
157     if (!rule)
158         return 0;
159
160     if (rule->isMediaRule())
161         return static_cast<CSSMediaRule*>(rule)->cssRules();
162
163     if (rule->isKeyframesRule())
164         return static_cast<WebKitCSSKeyframesRule*>(rule)->cssRules();
165
166     return 0;
167 }
168
169 static void fillMediaListChain(CSSRule* rule, InspectorArray* mediaArray)
170 {
171     MediaList* mediaList;
172     CSSRule* parentRule = rule;
173     String sourceURL;
174     while (parentRule) {
175         CSSStyleSheet* parentStyleSheet = 0;
176         bool isMediaRule = true;
177         if (parentRule->isMediaRule()) {
178             CSSMediaRule* mediaRule = static_cast<CSSMediaRule*>(parentRule);
179             mediaList = mediaRule->media();
180             parentStyleSheet = mediaRule->parentStyleSheet();
181         } else if (parentRule->isImportRule()) {
182             CSSImportRule* importRule = static_cast<CSSImportRule*>(parentRule);
183             mediaList = importRule->media();
184             parentStyleSheet = importRule->parentStyleSheet();
185             isMediaRule = false;
186         } else
187             mediaList = 0;
188
189         if (parentStyleSheet) {
190             sourceURL = parentStyleSheet->finalURL();
191             if (sourceURL.isEmpty())
192                 sourceURL = InspectorDOMAgent::documentURLString(parentStyleSheet->findDocument());
193         } else
194             sourceURL = "";
195
196         if (mediaList && mediaList->length())
197             mediaArray->pushObject(buildMediaObject(mediaList, isMediaRule ? MediaListSourceMediaRule : MediaListSourceImportRule, sourceURL));
198
199         if (parentRule->parentRule())
200             parentRule = parentRule->parentRule();
201         else {
202             CSSStyleSheet* styleSheet = parentRule->parentStyleSheet();
203             while (styleSheet) {
204                 mediaList = styleSheet->media();
205                 if (mediaList && mediaList->length()) {
206                     Document* doc = styleSheet->findDocument();
207                     if (doc)
208                         sourceURL = doc->url();
209                     else if (!styleSheet->finalURL().isEmpty())
210                         sourceURL = styleSheet->finalURL();
211                     else
212                         sourceURL = "";
213                     mediaArray->pushObject(buildMediaObject(mediaList, styleSheet->ownerNode() ? MediaListSourceLinkedSheet : MediaListSourceInlineSheet, sourceURL));
214                 }
215                 parentRule = styleSheet->parentRule();
216                 if (parentRule)
217                     break;
218                 styleSheet = styleSheet->parentStyleSheet();
219             }
220         }
221     }
222 }
223
224 PassRefPtr<InspectorStyle> InspectorStyle::create(const InspectorCSSId& styleId, PassRefPtr<CSSStyleDeclaration> style, InspectorStyleSheet* parentStyleSheet)
225 {
226     return adoptRef(new InspectorStyle(styleId, style, parentStyleSheet));
227 }
228
229 InspectorStyle::InspectorStyle(const InspectorCSSId& styleId, PassRefPtr<CSSStyleDeclaration> style, InspectorStyleSheet* parentStyleSheet)
230     : m_styleId(styleId)
231     , m_style(style)
232     , m_parentStyleSheet(parentStyleSheet)
233     , m_formatAcquired(false)
234 {
235     ASSERT(m_style);
236 }
237
238 InspectorStyle::~InspectorStyle()
239 {
240 }
241
242 PassRefPtr<InspectorObject> InspectorStyle::buildObjectForStyle() const
243 {
244     RefPtr<InspectorObject> result = InspectorObject::create();
245     if (!m_styleId.isEmpty())
246         result->setValue("styleId", m_styleId.asInspectorValue());
247
248     result->setString("width", m_style->getPropertyValue("width"));
249     result->setString("height", m_style->getPropertyValue("height"));
250
251     RefPtr<CSSRuleSourceData> sourceData = m_parentStyleSheet ? m_parentStyleSheet->ruleSourceDataFor(m_style.get()) : 0;
252     if (sourceData)
253         result->setObject("range", buildSourceRangeObject(sourceData->styleSourceData->styleBodyRange));
254
255     populateObjectWithStyleProperties(result.get());
256
257     return result.release();
258 }
259
260 PassRefPtr<InspectorArray> InspectorStyle::buildArrayForComputedStyle() const
261 {
262     RefPtr<InspectorArray> result = InspectorArray::create();
263     Vector<InspectorStyleProperty> properties;
264     populateAllProperties(&properties);
265
266     for (Vector<InspectorStyleProperty>::iterator it = properties.begin(), itEnd = properties.end(); it != itEnd; ++it) {
267         const CSSPropertySourceData& propertyEntry = it->sourceData;
268         RefPtr<InspectorObject> entry = InspectorObject::create();
269         entry->setString("name", propertyEntry.name);
270         entry->setString("value", propertyEntry.value);
271         result->pushObject(entry);
272     }
273
274     return result.release();
275 }
276
277 // This method does the following preprocessing of |propertyText| with |overwrite| == false and |index| past the last active property:
278 // - If the last property (if present) has no closing ";", the ";" is prepended to the current |propertyText| value.
279 // - A heuristic formatting is attempted to retain the style structure.
280 //
281 // The propertyText (if not empty) is checked to be a valid style declaration (containing at least one property). If not,
282 // the method returns false (denoting an error).
283 bool InspectorStyle::setPropertyText(ErrorString* errorString, unsigned index, const String& propertyText, bool overwrite)
284 {
285     ASSERT(m_parentStyleSheet);
286     DEFINE_STATIC_LOCAL(String, bogusPropertyName, ("-webkit-boguz-propertee"));
287
288     if (!m_parentStyleSheet->ensureParsedDataReady()) {
289         *errorString = "Internal error: no stylesheet parsed data available";
290         return false;
291     }
292
293     Vector<InspectorStyleProperty> allProperties;
294     populateAllProperties(&allProperties);
295
296     if (propertyText.stripWhiteSpace().length()) {
297         RefPtr<CSSMutableStyleDeclaration> tempMutableStyle = CSSMutableStyleDeclaration::create();
298         RefPtr<CSSStyleSourceData> sourceData = CSSStyleSourceData::create();
299         CSSParser p;
300         p.parseDeclaration(tempMutableStyle.get(), propertyText + " " + bogusPropertyName + ": none", &sourceData, m_style->parentStyleSheet());
301         Vector<CSSPropertySourceData>& propertyData = sourceData->propertyData;
302         unsigned propertyCount = propertyData.size();
303
304         // At least one property + the bogus property added just above should be present.
305         if (propertyCount < 2) {
306             *errorString = "Invalid property value";
307             return false;
308         }
309
310         // Check for a proper propertyText termination (the parser could at least restore to the PROPERTY_NAME state).
311         if (propertyData.at(propertyCount - 1).name != bogusPropertyName) {
312             *errorString = "Invalid property value";
313             return false;
314         }
315     }
316
317     RefPtr<CSSRuleSourceData> sourceData = m_parentStyleSheet->ruleSourceDataFor(m_style.get());
318     if (!sourceData) {
319         *errorString = "Internal error: no CSS rule source found";
320         return false;
321     }
322
323     String text;
324     bool success = styleText(&text);
325     if (!success) {
326         *errorString = "Internal error: could not fetch style text";
327         return false;
328     }
329
330     InspectorStyleTextEditor editor(&allProperties, &m_disabledProperties, text, newLineAndWhitespaceDelimiters());
331     if (overwrite)
332         editor.replaceProperty(index, propertyText);
333     else
334         editor.insertProperty(index, propertyText, sourceData->styleSourceData->styleBodyRange.length());
335
336     return applyStyleText(editor.styleText());
337 }
338
339 bool InspectorStyle::toggleProperty(ErrorString* errorString, unsigned index, bool disable)
340 {
341     ASSERT(m_parentStyleSheet);
342     if (!m_parentStyleSheet->ensureParsedDataReady()) {
343         *errorString = "Can toggle only source-based properties";
344         return false;
345     }
346
347     RefPtr<CSSRuleSourceData> sourceData = m_parentStyleSheet->ruleSourceDataFor(m_style.get());
348     if (!sourceData) {
349         *errorString = "Internal error: No source data for the style found";
350         return false;
351     }
352
353     String text;
354     bool success = styleText(&text);
355     if (!success) {
356         *errorString = "Internal error: could not fetch style text";
357         return false;
358     }
359
360     Vector<InspectorStyleProperty> allProperties;
361     populateAllProperties(&allProperties);
362     if (index >= allProperties.size()) {
363         *errorString = "Property index is outside of property range";
364         return false;
365     }
366
367     InspectorStyleProperty& property = allProperties.at(index);
368     if (property.disabled == disable)
369         return true; // Idempotent operation.
370
371     InspectorStyleTextEditor editor(&allProperties, &m_disabledProperties, text, newLineAndWhitespaceDelimiters());
372     if (disable)
373         editor.disableProperty(index);
374     else
375         editor.enableProperty(index);
376
377     return applyStyleText(editor.styleText());
378 }
379
380 bool InspectorStyle::styleText(String* result) const
381 {
382     // Precondition: m_parentStyleSheet->ensureParsedDataReady() has been called successfully.
383     RefPtr<CSSRuleSourceData> sourceData = m_parentStyleSheet->ruleSourceDataFor(m_style.get());
384     if (!sourceData)
385         return false;
386
387     String styleSheetText;
388     bool success = m_parentStyleSheet->text(&styleSheetText);
389     if (!success)
390         return false;
391
392     SourceRange& bodyRange = sourceData->styleSourceData->styleBodyRange;
393     *result = styleSheetText.substring(bodyRange.start, bodyRange.end - bodyRange.start);
394     return true;
395 }
396
397 bool InspectorStyle::populateAllProperties(Vector<InspectorStyleProperty>* result) const
398 {
399     HashSet<String> foundShorthands;
400     HashSet<String> sourcePropertyNames;
401     unsigned disabledIndex = 0;
402     unsigned disabledLength = m_disabledProperties.size();
403     InspectorStyleProperty disabledProperty;
404     if (disabledIndex < disabledLength)
405         disabledProperty = m_disabledProperties.at(disabledIndex);
406
407     RefPtr<CSSRuleSourceData> sourceData = (m_parentStyleSheet && m_parentStyleSheet->ensureParsedDataReady()) ? m_parentStyleSheet->ruleSourceDataFor(m_style.get()) : 0;
408     Vector<CSSPropertySourceData>* sourcePropertyData = sourceData ? &(sourceData->styleSourceData->propertyData) : 0;
409     if (sourcePropertyData) {
410         String styleDeclaration;
411         bool isStyleTextKnown = styleText(&styleDeclaration);
412         ASSERT_UNUSED(isStyleTextKnown, isStyleTextKnown);
413         for (Vector<CSSPropertySourceData>::const_iterator it = sourcePropertyData->begin(); it != sourcePropertyData->end(); ++it) {
414             while (disabledIndex < disabledLength && disabledProperty.sourceData.range.start <= it->range.start) {
415                 result->append(disabledProperty);
416                 if (++disabledIndex < disabledLength)
417                     disabledProperty = m_disabledProperties.at(disabledIndex);
418             }
419             InspectorStyleProperty p(*it, true, false);
420             p.setRawTextFromStyleDeclaration(styleDeclaration);
421             result->append(p);
422             sourcePropertyNames.add(it->name.lower());
423         }
424     }
425
426     while (disabledIndex < disabledLength) {
427         disabledProperty = m_disabledProperties.at(disabledIndex++);
428         result->append(disabledProperty);
429     }
430
431     for (int i = 0, size = m_style->length(); i < size; ++i) {
432         String name = m_style->item(i);
433         if (sourcePropertyNames.contains(name.lower()))
434             continue;
435
436         sourcePropertyNames.add(name.lower());
437         result->append(InspectorStyleProperty(CSSPropertySourceData(name, m_style->getPropertyValue(name), !m_style->getPropertyPriority(name).isEmpty(), true, SourceRange()), false, false));
438     }
439
440     return true;
441 }
442
443 void InspectorStyle::populateObjectWithStyleProperties(InspectorObject* result) const
444 {
445     Vector<InspectorStyleProperty> properties;
446     populateAllProperties(&properties);
447
448     RefPtr<InspectorArray> propertiesObject = InspectorArray::create();
449     RefPtr<InspectorArray> shorthandEntries = InspectorArray::create();
450     HashMap<String, RefPtr<InspectorObject> > propertyNameToPreviousActiveProperty;
451     HashSet<String> foundShorthands;
452
453     for (Vector<InspectorStyleProperty>::iterator it = properties.begin(), itEnd = properties.end(); it != itEnd; ++it) {
454         const CSSPropertySourceData& propertyEntry = it->sourceData;
455         const String& name = propertyEntry.name;
456
457         RefPtr<InspectorObject> property = InspectorObject::create();
458         propertiesObject->pushObject(property);
459         String status = it->disabled ? "disabled" : "active";
460
461         // Default "parsedOk" == true.
462         if (!propertyEntry.parsedOk)
463             property->setBoolean("parsedOk", false);
464         if (it->hasRawText())
465             property->setString("text", it->rawText);
466         property->setString("name", name);
467         property->setString("value", propertyEntry.value);
468
469         // Default "priority" == "".
470         if (propertyEntry.important)
471             property->setString("priority", "important");
472         if (!it->disabled) {
473             if (it->hasSource) {
474                 property->setBoolean("implicit", false);
475                 property->setObject("range", buildSourceRangeObject(propertyEntry.range));
476
477                 // Parsed property overrides any property with the same name. Non-parsed property overrides
478                 // previous non-parsed property with the same name (if any).
479                 bool shouldInactivate = false;
480                 HashMap<String, RefPtr<InspectorObject> >::iterator activeIt = propertyNameToPreviousActiveProperty.find(name);
481                 if (activeIt != propertyNameToPreviousActiveProperty.end()) {
482                     if (propertyEntry.parsedOk)
483                         shouldInactivate = true;
484                     else {
485                         bool previousParsedOk;
486                         bool success = activeIt->second->getBoolean("parsedOk", &previousParsedOk);
487                         if (success && !previousParsedOk)
488                             shouldInactivate = true;
489                     }
490                 } else
491                     propertyNameToPreviousActiveProperty.set(name, property);
492
493                 if (shouldInactivate) {
494                     activeIt->second->setString("status", "inactive");
495                     activeIt->second->remove("shorthandName");
496                     propertyNameToPreviousActiveProperty.set(name, property);
497                 }
498             } else {
499                 bool implicit = m_style->isPropertyImplicit(name);
500                 // Default "implicit" == false.
501                 if (implicit)
502                     property->setBoolean("implicit", true);
503                 status = "";
504             }
505         }
506
507         // Default "status" == "style".
508         if (!status.isEmpty())
509             property->setString("status", status);
510
511         if (propertyEntry.parsedOk) {
512             // Both for style-originated and parsed source properties.
513             String shorthand = m_style->getPropertyShorthand(name);
514             if (!shorthand.isEmpty()) {
515                 // Default "shorthandName" == "".
516                 property->setString("shorthandName", shorthand);
517                 if (!foundShorthands.contains(shorthand)) {
518                     foundShorthands.add(shorthand);
519                     RefPtr<InspectorObject> shorthandEntry = InspectorObject::create();
520                     shorthandEntry->setString("name", shorthand);
521                     shorthandEntry->setString("value", shorthandValue(shorthand));
522                     shorthandEntries->pushObject(shorthandEntry.release());
523                 }
524             }
525         }
526         // else shorthandName is not set
527     }
528
529     result->setArray("cssProperties", propertiesObject);
530     result->setArray("shorthandEntries", shorthandEntries);
531 }
532
533 bool InspectorStyle::applyStyleText(const String& text)
534 {
535     return m_parentStyleSheet->setStyleText(m_style.get(), text);
536 }
537
538 String InspectorStyle::shorthandValue(const String& shorthandProperty) const
539 {
540     String value = m_style->getPropertyValue(shorthandProperty);
541     if (value.isEmpty()) {
542         for (unsigned i = 0; i < m_style->length(); ++i) {
543             String individualProperty = m_style->item(i);
544             if (m_style->getPropertyShorthand(individualProperty) != shorthandProperty)
545                 continue;
546             if (m_style->isPropertyImplicit(individualProperty))
547                 continue;
548             String individualValue = m_style->getPropertyValue(individualProperty);
549             if (individualValue == "initial")
550                 continue;
551             if (value.length())
552                 value.append(" ");
553             value.append(individualValue);
554         }
555     }
556     return value;
557 }
558
559 String InspectorStyle::shorthandPriority(const String& shorthandProperty) const
560 {
561     String priority = m_style->getPropertyPriority(shorthandProperty);
562     if (priority.isEmpty()) {
563         for (unsigned i = 0; i < m_style->length(); ++i) {
564             String individualProperty = m_style->item(i);
565             if (m_style->getPropertyShorthand(individualProperty) != shorthandProperty)
566                 continue;
567             priority = m_style->getPropertyPriority(individualProperty);
568             break;
569         }
570     }
571     return priority;
572 }
573
574 Vector<String> InspectorStyle::longhandProperties(const String& shorthandProperty) const
575 {
576     Vector<String> properties;
577     HashSet<String> foundProperties;
578     for (unsigned i = 0; i < m_style->length(); ++i) {
579         String individualProperty = m_style->item(i);
580         if (foundProperties.contains(individualProperty) || m_style->getPropertyShorthand(individualProperty) != shorthandProperty)
581             continue;
582
583         foundProperties.add(individualProperty);
584         properties.append(individualProperty);
585     }
586     return properties;
587 }
588
589 NewLineAndWhitespace& InspectorStyle::newLineAndWhitespaceDelimiters() const
590 {
591     DEFINE_STATIC_LOCAL(String, defaultPrefix, ("    "));
592
593     if (m_formatAcquired)
594         return m_format;
595
596     RefPtr<CSSRuleSourceData> sourceData = (m_parentStyleSheet && m_parentStyleSheet->ensureParsedDataReady()) ? m_parentStyleSheet->ruleSourceDataFor(m_style.get()) : 0;
597     Vector<CSSPropertySourceData>* sourcePropertyData = sourceData ? &(sourceData->styleSourceData->propertyData) : 0;
598     int propertyCount;
599     if (!sourcePropertyData || !(propertyCount = sourcePropertyData->size())) {
600         m_format.first = "\n";
601         m_format.second = defaultPrefix;
602         return m_format; // Do not remember the default formatting and attempt to acquire it later.
603     }
604
605     String text;
606     bool success = styleText(&text);
607     ASSERT_UNUSED(success, success);
608
609     m_formatAcquired = true;
610
611     String formatLineFeed = "";
612     String formatPropertyPrefix = "";
613     String prefix;
614     String candidatePrefix = defaultPrefix;
615     int scanStart = 0;
616     int propertyIndex = 0;
617     bool isFullPrefixScanned = false;
618     bool lineFeedTerminated = false;
619     const UChar* characters = text.characters();
620     while (propertyIndex < propertyCount) {
621         const WebCore::CSSPropertySourceData& currentProperty = sourcePropertyData->at(propertyIndex++);
622
623         bool processNextProperty = false;
624         int scanEnd = currentProperty.range.start;
625         for (int i = scanStart; i < scanEnd; ++i) {
626             UChar ch = characters[i];
627             bool isLineFeed = isHTMLLineBreak(ch);
628             if (isLineFeed) {
629                 if (!lineFeedTerminated)
630                     formatLineFeed.append(ch);
631             } else if (isHTMLSpace(ch))
632                 prefix.append(ch);
633             else {
634                 candidatePrefix = prefix;
635                 prefix = "";
636                 scanStart = currentProperty.range.end;
637                 ++propertyIndex;
638                 processNextProperty = true;
639                 break;
640             }
641             if (!isLineFeed && formatLineFeed.length())
642                 lineFeedTerminated = true;
643         }
644         if (!processNextProperty) {
645             isFullPrefixScanned = true;
646             break;
647         }
648     }
649
650     m_format.first = formatLineFeed;
651     m_format.second = isFullPrefixScanned ? prefix : candidatePrefix;
652     return m_format;
653 }
654
655 PassRefPtr<InspectorStyleSheet> InspectorStyleSheet::create(const String& id, PassRefPtr<CSSStyleSheet> pageStyleSheet, const String& origin, const String& documentURL)
656 {
657     return adoptRef(new InspectorStyleSheet(id, pageStyleSheet, origin, documentURL));
658 }
659
660 InspectorStyleSheet::InspectorStyleSheet(const String& id, PassRefPtr<CSSStyleSheet> pageStyleSheet, const String& origin, const String& documentURL)
661     : m_id(id)
662     , m_pageStyleSheet(pageStyleSheet)
663     , m_origin(origin)
664     , m_documentURL(documentURL)
665     , m_isRevalidating(false)
666 {
667     m_parsedStyleSheet = new ParsedStyleSheet();
668 }
669
670 InspectorStyleSheet::~InspectorStyleSheet()
671 {
672     delete m_parsedStyleSheet;
673 }
674
675 String InspectorStyleSheet::finalURL() const
676 {
677     if (m_pageStyleSheet && !m_pageStyleSheet->finalURL().isEmpty())
678         return m_pageStyleSheet->finalURL().string();
679     return m_documentURL;
680 }
681
682 void InspectorStyleSheet::reparseStyleSheet(const String& text)
683 {
684     for (unsigned i = 0, size = m_pageStyleSheet->length(); i < size; ++i)
685         m_pageStyleSheet->remove(0);
686     m_pageStyleSheet->parseString(text, m_pageStyleSheet->useStrictParsing());
687     m_pageStyleSheet->styleSheetChanged();
688     m_inspectorStyles.clear();
689 }
690
691 bool InspectorStyleSheet::setText(const String& text)
692 {
693     if (!m_parsedStyleSheet)
694         return false;
695
696     m_parsedStyleSheet->setText(text);
697     m_flatRules.clear();
698
699     return true;
700 }
701
702 bool InspectorStyleSheet::setRuleSelector(const InspectorCSSId& id, const String& selector)
703 {
704     CSSStyleRule* rule = ruleForId(id);
705     if (!rule)
706         return false;
707     CSSStyleSheet* styleSheet = InspectorCSSAgent::parentStyleSheet(rule);
708     if (!styleSheet || !ensureParsedDataReady())
709         return false;
710
711     rule->setSelectorText(selector);
712     RefPtr<CSSRuleSourceData> sourceData = ruleSourceDataFor(rule->style());
713     if (!sourceData)
714         return false;
715
716     String sheetText = m_parsedStyleSheet->text();
717     sheetText.replace(sourceData->selectorListRange.start, sourceData->selectorListRange.end - sourceData->selectorListRange.start, selector);
718     m_parsedStyleSheet->setText(sheetText);
719     return true;
720 }
721
722 CSSStyleRule* InspectorStyleSheet::addRule(const String& selector)
723 {
724     String styleSheetText;
725     bool success = text(&styleSheetText);
726     if (!success)
727         return 0;
728
729     ExceptionCode ec = 0;
730     m_pageStyleSheet->addRule(selector, "", ec);
731     if (ec)
732         return 0;
733     RefPtr<CSSRuleList> rules = m_pageStyleSheet->cssRules();
734     ASSERT(rules->length());
735     CSSStyleRule* rule = InspectorCSSAgent::asCSSStyleRule(rules->item(rules->length() - 1));
736     ASSERT(rule);
737
738     if (styleSheetText.length())
739         styleSheetText += "\n";
740
741     styleSheetText += selector;
742     styleSheetText += " {}";
743     // Using setText() as this operation changes the style sheet rule set.
744     setText(styleSheetText);
745
746     return rule;
747 }
748
749 CSSStyleRule* InspectorStyleSheet::ruleForId(const InspectorCSSId& id) const
750 {
751     if (!m_pageStyleSheet)
752         return 0;
753
754     ASSERT(!id.isEmpty());
755     ensureFlatRules();
756     return id.ordinal() >= m_flatRules.size() ? 0 : m_flatRules.at(id.ordinal());
757
758 }
759
760 PassRefPtr<InspectorObject> InspectorStyleSheet::buildObjectForStyleSheet()
761 {
762     CSSStyleSheet* styleSheet = pageStyleSheet();
763     if (!styleSheet)
764         return 0;
765
766     RefPtr<InspectorObject> result = InspectorObject::create();
767     result->setString("styleSheetId", id());
768     RefPtr<CSSRuleList> cssRuleList = CSSRuleList::create(styleSheet, true);
769     RefPtr<InspectorArray> cssRules = buildArrayForRuleList(cssRuleList.get());
770     result->setArray("rules", cssRules.release());
771
772     String styleSheetText;
773     bool success = text(&styleSheetText);
774     if (success)
775         result->setString("text", styleSheetText);
776
777     return result.release();
778 }
779
780 PassRefPtr<InspectorObject> InspectorStyleSheet::buildObjectForStyleSheetInfo()
781 {
782     CSSStyleSheet* styleSheet = pageStyleSheet();
783     if (!styleSheet)
784         return 0;
785
786     RefPtr<InspectorObject> result = InspectorObject::create();
787     result->setString("styleSheetId", id());
788     result->setBoolean("disabled", styleSheet->disabled());
789     result->setString("sourceURL", finalURL());
790     result->setString("title", styleSheet->title());
791     return result.release();
792 }
793
794 PassRefPtr<InspectorObject> InspectorStyleSheet::buildObjectForRule(CSSStyleRule* rule)
795 {
796     CSSStyleSheet* styleSheet = pageStyleSheet();
797     if (!styleSheet)
798         return 0;
799
800     RefPtr<InspectorObject> result = InspectorObject::create();
801     result->setString("selectorText", rule->selectorText());
802     // "sourceURL" is present only for regular rules, otherwise "origin" should be used in the frontend.
803     if (!m_origin.length())
804         result->setString("sourceURL", finalURL());
805     result->setNumber("sourceLine", rule->sourceLine());
806     result->setString("origin", m_origin);
807
808     result->setObject("style", buildObjectForStyle(rule->style()));
809     if (canBind()) {
810         InspectorCSSId id(ruleId(rule));
811         if (!id.isEmpty())
812             result->setValue("ruleId", id.asInspectorValue());
813     }
814
815     RefPtr<CSSRuleSourceData> sourceData;
816     if (ensureParsedDataReady())
817         sourceData = ruleSourceDataFor(rule->style());
818     if (sourceData) {
819         RefPtr<InspectorObject> selectorRange = InspectorObject::create();
820         selectorRange->setNumber("start", sourceData->selectorListRange.start);
821         selectorRange->setNumber("end", sourceData->selectorListRange.end);
822         result->setObject("selectorRange", selectorRange.release());
823     }
824
825     RefPtr<InspectorArray> mediaArray = InspectorArray::create();
826
827     fillMediaListChain(rule, mediaArray.get());
828     if (mediaArray->length())
829         result->setArray("media", mediaArray.release());
830
831     return result.release();
832 }
833
834 PassRefPtr<InspectorObject> InspectorStyleSheet::buildObjectForStyle(CSSStyleDeclaration* style)
835 {
836     RefPtr<CSSRuleSourceData> sourceData;
837     if (ensureParsedDataReady())
838         sourceData = ruleSourceDataFor(style);
839
840     InspectorCSSId id = ruleOrStyleId(style);
841     if (id.isEmpty()) {
842         RefPtr<InspectorObject> bogusStyle = InspectorObject::create();
843         bogusStyle->setArray("cssProperties", InspectorArray::create());
844         bogusStyle->setObject("shorthandValues", InspectorObject::create());
845         bogusStyle->setObject("properties", InspectorObject::create());
846         return bogusStyle.release();
847     }
848     RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id);
849     RefPtr<InspectorObject> result = inspectorStyle->buildObjectForStyle();
850
851     // Style text cannot be retrieved without stylesheet, so set cssText here.
852     if (sourceData) {
853         String sheetText;
854         bool success = text(&sheetText);
855         if (success) {
856             const SourceRange& bodyRange = sourceData->styleSourceData->styleBodyRange;
857             result->setString("cssText", sheetText.substring(bodyRange.start, bodyRange.end - bodyRange.start));
858         }
859     }
860
861     return result.release();
862 }
863
864 bool InspectorStyleSheet::setPropertyText(ErrorString* errorString, const InspectorCSSId& id, unsigned propertyIndex, const String& text, bool overwrite)
865 {
866     RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id);
867     if (!inspectorStyle) {
868         *errorString = "No style found for given id";
869         return false;
870     }
871
872     return inspectorStyle->setPropertyText(errorString, propertyIndex, text, overwrite);
873 }
874
875 bool InspectorStyleSheet::toggleProperty(ErrorString* errorString, const InspectorCSSId& id, unsigned propertyIndex, bool disable)
876 {
877     RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id);
878     if (!inspectorStyle) {
879         *errorString = "No style found for given id";
880         return false;
881     }
882
883     bool success = inspectorStyle->toggleProperty(errorString, propertyIndex, disable);
884     if (success) {
885         if (disable)
886             rememberInspectorStyle(inspectorStyle);
887         else if (!inspectorStyle->hasDisabledProperties())
888             forgetInspectorStyle(inspectorStyle->cssStyle());
889     }
890     return success;
891 }
892
893 bool InspectorStyleSheet::text(String* result) const
894 {
895     if (!ensureText())
896         return false;
897     *result = m_parsedStyleSheet->text();
898     return true;
899 }
900
901 CSSStyleDeclaration* InspectorStyleSheet::styleForId(const InspectorCSSId& id) const
902 {
903     CSSStyleRule* rule = ruleForId(id);
904     if (!rule)
905         return 0;
906
907     return rule->style();
908 }
909
910 PassRefPtr<InspectorStyle> InspectorStyleSheet::inspectorStyleForId(const InspectorCSSId& id)
911 {
912     CSSStyleDeclaration* style = styleForId(id);
913     if (!style)
914         return 0;
915
916     InspectorStyleMap::iterator it = m_inspectorStyles.find(style);
917     if (it == m_inspectorStyles.end()) {
918         RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(id, style, this);
919         return inspectorStyle.release();
920     }
921     return it->second;
922 }
923
924 void InspectorStyleSheet::rememberInspectorStyle(RefPtr<InspectorStyle> inspectorStyle)
925 {
926     m_inspectorStyles.set(inspectorStyle->cssStyle(), inspectorStyle);
927 }
928
929 void InspectorStyleSheet::forgetInspectorStyle(CSSStyleDeclaration* style)
930 {
931     m_inspectorStyles.remove(style);
932 }
933
934 InspectorCSSId InspectorStyleSheet::ruleOrStyleId(CSSStyleDeclaration* style) const
935 {
936     unsigned index = ruleIndexByStyle(style);
937     if (index != UINT_MAX)
938         return InspectorCSSId(id(), index);
939     return InspectorCSSId();
940 }
941
942 Document* InspectorStyleSheet::ownerDocument() const
943 {
944     return m_pageStyleSheet->findDocument();
945 }
946
947 RefPtr<CSSRuleSourceData> InspectorStyleSheet::ruleSourceDataFor(CSSStyleDeclaration* style) const
948 {
949     return m_parsedStyleSheet->ruleSourceDataAt(ruleIndexByStyle(style));
950 }
951
952 unsigned InspectorStyleSheet::ruleIndexByStyle(CSSStyleDeclaration* pageStyle) const
953 {
954     ensureFlatRules();
955     unsigned index = 0;
956     for (unsigned i = 0, size = m_flatRules.size(); i < size; ++i) {
957         if (m_flatRules.at(i)->style() == pageStyle)
958             return index;
959
960         ++index;
961     }
962     return UINT_MAX;
963 }
964
965 bool InspectorStyleSheet::ensureParsedDataReady()
966 {
967     return ensureText() && ensureSourceData();
968 }
969
970 bool InspectorStyleSheet::ensureText() const
971 {
972     if (!m_parsedStyleSheet)
973         return false;
974     if (m_parsedStyleSheet->hasText())
975         return true;
976
977     String text;
978     bool success = originalStyleSheetText(&text);
979     if (success)
980         m_parsedStyleSheet->setText(text);
981     // No need to clear m_flatRules here - it's empty.
982
983     return success;
984 }
985
986 bool InspectorStyleSheet::ensureSourceData()
987 {
988     if (m_parsedStyleSheet->hasSourceData())
989         return true;
990
991     if (!m_parsedStyleSheet->hasText())
992         return false;
993
994     RefPtr<CSSStyleSheet> newStyleSheet = CSSStyleSheet::create();
995     CSSParser p;
996     StyleRuleRangeMap ruleRangeMap;
997     p.parseSheet(newStyleSheet.get(), m_parsedStyleSheet->text(), 0, &ruleRangeMap);
998     OwnPtr<ParsedStyleSheet::SourceData> rangesVector(adoptPtr(new ParsedStyleSheet::SourceData));
999
1000     Vector<CSSStyleRule*> rules;
1001     RefPtr<CSSRuleList> ruleList = asCSSRuleList(newStyleSheet.get());
1002     collectFlatRules(ruleList, &rules);
1003     for (unsigned i = 0, size = rules.size(); i < size; ++i) {
1004         StyleRuleRangeMap::iterator it = ruleRangeMap.find(rules.at(i));
1005         if (it != ruleRangeMap.end()) {
1006             fixUnparsedPropertyRanges(it->second.get(), m_parsedStyleSheet->text());
1007             rangesVector->append(it->second);
1008         }
1009     }
1010
1011     m_parsedStyleSheet->setSourceData(rangesVector.release());
1012     return m_parsedStyleSheet->hasSourceData();
1013 }
1014
1015 void InspectorStyleSheet::ensureFlatRules() const
1016 {
1017     // We are fine with redoing this for empty stylesheets as this will run fast.
1018     if (m_flatRules.isEmpty())
1019         collectFlatRules(asCSSRuleList(pageStyleSheet()), &m_flatRules);
1020 }
1021
1022 bool InspectorStyleSheet::setStyleText(CSSStyleDeclaration* style, const String& text)
1023 {
1024     if (!pageStyleSheet())
1025         return false;
1026     if (!ensureParsedDataReady())
1027         return false;
1028
1029     String patchedStyleSheetText;
1030     bool success = styleSheetTextWithChangedStyle(style, text, &patchedStyleSheetText);
1031     if (!success)
1032         return false;
1033
1034     InspectorCSSId id = ruleOrStyleId(style);
1035     if (id.isEmpty())
1036         return false;
1037
1038     ExceptionCode ec = 0;
1039     style->setCssText(text, ec);
1040     if (!ec)
1041         m_parsedStyleSheet->setText(patchedStyleSheetText);
1042
1043     return !ec;
1044 }
1045
1046 bool InspectorStyleSheet::styleSheetTextWithChangedStyle(CSSStyleDeclaration* style, const String& newStyleText, String* result)
1047 {
1048     if (!style)
1049         return false;
1050
1051     if (!ensureParsedDataReady())
1052         return false;
1053
1054     RefPtr<CSSRuleSourceData> sourceData = ruleSourceDataFor(style);
1055     unsigned bodyStart = sourceData->styleSourceData->styleBodyRange.start;
1056     unsigned bodyEnd = sourceData->styleSourceData->styleBodyRange.end;
1057     ASSERT(bodyStart <= bodyEnd);
1058
1059     String text = m_parsedStyleSheet->text();
1060     ASSERT(bodyEnd <= text.length()); // bodyEnd is exclusive
1061
1062     text.replace(bodyStart, bodyEnd - bodyStart, newStyleText);
1063     *result = text;
1064     return true;
1065 }
1066
1067 InspectorCSSId InspectorStyleSheet::ruleId(CSSStyleRule* rule) const
1068 {
1069     return ruleOrStyleId(rule->style());
1070 }
1071
1072 void InspectorStyleSheet::revalidateStyle(CSSStyleDeclaration* pageStyle)
1073 {
1074     if (m_isRevalidating)
1075         return;
1076
1077     m_isRevalidating = true;
1078     ensureFlatRules();
1079     for (unsigned i = 0, size = m_flatRules.size(); i < size; ++i) {
1080         CSSStyleRule* parsedRule = m_flatRules.at(i);
1081         if (parsedRule->style() == pageStyle) {
1082             if (parsedRule->style()->cssText() != pageStyle->cssText()) {
1083                 // Clear the disabled properties for the invalid style here.
1084                 m_inspectorStyles.remove(pageStyle);
1085                 setStyleText(pageStyle, pageStyle->cssText());
1086             }
1087             break;
1088         }
1089     }
1090     m_isRevalidating = false;
1091 }
1092
1093 bool InspectorStyleSheet::originalStyleSheetText(String* result) const
1094 {
1095     bool success = inlineStyleSheetText(result);
1096     if (!success)
1097         success = resourceStyleSheetText(result);
1098     return success;
1099 }
1100
1101 bool InspectorStyleSheet::resourceStyleSheetText(String* result) const
1102 {
1103     if (m_origin == "user" || m_origin == "user-agent")
1104         return false;
1105
1106     if (!m_pageStyleSheet || !ownerDocument() || !ownerDocument()->frame())
1107         return false;
1108
1109     String error;
1110     bool base64Encoded;
1111     InspectorPageAgent::resourceContent(&error, ownerDocument()->frame(), KURL(ParsedURLString, m_pageStyleSheet->href()), result, &base64Encoded);
1112     return error.isEmpty() && !base64Encoded;
1113 }
1114
1115 bool InspectorStyleSheet::inlineStyleSheetText(String* result) const
1116 {
1117     if (!m_pageStyleSheet)
1118         return false;
1119
1120     Node* ownerNode = m_pageStyleSheet->ownerNode();
1121     if (!ownerNode || ownerNode->nodeType() != Node::ELEMENT_NODE)
1122         return false;
1123     Element* ownerElement = static_cast<Element*>(ownerNode);
1124
1125     if (!ownerElement->hasTagName(HTMLNames::styleTag)
1126 #if ENABLE(SVG)
1127         && !ownerElement->hasTagName(SVGNames::styleTag)
1128 #endif
1129     )
1130         return false;
1131     *result = ownerElement->innerText();
1132     return true;
1133 }
1134
1135 PassRefPtr<InspectorArray> InspectorStyleSheet::buildArrayForRuleList(CSSRuleList* ruleList)
1136 {
1137     RefPtr<InspectorArray> result = InspectorArray::create();
1138     if (!ruleList)
1139         return result.release();
1140
1141     RefPtr<CSSRuleList> refRuleList = ruleList;
1142     Vector<CSSStyleRule*> rules;
1143     collectFlatRules(refRuleList, &rules);
1144
1145     for (unsigned i = 0, size = rules.size(); i < size; ++i)
1146         result->pushObject(buildObjectForRule(rules.at(i)));
1147
1148     return result.release();
1149 }
1150
1151 void InspectorStyleSheet::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData, const String& styleSheetText)
1152 {
1153     Vector<CSSPropertySourceData>& propertyData = ruleData->styleSourceData->propertyData;
1154     unsigned size = propertyData.size();
1155     if (!size)
1156         return;
1157
1158     unsigned styleStart = ruleData->styleSourceData->styleBodyRange.start;
1159     const UChar* characters = styleSheetText.characters();
1160     CSSPropertySourceData* nextData = &(propertyData.at(0));
1161     for (unsigned i = 0; i < size; ++i) {
1162         CSSPropertySourceData* currentData = nextData;
1163         nextData = i < size - 1 ? &(propertyData.at(i + 1)) : 0;
1164
1165         if (currentData->parsedOk)
1166             continue;
1167         if (currentData->range.end > 0 && characters[styleStart + currentData->range.end - 1] == ';')
1168             continue;
1169
1170         unsigned propertyEndInStyleSheet;
1171         if (!nextData)
1172             propertyEndInStyleSheet = ruleData->styleSourceData->styleBodyRange.end - 1;
1173         else
1174             propertyEndInStyleSheet = styleStart + nextData->range.start - 1;
1175
1176         while (isHTMLSpace(characters[propertyEndInStyleSheet]))
1177             --propertyEndInStyleSheet;
1178
1179         // propertyEndInStyleSheet points at the last property text character.
1180         unsigned newPropertyEnd = propertyEndInStyleSheet - styleStart + 1; // Exclusive of the last property text character.
1181         if (currentData->range.end != newPropertyEnd) {
1182             currentData->range.end = newPropertyEnd;
1183             unsigned valueStartInStyleSheet = styleStart + currentData->range.start + currentData->name.length();
1184             while (valueStartInStyleSheet < propertyEndInStyleSheet && characters[valueStartInStyleSheet] != ':')
1185                 ++valueStartInStyleSheet;
1186             if (valueStartInStyleSheet < propertyEndInStyleSheet)
1187                 ++valueStartInStyleSheet; // Shift past the ':'.
1188             while (valueStartInStyleSheet < propertyEndInStyleSheet && isHTMLSpace(characters[valueStartInStyleSheet]))
1189                 ++valueStartInStyleSheet;
1190             // Need to exclude the trailing ';' from the property value.
1191             currentData->value = styleSheetText.substring(valueStartInStyleSheet, propertyEndInStyleSheet - valueStartInStyleSheet + (characters[propertyEndInStyleSheet] == ';' ? 0 : 1));
1192         }
1193     }
1194 }
1195
1196 void InspectorStyleSheet::collectFlatRules(PassRefPtr<CSSRuleList> ruleList, Vector<CSSStyleRule*>* result)
1197 {
1198     if (!ruleList)
1199         return;
1200
1201     for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
1202         CSSRule* rule = ruleList->item(i);
1203         CSSStyleRule* styleRule = InspectorCSSAgent::asCSSStyleRule(rule);
1204         if (styleRule)
1205             result->append(styleRule);
1206         else {
1207             RefPtr<CSSRuleList> childRuleList = asCSSRuleList(rule);
1208             if (childRuleList)
1209                 collectFlatRules(childRuleList, result);
1210         }
1211     }
1212 }
1213
1214 PassRefPtr<InspectorStyleSheetForInlineStyle> InspectorStyleSheetForInlineStyle::create(const String& id, PassRefPtr<Element> element, const String& origin)
1215 {
1216     return adoptRef(new InspectorStyleSheetForInlineStyle(id, element, origin));
1217 }
1218
1219 InspectorStyleSheetForInlineStyle::InspectorStyleSheetForInlineStyle(const String& id, PassRefPtr<Element> element, const String& origin)
1220     : InspectorStyleSheet(id, 0, origin, "")
1221     , m_element(element)
1222     , m_ruleSourceData(0)
1223     , m_isStyleTextValid(false)
1224 {
1225     ASSERT(m_element);
1226     m_inspectorStyle = InspectorStyle::create(InspectorCSSId(id, 0), inlineStyle(), this);
1227     m_styleText = m_element->isStyledElement() ? m_element->getAttribute("style").string() : String();
1228 }
1229
1230 void InspectorStyleSheetForInlineStyle::didModifyElementAttribute()
1231 {
1232     m_isStyleTextValid = false;
1233     if (m_element->isStyledElement() && m_element->style() != m_inspectorStyle->cssStyle())
1234         m_inspectorStyle = InspectorStyle::create(InspectorCSSId(id(), 0), inlineStyle(), this);
1235     m_ruleSourceData.clear();
1236 }
1237
1238 bool InspectorStyleSheetForInlineStyle::text(String* result) const
1239 {
1240     if (!m_isStyleTextValid) {
1241         m_styleText = elementStyleText();
1242         m_isStyleTextValid = true;
1243     }
1244     *result = m_styleText;
1245     return true;
1246 }
1247
1248 bool InspectorStyleSheetForInlineStyle::setStyleText(CSSStyleDeclaration* style, const String& text)
1249 {
1250     ASSERT_UNUSED(style, style == inlineStyle());
1251     ExceptionCode ec = 0;
1252     m_element->setAttribute("style", text, ec);
1253     m_styleText = text;
1254     m_isStyleTextValid = true;
1255     m_ruleSourceData.clear();
1256     return !ec;
1257 }
1258
1259 Document* InspectorStyleSheetForInlineStyle::ownerDocument() const
1260 {
1261     return m_element->document();
1262 }
1263
1264 bool InspectorStyleSheetForInlineStyle::ensureParsedDataReady()
1265 {
1266     // The "style" property value can get changed indirectly, e.g. via element.style.borderWidth = "2px".
1267     const String& currentStyleText = elementStyleText();
1268     if (m_styleText != currentStyleText) {
1269         m_ruleSourceData.clear();
1270         m_styleText = currentStyleText;
1271         m_isStyleTextValid = true;
1272     }
1273
1274     if (m_ruleSourceData)
1275         return true;
1276
1277     m_ruleSourceData = CSSRuleSourceData::create();
1278     RefPtr<CSSStyleSourceData> sourceData = CSSStyleSourceData::create();
1279     bool success = getStyleAttributeRanges(&sourceData);
1280     if (!success)
1281         return false;
1282
1283     m_ruleSourceData->styleSourceData = sourceData.release();
1284     return true;
1285 }
1286
1287 PassRefPtr<InspectorStyle> InspectorStyleSheetForInlineStyle::inspectorStyleForId(const InspectorCSSId& id)
1288 {
1289     ASSERT_UNUSED(id, !id.ordinal());
1290     return m_inspectorStyle;
1291 }
1292
1293 CSSStyleDeclaration* InspectorStyleSheetForInlineStyle::inlineStyle() const
1294 {
1295     return m_element->style();
1296 }
1297
1298 const String& InspectorStyleSheetForInlineStyle::elementStyleText() const
1299 {
1300     return m_element->getAttribute("style").string();
1301 }
1302
1303 bool InspectorStyleSheetForInlineStyle::getStyleAttributeRanges(RefPtr<CSSStyleSourceData>* result) const
1304 {
1305     if (!m_element->isStyledElement())
1306         return false;
1307
1308     if (m_styleText.isEmpty()) {
1309         (*result)->styleBodyRange.start = 0;
1310         (*result)->styleBodyRange.end = 0;
1311         return true;
1312     }
1313
1314     RefPtr<CSSMutableStyleDeclaration> tempDeclaration = CSSMutableStyleDeclaration::create();
1315     CSSParser p;
1316     p.parseDeclaration(tempDeclaration.get(), m_styleText, result, m_element->document()->elementSheet());
1317     return true;
1318 }
1319
1320 } // namespace WebCore
1321
1322 #endif // ENABLE(INSPECTOR)