[CSS Parser] Implement deferred parsing of properties, @media, @supports and @keyframes
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Dec 2016 21:02:07 +0000 (21:02 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Dec 2016 21:02:07 +0000 (21:02 +0000)
commitf3d4f400fbf678e12a480913893785fb41b256db
tree28a7ec6ab6cdc4aefab9599aa2b3b45b9463af11
parentd9ef87e57f5e42deec027a547e9483b945af62b2
[CSS Parser] Implement deferred parsing of properties, @media, @supports and @keyframes
https://bugs.webkit.org/show_bug.cgi?id=165743

Reviewed by Dean Jackson.

Source/WebCore:

Added new tests in fast/css/deferred-parsing.

This patch implements deferred parsing in CSS. By default, when parsing
author stylesheets, the parser goes into a deferred mode where it leaves
the declaration block of all style rules unparsed initially. Instead of
creating and setting an ImmutableStyleProperties object on the StyleRule,
the parser creates a DeferredStyleProperties object instead that is
capable of calling into CSSDeferredParser to parse the properties and values
only when the properties are finally asked for.

In addition, this patch defers the parsing of the interior of @media,
@supports, and @keyframes rules. @media blocks that are never matched will
never parse any of the rules inside. @supports conditions for unsupported
features will also not be parsed. For @keyframes, if the animation is never
referenced/used, then the @keyframes child rules will never be parsed.

* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:
Add CSSDeferredParser to the build.

* css/CSSFontFaceSet.cpp:
(WebCore::CSSFontFaceSet::matchingFaces):
Patched to drop the StyleSheetContents* argument from parseValue, since it
is no longer needed.

* css/CSSKeyframesRule.cpp:
(WebCore::StyleRuleKeyframes::StyleRuleKeyframes):
(WebCore::StyleRuleKeyframes::parseDeferredRulesIfNeeded):
(WebCore::StyleRuleKeyframes::keyframes):
(WebCore::StyleRuleKeyframes::wrapperAppendKeyframe):
(WebCore::StyleRuleKeyframes::wrapperRemoveKeyframe):
(WebCore::StyleRuleKeyframes::findKeyframeIndex):
* css/CSSKeyframesRule.h:
Keyframes now hold both a keyframes Vector and a DeferredStyleGroupRuleList
object. The keyframes vector won't be populated until it is needed, and the
population is done by DeferredStyleGroupRuleList, which holds both the original
tokens of the keyframes rule interior, and a references to the
CSSDeferredParser that will do the parsing.

* css/DOMCSSNamespace.cpp:
(WebCore::DOMCSSNamespace::supports):
Patched to drop the StyleSheetContents* argument from parseValue, since it
is no longer needed.

* css/ElementRuleCollector.cpp:
(WebCore::ElementRuleCollector::collectMatchingRulesForList):
ElementRuleCollector tests to see if a rule is empty by counting properties(),
but we don't want to initiate deferred parsing just to check this. Instead we
invoke propertiesWithoutDeferredParsing, which will hand back a nullptr if
the properties haven't been parsed yet. In order to ensure this optimization
continues to work, any rules whose interiors consist of only whitespace do
not get deferred.

* css/FontFace.cpp:
(WebCore::FontFace::setVariant):
* css/PropertySetCSSStyleDeclaration.cpp:
(WebCore::PropertySetCSSStyleDeclaration::setProperty):
(WebCore::PropertySetCSSStyleDeclaration::setPropertyInternal):
Patched to drop the StyleSheetContents* argument from parseValue, since it
is no longer needed.

* css/StyleProperties.cpp:
(WebCore::MutableStyleProperties::MutableStyleProperties):
(WebCore::MutableStyleProperties::setProperty):
(WebCore::DeferredStyleProperties::create):
(WebCore::DeferredStyleProperties::DeferredStyleProperties):
(WebCore::DeferredStyleProperties::~DeferredStyleProperties):
(WebCore::DeferredStyleProperties::parseDeferredProperties):
* css/StyleProperties.h:
(WebCore::StylePropertiesBase::type):
(WebCore::StylePropertiesBase::cssParserMode):
(WebCore::StylePropertiesBase::StylePropertiesBase):
(WebCore::StyleProperties::isMutable):
(WebCore::StyleProperties::StyleProperties):
(WebCore::StylePropertiesBase::deref):
(isType):
(WebCore::StyleProperties::cssParserMode): Deleted.
(WebCore::StyleProperties::deref): Deleted.
Right now StyleProperties has two subclasses, ImmutableStyleProperties (which
is created by the parser when not deferring), and MutableStyleProperties (used
when making changes and doing DOM Manipulations).

This patch adds a new base class called StylePropertiesBase, and StyleProperties
now derives from it. DeferredStyleProperties derives from this base. The members
of StyleProperties have been moved up into StylePropertiesBase.

The m_isMutable bit, used to determine the type for downcasting has been enhanced
to m_type (2 bits), since there are now three possible subclasses.

* css/StyleRule.cpp:
(WebCore::StyleRule::StyleRule):
(WebCore::StyleRule::properties):
(WebCore::StyleRule::mutableProperties):
(WebCore::StyleRule::splitIntoMultipleRulesWithMaximumSelectorComponentCount):
Patched to ensure that when properties() are accessed, that if the current
stored StylePropertyBase in the rule is a DeferredStyleProperties, we then
parse and replace DeferredStyleProperties with ImmutableStyleProperties on the
rule. By using a common base class, we avoid increasing memory usage in
StyleRule.

(WebCore::DeferredStyleGroupRuleList::create):
(WebCore::DeferredStyleGroupRuleList::DeferredStyleGroupRuleList):
(WebCore::DeferredStyleGroupRuleList::parseDeferredRules):
(WebCore::DeferredStyleGroupRuleList::parseDeferredKeyframes):
DeferredStyleGroupList is used to handle deferred parsing of objects with
child rules. These include @media, @supports and @keyframes.

(WebCore::StyleRuleGroup::StyleRuleGroup):
(WebCore::StyleRuleGroup::childRules):
(WebCore::StyleRuleGroup::wrapperInsertRule):
(WebCore::StyleRuleGroup::wrapperRemoveRule):
(WebCore::StyleRuleGroup::parseDeferredRulesIfNeeded):
(WebCore::StyleRuleMedia::StyleRuleMedia):
(WebCore::StyleRuleSupports::StyleRuleSupports):
StyleRuleGroup now holds both a child rules Vector and a
DeferredStyleGroupRuleList. If DeferredStyleGroupRuleList is set, then
when the childRules are finally accessed, we will populate the childRules
Vector and then null out the DeferredStyleGroupRuleList.

* css/StyleRule.h:
(WebCore::StyleRule::propertiesWithoutDeferredParsing):
(WebCore::StyleRuleGroup::childRulesWithoutDeferredParsing):
(WebCore::StyleRuleGroup::childRules): Deleted.
Add new accesors for fetching properties and child rules without causing
deferred parsing to happen.

* css/StyleSheetContents.cpp:
(WebCore::StyleSheetContents::parseAuthorStyleSheet):
(WebCore::StyleSheetContents::parseString):
Patched to turn on deferred parsing for author sheets and for all
non-UA stylesheets parsed from a string (e.g., <style>).

(WebCore::traverseSubresourcesInRules):
The broken resource check was aggressively accessing properties(). Patch
it to call propertiesWithoutDeferredParsing() instead so that it doesn't
defeat the new optimization.

* css/WebKitCSSMatrix.cpp:
(WebCore::WebKitCSSMatrix::setMatrixValue):
Patched to drop the StyleSheetContents* argument from parseValue, since it
is no longer needed.

* css/parser/CSSDeferredParser.cpp: Added.
(WebCore::CSSDeferredParser::CSSDeferredParser):
(WebCore::CSSDeferredParser::parseDeclaration):
(WebCore::CSSDeferredParser::parseRuleList):
(WebCore::CSSDeferredParser::parseKeyframeList):
* css/parser/CSSDeferredParser.h: Added.
(WebCore::CSSDeferredParser::create):
(WebCore::CSSDeferredParser::tokenizer):
(WebCore::CSSDeferredParser::mode):
(WebCore::CSSDeferredParser::context):
(WebCore::CSSDeferredParser::styleSheet):
The CSSDeferredParser. It caches the original tokenizer's' escaped strings. Because
the CSSDeferredParser is referenced by all the rules that have yet to parse,
it will stay alive until all rules in the stylesheet has been fully parsed.

The parser receives CSSParserTokenRanges from DeferredStyleProperties or
DeferredStyleGroupRuleList and feeds them to CSSParserImpl, which then
is able to do the parsing as it would have occurred originally had the
range not been deferred.

* css/parser/CSSParser.cpp:
(WebCore::CSSParser::parseSheet):
(WebCore::CSSParser::parseSupportsCondition):
(WebCore::CSSParser::parseSingleValue):
(WebCore::CSSParser::parseValue):
* css/parser/CSSParser.h:
* css/parser/CSSParserFastPaths.cpp:
(WebCore::CSSParserFastPaths::isValidKeywordPropertyAndValue):
(WebCore::parseKeywordValue):
(WebCore::CSSParserFastPaths::maybeParseValue):
* css/parser/CSSParserFastPaths.h:
Drop the StyleSheetContents* argument from the methods that no longer need
them.

* css/parser/CSSParserImpl.cpp:
(WebCore::CSSParserImpl::CSSParserImpl):
(WebCore::CSSParserImpl::tokenizer):
(WebCore::CSSParserImpl::parseValue):
(WebCore::CSSParserImpl::parseCustomPropertyValue):
(WebCore::CSSParserImpl::parseDeclarationList):
(WebCore::CSSParserImpl::parseInlineStyleDeclaration):
(WebCore::CSSParserImpl::parseRule):
(WebCore::CSSParserImpl::parseStyleSheet):
(WebCore::CSSParserImpl::parseDeclarationListForInspector):
(WebCore::CSSParserImpl::parseStyleSheetForInspector):
(WebCore::CSSParserImpl::consumeQualifiedRule):
(WebCore::CSSParserImpl::consumeMediaRule):
(WebCore::CSSParserImpl::consumeSupportsRule):
(WebCore::CSSParserImpl::consumeKeyframesRule):
(WebCore::CSSParserImpl::consumeStyleRule):
Drop the StyleSheetContents* argument from the methods that no longer need
them.

(WebCore::CSSParserImpl::createDeferredStyleProperties):
(WebCore::CSSParserImpl::parseDeferredDeclaration):
(WebCore::CSSParserImpl::parseDeferredRuleList):
(WebCore::CSSParserImpl::parseDeferredKeyframeList):
The methods that handle deferred parsing. They make sure to initialize
new CSSParserImpls with the original deferred parser, and then call existing
methods to do the parsing.

* css/parser/CSSParserImpl.h:
Patched to remove StyleSheetContents* arguments from some methods and
to add the new deferred parsing methods.

* css/parser/CSSParserTokenRange.cpp:
(WebCore::CSSParserTokenRange::consumeBlockCheckingForEditability):
* css/parser/CSSParserTokenRange.h:
In order to preserve the editability optimization from r180867, when
a style rule's block is consumed, we use a special method that looks
for -webkit-user-modify tokens. If one is seen, then the editability
optimization is turned off. Because we do this at the token level,
the optimization keeps working even if properties don't get parsed.

* css/parser/CSSPropertyParser.cpp:
(WebCore::CSSPropertyParser::parseSingleValue):
(WebCore::CSSPropertyParser::parseFontFaceDescriptor):
(WebCore::CSSPropertyParser::consumeFont):
(WebCore::CSSPropertyParser::parseShorthand):
Patched to remove StyleSheetContents* arguments now that the editability
check is in CSSTokenizer instead.

* css/parser/CSSTokenizer.cpp:
(WebCore::CSSTokenizer::tokenRange):
* css/parser/CSSTokenizer.h:
Make tokenRange() const.

* html/canvas/CanvasRenderingContext2D.cpp:
(WebCore::CanvasRenderingContext2D::setFont):
Patched to drop the StyleSheetContents* argument.

* testing/Internals.cpp:
(WebCore::deferredStyleRulesCountForList):
(WebCore::Internals::deferredStyleRulesCount):
(WebCore::deferredGroupRulesCountForList):
(WebCore::Internals::deferredGroupRulesCount):
(WebCore::deferredKeyframesRulesCountForList):
(WebCore::Internals::deferredKeyframesRulesCount):
* testing/Internals.h:
* testing/Internals.idl:
Add new testing methods that can count the deferred style rules and
group child rule lists. These methods are used by the new layout tests.

Source/WebKit2:

Repurpose the newCSSParserEnabled preference for deferred parsing. Just change the name
from "new" to "deferred."

* Shared/WebPreferencesDefinitions.h:
* UIProcess/API/C/WKPreferences.cpp:
(WKPreferencesSetDeferredCSSParserEnabled):
(WKPreferencesGetDeferredCSSParserEnabled):
(WKPreferencesSetNewCSSParserEnabled): Deleted.
(WKPreferencesGetNewCSSParserEnabled): Deleted.
* UIProcess/API/C/WKPreferencesRefPrivate.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::updatePreferences):

