Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/inspector/InspectorStyleSheet.h"
27
28 #include "CSSPropertyNames.h"
29 #include "HTMLNames.h"
30 #include "SVGNames.h"
31 #include "bindings/v8/ExceptionState.h"
32 #include "bindings/v8/ExceptionStatePlaceholder.h"
33 #include "bindings/v8/ScriptRegexp.h"
34 #include "core/css/CSSKeyframesRule.h"
35 #include "core/css/CSSMediaRule.h"
36 #include "core/css/parser/BisonCSSParser.h"
37 #include "core/css/CSSRuleList.h"
38 #include "core/css/CSSStyleRule.h"
39 #include "core/css/CSSStyleSheet.h"
40 #include "core/css/CSSSupportsRule.h"
41 #include "core/css/StylePropertySet.h"
42 #include "core/css/StyleRule.h"
43 #include "core/css/StyleSheetContents.h"
44 #include "core/dom/Document.h"
45 #include "core/dom/Element.h"
46 #include "core/frame/PageConsole.h"
47 #include "core/html/parser/HTMLParserIdioms.h"
48 #include "core/inspector/ContentSearchUtils.h"
49 #include "core/inspector/InspectorCSSAgent.h"
50 #include "core/inspector/InspectorPageAgent.h"
51 #include "core/inspector/InspectorResourceAgent.h"
52 #include "wtf/OwnPtr.h"
53 #include "wtf/PassOwnPtr.h"
54 #include "wtf/text/StringBuilder.h"
55 #include "wtf/text/TextPosition.h"
56
57 using WebCore::TypeBuilder::Array;
58 using WebCore::RuleSourceDataList;
59 using WebCore::CSSRuleSourceData;
60
61 class ParsedStyleSheet {
62     WTF_MAKE_FAST_ALLOCATED;
63 public:
64     ParsedStyleSheet();
65
66     const String& text() const { ASSERT(m_hasText); return m_text; }
67     void setText(const String& text);
68     bool hasText() const { return m_hasText; }
69     void setSourceData(PassOwnPtr<RuleSourceDataList>);
70     bool hasSourceData() const { return m_sourceData; }
71     PassRefPtr<WebCore::CSSRuleSourceData> ruleSourceDataAt(unsigned) const;
72
73 private:
74     void flattenSourceData(RuleSourceDataList*);
75
76     String m_text;
77     bool m_hasText;
78     OwnPtr<RuleSourceDataList> m_sourceData;
79 };
80
81 ParsedStyleSheet::ParsedStyleSheet()
82     : m_hasText(false)
83 {
84 }
85
86 void ParsedStyleSheet::setText(const String& text)
87 {
88     m_hasText = true;
89     m_text = text;
90     setSourceData(nullptr);
91 }
92
93 void ParsedStyleSheet::flattenSourceData(RuleSourceDataList* dataList)
94 {
95     for (size_t i = 0; i < dataList->size(); ++i) {
96         RefPtr<CSSRuleSourceData>& data = dataList->at(i);
97         if (data->type == CSSRuleSourceData::STYLE_RULE) {
98             m_sourceData->append(data);
99         } else if (data->type == CSSRuleSourceData::IMPORT_RULE) {
100             m_sourceData->append(data);
101         } else if (data->type == CSSRuleSourceData::MEDIA_RULE) {
102             m_sourceData->append(data);
103             flattenSourceData(&data->childRules);
104         } else if (data->type == CSSRuleSourceData::SUPPORTS_RULE) {
105             flattenSourceData(&data->childRules);
106         }
107     }
108 }
109
110 void ParsedStyleSheet::setSourceData(PassOwnPtr<RuleSourceDataList> sourceData)
111 {
112     if (!sourceData) {
113         m_sourceData.clear();
114         return;
115     }
116
117     m_sourceData = adoptPtr(new RuleSourceDataList());
118
119     // FIXME: This is a temporary solution to retain the original flat sourceData structure
120     // containing only style rules, even though BisonCSSParser now provides the full rule source data tree.
121     // Normally, we should just assign m_sourceData = sourceData;
122     flattenSourceData(sourceData.get());
123 }
124
125 PassRefPtr<WebCore::CSSRuleSourceData> ParsedStyleSheet::ruleSourceDataAt(unsigned index) const
126 {
127     if (!hasSourceData() || index >= m_sourceData->size())
128         return 0;
129
130     return m_sourceData->at(index);
131 }
132
133 namespace WebCore {
134
135 static PassOwnPtr<BisonCSSParser> createCSSParser(Document* document)
136 {
137     return adoptPtr(new BisonCSSParser(document ? CSSParserContext(*document, 0) : strictCSSParserContext()));
138 }
139
140 namespace {
141
142 class StyleSheetHandler FINAL : public CSSParserObserver {
143 public:
144     StyleSheetHandler(const String& parsedText, Document* document, StyleSheetContents* styleSheetContents, RuleSourceDataList* result)
145         : m_parsedText(parsedText)
146         , m_document(document)
147         , m_styleSheetContents(styleSheetContents)
148         , m_result(result)
149         , m_propertyRangeStart(UINT_MAX)
150         , m_selectorRangeStart(UINT_MAX)
151         , m_commentRangeStart(UINT_MAX)
152     {
153         ASSERT(m_result);
154     }
155
156 private:
157     virtual void startRuleHeader(CSSRuleSourceData::Type, unsigned) OVERRIDE;
158     virtual void endRuleHeader(unsigned) OVERRIDE;
159     virtual void startSelector(unsigned) OVERRIDE;
160     virtual void endSelector(unsigned) OVERRIDE;
161     virtual void startRuleBody(unsigned) OVERRIDE;
162     virtual void endRuleBody(unsigned, bool) OVERRIDE;
163     virtual void startEndUnknownRule() OVERRIDE { addNewRuleToSourceTree(CSSRuleSourceData::createUnknown()); }
164     virtual void startProperty(unsigned) OVERRIDE;
165     virtual void endProperty(bool, bool, unsigned, CSSParserError) OVERRIDE;
166     virtual void startComment(unsigned) OVERRIDE;
167     virtual void endComment(unsigned) OVERRIDE;
168
169     void addNewRuleToSourceTree(PassRefPtr<CSSRuleSourceData>);
170     PassRefPtr<CSSRuleSourceData> popRuleData();
171     template <typename CharacterType> inline void setRuleHeaderEnd(const CharacterType*, unsigned);
172     void fixUnparsedPropertyRanges(CSSRuleSourceData*);
173
174     const String& m_parsedText;
175     Document* m_document;
176     StyleSheetContents* m_styleSheetContents;
177     RuleSourceDataList* m_result;
178     RuleSourceDataList m_currentRuleDataStack;
179     RefPtr<CSSRuleSourceData> m_currentRuleData;
180     OwnPtr<BisonCSSParser> m_commentParser;
181     unsigned m_propertyRangeStart;
182     unsigned m_selectorRangeStart;
183     unsigned m_commentRangeStart;
184 };
185
186 void StyleSheetHandler::startRuleHeader(CSSRuleSourceData::Type type, unsigned offset)
187 {
188     // Pop off data for a previous invalid rule.
189     if (m_currentRuleData)
190         m_currentRuleDataStack.removeLast();
191
192     RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(type);
193     data->ruleHeaderRange.start = offset;
194     m_currentRuleData = data;
195     m_currentRuleDataStack.append(data.release());
196 }
197
198 template <typename CharacterType>
199 inline void StyleSheetHandler::setRuleHeaderEnd(const CharacterType* dataStart, unsigned listEndOffset)
200 {
201     while (listEndOffset > 1) {
202         if (isHTMLSpace<CharacterType>(*(dataStart + listEndOffset - 1)))
203             --listEndOffset;
204         else
205             break;
206     }
207
208     m_currentRuleDataStack.last()->ruleHeaderRange.end = listEndOffset;
209     if (!m_currentRuleDataStack.last()->selectorRanges.isEmpty())
210         m_currentRuleDataStack.last()->selectorRanges.last().end = listEndOffset;
211 }
212
213 void StyleSheetHandler::endRuleHeader(unsigned offset)
214 {
215     ASSERT(!m_currentRuleDataStack.isEmpty());
216
217     if (m_parsedText.is8Bit())
218         setRuleHeaderEnd<LChar>(m_parsedText.characters8(), offset);
219     else
220         setRuleHeaderEnd<UChar>(m_parsedText.characters16(), offset);
221 }
222
223 void StyleSheetHandler::startSelector(unsigned offset)
224 {
225     m_selectorRangeStart = offset;
226 }
227
228 void StyleSheetHandler::endSelector(unsigned offset)
229 {
230     ASSERT(m_currentRuleDataStack.size());
231     m_currentRuleDataStack.last()->selectorRanges.append(SourceRange(m_selectorRangeStart, offset));
232     m_selectorRangeStart = UINT_MAX;
233 }
234
235 void StyleSheetHandler::startRuleBody(unsigned offset)
236 {
237     m_currentRuleData.clear();
238     ASSERT(!m_currentRuleDataStack.isEmpty());
239     if (m_parsedText[offset] == '{')
240         ++offset; // Skip the rule body opening brace.
241     m_currentRuleDataStack.last()->ruleBodyRange.start = offset;
242 }
243
244 void StyleSheetHandler::endRuleBody(unsigned offset, bool error)
245 {
246     ASSERT(!m_currentRuleDataStack.isEmpty());
247     m_currentRuleDataStack.last()->ruleBodyRange.end = offset;
248     m_propertyRangeStart = UINT_MAX;
249     RefPtr<CSSRuleSourceData> rule = popRuleData();
250     if (error)
251         return;
252
253     fixUnparsedPropertyRanges(rule.get());
254     addNewRuleToSourceTree(rule.release());
255 }
256
257 void StyleSheetHandler::addNewRuleToSourceTree(PassRefPtr<CSSRuleSourceData> rule)
258 {
259     if (m_currentRuleDataStack.isEmpty())
260         m_result->append(rule);
261     else
262         m_currentRuleDataStack.last()->childRules.append(rule);
263 }
264
265 PassRefPtr<CSSRuleSourceData> StyleSheetHandler::popRuleData()
266 {
267     ASSERT(!m_currentRuleDataStack.isEmpty());
268     m_currentRuleData.clear();
269     RefPtr<CSSRuleSourceData> data = m_currentRuleDataStack.last();
270     m_currentRuleDataStack.removeLast();
271     return data.release();
272 }
273
274 template <typename CharacterType>
275 static inline void fixUnparsedProperties(const CharacterType* characters, CSSRuleSourceData* ruleData)
276 {
277     Vector<CSSPropertySourceData>& propertyData = ruleData->styleSourceData->propertyData;
278     unsigned size = propertyData.size();
279     if (!size)
280         return;
281
282     unsigned styleStart = ruleData->ruleBodyRange.start;
283     CSSPropertySourceData* nextData = &(propertyData.at(0));
284     for (unsigned i = 0; i < size; ++i) {
285         CSSPropertySourceData* currentData = nextData;
286         nextData = i < size - 1 ? &(propertyData.at(i + 1)) : 0;
287
288         if (currentData->parsedOk)
289             continue;
290         if (currentData->range.end > 0 && characters[styleStart + currentData->range.end - 1] == ';')
291             continue;
292
293         unsigned propertyEndInStyleSheet;
294         if (!nextData)
295             propertyEndInStyleSheet = ruleData->ruleBodyRange.end - 1;
296         else
297             propertyEndInStyleSheet = styleStart + nextData->range.start - 1;
298
299         while (isHTMLSpace<CharacterType>(characters[propertyEndInStyleSheet]))
300             --propertyEndInStyleSheet;
301
302         // propertyEndInStyleSheet points at the last property text character.
303         unsigned newPropertyEnd = propertyEndInStyleSheet - styleStart + 1; // Exclusive of the last property text character.
304         if (currentData->range.end != newPropertyEnd) {
305             currentData->range.end = newPropertyEnd;
306             unsigned valueStartInStyleSheet = styleStart + currentData->range.start + currentData->name.length();
307             while (valueStartInStyleSheet < propertyEndInStyleSheet && characters[valueStartInStyleSheet] != ':')
308                 ++valueStartInStyleSheet;
309             if (valueStartInStyleSheet < propertyEndInStyleSheet)
310                 ++valueStartInStyleSheet; // Shift past the ':'.
311             while (valueStartInStyleSheet < propertyEndInStyleSheet && isHTMLSpace<CharacterType>(characters[valueStartInStyleSheet]))
312                 ++valueStartInStyleSheet;
313             // Need to exclude the trailing ';' from the property value.
314             currentData->value = String(characters + valueStartInStyleSheet, propertyEndInStyleSheet - valueStartInStyleSheet + (characters[propertyEndInStyleSheet] == ';' ? 0 : 1));
315         }
316     }
317 }
318
319 void StyleSheetHandler::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData)
320 {
321     if (!ruleData->styleSourceData)
322         return;
323
324     if (m_parsedText.is8Bit()) {
325         fixUnparsedProperties<LChar>(m_parsedText.characters8(), ruleData);
326         return;
327     }
328
329     fixUnparsedProperties<UChar>(m_parsedText.characters16(), ruleData);
330 }
331
332 void StyleSheetHandler::startProperty(unsigned offset)
333 {
334     if (m_currentRuleDataStack.isEmpty() || !m_currentRuleDataStack.last()->styleSourceData)
335         return;
336     m_propertyRangeStart = offset;
337 }
338
339 void StyleSheetHandler::endProperty(bool isImportant, bool isParsed, unsigned offset, CSSParserError errorType)
340 {
341     // FIXME: This is the only place CSSParserError is every read!?
342     if (errorType != NoCSSError)
343         m_propertyRangeStart = UINT_MAX;
344
345     if (m_propertyRangeStart == UINT_MAX || m_currentRuleDataStack.isEmpty() || !m_currentRuleDataStack.last()->styleSourceData)
346         return;
347
348     ASSERT(offset <= m_parsedText.length());
349     if (offset < m_parsedText.length() && m_parsedText[offset] == ';') // Include semicolon into the property text.
350         ++offset;
351
352     const unsigned start = m_propertyRangeStart;
353     const unsigned end = offset;
354     ASSERT(start < end);
355     String propertyString = m_parsedText.substring(start, end - start).stripWhiteSpace();
356     if (propertyString.endsWith(';'))
357         propertyString = propertyString.left(propertyString.length() - 1);
358     size_t colonIndex = propertyString.find(':');
359     ASSERT(colonIndex != kNotFound);
360
361     String name = propertyString.left(colonIndex).stripWhiteSpace();
362     String value = propertyString.substring(colonIndex + 1, propertyString.length()).stripWhiteSpace();
363     // The property range is relative to the declaration start offset.
364     unsigned topRuleBodyRangeStart = m_currentRuleDataStack.last()->ruleBodyRange.start;
365     m_currentRuleDataStack.last()->styleSourceData->propertyData.append(
366         CSSPropertySourceData(name, value, isImportant, false, isParsed, SourceRange(start - topRuleBodyRangeStart, end - topRuleBodyRangeStart)));
367     m_propertyRangeStart = UINT_MAX;
368 }
369
370 void StyleSheetHandler::startComment(unsigned offset)
371 {
372     ASSERT(m_commentRangeStart == UINT_MAX);
373     m_commentRangeStart = offset;
374 }
375
376 void StyleSheetHandler::endComment(unsigned offset)
377 {
378     ASSERT(offset <= m_parsedText.length());
379
380     unsigned startOffset = m_commentRangeStart;
381     m_commentRangeStart = UINT_MAX;
382     if (m_propertyRangeStart != UINT_MAX) {
383         ASSERT(startOffset >= m_propertyRangeStart);
384         // startProperty() is called automatically at the start of a style declaration.
385         // Check if no text has been scanned yet, otherwise the comment is inside a property.
386         if (!m_parsedText.substring(m_propertyRangeStart, startOffset).stripWhiteSpace().isEmpty())
387             return;
388         m_propertyRangeStart = UINT_MAX;
389     }
390     if (m_currentRuleDataStack.isEmpty() || !m_currentRuleDataStack.last()->ruleHeaderRange.end || !m_currentRuleDataStack.last()->styleSourceData)
391         return;
392
393     // The lexer is not inside a property AND it is scanning a declaration-aware rule body.
394     String commentText = m_parsedText.substring(startOffset, offset - startOffset);
395
396     ASSERT(commentText.startsWith("/*"));
397     commentText = commentText.substring(2);
398
399     // Require well-formed comments.
400     if (!commentText.endsWith("*/"))
401         return;
402     commentText = commentText.substring(0, commentText.length() - 2).stripWhiteSpace();
403     if (commentText.isEmpty())
404         return;
405
406     // FIXME: Use the actual rule type rather than STYLE_RULE?
407     if (!m_commentParser)
408         m_commentParser = createCSSParser(m_document);
409     RuleSourceDataList sourceData;
410
411     // FIXME: Use another subclass of BisonCSSParser::SourceDataHandler and assert that
412     // no comments are encountered (will not need m_document and m_styleSheetContents).
413     StyleSheetHandler handler(commentText, m_document, m_styleSheetContents, &sourceData);
414     RefPtr<MutableStylePropertySet> tempMutableStyle = MutableStylePropertySet::create();
415     m_commentParser->parseDeclaration(tempMutableStyle.get(), commentText, &handler, m_styleSheetContents);
416     Vector<CSSPropertySourceData>& commentPropertyData = sourceData.first()->styleSourceData->propertyData;
417     if (commentPropertyData.size() != 1)
418         return;
419     CSSPropertySourceData& propertyData = commentPropertyData.at(0);
420     if (propertyData.range.length() != commentText.length())
421         return;
422
423     unsigned topRuleBodyRangeStart = m_currentRuleDataStack.last()->ruleBodyRange.start;
424     m_currentRuleDataStack.last()->styleSourceData->propertyData.append(
425         CSSPropertySourceData(propertyData.name, propertyData.value, false, true, true, SourceRange(startOffset - topRuleBodyRangeStart, offset - topRuleBodyRangeStart)));
426 }
427
428 } // namespace
429
430 enum MediaListSource {
431     MediaListSourceLinkedSheet,
432     MediaListSourceInlineSheet,
433     MediaListSourceMediaRule,
434     MediaListSourceImportRule
435 };
436
437 static PassRefPtr<TypeBuilder::CSS::SourceRange> buildSourceRangeObject(const SourceRange& range, Vector<unsigned>* lineEndings)
438 {
439     if (!lineEndings)
440         return 0;
441     TextPosition start = TextPosition::fromOffsetAndLineEndings(range.start, *lineEndings);
442     TextPosition end = TextPosition::fromOffsetAndLineEndings(range.end, *lineEndings);
443
444     RefPtr<TypeBuilder::CSS::SourceRange> result = TypeBuilder::CSS::SourceRange::create()
445         .setStartLine(start.m_line.zeroBasedInt())
446         .setStartColumn(start.m_column.zeroBasedInt())
447         .setEndLine(end.m_line.zeroBasedInt())
448         .setEndColumn(end.m_column.zeroBasedInt());
449     return result.release();
450 }
451
452 static PassRefPtr<CSSRuleList> asCSSRuleList(CSSStyleSheet* styleSheet)
453 {
454     if (!styleSheet)
455         return 0;
456
457     RefPtr<StaticCSSRuleList> list = StaticCSSRuleList::create();
458     Vector<RefPtr<CSSRule> >& listRules = list->rules();
459     for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
460         CSSRule* item = styleSheet->item(i);
461         if (item->type() == CSSRule::CHARSET_RULE)
462             continue;
463         listRules.append(item);
464     }
465     return list.release();
466 }
467
468 static PassRefPtr<CSSRuleList> asCSSRuleList(CSSRule* rule)
469 {
470     if (!rule)
471         return 0;
472
473     if (rule->type() == CSSRule::MEDIA_RULE)
474         return toCSSMediaRule(rule)->cssRules();
475
476     if (rule->type() == CSSRule::KEYFRAMES_RULE)
477         return toCSSKeyframesRule(rule)->cssRules();
478
479     if (rule->type() == CSSRule::SUPPORTS_RULE)
480         return toCSSSupportsRule(rule)->cssRules();
481
482     return 0;
483 }
484
485 PassRefPtr<InspectorStyle> InspectorStyle::create(const InspectorCSSId& styleId, PassRefPtr<CSSStyleDeclaration> style, InspectorStyleSheet* parentStyleSheet)
486 {
487     return adoptRef(new InspectorStyle(styleId, style, parentStyleSheet));
488 }
489
490 InspectorStyle::InspectorStyle(const InspectorCSSId& styleId, PassRefPtr<CSSStyleDeclaration> style, InspectorStyleSheet* parentStyleSheet)
491     : m_styleId(styleId)
492     , m_style(style)
493     , m_parentStyleSheet(parentStyleSheet)
494     , m_formatAcquired(false)
495 {
496     ASSERT(m_style);
497 }
498
499 PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorStyle::buildObjectForStyle() const
500 {
501     RefPtr<TypeBuilder::CSS::CSSStyle> result = styleWithProperties();
502     if (!m_styleId.isEmpty())
503         result->setStyleId(m_styleId.asProtocolValue<TypeBuilder::CSS::CSSStyleId>());
504
505     RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
506     if (sourceData)
507         result->setRange(buildSourceRangeObject(sourceData->ruleBodyRange, m_parentStyleSheet->lineEndings().get()));
508
509     return result.release();
510 }
511
512 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> > InspectorStyle::buildArrayForComputedStyle() const
513 {
514     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> > result = TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty>::create();
515     Vector<InspectorStyleProperty> properties;
516     populateAllProperties(properties);
517
518     for (Vector<InspectorStyleProperty>::iterator it = properties.begin(), itEnd = properties.end(); it != itEnd; ++it) {
519         const CSSPropertySourceData& propertyEntry = it->sourceData;
520         RefPtr<TypeBuilder::CSS::CSSComputedStyleProperty> entry = TypeBuilder::CSS::CSSComputedStyleProperty::create()
521             .setName(propertyEntry.name)
522             .setValue(propertyEntry.value);
523         result->addItem(entry);
524     }
525
526     return result.release();
527 }
528
529 bool InspectorStyle::verifyPropertyText(const String& propertyText, bool canOmitSemicolon)
530 {
531     DEFINE_STATIC_LOCAL(String, bogusPropertyName, ("-webkit-boguz-propertee"));
532     RefPtr<MutableStylePropertySet> tempMutableStyle = MutableStylePropertySet::create();
533     RuleSourceDataList sourceData;
534     RefPtr<StyleSheetContents> styleSheetContents = StyleSheetContents::create(strictCSSParserContext());
535     String declarationText = propertyText + (canOmitSemicolon ? ";" : " ") + bogusPropertyName + ": none";
536     StyleSheetHandler handler(declarationText, ownerDocument(), styleSheetContents.get(), &sourceData);
537     createCSSParser(ownerDocument())->parseDeclaration(tempMutableStyle.get(), declarationText, &handler, styleSheetContents.get());
538     Vector<CSSPropertySourceData>& propertyData = sourceData.first()->styleSourceData->propertyData;
539     unsigned propertyCount = propertyData.size();
540
541     // At least one property + the bogus property added just above should be present.
542     if (propertyCount < 2)
543         return false;
544
545     // Check for the proper propertyText termination (the parser could at least restore to the PROPERTY_NAME state).
546     if (propertyData.at(propertyCount - 1).name != bogusPropertyName)
547         return false;
548
549     return true;
550 }
551
552 bool InspectorStyle::setPropertyText(unsigned index, const String& propertyText, bool overwrite, String* oldText, ExceptionState& exceptionState)
553 {
554     ASSERT(m_parentStyleSheet);
555
556     if (!m_parentStyleSheet->ensureParsedDataReady()) {
557         exceptionState.throwDOMException(NotFoundError, "The parent style sheet's data hasn't been processed.");
558         return false;
559     }
560
561     if (!propertyText.stripWhiteSpace().isEmpty()) {
562         if (!verifyPropertyText(propertyText, false) && !verifyPropertyText(propertyText, true)) {
563             exceptionState.throwDOMException(SyntaxError, "The property '" + propertyText + "' could not be set.");
564             return false;
565         }
566     }
567
568     RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
569     if (!sourceData) {
570         exceptionState.throwDOMException(NotFoundError, "The property '" + propertyText + "' could not be set.");
571         return false;
572     }
573
574     String text;
575     bool success = styleText(&text);
576     if (!success) {
577         exceptionState.throwDOMException(NotFoundError, "The property '" + propertyText + "' could not be set.");
578         return false;
579     }
580
581     Vector<InspectorStyleProperty> allProperties;
582     populateAllProperties(allProperties);
583
584     InspectorStyleTextEditor editor(&allProperties, text, newLineAndWhitespaceDelimiters());
585     if (overwrite) {
586         if (index >= allProperties.size()) {
587             exceptionState.throwDOMException(IndexSizeError, "The index provided (" + String::number(index) + ") is greater than or equal to the maximum bound (" + String::number(allProperties.size()) + ").");
588             return false;
589         }
590         *oldText = allProperties.at(index).rawText;
591         editor.replaceProperty(index, propertyText);
592     } else
593         editor.insertProperty(index, propertyText, sourceData->ruleBodyRange.length());
594
595     return applyStyleText(editor.styleText());
596 }
597
598 bool InspectorStyle::styleText(String* result) const
599 {
600     RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
601     if (!sourceData)
602         return false;
603
604     String styleSheetText;
605     bool success = m_parentStyleSheet->getText(&styleSheetText);
606     if (!success)
607         return false;
608
609     SourceRange& bodyRange = sourceData->ruleBodyRange;
610     *result = styleSheetText.substring(bodyRange.start, bodyRange.end - bodyRange.start);
611     return true;
612 }
613
614 void InspectorStyle::populateAllProperties(Vector<InspectorStyleProperty>& result) const
615 {
616     HashSet<String> sourcePropertyNames;
617
618     RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
619     if (sourceData) {
620         String styleDeclaration;
621         bool isStyleTextKnown = styleText(&styleDeclaration);
622         ASSERT_UNUSED(isStyleTextKnown, isStyleTextKnown);
623         Vector<CSSPropertySourceData>& sourcePropertyData = sourceData->styleSourceData->propertyData;
624         for (Vector<CSSPropertySourceData>::const_iterator it = sourcePropertyData.begin(); it != sourcePropertyData.end(); ++it) {
625             InspectorStyleProperty p(*it, true);
626             p.setRawTextFromStyleDeclaration(styleDeclaration);
627             result.append(p);
628             sourcePropertyNames.add(it->name.lower());
629         }
630     }
631
632     for (int i = 0, size = m_style->length(); i < size; ++i) {
633         String name = m_style->item(i);
634         if (!sourcePropertyNames.add(name.lower()).isNewEntry)
635             continue;
636
637         result.append(InspectorStyleProperty(CSSPropertySourceData(name, m_style->getPropertyValue(name), !m_style->getPropertyPriority(name).isEmpty(), false, true, SourceRange()), false));
638     }
639 }
640
641 PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorStyle::styleWithProperties() const
642 {
643     RefPtr<Array<TypeBuilder::CSS::CSSProperty> > propertiesObject = Array<TypeBuilder::CSS::CSSProperty>::create();
644     RefPtr<Array<TypeBuilder::CSS::ShorthandEntry> > shorthandEntries = Array<TypeBuilder::CSS::ShorthandEntry>::create();
645     HashMap<String, RefPtr<TypeBuilder::CSS::CSSProperty> > propertyNameToPreviousActiveProperty;
646     HashSet<String> foundShorthands;
647     String previousPriority;
648     String previousStatus;
649     OwnPtr<Vector<unsigned> > lineEndings(m_parentStyleSheet ? m_parentStyleSheet->lineEndings() : PassOwnPtr<Vector<unsigned> >());
650     RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
651     unsigned ruleBodyRangeStart = sourceData ? sourceData->ruleBodyRange.start : 0;
652
653     Vector<InspectorStyleProperty> properties;
654     populateAllProperties(properties);
655
656     for (Vector<InspectorStyleProperty>::iterator it = properties.begin(), itEnd = properties.end(); it != itEnd; ++it) {
657         const CSSPropertySourceData& propertyEntry = it->sourceData;
658         const String& name = propertyEntry.name;
659         const bool disabled = it->sourceData.disabled;
660
661         TypeBuilder::CSS::CSSProperty::Status::Enum status = disabled ? TypeBuilder::CSS::CSSProperty::Status::Disabled : TypeBuilder::CSS::CSSProperty::Status::Active;
662
663         RefPtr<TypeBuilder::CSS::CSSProperty> property = TypeBuilder::CSS::CSSProperty::create()
664             .setName(name)
665             .setValue(propertyEntry.value);
666         propertiesObject->addItem(property);
667
668         // Default "parsedOk" == true.
669         if (!propertyEntry.parsedOk)
670             property->setParsedOk(false);
671         if (it->hasRawText())
672             property->setText(it->rawText);
673
674         // Default "priority" == "".
675         if (propertyEntry.important)
676             property->setPriority("important");
677         if (it->hasSource) {
678             // The property range is relative to the style body start.
679             // Should be converted into an absolute range (relative to the stylesheet start)
680             // for the proper conversion into line:column.
681             SourceRange absolutePropertyRange = propertyEntry.range;
682             absolutePropertyRange.start += ruleBodyRangeStart;
683             absolutePropertyRange.end += ruleBodyRangeStart;
684             property->setRange(buildSourceRangeObject(absolutePropertyRange, lineEndings.get()));
685         }
686         if (!disabled) {
687             if (it->hasSource) {
688                 ASSERT(sourceData);
689                 property->setImplicit(false);
690
691                 // Parsed property overrides any property with the same name. Non-parsed property overrides
692                 // previous non-parsed property with the same name (if any).
693                 bool shouldInactivate = false;
694                 CSSPropertyID propertyId = cssPropertyID(name);
695                 // Canonicalize property names to treat non-prefixed and vendor-prefixed property names the same (opacity vs. -webkit-opacity).
696                 String canonicalPropertyName = propertyId ? getPropertyNameString(propertyId) : name;
697                 HashMap<String, RefPtr<TypeBuilder::CSS::CSSProperty> >::iterator activeIt = propertyNameToPreviousActiveProperty.find(canonicalPropertyName);
698                 if (activeIt != propertyNameToPreviousActiveProperty.end()) {
699                     if (propertyEntry.parsedOk) {
700                         bool successPriority = activeIt->value->getString(TypeBuilder::CSS::CSSProperty::Priority, &previousPriority);
701                         bool successStatus = activeIt->value->getString(TypeBuilder::CSS::CSSProperty::Status, &previousStatus);
702                         if (successStatus && previousStatus != "inactive") {
703                             if (propertyEntry.important || !successPriority) // Priority not set == "not important".
704                                 shouldInactivate = true;
705                             else if (status == TypeBuilder::CSS::CSSProperty::Status::Active) {
706                                 // Inactivate a non-important property following the same-named important property.
707                                 status = TypeBuilder::CSS::CSSProperty::Status::Inactive;
708                             }
709                         }
710                     } else {
711                         bool previousParsedOk;
712                         bool success = activeIt->value->getBoolean(TypeBuilder::CSS::CSSProperty::ParsedOk, &previousParsedOk);
713                         if (success && !previousParsedOk)
714                             shouldInactivate = true;
715                     }
716                 } else
717                     propertyNameToPreviousActiveProperty.set(canonicalPropertyName, property);
718
719                 if (shouldInactivate) {
720                     activeIt->value->setStatus(TypeBuilder::CSS::CSSProperty::Status::Inactive);
721                     propertyNameToPreviousActiveProperty.set(canonicalPropertyName, property);
722                 }
723             } else {
724                 bool implicit = m_style->isPropertyImplicit(name);
725                 // Default "implicit" == false.
726                 if (implicit)
727                     property->setImplicit(true);
728                 status = TypeBuilder::CSS::CSSProperty::Status::Style;
729
730                 String shorthand = m_style->getPropertyShorthand(name);
731                 if (!shorthand.isEmpty()) {
732                     if (foundShorthands.add(shorthand).isNewEntry) {
733                         RefPtr<TypeBuilder::CSS::ShorthandEntry> entry = TypeBuilder::CSS::ShorthandEntry::create()
734                             .setName(shorthand)
735                             .setValue(shorthandValue(shorthand));
736                         shorthandEntries->addItem(entry);
737                     }
738                 }
739             }
740         }
741
742         // Default "status" == "style".
743         if (status != TypeBuilder::CSS::CSSProperty::Status::Style)
744             property->setStatus(status);
745     }
746
747     RefPtr<TypeBuilder::CSS::CSSStyle> result = TypeBuilder::CSS::CSSStyle::create()
748         .setCssProperties(propertiesObject)
749         .setShorthandEntries(shorthandEntries);
750     return result.release();
751 }
752
753 PassRefPtr<CSSRuleSourceData> InspectorStyle::extractSourceData() const
754 {
755     if (!m_parentStyleSheet || !m_parentStyleSheet->ensureParsedDataReady())
756         return 0;
757     return m_parentStyleSheet->ruleSourceDataFor(m_style.get());
758 }
759
760 bool InspectorStyle::applyStyleText(const String& text)
761 {
762     return m_parentStyleSheet->setStyleText(m_style.get(), text);
763 }
764
765 String InspectorStyle::shorthandValue(const String& shorthandProperty) const
766 {
767     String value = m_style->getPropertyValue(shorthandProperty);
768     if (value.isEmpty()) {
769         StringBuilder builder;
770
771         for (unsigned i = 0; i < m_style->length(); ++i) {
772             String individualProperty = m_style->item(i);
773             if (m_style->getPropertyShorthand(individualProperty) != shorthandProperty)
774                 continue;
775             if (m_style->isPropertyImplicit(individualProperty))
776                 continue;
777             String individualValue = m_style->getPropertyValue(individualProperty);
778             if (individualValue == "initial")
779                 continue;
780             if (!builder.isEmpty())
781                 builder.append(" ");
782             builder.append(individualValue);
783         }
784
785         return builder.toString();
786     }
787     return value;
788 }
789
790 String InspectorStyle::shorthandPriority(const String& shorthandProperty) const
791 {
792     String priority = m_style->getPropertyPriority(shorthandProperty);
793     if (priority.isEmpty()) {
794         for (unsigned i = 0; i < m_style->length(); ++i) {
795             String individualProperty = m_style->item(i);
796             if (m_style->getPropertyShorthand(individualProperty) != shorthandProperty)
797                 continue;
798             priority = m_style->getPropertyPriority(individualProperty);
799             break;
800         }
801     }
802     return priority;
803 }
804
805 Vector<String> InspectorStyle::longhandProperties(const String& shorthandProperty) const
806 {
807     Vector<String> properties;
808     HashSet<String> foundProperties;
809     for (unsigned i = 0; i < m_style->length(); ++i) {
810         String individualProperty = m_style->item(i);
811         if (foundProperties.contains(individualProperty) || m_style->getPropertyShorthand(individualProperty) != shorthandProperty)
812             continue;
813
814         foundProperties.add(individualProperty);
815         properties.append(individualProperty);
816     }
817     return properties;
818 }
819
820 NewLineAndWhitespace& InspectorStyle::newLineAndWhitespaceDelimiters() const
821 {
822     DEFINE_STATIC_LOCAL(String, defaultPrefix, ("    "));
823
824     if (m_formatAcquired)
825         return m_format;
826
827     RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
828     Vector<CSSPropertySourceData>* sourcePropertyData = sourceData ? &(sourceData->styleSourceData->propertyData) : 0;
829     int propertyCount;
830     if (!sourcePropertyData || !(propertyCount = sourcePropertyData->size())) {
831         m_format.first = "\n";
832         m_format.second = defaultPrefix;
833         return m_format; // Do not remember the default formatting and attempt to acquire it later.
834     }
835
836     String text;
837     bool success = styleText(&text);
838     ASSERT_UNUSED(success, success);
839
840     m_formatAcquired = true;
841
842     String candidatePrefix = defaultPrefix;
843     StringBuilder formatLineFeed;
844     StringBuilder prefix;
845     int scanStart = 0;
846     int propertyIndex = 0;
847     bool isFullPrefixScanned = false;
848     bool lineFeedTerminated = false;
849     while (propertyIndex < propertyCount) {
850         const WebCore::CSSPropertySourceData& currentProperty = sourcePropertyData->at(propertyIndex++);
851
852         bool processNextProperty = false;
853         int scanEnd = currentProperty.range.start;
854         for (int i = scanStart; i < scanEnd; ++i) {
855             UChar ch = text[i];
856             bool isLineFeed = isHTMLLineBreak(ch);
857             if (isLineFeed) {
858                 if (!lineFeedTerminated)
859                     formatLineFeed.append(ch);
860                 prefix.clear();
861             } else if (isHTMLSpace<UChar>(ch))
862                 prefix.append(ch);
863             else {
864                 candidatePrefix = prefix.toString();
865                 prefix.clear();
866                 scanStart = currentProperty.range.end;
867                 ++propertyIndex;
868                 processNextProperty = true;
869                 break;
870             }
871             if (!isLineFeed && formatLineFeed.length())
872                 lineFeedTerminated = true;
873         }
874         if (!processNextProperty) {
875             isFullPrefixScanned = true;
876             break;
877         }
878     }
879
880     m_format.first = formatLineFeed.toString();
881     m_format.second = isFullPrefixScanned ? prefix.toString() : candidatePrefix;
882     return m_format;
883 }
884
885 Document* InspectorStyle::ownerDocument() const
886 {
887     return m_parentStyleSheet->pageStyleSheet() ? m_parentStyleSheet->pageStyleSheet()->ownerDocument() : 0;
888 }
889
890 PassRefPtr<InspectorStyleSheet> InspectorStyleSheet::create(InspectorPageAgent* pageAgent, InspectorResourceAgent* resourceAgent, const String& id, PassRefPtr<CSSStyleSheet> pageStyleSheet, TypeBuilder::CSS::StyleSheetOrigin::Enum origin, const String& documentURL, Listener* listener)
891 {
892     return adoptRef(new InspectorStyleSheet(pageAgent, resourceAgent, id, pageStyleSheet, origin, documentURL, listener));
893 }
894
895 // static
896 String InspectorStyleSheet::styleSheetURL(CSSStyleSheet* pageStyleSheet)
897 {
898     if (pageStyleSheet && !pageStyleSheet->contents()->baseURL().isEmpty())
899         return pageStyleSheet->contents()->baseURL().string();
900     return emptyString();
901 }
902
903 // static
904 void InspectorStyleSheet::collectFlatRules(PassRefPtr<CSSRuleList> ruleList, CSSRuleVector* result)
905 {
906     if (!ruleList)
907         return;
908
909     for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
910         CSSRule* rule = ruleList->item(i);
911
912         // The result->append()'ed types should be exactly the same as in ParsedStyleSheet::flattenSourceData().
913         switch (rule->type()) {
914         case CSSRule::STYLE_RULE:
915             result->append(rule);
916             continue;
917         case CSSRule::IMPORT_RULE:
918         case CSSRule::MEDIA_RULE:
919             result->append(rule);
920             break;
921         default:
922             break;
923         }
924         RefPtr<CSSRuleList> childRuleList = asCSSRuleList(rule);
925         if (childRuleList)
926             collectFlatRules(childRuleList, result);
927     }
928 }
929
930 InspectorStyleSheet::InspectorStyleSheet(InspectorPageAgent* pageAgent, InspectorResourceAgent* resourceAgent, const String& id, PassRefPtr<CSSStyleSheet> pageStyleSheet, TypeBuilder::CSS::StyleSheetOrigin::Enum origin, const String& documentURL, Listener* listener)
931     : m_pageAgent(pageAgent)
932     , m_resourceAgent(resourceAgent)
933     , m_id(id)
934     , m_pageStyleSheet(pageStyleSheet)
935     , m_origin(origin)
936     , m_documentURL(documentURL)
937     , m_isRevalidating(false)
938     , m_listener(listener)
939 {
940     m_parsedStyleSheet = new ParsedStyleSheet();
941 }
942
943 InspectorStyleSheet::~InspectorStyleSheet()
944 {
945     delete m_parsedStyleSheet;
946 }
947
948 String InspectorStyleSheet::finalURL() const
949 {
950     String url = styleSheetURL(m_pageStyleSheet.get());
951     return url.isEmpty() ? m_documentURL : url;
952 }
953
954 void InspectorStyleSheet::reparseStyleSheet(const String& text)
955 {
956     if (m_listener)
957         m_listener->willReparseStyleSheet();
958
959     {
960         // Have a separate scope for clearRules() (bug 95324).
961         CSSStyleSheet::RuleMutationScope mutationScope(m_pageStyleSheet.get());
962         m_pageStyleSheet->contents()->clearRules();
963         m_pageStyleSheet->clearChildRuleCSSOMWrappers();
964     }
965     {
966         CSSStyleSheet::RuleMutationScope mutationScope(m_pageStyleSheet.get());
967         m_pageStyleSheet->contents()->parseString(text);
968     }
969
970     if (m_listener)
971         m_listener->didReparseStyleSheet();
972     fireStyleSheetChanged();
973     m_pageStyleSheet->ownerDocument()->styleResolverChanged(RecalcStyleImmediately, FullStyleUpdate);
974 }
975
976 bool InspectorStyleSheet::setText(const String& text, ExceptionState& exceptionState)
977 {
978     if (!checkPageStyleSheet(exceptionState))
979         return false;
980     if (!m_parsedStyleSheet)
981         return false;
982
983     m_parsedStyleSheet->setText(text);
984     m_flatRules.clear();
985
986     return true;
987 }
988
989 String InspectorStyleSheet::ruleSelector(const InspectorCSSId& id, ExceptionState& exceptionState)
990 {
991     CSSStyleRule* rule = ruleForId(id);
992     if (!rule) {
993         exceptionState.throwDOMException(NotFoundError, "No rule was found for the given ID.");
994         return "";
995     }
996     return rule->selectorText();
997 }
998
999 bool InspectorStyleSheet::setRuleSelector(const InspectorCSSId& id, const String& selector, ExceptionState& exceptionState)
1000 {
1001     if (!checkPageStyleSheet(exceptionState))
1002         return false;
1003     CSSStyleRule* rule = ruleForId(id);
1004     if (!rule) {
1005         exceptionState.throwDOMException(NotFoundError, "No rule was found for the given ID.");
1006         return false;
1007     }
1008     CSSStyleSheet* styleSheet = rule->parentStyleSheet();
1009     if (!styleSheet || !ensureParsedDataReady()) {
1010         exceptionState.throwDOMException(NotFoundError, "No stylesheet could be found in which to set the selector.");
1011         return false;
1012     }
1013
1014     rule->setSelectorText(selector);
1015     RefPtr<CSSRuleSourceData> sourceData = ruleSourceDataFor(rule->style());
1016     if (!sourceData) {
1017         exceptionState.throwDOMException(NotFoundError, "The selector '" + selector + "' could not be set.");
1018         return false;
1019     }
1020
1021     String sheetText = m_parsedStyleSheet->text();
1022     sheetText.replace(sourceData->ruleHeaderRange.start, sourceData->ruleHeaderRange.length(), selector);
1023     m_parsedStyleSheet->setText(sheetText);
1024     fireStyleSheetChanged();
1025     return true;
1026 }
1027
1028 static bool checkStyleRuleSelector(Document* document, const String& selector)
1029 {
1030     CSSSelectorList selectorList;
1031     createCSSParser(document)->parseSelector(selector, selectorList);
1032     return selectorList.isValid();
1033 }
1034
1035 CSSStyleRule* InspectorStyleSheet::addRule(const String& selector, ExceptionState& exceptionState)
1036 {
1037     if (!checkPageStyleSheet(exceptionState))
1038         return 0;
1039     if (!checkStyleRuleSelector(m_pageStyleSheet->ownerDocument(), selector)) {
1040         exceptionState.throwDOMException(SyntaxError, "The selector '" + selector + "' could not be added.");
1041         return 0;
1042     }
1043
1044     String text;
1045     bool success = getText(&text);
1046     if (!success) {
1047         exceptionState.throwDOMException(NotFoundError, "The selector '" + selector + "' could not be added.");
1048         return 0;
1049     }
1050     StringBuilder styleSheetText;
1051     styleSheetText.append(text);
1052
1053     m_pageStyleSheet->addRule(selector, "", exceptionState);
1054     if (exceptionState.hadException())
1055         return 0;
1056     ASSERT(m_pageStyleSheet->length());
1057     unsigned lastRuleIndex = m_pageStyleSheet->length() - 1;
1058     CSSRule* rule = m_pageStyleSheet->item(lastRuleIndex);
1059     ASSERT(rule);
1060
1061     CSSStyleRule* styleRule = InspectorCSSAgent::asCSSStyleRule(rule);
1062     if (!styleRule) {
1063         // What we just added has to be a CSSStyleRule - we cannot handle other types of rules yet.
1064         // If it is not a style rule, pretend we never touched the stylesheet.
1065         m_pageStyleSheet->deleteRule(lastRuleIndex, ASSERT_NO_EXCEPTION);
1066         exceptionState.throwDOMException(SyntaxError, "The selector '" + selector + "' could not be added.");
1067         return 0;
1068     }
1069
1070     if (!styleSheetText.isEmpty())
1071         styleSheetText.append('\n');
1072
1073     styleSheetText.append(selector);
1074     styleSheetText.appendLiteral(" {}");
1075     // Using setText() as this operation changes the style sheet rule set.
1076     setText(styleSheetText.toString(), ASSERT_NO_EXCEPTION);
1077
1078     fireStyleSheetChanged();
1079
1080     return styleRule;
1081 }
1082
1083 bool InspectorStyleSheet::deleteRule(const InspectorCSSId& id, ExceptionState& exceptionState)
1084 {
1085     if (!checkPageStyleSheet(exceptionState))
1086         return false;
1087     RefPtr<CSSStyleRule> rule = ruleForId(id);
1088     if (!rule) {
1089         exceptionState.throwDOMException(NotFoundError, "No style rule could be found for the provided ID.");
1090         return false;
1091     }
1092     CSSStyleSheet* styleSheet = rule->parentStyleSheet();
1093     if (!styleSheet || !ensureParsedDataReady()) {
1094         exceptionState.throwDOMException(NotFoundError, "No parent stylesheet could be found.");
1095         return false;
1096     }
1097
1098     RefPtr<CSSRuleSourceData> sourceData = ruleSourceDataFor(rule->style());
1099     if (!sourceData) {
1100         exceptionState.throwDOMException(NotFoundError, "No style rule could be found for the provided ID.");
1101         return false;
1102     }
1103
1104     styleSheet->deleteRule(id.ordinal(), exceptionState);
1105     // |rule| MAY NOT be addressed after this line!
1106
1107     if (exceptionState.hadException())
1108         return false;
1109
1110     String sheetText = m_parsedStyleSheet->text();
1111     sheetText.remove(sourceData->ruleHeaderRange.start, sourceData->ruleBodyRange.end - sourceData->ruleHeaderRange.start + 1);
1112     setText(sheetText, ASSERT_NO_EXCEPTION);
1113     fireStyleSheetChanged();
1114     return true;
1115 }
1116
1117 CSSStyleRule* InspectorStyleSheet::ruleForId(const InspectorCSSId& id) const
1118 {
1119     if (!m_pageStyleSheet)
1120         return 0;
1121
1122     ASSERT(!id.isEmpty());
1123     ensureFlatRules();
1124     return InspectorCSSAgent::asCSSStyleRule(id.ordinal() >= m_flatRules.size() ? 0 : m_flatRules.at(id.ordinal()).get());
1125 }
1126
1127 bool InspectorStyleSheet::fillObjectForStyleSheet(PassRefPtr<TypeBuilder::CSS::CSSStyleSheetBody> prpResult)
1128 {
1129     CSSStyleSheet* styleSheet = pageStyleSheet();
1130     if (!styleSheet)
1131         return false;
1132
1133     RefPtr<TypeBuilder::CSS::CSSStyleSheetBody> result = prpResult;
1134
1135     String styleSheetText;
1136     bool success = getText(&styleSheetText);
1137     if (success)
1138         result->setText(styleSheetText);
1139     return success;
1140 }
1141
1142 PassRefPtr<TypeBuilder::CSS::CSSStyleSheetHeader> InspectorStyleSheet::buildObjectForStyleSheetInfo() const
1143 {
1144     CSSStyleSheet* styleSheet = pageStyleSheet();
1145     if (!styleSheet)
1146         return 0;
1147
1148     Document* document = styleSheet->ownerDocument();
1149     Frame* frame = document ? document->frame() : 0;
1150
1151     RefPtr<TypeBuilder::CSS::CSSStyleSheetHeader> result = TypeBuilder::CSS::CSSStyleSheetHeader::create()
1152         .setStyleSheetId(id())
1153         .setOrigin(m_origin)
1154         .setDisabled(styleSheet->disabled())
1155         .setSourceURL(url())
1156         .setTitle(styleSheet->title())
1157         .setFrameId(m_pageAgent->frameId(frame))
1158         .setIsInline(styleSheet->isInline() && !startsAtZero())
1159         .setStartLine(styleSheet->startPositionInSource().m_line.zeroBasedInt())
1160         .setStartColumn(styleSheet->startPositionInSource().m_column.zeroBasedInt());
1161
1162     if (hasSourceURL())
1163         result->setHasSourceURL(true);
1164
1165     String sourceMapURLValue = sourceMapURL();
1166     if (!sourceMapURLValue.isEmpty())
1167         result->setSourceMapURL(sourceMapURLValue);
1168     return result.release();
1169 }
1170
1171 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::Selector> > InspectorStyleSheet::selectorsFromSource(const CSSRuleSourceData* sourceData, const String& sheetText) const
1172 {
1173     ScriptRegexp comment("/\\*[^]*?\\*/", TextCaseSensitive, MultilineEnabled);
1174     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::Selector> > result = TypeBuilder::Array<TypeBuilder::CSS::Selector>::create();
1175     const SelectorRangeList& ranges = sourceData->selectorRanges;
1176     for (size_t i = 0, size = ranges.size(); i < size; ++i) {
1177         const SourceRange& range = ranges.at(i);
1178         String selector = sheetText.substring(range.start, range.length());
1179
1180         // We don't want to see any comments in the selector components, only the meaningful parts.
1181         int matchLength;
1182         int offset = 0;
1183         while ((offset = comment.match(selector, offset, &matchLength)) >= 0)
1184             selector.replace(offset, matchLength, "");
1185
1186         RefPtr<TypeBuilder::CSS::Selector> simpleSelector = TypeBuilder::CSS::Selector::create()
1187             .setValue(selector.stripWhiteSpace());
1188         simpleSelector->setRange(buildSourceRangeObject(range, lineEndings().get()));
1189         result->addItem(simpleSelector.release());
1190     }
1191     return result.release();
1192 }
1193
1194 PassRefPtr<TypeBuilder::CSS::SelectorList> InspectorStyleSheet::buildObjectForSelectorList(CSSStyleRule* rule)
1195 {
1196     RefPtr<CSSRuleSourceData> sourceData;
1197     if (ensureParsedDataReady())
1198         sourceData = ruleSourceDataFor(rule->style());
1199     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::Selector> > selectors;
1200
1201     // This intentionally does not rely on the source data to avoid catching the trailing comments (before the declaration starting '{').
1202     String selectorText = rule->selectorText();
1203
1204     if (sourceData)
1205         selectors = selectorsFromSource(sourceData.get(), m_parsedStyleSheet->text());
1206     else {
1207         selectors = TypeBuilder::Array<TypeBuilder::CSS::Selector>::create();
1208         const CSSSelectorList& selectorList = rule->styleRule()->selectorList();
1209         for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector))
1210             selectors->addItem(TypeBuilder::CSS::Selector::create().setValue(selector->selectorText()).release());
1211     }
1212     RefPtr<TypeBuilder::CSS::SelectorList> result = TypeBuilder::CSS::SelectorList::create()
1213         .setSelectors(selectors)
1214         .setText(selectorText)
1215         .release();
1216     return result.release();
1217 }
1218
1219 PassRefPtr<TypeBuilder::CSS::CSSRule> InspectorStyleSheet::buildObjectForRule(CSSStyleRule* rule, PassRefPtr<Array<TypeBuilder::CSS::CSSMedia> > mediaStack)
1220 {
1221     CSSStyleSheet* styleSheet = pageStyleSheet();
1222     if (!styleSheet)
1223         return 0;
1224
1225     RefPtr<TypeBuilder::CSS::CSSRule> result = TypeBuilder::CSS::CSSRule::create()
1226         .setSelectorList(buildObjectForSelectorList(rule))
1227         .setOrigin(m_origin)
1228         .setStyle(buildObjectForStyle(rule->style()));
1229
1230     String url = this->url();
1231     if (!url.isEmpty())
1232         result->setSourceURL(url);
1233
1234     if (canBind()) {
1235         InspectorCSSId id(ruleId(rule));
1236         if (!id.isEmpty())
1237             result->setRuleId(id.asProtocolValue<TypeBuilder::CSS::CSSRuleId>());
1238     }
1239
1240     if (mediaStack)
1241         result->setMedia(mediaStack);
1242
1243     return result.release();
1244 }
1245
1246 PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorStyleSheet::buildObjectForStyle(CSSStyleDeclaration* style)
1247 {
1248     RefPtr<CSSRuleSourceData> sourceData;
1249     if (ensureParsedDataReady())
1250         sourceData = ruleSourceDataFor(style);
1251
1252     InspectorCSSId id = ruleOrStyleId(style);
1253     if (id.isEmpty()) {
1254         // Any rule coming from User Agent and not from DefaultStyleSheet will not have id.
1255         // See InspectorCSSAgent::buildObjectForRule for details.
1256         RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(id, style, this);
1257         return inspectorStyle->buildObjectForStyle();
1258     }
1259     RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id);
1260     RefPtr<TypeBuilder::CSS::CSSStyle> result = inspectorStyle->buildObjectForStyle();
1261
1262     // Style text cannot be retrieved without stylesheet, so set cssText here.
1263     if (sourceData) {
1264         String sheetText;
1265         bool success = getText(&sheetText);
1266         if (success) {
1267             const SourceRange& bodyRange = sourceData->ruleBodyRange;
1268             result->setCssText(sheetText.substring(bodyRange.start, bodyRange.end - bodyRange.start));
1269         }
1270     }
1271
1272     return result.release();
1273 }
1274
1275 bool InspectorStyleSheet::setStyleText(const InspectorCSSId& id, const String& text, String* oldText, ExceptionState& exceptionState)
1276 {
1277     RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id);
1278     if (!inspectorStyle || !inspectorStyle->cssStyle()) {
1279         exceptionState.throwDOMException(NotFoundError, "No property could be found for the given ID.");
1280         return false;
1281     }
1282
1283     bool success = inspectorStyle->styleText(oldText);
1284     if (!success) {
1285         exceptionState.throwDOMException(NotFoundError, "Style text could not be read for the given property.");
1286         return false;
1287     }
1288
1289     success = setStyleText(inspectorStyle->cssStyle(), text);
1290     if (success)
1291         fireStyleSheetChanged();
1292     else
1293         exceptionState.throwDOMException(SyntaxError, "The style text '" + text + "' is invalid.");
1294     return success;
1295 }
1296
1297 bool InspectorStyleSheet::setPropertyText(const InspectorCSSId& id, unsigned propertyIndex, const String& text, bool overwrite, String* oldText, ExceptionState& exceptionState)
1298 {
1299     RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id);
1300     if (!inspectorStyle) {
1301         exceptionState.throwDOMException(NotFoundError, "No property could be found for the given ID.");
1302         return false;
1303     }
1304
1305     bool success = inspectorStyle->setPropertyText(propertyIndex, text, overwrite, oldText, exceptionState);
1306     if (success)
1307         fireStyleSheetChanged();
1308     return success;
1309 }
1310
1311 bool InspectorStyleSheet::getText(String* result) const
1312 {
1313     if (!ensureText())
1314         return false;
1315     *result = m_parsedStyleSheet->text();
1316     return true;
1317 }
1318
1319 CSSStyleDeclaration* InspectorStyleSheet::styleForId(const InspectorCSSId& id) const
1320 {
1321     CSSStyleRule* rule = ruleForId(id);
1322     if (!rule)
1323         return 0;
1324
1325     return rule->style();
1326 }
1327
1328 void InspectorStyleSheet::fireStyleSheetChanged()
1329 {
1330     if (m_listener)
1331         m_listener->styleSheetChanged(this);
1332 }
1333
1334 PassRefPtr<TypeBuilder::CSS::SourceRange> InspectorStyleSheet::ruleHeaderSourceRange(const CSSRule* rule)
1335 {
1336     if (!ensureParsedDataReady())
1337         return 0;
1338
1339     RefPtr<CSSRuleSourceData> sourceData = m_parsedStyleSheet->ruleSourceDataAt(ruleIndexByRule(rule));
1340     if (!sourceData)
1341         return 0;
1342     return buildSourceRangeObject(sourceData->ruleHeaderRange, lineEndings().get());
1343 }
1344
1345 PassRefPtr<InspectorStyle> InspectorStyleSheet::inspectorStyleForId(const InspectorCSSId& id)
1346 {
1347     CSSStyleDeclaration* style = styleForId(id);
1348     if (!style)
1349         return 0;
1350
1351     return InspectorStyle::create(id, style, this);
1352 }
1353
1354 String InspectorStyleSheet::sourceURL() const
1355 {
1356     if (!m_sourceURL.isNull())
1357         return m_sourceURL;
1358     if (m_origin != TypeBuilder::CSS::StyleSheetOrigin::Regular) {
1359         m_sourceURL = "";
1360         return m_sourceURL;
1361     }
1362
1363     String styleSheetText;
1364     bool success = getText(&styleSheetText);
1365     if (success) {
1366         bool deprecated;
1367         String commentValue = ContentSearchUtils::findSourceURL(styleSheetText, ContentSearchUtils::CSSMagicComment, &deprecated);
1368         if (!commentValue.isEmpty()) {
1369             // FIXME: add deprecated console message here.
1370             m_sourceURL = commentValue;
1371             return commentValue;
1372         }
1373     }
1374     m_sourceURL = "";
1375     return m_sourceURL;
1376 }
1377
1378 String InspectorStyleSheet::url() const
1379 {
1380     // "sourceURL" is present only for regular rules, otherwise "origin" should be used in the frontend.
1381     if (m_origin != TypeBuilder::CSS::StyleSheetOrigin::Regular)
1382         return String();
1383
1384     CSSStyleSheet* styleSheet = pageStyleSheet();
1385     if (!styleSheet)
1386         return String();
1387
1388     if (hasSourceURL())
1389         return sourceURL();
1390
1391     if (styleSheet->isInline() && startsAtZero())
1392         return String();
1393
1394     return finalURL();
1395 }
1396
1397 bool InspectorStyleSheet::hasSourceURL() const
1398 {
1399     return !sourceURL().isEmpty();
1400 }
1401
1402 bool InspectorStyleSheet::startsAtZero() const
1403 {
1404     CSSStyleSheet* styleSheet = pageStyleSheet();
1405     if (!styleSheet)
1406         return true;
1407
1408     return styleSheet->startPositionInSource() == TextPosition::minimumPosition();
1409 }
1410
1411 String InspectorStyleSheet::sourceMapURL() const
1412 {
1413     if (m_origin != TypeBuilder::CSS::StyleSheetOrigin::Regular)
1414         return String();
1415
1416     String styleSheetText;
1417     bool success = getText(&styleSheetText);
1418     if (success) {
1419         bool deprecated;
1420         String commentValue = ContentSearchUtils::findSourceMapURL(styleSheetText, ContentSearchUtils::CSSMagicComment, &deprecated);
1421         if (!commentValue.isEmpty()) {
1422             // FIXME: add deprecated console message here.
1423             return commentValue;
1424         }
1425     }
1426     return m_pageAgent->resourceSourceMapURL(finalURL());
1427 }
1428
1429 InspectorCSSId InspectorStyleSheet::ruleOrStyleId(CSSStyleDeclaration* style) const
1430 {
1431     unsigned index = ruleIndexByStyle(style);
1432     if (index != UINT_MAX)
1433         return InspectorCSSId(id(), index);
1434     return InspectorCSSId();
1435 }
1436
1437 Document* InspectorStyleSheet::ownerDocument() const
1438 {
1439     return m_pageStyleSheet->ownerDocument();
1440 }
1441
1442 PassRefPtr<CSSRuleSourceData> InspectorStyleSheet::ruleSourceDataFor(CSSStyleDeclaration* style) const
1443 {
1444     return m_parsedStyleSheet->ruleSourceDataAt(ruleIndexByStyle(style));
1445 }
1446
1447 PassOwnPtr<Vector<unsigned> > InspectorStyleSheet::lineEndings() const
1448 {
1449     if (!m_parsedStyleSheet->hasText())
1450         return PassOwnPtr<Vector<unsigned> >();
1451     return WTF::lineEndings(m_parsedStyleSheet->text());
1452 }
1453
1454 unsigned InspectorStyleSheet::ruleIndexByStyle(CSSStyleDeclaration* pageStyle) const
1455 {
1456     ensureFlatRules();
1457     for (unsigned i = 0, size = m_flatRules.size(); i < size; ++i) {
1458         CSSStyleRule* styleRule = InspectorCSSAgent::asCSSStyleRule(m_flatRules.at(i).get());
1459         if (styleRule && styleRule->style() == pageStyle)
1460             return i;
1461     }
1462     return UINT_MAX;
1463 }
1464
1465 unsigned InspectorStyleSheet::ruleIndexByRule(const CSSRule* rule) const
1466 {
1467     ensureFlatRules();
1468     size_t index = m_flatRules.find(rule);
1469     return index == kNotFound ? UINT_MAX : static_cast<unsigned>(index);
1470 }
1471
1472 bool InspectorStyleSheet::checkPageStyleSheet(ExceptionState& exceptionState) const
1473 {
1474     if (!m_pageStyleSheet) {
1475         exceptionState.throwDOMException(NotSupportedError, "No stylesheet is available.");
1476         return false;
1477     }
1478     return true;
1479 }
1480
1481 bool InspectorStyleSheet::ensureParsedDataReady()
1482 {
1483     return ensureText() && ensureSourceData();
1484 }
1485
1486 bool InspectorStyleSheet::ensureText() const
1487 {
1488     if (!m_parsedStyleSheet)
1489         return false;
1490     if (m_parsedStyleSheet->hasText())
1491         return true;
1492
1493     String text;
1494     bool success = originalStyleSheetText(&text);
1495     if (success)
1496         m_parsedStyleSheet->setText(text);
1497     // No need to clear m_flatRules here - it's empty.
1498
1499     return success;
1500 }
1501
1502 bool InspectorStyleSheet::ensureSourceData()
1503 {
1504     if (m_parsedStyleSheet->hasSourceData())
1505         return true;
1506
1507     if (!m_parsedStyleSheet->hasText())
1508         return false;
1509
1510     RefPtr<StyleSheetContents> newStyleSheet = StyleSheetContents::create(strictCSSParserContext());
1511     OwnPtr<RuleSourceDataList> result = adoptPtr(new RuleSourceDataList());
1512     StyleSheetHandler handler(m_parsedStyleSheet->text(), m_pageStyleSheet->ownerDocument(), newStyleSheet.get(), result.get());
1513     createCSSParser(m_pageStyleSheet->ownerDocument())->parseSheet(newStyleSheet.get(), m_parsedStyleSheet->text(), TextPosition::minimumPosition(), &handler);
1514     m_parsedStyleSheet->setSourceData(result.release());
1515     return m_parsedStyleSheet->hasSourceData();
1516 }
1517
1518 void InspectorStyleSheet::ensureFlatRules() const
1519 {
1520     // We are fine with redoing this for empty stylesheets as this will run fast.
1521     if (m_flatRules.isEmpty())
1522         collectFlatRules(asCSSRuleList(pageStyleSheet()), &m_flatRules);
1523 }
1524
1525 bool InspectorStyleSheet::setStyleText(CSSStyleDeclaration* style, const String& text)
1526 {
1527     if (!m_pageStyleSheet)
1528         return false;
1529     if (!ensureParsedDataReady())
1530         return false;
1531
1532     String patchedStyleSheetText;
1533     bool success = styleSheetTextWithChangedStyle(style, text, &patchedStyleSheetText);
1534     if (!success)
1535         return false;
1536
1537     InspectorCSSId id = ruleOrStyleId(style);
1538     if (id.isEmpty())
1539         return false;
1540
1541     TrackExceptionState exceptionState;
1542     style->setCSSText(text, exceptionState);
1543     if (!exceptionState.hadException())
1544         m_parsedStyleSheet->setText(patchedStyleSheetText);
1545
1546     return !exceptionState.hadException();
1547 }
1548
1549 bool InspectorStyleSheet::styleSheetTextWithChangedStyle(CSSStyleDeclaration* style, const String& newStyleText, String* result)
1550 {
1551     if (!style)
1552         return false;
1553
1554     if (!ensureParsedDataReady())
1555         return false;
1556
1557     RefPtr<CSSRuleSourceData> sourceData = ruleSourceDataFor(style);
1558     unsigned bodyStart = sourceData->ruleBodyRange.start;
1559     unsigned bodyEnd = sourceData->ruleBodyRange.end;
1560     ASSERT(bodyStart <= bodyEnd);
1561
1562     String text = m_parsedStyleSheet->text();
1563     ASSERT_WITH_SECURITY_IMPLICATION(bodyEnd <= text.length()); // bodyEnd is exclusive
1564
1565     text.replace(bodyStart, bodyEnd - bodyStart, newStyleText);
1566     *result = text;
1567     return true;
1568 }
1569
1570 InspectorCSSId InspectorStyleSheet::ruleId(CSSStyleRule* rule) const
1571 {
1572     return ruleOrStyleId(rule->style());
1573 }
1574
1575 void InspectorStyleSheet::revalidateStyle(CSSStyleDeclaration* pageStyle)
1576 {
1577     if (m_isRevalidating)
1578         return;
1579
1580     m_isRevalidating = true;
1581     ensureFlatRules();
1582     for (unsigned i = 0, size = m_flatRules.size(); i < size; ++i) {
1583         CSSStyleRule* parsedRule = InspectorCSSAgent::asCSSStyleRule(m_flatRules.at(i).get());
1584         if (parsedRule && parsedRule->style() == pageStyle) {
1585             if (parsedRule->styleRule()->properties()->asText() != pageStyle->cssText())
1586                 setStyleText(pageStyle, pageStyle->cssText());
1587             break;
1588         }
1589     }
1590     m_isRevalidating = false;
1591 }
1592
1593 bool InspectorStyleSheet::originalStyleSheetText(String* result) const
1594 {
1595     bool success = inlineStyleSheetText(result);
1596     if (!success)
1597         success = resourceStyleSheetText(result);
1598     return success;
1599 }
1600
1601 bool InspectorStyleSheet::resourceStyleSheetText(String* result) const
1602 {
1603     if (m_origin == TypeBuilder::CSS::StyleSheetOrigin::User || m_origin == TypeBuilder::CSS::StyleSheetOrigin::User_agent)
1604         return false;
1605
1606     if (!m_pageStyleSheet || !ownerDocument() || !ownerDocument()->frame())
1607         return false;
1608
1609     bool base64Encoded;
1610     bool success = m_resourceAgent->fetchResourceContent(ownerDocument()->frame(), KURL(ParsedURLString, m_pageStyleSheet->href()), result, &base64Encoded) && !base64Encoded;
1611     return success;
1612 }
1613
1614 bool InspectorStyleSheet::inlineStyleSheetText(String* result) const
1615 {
1616     if (!m_pageStyleSheet)
1617         return false;
1618
1619     Node* ownerNode = m_pageStyleSheet->ownerNode();
1620     if (!ownerNode || ownerNode->nodeType() != Node::ELEMENT_NODE)
1621         return false;
1622     Element* ownerElement = toElement(ownerNode);
1623
1624     if (!ownerElement->hasTagName(HTMLNames::styleTag) && !ownerElement->hasTagName(SVGNames::styleTag))
1625         return false;
1626     *result = ownerElement->textContent();
1627     return true;
1628 }
1629
1630 PassRefPtr<InspectorStyleSheetForInlineStyle> InspectorStyleSheetForInlineStyle::create(InspectorPageAgent* pageAgent, InspectorResourceAgent* resourceAgent, const String& id, PassRefPtr<Element> element, TypeBuilder::CSS::StyleSheetOrigin::Enum origin, Listener* listener)
1631 {
1632     return adoptRef(new InspectorStyleSheetForInlineStyle(pageAgent, resourceAgent, id, element, origin, listener));
1633 }
1634
1635 InspectorStyleSheetForInlineStyle::InspectorStyleSheetForInlineStyle(InspectorPageAgent* pageAgent, InspectorResourceAgent* resourceAgent, const String& id, PassRefPtr<Element> element, TypeBuilder::CSS::StyleSheetOrigin::Enum origin, Listener* listener)
1636     : InspectorStyleSheet(pageAgent, resourceAgent, id, 0, origin, "", listener)
1637     , m_element(element)
1638     , m_ruleSourceData(0)
1639     , m_isStyleTextValid(false)
1640 {
1641     ASSERT(m_element);
1642     m_inspectorStyle = InspectorStyle::create(InspectorCSSId(id, 0), inlineStyle(), this);
1643     m_styleText = m_element->isStyledElement() ? m_element->getAttribute("style").string() : String();
1644 }
1645
1646 void InspectorStyleSheetForInlineStyle::didModifyElementAttribute()
1647 {
1648     m_isStyleTextValid = false;
1649     if (m_element->isStyledElement() && m_element->style() != m_inspectorStyle->cssStyle())
1650         m_inspectorStyle = InspectorStyle::create(InspectorCSSId(id(), 0), inlineStyle(), this);
1651     m_ruleSourceData.clear();
1652 }
1653
1654 void InspectorStyleSheetForInlineStyle::reparseStyleSheet(const String& text)
1655 {
1656     fireStyleSheetChanged();
1657 }
1658
1659 bool InspectorStyleSheetForInlineStyle::setText(const String& text, ExceptionState& exceptionState)
1660 {
1661     bool success = setStyleText(inlineStyle(), text);
1662     if (!success)
1663         exceptionState.throwDOMException(SyntaxError, "Style sheet text is invalid.");
1664     return success;
1665 }
1666
1667 bool InspectorStyleSheetForInlineStyle::getText(String* result) const
1668 {
1669     if (!m_isStyleTextValid) {
1670         m_styleText = elementStyleText();
1671         m_isStyleTextValid = true;
1672     }
1673     *result = m_styleText;
1674     return true;
1675 }
1676
1677 bool InspectorStyleSheetForInlineStyle::setStyleText(CSSStyleDeclaration* style, const String& text)
1678 {
1679     ASSERT_UNUSED(style, style == inlineStyle());
1680     TrackExceptionState exceptionState;
1681
1682     {
1683         InspectorCSSAgent::InlineStyleOverrideScope overrideScope(m_element->ownerDocument());
1684         m_element->setAttribute("style", AtomicString(text), exceptionState);
1685     }
1686
1687     m_styleText = text;
1688     m_isStyleTextValid = true;
1689     m_ruleSourceData.clear();
1690     return !exceptionState.hadException();
1691 }
1692
1693 PassOwnPtr<Vector<unsigned> > InspectorStyleSheetForInlineStyle::lineEndings() const
1694 {
1695     return WTF::lineEndings(elementStyleText());
1696 }
1697
1698 Document* InspectorStyleSheetForInlineStyle::ownerDocument() const
1699 {
1700     return &m_element->document();
1701 }
1702
1703 bool InspectorStyleSheetForInlineStyle::ensureParsedDataReady()
1704 {
1705     // The "style" property value can get changed indirectly, e.g. via element.style.borderWidth = "2px".
1706     const String& currentStyleText = elementStyleText();
1707     if (m_styleText != currentStyleText) {
1708         m_ruleSourceData.clear();
1709         m_styleText = currentStyleText;
1710         m_isStyleTextValid = true;
1711     }
1712
1713     if (m_ruleSourceData)
1714         return true;
1715
1716     m_ruleSourceData = getStyleAttributeData();
1717
1718     bool success = !!m_ruleSourceData;
1719     if (!success) {
1720         m_ruleSourceData = CSSRuleSourceData::create(CSSRuleSourceData::STYLE_RULE);
1721         return false;
1722     }
1723
1724     return true;
1725 }
1726
1727 PassRefPtr<InspectorStyle> InspectorStyleSheetForInlineStyle::inspectorStyleForId(const InspectorCSSId& id)
1728 {
1729     ASSERT_UNUSED(id, !id.ordinal());
1730     return m_inspectorStyle;
1731 }
1732
1733 CSSStyleDeclaration* InspectorStyleSheetForInlineStyle::inlineStyle() const
1734 {
1735     return m_element->style();
1736 }
1737
1738 const String& InspectorStyleSheetForInlineStyle::elementStyleText() const
1739 {
1740     return m_element->getAttribute("style").string();
1741 }
1742
1743 PassRefPtr<CSSRuleSourceData> InspectorStyleSheetForInlineStyle::getStyleAttributeData() const
1744 {
1745     if (!m_element->isStyledElement())
1746         return 0;
1747
1748     if (m_styleText.isEmpty()) {
1749         RefPtr<CSSRuleSourceData> result = CSSRuleSourceData::create(CSSRuleSourceData::STYLE_RULE);
1750         result->ruleBodyRange.start = 0;
1751         result->ruleBodyRange.end = 0;
1752         return result.release();
1753     }
1754
1755     RefPtr<MutableStylePropertySet> tempDeclaration = MutableStylePropertySet::create();
1756     RuleSourceDataList ruleSourceDataResult;
1757     StyleSheetHandler handler(m_styleText, &m_element->document(), m_element->document().elementSheet()->contents(), &ruleSourceDataResult);
1758     createCSSParser(&m_element->document())->parseDeclaration(tempDeclaration.get(), m_styleText, &handler, m_element->document().elementSheet()->contents());
1759     return ruleSourceDataResult.first().release();
1760 }
1761
1762 } // namespace WebCore
1763