Chromium Code Reviews| 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 16 matching lines...) Expand all Loading... | |
| 27 #include "core/dom/Element.h" | 27 #include "core/dom/Element.h" |
| 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/TraceEvent.h" | 30 #include "platform/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, StyleSheetContents * styleSheet) | 37 CSSParserImpl::CSSParserImpl(const CSSParserContext& context, StyleSheetContents * styleSheet, bool deferPropertyParsing) |
| 38 : m_context(context) | 38 : m_context(context) |
| 39 , m_styleSheet(styleSheet) | 39 , m_styleSheet(styleSheet) |
| 40 , m_observerWrapper(nullptr) | 40 , m_observerWrapper(nullptr) |
| 41 , m_deferPropertyParsing(deferPropertyParsing) | |
| 41 { | 42 { |
| 42 } | 43 } |
| 43 | 44 |
| 44 bool CSSParserImpl::parseValue(MutableStylePropertySet* declaration, CSSProperty ID unresolvedProperty, const String& string, bool important, const CSSParserCont ext& context) | 45 bool CSSParserImpl::parseValue(MutableStylePropertySet* declaration, CSSProperty ID unresolvedProperty, const String& string, bool important, const CSSParserCont ext& context) |
| 45 { | 46 { |
| 46 CSSParserImpl parser(context); | 47 CSSParserImpl parser(context); |
| 47 StyleRule::RuleType ruleType = StyleRule::Style; | 48 StyleRule::RuleType ruleType = StyleRule::Style; |
| 48 if (declaration->cssParserMode() == CSSViewportRuleMode) | 49 if (declaration->cssParserMode() == CSSViewportRuleMode) |
| 49 ruleType = StyleRule::Viewport; | 50 ruleType = StyleRule::Viewport; |
| 50 CSSTokenizer::Scope scope(string); | 51 CSSTokenizer::Scope scope(string); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 152 else | 153 else |
| 153 rule = parser.consumeQualifiedRule(range, allowedRules); | 154 rule = parser.consumeQualifiedRule(range, allowedRules); |
| 154 if (!rule) | 155 if (!rule) |
| 155 return nullptr; // Parse error, failed to consume rule | 156 return nullptr; // Parse error, failed to consume rule |
| 156 range.consumeWhitespace(); | 157 range.consumeWhitespace(); |
| 157 if (!rule || !range.atEnd()) | 158 if (!rule || !range.atEnd()) |
| 158 return nullptr; // Parse error, trailing garbage | 159 return nullptr; // Parse error, trailing garbage |
| 159 return rule; | 160 return rule; |
| 160 } | 161 } |
| 161 | 162 |
| 162 void CSSParserImpl::parseStyleSheet(const String& string, const CSSParserContext & context, StyleSheetContents* styleSheet) | 163 void CSSParserImpl::parseStyleSheet(const String& string, const CSSParserContext & context, StyleSheetContents* styleSheet, bool deferPropertyParsing) |
| 163 { | 164 { |
| 164 TRACE_EVENT_BEGIN2( | 165 TRACE_EVENT_BEGIN2( |
| 165 "blink,blink_style", "CSSParserImpl::parseStyleSheet", | 166 "blink,blink_style", "CSSParserImpl::parseStyleSheet", |
| 166 "baseUrl", context.baseURL().getString().utf8(), | 167 "baseUrl", context.baseURL().getString().utf8(), |
| 167 "mode", context.mode()); | 168 "mode", context.mode()); |
| 168 | 169 |
| 169 TRACE_EVENT_BEGIN0("blink,blink_style", "CSSParserImpl::parseStyleSheet.toke nize"); | 170 TRACE_EVENT_BEGIN0("blink,blink_style", "CSSParserImpl::parseStyleSheet.toke nize"); |
| 170 CSSTokenizer::Scope scope(string); | 171 CSSTokenizer::Scope scope(string); |
| 171 TRACE_EVENT_END0("blink,blink_style", "CSSParserImpl::parseStyleSheet.tokeni ze"); | 172 TRACE_EVENT_END0("blink,blink_style", "CSSParserImpl::parseStyleSheet.tokeni ze"); |
| 172 | 173 |
| 173 TRACE_EVENT_BEGIN0("blink,blink_style", "CSSParserImpl::parseStyleSheet.pars e"); | 174 TRACE_EVENT_BEGIN0("blink,blink_style", "CSSParserImpl::parseStyleSheet.pars e"); |
| 174 CSSParserImpl parser(context, styleSheet); | 175 CSSParserImpl parser(context, styleSheet, deferPropertyParsing); |
| 175 bool firstRuleValid = parser.consumeRuleList(scope.tokenRange(), TopLevelRul eList, [&styleSheet](StyleRuleBase* rule) { | 176 bool firstRuleValid = parser.consumeRuleList(scope.tokenRange(), TopLevelRul eList, [&styleSheet](StyleRuleBase* rule) { |
| 176 if (rule->isCharsetRule()) | 177 if (rule->isCharsetRule()) |
| 177 return; | 178 return; |
| 178 styleSheet->parserAppendRule(rule); | 179 styleSheet->parserAppendRule(rule); |
| 179 }); | 180 }); |
| 180 styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid); | 181 styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid); |
| 182 | |
| 183 // For lazy parsing the owning contents requires ownership of strings the | |
| 184 // scope allocates. | |
| 185 if (deferPropertyParsing) | |
| 186 styleSheet->takeEscapedStrings(scope.releaseEscapedStrings()); | |
| 187 | |
| 181 TRACE_EVENT_END0("blink,blink_style", "CSSParserImpl::parseStyleSheet.parse" ); | 188 TRACE_EVENT_END0("blink,blink_style", "CSSParserImpl::parseStyleSheet.parse" ); |
| 182 | 189 |
| 183 TRACE_EVENT_END2( | 190 TRACE_EVENT_END2( |
| 184 "blink,blink_style", "CSSParserImpl::parseStyleSheet", | 191 "blink,blink_style", "CSSParserImpl::parseStyleSheet", |
| 185 "tokenCount", scope.tokenCount(), | 192 "tokenCount", scope.tokenCount(), |
| 186 "length", string.length()); | 193 "length", string.length()); |
| 187 } | 194 } |
| 188 | 195 |
| 189 CSSSelectorList CSSParserImpl::parsePageSelector(CSSParserTokenRange range, Styl eSheetContents* styleSheet) | 196 CSSSelectorList CSSParserImpl::parsePageSelector(CSSParserTokenRange range, Styl eSheetContents* styleSheet) |
| 190 { | 197 { |
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 667 selectors.consumeComponentValue(); | 674 selectors.consumeComponentValue(); |
| 668 CSSParserTokenRange selector = selectors.makeSubRange(selectorStart, &se lectors.peek()); | 675 CSSParserTokenRange selector = selectors.makeSubRange(selectorStart, &se lectors.peek()); |
| 669 selectors.consumeIncludingWhitespace(); | 676 selectors.consumeIncludingWhitespace(); |
| 670 | 677 |
| 671 wrapper.observer().observeSelector(wrapper.startOffset(selector), wrappe r.endOffset(selector)); | 678 wrapper.observer().observeSelector(wrapper.startOffset(selector), wrappe r.endOffset(selector)); |
| 672 } | 679 } |
| 673 | 680 |
| 674 wrapper.observer().endRuleHeader(wrapper.endOffset(originalRange)); | 681 wrapper.observer().endRuleHeader(wrapper.endOffset(originalRange)); |
| 675 } | 682 } |
| 676 | 683 |
| 677 | |
| 678 StyleRule* CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, CSSParse rTokenRange block) | 684 StyleRule* CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, CSSParse rTokenRange block) |
| 679 { | 685 { |
| 680 CSSSelectorList selectorList = CSSSelectorParser::parseSelector(prelude, m_c ontext, m_styleSheet); | 686 CSSSelectorList selectorList = CSSSelectorParser::parseSelector(prelude, m_c ontext, m_styleSheet); |
| 681 if (!selectorList.isValid()) | 687 if (!selectorList.isValid()) |
| 682 return nullptr; // Parse error, invalid selector list | 688 return nullptr; // Parse error, invalid selector list |
| 683 | 689 |
| 684 if (m_observerWrapper) | 690 // TODO(csharrison): How should we lazily parse css that needs the observer? |
| 691 if (m_observerWrapper) { | |
| 685 observeSelectors(*m_observerWrapper, prelude); | 692 observeSelectors(*m_observerWrapper, prelude); |
| 686 | 693 } else if (m_deferPropertyParsing && shouldLazilyParseProperties(selectorLis t, block)) { |
| 694 DCHECK(m_styleSheet); | |
| 695 return StyleRule::createLazy(std::move(selectorList), createDeferredProp ertiesClosure(block, m_styleSheet->parserContext(), m_context.useCounter())); | |
| 696 } | |
| 687 consumeDeclarationList(block, StyleRule::Style); | 697 consumeDeclarationList(block, StyleRule::Style); |
| 688 | |
| 689 return StyleRule::create(std::move(selectorList), createStylePropertySet(m_p arsedProperties, m_context.mode())); | 698 return StyleRule::create(std::move(selectorList), createStylePropertySet(m_p arsedProperties, m_context.mode())); |
| 690 } | 699 } |
| 691 | 700 |
| 692 void CSSParserImpl::consumeDeclarationList(CSSParserTokenRange range, StyleRule: :RuleType ruleType) | 701 void CSSParserImpl::consumeDeclarationList(CSSParserTokenRange range, StyleRule: :RuleType ruleType) |
| 693 { | 702 { |
| 694 ASSERT(m_parsedProperties.isEmpty()); | 703 ASSERT(m_parsedProperties.isEmpty()); |
| 695 | 704 |
| 696 bool useObserver = m_observerWrapper && (ruleType == StyleRule::Style || rul eType == StyleRule::Keyframe); | 705 bool useObserver = m_observerWrapper && (ruleType == StyleRule::Style || rul eType == StyleRule::Keyframe); |
| 697 if (useObserver) { | 706 if (useObserver) { |
| 698 m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousT okenStartOffset(range)); | 707 m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousT okenStartOffset(range)); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 813 result->append(1); | 822 result->append(1); |
| 814 else | 823 else |
| 815 return nullptr; // Parser error, invalid value in keyframe selector | 824 return nullptr; // Parser error, invalid value in keyframe selector |
| 816 if (range.atEnd()) | 825 if (range.atEnd()) |
| 817 return result; | 826 return result; |
| 818 if (range.consume().type() != CommaToken) | 827 if (range.consume().type() != CommaToken) |
| 819 return nullptr; // Parser error | 828 return nullptr; // Parser error |
| 820 } | 829 } |
| 821 } | 830 } |
| 822 | 831 |
| 832 // The closure created here must not outlive the underlying StyleSheetContents, | |
| 833 // as it has non retaining references to the strings backing the tokens, as | |
| 834 // well as the parser context. | |
| 835 std::unique_ptr<DeferredPropertiesClosure> CSSParserImpl::createDeferredProperti esClosure(CSSParserTokenRange block, const CSSParserContext& sheetContext, UseCo unter* counter) | |
| 836 { | |
| 837 // Note: there may be optimizations to be had in allocating so many Vectors | |
| 838 // to store the token copies. One idea is to allocate a large Vector in | |
| 839 // parseStyleSheet and immediately free it, so we don't go through the slow | |
| 840 // path in PartitionAlloc. | |
| 841 Vector<CSSParserToken, 0u> tokens; | |
| 842 | |
| 843 // Reserve capacity to minimize heap bloat. | |
| 844 size_t length = block.end() - block.begin(); | |
| 845 tokens.reserveCapacity(length); | |
| 846 tokens.append(block.begin(), length); | |
| 847 | |
| 848 return WTF::bind(&CSSParserImpl::parseDeclarationListForLazyStyle, WTF::pass ed(std::move(tokens)), WTF::unretained(&sheetContext), WTF::unretained(counter)) ; | |
| 849 } | |
| 850 | |
| 851 StylePropertySet* CSSParserImpl::parseDeclarationListForLazyStyle(Vector<CSSPars erToken> block, const CSSParserContext* sheetContext, UseCounter* counter) | |
| 852 { | |
| 853 CSSParserContext context(*sheetContext, counter); | |
| 854 CSSParserImpl parser(context); | |
| 855 parser.consumeDeclarationList(block, StyleRule::Style); | |
| 856 return createStylePropertySet(parser.m_parsedProperties, context.mode()); | |
| 857 } | |
| 858 | |
| 859 // Disallow lazy parsing for blocks which have | |
| 860 // - before/after in their selector list. This ensures we don't cause a | |
| 861 // collectFeatures() when we trigger parsing for attr() functions which would | |
| 862 // trigger expensive invalidation propagation. | |
| 863 // - Empty property sets (so that emptiness can be established without forcing | |
| 864 // a strict point. | |
| 865 bool CSSParserImpl::shouldLazilyParseProperties(const CSSSelectorList& selectors , CSSParserTokenRange block) | |
|
Timothy Loh
2016/09/27 05:15:45
Could just be static and not on CSSParserImpl I gu
Charlie Harrison
2016/09/27 13:22:01
Do you mean in an anonymous namespace? It's alread
| |
| 866 { | |
| 867 if (static_cast<size_t>(block.end() - block.begin()) == 0) | |
|
Timothy Loh
2016/09/27 05:15:45
if (block.atEnd()), but see other comment.
Charlie Harrison
2016/09/27 13:22:01
Deleted this code.
| |
| 868 return false; | |
| 869 for (const auto* s = selectors.first(); s; s = CSSSelectorList::next(*s)) { | |
| 870 const CSSSelector::PseudoType type(s->getPseudoType()); | |
| 871 if (type == CSSSelector::PseudoBefore || type == CSSSelector::PseudoAfte r) | |
| 872 return false; | |
| 873 } | |
| 874 return true; | |
| 875 } | |
| 876 | |
| 823 } // namespace blink | 877 } // namespace blink |
| OLD | NEW |