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..37e258ec856409a1df31f67299e15deda89dff73 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) |
| +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( |
| @@ -681,11 +688,19 @@ StyleRule* CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, CSSParse |
| 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) { |
| + DCHECK(m_styleSheet); |
| + bool forceStrict = false; |
| + StyleRule* rule = StyleRule::createLazy(std::move(selectorList), createDeferredPropertiesClosure(block, m_context, &forceStrict)); |
| + if (forceStrict) |
| + rule->properties(); |
| + return rule; |
| + } |
| consumeDeclarationList(block, StyleRule::Style); |
| - |
| return StyleRule::create(std::move(selectorList), createStylePropertySet(m_parsedProperties, m_context.mode())); |
| } |
| @@ -820,4 +835,41 @@ 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. |
| +// Sets forceStrict to true if we should bail out on lazy parsing. This occurs |
| +// for: |
| +// - attr() functions (which require invalidation set propogation) |
| +// - Empty property sets (so that emptiness can be established without forcing |
| +// a strict point in general. |
| +std::unique_ptr<CSSParser::DeferredPropertiesClosure> CSSParserImpl::createDeferredPropertiesClosure(CSSParserTokenRange block, const CSSParserContext& context, bool* forceStrict) |
| +{ |
| + // TODO(csharrison): A slightly more complex design could have the |
| + // StyleSheetContents own the tokens. This would mean we don't have to copy |
| + // them to a local vector here. |
| + size_t length = block.end() - block.begin(); |
| + std::unique_ptr<Vector<CSSParserToken>> tokens = WTF::wrapUnique(new Vector<CSSParserToken>); |
| + tokens->reserveInitialCapacity(length); |
| + while (!block.atEnd()) { |
| + const CSSParserToken& token = block.consume(); |
| + if (token.type() == CSSParserTokenType::FunctionToken && token.value() == "attr") { |
|
Timothy Loh
2016/09/26 05:18:00
I think attr is case insensitive.
Charlie Harrison
2016/09/26 22:14:45
I've moved the check to checking "before/after" in
|
| + *forceStrict = true; |
| + } |
| + tokens->append(token); |
|
Timothy Loh
2016/09/26 05:18:01
Probably nicer to use Vector::append(const U*, siz
Charlie Harrison
2016/09/26 22:14:45
Cool :) Done.
|
| + } |
| + if (tokens->isEmpty()) |
| + *forceStrict = true; |
| + |
| + return WTF::bind(&CSSParserImpl::parseDeclarationListForLazyStyle, WTF::passed(std::move(tokens)), WTF::unretained(&context)); |
| +} |
| + |
| +StylePropertySet* CSSParserImpl::parseDeclarationListForLazyStyle(std::unique_ptr<Vector<CSSParserToken>> block, const CSSParserContext* context) |
| +{ |
| + CSSParserImpl parser(*context); |
| + parser.consumeDeclarationList(*block, StyleRule::Style); |
| + return createStylePropertySet(parser.m_parsedProperties, context->mode()); |
| +} |
| + |
| + |
| } // namespace blink |