| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "core/css/parser/CSSParserImpl.h" | 6 #include "core/css/parser/CSSParserImpl.h" |
| 7 | 7 |
| 8 #include "core/css/CSSKeyframesRule.h" | 8 #include "core/css/CSSKeyframesRule.h" |
| 9 #include "core/css/CSSStyleSheet.h" | 9 #include "core/css/CSSStyleSheet.h" |
| 10 #include "core/css/StylePropertySet.h" | 10 #include "core/css/StylePropertySet.h" |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 range.consumeWhitespace(); | 117 range.consumeWhitespace(); |
| 118 if (!rule || !range.atEnd()) | 118 if (!rule || !range.atEnd()) |
| 119 return nullptr; // Parse error, trailing garbage | 119 return nullptr; // Parse error, trailing garbage |
| 120 return rule; | 120 return rule; |
| 121 } | 121 } |
| 122 | 122 |
| 123 void CSSParserImpl::parseStyleSheet(const String& string, const CSSParserContext
& context, StyleSheetContents* styleSheet) | 123 void CSSParserImpl::parseStyleSheet(const String& string, const CSSParserContext
& context, StyleSheetContents* styleSheet) |
| 124 { | 124 { |
| 125 CSSParserImpl parser(context, styleSheet); | 125 CSSParserImpl parser(context, styleSheet); |
| 126 CSSTokenizer::Scope scope(string); | 126 CSSTokenizer::Scope scope(string); |
| 127 parser.consumeRuleList(scope.tokenRange(), TopLevelRuleList, [&styleSheet](P
assRefPtrWillBeRawPtr<StyleRuleBase> rule) { | 127 bool firstRuleValid = parser.consumeRuleList(scope.tokenRange(), TopLevelRul
eList, [&styleSheet](PassRefPtrWillBeRawPtr<StyleRuleBase> rule) { |
| 128 styleSheet->parserAppendRule(rule); | 128 styleSheet->parserAppendRule(rule); |
| 129 }); | 129 }); |
| 130 styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid); |
| 130 } | 131 } |
| 131 | 132 |
| 132 PassOwnPtr<Vector<double>> CSSParserImpl::parseKeyframeKeyList(const String& key
List) | 133 PassOwnPtr<Vector<double>> CSSParserImpl::parseKeyframeKeyList(const String& key
List) |
| 133 { | 134 { |
| 134 return consumeKeyframeKeyList(CSSTokenizer::Scope(keyList).tokenRange()); | 135 return consumeKeyframeKeyList(CSSTokenizer::Scope(keyList).tokenRange()); |
| 135 } | 136 } |
| 136 | 137 |
| 137 bool CSSParserImpl::supportsDeclaration(CSSParserTokenRange& range) | 138 bool CSSParserImpl::supportsDeclaration(CSSParserTokenRange& range) |
| 138 { | 139 { |
| 139 ASSERT(m_parsedProperties.isEmpty()); | 140 ASSERT(m_parsedProperties.isEmpty()); |
| 140 consumeDeclaration(range, StyleRule::Style); | 141 consumeDeclaration(range, StyleRule::Style); |
| 141 bool result = !m_parsedProperties.isEmpty(); | 142 bool result = !m_parsedProperties.isEmpty(); |
| 142 m_parsedProperties.clear(); | 143 m_parsedProperties.clear(); |
| 143 return result; | 144 return result; |
| 144 } | 145 } |
| 145 | 146 |
| 146 static CSSParserImpl::AllowedRulesType computeNewAllowedRules(CSSParserImpl::All
owedRulesType allowedRules, StyleRuleBase* rule) | 147 static CSSParserImpl::AllowedRulesType computeNewAllowedRules(CSSParserImpl::All
owedRulesType allowedRules, StyleRuleBase* rule) |
| 147 { | 148 { |
| 148 if (!rule || allowedRules == CSSParserImpl::KeyframeRules) | 149 if (!rule || allowedRules == CSSParserImpl::KeyframeRules) |
| 149 return allowedRules; | 150 return allowedRules; |
| 150 ASSERT(allowedRules <= CSSParserImpl::RegularRules); | 151 ASSERT(allowedRules <= CSSParserImpl::RegularRules); |
| 151 if (rule->isImportRule()) | 152 if (rule->isImportRule()) |
| 152 return CSSParserImpl::AllowImportRules; | 153 return CSSParserImpl::AllowImportRules; |
| 153 if (rule->isNamespaceRule()) | 154 if (rule->isNamespaceRule()) |
| 154 return CSSParserImpl::AllowNamespaceRules; | 155 return CSSParserImpl::AllowNamespaceRules; |
| 155 return CSSParserImpl::RegularRules; | 156 return CSSParserImpl::RegularRules; |
| 156 } | 157 } |
| 157 | 158 |
| 158 template<typename T> | 159 template<typename T> |
| 159 void CSSParserImpl::consumeRuleList(CSSParserTokenRange range, RuleListType rule
ListType, const T callback) | 160 bool CSSParserImpl::consumeRuleList(CSSParserTokenRange range, RuleListType rule
ListType, const T callback) |
| 160 { | 161 { |
| 161 AllowedRulesType allowedRules = RegularRules; | 162 AllowedRulesType allowedRules = RegularRules; |
| 162 switch (ruleListType) { | 163 switch (ruleListType) { |
| 163 case TopLevelRuleList: | 164 case TopLevelRuleList: |
| 164 allowedRules = AllowCharsetRules; | 165 allowedRules = AllowCharsetRules; |
| 165 break; | 166 break; |
| 166 case RegularRuleList: | 167 case RegularRuleList: |
| 167 allowedRules = RegularRules; | 168 allowedRules = RegularRules; |
| 168 break; | 169 break; |
| 169 case KeyframesRuleList: | 170 case KeyframesRuleList: |
| 170 allowedRules = KeyframeRules; | 171 allowedRules = KeyframeRules; |
| 171 break; | 172 break; |
| 172 default: | 173 default: |
| 173 ASSERT_NOT_REACHED(); | 174 ASSERT_NOT_REACHED(); |
| 174 } | 175 } |
| 175 | 176 |
| 177 bool seenRule = false; |
| 178 bool firstRuleValid = false; |
| 176 while (!range.atEnd()) { | 179 while (!range.atEnd()) { |
| 180 RefPtrWillBeRawPtr<StyleRuleBase> rule; |
| 177 switch (range.peek().type()) { | 181 switch (range.peek().type()) { |
| 178 case WhitespaceToken: | 182 case WhitespaceToken: |
| 179 range.consumeWhitespace(); | 183 range.consumeWhitespace(); |
| 180 break; | 184 continue; |
| 181 case AtKeywordToken: | 185 case AtKeywordToken: |
| 182 if (PassRefPtrWillBeRawPtr<StyleRuleBase> rule = consumeAtRule(range
, allowedRules)) { | 186 rule = consumeAtRule(range, allowedRules); |
| 183 allowedRules = computeNewAllowedRules(allowedRules, rule.get()); | |
| 184 callback(rule); | |
| 185 } | |
| 186 break; | 187 break; |
| 187 case CDOToken: | 188 case CDOToken: |
| 188 case CDCToken: | 189 case CDCToken: |
| 189 if (ruleListType == TopLevelRuleList) { | 190 if (ruleListType == TopLevelRuleList) { |
| 190 range.consume(); | 191 range.consume(); |
| 191 break; | 192 continue; |
| 192 } | 193 } |
| 193 // fallthrough | 194 // fallthrough |
| 194 default: | 195 default: |
| 195 if (PassRefPtrWillBeRawPtr<StyleRuleBase> rule = consumeQualifiedRul
e(range, allowedRules)) { | 196 rule = consumeQualifiedRule(range, allowedRules); |
| 196 allowedRules = computeNewAllowedRules(allowedRules, rule.get()); | |
| 197 callback(rule); | |
| 198 } | |
| 199 break; | 197 break; |
| 200 } | 198 } |
| 199 if (!seenRule) { |
| 200 seenRule = true; |
| 201 firstRuleValid = rule; |
| 202 } |
| 203 if (rule) { |
| 204 allowedRules = computeNewAllowedRules(allowedRules, rule.get()); |
| 205 callback(rule.release()); |
| 206 } |
| 201 } | 207 } |
| 208 |
| 209 return firstRuleValid; |
| 202 } | 210 } |
| 203 | 211 |
| 204 PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParserImpl::consumeAtRule(CSSParserToke
nRange& range, AllowedRulesType allowedRules) | 212 PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParserImpl::consumeAtRule(CSSParserToke
nRange& range, AllowedRulesType allowedRules) |
| 205 { | 213 { |
| 206 ASSERT(range.peek().type() == AtKeywordToken); | 214 ASSERT(range.peek().type() == AtKeywordToken); |
| 207 const CSSParserString& name = range.consume().value(); | 215 const CSSParserString& name = range.consume().value(); |
| 208 const CSSParserToken* preludeStart = &range.peek(); | 216 const CSSParserToken* preludeStart = &range.peek(); |
| 209 while (!range.atEnd() && range.peek().type() != LeftBraceToken && range.peek
().type() != SemicolonToken) | 217 while (!range.atEnd() && range.peek().type() != LeftBraceToken && range.peek
().type() != SemicolonToken) |
| 210 range.consumeComponentValue(); | 218 range.consumeComponentValue(); |
| 211 | 219 |
| 212 CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek()
); | 220 CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek()
); |
| 213 | 221 |
| 214 if (range.atEnd() || range.peek().type() == SemicolonToken) { | 222 if (range.atEnd() || range.peek().type() == SemicolonToken) { |
| 215 range.consume(); | 223 range.consume(); |
| 216 if (allowedRules == AllowCharsetRules && name.equalIgnoringCase("charset
")) { | 224 if (allowedRules == AllowCharsetRules && name.equalIgnoringCase("charset
")) |
| 217 // @charset is actually parsed before we get into the CSS parser. | 225 return consumeCharsetRule(prelude); |
| 218 // In theory we should validate the prelude is a string, but we don'
t | |
| 219 // have error logging yet so it doesn't matter. | |
| 220 return nullptr; | |
| 221 } | |
| 222 if (allowedRules <= AllowImportRules && name.equalIgnoringCase("import")
) | 226 if (allowedRules <= AllowImportRules && name.equalIgnoringCase("import")
) |
| 223 return consumeImportRule(prelude); | 227 return consumeImportRule(prelude); |
| 224 if (allowedRules <= AllowNamespaceRules && name.equalIgnoringCase("names
pace")) | 228 if (allowedRules <= AllowNamespaceRules && name.equalIgnoringCase("names
pace")) |
| 225 return consumeNamespaceRule(prelude); | 229 return consumeNamespaceRule(prelude); |
| 226 return nullptr; // Parse error, unrecognised at-rule without block | 230 return nullptr; // Parse error, unrecognised at-rule without block |
| 227 } | 231 } |
| 228 | 232 |
| 229 CSSParserTokenRange block = range.consumeBlock(); | 233 CSSParserTokenRange block = range.consumeBlock(); |
| 230 if (allowedRules == KeyframeRules) | 234 if (allowedRules == KeyframeRules) |
| 231 return nullptr; // Parse error, no at-rules supported inside @keyframes | 235 return nullptr; // Parse error, no at-rules supported inside @keyframes |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 return AtomicString(); | 286 return AtomicString(); |
| 283 | 287 |
| 284 CSSParserTokenRange contents = range.consumeBlock(); | 288 CSSParserTokenRange contents = range.consumeBlock(); |
| 285 const CSSParserToken& uri = contents.consumeIncludingWhitespace(); | 289 const CSSParserToken& uri = contents.consumeIncludingWhitespace(); |
| 286 ASSERT(uri.type() == StringToken); | 290 ASSERT(uri.type() == StringToken); |
| 287 if (!contents.atEnd()) | 291 if (!contents.atEnd()) |
| 288 return AtomicString(); | 292 return AtomicString(); |
| 289 return uri.value(); | 293 return uri.value(); |
| 290 } | 294 } |
| 291 | 295 |
| 296 PassRefPtrWillBeRawPtr<StyleRuleCharset> CSSParserImpl::consumeCharsetRule(CSSPa
rserTokenRange prelude) |
| 297 { |
| 298 prelude.consumeWhitespace(); |
| 299 const CSSParserToken& string = prelude.consumeIncludingWhitespace(); |
| 300 if (string.type() != StringToken || !prelude.atEnd()) |
| 301 return nullptr; // Parse error, expected a single string |
| 302 return StyleRuleCharset::create(); |
| 303 } |
| 304 |
| 292 PassRefPtrWillBeRawPtr<StyleRuleImport> CSSParserImpl::consumeImportRule(CSSPars
erTokenRange prelude) | 305 PassRefPtrWillBeRawPtr<StyleRuleImport> CSSParserImpl::consumeImportRule(CSSPars
erTokenRange prelude) |
| 293 { | 306 { |
| 294 prelude.consumeWhitespace(); | 307 prelude.consumeWhitespace(); |
| 295 AtomicString uri(consumeStringOrURI(prelude)); | 308 AtomicString uri(consumeStringOrURI(prelude)); |
| 296 if (uri.isNull()) | 309 if (uri.isNull()) |
| 297 return nullptr; // Parse error, expected string or URI | 310 return nullptr; // Parse error, expected string or URI |
| 298 return StyleRuleImport::create(uri, MediaQueryParser::parseMediaQuerySet(pre
lude)); | 311 return StyleRuleImport::create(uri, MediaQueryParser::parseMediaQuerySet(pre
lude)); |
| 299 } | 312 } |
| 300 | 313 |
| 301 PassRefPtrWillBeRawPtr<StyleRuleNamespace> CSSParserImpl::consumeNamespaceRule(C
SSParserTokenRange prelude) | 314 PassRefPtrWillBeRawPtr<StyleRuleNamespace> CSSParserImpl::consumeNamespaceRule(C
SSParserTokenRange prelude) |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 else | 575 else |
| 563 return nullptr; // Parser error, invalid value in keyframe selector | 576 return nullptr; // Parser error, invalid value in keyframe selector |
| 564 if (range.atEnd()) | 577 if (range.atEnd()) |
| 565 return result.release(); | 578 return result.release(); |
| 566 if (range.consume().type() != CommaToken) | 579 if (range.consume().type() != CommaToken) |
| 567 return nullptr; // Parser error | 580 return nullptr; // Parser error |
| 568 } | 581 } |
| 569 } | 582 } |
| 570 | 583 |
| 571 } // namespace blink | 584 } // namespace blink |
| OLD | NEW |