| 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 df4464540a3dbd3fe6230eaffad4432169308684..b2d57673d0ddc37c8af0cb2bcc3343c4a3ddecf1 100644
|
| --- a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
|
| +++ b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
|
| @@ -35,10 +35,12 @@
|
| namespace blink {
|
|
|
| CSSParserImpl::CSSParserImpl(const CSSParserContext& context,
|
| - StyleSheetContents* styleSheet)
|
| + StyleSheetContents* styleSheet,
|
| + bool deferPropertyParsing)
|
| : m_context(context),
|
| m_styleSheet(styleSheet),
|
| - m_observerWrapper(nullptr) {}
|
| + m_observerWrapper(nullptr),
|
| + m_deferPropertyParsing(deferPropertyParsing) {}
|
|
|
| bool CSSParserImpl::parseValue(MutableStylePropertySet* declaration,
|
| CSSPropertyID unresolvedProperty,
|
| @@ -192,31 +194,38 @@ StyleRuleBase* CSSParserImpl::parseRule(const String& string,
|
|
|
| void CSSParserImpl::parseStyleSheet(const String& string,
|
| const CSSParserContext& context,
|
| - StyleSheetContents* styleSheet) {
|
| + StyleSheetContents* styleSheet,
|
| + bool deferPropertyParsing) {
|
| TRACE_EVENT_BEGIN2("blink,blink_style", "CSSParserImpl::parseStyleSheet",
|
| "baseUrl", context.baseURL().getString().utf8(), "mode",
|
| context.mode());
|
|
|
| TRACE_EVENT_BEGIN0("blink,blink_style",
|
| "CSSParserImpl::parseStyleSheet.tokenize");
|
| - CSSTokenizer::Scope scope(string);
|
| + styleSheet->m_scope = CSSTokenizer::Scope(string);
|
| 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) {
|
| + styleSheet->m_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(styleSheet->m_scope.releaseEscapedStrings());
|
| +
|
| TRACE_EVENT_END0("blink,blink_style", "CSSParserImpl::parseStyleSheet.parse");
|
|
|
| TRACE_EVENT_END2("blink,blink_style", "CSSParserImpl::parseStyleSheet",
|
| - "tokenCount", scope.tokenCount(), "length", string.length());
|
| + "tokenCount", styleSheet->m_scope.tokenCount(), "length", string.length());
|
| }
|
|
|
| CSSSelectorList CSSParserImpl::parsePageSelector(
|
| @@ -765,11 +774,18 @@ StyleRule* CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude,
|
| 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)) {
|
| + 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()));
|
| @@ -938,4 +954,45 @@ std::unique_ptr<Vector<double>> CSSParserImpl::consumeKeyframeKeyList(
|
| }
|
| }
|
|
|
| +// 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) {
|
| + return WTF::bind(&CSSParserImpl::parseDeclarationListForLazyStyle, block,
|
| + WTF::unretained(&sheetContext), WTF::unretained(counter));
|
| +}
|
| +
|
| +StylePropertySet* CSSParserImpl::parseDeclarationListForLazyStyle(
|
| + CSSParserTokenRange 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.
|
| +//
|
| +// Note: another optimization might be to disallow lazy parsing for rules which
|
| +// will end up being empty. This is hard to know without parsing but we may be
|
| +// able to catch the {}, { } cases. This would be to hit
|
| +// StyleRule::shouldConsiderForMatchingRules more.
|
| +bool CSSParserImpl::shouldLazilyParseProperties(
|
| + const CSSSelectorList& selectors) {
|
| + 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
|
|
|