LayoutTests:

* fast/css/deferred-parsing: Added.
* fast/css/deferred-parsing/dynamic-external-style-expected.txt: Added.
* fast/css/deferred-parsing/dynamic-external-style.html: Added.
* fast/css/deferred-parsing/dynamic-style-in-document-expected.txt: Added.
* fast/css/deferred-parsing/dynamic-style-in-document.html: Added.
* fast/css/deferred-parsing/hover-test-expected.txt: Added.
* fast/css/deferred-parsing/hover-test.html: Added.
* fast/css/deferred-parsing/keyframes-rule-expected.txt: Added.
* fast/css/deferred-parsing/keyframes-rule.html: Added.
* fast/css/deferred-parsing/media-print-expected.txt: Added.
* fast/css/deferred-parsing/media-print.html: Added.
* fast/css/deferred-parsing/nth-of-type-expected.txt: Added.
* fast/css/deferred-parsing/nth-of-type.html: Added.
* fast/css/deferred-parsing/resources: Added.
* fast/css/deferred-parsing/resources/basic-sheet.css: Added.
* fast/css/deferred-parsing/simple-external-style-expected.txt: Added.
* fast/css/deferred-parsing/simple-external-style.html: Added.
* fast/css/deferred-parsing/simple-style-in-document-expected.txt: Added.
* fast/css/deferred-parsing/simple-style-in-document.html: Added.
* fast/css/deferred-parsing/supports-rule-expected.txt: Added.
* fast/css/deferred-parsing/supports-rule.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@209826 268f45cc-cd09-0410-ab3c-d52691b4dbfc
67 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css/deferred-parsing/dynamic-external-style-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/dynamic-external-style.html [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/dynamic-style-in-document-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/dynamic-style-in-document.html [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/hover-test-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/hover-test.html [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/keyframes-rule-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/keyframes-rule.html [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/media-print-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/media-print.html [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/nth-of-type-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/nth-of-type.html [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/resources/basic-sheet.css [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/simple-external-style-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/simple-external-style.html [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/simple-style-in-document-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/simple-style-in-document.html [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/supports-rule-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/deferred-parsing/supports-rule.html [new file with mode: 0644]
LayoutTests/platform/ios-simulator-wk1/TestExpectations
LayoutTests/platform/ios-simulator-wk2/TestExpectations
LayoutTests/platform/ios-simulator/TestExpectations
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/CSSFontFaceSet.cpp
Source/WebCore/css/CSSKeyframesRule.cpp
Source/WebCore/css/CSSKeyframesRule.h
Source/WebCore/css/DOMCSSNamespace.cpp
Source/WebCore/css/ElementRuleCollector.cpp
Source/WebCore/css/FontFace.cpp
Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp
Source/WebCore/css/StyleProperties.cpp
Source/WebCore/css/StyleProperties.h
Source/WebCore/css/StyleRule.cpp
Source/WebCore/css/StyleRule.h
Source/WebCore/css/StyleSheetContents.cpp
Source/WebCore/css/StyleSheetContents.h
Source/WebCore/css/WebKitCSSMatrix.cpp
Source/WebCore/css/parser/CSSDeferredParser.cpp [new file with mode: 0644]
Source/WebCore/css/parser/CSSDeferredParser.h [new file with mode: 0644]
Source/WebCore/css/parser/CSSParser.cpp
Source/WebCore/css/parser/CSSParser.h
Source/WebCore/css/parser/CSSParserFastPaths.cpp
Source/WebCore/css/parser/CSSParserFastPaths.h
Source/WebCore/css/parser/CSSParserImpl.cpp
Source/WebCore/css/parser/CSSParserImpl.h
Source/WebCore/css/parser/CSSParserMode.h
Source/WebCore/css/parser/CSSParserTokenRange.cpp
Source/WebCore/css/parser/CSSParserTokenRange.h
Source/WebCore/css/parser/CSSPropertyParser.cpp
Source/WebCore/css/parser/CSSTokenizer.cpp
Source/WebCore/css/parser/CSSTokenizer.h
Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp
Source/WebCore/page/Settings.in
Source/WebCore/testing/InternalSettings.cpp
Source/WebCore/testing/InternalSettings.h
Source/WebCore/testing/InternalSettings.idl
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/WebPreferencesDefinitions.h
Source/WebKit2/UIProcess/API/C/WKPreferences.cpp
Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h
Source/WebKit2/WebProcess/WebPage/WebPage.cpp