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