| 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 "core/css/parser/CSSParserImpl.h" | 5 #include "core/css/parser/CSSParserImpl.h" |
| 6 | 6 |
| 7 #include "core/css/CSSCustomIdentValue.h" | 7 #include "core/css/CSSCustomIdentValue.h" |
| 8 #include "core/css/CSSCustomPropertyDeclaration.h" | 8 #include "core/css/CSSCustomPropertyDeclaration.h" |
| 9 #include "core/css/CSSKeyframesRule.h" | 9 #include "core/css/CSSKeyframesRule.h" |
| 10 #include "core/css/CSSStyleSheet.h" | 10 #include "core/css/CSSStyleSheet.h" |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 #include "core/frame/Deprecation.h" | 28 #include "core/frame/Deprecation.h" |
| 29 #include "core/frame/UseCounter.h" | 29 #include "core/frame/UseCounter.h" |
| 30 #include "platform/tracing/TraceEvent.h" | 30 #include "platform/tracing/TraceEvent.h" |
| 31 #include "wtf/PtrUtil.h" | 31 #include "wtf/PtrUtil.h" |
| 32 #include <bitset> | 32 #include <bitset> |
| 33 #include <memory> | 33 #include <memory> |
| 34 | 34 |
| 35 namespace blink { | 35 namespace blink { |
| 36 | 36 |
| 37 CSSParserImpl::CSSParserImpl(const CSSParserContext& context, | 37 CSSParserImpl::CSSParserImpl(const CSSParserContext& context, |
| 38 StyleSheetContents* styleSheet) | 38 StyleSheetContents* styleSheet, |
| 39 bool deferPropertyParsing) |
| 39 : m_context(context), | 40 : m_context(context), |
| 40 m_styleSheet(styleSheet), | 41 m_styleSheet(styleSheet), |
| 41 m_observerWrapper(nullptr) {} | 42 m_observerWrapper(nullptr), |
| 43 m_deferPropertyParsing(deferPropertyParsing) {} |
| 42 | 44 |
| 43 bool CSSParserImpl::parseValue(MutableStylePropertySet* declaration, | 45 bool CSSParserImpl::parseValue(MutableStylePropertySet* declaration, |
| 44 CSSPropertyID unresolvedProperty, | 46 CSSPropertyID unresolvedProperty, |
| 45 const String& string, | 47 const String& string, |
| 46 bool important, | 48 bool important, |
| 47 const CSSParserContext& context) { | 49 const CSSParserContext& context) { |
| 48 CSSParserImpl parser(context); | 50 CSSParserImpl parser(context); |
| 49 StyleRule::RuleType ruleType = StyleRule::Style; | 51 StyleRule::RuleType ruleType = StyleRule::Style; |
| 50 if (declaration->cssParserMode() == CSSViewportRuleMode) | 52 if (declaration->cssParserMode() == CSSViewportRuleMode) |
| 51 ruleType = StyleRule::Viewport; | 53 ruleType = StyleRule::Viewport; |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 if (!rule) | 187 if (!rule) |
| 186 return nullptr; // Parse error, failed to consume rule | 188 return nullptr; // Parse error, failed to consume rule |
| 187 range.consumeWhitespace(); | 189 range.consumeWhitespace(); |
| 188 if (!rule || !range.atEnd()) | 190 if (!rule || !range.atEnd()) |
| 189 return nullptr; // Parse error, trailing garbage | 191 return nullptr; // Parse error, trailing garbage |
| 190 return rule; | 192 return rule; |
| 191 } | 193 } |
| 192 | 194 |
| 193 void CSSParserImpl::parseStyleSheet(const String& string, | 195 void CSSParserImpl::parseStyleSheet(const String& string, |
| 194 const CSSParserContext& context, | 196 const CSSParserContext& context, |
| 195 StyleSheetContents* styleSheet) { | 197 StyleSheetContents* styleSheet, |
| 198 bool deferPropertyParsing) { |
| 196 TRACE_EVENT_BEGIN2("blink,blink_style", "CSSParserImpl::parseStyleSheet", | 199 TRACE_EVENT_BEGIN2("blink,blink_style", "CSSParserImpl::parseStyleSheet", |
| 197 "baseUrl", context.baseURL().getString().utf8(), "mode", | 200 "baseUrl", context.baseURL().getString().utf8(), "mode", |
| 198 context.mode()); | 201 context.mode()); |
| 199 | 202 |
| 200 TRACE_EVENT_BEGIN0("blink,blink_style", | 203 TRACE_EVENT_BEGIN0("blink,blink_style", |
| 201 "CSSParserImpl::parseStyleSheet.tokenize"); | 204 "CSSParserImpl::parseStyleSheet.tokenize"); |
| 202 CSSTokenizer::Scope scope(string); | 205 styleSheet->m_scope = CSSTokenizer::Scope(string); |
| 203 TRACE_EVENT_END0("blink,blink_style", | 206 TRACE_EVENT_END0("blink,blink_style", |
| 204 "CSSParserImpl::parseStyleSheet.tokenize"); | 207 "CSSParserImpl::parseStyleSheet.tokenize"); |
| 205 | 208 |
| 206 TRACE_EVENT_BEGIN0("blink,blink_style", | 209 TRACE_EVENT_BEGIN0("blink,blink_style", |
| 207 "CSSParserImpl::parseStyleSheet.parse"); | 210 "CSSParserImpl::parseStyleSheet.parse"); |
| 208 CSSParserImpl parser(context, styleSheet); | 211 CSSParserImpl parser(context, styleSheet, deferPropertyParsing); |
| 209 bool firstRuleValid = parser.consumeRuleList( | 212 bool firstRuleValid = parser.consumeRuleList( |
| 210 scope.tokenRange(), TopLevelRuleList, [&styleSheet](StyleRuleBase* rule) { | 213 styleSheet->m_scope.tokenRange(), TopLevelRuleList, [&styleSheet](StyleRul
eBase* rule) { |
| 211 if (rule->isCharsetRule()) | 214 if (rule->isCharsetRule()) |
| 212 return; | 215 return; |
| 213 styleSheet->parserAppendRule(rule); | 216 styleSheet->parserAppendRule(rule); |
| 214 }); | 217 }); |
| 215 styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid); | 218 styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid); |
| 219 |
| 220 // For lazy parsing the owning contents requires ownership of strings the |
| 221 // scope allocates. |
| 222 if (deferPropertyParsing) |
| 223 styleSheet->takeEscapedStrings(styleSheet->m_scope.releaseEscapedStrings()); |
| 224 |
| 216 TRACE_EVENT_END0("blink,blink_style", "CSSParserImpl::parseStyleSheet.parse"); | 225 TRACE_EVENT_END0("blink,blink_style", "CSSParserImpl::parseStyleSheet.parse"); |
| 217 | 226 |
| 218 TRACE_EVENT_END2("blink,blink_style", "CSSParserImpl::parseStyleSheet", | 227 TRACE_EVENT_END2("blink,blink_style", "CSSParserImpl::parseStyleSheet", |
| 219 "tokenCount", scope.tokenCount(), "length", string.length()); | 228 "tokenCount", styleSheet->m_scope.tokenCount(), "length", str
ing.length()); |
| 220 } | 229 } |
| 221 | 230 |
| 222 CSSSelectorList CSSParserImpl::parsePageSelector( | 231 CSSSelectorList CSSParserImpl::parsePageSelector( |
| 223 CSSParserTokenRange range, | 232 CSSParserTokenRange range, |
| 224 StyleSheetContents* styleSheet) { | 233 StyleSheetContents* styleSheet) { |
| 225 // We only support a small subset of the css-page spec. | 234 // We only support a small subset of the css-page spec. |
| 226 range.consumeWhitespace(); | 235 range.consumeWhitespace(); |
| 227 AtomicString typeSelector; | 236 AtomicString typeSelector; |
| 228 if (range.peek().type() == IdentToken) | 237 if (range.peek().type() == IdentToken) |
| 229 typeSelector = range.consume().value().toAtomicString(); | 238 typeSelector = range.consume().value().toAtomicString(); |
| (...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 758 wrapper.observer().endRuleHeader(wrapper.endOffset(originalRange)); | 767 wrapper.observer().endRuleHeader(wrapper.endOffset(originalRange)); |
| 759 } | 768 } |
| 760 | 769 |
| 761 StyleRule* CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, | 770 StyleRule* CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, |
| 762 CSSParserTokenRange block) { | 771 CSSParserTokenRange block) { |
| 763 CSSSelectorList selectorList = | 772 CSSSelectorList selectorList = |
| 764 CSSSelectorParser::parseSelector(prelude, m_context, m_styleSheet); | 773 CSSSelectorParser::parseSelector(prelude, m_context, m_styleSheet); |
| 765 if (!selectorList.isValid()) | 774 if (!selectorList.isValid()) |
| 766 return nullptr; // Parse error, invalid selector list | 775 return nullptr; // Parse error, invalid selector list |
| 767 | 776 |
| 768 if (m_observerWrapper) | 777 // TODO(csharrison): How should we lazily parse css that needs the observer? |
| 778 if (m_observerWrapper) { |
| 769 observeSelectors(*m_observerWrapper, prelude); | 779 observeSelectors(*m_observerWrapper, prelude); |
| 770 | 780 } else if (m_deferPropertyParsing && |
| 781 shouldLazilyParseProperties(selectorList)) { |
| 782 DCHECK(m_styleSheet); |
| 783 return StyleRule::createLazy( |
| 784 std::move(selectorList), |
| 785 createDeferredPropertiesClosure(block, m_styleSheet->parserContext(), |
| 786 m_context.useCounter())); |
| 787 } |
| 771 consumeDeclarationList(block, StyleRule::Style); | 788 consumeDeclarationList(block, StyleRule::Style); |
| 772 | |
| 773 return StyleRule::create( | 789 return StyleRule::create( |
| 774 std::move(selectorList), | 790 std::move(selectorList), |
| 775 createStylePropertySet(m_parsedProperties, m_context.mode())); | 791 createStylePropertySet(m_parsedProperties, m_context.mode())); |
| 776 } | 792 } |
| 777 | 793 |
| 778 void CSSParserImpl::consumeDeclarationList(CSSParserTokenRange range, | 794 void CSSParserImpl::consumeDeclarationList(CSSParserTokenRange range, |
| 779 StyleRule::RuleType ruleType) { | 795 StyleRule::RuleType ruleType) { |
| 780 ASSERT(m_parsedProperties.isEmpty()); | 796 ASSERT(m_parsedProperties.isEmpty()); |
| 781 | 797 |
| 782 bool useObserver = m_observerWrapper && (ruleType == StyleRule::Style || | 798 bool useObserver = m_observerWrapper && (ruleType == StyleRule::Style || |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 931 result->append(1); | 947 result->append(1); |
| 932 else | 948 else |
| 933 return nullptr; // Parser error, invalid value in keyframe selector | 949 return nullptr; // Parser error, invalid value in keyframe selector |
| 934 if (range.atEnd()) | 950 if (range.atEnd()) |
| 935 return result; | 951 return result; |
| 936 if (range.consume().type() != CommaToken) | 952 if (range.consume().type() != CommaToken) |
| 937 return nullptr; // Parser error | 953 return nullptr; // Parser error |
| 938 } | 954 } |
| 939 } | 955 } |
| 940 | 956 |
| 957 // The closure created here must not outlive the underlying StyleSheetContents, |
| 958 // as it has non retaining references to the strings backing the tokens, as |
| 959 // well as the parser context. |
| 960 std::unique_ptr<DeferredPropertiesClosure> |
| 961 CSSParserImpl::createDeferredPropertiesClosure( |
| 962 CSSParserTokenRange block, |
| 963 const CSSParserContext& sheetContext, |
| 964 UseCounter* counter) { |
| 965 return WTF::bind(&CSSParserImpl::parseDeclarationListForLazyStyle, block, |
| 966 WTF::unretained(&sheetContext), WTF::unretained(counter)); |
| 967 } |
| 968 |
| 969 StylePropertySet* CSSParserImpl::parseDeclarationListForLazyStyle( |
| 970 CSSParserTokenRange block, |
| 971 const CSSParserContext* sheetContext, |
| 972 UseCounter* counter) { |
| 973 CSSParserContext context(*sheetContext, counter); |
| 974 CSSParserImpl parser(context); |
| 975 parser.consumeDeclarationList(block, StyleRule::Style); |
| 976 return createStylePropertySet(parser.m_parsedProperties, context.mode()); |
| 977 } |
| 978 |
| 979 // Disallow lazy parsing for blocks which have |
| 980 // - before/after in their selector list. This ensures we don't cause a |
| 981 // collectFeatures() when we trigger parsing for attr() functions which would |
| 982 // trigger expensive invalidation propagation. |
| 983 // |
| 984 // Note: another optimization might be to disallow lazy parsing for rules which |
| 985 // will end up being empty. This is hard to know without parsing but we may be |
| 986 // able to catch the {}, { } cases. This would be to hit |
| 987 // StyleRule::shouldConsiderForMatchingRules more. |
| 988 bool CSSParserImpl::shouldLazilyParseProperties( |
| 989 const CSSSelectorList& selectors) { |
| 990 for (const auto* s = selectors.first(); s; s = CSSSelectorList::next(*s)) { |
| 991 const CSSSelector::PseudoType type(s->getPseudoType()); |
| 992 if (type == CSSSelector::PseudoBefore || type == CSSSelector::PseudoAfter) |
| 993 return false; |
| 994 } |
| 995 return true; |
| 996 } |
| 997 |
| 941 } // namespace blink | 998 } // namespace blink |
| OLD | NEW |