Chromium Code Reviews| Index: third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp |
| diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp |
| index f5bd2e8b8f5f2e1f04e700fea4bbf5833d8ffc5c..42262eb30a6bed4ec3cddd330083f3d09c9c1328 100644 |
| --- a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp |
| +++ b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp |
| @@ -34,10 +34,11 @@ |
| namespace blink { |
| -CSSParserImpl::CSSParserImpl(const CSSParserContext& context, StyleSheetContents* styleSheet) |
| -: m_context(context) |
| -, m_styleSheet(styleSheet) |
| -, m_observerWrapper(nullptr) |
| +CSSParserImpl::CSSParserImpl(const CSSParserContext& context, StyleSheetContents* styleSheet, bool deferPropertyParsing) |
| + : m_context(context) |
| + , m_styleSheet(styleSheet) |
| + , m_observerWrapper(nullptr) |
| + , m_deferPropertyParsing(deferPropertyParsing) |
| { |
| } |
| @@ -159,7 +160,7 @@ StyleRuleBase* CSSParserImpl::parseRule(const String& string, const CSSParserCon |
| return rule; |
| } |
| -void CSSParserImpl::parseStyleSheet(const String& string, const CSSParserContext& context, StyleSheetContents* styleSheet) |
| +void CSSParserImpl::parseStyleSheet(const String& string, const CSSParserContext& context, StyleSheetContents* styleSheet, bool deferPropertyParsing) |
| { |
| TRACE_EVENT_BEGIN2( |
| "blink,blink_style", "CSSParserImpl::parseStyleSheet", |
| @@ -171,13 +172,19 @@ void CSSParserImpl::parseStyleSheet(const String& string, const CSSParserContext |
| TRACE_EVENT_END0("blink,blink_style", "CSSParserImpl::parseStyleSheet.tokenize"); |
| TRACE_EVENT_BEGIN0("blink,blink_style", "CSSParserImpl::parseStyleSheet.parse"); |
| - CSSParserImpl parser(context, styleSheet); |
| + CSSParserImpl parser(context, styleSheet, deferPropertyParsing); |
| bool firstRuleValid = parser.consumeRuleList(scope.tokenRange(), TopLevelRuleList, [&styleSheet](StyleRuleBase* rule) { |
| if (rule->isCharsetRule()) |
| return; |
| styleSheet->parserAppendRule(rule); |
| }); |
| styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid); |
| + |
| + // For lazy parsing the owning contents requires ownership of strings the |
| + // scope allocates. |
| + if (deferPropertyParsing) |
| + styleSheet->takeEscapedStrings(scope.releaseEscapedStrings()); |
| + |
| TRACE_EVENT_END0("blink,blink_style", "CSSParserImpl::parseStyleSheet.parse"); |
| TRACE_EVENT_END2( |
| @@ -674,18 +681,20 @@ static void observeSelectors(CSSParserObserverWrapper& wrapper, CSSParserTokenRa |
| wrapper.observer().endRuleHeader(wrapper.endOffset(originalRange)); |
| } |
| - |
| StyleRule* CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block) |
| { |
| CSSSelectorList selectorList = CSSSelectorParser::parseSelector(prelude, m_context, m_styleSheet); |
| if (!selectorList.isValid()) |
| return nullptr; // Parse error, invalid selector list |
| - if (m_observerWrapper) |
| + // TODO(csharrison): How should we lazily parse css that needs the observer? |
| + if (m_observerWrapper) { |
| observeSelectors(*m_observerWrapper, prelude); |
| - |
| + } else if (m_deferPropertyParsing && shouldLazilyParseProperties(selectorList, block)) { |
| + DCHECK(m_styleSheet); |
| + return StyleRule::createLazy(std::move(selectorList), createDeferredPropertiesClosure(block, m_styleSheet->parserContext(), m_context.useCounter())); |
| + } |
| consumeDeclarationList(block, StyleRule::Style); |
| - |
| return StyleRule::create(std::move(selectorList), createStylePropertySet(m_parsedProperties, m_context.mode())); |
| } |
| @@ -820,4 +829,49 @@ std::unique_ptr<Vector<double>> CSSParserImpl::consumeKeyframeKeyList(CSSParserT |
| } |
| } |
| +// The closure created here must not outlive the underlying StyleSheetContents, |
| +// as it has non retaining references to the strings backing the tokens, as |
| +// well as the parser context. |
| +std::unique_ptr<DeferredPropertiesClosure> CSSParserImpl::createDeferredPropertiesClosure(CSSParserTokenRange block, const CSSParserContext& sheetContext, UseCounter* counter) |
| +{ |
| + // Note: there may be optimizations to be had in allocating so many Vectors |
| + // to store the token copies. One idea is to allocate a large Vector in |
| + // parseStyleSheet and immediately free it, so we don't go through the slow |
| + // path in PartitionAlloc. |
| + Vector<CSSParserToken, 0u> tokens; |
| + |
| + // Reserve capacity to minimize heap bloat. |
| + size_t length = block.end() - block.begin(); |
| + tokens.reserveCapacity(length); |
| + tokens.append(block.begin(), length); |
| + |
| + return WTF::bind(&CSSParserImpl::parseDeclarationListForLazyStyle, WTF::passed(std::move(tokens)), WTF::unretained(&sheetContext), WTF::unretained(counter)); |
| +} |
| + |
| +StylePropertySet* CSSParserImpl::parseDeclarationListForLazyStyle(Vector<CSSParserToken> block, const CSSParserContext* sheetContext, UseCounter* counter) |
| +{ |
| + CSSParserContext context(*sheetContext, counter); |
| + CSSParserImpl parser(context); |
| + parser.consumeDeclarationList(block, StyleRule::Style); |
| + return createStylePropertySet(parser.m_parsedProperties, context.mode()); |
| +} |
| + |
| +// Disallow lazy parsing for blocks which have |
| +// - before/after in their selector list. This ensures we don't cause a |
| +// collectFeatures() when we trigger parsing for attr() functions which would |
| +// trigger expensive invalidation propagation. |
| +// - Empty property sets (so that emptiness can be established without forcing |
| +// a strict point. |
| +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
|
| +{ |
| + 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.
|
| + return false; |
| + for (const auto* s = selectors.first(); s; s = CSSSelectorList::next(*s)) { |
| + const CSSSelector::PseudoType type(s->getPseudoType()); |
| + if (type == CSSSelector::PseudoBefore || type == CSSSelector::PseudoAfter) |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| } // namespace blink |