<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[205103] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/205103">205103</a></dd>
<dt>Author</dt> <dd>hyatt@apple.com</dd>
<dt>Date</dt> <dd>2016-08-28 08:46:11 -0700 (Sun, 28 Aug 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Initial landing of CSS Parser Tokenization (and files to support that). Not used yet.
https://bugs.webkit.org/show_bug.cgi?id=161174

This code is imported from Blink and is their CSS parser (modified to work in WebKit).
It is from commit e4bb90df7f2ed8a63975b5ed27a1b488cb9b146f, Mon Aug 22 2016.

Reviewed by Simon Fraser.

* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:
* css/CSSMarkup.cpp: Added.
(WebCore::isCSSTokenizerIdentifier):
(WebCore::serializeCharacter):
(WebCore::serializeCharacterAsCodePoint):
(WebCore::serializeIdentifier):
(WebCore::serializeString):
(WebCore::serializeURI):
(WebCore::serializeFontFamily):
* css/CSSMarkup.h: Added.
* css/CSSOMUtils.cpp: Removed.
* css/CSSOMUtils.h: Removed.
* css/CSSSelector.cpp:
* css/parser/CSSParserFastPaths.cpp: Added.
* css/parser/CSSParserFastPaths.h: Added.
* css/parser/CSSParserIdioms.h: Added.
(WebCore::isCSSSpace):
(WebCore::isNameStartCodePoint):
(WebCore::isNameCodePoint):
* css/parser/CSSParserObserver.h: Added.
(WebCore::CSSParserObserver::~CSSParserObserver):
* css/parser/CSSParserObserverWrapper.cpp: Added.
(WebCore::CSSParserObserverWrapper::startOffset):
(WebCore::CSSParserObserverWrapper::previousTokenStartOffset):
(WebCore::CSSParserObserverWrapper::endOffset):
(WebCore::CSSParserObserverWrapper::skipCommentsBefore):
(WebCore::CSSParserObserverWrapper::yieldCommentsBefore):
* css/parser/CSSParserObserverWrapper.h: Added.
(WebCore::CSSParserObserverWrapper::CSSParserObserverWrapper):
(WebCore::CSSParserObserverWrapper::observer):
(WebCore::CSSParserObserverWrapper::addComment):
(WebCore::CSSParserObserverWrapper::addToken):
(WebCore::CSSParserObserverWrapper::finalizeConstruction):
* css/parser/CSSParserToken.cpp: Added.
(WebCore::cssPrimitiveValueUnitFromTrie):
(WebCore::stringToUnitType):
(WebCore::CSSParserToken::CSSParserToken):
(WebCore::CSSParserToken::convertToDimensionWithUnit):
(WebCore::CSSParserToken::convertToPercentage):
(WebCore::CSSParserToken::delimiter):
(WebCore::CSSParserToken::numericSign):
(WebCore::CSSParserToken::numericValueType):
(WebCore::CSSParserToken::numericValue):
(WebCore::CSSParserToken::parseAsUnresolvedCSSPropertyID):
(WebCore::CSSParserToken::id):
(WebCore::CSSParserToken::functionId):
(WebCore::CSSParserToken::hasStringBacking):
(WebCore::CSSParserToken::copyWithUpdatedString):
(WebCore::CSSParserToken::valueDataCharRawEqual):
(WebCore::CSSParserToken::operator==):
(WebCore::CSSParserToken::serialize):
* css/parser/CSSParserToken.h: Added.
(WebCore::CSSParserToken::operator!=):
(WebCore::CSSParserToken::type):
(WebCore::CSSParserToken::value):
(WebCore::CSSParserToken::getHashTokenType):
(WebCore::CSSParserToken::getBlockType):
(WebCore::CSSParserToken::unitType):
(WebCore::CSSParserToken::unicodeRangeStart):
(WebCore::CSSParserToken::unicodeRangeEnd):
(WebCore::CSSParserToken::initValueFromStringView):
* css/parser/CSSParserTokenRange.cpp: Added.
(WebCore::CSSParserTokenRange::eofToken):
(WebCore::CSSParserTokenRange::makeSubRange):
(WebCore::CSSParserTokenRange::consumeBlock):
(WebCore::CSSParserTokenRange::consumeComponentValue):
(WebCore::CSSParserTokenRange::serialize):
* css/parser/CSSParserTokenRange.h: Added.
(WebCore::CSSParserTokenRange::CSSParserTokenRange):
(WebCore::CSSParserTokenRange::atEnd):
(WebCore::CSSParserTokenRange::end):
(WebCore::CSSParserTokenRange::peek):
(WebCore::CSSParserTokenRange::consume):
(WebCore::CSSParserTokenRange::consumeIncludingWhitespace):
(WebCore::CSSParserTokenRange::consumeWhitespace):
(WebCore::CSSParserTokenRange::begin):
* css/parser/CSSPropertyParser.cpp: Added.
(WebCore::hasPrefix):
(WebCore::cssPropertyID):
(WebCore::cssPropertyNameIOSAliasing):
(WebCore::isAppleLegacyCssValueKeyword):
(WebCore::cssValueKeywordID):
(WebCore::unresolvedCSSPropertyID):
* css/parser/CSSPropertyParser.h: Added.
(WebCore::CSSPropertyParser::inQuirksMode):
* css/parser/CSSPropertyParserHelpers.cpp: Added.
* css/parser/CSSPropertyParserHelpers.h: Added.
(WebCore::CSSPropertyParserHelpers::identMatches):
(WebCore::CSSPropertyParserHelpers::consumeIdent):
(WebCore::CSSPropertyParserHelpers::isCSSWideKeyword):
* css/parser/CSSTokenizer.cpp: Added.
(WebCore::CSSTokenizer::Scope::Scope):
(WebCore::CSSTokenizer::Scope::tokenRange):
(WebCore::CSSTokenizer::Scope::tokenCount):
(WebCore::isNewLine):
(WebCore::twoCharsAreValidEscape):
(WebCore::CSSTokenizer::CSSTokenizer):
(WebCore::CSSTokenizer::reconsume):
(WebCore::CSSTokenizer::consume):
(WebCore::CSSTokenizer::whiteSpace):
(WebCore::CSSTokenizer::blockStart):
(WebCore::CSSTokenizer::blockEnd):
(WebCore::CSSTokenizer::leftParenthesis):
(WebCore::CSSTokenizer::rightParenthesis):
(WebCore::CSSTokenizer::leftBracket):
(WebCore::CSSTokenizer::rightBracket):
(WebCore::CSSTokenizer::leftBrace):
(WebCore::CSSTokenizer::rightBrace):
(WebCore::CSSTokenizer::plusOrFullStop):
(WebCore::CSSTokenizer::asterisk):
(WebCore::CSSTokenizer::lessThan):
(WebCore::CSSTokenizer::comma):
(WebCore::CSSTokenizer::hyphenMinus):
(WebCore::CSSTokenizer::solidus):
(WebCore::CSSTokenizer::colon):
(WebCore::CSSTokenizer::semiColon):
(WebCore::CSSTokenizer::hash):
(WebCore::CSSTokenizer::circumflexAccent):
(WebCore::CSSTokenizer::dollarSign):
(WebCore::CSSTokenizer::verticalLine):
(WebCore::CSSTokenizer::tilde):
(WebCore::CSSTokenizer::commercialAt):
(WebCore::CSSTokenizer::reverseSolidus):
(WebCore::CSSTokenizer::asciiDigit):
(WebCore::CSSTokenizer::letterU):
(WebCore::CSSTokenizer::nameStart):
(WebCore::CSSTokenizer::stringStart):
(WebCore::CSSTokenizer::endOfFile):
(WebCore::CSSTokenizer::nextToken):
(WebCore::CSSTokenizer::consumeNumber):
(WebCore::CSSTokenizer::consumeNumericToken):
(WebCore::CSSTokenizer::consumeIdentLikeToken):
(WebCore::CSSTokenizer::consumeStringTokenUntil):
(WebCore::CSSTokenizer::consumeUnicodeRange):
(WebCore::isNonPrintableCodePoint):
(WebCore::CSSTokenizer::consumeUrlToken):
(WebCore::CSSTokenizer::consumeBadUrlRemnants):
(WebCore::CSSTokenizer::consumeSingleWhitespaceIfNext):
(WebCore::CSSTokenizer::consumeUntilCommentEndFound):
(WebCore::CSSTokenizer::consumeIfNext):
(WebCore::CSSTokenizer::consumeName):
(WebCore::CSSTokenizer::consumeEscape):
(WebCore::CSSTokenizer::nextTwoCharsAreValidEscape):
(WebCore::CSSTokenizer::nextCharsAreNumber):
(WebCore::CSSTokenizer::nextCharsAreIdentifier):
(WebCore::CSSTokenizer::registerString):
* css/parser/CSSTokenizer.h: Added.
(WebCore::CSSTokenizer::Scope::storeString):
* css/parser/CSSTokenizerInputStream.cpp: Added.
(WebCore::CSSTokenizerInputStream::CSSTokenizerInputStream):
(WebCore::CSSTokenizerInputStream::advanceUntilNonWhitespace):
(WebCore::CSSTokenizerInputStream::getDouble):
* css/parser/CSSTokenizerInputStream.h: Added.
(WebCore::CSSTokenizerInputStream::nextInputChar):
(WebCore::CSSTokenizerInputStream::peekWithoutReplacement):
(WebCore::CSSTokenizerInputStream::advance):
(WebCore::CSSTokenizerInputStream::pushBack):
(WebCore::CSSTokenizerInputStream::skipWhilePredicate):
(WebCore::CSSTokenizerInputStream::length):
(WebCore::CSSTokenizerInputStream::offset):
(WebCore::CSSTokenizerInputStream::rangeAt):
* platform/Length.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreCMakeListstxt">trunk/Source/WebCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCorecssCSSAllInOnecpp">trunk/Source/WebCore/css/CSSAllInOne.cpp</a></li>
<li><a href="#trunkSourceWebCorecssCSSSelectorcpp">trunk/Source/WebCore/css/CSSSelector.cpp</a></li>
<li><a href="#trunkSourceWebCorecssDOMCSSNamespacecpp">trunk/Source/WebCore/css/DOMCSSNamespace.cpp</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParsercpp">trunk/Source/WebCore/css/parser/CSSParser.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformLengthh">trunk/Source/WebCore/platform/Length.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebCorecssCSSMarkupcpp">trunk/Source/WebCore/css/CSSMarkup.cpp</a></li>
<li><a href="#trunkSourceWebCorecssCSSMarkuph">trunk/Source/WebCore/css/CSSMarkup.h</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserFastPathscpp">trunk/Source/WebCore/css/parser/CSSParserFastPaths.cpp</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserFastPathsh">trunk/Source/WebCore/css/parser/CSSParserFastPaths.h</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserIdiomsh">trunk/Source/WebCore/css/parser/CSSParserIdioms.h</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserObserverh">trunk/Source/WebCore/css/parser/CSSParserObserver.h</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserObserverWrappercpp">trunk/Source/WebCore/css/parser/CSSParserObserverWrapper.cpp</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserObserverWrapperh">trunk/Source/WebCore/css/parser/CSSParserObserverWrapper.h</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserTokencpp">trunk/Source/WebCore/css/parser/CSSParserToken.cpp</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserTokenh">trunk/Source/WebCore/css/parser/CSSParserToken.h</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserTokenRangecpp">trunk/Source/WebCore/css/parser/CSSParserTokenRange.cpp</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserTokenRangeh">trunk/Source/WebCore/css/parser/CSSParserTokenRange.h</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSPropertyParsercpp">trunk/Source/WebCore/css/parser/CSSPropertyParser.cpp</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSPropertyParserh">trunk/Source/WebCore/css/parser/CSSPropertyParser.h</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSPropertyParserHelperscpp">trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSPropertyParserHelpersh">trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.h</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSTokenizercpp">trunk/Source/WebCore/css/parser/CSSTokenizer.cpp</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSTokenizerh">trunk/Source/WebCore/css/parser/CSSTokenizer.h</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSTokenizerInputStreamcpp">trunk/Source/WebCore/css/parser/CSSTokenizerInputStream.cpp</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSTokenizerInputStreamh">trunk/Source/WebCore/css/parser/CSSTokenizerInputStream.h</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkSourceWebCorecssCSSOMUtilscpp">trunk/Source/WebCore/css/CSSOMUtils.cpp</a></li>
<li><a href="#trunkSourceWebCorecssCSSOMUtilsh">trunk/Source/WebCore/css/CSSOMUtils.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/CMakeLists.txt (205102 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/CMakeLists.txt        2016-08-28 14:45:43 UTC (rev 205102)
+++ trunk/Source/WebCore/CMakeLists.txt        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -1337,9 +1337,9 @@
</span><span class="cx">     css/CSSKeyframeRule.cpp
</span><span class="cx">     css/CSSKeyframesRule.cpp
</span><span class="cx">     css/CSSLineBoxContainValue.cpp
</span><ins>+    css/CSSMarkup.cpp
</ins><span class="cx">     css/CSSMediaRule.cpp
</span><span class="cx">     css/CSSNamedImageValue.cpp
</span><del>-    css/CSSOMUtils.cpp
</del><span class="cx">     css/CSSPageRule.cpp
</span><span class="cx">     css/CSSPrimitiveValue.cpp
</span><span class="cx">     css/CSSProperty.cpp
</span><span class="lines">@@ -1406,7 +1406,15 @@
</span><span class="cx">     css/WebKitCSSViewportRule.cpp
</span><span class="cx"> 
</span><span class="cx">     css/parser/CSSParser.cpp
</span><ins>+    css/parser/CSSParserFastPaths.cpp
+    css/parser/CSSParserObserverWrapper.cpp
+    css/parser/CSSParserToken.cpp
+    css/parser/CSSParserTokenRange.cpp
</ins><span class="cx">     css/parser/CSSParserValues.cpp
</span><ins>+    css/parser/CSSPropertyParser.cpp
+    css/parser/CSSPropertyParserHelpers.cpp
+    css/parser/CSSTokenizer.cpp
+    css/parser/CSSTokenizerInputStream.cpp
</ins><span class="cx">     css/parser/SVGCSSParser.cpp
</span><span class="cx"> 
</span><span class="cx">     cssjit/SelectorCompiler.cpp
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (205102 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-08-28 14:45:43 UTC (rev 205102)
+++ trunk/Source/WebCore/ChangeLog        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -1,3 +1,177 @@
</span><ins>+2016-08-24  Dave Hyatt  &lt;hyatt@apple.com&gt;
+
+        Initial landing of CSS Parser Tokenization (and files to support that). Not used yet.
+        https://bugs.webkit.org/show_bug.cgi?id=161174
+
+        This code is imported from Blink and is their CSS parser (modified to work in WebKit).
+        It is from commit e4bb90df7f2ed8a63975b5ed27a1b488cb9b146f, Mon Aug 22 2016.
+
+        Reviewed by Simon Fraser.
+
+        * CMakeLists.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/CSSMarkup.cpp: Added.
+        (WebCore::isCSSTokenizerIdentifier):
+        (WebCore::serializeCharacter):
+        (WebCore::serializeCharacterAsCodePoint):
+        (WebCore::serializeIdentifier):
+        (WebCore::serializeString):
+        (WebCore::serializeURI):
+        (WebCore::serializeFontFamily):
+        * css/CSSMarkup.h: Added.
+        * css/CSSOMUtils.cpp: Removed.
+        * css/CSSOMUtils.h: Removed.
+        * css/CSSSelector.cpp:
+        * css/parser/CSSParserFastPaths.cpp: Added.
+        * css/parser/CSSParserFastPaths.h: Added.
+        * css/parser/CSSParserIdioms.h: Added.
+        (WebCore::isCSSSpace):
+        (WebCore::isNameStartCodePoint):
+        (WebCore::isNameCodePoint):
+        * css/parser/CSSParserObserver.h: Added.
+        (WebCore::CSSParserObserver::~CSSParserObserver):
+        * css/parser/CSSParserObserverWrapper.cpp: Added.
+        (WebCore::CSSParserObserverWrapper::startOffset):
+        (WebCore::CSSParserObserverWrapper::previousTokenStartOffset):
+        (WebCore::CSSParserObserverWrapper::endOffset):
+        (WebCore::CSSParserObserverWrapper::skipCommentsBefore):
+        (WebCore::CSSParserObserverWrapper::yieldCommentsBefore):
+        * css/parser/CSSParserObserverWrapper.h: Added.
+        (WebCore::CSSParserObserverWrapper::CSSParserObserverWrapper):
+        (WebCore::CSSParserObserverWrapper::observer):
+        (WebCore::CSSParserObserverWrapper::addComment):
+        (WebCore::CSSParserObserverWrapper::addToken):
+        (WebCore::CSSParserObserverWrapper::finalizeConstruction):
+        * css/parser/CSSParserToken.cpp: Added.
+        (WebCore::cssPrimitiveValueUnitFromTrie):
+        (WebCore::stringToUnitType):
+        (WebCore::CSSParserToken::CSSParserToken):
+        (WebCore::CSSParserToken::convertToDimensionWithUnit):
+        (WebCore::CSSParserToken::convertToPercentage):
+        (WebCore::CSSParserToken::delimiter):
+        (WebCore::CSSParserToken::numericSign):
+        (WebCore::CSSParserToken::numericValueType):
+        (WebCore::CSSParserToken::numericValue):
+        (WebCore::CSSParserToken::parseAsUnresolvedCSSPropertyID):
+        (WebCore::CSSParserToken::id):
+        (WebCore::CSSParserToken::functionId):
+        (WebCore::CSSParserToken::hasStringBacking):
+        (WebCore::CSSParserToken::copyWithUpdatedString):
+        (WebCore::CSSParserToken::valueDataCharRawEqual):
+        (WebCore::CSSParserToken::operator==):
+        (WebCore::CSSParserToken::serialize):
+        * css/parser/CSSParserToken.h: Added.
+        (WebCore::CSSParserToken::operator!=):
+        (WebCore::CSSParserToken::type):
+        (WebCore::CSSParserToken::value):
+        (WebCore::CSSParserToken::getHashTokenType):
+        (WebCore::CSSParserToken::getBlockType):
+        (WebCore::CSSParserToken::unitType):
+        (WebCore::CSSParserToken::unicodeRangeStart):
+        (WebCore::CSSParserToken::unicodeRangeEnd):
+        (WebCore::CSSParserToken::initValueFromStringView):
+        * css/parser/CSSParserTokenRange.cpp: Added.
+        (WebCore::CSSParserTokenRange::eofToken):
+        (WebCore::CSSParserTokenRange::makeSubRange):
+        (WebCore::CSSParserTokenRange::consumeBlock):
+        (WebCore::CSSParserTokenRange::consumeComponentValue):
+        (WebCore::CSSParserTokenRange::serialize):
+        * css/parser/CSSParserTokenRange.h: Added.
+        (WebCore::CSSParserTokenRange::CSSParserTokenRange):
+        (WebCore::CSSParserTokenRange::atEnd):
+        (WebCore::CSSParserTokenRange::end):
+        (WebCore::CSSParserTokenRange::peek):
+        (WebCore::CSSParserTokenRange::consume):
+        (WebCore::CSSParserTokenRange::consumeIncludingWhitespace):
+        (WebCore::CSSParserTokenRange::consumeWhitespace):
+        (WebCore::CSSParserTokenRange::begin):
+        * css/parser/CSSPropertyParser.cpp: Added.
+        (WebCore::hasPrefix):
+        (WebCore::cssPropertyID):
+        (WebCore::cssPropertyNameIOSAliasing):
+        (WebCore::isAppleLegacyCssValueKeyword):
+        (WebCore::cssValueKeywordID):
+        (WebCore::unresolvedCSSPropertyID):
+        * css/parser/CSSPropertyParser.h: Added.
+        (WebCore::CSSPropertyParser::inQuirksMode):
+        * css/parser/CSSPropertyParserHelpers.cpp: Added.
+        * css/parser/CSSPropertyParserHelpers.h: Added.
+        (WebCore::CSSPropertyParserHelpers::identMatches):
+        (WebCore::CSSPropertyParserHelpers::consumeIdent):
+        (WebCore::CSSPropertyParserHelpers::isCSSWideKeyword):
+        * css/parser/CSSTokenizer.cpp: Added.
+        (WebCore::CSSTokenizer::Scope::Scope):
+        (WebCore::CSSTokenizer::Scope::tokenRange):
+        (WebCore::CSSTokenizer::Scope::tokenCount):
+        (WebCore::isNewLine):
+        (WebCore::twoCharsAreValidEscape):
+        (WebCore::CSSTokenizer::CSSTokenizer):
+        (WebCore::CSSTokenizer::reconsume):
+        (WebCore::CSSTokenizer::consume):
+        (WebCore::CSSTokenizer::whiteSpace):
+        (WebCore::CSSTokenizer::blockStart):
+        (WebCore::CSSTokenizer::blockEnd):
+        (WebCore::CSSTokenizer::leftParenthesis):
+        (WebCore::CSSTokenizer::rightParenthesis):
+        (WebCore::CSSTokenizer::leftBracket):
+        (WebCore::CSSTokenizer::rightBracket):
+        (WebCore::CSSTokenizer::leftBrace):
+        (WebCore::CSSTokenizer::rightBrace):
+        (WebCore::CSSTokenizer::plusOrFullStop):
+        (WebCore::CSSTokenizer::asterisk):
+        (WebCore::CSSTokenizer::lessThan):
+        (WebCore::CSSTokenizer::comma):
+        (WebCore::CSSTokenizer::hyphenMinus):
+        (WebCore::CSSTokenizer::solidus):
+        (WebCore::CSSTokenizer::colon):
+        (WebCore::CSSTokenizer::semiColon):
+        (WebCore::CSSTokenizer::hash):
+        (WebCore::CSSTokenizer::circumflexAccent):
+        (WebCore::CSSTokenizer::dollarSign):
+        (WebCore::CSSTokenizer::verticalLine):
+        (WebCore::CSSTokenizer::tilde):
+        (WebCore::CSSTokenizer::commercialAt):
+        (WebCore::CSSTokenizer::reverseSolidus):
+        (WebCore::CSSTokenizer::asciiDigit):
+        (WebCore::CSSTokenizer::letterU):
+        (WebCore::CSSTokenizer::nameStart):
+        (WebCore::CSSTokenizer::stringStart):
+        (WebCore::CSSTokenizer::endOfFile):
+        (WebCore::CSSTokenizer::nextToken):
+        (WebCore::CSSTokenizer::consumeNumber):
+        (WebCore::CSSTokenizer::consumeNumericToken):
+        (WebCore::CSSTokenizer::consumeIdentLikeToken):
+        (WebCore::CSSTokenizer::consumeStringTokenUntil):
+        (WebCore::CSSTokenizer::consumeUnicodeRange):
+        (WebCore::isNonPrintableCodePoint):
+        (WebCore::CSSTokenizer::consumeUrlToken):
+        (WebCore::CSSTokenizer::consumeBadUrlRemnants):
+        (WebCore::CSSTokenizer::consumeSingleWhitespaceIfNext):
+        (WebCore::CSSTokenizer::consumeUntilCommentEndFound):
+        (WebCore::CSSTokenizer::consumeIfNext):
+        (WebCore::CSSTokenizer::consumeName):
+        (WebCore::CSSTokenizer::consumeEscape):
+        (WebCore::CSSTokenizer::nextTwoCharsAreValidEscape):
+        (WebCore::CSSTokenizer::nextCharsAreNumber):
+        (WebCore::CSSTokenizer::nextCharsAreIdentifier):
+        (WebCore::CSSTokenizer::registerString):
+        * css/parser/CSSTokenizer.h: Added.
+        (WebCore::CSSTokenizer::Scope::storeString):
+        * css/parser/CSSTokenizerInputStream.cpp: Added.
+        (WebCore::CSSTokenizerInputStream::CSSTokenizerInputStream):
+        (WebCore::CSSTokenizerInputStream::advanceUntilNonWhitespace):
+        (WebCore::CSSTokenizerInputStream::getDouble):
+        * css/parser/CSSTokenizerInputStream.h: Added.
+        (WebCore::CSSTokenizerInputStream::nextInputChar):
+        (WebCore::CSSTokenizerInputStream::peekWithoutReplacement):
+        (WebCore::CSSTokenizerInputStream::advance):
+        (WebCore::CSSTokenizerInputStream::pushBack):
+        (WebCore::CSSTokenizerInputStream::skipWhilePredicate):
+        (WebCore::CSSTokenizerInputStream::length):
+        (WebCore::CSSTokenizerInputStream::offset):
+        (WebCore::CSSTokenizerInputStream::rangeAt):
+        * platform/Length.h:
+
</ins><span class="cx"> 2016-08-28  Javier Fernandez  &lt;jfernandez@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Should never be reached failure in WebCore::RenderFlexibleBox::alignChildren
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (205102 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2016-08-28 14:45:43 UTC (rev 205102)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -3340,6 +3340,26 @@
</span><span class="cx">                 946D37301D6CB2940077084F /* CSSParserValues.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 946D372B1D6CB28B0077084F /* CSSParserValues.cpp */; };
</span><span class="cx">                 946D37311D6CB2940077084F /* CSSParserValues.h in Headers */ = {isa = PBXBuildFile; fileRef = 946D372C1D6CB28B0077084F /* CSSParserValues.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 946D37331D6CC42B0077084F /* SVGCSSParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 946D37321D6CC3720077084F /* SVGCSSParser.cpp */; };
</span><ins>+                946D37391D6CDFC00077084F /* CSSTokenizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 946D37341D6CDF980077084F /* CSSTokenizer.cpp */; };
+                946D373A1D6CDFC00077084F /* CSSTokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 946D37371D6CDF980077084F /* CSSTokenizer.h */; };
+                946D373B1D6CDFC00077084F /* CSSTokenizerInputStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 946D37351D6CDF980077084F /* CSSTokenizerInputStream.cpp */; };
+                946D373C1D6CDFC00077084F /* CSSTokenizerInputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 946D37381D6CDF980077084F /* CSSTokenizerInputStream.h */; };
+                946D373F1D6CE3C20077084F /* CSSParserToken.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 946D373E1D6CE31A0077084F /* CSSParserToken.cpp */; };
+                946D37401D6CE3C20077084F /* CSSParserToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 946D373D1D6CE31A0077084F /* CSSParserToken.h */; };
+                946D37441D6CF7B20077084F /* CSSParserIdioms.h in Headers */ = {isa = PBXBuildFile; fileRef = 946D37431D6CF7880077084F /* CSSParserIdioms.h */; };
+                946D37451D6D01D40077084F /* CSSPropertyParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 946D37411D6CF6320077084F /* CSSPropertyParser.cpp */; };
+                946D37461D6D01D40077084F /* CSSPropertyParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 946D37421D6CF6320077084F /* CSSPropertyParser.h */; };
+                946D37491D6D06280077084F /* CSSMarkup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 946D37471D6D060C0077084F /* CSSMarkup.cpp */; };
+                946D374A1D6D06280077084F /* CSSMarkup.h in Headers */ = {isa = PBXBuildFile; fileRef = 946D37481D6D060C0077084F /* CSSMarkup.h */; };
+                946D374D1D6D08A60077084F /* CSSParserTokenRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 946D374B1D6D07F50077084F /* CSSParserTokenRange.cpp */; };
+                946D374E1D6D08AA0077084F /* CSSParserTokenRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 946D374C1D6D07F50077084F /* CSSParserTokenRange.h */; };
+                949C77001D6E1D9800C0DE4F /* CSSParserFastPaths.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 949C76FE1D6E1D8C00C0DE4F /* CSSParserFastPaths.cpp */; };
+                949C77011D6E1D9800C0DE4F /* CSSParserFastPaths.h in Headers */ = {isa = PBXBuildFile; fileRef = 949C76FF1D6E1D8C00C0DE4F /* CSSParserFastPaths.h */; };
+                949C77041D6E39EA00C0DE4F /* CSSPropertyParserHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 949C77021D6E393500C0DE4F /* CSSPropertyParserHelpers.cpp */; };
+                949C77051D6E39EA00C0DE4F /* CSSPropertyParserHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 949C77031D6E393500C0DE4F /* CSSPropertyParserHelpers.h */; };
+                949C77081D6E498700C0DE4F /* CSSParserObserverWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 949C77061D6E48ED00C0DE4F /* CSSParserObserverWrapper.cpp */; };
+                949C77091D6E498700C0DE4F /* CSSParserObserverWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 949C77071D6E48ED00C0DE4F /* CSSParserObserverWrapper.h */; };
+                949C770B1D6E49ED00C0DE4F /* CSSParserObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 949C770A1D6E49C300C0DE4F /* CSSParserObserver.h */; };
</ins><span class="cx">                 96ABA42314BCB80E00D56204 /* GraphicsContext3DOpenGLCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96ABA42214BCB80E00D56204 /* GraphicsContext3DOpenGLCommon.cpp */; };
</span><span class="cx">                 9703E1BF15DC4E37001F24C8 /* JSVoidCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E9EC8B15DC492F004F2E71 /* JSVoidCallback.cpp */; };
</span><span class="cx">                 97059977107D975200A50A7C /* PolicyCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97059973107D975200A50A7C /* PolicyCallback.cpp */; };
</span><span class="lines">@@ -6317,8 +6337,6 @@
</span><span class="cx">                 F5E0C65C1643C42C00D6CB69 /* BaseChooserOnlyDateAndTimeInputType.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E0C65A1643C42C00D6CB69 /* BaseChooserOnlyDateAndTimeInputType.h */; };
</span><span class="cx">                 F916C48D0DB510F80076CD83 /* JSXMLHttpRequestProgressEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F916C48B0DB510F80076CD83 /* JSXMLHttpRequestProgressEvent.cpp */; };
</span><span class="cx">                 F916C48E0DB510F80076CD83 /* JSXMLHttpRequestProgressEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = F916C48C0DB510F80076CD83 /* JSXMLHttpRequestProgressEvent.h */; };
</span><del>-                F98FFF4411A2676200F548E8 /* CSSOMUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F98FFF4211A2676200F548E8 /* CSSOMUtils.cpp */; };
-                F98FFF4511A2676200F548E8 /* CSSOMUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = F98FFF4311A2676200F548E8 /* CSSOMUtils.h */; };
</del><span class="cx">                 F9F0ED7A0DB50CA200D16DB9 /* XMLHttpRequestProgressEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = F9F0ED770DB50CA200D16DB9 /* XMLHttpRequestProgressEvent.h */; };
</span><span class="cx">                 FA654A6B1108ABED002615E0 /* MathMLTokenElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA654A691108ABED002615E0 /* MathMLTokenElement.cpp */; };
</span><span class="cx">                 FA654A6B1108ABED002616F1 /* MathMLOperatorElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA654A691108ABED002616F1 /* MathMLOperatorElement.cpp */; };
</span><span class="lines">@@ -10450,6 +10468,26 @@
</span><span class="cx">                 946D372B1D6CB28B0077084F /* CSSParserValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSParserValues.cpp; path = parser/CSSParserValues.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 946D372C1D6CB28B0077084F /* CSSParserValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserValues.h; path = parser/CSSParserValues.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 946D37321D6CC3720077084F /* SVGCSSParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SVGCSSParser.cpp; path = parser/SVGCSSParser.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                946D37341D6CDF980077084F /* CSSTokenizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSTokenizer.cpp; path = parser/CSSTokenizer.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D37351D6CDF980077084F /* CSSTokenizerInputStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSTokenizerInputStream.cpp; path = parser/CSSTokenizerInputStream.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D37371D6CDF980077084F /* CSSTokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSTokenizer.h; path = parser/CSSTokenizer.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D37381D6CDF980077084F /* CSSTokenizerInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSTokenizerInputStream.h; path = parser/CSSTokenizerInputStream.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D373D1D6CE31A0077084F /* CSSParserToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserToken.h; path = parser/CSSParserToken.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D373E1D6CE31A0077084F /* CSSParserToken.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSParserToken.cpp; path = parser/CSSParserToken.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D37411D6CF6320077084F /* CSSPropertyParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSPropertyParser.cpp; path = parser/CSSPropertyParser.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D37421D6CF6320077084F /* CSSPropertyParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSPropertyParser.h; path = parser/CSSPropertyParser.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D37431D6CF7880077084F /* CSSParserIdioms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserIdioms.h; path = parser/CSSParserIdioms.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D37471D6D060C0077084F /* CSSMarkup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSMarkup.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D37481D6D060C0077084F /* CSSMarkup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSMarkup.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D374B1D6D07F50077084F /* CSSParserTokenRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSParserTokenRange.cpp; path = parser/CSSParserTokenRange.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                946D374C1D6D07F50077084F /* CSSParserTokenRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserTokenRange.h; path = parser/CSSParserTokenRange.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                949C76FE1D6E1D8C00C0DE4F /* CSSParserFastPaths.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSParserFastPaths.cpp; path = parser/CSSParserFastPaths.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                949C76FF1D6E1D8C00C0DE4F /* CSSParserFastPaths.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserFastPaths.h; path = parser/CSSParserFastPaths.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                949C77021D6E393500C0DE4F /* CSSPropertyParserHelpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSPropertyParserHelpers.cpp; path = parser/CSSPropertyParserHelpers.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                949C77031D6E393500C0DE4F /* CSSPropertyParserHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSPropertyParserHelpers.h; path = parser/CSSPropertyParserHelpers.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                949C77061D6E48ED00C0DE4F /* CSSParserObserverWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSParserObserverWrapper.cpp; path = parser/CSSParserObserverWrapper.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                949C77071D6E48ED00C0DE4F /* CSSParserObserverWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserObserverWrapper.h; path = parser/CSSParserObserverWrapper.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                949C770A1D6E49C300C0DE4F /* CSSParserObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserObserver.h; path = parser/CSSParserObserver.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 950C4C02BED8936F818E2F99 /* JSSVGGraphicsElement.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSSVGGraphicsElement.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 96ABA42214BCB80E00D56204 /* GraphicsContext3DOpenGLCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GraphicsContext3DOpenGLCommon.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 97059973107D975200A50A7C /* PolicyCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PolicyCallback.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -13889,8 +13927,6 @@
</span><span class="cx">                 F8216299029F4FB501000131 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JavaScriptCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
</span><span class="cx">                 F916C48B0DB510F80076CD83 /* JSXMLHttpRequestProgressEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSXMLHttpRequestProgressEvent.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 F916C48C0DB510F80076CD83 /* JSXMLHttpRequestProgressEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSXMLHttpRequestProgressEvent.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><del>-                F98FFF4211A2676200F548E8 /* CSSOMUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSOMUtils.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
-                F98FFF4311A2676200F548E8 /* CSSOMUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSOMUtils.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</del><span class="cx">                 F9F0ED770DB50CA200D16DB9 /* XMLHttpRequestProgressEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = XMLHttpRequestProgressEvent.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 F9F0ED780DB50CA200D16DB9 /* XMLHttpRequestProgressEvent.idl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = XMLHttpRequestProgressEvent.idl; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FA654A631108ABB7002615E0 /* mathml.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = mathml.css; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -18068,12 +18104,30 @@
</span><span class="cx">                 946D37271D6CB2250077084F /* parser */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><del>-                                946D37321D6CC3720077084F /* SVGCSSParser.cpp */,
</del><span class="cx">                                 946D37281D6CB28B0077084F /* CSSParser.cpp */,
</span><span class="cx">                                 946D37291D6CB28B0077084F /* CSSParser.h */,
</span><ins>+                                949C76FE1D6E1D8C00C0DE4F /* CSSParserFastPaths.cpp */,
+                                949C76FF1D6E1D8C00C0DE4F /* CSSParserFastPaths.h */,
+                                946D37431D6CF7880077084F /* CSSParserIdioms.h */,
</ins><span class="cx">                                 946D372A1D6CB28B0077084F /* CSSParserMode.h */,
</span><ins>+                                949C770A1D6E49C300C0DE4F /* CSSParserObserver.h */,
+                                949C77061D6E48ED00C0DE4F /* CSSParserObserverWrapper.cpp */,
+                                949C77071D6E48ED00C0DE4F /* CSSParserObserverWrapper.h */,
+                                946D373E1D6CE31A0077084F /* CSSParserToken.cpp */,
+                                946D373D1D6CE31A0077084F /* CSSParserToken.h */,
+                                946D374B1D6D07F50077084F /* CSSParserTokenRange.cpp */,
+                                946D374C1D6D07F50077084F /* CSSParserTokenRange.h */,
</ins><span class="cx">                                 946D372B1D6CB28B0077084F /* CSSParserValues.cpp */,
</span><span class="cx">                                 946D372C1D6CB28B0077084F /* CSSParserValues.h */,
</span><ins>+                                946D37411D6CF6320077084F /* CSSPropertyParser.cpp */,
+                                946D37421D6CF6320077084F /* CSSPropertyParser.h */,
+                                949C77021D6E393500C0DE4F /* CSSPropertyParserHelpers.cpp */,
+                                949C77031D6E393500C0DE4F /* CSSPropertyParserHelpers.h */,
+                                946D37341D6CDF980077084F /* CSSTokenizer.cpp */,
+                                946D37371D6CDF980077084F /* CSSTokenizer.h */,
+                                946D37351D6CDF980077084F /* CSSTokenizerInputStream.cpp */,
+                                946D37381D6CDF980077084F /* CSSTokenizerInputStream.h */,
+                                946D37321D6CC3720077084F /* SVGCSSParser.cpp */,
</ins><span class="cx">                         );
</span><span class="cx">                         name = parser;
</span><span class="cx">                         sourceTree = &quot;&lt;group&gt;&quot;;
</span><span class="lines">@@ -20939,8 +20993,8 @@
</span><span class="cx">                                 BE6DF70E171CA2DA00DD52B8 /* JSAudioTrackCustom.cpp */,
</span><span class="cx">                                 BE6DF710171CA2DA00DD52B8 /* JSAudioTrackListCustom.cpp */,
</span><span class="cx">                                 8931DE5A14C44C44000DC9D2 /* JSBlobCustom.cpp */,
</span><ins>+                                4659D2701D6B909F0096FD86 /* JSCanvasRenderingContext.h */,
</ins><span class="cx">                                 49EED14B1051971900099FAB /* JSCanvasRenderingContext2DCustom.cpp */,
</span><del>-                                4659D2701D6B909F0096FD86 /* JSCanvasRenderingContext.h */,
</del><span class="cx">                                 7C33F3581B4A044800502CAF /* JSCharacterDataCustom.cpp */,
</span><span class="cx">                                 46A58AC41D46B3FA00432036 /* JSClientRectCustom.cpp */,
</span><span class="cx">                                 A584FE371864DAC100843B10 /* JSCommandLineAPIHostCustom.cpp */,
</span><span class="lines">@@ -22227,13 +22281,13 @@
</span><span class="cx">                                 316FE0920E6CCD7F00BF6088 /* CSSKeyframesRule.idl */,
</span><span class="cx">                                 BC772E15133162C2001EC9CE /* CSSLineBoxContainValue.cpp */,
</span><span class="cx">                                 BC772E121331620C001EC9CE /* CSSLineBoxContainValue.h */,
</span><ins>+                                946D37471D6D060C0077084F /* CSSMarkup.cpp */,
+                                946D37481D6D060C0077084F /* CSSMarkup.h */,
</ins><span class="cx">                                 A80E6CD20A1989CA007FB8C5 /* CSSMediaRule.cpp */,
</span><span class="cx">                                 A80E6CD90A1989CA007FB8C5 /* CSSMediaRule.h */,
</span><span class="cx">                                 85C56CA20AA89C1000D95755 /* CSSMediaRule.idl */,
</span><span class="cx">                                 314BE3A21B30F6D100141982 /* CSSNamedImageValue.cpp */,
</span><span class="cx">                                 314BE3A01B30F6B700141982 /* CSSNamedImageValue.h */,
</span><del>-                                F98FFF4211A2676200F548E8 /* CSSOMUtils.cpp */,
-                                F98FFF4311A2676200F548E8 /* CSSOMUtils.h */,
</del><span class="cx">                                 A80E6CCB0A1989CA007FB8C5 /* CSSPageRule.cpp */,
</span><span class="cx">                                 A80E6CD60A1989CA007FB8C5 /* CSSPageRule.h */,
</span><span class="cx">                                 85C56CA60AA89D5F00D95755 /* CSSPageRule.idl */,
</span><span class="lines">@@ -23140,8 +23194,6 @@
</span><span class="cx">                                 FABE72EE1059C1EB00D999DD /* MathMLElement.h */,
</span><span class="cx">                                 0BCF83EF1059C1EB00D999DD /* MathMLFractionElement.cpp */,
</span><span class="cx">                                 0BCF83F01059C1EB00D999DD /* MathMLFractionElement.h */,
</span><del>-                                FABE72EF1059C1EB00D999DD /* MathMLPresentationElement.cpp */,
-                                FABE72F01059C1EB00D999DD /* MathMLPresentationElement.h */,
</del><span class="cx">                                 FABE72F11059C1EB00D999DD /* MathMLMathElement.cpp */,
</span><span class="cx">                                 FABE72F21059C1EB00D999DD /* MathMLMathElement.h */,
</span><span class="cx">                                 C3E61C653A64807A83E76FB8 /* MathMLMencloseElement.cpp */,
</span><span class="lines">@@ -23152,6 +23204,10 @@
</span><span class="cx">                                 FA654A6A1108ABED002616F1 /* MathMLOperatorElement.h */,
</span><span class="cx">                                 B59CA59AF170D8FAA5B8CABE /* MathMLPaddedElement.cpp */,
</span><span class="cx">                                 B59CA849D41E6F65D81198BC /* MathMLPaddedElement.h */,
</span><ins>+                                FABE72EF1059C1EB00D999DD /* MathMLPresentationElement.cpp */,
+                                FABE72F01059C1EB00D999DD /* MathMLPresentationElement.h */,
+                                FA765A691108ABED002615E0 /* MathMLRowElement.cpp */,
+                                FA765A6A1108ABED002615E0 /* MathMLRowElement.h */,
</ins><span class="cx">                                 B59CA59AF170D8FAA5B8C9AD /* MathMLScriptsElement.cpp */,
</span><span class="cx">                                 B59CA849D41E6F65D81197AB /* MathMLScriptsElement.h */,
</span><span class="cx">                                 F75A059AF170D8FAA5B8CABE /* MathMLSelectElement.cpp */,
</span><span class="lines">@@ -23160,8 +23216,6 @@
</span><span class="cx">                                 4FA65A6A1108ABED002615E0 /* MathMLSpaceElement.h */,
</span><span class="cx">                                 FA654A691108ABED002615E0 /* MathMLTokenElement.cpp */,
</span><span class="cx">                                 FA654A6A1108ABED002615E0 /* MathMLTokenElement.h */,
</span><del>-                                FA765A691108ABED002615E0 /* MathMLRowElement.cpp */,
-                                FA765A6A1108ABED002615E0 /* MathMLRowElement.h */,
</del><span class="cx">                                 FA654A691108ABED002626F1 /* MathMLUnderOverElement.cpp */,
</span><span class="cx">                                 FA654A6A1108ABED002626F1 /* MathMLUnderOverElement.h */,
</span><span class="cx">                                 FABE72F31059C1EB00D999DD /* mathtags.in */,
</span><span class="lines">@@ -23523,8 +23577,6 @@
</span><span class="cx">                         isa = PBXHeadersBuildPhase;
</span><span class="cx">                         buildActionMask = 2147483647;
</span><span class="cx">                         files = (
</span><del>-                                51058ADE1D6792C1009A538C /* MockGamepadProvider.h in Headers */,
-                                51058ADC1D6792C1009A538C /* MockGamepad.h in Headers */,
</del><span class="cx">                                 51714EAD1CF65951004723C4 /* GCObservation.h in Headers */,
</span><span class="cx">                                 417DA6DA13734E6E007C57FB /* Internals.h in Headers */,
</span><span class="cx">                                 A7BF7EE014C9175A0014489D /* InternalSettings.h in Headers */,
</span><span class="lines">@@ -23540,6 +23592,8 @@
</span><span class="cx">                                 CDC26B41160A8CCE0026757B /* MockCDM.h in Headers */,
</span><span class="cx">                                 A1BF6B831AA96C7D00AF4A8A /* MockContentFilter.h in Headers */,
</span><span class="cx">                                 A1B5B29F1AAA846F008B6042 /* MockContentFilterSettings.h in Headers */,
</span><ins>+                                51058ADC1D6792C1009A538C /* MockGamepad.h in Headers */,
+                                51058ADE1D6792C1009A538C /* MockGamepadProvider.h in Headers */,
</ins><span class="cx">                                 2D6F3E911C1ECB2F0061DBD4 /* MockPageOverlay.h in Headers */,
</span><span class="cx">                                 2D97F04819DD4140001EE9C3 /* MockPageOverlayClient.h in Headers */,
</span><span class="cx">                                 AA5F3B8D16CC33D100455EB0 /* PlatformSpeechSynthesizerMock.h in Headers */,
</span><span class="lines">@@ -23671,7 +23725,6 @@
</span><span class="cx">                                 BEF29EEB1715DD0900C4B4C9 /* AudioTrackPrivate.h in Headers */,
</span><span class="cx">                                 CDE3A85417F5FCE600C5BE20 /* AudioTrackPrivateAVF.h in Headers */,
</span><span class="cx">                                 CDE3A85817F6020400C5BE20 /* AudioTrackPrivateAVFObjC.h in Headers */,
</span><del>-                                51058AE21D67C229009A538C /* MockGamepadProvider.h in Headers */,
</del><span class="cx">                                 CD54A763180F9F7000B076C9 /* AudioTrackPrivateMediaSourceAVFObjC.h in Headers */,
</span><span class="cx">                                 07D6A4F81BF2307D00174146 /* AudioTrackPrivateMediaStream.h in Headers */,
</span><span class="cx">                                 FD31608B12B026F700C1A359 /* AudioUtilities.h in Headers */,
</span><span class="lines">@@ -23952,7 +24005,6 @@
</span><span class="cx">                                 31BC742E1AAFF45C006B4340 /* CSSAnimationTriggerScrollValue.h in Headers */,
</span><span class="cx">                                 CAE9F910146441F000C245B0 /* CSSAspectRatioValue.h in Headers */,
</span><span class="cx">                                 FBD6AF8815EF25C9008B7110 /* CSSBasicShapes.h in Headers */,
</span><del>-                                51058AE01D67C229009A538C /* MockGamepad.h in Headers */,
</del><span class="cx">                                 E16A84FA14C85CCC002977DF /* CSSBorderImage.h in Headers */,
</span><span class="cx">                                 BC274B2F140EBEB200EADFA6 /* CSSBorderImageSliceValue.h in Headers */,
</span><span class="cx">                                 49AE2D8F134EE50C0072920A /* CSSCalculationValue.h in Headers */,
</span><span class="lines">@@ -23992,10 +24044,19 @@
</span><span class="cx">                                 31288E730E3005D6003619AE /* CSSKeyframeRule.h in Headers */,
</span><span class="cx">                                 31288E750E3005D6003619AE /* CSSKeyframesRule.h in Headers */,
</span><span class="cx">                                 BC772E131331620C001EC9CE /* CSSLineBoxContainValue.h in Headers */,
</span><ins>+                                946D374A1D6D06280077084F /* CSSMarkup.h in Headers */,
</ins><span class="cx">                                 A80E6D030A1989CA007FB8C5 /* CSSMediaRule.h in Headers */,
</span><span class="cx">                                 314BE3A11B30F6B700141982 /* CSSNamedImageValue.h in Headers */,
</span><del>-                                F98FFF4511A2676200F548E8 /* CSSOMUtils.h in Headers */,
</del><span class="cx">                                 A80E6D000A1989CA007FB8C5 /* CSSPageRule.h in Headers */,
</span><ins>+                                946D372E1D6CB2940077084F /* CSSParser.h in Headers */,
+                                949C77011D6E1D9800C0DE4F /* CSSParserFastPaths.h in Headers */,
+                                946D37441D6CF7B20077084F /* CSSParserIdioms.h in Headers */,
+                                946D372F1D6CB2940077084F /* CSSParserMode.h in Headers */,
+                                949C770B1D6E49ED00C0DE4F /* CSSParserObserver.h in Headers */,
+                                949C77091D6E498700C0DE4F /* CSSParserObserverWrapper.h in Headers */,
+                                946D37401D6CE3C20077084F /* CSSParserToken.h in Headers */,
+                                946D374E1D6D08AA0077084F /* CSSParserTokenRange.h in Headers */,
+                                946D37311D6CB2940077084F /* CSSParserValues.h in Headers */,
</ins><span class="cx">                                 977B3863122883E900B81FF8 /* CSSPreloadScanner.h in Headers */,
</span><span class="cx">                                 A80E6CE60A1989CA007FB8C5 /* CSSPrimitiveValue.h in Headers */,
</span><span class="cx">                                 E1ED8AC30CC49BE000BFC557 /* CSSPrimitiveValueMappings.h in Headers */,
</span><span class="lines">@@ -24002,6 +24063,8 @@
</span><span class="cx">                                 A80E6CFF0A1989CA007FB8C5 /* CSSProperty.h in Headers */,
</span><span class="cx">                                 78D02BC6154A18DF00B62D05 /* CSSPropertyAnimation.h in Headers */,
</span><span class="cx">                                 656580F409D12B20000E61D7 /* CSSPropertyNames.h in Headers */,
</span><ins>+                                946D37461D6D01D40077084F /* CSSPropertyParser.h in Headers */,
+                                949C77051D6E39EA00C0DE4F /* CSSPropertyParserHelpers.h in Headers */,
</ins><span class="cx">                                 82E3D8DF122EA0D1003AE5BC /* CSSPropertySourceData.h in Headers */,
</span><span class="cx">                                 9362640B0DE1137D009D5A00 /* CSSReflectionDirection.h in Headers */,
</span><span class="cx">                                 BC5A12E00DC0414800C9AFAD /* CSSReflectValue.h in Headers */,
</span><span class="lines">@@ -24017,6 +24080,8 @@
</span><span class="cx">                                 A8EA80070A19516E00A8EF5F /* CSSStyleSheet.h in Headers */,
</span><span class="cx">                                 FC54D05716A7673100575E4D /* CSSSupportsRule.h in Headers */,
</span><span class="cx">                                 BC80C9880CD294EE00A0B7B3 /* CSSTimingFunctionValue.h in Headers */,
</span><ins>+                                946D373A1D6CDFC00077084F /* CSSTokenizer.h in Headers */,
+                                946D373C1D6CDFC00077084F /* CSSTokenizerInputStream.h in Headers */,
</ins><span class="cx">                                 9AB1F38018E2489A00534743 /* CSSToLengthConversionData.h in Headers */,
</span><span class="cx">                                 A882DA231593848D000115ED /* CSSToStyleMap.h in Headers */,
</span><span class="cx">                                 371F53E90D2704F900ECE0D5 /* CSSUnicodeRangeValue.h in Headers */,
</span><span class="lines">@@ -24735,6 +24800,7 @@
</span><span class="cx">                                 65DF323C09D1DE65000BE325 /* JSCanvasPattern.h in Headers */,
</span><span class="cx">                                 65DF323C09D1DE65001BE325 /* JSCanvasProxy.h in Headers */,
</span><span class="cx">                                 49EED1431051969400099FAB /* JSCanvasRenderingContext.h in Headers */,
</span><ins>+                                4659D2711D6B90A50096FD86 /* JSCanvasRenderingContext.h in Headers */,
</ins><span class="cx">                                 49EED1451051969400099FAB /* JSCanvasRenderingContext2D.h in Headers */,
</span><span class="cx">                                 93F9B7A10BA6032600854064 /* JSCDATASection.h in Headers */,
</span><span class="cx">                                 FDA15EA212B03EE1003A583A /* JSChannelMergerNode.h in Headers */,
</span><span class="lines">@@ -24965,7 +25031,6 @@
</span><span class="cx">                                 FD23A12613F5FA5900F67001 /* JSMediaElementAudioSourceNode.h in Headers */,
</span><span class="cx">                                 E44614190CD6826900FADA75 /* JSMediaError.h in Headers */,
</span><span class="cx">                                 BC3C39B70C0D3D8D005F4D7A /* JSMediaList.h in Headers */,
</span><del>-                                4659D2711D6B90A50096FD86 /* JSCanvasRenderingContext.h in Headers */,
</del><span class="cx">                                 93D437A31D57B7E200AB85EA /* JSMediaListCustom.h in Headers */,
</span><span class="cx">                                 D3A94A47122DC40F00A37BBC /* JSMediaQueryList.h in Headers */,
</span><span class="cx">                                 7C5343FD17B74B63004232F0 /* JSMediaQueryListListener.h in Headers */,
</span><span class="lines">@@ -25174,7 +25239,6 @@
</span><span class="cx">                                 B2FA3DB50AB75A6F000E5AC4 /* JSSVGPathElement.h in Headers */,
</span><span class="cx">                                 B2FA3DB70AB75A6F000E5AC4 /* JSSVGPathSeg.h in Headers */,
</span><span class="cx">                                 B2FA3DB90AB75A6F000E5AC4 /* JSSVGPathSegArcAbs.h in Headers */,
</span><del>-                                946D372E1D6CB2940077084F /* CSSParser.h in Headers */,
</del><span class="cx">                                 B2FA3DBB0AB75A6F000E5AC4 /* JSSVGPathSegArcRel.h in Headers */,
</span><span class="cx">                                 B2FA3DBD0AB75A6F000E5AC4 /* JSSVGPathSegClosePath.h in Headers */,
</span><span class="cx">                                 B2FA3DBF0AB75A6F000E5AC4 /* JSSVGPathSegCurvetoCubicAbs.h in Headers */,
</span><span class="lines">@@ -25347,7 +25411,6 @@
</span><span class="cx">                                 E4E39AFB1330EFA8003AB274 /* LegacyTileLayerPool.h in Headers */,
</span><span class="cx">                                 512DD8F50D91E6AF000F89EE /* LegacyWebArchive.h in Headers */,
</span><span class="cx">                                 BCE65BEB0EACDF16007E4533 /* Length.h in Headers */,
</span><del>-                                946D372F1D6CB2940077084F /* CSSParserMode.h in Headers */,
</del><span class="cx">                                 BCFF64910EAD15C200C1D6F7 /* LengthBox.h in Headers */,
</span><span class="cx">                                 E5BA7D63151437CA00FE1E3F /* LengthFunctions.h in Headers */,
</span><span class="cx">                                 0F8716701C869D83004FF0DE /* LengthPoint.h in Headers */,
</span><span class="lines">@@ -25394,14 +25457,14 @@
</span><span class="cx">                                 FABE72F51059C1EB00D999DD /* MathMLElement.h in Headers */,
</span><span class="cx">                                 44A28AAC12DFB8AC00AE923B /* MathMLElementFactory.h in Headers */,
</span><span class="cx">                                 0BCF83F71059C1EB00D999DD /* MathMLFractionElement.h in Headers */,
</span><del>-                                FABE72F71059C1EB00D999DD /* MathMLPresentationElement.h in Headers */,
</del><span class="cx">                                 FABE72F91059C1EB00D999DD /* MathMLMathElement.h in Headers */,
</span><span class="cx">                                 44A28AAF12DFB8BF00AE923B /* MathMLNames.h in Headers */,
</span><span class="cx">                                 FA654A6C1108ABED002616F1 /* MathMLOperatorElement.h in Headers */,
</span><ins>+                                FABE72F71059C1EB00D999DD /* MathMLPresentationElement.h in Headers */,
+                                FA765A6C1108ABED002615E0 /* MathMLRowElement.h in Headers */,
</ins><span class="cx">                                 4FA65A6C1108ABED002615E0 /* MathMLSpaceElement.h in Headers */,
</span><span class="cx">                                 439176E012DA25E17BAF80A2 /* MathMLStyle.h in Headers */,
</span><span class="cx">                                 FA654A6C1108ABED002615E0 /* MathMLTokenElement.h in Headers */,
</span><del>-                                FA765A6C1108ABED002615E0 /* MathMLRowElement.h in Headers */,
</del><span class="cx">                                 FA654A6C1108ABED002626F1 /* MathMLUnderOverElement.h in Headers */,
</span><span class="cx">                                 439046EA12DA25E812AF80AC /* MathOperator.h in Headers */,
</span><span class="cx">                                 49D5DC2C0F423A73008F20FD /* Matrix3DTransformOperation.h in Headers */,
</span><span class="lines">@@ -25522,6 +25585,8 @@
</span><span class="cx">                                 52F10866162B6DA8009AC81E /* MixedContentChecker.h in Headers */,
</span><span class="cx">                                 CE1252491A16C3BC00864480 /* MobileGestaltSPI.h in Headers */,
</span><span class="cx">                                 CDF2B0111820540600F2B424 /* MockBox.h in Headers */,
</span><ins>+                                51058AE01D67C229009A538C /* MockGamepad.h in Headers */,
+                                51058AE21D67C229009A538C /* MockGamepadProvider.h in Headers */,
</ins><span class="cx">                                 5EA3D6DF1C859D7F00300BBB /* MockMediaEndpoint.h in Headers */,
</span><span class="cx">                                 CDF2B0131820540600F2B424 /* MockMediaPlayerMediaSource.h in Headers */,
</span><span class="cx">                                 CDF2B0151820540600F2B424 /* MockMediaSourcePrivate.h in Headers */,
</span><span class="lines">@@ -26527,7 +26592,6 @@
</span><span class="cx">                                 0813A4EA1284132600992511 /* SVGStaticPropertyTearOff.h in Headers */,
</span><span class="cx">                                 B2227AA90D00BF220071B782 /* SVGStopElement.h in Headers */,
</span><span class="cx">                                 B2227AAC0D00BF220071B782 /* SVGStringList.h in Headers */,
</span><del>-                                946D37311D6CB2940077084F /* CSSParserValues.h in Headers */,
</del><span class="cx">                                 B2227AB80D00BF220071B782 /* SVGStyleElement.h in Headers */,
</span><span class="cx">                                 B2227ABB0D00BF220071B782 /* SVGSVGElement.h in Headers */,
</span><span class="cx">                                 B2227ABE0D00BF220071B782 /* SVGSwitchElement.h in Headers */,
</span><span class="lines">@@ -27260,7 +27324,6 @@
</span><span class="cx">                                 417DA6D913734E6E007C57FB /* Internals.cpp in Sources */,
</span><span class="cx">                                 E179F0DA1B9774FE00ED0A27 /* Internals.mm in Sources */,
</span><span class="cx">                                 A7BF7EDF14C9175A0014489D /* InternalSettings.cpp in Sources */,
</span><del>-                                51058ADD1D6792C1009A538C /* MockGamepadProvider.cpp in Sources */,
</del><span class="cx">                                 53E29E5E167A8A1900586D3D /* InternalSettingsGenerated.cpp in Sources */,
</span><span class="cx">                                 51714EB01CF665CE004723C4 /* JSGCObservation.cpp in Sources */,
</span><span class="cx">                                 417DA71D13735DFA007C57FB /* JSInternals.cpp in Sources */,
</span><span class="lines">@@ -27270,12 +27333,13 @@
</span><span class="cx">                                 CD5393D3175E018600C07123 /* JSMemoryInfo.cpp in Sources */,
</span><span class="cx">                                 A19AEA221AAA808A00B52B25 /* JSMockContentFilterSettings.cpp in Sources */,
</span><span class="cx">                                 A1E5B31F1AAD1DA4006EBEFB /* JSMockContentFilterSettingsCustom.cpp in Sources */,
</span><del>-                                51058ADB1D6792C1009A538C /* MockGamepad.cpp in Sources */,
</del><span class="cx">                                 2D4150DE1C1F868C000A3BA2 /* JSMockPageOverlay.cpp in Sources */,
</span><span class="cx">                                 EBF5121C1696496C0056BD25 /* JSTypeConversions.cpp in Sources */,
</span><span class="cx">                                 CDC26B40160A8CC60026757B /* MockCDM.cpp in Sources */,
</span><span class="cx">                                 A1BF6B821AA96C7D00AF4A8A /* MockContentFilter.cpp in Sources */,
</span><span class="cx">                                 A1B5B29E1AAA846E008B6042 /* MockContentFilterSettings.cpp in Sources */,
</span><ins>+                                51058ADB1D6792C1009A538C /* MockGamepad.cpp in Sources */,
+                                51058ADD1D6792C1009A538C /* MockGamepadProvider.cpp in Sources */,
</ins><span class="cx">                                 2D6F3E901C1ECB270061DBD4 /* MockPageOverlay.cpp in Sources */,
</span><span class="cx">                                 2D97F04719DD413C001EE9C3 /* MockPageOverlayClient.cpp in Sources */,
</span><span class="cx">                                 AA5F3B8F16CC4B3900455EB0 /* PlatformSpeechSynthesizerMock.cpp in Sources */,
</span><span class="lines">@@ -27661,15 +27725,23 @@
</span><span class="cx">                                 31288E720E3005D6003619AE /* CSSKeyframeRule.cpp in Sources */,
</span><span class="cx">                                 31288E740E3005D6003619AE /* CSSKeyframesRule.cpp in Sources */,
</span><span class="cx">                                 BC772E16133162C2001EC9CE /* CSSLineBoxContainValue.cpp in Sources */,
</span><ins>+                                946D37491D6D06280077084F /* CSSMarkup.cpp in Sources */,
</ins><span class="cx">                                 A80E6CFC0A1989CA007FB8C5 /* CSSMediaRule.cpp in Sources */,
</span><span class="cx">                                 314BE3A31B30F6D100141982 /* CSSNamedImageValue.cpp in Sources */,
</span><del>-                                F98FFF4411A2676200F548E8 /* CSSOMUtils.cpp in Sources */,
</del><span class="cx">                                 A80E6CF50A1989CA007FB8C5 /* CSSPageRule.cpp in Sources */,
</span><ins>+                                946D372D1D6CB2940077084F /* CSSParser.cpp in Sources */,
+                                949C77001D6E1D9800C0DE4F /* CSSParserFastPaths.cpp in Sources */,
+                                949C77081D6E498700C0DE4F /* CSSParserObserverWrapper.cpp in Sources */,
+                                946D373F1D6CE3C20077084F /* CSSParserToken.cpp in Sources */,
+                                946D374D1D6D08A60077084F /* CSSParserTokenRange.cpp in Sources */,
+                                946D37301D6CB2940077084F /* CSSParserValues.cpp in Sources */,
</ins><span class="cx">                                 977B3862122883E900B81FF8 /* CSSPreloadScanner.cpp in Sources */,
</span><span class="cx">                                 A80E6D050A1989CA007FB8C5 /* CSSPrimitiveValue.cpp in Sources */,
</span><span class="cx">                                 A80E6CF70A1989CA007FB8C5 /* CSSProperty.cpp in Sources */,
</span><span class="cx">                                 78D02BC5154A18DF00B62D05 /* CSSPropertyAnimation.cpp in Sources */,
</span><span class="cx">                                 1ABA76CA11D20E50004C201C /* CSSPropertyNames.cpp in Sources */,
</span><ins>+                                946D37451D6D01D40077084F /* CSSPropertyParser.cpp in Sources */,
+                                949C77041D6E39EA00C0DE4F /* CSSPropertyParserHelpers.cpp in Sources */,
</ins><span class="cx">                                 82E3D8DE122EA0D1003AE5BC /* CSSPropertySourceData.cpp in Sources */,
</span><span class="cx">                                 BC5A12DF0DC0414800C9AFAD /* CSSReflectValue.cpp in Sources */,
</span><span class="cx">                                 BC7D8FF31BD1A47900FFE540 /* CSSRevertValue.cpp in Sources */,
</span><span class="lines">@@ -27683,6 +27755,8 @@
</span><span class="cx">                                 A8EA80080A19516E00A8EF5F /* CSSStyleSheet.cpp in Sources */,
</span><span class="cx">                                 FD677739195CAFBA0072E0D3 /* CSSSupportsRule.cpp in Sources */,
</span><span class="cx">                                 BC80C9870CD294EE00A0B7B3 /* CSSTimingFunctionValue.cpp in Sources */,
</span><ins>+                                946D37391D6CDFC00077084F /* CSSTokenizer.cpp in Sources */,
+                                946D373B1D6CDFC00077084F /* CSSTokenizerInputStream.cpp in Sources */,
</ins><span class="cx">                                 9AB1F38118E2489A00534743 /* CSSToLengthConversionData.cpp in Sources */,
</span><span class="cx">                                 A882DA201593846A000115ED /* CSSToStyleMap.cpp in Sources */,
</span><span class="cx">                                 371F53EA0D2704F900ECE0D5 /* CSSUnicodeRangeValue.cpp in Sources */,
</span><span class="lines">@@ -28353,6 +28427,7 @@
</span><span class="cx">                                 975CA2A11303679D00E99AD9 /* JSCrypto.cpp in Sources */,
</span><span class="cx">                                 E157A8F018185425009F821D /* JSCryptoAlgorithmBuilder.cpp in Sources */,
</span><span class="cx">                                 E1C657121815F9DD00256CDD /* JSCryptoAlgorithmDictionary.cpp in Sources */,
</span><ins>+                                7CEF26191D6A931700BE905D /* JSCryptoCustom.cpp in Sources */,
</ins><span class="cx">                                 E157A8E01817331C009F821D /* JSCryptoKey.cpp in Sources */,
</span><span class="cx">                                 E157A8E818184C67009F821D /* JSCryptoKeyCustom.cpp in Sources */,
</span><span class="cx">                                 E1F80B8D183172B5007885C3 /* JSCryptoKeyPair.cpp in Sources */,
</span><span class="lines">@@ -28668,7 +28743,6 @@
</span><span class="cx">                                 1A750D8D0A90E521000FF215 /* JSNodeIterator.cpp in Sources */,
</span><span class="cx">                                 1A750DD40A90E729000FF215 /* JSNodeIteratorCustom.cpp in Sources */,
</span><span class="cx">                                 BCD9C2C20C17B69E005C90A2 /* JSNodeList.cpp in Sources */,
</span><del>-                                946D37301D6CB2940077084F /* CSSParserValues.cpp in Sources */,
</del><span class="cx">                                 BCD9C2650C17AA67005C90A2 /* JSNodeListCustom.cpp in Sources */,
</span><span class="cx">                                 7C91A38F1B498ABE003F9EFA /* JSNodeOrString.cpp in Sources */,
</span><span class="cx">                                 33503CA310179AD7003B47E1 /* JSNotification.cpp in Sources */,
</span><span class="lines">@@ -29084,7 +29158,6 @@
</span><span class="cx">                                 FABE72F41059C1EB00D999DD /* MathMLElement.cpp in Sources */,
</span><span class="cx">                                 FABE72FD1059C21100D999DD /* MathMLElementFactory.cpp in Sources */,
</span><span class="cx">                                 0BCF83F61059C1EB00D999DD /* MathMLFractionElement.cpp in Sources */,
</span><del>-                                FABE72F61059C1EB00D999DD /* MathMLPresentationElement.cpp in Sources */,
</del><span class="cx">                                 FABE72F81059C1EB00D999DD /* MathMLMathElement.cpp in Sources */,
</span><span class="cx">                                 05D913CEEAB2A60534218ACF /* MathMLMencloseElement.cpp in Sources */,
</span><span class="cx">                                 FABE72FE1059C21100D999DD /* MathMLNames.cpp in Sources */,
</span><span class="lines">@@ -29091,12 +29164,13 @@
</span><span class="cx">                                 16EA24CEEAB2A60534218ACF /* MathMLOperatorDictionary.cpp in Sources */,
</span><span class="cx">                                 FA654A6B1108ABED002616F1 /* MathMLOperatorElement.cpp in Sources */,
</span><span class="cx">                                 B59CA390CED66C3255F72C59 /* MathMLPaddedElement.cpp in Sources */,
</span><ins>+                                FABE72F61059C1EB00D999DD /* MathMLPresentationElement.cpp in Sources */,
+                                FA765A6B1108ABED002615E0 /* MathMLRowElement.cpp in Sources */,
</ins><span class="cx">                                 B59CA390CED66C3255F72B48 /* MathMLScriptsElement.cpp in Sources */,
</span><span class="cx">                                 FED48390CED66C3255F72C59 /* MathMLSelectElement.cpp in Sources */,
</span><span class="cx">                                 4FA65A6B1108ABED002615E0 /* MathMLSpaceElement.cpp in Sources */,
</span><span class="cx">                                 439176DF12DA25E17BAF80A2 /* MathMLStyle.cpp in Sources */,
</span><span class="cx">                                 FA654A6B1108ABED002615E0 /* MathMLTokenElement.cpp in Sources */,
</span><del>-                                FA765A6B1108ABED002615E0 /* MathMLRowElement.cpp in Sources */,
</del><span class="cx">                                 FA654A6B1108ABED002626F1 /* MathMLUnderOverElement.cpp in Sources */,
</span><span class="cx">                                 439046E912DA25E812AF80AC /* MathOperator.cpp in Sources */,
</span><span class="cx">                                 49D5DC2B0F423A73008F20FD /* Matrix3DTransformOperation.cpp in Sources */,
</span><span class="lines">@@ -29198,6 +29272,8 @@
</span><span class="cx">                                 C53D39341C978A45007F3AE9 /* MIMETypeRegistryCocoa.mm in Sources */,
</span><span class="cx">                                 52F10865162B6DA4009AC81E /* MixedContentChecker.cpp in Sources */,
</span><span class="cx">                                 CDF2B0101820540600F2B424 /* MockBox.cpp in Sources */,
</span><ins>+                                51058ADF1D67C229009A538C /* MockGamepad.cpp in Sources */,
+                                51058AE11D67C229009A538C /* MockGamepadProvider.cpp in Sources */,
</ins><span class="cx">                                 5EA3D6E01C859D8400300BBB /* MockMediaEndpoint.cpp in Sources */,
</span><span class="cx">                                 CDF2B0121820540600F2B424 /* MockMediaPlayerMediaSource.cpp in Sources */,
</span><span class="cx">                                 CDF2B0141820540600F2B424 /* MockMediaSourcePrivate.cpp in Sources */,
</span><span class="lines">@@ -29240,7 +29316,6 @@
</span><span class="cx">                                 443F04270E75C8FB007E5407 /* NetworkStateNotifierIOS.mm in Sources */,
</span><span class="cx">                                 1A7FA6490DDA3CBA0028F8A5 /* NetworkStateNotifierMac.cpp in Sources */,
</span><span class="cx">                                 5C3C856D1D5A7ADE0088B9EC /* NetworkStorageSession.cpp in Sources */,
</span><del>-                                51058ADF1D67C229009A538C /* MockGamepad.cpp in Sources */,
</del><span class="cx">                                 E13EF34916850C470034C83F /* NetworkStorageSessionCFNet.cpp in Sources */,
</span><span class="cx">                                 269397261A4A5FBD00E8349D /* NFA.cpp in Sources */,
</span><span class="cx">                                 267726001A5B3AD9003C24DD /* NFAToDFA.cpp in Sources */,
</span><span class="lines">@@ -29274,7 +29349,6 @@
</span><span class="cx">                                 FDA9325D16703B2A008982DC /* OfflineAudioContext.cpp in Sources */,
</span><span class="cx">                                 FDA3E95B134A49EF008D4B5A /* OfflineAudioDestinationNode.cpp in Sources */,
</span><span class="cx">                                 B2D3DA640D006CD600EF6F3A /* OpenTypeCG.cpp in Sources */,
</span><del>-                                51058AE11D67C229009A538C /* MockGamepadProvider.cpp in Sources */,
</del><span class="cx">                                 B2D3DA640D006CD600EF6F27 /* OpenTypeMathData.cpp in Sources */,
</span><span class="cx">                                 CDE7FC44181904B1002BBB77 /* OrderIterator.cpp in Sources */,
</span><span class="cx">                                 0014628A103CD1DE000B20DB /* OriginAccessEntry.cpp in Sources */,
</span><span class="lines">@@ -29333,7 +29407,6 @@
</span><span class="cx">                                 0F43C85D189E10CF00019AE2 /* PerformanceTiming.cpp in Sources */,
</span><span class="cx">                                 FD581FB41520F93B003A7A75 /* PeriodicWave.cpp in Sources */,
</span><span class="cx">                                 49D5DC2D0F423A73008F20FD /* PerspectiveTransformOperation.cpp in Sources */,
</span><del>-                                946D37331D6CC42B0077084F /* SVGCSSParser.cpp in Sources */,
</del><span class="cx">                                 D0FF2A5D11F8C45A007E74E0 /* PingLoader.cpp in Sources */,
</span><span class="cx">                                 CD7D33431C7A123F00041293 /* PixelBufferConformerCV.cpp in Sources */,
</span><span class="cx">                                 0FDF45A71BD1C6FD00E4FA8C /* PlatformCAAnimation.cpp in Sources */,
</span><span class="lines">@@ -29751,7 +29824,6 @@
</span><span class="cx">                                 93309E15099E64920056E581 /* SplitTextNodeContainingElementCommand.cpp in Sources */,
</span><span class="cx">                                 A1E1154813015C5D0054AC8C /* SpotLightSource.cpp in Sources */,
</span><span class="cx">                                 97BC6A3E1505F081001B74AC /* SQLException.cpp in Sources */,
</span><del>-                                7CEF26191D6A931700BE905D /* JSCryptoCustom.cpp in Sources */,
</del><span class="cx">                                 1A2E6E7A0CC556D5004A2062 /* SQLiteAuthorizer.cpp in Sources */,
</span><span class="cx">                                 1A2246490CC98DDB00C05240 /* SQLiteDatabase.cpp in Sources */,
</span><span class="cx">                                 7E474E2012494DC900235364 /* SQLiteDatabaseTracker.cpp in Sources */,
</span><span class="lines">@@ -29866,6 +29938,7 @@
</span><span class="cx">                                 B22279A10D00BF220071B782 /* SVGColor.cpp in Sources */,
</span><span class="cx">                                 B22279A40D00BF220071B782 /* SVGComponentTransferFunctionElement.cpp in Sources */,
</span><span class="cx">                                 B2227B050D00BFF10071B782 /* SVGCSSComputedStyleDeclaration.cpp in Sources */,
</span><ins>+                                946D37331D6CC42B0077084F /* SVGCSSParser.cpp in Sources */,
</ins><span class="cx">                                 B22279A70D00BF220071B782 /* SVGCursorElement.cpp in Sources */,
</span><span class="cx">                                 B22279AD0D00BF220071B782 /* SVGDefsElement.cpp in Sources */,
</span><span class="cx">                                 B22279B00D00BF220071B782 /* SVGDescElement.cpp in Sources */,
</span><span class="lines">@@ -30068,7 +30141,6 @@
</span><span class="cx">                                 7AA3A699194A64E7001CBD24 /* TileController.cpp in Sources */,
</span><span class="cx">                                 1F72BF0A187FD4490009BCB3 /* TileControllerMemoryHandlerIOS.cpp in Sources */,
</span><span class="cx">                                 7AA3A6A3194B5C22001CBD24 /* TileCoverageMap.cpp in Sources */,
</span><del>-                                946D372D1D6CB2940077084F /* CSSParser.cpp in Sources */,
</del><span class="cx">                                 7AA3A69B194A64E7001CBD24 /* TileGrid.cpp in Sources */,
</span><span class="cx">                                 498770F21242C535002226BA /* TilingData.cpp in Sources */,
</span><span class="cx">                                 F55B3DDB1251F12D003EF269 /* TimeInputType.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSAllInOnecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSAllInOne.cpp (205102 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSAllInOne.cpp        2016-08-28 14:45:43 UTC (rev 205102)
+++ trunk/Source/WebCore/css/CSSAllInOne.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -62,9 +62,9 @@
</span><span class="cx"> #include &quot;CSSKeyframeRule.cpp&quot;
</span><span class="cx"> #include &quot;CSSKeyframesRule.cpp&quot;
</span><span class="cx"> #include &quot;CSSLineBoxContainValue.cpp&quot;
</span><ins>+#include &quot;CSSMarkup.cpp&quot;
</ins><span class="cx"> #include &quot;CSSMediaRule.cpp&quot;
</span><span class="cx"> #include &quot;CSSNamedImageValue.cpp&quot;
</span><del>-#include &quot;CSSOMUtils.cpp&quot;
</del><span class="cx"> #include &quot;CSSPageRule.cpp&quot;
</span><span class="cx"> #include &quot;CSSParser.cpp&quot;
</span><span class="cx"> #include &quot;CSSParserValues.cpp&quot;
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSMarkupcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/CSSMarkup.cpp (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSMarkup.cpp                                (rev 0)
+++ trunk/Source/WebCore/css/CSSMarkup.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,158 @@
</span><ins>+/*
+ * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2004-2012, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Nicholas Shanks &lt;webkit@nickshanks.com&gt;
+ * Copyright (C) 2008 Eric Seidel &lt;eric@webkit.org&gt;
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;CSSMarkup.h&quot;
+
+#include &quot;CSSParserIdioms.h&quot;
+#include &lt;wtf/HexNumber.h&gt;
+#include &lt;wtf/text/StringBuffer.h&gt;
+#include &lt;wtf/text/StringBuilder.h&gt;
+
+namespace WebCore {
+
+template &lt;typename CharacterType&gt;
+static inline bool isCSSTokenizerIdentifier(const CharacterType* characters, unsigned length)
+{
+    const CharacterType* end = characters + length;
+
+    // -?
+    if (characters != end &amp;&amp; characters[0] == '-')
+        ++characters;
+
+    // {nmstart}
+    if (characters == end || !isNameStartCodePoint(characters[0]))
+        return false;
+    ++characters;
+
+    // {nmchar}*
+    for (; characters != end; ++characters) {
+        if (!isNameCodePoint(characters[0]))
+            return false;
+    }
+
+    return true;
+}
+
+// &quot;ident&quot; from the CSS tokenizer, minus backslash-escape sequences
+static bool isCSSTokenizerIdentifier(const String&amp; string)
+{
+    unsigned length = string.length();
+
+    if (!length)
+        return false;
+
+    if (string.is8Bit())
+        return isCSSTokenizerIdentifier(string.characters8(), length);
+    return isCSSTokenizerIdentifier(string.characters16(), length);
+}
+
+static void serializeCharacter(UChar32 c, StringBuilder&amp; appendTo)
+{
+    appendTo.append('\\');
+    appendTo.append(c);
+}
+
+static void serializeCharacterAsCodePoint(UChar32 c, StringBuilder&amp; appendTo)
+{
+    appendTo.append('\\');
+    appendUnsignedAsHex(c, appendTo, Lowercase);
+    appendTo.append(' ');
+}
+
+void serializeIdentifier(const String&amp; identifier, StringBuilder&amp; appendTo, bool skipStartChecks)
+{
+    bool isFirst = !skipStartChecks;
+    bool isSecond = false;
+    bool isFirstCharHyphen = false;
+    unsigned index = 0;
+    while (index &lt; identifier.length()) {
+        UChar32 c = identifier.characterStartingAt(index);
+        if (!c) {
+            // Check for lone surrogate which characterStartingAt does not return.
+            c = identifier[index];
+        }
+
+        index += U16_LENGTH(c);
+
+        if (!c)
+            appendTo.append(0xfffd);
+        else if (c &lt;= 0x1f || c == 0x7f || (0x30 &lt;= c &amp;&amp; c &lt;= 0x39 &amp;&amp; (isFirst || (isSecond &amp;&amp; isFirstCharHyphen))))
+            serializeCharacterAsCodePoint(c, appendTo);
+        else if (c == 0x2d &amp;&amp; isFirst &amp;&amp; index == identifier.length())
+            serializeCharacter(c, appendTo);
+        else if (0x80 &lt;= c || c == 0x2d || c == 0x5f || (0x30 &lt;= c &amp;&amp; c &lt;= 0x39) || (0x41 &lt;= c &amp;&amp; c &lt;= 0x5a) || (0x61 &lt;= c &amp;&amp; c &lt;= 0x7a))
+            appendTo.append(c);
+        else
+            serializeCharacter(c, appendTo);
+
+        if (isFirst) {
+            isFirst = false;
+            isSecond = true;
+            isFirstCharHyphen = (c == 0x2d);
+        } else if (isSecond)
+            isSecond = false;
+    }
+}
+
+void serializeString(const String&amp; string, StringBuilder&amp; appendTo)
+{
+    appendTo.append('\&quot;');
+
+    unsigned index = 0;
+    while (index &lt; string.length()) {
+        UChar32 c = string.characterStartingAt(index);
+        index += U16_LENGTH(c);
+
+        if (c &lt;= 0x1f || c == 0x7f)
+            serializeCharacterAsCodePoint(c, appendTo);
+        else if (c == 0x22 || c == 0x5c)
+            serializeCharacter(c, appendTo);
+        else
+            appendTo.append(c);
+    }
+
+    appendTo.append('\&quot;');
+}
+
+String serializeString(const String&amp; string)
+{
+    StringBuilder builder;
+    serializeString(string, builder);
+    return builder.toString();
+}
+
+String serializeURI(const String&amp; string)
+{
+    return &quot;url(&quot; + serializeString(string) + &quot;)&quot;;
+}
+
+String serializeFontFamily(const String&amp; string)
+{
+    return isCSSTokenizerIdentifier(string) ? string : serializeString(string);
+}
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorecssCSSMarkuph"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/CSSMarkup.h (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSMarkup.h                                (rev 0)
+++ trunk/Source/WebCore/css/CSSMarkup.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+/*
+ * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2004-2008, 2009-2010, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Eric Seidel &lt;eric@webkit.org&gt;
+ * Copyright (C) 2009 - 2010  Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef CSSMarkup_h
+#define CSSMarkup_h
+
+#include &lt;wtf/text/WTFString.h&gt;
+
+// Helper functions for converting from CSSValues to text.
+
+namespace WebCore {
+
+// Common serializing methods. See: http://dev.w3.org/csswg/cssom/#common-serializing-idioms
+void serializeIdentifier(const String&amp; identifier, StringBuilder&amp; appendTo, bool skipStartChecks = false);
+void serializeString(const String&amp;, StringBuilder&amp; appendTo);
+String serializeString(const String&amp;);
+String serializeURI(const String&amp;);
+String serializeFontFamily(const String&amp;);
+
+} // namespace WebCore
+
+#endif // CSSMarkup_h
</ins></span></pre></div>
<a id="trunkSourceWebCorecssCSSOMUtilscpp"></a>
<div class="delfile"><h4>Deleted: trunk/Source/WebCore/css/CSSOMUtils.cpp (205102 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSOMUtils.cpp        2016-08-28 14:45:43 UTC (rev 205102)
+++ trunk/Source/WebCore/css/CSSOMUtils.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -1,106 +0,0 @@
</span><del>-/*
- * Copyright (c) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include &quot;config.h&quot;
-#include &quot;CSSOMUtils.h&quot;
-
-#include &lt;wtf/HexNumber.h&gt;
-#include &lt;wtf/text/StringBuilder.h&gt;
-
-namespace WebCore {
-
-void serializeCharacter(UChar32 c, StringBuilder&amp; appendTo)
-{
-    appendTo.append('\\');
-    appendTo.append(c);
-}
-
-void serializeCharacterAsCodePoint(UChar32 c, StringBuilder&amp; appendTo)
-{
-    appendTo.append('\\');
-    appendUnsignedAsHex(c, appendTo, Lowercase);
-    appendTo.append(' ');
-}
-
-void serializeIdentifier(const String&amp; identifier, StringBuilder&amp; appendTo)
-{
-    bool isFirst = true;
-    bool isSecond = false;
-    bool isFirstCharHyphen = false;
-    unsigned index = 0;
-    while (index &lt; identifier.length()) {
-        UChar32 c = identifier.characterStartingAt(index);
-        if (!c) {
-            // Check for lone surrogate which characterStartingAt does not return.
-            c = identifier[index];
-        }
-
-        index += U16_LENGTH(c);
-
-        if (!c)
-            appendTo.append(0xfffd);
-        else if (c &lt;= 0x1f || c == 0x7f || (0x30 &lt;= c &amp;&amp; c &lt;= 0x39 &amp;&amp; (isFirst || (isSecond &amp;&amp; isFirstCharHyphen))))
-            serializeCharacterAsCodePoint(c, appendTo);
-        else if (c == 0x2d &amp;&amp; isFirst &amp;&amp; index == identifier.length())
-            serializeCharacter(c, appendTo);
-        else if (0x80 &lt;= c || c == 0x2d || c == 0x5f || (0x30 &lt;= c &amp;&amp; c &lt;= 0x39) || (0x41 &lt;= c &amp;&amp; c &lt;= 0x5a) || (0x61 &lt;= c &amp;&amp; c &lt;= 0x7a))
-            appendTo.append(c);
-        else
-            serializeCharacter(c, appendTo);
-
-        if (isFirst) {
-            isFirst = false;
-            isSecond = true;
-            isFirstCharHyphen = (c == 0x2d);
-        } else if (isSecond)
-            isSecond = false;
-    }
-}
-
-void serializeString(const String&amp; string, StringBuilder&amp; appendTo)
-{
-    appendTo.append('\&quot;');
-
-    unsigned index = 0;
-    while (index &lt; string.length()) {
-        UChar32 c = string.characterStartingAt(index);
-        index += U16_LENGTH(c);
-        if (c &lt;= 0x1f)
-            serializeCharacterAsCodePoint(c, appendTo);
-        else if (c == 0x22 || c == 0x5c)
-            serializeCharacter(c, appendTo);
-        else
-            appendTo.append(c);
-    }
-
-    appendTo.append('\&quot;');
-}
-
-} // namespace WebCore
</del></span></pre></div>
<a id="trunkSourceWebCorecssCSSOMUtilsh"></a>
<div class="delfile"><h4>Deleted: trunk/Source/WebCore/css/CSSOMUtils.h (205102 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSOMUtils.h        2016-08-28 14:45:43 UTC (rev 205102)
+++ trunk/Source/WebCore/css/CSSOMUtils.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -1,46 +0,0 @@
</span><del>-/*
- * Copyright (c) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include &lt;unicode/umachine.h&gt;
-#include &lt;wtf/Forward.h&gt;
-
-// Utilities for CSSOM http://dev.w3.org/csswg/cssom/
-
-namespace WebCore {
-
-// Common serializing methods. See: http://dev.w3.org/csswg/cssom/#common-serializing-idioms
-void serializeCharacter(UChar32, StringBuilder&amp;);
-void serializeCharacterAsCodePoint(UChar32, StringBuilder&amp;);
-void serializeIdentifier(const String&amp; identifier, StringBuilder&amp;);
-void serializeString(const String&amp;, StringBuilder&amp;);
-
-} // namespace WebCore
</del></span></pre></div>
<a id="trunkSourceWebCorecssCSSSelectorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSSelector.cpp (205102 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSSelector.cpp        2016-08-28 14:45:43 UTC (rev 205102)
+++ trunk/Source/WebCore/css/CSSSelector.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -26,7 +26,7 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;CSSSelector.h&quot;
</span><span class="cx"> 
</span><del>-#include &quot;CSSOMUtils.h&quot;
</del><ins>+#include &quot;CSSMarkup.h&quot;
</ins><span class="cx"> #include &quot;CSSSelectorList.h&quot;
</span><span class="cx"> #include &quot;HTMLNames.h&quot;
</span><span class="cx"> #include &quot;SelectorPseudoTypeMap.h&quot;
</span></span></pre></div>
<a id="trunkSourceWebCorecssDOMCSSNamespacecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/DOMCSSNamespace.cpp (205102 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/DOMCSSNamespace.cpp        2016-08-28 14:45:43 UTC (rev 205102)
+++ trunk/Source/WebCore/css/DOMCSSNamespace.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -30,7 +30,7 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;DOMCSSNamespace.h&quot;
</span><span class="cx"> 
</span><del>-#include &quot;CSSOMUtils.h&quot;
</del><ins>+#include &quot;CSSMarkup.h&quot;
</ins><span class="cx"> #include &quot;CSSParser.h&quot;
</span><span class="cx"> #include &quot;StyleProperties.h&quot;
</span><span class="cx"> #include &lt;wtf/text/StringBuilder.h&gt;
</span></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/parser/CSSParser.cpp (205102 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParser.cpp        2016-08-28 14:45:43 UTC (rev 205102)
+++ trunk/Source/WebCore/css/parser/CSSParser.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
</span><span class="cx">  * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
</span><del>- * Copyright (C) 2004-2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2004-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2007 Nicholas Shanks &lt;webkit@nickshanks.com&gt;
</span><span class="cx">  * Copyright (C) 2008 Eric Seidel &lt;eric@webkit.org&gt;
</span><span class="cx">  * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
</span><span class="lines">@@ -13707,7 +13707,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename CharacterType&gt;
</span><del>-static inline bool isCSSTokenizerIdentifier(const CharacterType* characters, unsigned length)
</del><ins>+static inline bool isCSSTokenizerIdent(const CharacterType* characters, unsigned length)
</ins><span class="cx"> {
</span><span class="cx">     const CharacterType* end = characters + length;
</span><span class="cx"> 
</span><span class="lines">@@ -13730,7 +13730,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // &quot;ident&quot; from the CSS tokenizer, minus backslash-escape sequences
</span><del>-static bool isCSSTokenizerIdentifier(const String&amp; string)
</del><ins>+static bool isCSSTokenizerIdent(const String&amp; string)
</ins><span class="cx"> {
</span><span class="cx">     unsigned length = string.length();
</span><span class="cx"> 
</span><span class="lines">@@ -13738,8 +13738,8 @@
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     if (string.is8Bit())
</span><del>-        return isCSSTokenizerIdentifier(string.characters8(), length);
-    return isCSSTokenizerIdentifier(string.characters16(), length);
</del><ins>+        return isCSSTokenizerIdent(string.characters8(), length);
+    return isCSSTokenizerIdent(string.characters16(), length);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename CharacterType&gt;
</span><span class="lines">@@ -13853,7 +13853,7 @@
</span><span class="cx"> 
</span><span class="cx"> String quoteCSSStringIfNeeded(const String&amp; string)
</span><span class="cx"> {
</span><del>-    return isCSSTokenizerIdentifier(string) ? string : quoteCSSString(string);
</del><ins>+    return isCSSTokenizerIdent(string) ? string : quoteCSSString(string);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> String quoteCSSURLIfNeeded(const String&amp; string)
</span></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserFastPathscpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSParserFastPaths.cpp (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserFastPaths.cpp                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSParserFastPaths.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,1118 @@
</span><ins>+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include &quot;config.h&quot;
+#include &quot;CSSParserFastPaths.h&quot;
+
+// FIXME-NEWPARSER: #include &quot;CSSColorValue.h&quot;
+#include &quot;CSSFunctionValue.h&quot;
+#include &quot;CSSInheritedValue.h&quot;
+#include &quot;CSSInitialValue.h&quot;
+#include &quot;CSSParserIdioms.h&quot;
+#include &quot;CSSPrimitiveValue.h&quot;
+#include &quot;CSSPropertyParser.h&quot;
+#include &quot;HTMLParserIdioms.h&quot;
+#include &quot;RuntimeEnabledFeatures.h&quot;
+// FIXME-NEWPARSER: #include &quot;StyleColor.h&quot;
+#include &quot;StylePropertyShorthand.h&quot;
+
+namespace WebCore {
+
+/* FIXME-NEWPARSER: Turn off for now.

+static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool&amp; acceptsNegativeNumbers)
+{
+    switch (propertyId) {
+    case CSSPropertyFontSize:
+    case CSSPropertyGridColumnGap:
+    case CSSPropertyGridRowGap:
+    case CSSPropertyHeight:
+    case CSSPropertyWidth:
+    case CSSPropertyMinHeight:
+    case CSSPropertyMinWidth:
+    case CSSPropertyPaddingBottom:
+    case CSSPropertyPaddingLeft:
+    case CSSPropertyPaddingRight:
+    case CSSPropertyPaddingTop:
+    case CSSPropertyWebkitLogicalWidth:
+    case CSSPropertyWebkitLogicalHeight:
+    case CSSPropertyWebkitMinLogicalWidth:
+    case CSSPropertyWebkitMinLogicalHeight:
+    case CSSPropertyWebkitPaddingAfter:
+    case CSSPropertyWebkitPaddingBefore:
+    case CSSPropertyWebkitPaddingEnd:
+    case CSSPropertyWebkitPaddingStart:
+  //  case CSSPropertyShapeMargin:
+    case CSSPropertyR:
+    case CSSPropertyRx:
+    case CSSPropertyRy:
+        acceptsNegativeNumbers = false;
+        return true;
+    case CSSPropertyBottom:
+    case CSSPropertyCx:
+    case CSSPropertyCy:
+    case CSSPropertyLeft:
+    case CSSPropertyMarginBottom:
+    case CSSPropertyMarginLeft:
+    case CSSPropertyMarginRight:
+    case CSSPropertyMarginTop:
+ //   case CSSPropertyMotionOffset:
+    case CSSPropertyRight:
+    case CSSPropertyTop:
+    case CSSPropertyWebkitMarginAfter:
+    case CSSPropertyWebkitMarginBefore:
+    case CSSPropertyWebkitMarginEnd:
+    case CSSPropertyWebkitMarginStart:
+    case CSSPropertyX:
+    case CSSPropertyY:
+        acceptsNegativeNumbers = true;
+        return true;
+    default:
+        return false;
+    }
+}
+
+template &lt;typename CharacterType&gt;
+static inline bool parseSimpleLength(const CharacterType* characters, unsigned length, CSSPrimitiveValue::UnitTypes&amp; unit, double&amp; number)
+{
+    if (length &gt; 2 &amp;&amp; (characters[length - 2] | 0x20) == 'p' &amp;&amp; (characters[length - 1] | 0x20) == 'x') {
+        length -= 2;
+        unit = CSSPrimitiveValue::UnitTypes::CSS_PX;
+    } else if (length &gt; 1 &amp;&amp; characters[length - 1] == '%') {
+        length -= 1;
+        unit = CSSPrimitiveValue::UnitTypes::CSS_PERCENTAGE;
+    }
+
+    // We rely on charactersToDouble for validation as well. The function
+    // will set &quot;ok&quot; to &quot;false&quot; if the entire passed-in character range does
+    // not represent a double.
+    bool ok;
+    number = charactersToDouble(characters, length, &amp;ok);
+    if (!ok)
+        return false;
+    number = clampTo&lt;double&gt;(number, -std::numeric_limits&lt;float&gt;::max(), std::numeric_limits&lt;float&gt;::max());
+    return true;
+}
+
+static CSSValue* parseSimpleLengthValue(CSSPropertyID propertyId, const String&amp; string, CSSParserMode cssParserMode)
+{
+    ASSERT(!string.isEmpty());
+    bool acceptsNegativeNumbers = false;
+
+    // In @viewport, width and height are shorthands, not simple length values.
+    if (isCSSViewportParsingEnabledForMode(cssParserMode) || !isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
+        return nullptr;
+
+    unsigned length = string.length();
+    double number;
+    CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::UnitTypes::Number;
+
+    if (string.is8Bit()) {
+        if (!parseSimpleLength(string.characters8(), length, unit, number))
+            return nullptr;
+    } else {
+        if (!parseSimpleLength(string.characters16(), length, unit, number))
+            return nullptr;
+    }
+
+    if (unit == CSSPrimitiveValue::UnitTypes::Number) {
+        if (cssParserMode == SVGAttributeMode)
+            unit = CSSPrimitiveValue::UnitTypes::UserUnits;
+        else if (!number)
+            unit = CSSPrimitiveValue::UnitTypes::Pixels;
+        else
+            return nullptr;
+    }
+
+    if (number &lt; 0 &amp;&amp; !acceptsNegativeNumbers)
+        return nullptr;
+
+    return CSSPrimitiveValue::create(number, unit);
+}
+
+static inline bool isColorPropertyID(CSSPropertyID propertyId)
+{
+    switch (propertyId) {
+    case CSSPropertyColor:
+    case CSSPropertyBackgroundColor:
+    case CSSPropertyBorderBottomColor:
+    case CSSPropertyBorderLeftColor:
+    case CSSPropertyBorderRightColor:
+    case CSSPropertyBorderTopColor:
+    case CSSPropertyFill:
+    case CSSPropertyFloodColor:
+    case CSSPropertyLightingColor:
+    case CSSPropertyOutlineColor:
+    case CSSPropertyStopColor:
+    case CSSPropertyStroke:
+    case CSSPropertyWebkitBorderAfterColor:
+    case CSSPropertyWebkitBorderBeforeColor:
+    case CSSPropertyWebkitBorderEndColor:
+    case CSSPropertyWebkitBorderStartColor:
+    case CSSPropertyColumnRuleColor:
+    case CSSPropertyWebkitTextEmphasisColor:
+    case CSSPropertyWebkitTextFillColor:
+    case CSSPropertyWebkitTextStrokeColor:
+    case CSSPropertyTextDecorationColor:
+        return true;
+    default:
+        return false;
+    }
+}
+
+// Returns the number of characters which form a valid double
+// and are terminated by the given terminator character
+template &lt;typename CharacterType&gt;
+static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
+{
+    int length = end - string;
+    if (length &lt; 1)
+        return 0;
+
+    bool decimalMarkSeen = false;
+    int processedLength = 0;
+
+    for (int i = 0; i &lt; length; ++i) {
+        if (string[i] == terminator) {
+            processedLength = i;
+            break;
+        }
+        if (!isASCIIDigit(string[i])) {
+            if (!decimalMarkSeen &amp;&amp; string[i] == '.')
+                decimalMarkSeen = true;
+            else
+                return 0;
+        }
+    }
+
+    if (decimalMarkSeen &amp;&amp; processedLength == 1)
+        return 0;
+
+    return processedLength;
+}
+
+// Returns the number of characters consumed for parsing a valid double
+// terminated by the given terminator character
+template &lt;typename CharacterType&gt;
+static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double&amp; value)
+{
+    int length = checkForValidDouble(string, end, terminator);
+    if (!length)
+        return 0;
+
+    int position = 0;
+    double localValue = 0;
+
+    // The consumed characters here are guaranteed to be
+    // ASCII digits with or without a decimal mark
+    for (; position &lt; length; ++position) {
+        if (string[position] == '.')
+            break;
+        localValue = localValue * 10 + string[position] - '0';
+    }
+
+    if (++position == length) {
+        value = localValue;
+        return length;
+    }
+
+    double fraction = 0;
+    double scale = 1;
+
+    const double maxScale = 1000000;
+    while (position &lt; length &amp;&amp; scale &lt; maxScale) {
+        fraction = fraction * 10 + string[position++] - '0';
+        scale *= 10;
+    }
+
+    value = localValue + fraction / scale;
+    return length;
+}
+
+template &lt;typename CharacterType&gt;
+static bool parseColorIntOrPercentage(const CharacterType*&amp; string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes&amp; expect, int&amp; value)
+{
+    const CharacterType* current = string;
+    double localValue = 0;
+    bool negative = false;
+    while (current != end &amp;&amp; isHTMLSpace&lt;CharacterType&gt;(*current))
+        current++;
+    if (current != end &amp;&amp; *current == '-') {
+        negative = true;
+        current++;
+    }
+    if (current == end || !isASCIIDigit(*current))
+        return false;
+    while (current != end &amp;&amp; isASCIIDigit(*current)) {
+        double newValue = localValue * 10 + *current++ - '0';
+        if (newValue &gt;= 255) {
+            // Clamp values at 255.
+            localValue = 255;
+            while (current != end &amp;&amp; isASCIIDigit(*current))
+                ++current;
+            break;
+        }
+        localValue = newValue;
+    }
+
+    if (current == end)
+        return false;
+
+    if (expect == CSSPrimitiveValue::UnitTypes::Number &amp;&amp; (*current == '.' || *current == '%'))
+        return false;
+
+    if (*current == '.') {
+        // We already parsed the integral part, try to parse
+        // the fraction part of the percentage value.
+        double percentage = 0;
+        int numCharactersParsed = parseDouble(current, end, '%', percentage);
+        if (!numCharactersParsed)
+            return false;
+        current += numCharactersParsed;
+        if (*current != '%')
+            return false;
+        localValue += percentage;
+    }
+
+    if (expect == CSSPrimitiveValue::UnitTypes::Percentage &amp;&amp; *current != '%')
+        return false;
+
+    if (*current == '%') {
+        expect = CSSPrimitiveValue::UnitTypes::Percentage;
+        localValue = localValue / 100.0 * 256.0;
+        // Clamp values at 255 for percentages over 100%
+        if (localValue &gt; 255)
+            localValue = 255;
+        current++;
+    } else {
+        expect = CSSPrimitiveValue::UnitTypes::Number;
+    }
+
+    while (current != end &amp;&amp; isHTMLSpace&lt;CharacterType&gt;(*current))
+        current++;
+    if (current == end || *current++ != terminator)
+        return false;
+    // Clamp negative values at zero.
+    value = negative ? 0 : static_cast&lt;int&gt;(localValue);
+    string = current;
+    return true;
+}
+
+template &lt;typename CharacterType&gt;
+static inline bool isTenthAlpha(const CharacterType* string, const int length)
+{
+    // &quot;0.X&quot;
+    if (length == 3 &amp;&amp; string[0] == '0' &amp;&amp; string[1] == '.' &amp;&amp; isASCIIDigit(string[2]))
+        return true;
+
+    // &quot;.X&quot;
+    if (length == 2 &amp;&amp; string[0] == '.' &amp;&amp; isASCIIDigit(string[1]))
+        return true;
+
+    return false;
+}
+
+template &lt;typename CharacterType&gt;
+static inline bool parseAlphaValue(const CharacterType*&amp; string, const CharacterType* end, const char terminator, int&amp; value)
+{
+    while (string != end &amp;&amp; isHTMLSpace&lt;CharacterType&gt;(*string))
+        string++;
+
+    bool negative = false;
+
+    if (string != end &amp;&amp; *string == '-') {
+        negative = true;
+        string++;
+    }
+
+    value = 0;
+
+    int length = end - string;
+    if (length &lt; 2)
+        return false;
+
+    if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
+        return false;
+
+    if (string[0] != '0' &amp;&amp; string[0] != '1' &amp;&amp; string[0] != '.') {
+        if (checkForValidDouble(string, end, terminator)) {
+            value = negative ? 0 : 255;
+            string = end;
+            return true;
+        }
+        return false;
+    }
+
+    if (length == 2 &amp;&amp; string[0] != '.') {
+        value = !negative &amp;&amp; string[0] == '1' ? 255 : 0;
+        string = end;
+        return true;
+    }
+
+    if (isTenthAlpha(string, length - 1)) {
+        static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
+        value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
+        string = end;
+        return true;
+    }
+
+    double alpha = 0;
+    if (!parseDouble(string, end, terminator, alpha))
+        return false;
+    value = negative ? 0 : static_cast&lt;int&gt;(alpha * nextafter(256.0, 0.0));
+    string = end;
+    return true;
+}
+
+template &lt;typename CharacterType&gt;
+static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
+{
+    if (length &lt; 5)
+        return false;
+    return characters[4] == '('
+        &amp;&amp; isASCIIAlphaCaselessEqual(characters[0], 'r')
+        &amp;&amp; isASCIIAlphaCaselessEqual(characters[1], 'g')
+        &amp;&amp; isASCIIAlphaCaselessEqual(characters[2], 'b')
+        &amp;&amp; isASCIIAlphaCaselessEqual(characters[3], 'a');
+}
+
+template &lt;typename CharacterType&gt;
+static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
+{
+    if (length &lt; 4)
+        return false;
+    return characters[3] == '('
+        &amp;&amp; isASCIIAlphaCaselessEqual(characters[0], 'r')
+        &amp;&amp; isASCIIAlphaCaselessEqual(characters[1], 'g')
+        &amp;&amp; isASCIIAlphaCaselessEqual(characters[2], 'b');
+}
+
+template &lt;typename CharacterType&gt;
+static bool fastParseColorInternal(RGBA32&amp; rgb, const CharacterType* characters, unsigned length, bool quirksMode)
+{
+    CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::UnitTypes::Unknown;
+
+    if (length &gt;= 4 &amp;&amp; characters[0] == '#')
+        return Color::parseHexColor(characters + 1, length - 1, rgb);
+
+    if (quirksMode &amp;&amp; (length == 3 || length == 6)) {
+        if (Color::parseHexColor(characters, length, rgb))
+            return true;
+    }
+
+    // Try rgba() syntax.
+    if (mightBeRGBA(characters, length)) {
+        const CharacterType* current = characters + 5;
+        const CharacterType* end = characters + length;
+        int red;
+        int green;
+        int blue;
+        int alpha;
+
+        if (!parseColorIntOrPercentage(current, end, ',', expect, red))
+            return false;
+        if (!parseColorIntOrPercentage(current, end, ',', expect, green))
+            return false;
+        if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
+            return false;
+        if (!parseAlphaValue(current, end, ')', alpha))
+            return false;
+        if (current != end)
+            return false;
+        rgb = makeRGBA(red, green, blue, alpha);
+        return true;
+    }
+
+    // Try rgb() syntax.
+    if (mightBeRGB(characters, length)) {
+        const CharacterType* current = characters + 4;
+        const CharacterType* end = characters + length;
+        int red;
+        int green;
+        int blue;
+        if (!parseColorIntOrPercentage(current, end, ',', expect, red))
+            return false;
+        if (!parseColorIntOrPercentage(current, end, ',', expect, green))
+            return false;
+        if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
+            return false;
+        if (current != end)
+            return false;
+        rgb = makeRGB(red, green, blue);
+        return true;
+    }
+
+    return false;
+}
+
+CSSValue* CSSParserFastPaths::parseColor(const String&amp; string, CSSParserMode parserMode)
+{
+    ASSERT(!string.isEmpty());
+    CSSValueID valueID = cssValueKeywordID(string);
+    if (StyleColor::isColorKeyword(valueID)) {
+        if (!isValueAllowedInMode(valueID, parserMode))
+            return nullptr;
+        return CSSPrimitiveValue::createIdentifier(valueID);
+    }
+
+    RGBA32 color;
+    bool quirksMode = isQuirksModeBehavior(parserMode);
+
+    // Fast path for hex colors and rgb()/rgba() colors
+    bool parseResult;
+    if (string.is8Bit())
+        parseResult = fastParseColorInternal(color, string.characters8(), string.length(), quirksMode);
+    else
+        parseResult = fastParseColorInternal(color, string.characters16(), string.length(), quirksMode);
+    if (!parseResult)
+        return nullptr;
+    return CSSColorValue::create(color);
+}
+
+bool CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyID propertyId, CSSValueID valueID, CSSParserMode parserMode)
+{
+    if (valueID == CSSValueInvalid || !isValueAllowedInMode(valueID, parserMode))
+        return false;
+
+    switch (propertyId) {
+    case CSSPropertyAlignmentBaseline:
+        // auto | baseline | before-edge | text-before-edge | middle |
+        // central | after-edge | text-after-edge | ideographic | alphabetic |
+        // hanging | mathematical
+        return valueID == CSSValueAuto || valueID == CSSValueAlphabetic || valueID == CSSValueBaseline
+            || valueID == CSSValueMiddle || (valueID &gt;= CSSValueBeforeEdge &amp;&amp; valueID &lt;= CSSValueMathematical);
+    case CSSPropertyAll:
+        return false; // Only accepts css-wide keywords
+    case CSSPropertyBackgroundRepeatX: // repeat | no-repeat
+    case CSSPropertyBackgroundRepeatY: // repeat | no-repeat
+        return valueID == CSSValueRepeat || valueID == CSSValueNoRepeat;
+    case CSSPropertyBorderCollapse: // collapse | separate
+        return valueID == CSSValueCollapse || valueID == CSSValueSeparate;
+    case CSSPropertyBorderTopStyle: // &lt;border-style&gt;
+    case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
+    case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
+    case CSSPropertyBorderLeftStyle:
+    case CSSPropertyWebkitBorderAfterStyle:
+    case CSSPropertyWebkitBorderBeforeStyle:
+    case CSSPropertyWebkitBorderEndStyle:
+    case CSSPropertyWebkitBorderStartStyle:
+    case CSSPropertyColumnRuleStyle:
+        return valueID &gt;= CSSValueNone &amp;&amp; valueID &lt;= CSSValueDouble;
+    case CSSPropertyBoxSizing:
+        return valueID == CSSValueBorderBox || valueID == CSSValueContentBox;
+    case CSSPropertyBufferedRendering:
+        return valueID == CSSValueAuto || valueID == CSSValueDynamic || valueID == CSSValueStatic;
+    case CSSPropertyCaptionSide: // top | bottom | left | right
+        return valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom;
+    case CSSPropertyClear: // none | left | right | both
+        return valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth;
+    case CSSPropertyClipRule:
+    case CSSPropertyFillRule:
+        return valueID == CSSValueNonzero || valueID == CSSValueEvenodd;
+    case CSSPropertyColorInterpolation:
+    case CSSPropertyColorInterpolationFilters:
+        return valueID == CSSValueAuto || valueID == CSSValueSRGB || valueID == CSSValueLinearRGB;
+    case CSSPropertyColorRendering:
+        return valueID == CSSValueAuto || valueID == CSSValueOptimizeSpeed || valueID == CSSValueOptimizeQuality;
+    case CSSPropertyDirection: // ltr | rtl
+        return valueID == CSSValueLtr || valueID == CSSValueRtl;
+    case CSSPropertyDisplay:
+        // inline | block | list-item | inline-block | table |
+        // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
+        // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none
+        // flex | inline-flex | -webkit-flex | -webkit-inline-flex | grid | inline-grid
+        return (valueID &gt;= CSSValueInline &amp;&amp; valueID &lt;= CSSValueInlineFlex) || valueID == CSSValueWebkitFlex || valueID == CSSValueWebkitInlineFlex || valueID == CSSValueNone
+            || (RuntimeEnabledFeatures::cssGridLayoutEnabled() &amp;&amp; (valueID == CSSValueGrid || valueID == CSSValueInlineGrid));
+    case CSSPropertyDominantBaseline:
+        // auto | use-script | no-change | reset-size | ideographic |
+        // alphabetic | hanging | mathematical | central | middle |
+        // text-after-edge | text-before-edge
+        return valueID == CSSValueAuto || valueID == CSSValueAlphabetic || valueID == CSSValueMiddle
+            || (valueID &gt;= CSSValueUseScript &amp;&amp; valueID &lt;= CSSValueResetSize)
+            || (valueID &gt;= CSSValueCentral &amp;&amp; valueID &lt;= CSSValueMathematical);
+    case CSSPropertyEmptyCells: // show | hide
+        return valueID == CSSValueShow || valueID == CSSValueHide;
+    case CSSPropertyFloat: // left | right | none
+        return valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone;
+    case CSSPropertyFontStyle: // normal | italic | oblique
+        return valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique;
+    case CSSPropertyFontStretch: // normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded
+        return valueID == CSSValueNormal || (valueID &gt;= CSSValueUltraCondensed &amp;&amp; valueID &lt;= CSSValueUltraExpanded);
+    case CSSPropertyImageRendering: // auto | optimizeContrast | pixelated
+        return valueID == CSSValueAuto || valueID == CSSValueWebkitOptimizeContrast || valueID == CSSValuePixelated;
+    case CSSPropertyIsolation: // auto | isolate
+        return valueID == CSSValueAuto || valueID == CSSValueIsolate;
+    case CSSPropertyListStylePosition: // inside | outside
+        return valueID == CSSValueInside || valueID == CSSValueOutside;
+    case CSSPropertyListStyleType:
+        // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
+        // for the list of supported list-style-types.
+        return (valueID &gt;= CSSValueDisc &amp;&amp; valueID &lt;= CSSValueKatakanaIroha) || valueID == CSSValueNone;
+    case CSSPropertyMaskType:
+        return valueID == CSSValueLuminance || valueID == CSSValueAlpha;
+    case CSSPropertyObjectFit:
+        return valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown;
+    case CSSPropertyOutlineStyle: // (&lt;border-style&gt; except hidden) | auto
+        return valueID == CSSValueAuto || valueID == CSSValueNone || (valueID &gt;= CSSValueInset &amp;&amp; valueID &lt;= CSSValueDouble);
+    case CSSPropertyOverflowAnchor:
+        return valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAuto;
+    case CSSPropertyOverflowWrap: // normal | break-word
+    case CSSPropertyWordWrap:
+        return valueID == CSSValueNormal || valueID == CSSValueBreakWord;
+    case CSSPropertyOverflowX: // visible | hidden | scroll | auto | overlay
+        return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay;
+    case CSSPropertyOverflowY: // visible | hidden | scroll | auto | overlay | -webkit-paged-x | -webkit-paged-y
+        return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY;
+    case CSSPropertyBreakAfter:
+    case CSSPropertyBreakBefore:
+        return valueID == CSSValueAuto || valueID == CSSValueAvoid || valueID == CSSValueAvoidPage || valueID == CSSValuePage || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueRecto || valueID == CSSValueVerso || valueID == CSSValueAvoidColumn || valueID == CSSValueColumn;
+    case CSSPropertyBreakInside:
+        return valueID == CSSValueAuto || valueID == CSSValueAvoid || valueID == CSSValueAvoidPage || valueID == CSSValueAvoidColumn;
+    case CSSPropertyPointerEvents:
+        // none | visiblePainted | visibleFill | visibleStroke | visible |
+        // painted | fill | stroke | auto | all | bounding-box
+        return valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID &gt;= CSSValueVisiblePainted &amp;&amp; valueID &lt;= CSSValueBoundingBox);
+    case CSSPropertyPosition: // static | relative | absolute | fixed | sticky
+        return valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed || (RuntimeEnabledFeatures::cssStickyPositionEnabled() &amp;&amp; valueID == CSSValueSticky);
+    case CSSPropertyResize: // none | both | horizontal | vertical | auto
+        return valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto;
+    case CSSPropertyScrollBehavior: // auto | smooth
+        ASSERT(RuntimeEnabledFeatures::cssomSmoothScrollEnabled());
+        return valueID == CSSValueAuto || valueID == CSSValueSmooth;
+    case CSSPropertyShapeRendering:
+        return valueID == CSSValueAuto || valueID == CSSValueOptimizeSpeed || valueID == CSSValueCrispEdges || valueID == CSSValueGeometricPrecision;
+    case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation
+        return valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation;
+    case CSSPropertyStrokeLinejoin:
+        return valueID == CSSValueMiter || valueID == CSSValueRound || valueID == CSSValueBevel;
+    case CSSPropertyStrokeLinecap:
+        return valueID == CSSValueButt || valueID == CSSValueRound || valueID == CSSValueSquare;
+    case CSSPropertyTableLayout: // auto | fixed
+        return valueID == CSSValueAuto || valueID == CSSValueFixed;
+    case CSSPropertyTextAlign:
+        return (valueID &gt;= CSSValueWebkitAuto &amp;&amp; valueID &lt;= CSSValueInternalCenter) || valueID == CSSValueStart || valueID == CSSValueEnd;
+    case CSSPropertyTextAlignLast:
+        // auto | start | end | left | right | center | justify
+        return (valueID &gt;= CSSValueLeft &amp;&amp; valueID &lt;= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto;
+    case CSSPropertyTextAnchor:
+        return valueID == CSSValueStart || valueID == CSSValueMiddle || valueID == CSSValueEnd;
+    case CSSPropertyTextCombineUpright:
+        return valueID == CSSValueNone || valueID == CSSValueAll;
+    case CSSPropertyTextDecorationStyle:
+        // solid | double | dotted | dashed | wavy
+        ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
+        return valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDotted || valueID == CSSValueDashed || valueID == CSSValueWavy;
+    case CSSPropertyTextJustify:
+        // auto | none | inter-word | distribute
+        ASSERT(RuntimeEnabledFeatures::css3TextEnabled());
+        return valueID == CSSValueInterWord || valueID == CSSValueDistribute || valueID == CSSValueAuto || valueID == CSSValueNone;
+    case CSSPropertyTextOrientation: // mixed | upright | sideways | sideways-right
+        return valueID == CSSValueMixed || valueID == CSSValueUpright || valueID == CSSValueSideways || valueID == CSSValueSidewaysRight;
+    case CSSPropertyWebkitTextOrientation:
+        return valueID == CSSValueSideways || valueID == CSSValueSidewaysRight || valueID == CSSValueVerticalRight || valueID == CSSValueUpright;
+    case CSSPropertyTextOverflow: // clip | ellipsis
+        return valueID == CSSValueClip || valueID == CSSValueEllipsis;
+    case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
+        return valueID == CSSValueAuto || valueID == CSSValueOptimizeSpeed || valueID == CSSValueOptimizeLegibility || valueID == CSSValueGeometricPrecision;
+    case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none
+        return (valueID &gt;= CSSValueCapitalize &amp;&amp; valueID &lt;= CSSValueLowercase) || valueID == CSSValueNone;
+    case CSSPropertyUnicodeBidi:
+        return valueID == CSSValueNormal || valueID == CSSValueEmbed
+            || valueID == CSSValueBidiOverride || valueID == CSSValueWebkitIsolate
+            || valueID == CSSValueWebkitIsolateOverride || valueID == CSSValueWebkitPlaintext
+            || valueID == CSSValueIsolate || valueID == CSSValueIsolateOverride || valueID == CSSValuePlaintext;
+    case CSSPropertyVectorEffect:
+        return valueID == CSSValueNone || valueID == CSSValueNonScalingStroke;
+    case CSSPropertyVisibility: // visible | hidden | collapse
+        return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse;
+    case CSSPropertyWebkitAppRegion:
+        return valueID &gt;= CSSValueDrag &amp;&amp; valueID &lt;= CSSValueNoDrag;
+    case CSSPropertyWebkitAppearance:
+        return (valueID &gt;= CSSValueCheckbox &amp;&amp; valueID &lt;= CSSValueTextarea) || valueID == CSSValueNone;
+    case CSSPropertyBackfaceVisibility:
+        return valueID == CSSValueVisible || valueID == CSSValueHidden;
+    case CSSPropertyMixBlendMode:
+        return valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen || valueID == CSSValueOverlay
+            || valueID == CSSValueDarken || valueID == CSSValueLighten || valueID == CSSValueColorDodge || valueID == CSSValueColorBurn
+            || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference || valueID == CSSValueExclusion
+            || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor || valueID == CSSValueLuminosity;
+    case CSSPropertyWebkitBoxAlign:
+        return valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline;
+    case CSSPropertyWebkitBoxDecorationBreak:
+        return valueID == CSSValueClone || valueID == CSSValueSlice;
+    case CSSPropertyWebkitBoxDirection:
+        return valueID == CSSValueNormal || valueID == CSSValueReverse;
+    case CSSPropertyWebkitBoxLines:
+        return valueID == CSSValueSingle || valueID == CSSValueMultiple;
+    case CSSPropertyWebkitBoxOrient:
+        return valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis;
+    case CSSPropertyWebkitBoxPack:
+        return valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify;
+    case CSSPropertyColumnFill:
+        return valueID == CSSValueAuto || valueID == CSSValueBalance;
+    case CSSPropertyAlignContent:
+        // FIXME: Per CSS alignment, this property should accept an optional &lt;overflow-position&gt;. We should share this parsing code with 'justify-self'.
+        return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch;
+    case CSSPropertyAlignItems:
+        // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
+        return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
+    case CSSPropertyAlignSelf:
+        // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
+        return valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
+    case CSSPropertyFlexDirection:
+        return valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse;
+    case CSSPropertyFlexWrap:
+        return valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse;
+    case CSSPropertyHyphens:
+        return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueManual;
+    case CSSPropertyJustifyContent:
+        // FIXME: Per CSS alignment, this property should accept an optional &lt;overflow-position&gt;. We should share this parsing code with 'justify-self'.
+        return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround;
+    case CSSPropertyFontKerning:
+        return valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone;
+    case CSSPropertyWebkitFontSmoothing:
+        return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased;
+    case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
+        return valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace;
+    case CSSPropertyWebkitMarginAfterCollapse:
+    case CSSPropertyWebkitMarginBeforeCollapse:
+    case CSSPropertyWebkitMarginBottomCollapse:
+    case CSSPropertyWebkitMarginTopCollapse:
+        return valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard;
+    case CSSPropertyWebkitPrintColorAdjust:
+        return valueID == CSSValueExact || valueID == CSSValueEconomy;
+    case CSSPropertyWebkitRtlOrdering:
+        return valueID == CSSValueLogical || valueID == CSSValueVisual;
+    case CSSPropertyWebkitRubyPosition:
+        return valueID == CSSValueBefore || valueID == CSSValueAfter;
+    case CSSPropertyWebkitTextCombine:
+        return valueID == CSSValueNone || valueID == CSSValueHorizontal;
+    case CSSPropertyWebkitTextEmphasisPosition:
+        return valueID == CSSValueOver || valueID == CSSValueUnder;
+    case CSSPropertyWebkitTextSecurity: // disc | circle | square | none
+        return valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone;
+    case CSSPropertyTransformStyle:
+        return valueID == CSSValueFlat || valueID == CSSValuePreserve3d;
+    case CSSPropertyWebkitUserDrag: // auto | none | element
+        return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement;
+    case CSSPropertyWebkitUserModify: // read-only | read-write
+        return valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly;
+    case CSSPropertyUserSelect: // auto | none | text | all
+        return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll;
+    case CSSPropertyWebkitWritingMode:
+        return valueID &gt;= CSSValueHorizontalTb &amp;&amp; valueID &lt;= CSSValueVerticalLr;
+    case CSSPropertyWritingMode:
+        return valueID == CSSValueHorizontalTb
+            || valueID == CSSValueVerticalRl || valueID == CSSValueVerticalLr
+            || valueID == CSSValueLrTb || valueID == CSSValueRlTb || valueID == CSSValueTbRl
+            || valueID == CSSValueLr || valueID == CSSValueRl || valueID == CSSValueTb;
+    case CSSPropertyWhiteSpace: // normal | pre | nowrap
+        return valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap;
+    case CSSPropertyWordBreak: // normal | break-all | keep-all | break-word (this is a custom extension)
+        return valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueKeepAll || valueID == CSSValueBreakWord;
+    case CSSPropertyScrollSnapType: // none | mandatory | proximity
+        ASSERT(RuntimeEnabledFeatures::cssScrollSnapPointsEnabled());
+        return valueID == CSSValueNone || valueID == CSSValueMandatory || valueID == CSSValueProximity;
+    default:
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+}
+
+bool CSSParserFastPaths::isKeywordPropertyID(CSSPropertyID propertyId)
+{
+    switch (propertyId) {
+    case CSSPropertyAlignmentBaseline:
+    case CSSPropertyAll:
+    case CSSPropertyMixBlendMode:
+    case CSSPropertyIsolation:
+    case CSSPropertyBackgroundRepeatX:
+    case CSSPropertyBackgroundRepeatY:
+    case CSSPropertyBorderBottomStyle:
+    case CSSPropertyBorderCollapse:
+    case CSSPropertyBorderLeftStyle:
+    case CSSPropertyBorderRightStyle:
+    case CSSPropertyBorderTopStyle:
+    case CSSPropertyBoxSizing:
+    case CSSPropertyBufferedRendering:
+    case CSSPropertyCaptionSide:
+    case CSSPropertyClear:
+    case CSSPropertyClipRule:
+    case CSSPropertyColorInterpolation:
+    case CSSPropertyColorInterpolationFilters:
+    case CSSPropertyColorRendering:
+    case CSSPropertyDirection:
+    case CSSPropertyDisplay:
+    case CSSPropertyDominantBaseline:
+    case CSSPropertyEmptyCells:
+    case CSSPropertyFillRule:
+    case CSSPropertyFloat:
+    case CSSPropertyFontStyle:
+    case CSSPropertyFontStretch:
+    case CSSPropertyHyphens:
+    case CSSPropertyImageRendering:
+    case CSSPropertyListStylePosition:
+    case CSSPropertyListStyleType:
+    case CSSPropertyMaskType:
+    case CSSPropertyObjectFit:
+    case CSSPropertyOutlineStyle:
+    case CSSPropertyOverflowAnchor:
+    case CSSPropertyOverflowWrap:
+    case CSSPropertyOverflowX:
+    case CSSPropertyOverflowY:
+    case CSSPropertyBreakAfter:
+    case CSSPropertyBreakBefore:
+    case CSSPropertyBreakInside:
+    case CSSPropertyPointerEvents:
+    case CSSPropertyPosition:
+    case CSSPropertyResize:
+    case CSSPropertyScrollBehavior:
+    case CSSPropertyShapeRendering:
+    case CSSPropertySpeak:
+    case CSSPropertyStrokeLinecap:
+    case CSSPropertyStrokeLinejoin:
+    case CSSPropertyTableLayout:
+    case CSSPropertyTextAlign:
+    case CSSPropertyTextAlignLast:
+    case CSSPropertyTextAnchor:
+    case CSSPropertyTextCombineUpright:
+    case CSSPropertyTextDecorationStyle:
+    case CSSPropertyTextJustify:
+    case CSSPropertyTextOrientation:
+    case CSSPropertyWebkitTextOrientation:
+    case CSSPropertyTextOverflow:
+    case CSSPropertyTextRendering:
+    case CSSPropertyTextTransform:
+    case CSSPropertyUnicodeBidi:
+    case CSSPropertyVectorEffect:
+    case CSSPropertyVisibility:
+    case CSSPropertyWebkitAppRegion:
+    case CSSPropertyWebkitAppearance:
+    case CSSPropertyBackfaceVisibility:
+    case CSSPropertyWebkitBorderAfterStyle:
+    case CSSPropertyWebkitBorderBeforeStyle:
+    case CSSPropertyWebkitBorderEndStyle:
+    case CSSPropertyWebkitBorderStartStyle:
+    case CSSPropertyWebkitBoxAlign:
+    case CSSPropertyWebkitBoxDecorationBreak:
+    case CSSPropertyWebkitBoxDirection:
+    case CSSPropertyWebkitBoxLines:
+    case CSSPropertyWebkitBoxOrient:
+    case CSSPropertyWebkitBoxPack:
+    case CSSPropertyColumnFill:
+    case CSSPropertyColumnRuleStyle:
+    case CSSPropertyFlexDirection:
+    case CSSPropertyFlexWrap:
+    case CSSPropertyFontKerning:
+    case CSSPropertyWebkitFontSmoothing:
+    case CSSPropertyWebkitLineBreak:
+    case CSSPropertyWebkitMarginAfterCollapse:
+    case CSSPropertyWebkitMarginBeforeCollapse:
+    case CSSPropertyWebkitMarginBottomCollapse:
+    case CSSPropertyWebkitMarginTopCollapse:
+    case CSSPropertyWebkitPrintColorAdjust:
+    case CSSPropertyWebkitRtlOrdering:
+    case CSSPropertyWebkitRubyPosition:
+    case CSSPropertyWebkitTextCombine:
+    case CSSPropertyWebkitTextEmphasisPosition:
+    case CSSPropertyWebkitTextSecurity:
+    case CSSPropertyTransformStyle:
+    case CSSPropertyWebkitUserDrag:
+    case CSSPropertyWebkitUserModify:
+    case CSSPropertyUserSelect:
+    case CSSPropertyWebkitWritingMode:
+    case CSSPropertyWhiteSpace:
+    case CSSPropertyWordBreak:
+    case CSSPropertyWordWrap:
+    case CSSPropertyWritingMode:
+    case CSSPropertyScrollSnapType:
+        return true;
+    case CSSPropertyJustifyContent:
+    case CSSPropertyAlignContent:
+    case CSSPropertyAlignItems:
+    case CSSPropertyAlignSelf:
+        return !RuntimeEnabledFeatures::cssGridLayoutEnabled();
+    default:
+        return false;
+    }
+}
+
+static CSSValue* parseKeywordValue(CSSPropertyID propertyId, const String&amp; string, CSSParserMode parserMode)
+{
+    ASSERT(!string.isEmpty());
+
+    if (!CSSParserFastPaths::isKeywordPropertyID(propertyId)) {
+        // All properties accept the values of &quot;initial&quot; and &quot;inherit&quot;.
+        if (!equalIgnoringASCIICase(string, &quot;initial&quot;) &amp;&amp; !equalIgnoringASCIICase(string, &quot;inherit&quot;))
+            return nullptr;
+
+        // Parse initial/inherit shorthands using the CSSPropertyParser.
+        if (shorthandForProperty(propertyId).length())
+            return nullptr;
+
+        // Descriptors do not support css wide keywords.
+        if (CSSPropertyMetadata::isDescriptorOnly(propertyId))
+            return nullptr;
+    }
+
+    CSSValueID valueID = cssValueKeywordID(string);
+
+    if (!valueID)
+        return nullptr;
+
+    if (valueID == CSSValueInherit)
+        return CSSInheritedValue::create();
+    if (valueID == CSSValueInitial)
+        return CSSInitialValue::create();
+    if (CSSParserFastPaths::isValidKeywordPropertyAndValue(propertyId, valueID, parserMode))
+        return CSSPrimitiveValue::createIdentifier(valueID);
+    return nullptr;
+}
+
+template &lt;typename CharType&gt;
+static bool parseTransformTranslateArguments(CharType*&amp; pos, CharType* end, unsigned expectedCount, CSSFunctionValue* transformValue)
+{
+    while (expectedCount) {
+        size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
+        if (delimiter == kNotFound)
+            return false;
+        unsigned argumentLength = static_cast&lt;unsigned&gt;(delimiter);
+        CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::UnitTypes::Number;
+        double number;
+        if (!parseSimpleLength(pos, argumentLength, unit, number))
+            return false;
+        if (unit != CSSPrimitiveValue::UnitTypes::Pixels &amp;&amp; (number || unit != CSSPrimitiveValue::UnitTypes::Number))
+            return false;
+        transformValue-&gt;append(*CSSPrimitiveValue::create(number, CSSPrimitiveValue::UnitTypes::Pixels));
+        pos += argumentLength + 1;
+        --expectedCount;
+    }
+    return true;
+}
+
+template &lt;typename CharType&gt;
+static bool parseTransformNumberArguments(CharType*&amp; pos, CharType* end, unsigned expectedCount, CSSFunctionValue* transformValue)
+{
+    while (expectedCount) {
+        size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
+        if (delimiter == kNotFound)
+            return false;
+        unsigned argumentLength = static_cast&lt;unsigned&gt;(delimiter);
+        bool ok;
+        double number = charactersToDouble(pos, argumentLength, &amp;ok);
+        if (!ok)
+            return false;
+        transformValue-&gt;append(*CSSPrimitiveValue::create(number, CSSPrimitiveValue::UnitTypes::Number));
+        pos += argumentLength + 1;
+        --expectedCount;
+    }
+    return true;
+}
+
+static const int kShortestValidTransformStringLength = 12;
+
+template &lt;typename CharType&gt;
+static CSSFunctionValue* parseSimpleTransformValue(CharType*&amp; pos, CharType* end)
+{
+    if (end - pos &lt; kShortestValidTransformStringLength)
+        return nullptr;
+
+    const bool isTranslate = toASCIILower(pos[0]) == 't'
+        &amp;&amp; toASCIILower(pos[1]) == 'r'
+        &amp;&amp; toASCIILower(pos[2]) == 'a'
+        &amp;&amp; toASCIILower(pos[3]) == 'n'
+        &amp;&amp; toASCIILower(pos[4]) == 's'
+        &amp;&amp; toASCIILower(pos[5]) == 'l'
+        &amp;&amp; toASCIILower(pos[6]) == 'a'
+        &amp;&amp; toASCIILower(pos[7]) == 't'
+        &amp;&amp; toASCIILower(pos[8]) == 'e';
+
+    if (isTranslate) {
+        CSSValueID transformType;
+        unsigned expectedArgumentCount = 1;
+        unsigned argumentStart = 11;
+        CharType c9 = toASCIILower(pos[9]);
+        if (c9 == 'x' &amp;&amp; pos[10] == '(') {
+            transformType = CSSValueTranslateX;
+        } else if (c9 == 'y' &amp;&amp; pos[10] == '(') {
+            transformType = CSSValueTranslateY;
+        } else if (c9 == 'z' &amp;&amp; pos[10] == '(') {
+            transformType = CSSValueTranslateZ;
+        } else if (c9 == '(') {
+            transformType = CSSValueTranslate;
+            expectedArgumentCount = 2;
+            argumentStart = 10;
+        } else if (c9 == '3' &amp;&amp; toASCIILower(pos[10]) == 'd' &amp;&amp; pos[11] == '(') {
+            transformType = CSSValueTranslate3d;
+            expectedArgumentCount = 3;
+            argumentStart = 12;
+        } else {
+            return nullptr;
+        }
+        pos += argumentStart;
+        CSSFunctionValue* transformValue = CSSFunctionValue::create(transformType);
+        if (!parseTransformTranslateArguments(pos, end, expectedArgumentCount, transformValue))
+            return nullptr;
+        return transformValue;
+    }
+
+    const bool isMatrix3d = toASCIILower(pos[0]) == 'm'
+        &amp;&amp; toASCIILower(pos[1]) == 'a'
+        &amp;&amp; toASCIILower(pos[2]) == 't'
+        &amp;&amp; toASCIILower(pos[3]) == 'r'
+        &amp;&amp; toASCIILower(pos[4]) == 'i'
+        &amp;&amp; toASCIILower(pos[5]) == 'x'
+        &amp;&amp; pos[6] == '3'
+        &amp;&amp; toASCIILower(pos[7]) == 'd'
+        &amp;&amp; pos[8] == '(';
+
+    if (isMatrix3d) {
+        pos += 9;
+        CSSFunctionValue* transformValue = CSSFunctionValue::create(CSSValueMatrix3d);
+        if (!parseTransformNumberArguments(pos, end, 16, transformValue))
+            return nullptr;
+        return transformValue;
+    }
+
+    const bool isScale3d = toASCIILower(pos[0]) == 's'
+        &amp;&amp; toASCIILower(pos[1]) == 'c'
+        &amp;&amp; toASCIILower(pos[2]) == 'a'
+        &amp;&amp; toASCIILower(pos[3]) == 'l'
+        &amp;&amp; toASCIILower(pos[4]) == 'e'
+        &amp;&amp; pos[5] == '3'
+        &amp;&amp; toASCIILower(pos[6]) == 'd'
+        &amp;&amp; pos[7] == '(';
+
+    if (isScale3d) {
+        pos += 8;
+        CSSFunctionValue* transformValue = CSSFunctionValue::create(CSSValueScale3d);
+        if (!parseTransformNumberArguments(pos, end, 3, transformValue))
+            return nullptr;
+        return transformValue;
+    }
+
+    return nullptr;
+}
+
+template &lt;typename CharType&gt;
+static bool transformCanLikelyUseFastPath(const CharType* chars, unsigned length)
+{
+    // Very fast scan that attempts to reject most transforms that couldn't
+    // take the fast path. This avoids doing the malloc and string-&gt;double
+    // conversions in parseSimpleTransformValue only to discard them when we
+    // run into a transform component we don't understand.
+    unsigned i = 0;
+    while (i &lt; length) {
+        if (isCSSSpace(chars[i])) {
+            ++i;
+            continue;
+        }
+        if (length - i &lt; kShortestValidTransformStringLength)
+            return false;
+        switch (toASCIILower(chars[i])) {
+        case 't':
+            // translate, translateX, translateY, translateZ, translate3d.
+            if (toASCIILower(chars[i + 8]) != 'e')
+                return false;
+            i += 9;
+            break;
+        case 'm':
+            // matrix3d.
+            if (toASCIILower(chars[i + 7]) != 'd')
+                return false;
+            i += 8;
+            break;
+        case 's':
+            // scale3d.
+            if (toASCIILower(chars[i + 6]) != 'd')
+                return false;
+            i += 7;
+            break;
+        default:
+            // All other things, ex. rotate.
+            return false;
+        }
+        size_t argumentsEnd = WTF::find(chars, length, ')', i);
+        if (argumentsEnd == kNotFound)
+            return false;
+        // Advance to the end of the arguments.
+        i = argumentsEnd + 1;
+    }
+    return i == length;
+}
+
+template &lt;typename CharType&gt;
+static CSSValueList* parseSimpleTransformList(const CharType* chars, unsigned length)
+{
+    if (!transformCanLikelyUseFastPath(chars, length))
+        return nullptr;
+    const CharType*&amp; pos = chars;
+    const CharType* end = chars + length;
+    CSSValueList* transformList = nullptr;
+    while (pos &lt; end) {
+        while (pos &lt; end &amp;&amp; isCSSSpace(*pos))
+            ++pos;
+        if (pos &gt;= end)
+            break;
+        CSSFunctionValue* transformValue = parseSimpleTransformValue(pos, end);
+        if (!transformValue)
+            return nullptr;
+        if (!transformList)
+            transformList = CSSValueList::createSpaceSeparated();
+        transformList-&gt;append(*transformValue);
+    }
+    return transformList;
+}
+
+static CSSValue* parseSimpleTransform(CSSPropertyID propertyID, const String&amp; string)
+{
+    ASSERT(!string.isEmpty());
+
+    if (propertyID != CSSPropertyTransform)
+        return nullptr;
+    if (string.is8Bit())
+        return parseSimpleTransformList(string.characters8(), string.length());
+    return parseSimpleTransformList(string.characters16(), string.length());
+}
+
+CSSValue* CSSParserFastPaths::maybeParseValue(CSSPropertyID propertyID, const String&amp; string, CSSParserMode parserMode)
+{
+    if (CSSValue* length = parseSimpleLengthValue(propertyID, string, parserMode))
+        return length;
+    if (isColorPropertyID(propertyID))
+        return parseColor(string, parserMode);
+    if (CSSValue* keyword = parseKeywordValue(propertyID, string, parserMode))
+        return keyword;
+    if (CSSValue* transform = parseSimpleTransform(propertyID, string))
+        return transform;
+    return nullptr;
+}
+
+     */
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserFastPathsh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSParserFastPaths.h (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserFastPaths.h                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSParserFastPaths.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,57 @@
</span><ins>+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CSSParserFastPaths_h
+#define CSSParserFastPaths_h
+
+#include &quot;CSSParserMode.h&quot;
+#include &quot;CSSPropertyNames.h&quot;
+#include &quot;CSSValueKeywords.h&quot;
+#include &lt;wtf/text/WTFString.h&gt;
+
+namespace WebCore {
+
+class CSSValue;
+
+class CSSParserFastPaths {
+public:
+    // Parses simple values like '10px' or 'green', but makes no guarantees
+    // about handling any property completely.
+    static CSSValue* maybeParseValue(CSSPropertyID, const String&amp;, CSSParserMode);
+
+    // Properties handled here shouldn't be explicitly handled in CSSPropertyParser
+    static bool isKeywordPropertyID(CSSPropertyID);
+    static bool isValidKeywordPropertyAndValue(CSSPropertyID, CSSValueID, CSSParserMode);
+
+    static CSSValue* parseColor(const String&amp;, CSSParserMode);
+};
+
+} // namespace WebCore
+
+#endif // CSSParserFastPaths_h
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserIdiomsh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSParserIdioms.h (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserIdioms.h                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSParserIdioms.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CSSParserIdioms_h
+#define CSSParserIdioms_h
+
+#include &lt;wtf/ASCIICType.h&gt;
+
+namespace WebCore {
+
+// Space characters as defined by the CSS specification.
+// http://www.w3.org/TR/css3-syntax/#whitespace
+inline bool isCSSSpace(UChar c)
+{
+    return c == ' ' || c == '\t' || c == '\n';
+}
+
+// http://dev.w3.org/csswg/css-syntax/#name-start-code-point
+template &lt;typename CharacterType&gt;
+bool isNameStartCodePoint(CharacterType c)
+{
+    return isASCIIAlpha(c) || c == '_' || !isASCII(c);
+}
+
+// http://dev.w3.org/csswg/css-syntax/#name-code-point
+template &lt;typename CharacterType&gt;
+bool isNameCodePoint(CharacterType c)
+{
+    return isNameStartCodePoint(c) || isASCIIDigit(c) || c == '-';
+}
+
+}
+
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserObserverh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSParserObserver.h (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserObserver.h                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSParserObserver.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,55 @@
</span><ins>+/*
+ * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Eric Seidel &lt;eric@webkit.org&gt;
+ * Copyright (C) 2009 - 2010  Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef CSSParserObserver_h
+#define CSSParserObserver_h
+
+#include &quot;CSSPropertySourceData.h&quot;
+#include &quot;StyleRule.h&quot;
+#include &lt;wtf/Vector.h&gt;
+
+namespace WebCore {
+
+class CSSParserToken;
+class CSSParserTokenRange;
+
+// This is only for the inspector and shouldn't be used elsewhere.
+class CSSParserObserver {
+public:
+    virtual ~CSSParserObserver() { };
+    virtual void startRuleHeader(StyleRule::Type, unsigned offset) = 0;
+    virtual void endRuleHeader(unsigned offset) = 0;
+    virtual void observeSelector(unsigned startOffset, unsigned endOffset) = 0;
+    virtual void startRuleBody(unsigned offset) = 0;
+    virtual void endRuleBody(unsigned offset) = 0;
+    virtual void observeProperty(unsigned startOffset, unsigned endOffset, bool isImportant, bool isParsed) = 0;
+    virtual void observeComment(unsigned startOffset, unsigned endOffset) = 0;
+    // FIXME: Unused, should be removed
+    virtual void startMediaQueryExp(unsigned offset) = 0;
+    virtual void endMediaQueryExp(unsigned offset) = 0;
+    virtual void startMediaQuery() = 0;
+    virtual void endMediaQuery() = 0;
+};
+
+} // namespace WebCore
+
+#endif // CSSParserObserver_h
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserObserverWrappercpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSParserObserverWrapper.cpp (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserObserverWrapper.cpp                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSParserObserverWrapper.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,72 @@
</span><ins>+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include &quot;config.h&quot;
+#include &quot;CSSParserObserverWrapper.h&quot;
+
+#include &quot;CSSParserTokenRange.h&quot;
+
+namespace WebCore {
+
+unsigned CSSParserObserverWrapper::startOffset(const CSSParserTokenRange&amp; range)
+{
+    return m_tokenOffsets[range.begin() - m_firstParserToken];
+}
+
+unsigned CSSParserObserverWrapper::previousTokenStartOffset(const CSSParserTokenRange&amp; range)
+{
+    if (range.begin() == m_firstParserToken)
+        return 0;
+    return m_tokenOffsets[range.begin() - m_firstParserToken - 1];
+}
+
+unsigned CSSParserObserverWrapper::endOffset(const CSSParserTokenRange&amp; range)
+{
+    return m_tokenOffsets[range.end() - m_firstParserToken];
+}
+
+void CSSParserObserverWrapper::skipCommentsBefore(const CSSParserTokenRange&amp; range, bool leaveDirectlyBefore)
+{
+    unsigned startIndex = range.begin() - m_firstParserToken;
+    if (!leaveDirectlyBefore)
+        startIndex++;
+    while (m_commentIterator &lt; m_commentOffsets.end() &amp;&amp; m_commentIterator-&gt;tokensBefore &lt; startIndex)
+        m_commentIterator++;
+}
+
+void CSSParserObserverWrapper::yieldCommentsBefore(const CSSParserTokenRange&amp; range)
+{
+    unsigned startIndex = range.begin() - m_firstParserToken;
+    while (m_commentIterator &lt; m_commentOffsets.end() &amp;&amp; m_commentIterator-&gt;tokensBefore &lt;= startIndex) {
+        m_observer.observeComment(m_commentIterator-&gt;startOffset, m_commentIterator-&gt;endOffset);
+        m_commentIterator++;
+    }
+}
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserObserverWrapperh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSParserObserverWrapper.h (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserObserverWrapper.h                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSParserObserverWrapper.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,80 @@
</span><ins>+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CSSParserObserverWrapper_h
+#define CSSParserObserverWrapper_h
+
+#include &quot;CSSParserObserver.h&quot;
+
+namespace WebCore {
+
+class CSSParserObserverWrapper {
+public:
+    explicit CSSParserObserverWrapper(CSSParserObserver&amp; observer)
+        : m_observer(observer)
+    { }
+
+    unsigned startOffset(const CSSParserTokenRange&amp;);
+    unsigned previousTokenStartOffset(const CSSParserTokenRange&amp;);
+    unsigned endOffset(const CSSParserTokenRange&amp;); // Includes trailing comments
+
+    void skipCommentsBefore(const CSSParserTokenRange&amp;, bool leaveDirectlyBefore);
+    void yieldCommentsBefore(const CSSParserTokenRange&amp;);
+
+    CSSParserObserver&amp; observer() { return m_observer; }
+    void addComment(unsigned startOffset, unsigned endOffset, unsigned tokensBefore)
+    {
+        CommentPosition position = {startOffset, endOffset, tokensBefore};
+        m_commentOffsets.append(position);
+    }
+    void addToken(unsigned startOffset) { m_tokenOffsets.append(startOffset); }
+    void finalizeConstruction(CSSParserToken* firstParserToken)
+    {
+        m_firstParserToken = firstParserToken;
+        m_commentIterator = m_commentOffsets.begin();
+    }
+
+private:
+    CSSParserObserver&amp; m_observer;
+    Vector&lt;unsigned&gt; m_tokenOffsets;
+    CSSParserToken* m_firstParserToken;
+
+    struct CommentPosition {
+        unsigned startOffset;
+        unsigned endOffset;
+        unsigned tokensBefore;
+    };
+
+    Vector&lt;CommentPosition&gt; m_commentOffsets;
+    Vector&lt;CommentPosition&gt;::iterator m_commentIterator;
+};
+
+} // namespace WebCore
+
+#endif // CSSParserObserverWrapper_h
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserTokencpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSParserToken.cpp (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserToken.cpp                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSParserToken.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,477 @@
</span><ins>+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include &quot;config.h&quot;
+#include &quot;CSSParserToken.h&quot;
+
+#include &quot;CSSMarkup.h&quot;
+#include &quot;CSSPrimitiveValue.h&quot;
+#include &quot;CSSPropertyParser.h&quot;
+#include &lt;limits.h&gt;
+#include &lt;wtf/HashMap.h&gt;
+#include &lt;wtf/text/StringBuilder.h&gt;
+
+namespace WebCore {
+
+template&lt;typename CharacterType&gt;
+CSSPrimitiveValue::UnitTypes cssPrimitiveValueUnitFromTrie(const CharacterType* data, unsigned length)
+{
+    ASSERT(data);
+    ASSERT(length);
+    switch (length) {
+    case 1:
+        switch (toASCIILower(data[0])) {
+        case 's':
+            return CSSPrimitiveValue::UnitTypes::CSS_S;
+        }
+        break;
+    case 2:
+        switch (toASCIILower(data[0])) {
+        case 'c':
+            switch (toASCIILower(data[1])) {
+            case 'h':
+                return CSSPrimitiveValue::UnitTypes::CSS_CHS;
+            case 'm':
+                return CSSPrimitiveValue::UnitTypes::CSS_CM;
+            }
+            break;
+        case 'e':
+            switch (toASCIILower(data[1])) {
+            case 'm':
+                return CSSPrimitiveValue::UnitTypes::CSS_EMS;
+            case 'x':
+                return CSSPrimitiveValue::UnitTypes::CSS_EXS;
+            }
+            break;
+        case 'f':
+            if (toASCIILower(data[1]) == 'r')
+                return CSSPrimitiveValue::UnitTypes::CSS_FR;
+            break;
+        case 'h':
+            if (toASCIILower(data[1]) == 'z')
+                return CSSPrimitiveValue::UnitTypes::CSS_HZ;
+            break;
+        case 'i':
+            if (toASCIILower(data[1]) == 'n')
+                return CSSPrimitiveValue::UnitTypes::CSS_IN;
+            break;
+        case 'm':
+            switch (toASCIILower(data[1])) {
+            case 'm':
+                return CSSPrimitiveValue::UnitTypes::CSS_MM;
+            case 's':
+                return CSSPrimitiveValue::UnitTypes::CSS_MS;
+            }
+            break;
+        case 'p':
+            switch (toASCIILower(data[1])) {
+            case 'c':
+                return CSSPrimitiveValue::UnitTypes::CSS_PC;
+            case 't':
+                return CSSPrimitiveValue::UnitTypes::CSS_PT;
+            case 'x':
+                return CSSPrimitiveValue::UnitTypes::CSS_PX;
+            }
+            break;
+        case 'v':
+            switch (toASCIILower(data[1])) {
+            case 'h':
+                return CSSPrimitiveValue::UnitTypes::CSS_VH;
+            case 'w':
+                return CSSPrimitiveValue::UnitTypes::CSS_VW;
+            }
+            break;
+        }
+        break;
+    case 3:
+        switch (toASCIILower(data[0])) {
+        case 'd':
+            switch (toASCIILower(data[1])) {
+            case 'e':
+                if (toASCIILower(data[2]) == 'g')
+                    return CSSPrimitiveValue::UnitTypes::CSS_DEG;
+                break;
+            case 'p':
+                if (toASCIILower(data[2]) == 'i')
+                    return CSSPrimitiveValue::UnitTypes::CSS_DPI;
+                break;
+            }
+        break;
+        case 'k':
+            if (toASCIILower(data[1]) == 'h' &amp;&amp; toASCIILower(data[2]) == 'z')
+                return CSSPrimitiveValue::UnitTypes::CSS_KHZ;
+            break;
+        case 'r':
+            switch (toASCIILower(data[1])) {
+            case 'a':
+                if (toASCIILower(data[2]) == 'd')
+                    return CSSPrimitiveValue::UnitTypes::CSS_RAD;
+                break;
+            case 'e':
+                if (toASCIILower(data[2]) == 'm')
+                    return CSSPrimitiveValue::UnitTypes::CSS_REMS;
+                break;
+            }
+        break;
+    }
+    break;
+    case 4:
+        switch (toASCIILower(data[0])) {
+        case 'd':
+            switch (toASCIILower(data[1])) {
+            case 'p':
+                switch (toASCIILower(data[2])) {
+                case 'c':
+                    if (toASCIILower(data[3]) == 'm')
+                        return CSSPrimitiveValue::UnitTypes::CSS_DPCM;
+                    break;
+                case 'p':
+                    if (toASCIILower(data[3]) == 'x')
+                        return CSSPrimitiveValue::UnitTypes::CSS_DPPX;
+                    break;
+                }
+            break;
+        }
+        break;
+        case 'g':
+            if (toASCIILower(data[1]) == 'r' &amp;&amp; toASCIILower(data[2]) == 'a' &amp;&amp; toASCIILower(data[3]) == 'd')
+                return CSSPrimitiveValue::UnitTypes::CSS_GRAD;
+            break;
+        case 't':
+            if (toASCIILower(data[1]) == 'u' &amp;&amp; toASCIILower(data[2]) == 'r' &amp;&amp; toASCIILower(data[3]) == 'n')
+                return CSSPrimitiveValue::UnitTypes::CSS_TURN;
+            break;
+        case 'v':
+            switch (toASCIILower(data[1])) {
+            case 'm':
+                switch (toASCIILower(data[2])) {
+                case 'a':
+                    if (toASCIILower(data[3]) == 'x')
+                        return CSSPrimitiveValue::UnitTypes::CSS_VMAX;
+                    break;
+                case 'i':
+                    if (toASCIILower(data[3]) == 'n')
+                        return CSSPrimitiveValue::UnitTypes::CSS_VMIN;
+                    break;
+                }
+                break;
+            }
+            break;
+        }
+        break;
+    case 5:
+        switch (toASCIILower(data[0])) {
+        case '_':
+            if (toASCIILower(data[1]) == '_' &amp;&amp; toASCIILower(data[2]) == 'q' &amp;&amp; toASCIILower(data[3]) == 'e' &amp;&amp; toASCIILower(data[4]) == 'm')
+                return CSSPrimitiveValue::UnitTypes::CSS_EMS; // FIXME-NEWPARSER: Need quirky ems.
+            break;
+        }
+        break;
+    }
+    return CSSPrimitiveValue::UnitTypes::CSS_UNKNOWN;
+}
+
+static CSSPrimitiveValue::UnitTypes stringToUnitType(StringView stringView)
+{
+    if (stringView.is8Bit())
+        return cssPrimitiveValueUnitFromTrie(stringView.characters8(), stringView.length());
+    return cssPrimitiveValueUnitFromTrie(stringView.characters16(), stringView.length());
+}
+
+CSSParserToken::CSSParserToken(CSSParserTokenType type, BlockType blockType)
+    : m_type(type)
+    , m_blockType(blockType)
+{
+}
+
+// Just a helper used for Delimiter tokens.
+CSSParserToken::CSSParserToken(CSSParserTokenType type, UChar c)
+    : m_type(type)
+    , m_blockType(NotBlock)
+    , m_delimiter(c)
+{
+    ASSERT(m_type == DelimiterToken);
+}
+
+CSSParserToken::CSSParserToken(CSSParserTokenType type, StringView value, BlockType blockType)
+    : m_type(type)
+    , m_blockType(blockType)
+{
+    initValueFromStringView(value);
+    m_id = -1;
+}
+
+CSSParserToken::CSSParserToken(CSSParserTokenType type, double numericValue, NumericValueType numericValueType, NumericSign sign)
+    : m_type(type)
+    , m_blockType(NotBlock)
+    , m_numericValueType(numericValueType)
+    , m_numericSign(sign)
+    , m_unit(static_cast&lt;unsigned&gt;(CSSPrimitiveValue::UnitTypes::CSS_NUMBER))
+{
+    ASSERT(type == NumberToken);
+    m_numericValue = clampTo&lt;double&gt;(numericValue, -std::numeric_limits&lt;float&gt;::max(), std::numeric_limits&lt;float&gt;::max());
+}
+
+CSSParserToken::CSSParserToken(CSSParserTokenType type, UChar32 start, UChar32 end)
+    : m_type(UnicodeRangeToken)
+    , m_blockType(NotBlock)
+{
+    ASSERT_UNUSED(type, type == UnicodeRangeToken);
+    m_unicodeRange.start = start;
+    m_unicodeRange.end = end;
+}
+
+CSSParserToken::CSSParserToken(HashTokenType type, StringView value)
+    : m_type(HashToken)
+    , m_blockType(NotBlock)
+    , m_hashTokenType(type)
+{
+    initValueFromStringView(value);
+}
+
+void CSSParserToken::convertToDimensionWithUnit(StringView unit)
+{
+    ASSERT(m_type == NumberToken);
+    m_type = DimensionToken;
+    initValueFromStringView(unit);
+    m_unit = static_cast&lt;unsigned&gt;(stringToUnitType(unit));
+}
+
+void CSSParserToken::convertToPercentage()
+{
+    ASSERT(m_type == NumberToken);
+    m_type = PercentageToken;
+    m_unit = static_cast&lt;unsigned&gt;(CSSPrimitiveValue::UnitTypes::CSS_PERCENTAGE);
+}
+
+UChar CSSParserToken::delimiter() const
+{
+    ASSERT(m_type == DelimiterToken);
+    return m_delimiter;
+}
+
+NumericSign CSSParserToken::numericSign() const
+{
+    // This is valid for DimensionToken and PercentageToken, but only used
+    // in &lt;an+b&gt; parsing on NumberTokens.
+    ASSERT(m_type == NumberToken);
+    return static_cast&lt;NumericSign&gt;(m_numericSign);
+}
+
+NumericValueType CSSParserToken::numericValueType() const
+{
+    ASSERT(m_type == NumberToken || m_type == PercentageToken || m_type == DimensionToken);
+    return static_cast&lt;NumericValueType&gt;(m_numericValueType);
+}
+
+double CSSParserToken::numericValue() const
+{
+    ASSERT(m_type == NumberToken || m_type == PercentageToken || m_type == DimensionToken);
+    return m_numericValue;
+}
+
+CSSPropertyID CSSParserToken::parseAsUnresolvedCSSPropertyID() const
+{
+    ASSERT(m_type == IdentToken);
+    return unresolvedCSSPropertyID(value());
+}
+
+CSSValueID CSSParserToken::id() const
+{
+    if (m_type != IdentToken)
+        return CSSValueInvalid;
+    if (m_id &lt; 0)
+        m_id = cssValueKeywordID(value());
+    return static_cast&lt;CSSValueID&gt;(m_id);
+}
+
+CSSValueID CSSParserToken::functionId() const
+{
+    if (m_type != FunctionToken)
+        return CSSValueInvalid;
+    if (m_id &lt; 0)
+        m_id = cssValueKeywordID(value());
+    return static_cast&lt;CSSValueID&gt;(m_id);
+}
+
+bool CSSParserToken::hasStringBacking() const
+{
+    CSSParserTokenType tokenType = type();
+    return tokenType == IdentToken
+        || tokenType == FunctionToken
+        || tokenType == AtKeywordToken
+        || tokenType == HashToken
+        || tokenType == UrlToken
+        || tokenType == DimensionToken
+        || tokenType == StringToken;
+}
+
+CSSParserToken CSSParserToken::copyWithUpdatedString(const StringView&amp; string) const
+{
+    CSSParserToken copy(*this);
+    copy.initValueFromStringView(string);
+    return copy;
+}
+
+bool CSSParserToken::valueDataCharRawEqual(const CSSParserToken&amp; other) const
+{
+    if (m_valueLength != other.m_valueLength)
+        return false;
+
+    if (m_valueDataCharRaw == other.m_valueDataCharRaw &amp;&amp; m_valueIs8Bit == other.m_valueIs8Bit)
+        return true;
+
+    if (m_valueIs8Bit)
+        return other.m_valueIs8Bit ? equal(static_cast&lt;const LChar*&gt;(m_valueDataCharRaw), static_cast&lt;const LChar*&gt;(other.m_valueDataCharRaw), m_valueLength) : equal(static_cast&lt;const LChar*&gt;(m_valueDataCharRaw), static_cast&lt;const UChar*&gt;(other.m_valueDataCharRaw), m_valueLength);
+    
+    return other.m_valueIs8Bit ? equal(static_cast&lt;const UChar*&gt;(m_valueDataCharRaw), static_cast&lt;const LChar*&gt;(other.m_valueDataCharRaw), m_valueLength) : equal(static_cast&lt;const UChar*&gt;(m_valueDataCharRaw), static_cast&lt;const UChar*&gt;(other.m_valueDataCharRaw), m_valueLength);
+}
+
+bool CSSParserToken::operator==(const CSSParserToken&amp; other) const
+{
+    if (m_type != other.m_type)
+        return false;
+    switch (m_type) {
+    case DelimiterToken:
+        return delimiter() == other.delimiter();
+    case HashToken:
+        if (m_hashTokenType != other.m_hashTokenType)
+            return false;
+        FALLTHROUGH;
+    case IdentToken:
+    case FunctionToken:
+    case StringToken:
+    case UrlToken:
+        return valueDataCharRawEqual(other);
+    case DimensionToken:
+        if (!valueDataCharRawEqual(other))
+            return false;
+        FALLTHROUGH;
+    case NumberToken:
+    case PercentageToken:
+        return m_numericSign == other.m_numericSign &amp;&amp; m_numericValue == other.m_numericValue &amp;&amp; m_numericValueType == other.m_numericValueType;
+    case UnicodeRangeToken:
+        return m_unicodeRange.start == other.m_unicodeRange.start &amp;&amp; m_unicodeRange.end == other.m_unicodeRange.end;
+    default:
+        return true;
+    }
+}
+
+void CSSParserToken::serialize(StringBuilder&amp; builder) const
+{
+    // This is currently only used for @supports CSSOM. To keep our implementation
+    // simple we handle some of the edge cases incorrectly (see comments below).
+    switch (type()) {
+    case IdentToken:
+        serializeIdentifier(value().toString(), builder);
+        break;
+    case FunctionToken:
+        serializeIdentifier(value().toString(), builder);
+        return builder.append('(');
+    case AtKeywordToken:
+        builder.append('@');
+        serializeIdentifier(value().toString(), builder);
+        break;
+    case HashToken:
+        builder.append('#');
+        serializeIdentifier(value().toString(), builder, (getHashTokenType() == HashTokenUnrestricted));
+        break;
+    case UrlToken:
+        builder.append(&quot;url(&quot;);
+        serializeIdentifier(value().toString(), builder);
+        return builder.append(')');
+    case DelimiterToken:
+        if (delimiter() == '\\')
+            return builder.append(&quot;\\\n&quot;);
+        return builder.append(delimiter());
+    case NumberToken:
+        // These won't properly preserve the NumericValueType flag
+        return builder.appendNumber(numericValue());
+    case PercentageToken:
+        builder.appendNumber(numericValue());
+        return builder.append('%');
+    case DimensionToken:
+        // This will incorrectly serialize e.g. 4e3e2 as 4000e2
+        builder.appendNumber(numericValue());
+        serializeIdentifier(value().toString(), builder);
+        break;
+    case UnicodeRangeToken:
+        return builder.append(String::format(&quot;U+%X-%X&quot;, unicodeRangeStart(), unicodeRangeEnd()));
+    case StringToken:
+        return serializeString(value().toString(), builder);
+
+    case IncludeMatchToken:
+        return builder.append(&quot;~=&quot;);
+    case DashMatchToken:
+        return builder.append(&quot;|=&quot;);
+    case PrefixMatchToken:
+        return builder.append(&quot;^=&quot;);
+    case SuffixMatchToken:
+        return builder.append(&quot;$=&quot;);
+    case SubstringMatchToken:
+        return builder.append(&quot;*=&quot;);
+    case ColumnToken:
+        return builder.append(&quot;||&quot;);
+    case CDOToken:
+        return builder.append(&quot;&lt;!--&quot;);
+    case CDCToken:
+        return builder.append(&quot;--&gt;&quot;);
+    case BadStringToken:
+        return builder.append(&quot;'\n&quot;);
+    case BadUrlToken:
+        return builder.append(&quot;url(()&quot;);
+    case WhitespaceToken:
+        return builder.append(' ');
+    case ColonToken:
+        return builder.append(':');
+    case SemicolonToken:
+        return builder.append(';');
+    case CommaToken:
+        return builder.append(',');
+    case LeftParenthesisToken:
+        return builder.append('(');
+    case RightParenthesisToken:
+        return builder.append(')');
+    case LeftBracketToken:
+        return builder.append('[');
+    case RightBracketToken:
+        return builder.append(']');
+    case LeftBraceToken:
+        return builder.append('{');
+    case RightBraceToken:
+        return builder.append('}');
+
+    case EOFToken:
+    case CommentToken:
+        ASSERT_NOT_REACHED();
+        return;
+    }
+}
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserTokenh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSParserToken.h (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserToken.h                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSParserToken.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,181 @@
</span><ins>+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CSSParserToken_h
+#define CSSParserToken_h
+
+#include &quot;CSSPrimitiveValue.h&quot;
+#include &lt;wtf/text/StringView.h&gt;
+
+namespace WebCore {
+
+enum CSSParserTokenType {
+    IdentToken = 0,
+    FunctionToken,
+    AtKeywordToken,
+    HashToken,
+    UrlToken,
+    BadUrlToken,
+    DelimiterToken,
+    NumberToken,
+    PercentageToken,
+    DimensionToken,
+    IncludeMatchToken,
+    DashMatchToken,
+    PrefixMatchToken,
+    SuffixMatchToken,
+    SubstringMatchToken,
+    ColumnToken,
+    UnicodeRangeToken,
+    WhitespaceToken,
+    CDOToken,
+    CDCToken,
+    ColonToken,
+    SemicolonToken,
+    CommaToken,
+    LeftParenthesisToken,
+    RightParenthesisToken,
+    LeftBracketToken,
+    RightBracketToken,
+    LeftBraceToken,
+    RightBraceToken,
+    StringToken,
+    BadStringToken,
+    EOFToken,
+    CommentToken,
+};
+
+enum NumericSign {
+    NoSign,
+    PlusSign,
+    MinusSign,
+};
+
+enum NumericValueType {
+    IntegerValueType,
+    NumberValueType,
+};
+
+enum HashTokenType {
+    HashTokenId,
+    HashTokenUnrestricted,
+};
+
+class CSSParserToken {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    enum BlockType {
+        NotBlock,
+        BlockStart,
+        BlockEnd,
+    };
+
+    CSSParserToken(CSSParserTokenType, BlockType = NotBlock);
+    CSSParserToken(CSSParserTokenType, StringView, BlockType = NotBlock);
+
+    CSSParserToken(CSSParserTokenType, UChar); // for DelimiterToken
+    CSSParserToken(CSSParserTokenType, double, NumericValueType, NumericSign); // for NumberToken
+    CSSParserToken(CSSParserTokenType, UChar32, UChar32); // for UnicodeRangeToken
+
+    CSSParserToken(HashTokenType, StringView);
+
+    bool operator==(const CSSParserToken&amp; other) const;
+    bool operator!=(const CSSParserToken&amp; other) const { return !(*this == other); }
+
+    // Converts NumberToken to DimensionToken.
+    void convertToDimensionWithUnit(StringView);
+
+    // Converts NumberToken to PercentageToken.
+    void convertToPercentage();
+
+    CSSParserTokenType type() const { return static_cast&lt;CSSParserTokenType&gt;(m_type); }
+    StringView value() const
+    {
+        if (m_valueIs8Bit)
+            return StringView(reinterpret_cast&lt;const LChar*&gt;(m_valueDataCharRaw), m_valueLength);
+        return StringView(reinterpret_cast&lt;const UChar*&gt;(m_valueDataCharRaw), m_valueLength);
+    }
+
+    UChar delimiter() const;
+    NumericSign numericSign() const;
+    NumericValueType numericValueType() const;
+    double numericValue() const;
+    HashTokenType getHashTokenType() const { ASSERT(m_type == HashToken); return m_hashTokenType; }
+    BlockType getBlockType() const { return static_cast&lt;BlockType&gt;(m_blockType); }
+    CSSPrimitiveValue::UnitTypes unitType() const { return static_cast&lt;CSSPrimitiveValue::UnitTypes&gt;(m_unit); }
+    UChar32 unicodeRangeStart() const { ASSERT(m_type == UnicodeRangeToken); return m_unicodeRange.start; }
+    UChar32 unicodeRangeEnd() const { ASSERT(m_type == UnicodeRangeToken); return m_unicodeRange.end; }
+    CSSValueID id() const;
+    CSSValueID functionId() const;
+
+    bool hasStringBacking() const;
+
+    CSSPropertyID parseAsUnresolvedCSSPropertyID() const;
+
+    void serialize(StringBuilder&amp;) const;
+
+    CSSParserToken copyWithUpdatedString(const StringView&amp;) const;
+
+private:
+    void initValueFromStringView(StringView string)
+    {
+        m_valueLength = string.length();
+        m_valueIs8Bit = string.is8Bit();
+        m_valueDataCharRaw = m_valueIs8Bit ? static_cast&lt;const void*&gt;(string.characters8()) : static_cast&lt;const void*&gt;(string.characters16());
+    }
+    unsigned m_type : 6; // CSSParserTokenType
+    unsigned m_blockType : 2; // BlockType
+    unsigned m_numericValueType : 1; // NumericValueType
+    unsigned m_numericSign : 2; // NumericSign
+    unsigned m_unit : 7; // CSSPrimitiveValue::UnitTypes
+
+    bool valueDataCharRawEqual(const CSSParserToken&amp; other) const;
+
+    // m_value... is an unpacked StringView so that we can pack it
+    // tightly with the rest of this object for a smaller object size.
+    bool m_valueIs8Bit : 1;
+    unsigned m_valueLength;
+    const void* m_valueDataCharRaw; // Either LChar* or UChar*.
+
+    union {
+        UChar m_delimiter;
+        HashTokenType m_hashTokenType;
+        double m_numericValue;
+        mutable int m_id;
+
+        struct {
+            UChar32 start;
+            UChar32 end;
+        } m_unicodeRange;
+    };
+};
+
+} // namespace WebCore
+
+#endif // CSSSParserToken_h
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserTokenRangecpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSParserTokenRange.cpp (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserTokenRange.cpp                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSParserTokenRange.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,97 @@
</span><ins>+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include &quot;config.h&quot;
+#include &quot;CSSParserTokenRange.h&quot;
+
+#include &lt;wtf/NeverDestroyed.h&gt;
+#include &lt;wtf/text/StringBuilder.h&gt;
+
+namespace WebCore {
+
+CSSParserToken&amp; CSSParserTokenRange::eofToken()
+{
+    static NeverDestroyed&lt;CSSParserToken&gt; eofToken(EOFToken);
+    return eofToken.get();
+}
+
+CSSParserTokenRange CSSParserTokenRange::makeSubRange(const CSSParserToken* first, const CSSParserToken* last) const
+{
+    if (first == &amp;eofToken())
+        first = m_last;
+    if (last == &amp;eofToken())
+        last = m_last;
+    ASSERT(first &lt;= last);
+    return CSSParserTokenRange(first, last);
+}
+
+CSSParserTokenRange CSSParserTokenRange::consumeBlock()
+{
+    ASSERT(peek().getBlockType() == CSSParserToken::BlockStart);
+    const CSSParserToken* start = &amp;peek() + 1;
+    unsigned nestingLevel = 0;
+    do {
+        const CSSParserToken&amp; token = consume();
+        if (token.getBlockType() == CSSParserToken::BlockStart)
+            nestingLevel++;
+        else if (token.getBlockType() == CSSParserToken::BlockEnd)
+            nestingLevel--;
+    } while (nestingLevel &amp;&amp; m_first &lt; m_last);
+
+    if (nestingLevel)
+        return makeSubRange(start, m_first); // Ended at EOF
+    return makeSubRange(start, m_first - 1);
+}
+
+void CSSParserTokenRange::consumeComponentValue()
+{
+    // FIXME: This is going to do multiple passes over large sections of a stylesheet.
+    // We should consider optimising this by precomputing where each block ends.
+    unsigned nestingLevel = 0;
+    do {
+        const CSSParserToken&amp; token = consume();
+        if (token.getBlockType() == CSSParserToken::BlockStart)
+            nestingLevel++;
+        else if (token.getBlockType() == CSSParserToken::BlockEnd)
+            nestingLevel--;
+    } while (nestingLevel &amp;&amp; m_first &lt; m_last);
+}
+
+String CSSParserTokenRange::serialize() const
+{
+    // We're supposed to insert comments between certain pairs of token types
+    // as per spec, but since this is currently only used for @supports CSSOM
+    // we just get these cases wrong and avoid the additional complexity.
+    StringBuilder builder;
+    for (const CSSParserToken* it = m_first; it &lt; m_last; ++it)
+        it-&gt;serialize(builder);
+    return builder.toString();
+}
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserTokenRangeh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSParserTokenRange.h (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserTokenRange.h                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSParserTokenRange.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,106 @@
</span><ins>+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CSSParserTokenRange_h
+#define CSSParserTokenRange_h
+
+#include &quot;CSSParserToken.h&quot;
+#include &lt;wtf/Vector.h&gt;
+
+namespace WebCore {
+
+// A CSSParserTokenRange is an iterator over a subrange of a vector of CSSParserTokens.
+// Accessing outside of the range will return an endless stream of EOF tokens.
+// This class refers to half-open intervals [first, last).
+class CSSParserTokenRange {
+public:
+    template&lt;size_t inlineBuffer&gt;
+    CSSParserTokenRange(const Vector&lt;CSSParserToken, inlineBuffer&gt;&amp; vector)
+        : m_first(vector.begin())
+        , m_last(vector.end())
+    {
+    }
+
+    // This should be called on a range with tokens returned by that range.
+    CSSParserTokenRange makeSubRange(const CSSParserToken* first, const CSSParserToken* last) const;
+
+    bool atEnd() const { return m_first == m_last; }
+    const CSSParserToken* end() const { return m_last; }
+
+    const CSSParserToken&amp; peek(unsigned offset = 0) const
+    {
+        if (m_first + offset &gt;= m_last)
+            return eofToken();
+        return *(m_first + offset);
+    }
+
+    const CSSParserToken&amp; consume()
+    {
+        if (m_first == m_last)
+            return eofToken();
+        return *m_first++;
+    }
+
+    const CSSParserToken&amp; consumeIncludingWhitespace()
+    {
+        const CSSParserToken&amp; result = consume();
+        consumeWhitespace();
+        return result;
+    }
+
+    // The returned range doesn't include the brackets
+    CSSParserTokenRange consumeBlock();
+
+    void consumeComponentValue();
+
+    void consumeWhitespace()
+    {
+        while (peek().type() == WhitespaceToken)
+            ++m_first;
+    }
+
+    String serialize() const;
+
+    const CSSParserToken* begin() const { return m_first; }
+
+    static CSSParserToken&amp; eofToken();
+
+private:
+    CSSParserTokenRange(const CSSParserToken* first, const CSSParserToken* last)
+        : m_first(first)
+        , m_last(last)
+    { }
+
+    const CSSParserToken* m_first;
+    const CSSParserToken* m_last;
+};
+
+} // namespace WebCore
+
+#endif // CSSParserTokenRange_h
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSPropertyParsercpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSPropertyParser.cpp (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSPropertyParser.cpp                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSPropertyParser.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,4784 @@
</span><ins>+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include &quot;config.h&quot;
+#include &quot;CSSPropertyParser.h&quot;
+
+#include &quot;CSSBasicShapes.h&quot;
+#include &quot;CSSBorderImage.h&quot;
+#include &quot;CSSContentDistributionValue.h&quot;
+#include &quot;CSSCursorImageValue.h&quot;
+// FIXME-NEWPARSER #include &quot;CSSCustomIdentValue.h&quot;
+#include &quot;CSSFontFaceSrcValue.h&quot;
+// FIXME-NEWPARSER #include &quot;CSSFontFamilyValue.h&quot;
+#include &quot;CSSFontFeatureValue.h&quot;
+#include &quot;CSSFunctionValue.h&quot;
+#include &quot;CSSGridAutoRepeatValue.h&quot;
+#include &quot;CSSGridLineNamesValue.h&quot;
+#include &quot;CSSGridTemplateAreasValue.h&quot;
+#include &quot;CSSInheritedValue.h&quot;
+#include &quot;CSSInitialValue.h&quot;
+#include &quot;CSSParserFastPaths.h&quot;
+#include &quot;CSSParserIdioms.h&quot;
+// FIXME-NEWPARSER #include &quot;CSSPathValue.h&quot;
+// FIXME-NEWPARSER #include &quot;CSSPendingSubstitutionValue.h&quot;
+#include &quot;CSSPrimitiveValueMappings.h&quot;
+#include &quot;CSSPropertyParserHelpers.h&quot;
+// FIXME-NEWPARSER #include &quot;CSSQuadValue.h&quot;
+#include &quot;CSSReflectValue.h&quot;
+#include &quot;CSSShadowValue.h&quot;
+// FIXME-NEWPARSER #include &quot;CSSStringValue.h&quot;
+#include &quot;CSSTimingFunctionValue.h&quot;
+// FIXME-NEWPARSER #include &quot;CSSURIValue.h&quot;
+#include &quot;CSSUnicodeRangeValue.h&quot;
+#include &quot;CSSUnsetValue.h&quot;
+// FIXME-NEWPARSER #include &quot;CSSValuePair.h&quot;
+// FIXME-NEWPARSER #include &quot;CSSVariableReferenceValue.h&quot;
+// FIXME-NEWPARSER #include &quot;CSSVariableParser.h&quot;
+#include &quot;Counter.h&quot;
+#include &quot;FontFace.h&quot;
+#include &quot;HashTools.h&quot;
+#include &quot;RenderTheme.h&quot;
+#include &quot;RuntimeEnabledFeatures.h&quot;
+#include &quot;SVGPathUtilities.h&quot;
+#include &quot;StylePropertyShorthand.h&quot;
+#include &lt;memory&gt;
+#include &lt;wtf/text/StringBuilder.h&gt;
+
+namespace WebCore {
+
+static bool hasPrefix(const char* string, unsigned length, const char* prefix)
+{
+    for (unsigned i = 0; i &lt; length; ++i) {
+        if (!prefix[i])
+            return true;
+        if (string[i] != prefix[i])
+            return false;
+    }
+    return false;
+}
+
+#if PLATFORM(IOS)
+static void cssPropertyNameIOSAliasing(const char* propertyName, const char*&amp; propertyNameAlias, unsigned&amp; newLength)
+{
+    if (!strcmp(propertyName, &quot;-webkit-hyphenate-locale&quot;)) {
+        // Worked in iOS 4.2.
+        static const char webkitLocale[] = &quot;-webkit-locale&quot;;
+        propertyNameAlias = webkitLocale;
+        newLength = strlen(webkitLocale);
+    }
+}
+#endif
+
+template &lt;typename CharacterType&gt;
+static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
+{
+    char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn &quot;apple&quot;/&quot;khtml&quot; into &quot;webkit&quot;, 1 for null character
+    
+    for (unsigned i = 0; i != length; ++i) {
+        CharacterType c = propertyName[i];
+        if (!c || c &gt;= 0x7F)
+            return CSSPropertyInvalid; // illegal character
+        buffer[i] = toASCIILower(c);
+    }
+    buffer[length] = '\0';
+    
+    const char* name = buffer;
+    if (buffer[0] == '-') {
+#if ENABLE(LEGACY_CSS_VENDOR_PREFIXES)
+        // If the prefix is -apple- or -khtml-, change it to -webkit-.
+        // This makes the string one character longer.
+        if (RuntimeEnabledFeatures::sharedFeatures().legacyCSSVendorPrefixesEnabled()
+            &amp;&amp; (hasPrefix(buffer, length, &quot;-apple-&quot;) || hasPrefix(buffer, length, &quot;-khtml-&quot;))) {
+            memmove(buffer + 7, buffer + 6, length + 1 - 6);
+            memcpy(buffer, &quot;-webkit&quot;, 7);
+            ++length;
+        }
+#endif
+#if PLATFORM(IOS)
+        cssPropertyNameIOSAliasing(buffer, name, length);
+#endif
+    }
+    
+    const Property* hashTableEntry = findProperty(name, length);
+    return hashTableEntry ? static_cast&lt;CSSPropertyID&gt;(hashTableEntry-&gt;id) : CSSPropertyInvalid;
+}
+
+static bool isAppleLegacyCssValueKeyword(const char* valueKeyword, unsigned length)
+{
+    static const char applePrefix[] = &quot;-apple-&quot;;
+    static const char appleSystemPrefix[] = &quot;-apple-system&quot;;
+    static const char* appleWirelessPlaybackTargetActive = getValueName(CSSValueAppleWirelessPlaybackTargetActive);
+    
+    return hasPrefix(valueKeyword, length, applePrefix)
+    &amp;&amp; !hasPrefix(valueKeyword, length, appleSystemPrefix)
+    &amp;&amp; !WTF::equal(reinterpret_cast&lt;const LChar*&gt;(valueKeyword), reinterpret_cast&lt;const LChar*&gt;(appleWirelessPlaybackTargetActive), length);
+}
+
+template &lt;typename CharacterType&gt;
+static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
+{
+    char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn &quot;apple&quot;/&quot;khtml&quot; into &quot;webkit&quot;, 1 for null character
+    
+    for (unsigned i = 0; i != length; ++i) {
+        CharacterType c = valueKeyword[i];
+        if (!c || c &gt;= 0x7F)
+            return CSSValueInvalid; // illegal keyword.
+        buffer[i] = WTF::toASCIILower(c);
+    }
+    buffer[length] = '\0';
+    
+    if (buffer[0] == '-') {
+        // If the prefix is -apple- or -khtml-, change it to -webkit-.
+        // This makes the string one character longer.
+        // On iOS we don't want to change values starting with -apple-system to -webkit-system.
+        // FIXME: Remove this mangling without breaking the web.
+        if (isAppleLegacyCssValueKeyword(buffer, length) || hasPrefix(buffer, length, &quot;-khtml-&quot;)) {
+            memmove(buffer + 7, buffer + 6, length + 1 - 6);
+            memcpy(buffer, &quot;-webkit&quot;, 7);
+            ++length;
+        }
+    }
+    
+    const Value* hashTableEntry = findValue(buffer, length);
+    return hashTableEntry ? static_cast&lt;CSSValueID&gt;(hashTableEntry-&gt;id) : CSSValueInvalid;
+}
+
+CSSValueID cssValueKeywordID(StringView string)
+{
+    unsigned length = string.length();
+    if (!length)
+        return CSSValueInvalid;
+    if (length &gt; maxCSSValueKeywordLength)
+        return CSSValueInvalid;
+    
+    return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
+}
+
+CSSPropertyID unresolvedCSSPropertyID(StringView string)
+{
+    unsigned length = string.length();
+    
+    if (!length)
+        return CSSPropertyInvalid;
+    if (length &gt; maxCSSPropertyNameLength)
+        return CSSPropertyInvalid;
+    
+    return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
+}
+    
+// FIXME-NEWPARSER
+// Comment out property parsing for now.
+/*
+using namespace CSSPropertyParserHelpers;
+
+
+CSSPropertyParser::CSSPropertyParser(const CSSParserTokenRange&amp; range,
+    const CSSParserContext&amp; context, Vector&lt;CSSProperty, 256&gt;* parsedProperties)
+    : m_range(range)
+    , m_context(context)
+    , m_parsedProperties(parsedProperties)
+{
+    m_range.consumeWhitespace();
+}
+
+void CSSPropertyParser::addProperty(CSSPropertyID property, CSSPropertyID currentShorthand, const CSSValue&amp; value, bool important, bool implicit)
+{
+    ASSERT(!isPropertyAlias(property));
+
+    int shorthandIndex = 0;
+    bool setFromShorthand = false;
+
+    if (currentShorthand) {
+        Vector&lt;StylePropertyShorthand, 4&gt; shorthands;
+        getMatchingShorthandsForLonghand(property, &amp;shorthands);
+        setFromShorthand = true;
+        if (shorthands.size() &gt; 1)
+            shorthandIndex = indexOfShorthandForLonghand(currentShorthand, shorthands);
+    }
+
+    m_parsedProperties-&gt;append(CSSProperty(property, value, important, setFromShorthand, shorthandIndex, implicit));
+}
+
+void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID property, const CSSValue&amp; value, bool important)
+{
+    const StylePropertyShorthand&amp; shorthand = shorthandForProperty(property);
+    unsigned shorthandLength = shorthand.length();
+    ASSERT(shorthandLength);
+    const CSSPropertyID* longhands = shorthand.properties();
+    for (unsigned i = 0; i &lt; shorthandLength; ++i)
+        addProperty(longhands[i], property, value, important);
+}
+
+bool CSSPropertyParser::parseValue(CSSPropertyID unresolvedProperty, bool important,
+    const CSSParserTokenRange&amp; range, const CSSParserContext&amp; context,
+    Vector&lt;CSSProperty, 256&gt;&amp; parsedProperties, StyleRule::Type ruleType)
+{
+    int parsedPropertiesSize = parsedProperties.size();
+
+    CSSPropertyParser parser(range, context, &amp;parsedProperties);
+    CSSPropertyID resolvedProperty = resolveCSSPropertyID(unresolvedProperty);
+    bool parseSuccess;
+
+    if (ruleType == StyleRule::Viewport) {
+        parseSuccess = (RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(context.mode()))
+            &amp;&amp; parser.parseViewportDescriptor(resolvedProperty, important);
+    } else if (ruleType == StyleRule::FontFace) {
+        parseSuccess = parser.parseFontFaceDescriptor(resolvedProperty);
+    } else {
+        parseSuccess = parser.parseValueStart(unresolvedProperty, important);
+    }
+
+    // This doesn't count UA style sheets
+    if (parseSuccess &amp;&amp; context.useCounter())
+        context.useCounter()-&gt;count(context.mode(), unresolvedProperty);
+
+    if (!parseSuccess)
+        parsedProperties.shrink(parsedPropertiesSize);
+
+    return parseSuccess;
+}
+
+const CSSValue* CSSPropertyParser::parseSingleValue(
+    CSSPropertyID property, const CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    CSSPropertyParser parser(range, context, nullptr);
+    const CSSValue* value = parser.parseSingleValue(property);
+    if (!value || !parser.m_range.atEnd())
+        return nullptr;
+    return value;
+}
+
+bool CSSPropertyParser::parseValueStart(CSSPropertyID unresolvedProperty, bool important)
+{
+    if (consumeCSSWideKeyword(unresolvedProperty, important))
+        return true;
+
+    CSSParserTokenRange originalRange = m_range;
+    CSSPropertyID propertyId = resolveCSSPropertyID(unresolvedProperty);
+    bool isShorthand = isShorthandProperty(propertyId);
+
+    if (isShorthand) {
+        // Variable references will fail to parse here and will fall out to the variable ref parser below.
+        if (parseShorthand(unresolvedProperty, important))
+            return true;
+    } else {
+        if (const CSSValue* parsedValue = parseSingleValue(unresolvedProperty)) {
+            if (m_range.atEnd()) {
+                addProperty(propertyId, CSSPropertyInvalid, *parsedValue, important);
+                return true;
+            }
+        }
+    }
+
+    if (RuntimeEnabledFeatures::cssVariablesEnabled() &amp;&amp; CSSVariableParser::containsValidVariableReferences(originalRange)) {
+        CSSVariableReferenceValue* variable = CSSVariableReferenceValue::create(CSSVariableData::create(originalRange));
+
+        if (isShorthand) {
+            const CSSPendingSubstitutionValue&amp; pendingValue = *CSSPendingSubstitutionValue::create(propertyId, variable);
+            addExpandedPropertyForValue(propertyId, pendingValue, important);
+        } else {
+            addProperty(propertyId, CSSPropertyInvalid, *variable, important);
+        }
+        return true;
+    }
+
+    return false;
+}

+bool CSSPropertyParser::consumeCSSWideKeyword(CSSPropertyID unresolvedProperty, bool important)
+{
+    CSSParserTokenRange rangeCopy = m_range;
+    CSSValueID id = rangeCopy.consumeIncludingWhitespace().id();
+    if (!rangeCopy.atEnd())
+        return false;
+
+    CSSValue* value = nullptr;
+    if (id == CSSValueInitial)
+        value = CSSInitialValue::create();
+    else if (id == CSSValueInherit)
+        value = CSSInheritedValue::create();
+    else if (id == CSSValueUnset)
+        value = CSSUnsetValue::create();
+    else
+        return false;
+
+    CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty);
+    const StylePropertyShorthand&amp; shorthand = shorthandForProperty(property);
+    if (!shorthand.length()) {
+        if (CSSPropertyMetadata::isDescriptorOnly(unresolvedProperty))
+            return false;
+        addProperty(property, CSSPropertyInvalid, *value, important);
+    } else {
+        addExpandedPropertyForValue(property, *value, important);
+    }
+    m_range = rangeCopy;
+    return true;
+}
+
+static CSSValueList* consumeTransformOrigin(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+    CSSValue* resultX = nullptr;
+    CSSValue* resultY = nullptr;
+    if (consumeOneOrTwoValuedPosition(range, cssParserMode, unitless, resultX, resultY)) {
+        CSSValueList* list = CSSValueList::createSpaceSeparated();
+        list-&gt;append(*resultX);
+        list-&gt;append(*resultY);
+        CSSValue* resultZ = consumeLength(range, cssParserMode, ValueRangeAll);
+        if (!resultZ)
+            resultZ = CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitType::Pixels);
+        list-&gt;append(*resultZ);
+        return list;
+    }
+    return nullptr;
+}
+
+// Methods for consuming non-shorthand properties starts here.
+static CSSValue* consumeWillChange(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+
+    CSSValueList* values = CSSValueList::createCommaSeparated();
+    // Every comma-separated list of identifiers is a valid will-change value,
+    // unless the list includes an explicitly disallowed identifier.
+    while (true) {
+        if (range.peek().type() != IdentToken)
+            return nullptr;
+        CSSPropertyID unresolvedProperty = unresolvedCSSPropertyID(range.peek().value());
+        if (unresolvedProperty) {
+            ASSERT(CSSPropertyMetadata::isEnabledProperty(unresolvedProperty));
+            // Now &quot;all&quot; is used by both CSSValue and CSSPropertyValue.
+            // Need to return nullptr when currentValue is CSSPropertyAll.
+            if (unresolvedProperty == CSSPropertyWillChange || unresolvedProperty == CSSPropertyAll)
+                return nullptr;
+            values-&gt;append(*CSSCustomIdentValue::create(unresolvedProperty));
+            range.consumeIncludingWhitespace();
+        } else {
+            switch (range.peek().id()) {
+            case CSSValueNone:
+            case CSSValueAll:
+            case CSSValueAuto:
+            case CSSValueDefault:
+            case CSSValueInitial:
+            case CSSValueInherit:
+                return nullptr;
+            case CSSValueContents:
+            case CSSValueScrollPosition:
+                values-&gt;append(*consumeIdent(range));
+                break;
+            default:
+                range.consumeIncludingWhitespace();
+                break;
+            }
+        }
+
+        if (range.atEnd())
+            break;
+        if (!consumeCommaIncludingWhitespace(range))
+            return nullptr;
+    }
+
+    return values;
+}
+
+static CSSFontFeatureValue* consumeFontFeatureTag(CSSParserTokenRange&amp; range)
+{
+    // Feature tag name consists of 4-letter characters.
+    static const unsigned tagNameLength = 4;
+
+    const CSSParserToken&amp; token = range.consumeIncludingWhitespace();
+    // Feature tag name comes first
+    if (token.type() != StringToken)
+        return nullptr;
+    if (token.value().length() != tagNameLength)
+        return nullptr;
+    AtomicString tag = token.value().toAtomicString();
+    for (unsigned i = 0; i &lt; tagNameLength; ++i) {
+        // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
+        UChar character = tag[i];
+        if (character &lt; 0x20 || character &gt; 0x7E)
+            return nullptr;
+    }
+
+    int tagValue = 1;
+    // Feature tag values could follow: &lt;integer&gt; | on | off
+    if (range.peek().type() == NumberToken &amp;&amp; range.peek().numericValueType() == IntegerValueType &amp;&amp; range.peek().numericValue() &gt;= 0) {
+        tagValue = clampTo&lt;int&gt;(range.consumeIncludingWhitespace().numericValue());
+        if (tagValue &lt; 0)
+            return nullptr;
+    } else if (range.peek().id() == CSSValueOn || range.peek().id() == CSSValueOff) {
+        tagValue = range.consumeIncludingWhitespace().id() == CSSValueOn;
+    }
+    return CSSFontFeatureValue::create(tag, tagValue);
+}
+
+static CSSValue* consumeFontFeatureSettings(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueNormal)
+        return consumeIdent(range);
+    CSSValueList* settings = CSSValueList::createCommaSeparated();
+    do {
+        CSSFontFeatureValue* fontFeatureValue = consumeFontFeatureTag(range);
+        if (!fontFeatureValue)
+            return nullptr;
+        settings-&gt;append(*fontFeatureValue);
+    } while (consumeCommaIncludingWhitespace(range));
+    return settings;
+}
+
+static CSSValue* consumePage(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+    return consumeCustomIdent(range);
+}
+
+static CSSValue* consumeQuotes(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    CSSValueList* values = CSSValueList::createSpaceSeparated();
+    while (!range.atEnd()) {
+        CSSStringValue* parsedValue = consumeString(range);
+        if (!parsedValue)
+            return nullptr;
+        values-&gt;append(*parsedValue);
+    }
+    if (values-&gt;length() &amp;&amp; values-&gt;length() % 2 == 0)
+        return values;
+    return nullptr;
+}
+
+static CSSValue* consumeWebkitHighlight(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    return consumeString(range);
+}
+
+class FontVariantLigaturesParser {
+    STACK_ALLOCATED();
+
+public:
+    FontVariantLigaturesParser()
+        : m_sawCommonLigaturesValue(false)
+        , m_sawDiscretionaryLigaturesValue(false)
+        , m_sawHistoricalLigaturesValue(false)
+        , m_sawContextualLigaturesValue(false)
+        , m_result(CSSValueList::createSpaceSeparated())
+    {
+    }
+
+    enum class ParseResult {
+        ConsumedValue,
+        DisallowedValue,
+        UnknownValue
+    };
+
+    ParseResult consumeLigature(CSSParserTokenRange&amp; range)
+    {
+        CSSValueID valueID = range.peek().id();
+        switch (valueID) {
+        case CSSValueNoCommonLigatures:
+        case CSSValueCommonLigatures:
+            if (m_sawCommonLigaturesValue)
+                return ParseResult::DisallowedValue;
+            m_sawCommonLigaturesValue = true;
+            break;
+        case CSSValueNoDiscretionaryLigatures:
+        case CSSValueDiscretionaryLigatures:
+            if (m_sawDiscretionaryLigaturesValue)
+                return ParseResult::DisallowedValue;
+            m_sawDiscretionaryLigaturesValue = true;
+            break;
+        case CSSValueNoHistoricalLigatures:
+        case CSSValueHistoricalLigatures:
+            if (m_sawHistoricalLigaturesValue)
+                return ParseResult::DisallowedValue;
+            m_sawHistoricalLigaturesValue = true;
+            break;
+        case CSSValueNoContextual:
+        case CSSValueContextual:
+            if (m_sawContextualLigaturesValue)
+                return ParseResult::DisallowedValue;
+            m_sawContextualLigaturesValue = true;
+            break;
+        default:
+            return ParseResult::UnknownValue;
+        }
+        m_result-&gt;append(*consumeIdent(range));
+        return ParseResult::ConsumedValue;
+    }
+
+    CSSValue* finalizeValue()
+    {
+        if (!m_result-&gt;length())
+            return CSSPrimitiveValue::createIdentifier(CSSValueNormal);
+        return m_result.release();
+    }
+
+private:
+    bool m_sawCommonLigaturesValue;
+    bool m_sawDiscretionaryLigaturesValue;
+    bool m_sawHistoricalLigaturesValue;
+    bool m_sawContextualLigaturesValue;
+    Member&lt;CSSValueList&gt; m_result;
+};
+
+static CSSValue* consumeFontVariantLigatures(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueNormal || range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+
+    FontVariantLigaturesParser ligaturesParser;
+    do {
+        if (ligaturesParser.consumeLigature(range) !=
+            FontVariantLigaturesParser::ParseResult::ConsumedValue)
+            return nullptr;
+    } while (!range.atEnd());
+
+    return ligaturesParser.finalizeValue();
+}
+
+static CSSPrimitiveValue* consumeFontVariantCaps(CSSParserTokenRange&amp; range)
+{
+    return consumeIdent&lt;CSSValueNormal, CSSValueSmallCaps, CSSValueAllSmallCaps,
+        CSSValuePetiteCaps, CSSValueAllPetiteCaps,
+        CSSValueUnicase, CSSValueTitlingCaps&gt;(range);
+}
+
+class FontVariantNumericParser {
+    STACK_ALLOCATED();
+
+public:
+    FontVariantNumericParser()
+        : m_sawNumericFigureValue(false)
+        , m_sawNumericSpacingValue(false)
+        , m_sawNumericFractionValue(false)
+        , m_sawOrdinalValue(false)
+        , m_sawSlashedZeroValue(false)
+        , m_result(CSSValueList::createSpaceSeparated())
+    {
+    }
+
+    enum class ParseResult {
+        ConsumedValue,
+        DisallowedValue,
+        UnknownValue
+    };
+
+    ParseResult consumeNumeric(CSSParserTokenRange&amp; range)
+    {
+        CSSValueID valueID = range.peek().id();
+        switch (valueID) {
+        case CSSValueLiningNums:
+        case CSSValueOldstyleNums:
+            if (m_sawNumericFigureValue)
+                return ParseResult::DisallowedValue;
+            m_sawNumericFigureValue = true;
+            break;
+        case CSSValueProportionalNums:
+        case CSSValueTabularNums:
+            if (m_sawNumericSpacingValue)
+                return ParseResult::DisallowedValue;
+            m_sawNumericSpacingValue = true;
+            break;
+        case CSSValueDiagonalFractions:
+        case CSSValueStackedFractions:
+            if (m_sawNumericFractionValue)
+                return ParseResult::DisallowedValue;
+            m_sawNumericFractionValue = true;
+            break;
+        case CSSValueOrdinal:
+            if (m_sawOrdinalValue)
+                return ParseResult::DisallowedValue;
+            m_sawOrdinalValue = true;
+            break;
+        case CSSValueSlashedZero:
+            if (m_sawSlashedZeroValue)
+                return ParseResult::DisallowedValue;
+            m_sawSlashedZeroValue = true;
+            break;
+        default:
+            return ParseResult::UnknownValue;
+        }
+        m_result-&gt;append(*consumeIdent(range));
+        return ParseResult::ConsumedValue;
+    }
+
+    CSSValue* finalizeValue()
+    {
+        if (!m_result-&gt;length())
+            return CSSPrimitiveValue::createIdentifier(CSSValueNormal);
+        return m_result.release();
+    }
+
+
+private:
+    bool m_sawNumericFigureValue;
+    bool m_sawNumericSpacingValue;
+    bool m_sawNumericFractionValue;
+    bool m_sawOrdinalValue;
+    bool m_sawSlashedZeroValue;
+    Member&lt;CSSValueList&gt; m_result;
+};
+
+static CSSValue* consumeFontVariantNumeric(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueNormal)
+        return consumeIdent(range);
+
+    FontVariantNumericParser numericParser;
+    do {
+        if (numericParser.consumeNumeric(range) !=
+            FontVariantNumericParser::ParseResult::ConsumedValue)
+            return nullptr;
+    } while (!range.atEnd());
+
+    return numericParser.finalizeValue();
+}
+
+static CSSPrimitiveValue* consumeFontVariantCSS21(CSSParserTokenRange&amp; range)
+{
+    return consumeIdent&lt;CSSValueNormal, CSSValueSmallCaps&gt;(range);
+}
+
+static CSSValue* consumeFontVariantList(CSSParserTokenRange&amp; range)
+{
+    CSSValueList* values = CSSValueList::createCommaSeparated();
+    do {
+        if (range.peek().id() == CSSValueAll) {
+            // FIXME: CSSPropertyParser::parseFontVariant() implements
+            // the old css3 draft:
+            // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#font-variant
+            // 'all' is only allowed in @font-face and with no other values.
+            if (values-&gt;length())
+                return nullptr;
+            return consumeIdent(range);
+        }
+        CSSPrimitiveValue* fontVariant = consumeFontVariantCSS21(range);
+        if (fontVariant)
+            values-&gt;append(*fontVariant);
+    } while (consumeCommaIncludingWhitespace(range));
+
+    if (values-&gt;length())
+        return values;
+
+    return nullptr;
+}
+
+static CSSPrimitiveValue* consumeFontWeight(CSSParserTokenRange&amp; range)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (token.id() &gt;= CSSValueNormal &amp;&amp; token.id() &lt;= CSSValueLighter)
+        return consumeIdent(range);
+    if (token.type() != NumberToken || token.numericValueType() != IntegerValueType)
+        return nullptr;
+    int weight = static_cast&lt;int&gt;(token.numericValue());
+    if ((weight % 100) || weight &lt; 100 || weight &gt; 900)
+        return nullptr;
+    range.consumeIncludingWhitespace();
+    return CSSPrimitiveValue::createIdentifier(static_cast&lt;CSSValueID&gt;(CSSValue100 + weight / 100 - 1));
+}
+
+static String concatenateFamilyName(CSSParserTokenRange&amp; range)
+{
+    StringBuilder builder;
+    bool addedSpace = false;
+    const CSSParserToken&amp; firstToken = range.peek();
+    while (range.peek().type() == IdentToken) {
+        if (!builder.isEmpty()) {
+            builder.append(' ');
+            addedSpace = true;
+        }
+        builder.append(range.consumeIncludingWhitespace().value());
+    }
+    if (!addedSpace &amp;&amp; isCSSWideKeyword(firstToken.id()))
+        return String();
+    return builder.toString();
+}
+
+static CSSValue* consumeFamilyName(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().type() == StringToken)
+        return CSSFontFamilyValue::create(range.consumeIncludingWhitespace().value().toString());
+    if (range.peek().type() != IdentToken)
+        return nullptr;
+    String familyName = concatenateFamilyName(range);
+    if (familyName.isNull())
+        return nullptr;
+    return CSSFontFamilyValue::create(familyName);
+}
+
+static CSSValue* consumeGenericFamily(CSSParserTokenRange&amp; range)
+{
+    return consumeIdentRange(range, CSSValueSerif, CSSValueWebkitBody);
+}
+
+static CSSValueList* consumeFontFamily(CSSParserTokenRange&amp; range)
+{
+    CSSValueList* list = CSSValueList::createCommaSeparated();
+    do {
+        CSSValue* parsedValue = consumeGenericFamily(range);
+        if (parsedValue) {
+            list-&gt;append(*parsedValue);
+        } else {
+            parsedValue = consumeFamilyName(range);
+            if (parsedValue) {
+                list-&gt;append(*parsedValue);
+            } else {
+                return nullptr;
+            }
+        }
+    } while (consumeCommaIncludingWhitespace(range));
+    return list;
+}
+
+static CSSValue* consumeSpacing(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (range.peek().id() == CSSValueNormal)
+        return consumeIdent(range);
+    // FIXME: allow &lt;percentage&gt;s in word-spacing.
+    return consumeLength(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
+}
+
+static CSSValue* consumeTabSize(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    CSSPrimitiveValue* parsedValue = consumeInteger(range, 0);
+    if (parsedValue)
+        return parsedValue;
+    return consumeLength(range, cssParserMode, ValueRangeNonNegative);
+}
+
+static CSSValue* consumeTextSizeAdjust(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    return consumePercent(range, ValueRangeNonNegative);
+}
+
+static CSSValue* consumeFontSize(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, UnitlessQuirk unitless = UnitlessQuirk::Forbid)
+{
+    if (range.peek().id() &gt;= CSSValueXxSmall &amp;&amp; range.peek().id() &lt;= CSSValueLarger)
+        return consumeIdent(range);
+    return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative, unitless);
+}
+
+static CSSPrimitiveValue* consumeLineHeight(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (range.peek().id() == CSSValueNormal)
+        return consumeIdent(range);
+
+    CSSPrimitiveValue* lineHeight = consumeNumber(range, ValueRangeNonNegative);
+    if (lineHeight)
+        return lineHeight;
+    return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
+}
+
+static CSSValueList* consumeRotation(CSSParserTokenRange&amp; range)
+{
+    ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled());
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+
+    CSSValue* rotation = consumeAngle(range);
+    if (!rotation)
+        return nullptr;
+    list-&gt;append(*rotation);
+
+    if (range.atEnd())
+        return list;
+
+    for (unsigned i = 0; i &lt; 3; i++) { // 3 dimensions of rotation
+        CSSValue* dimension = consumeNumber(range, ValueRangeAll);
+        if (!dimension)
+            return nullptr;
+        list-&gt;append(*dimension);
+    }
+
+    return list;
+}
+
+static CSSValueList* consumeScale(CSSParserTokenRange&amp; range)
+{
+    ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled());
+
+    CSSValue* scale = consumeNumber(range, ValueRangeAll);
+    if (!scale)
+        return nullptr;
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+    list-&gt;append(*scale);
+    scale = consumeNumber(range, ValueRangeAll);
+    if (scale) {
+        list-&gt;append(*scale);
+        scale = consumeNumber(range, ValueRangeAll);
+        if (scale)
+            list-&gt;append(*scale);
+    }
+
+    return list;
+}
+
+static CSSValueList* consumeTranslate(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled());
+    CSSValue* translate = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
+    if (!translate)
+        return nullptr;
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+    list-&gt;append(*translate);
+    translate = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
+    if (translate) {
+        list-&gt;append(*translate);
+        translate = consumeLength(range, cssParserMode, ValueRangeAll);
+        if (translate)
+            list-&gt;append(*translate);
+    }
+
+    return list;
+}
+
+static CSSValue* consumeCounter(CSSParserTokenRange&amp; range, int defaultValue)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+    do {
+        CSSCustomIdentValue* counterName = consumeCustomIdent(range);
+        if (!counterName)
+            return nullptr;
+        int i = defaultValue;
+        if (CSSPrimitiveValue* counterValue = consumeInteger(range))
+            i = clampTo&lt;int&gt;(counterValue-&gt;getDoubleValue());
+        list-&gt;append(*CSSValuePair::create(counterName,
+            CSSPrimitiveValue::create(i, CSSPrimitiveValue::UnitType::Integer),
+            CSSValuePair::DropIdenticalValues));
+    } while (!range.atEnd());
+    return list;
+}
+
+static CSSValue* consumePageSize(CSSParserTokenRange&amp; range)
+{
+    return consumeIdent&lt;CSSValueA3, CSSValueA4, CSSValueA5, CSSValueB4, CSSValueB5, CSSValueLedger, CSSValueLegal, CSSValueLetter&gt;(range);
+}
+
+static CSSValueList* consumeSize(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    CSSValueList* result = CSSValueList::createSpaceSeparated();
+
+    if (range.peek().id() == CSSValueAuto) {
+        result-&gt;append(*consumeIdent(range));
+        return result;
+    }
+
+    if (CSSValue* width = consumeLength(range, cssParserMode, ValueRangeNonNegative)) {
+        CSSValue* height = consumeLength(range, cssParserMode, ValueRangeNonNegative);
+        result-&gt;append(*width);
+        if (height)
+            result-&gt;append(*height);
+        return result;
+    }
+
+    CSSValue* pageSize = consumePageSize(range);
+    CSSValue* orientation = consumeIdent&lt;CSSValuePortrait, CSSValueLandscape&gt;(range);
+    if (!pageSize)
+        pageSize = consumePageSize(range);
+
+    if (!orientation &amp;&amp; !pageSize)
+        return nullptr;
+    if (pageSize)
+        result-&gt;append(*pageSize);
+    if (orientation)
+        result-&gt;append(*orientation);
+    return result;
+}
+
+static CSSValue* consumeSnapHeight(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    CSSPrimitiveValue* unit = consumeLength(range, cssParserMode, ValueRangeNonNegative);
+    if (!unit)
+        return nullptr;
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+    list-&gt;append(*unit);
+
+    if (CSSPrimitiveValue* position = consumePositiveInteger(range)) {
+        if (position-&gt;getIntValue() &gt; 100)
+            return nullptr;
+        list-&gt;append(*position);
+    }
+
+    return list;
+}
+
+static CSSValue* consumeTextIndent(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    // [ &lt;length&gt; | &lt;percentage&gt; ] &amp;&amp; hanging? &amp;&amp; each-line?
+    // Keywords only allowed when css3Text is enabled.
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+
+    bool hasLengthOrPercentage = false;
+    bool hasEachLine = false;
+    bool hasHanging = false;
+
+    do {
+        if (!hasLengthOrPercentage) {
+            if (CSSValue* textIndent = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow)) {
+                list-&gt;append(*textIndent);
+                hasLengthOrPercentage = true;
+                continue;
+            }
+        }
+
+        if (RuntimeEnabledFeatures::css3TextEnabled()) {
+            CSSValueID id = range.peek().id();
+            if (!hasEachLine &amp;&amp; id == CSSValueEachLine) {
+                list-&gt;append(*consumeIdent(range));
+                hasEachLine = true;
+                continue;
+            }
+            if (!hasHanging &amp;&amp; id == CSSValueHanging) {
+                list-&gt;append(*consumeIdent(range));
+                hasHanging = true;
+                continue;
+            }
+        }
+        return nullptr;
+    } while (!range.atEnd());
+
+    if (!hasLengthOrPercentage)
+        return nullptr;
+
+    return list;
+}
+
+static bool validWidthOrHeightKeyword(CSSValueID id, const CSSParserContext&amp; context)
+{
+    if (id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent
+        || id == CSSValueMinContent || id == CSSValueMaxContent || id == CSSValueFitContent) {
+        if (context.useCounter()) {
+            switch (id) {
+            case CSSValueWebkitMinContent:
+                context.useCounter()-&gt;count(UseCounter::CSSValuePrefixedMinContent);
+                break;
+            case CSSValueWebkitMaxContent:
+                context.useCounter()-&gt;count(UseCounter::CSSValuePrefixedMaxContent);
+                break;
+            case CSSValueWebkitFillAvailable:
+                context.useCounter()-&gt;count(UseCounter::CSSValuePrefixedFillAvailable);
+                break;
+            case CSSValueWebkitFitContent:
+                context.useCounter()-&gt;count(UseCounter::CSSValuePrefixedFitContent);
+                break;
+            default:
+                break;
+            }
+        }
+        return true;
+    }
+    return false;
+}
+
+static CSSValue* consumeMaxWidthOrHeight(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context, UnitlessQuirk unitless = UnitlessQuirk::Forbid)
+{
+    if (range.peek().id() == CSSValueNone || validWidthOrHeightKeyword(range.peek().id(), context))
+        return consumeIdent(range);
+    return consumeLengthOrPercent(range, context.mode(), ValueRangeNonNegative, unitless);
+}
+
+static CSSValue* consumeWidthOrHeight(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context, UnitlessQuirk unitless = UnitlessQuirk::Forbid)
+{
+    if (range.peek().id() == CSSValueAuto || validWidthOrHeightKeyword(range.peek().id(), context))
+        return consumeIdent(range);
+    return consumeLengthOrPercent(range, context.mode(), ValueRangeNonNegative, unitless);
+}
+
+static CSSValue* consumeMarginOrOffset(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+    return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, unitless);
+}
+
+static CSSPrimitiveValue* consumeClipComponent(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+    return consumeLength(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
+}
+
+static CSSValue* consumeClip(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+
+    if (range.peek().functionId() != CSSValueRect)
+        return nullptr;
+
+    CSSParserTokenRange args = consumeFunction(range);
+    // rect(t, r, b, l) || rect(t r b l)
+    CSSPrimitiveValue* top = consumeClipComponent(args, cssParserMode);
+    if (!top)
+        return nullptr;
+    bool needsComma = consumeCommaIncludingWhitespace(args);
+    CSSPrimitiveValue* right = consumeClipComponent(args, cssParserMode);
+    if (!right || (needsComma &amp;&amp; !consumeCommaIncludingWhitespace(args)))
+        return nullptr;
+    CSSPrimitiveValue* bottom = consumeClipComponent(args, cssParserMode);
+    if (!bottom || (needsComma &amp;&amp; !consumeCommaIncludingWhitespace(args)))
+        return nullptr;
+    CSSPrimitiveValue* left = consumeClipComponent(args, cssParserMode);
+    if (!left || !args.atEnd())
+        return nullptr;
+    return CSSQuadValue::create(top, right, bottom, left, CSSQuadValue::SerializeAsRect);
+}
+
+static bool consumePan(CSSParserTokenRange&amp; range, CSSValue*&amp; panX, CSSValue*&amp; panY)
+{
+    CSSValueID id = range.peek().id();
+    if ((id == CSSValuePanX || id == CSSValuePanRight || id == CSSValuePanLeft) &amp;&amp; !panX) {
+        if (id != CSSValuePanX &amp;&amp; !RuntimeEnabledFeatures::cssTouchActionPanDirectionsEnabled())
+            return false;
+        panX = consumeIdent(range);
+    } else if ((id == CSSValuePanY || id == CSSValuePanDown || id == CSSValuePanUp) &amp;&amp; !panY) {
+        if (id != CSSValuePanY &amp;&amp; !RuntimeEnabledFeatures::cssTouchActionPanDirectionsEnabled())
+            return false;
+        panY = consumeIdent(range);
+    } else {
+        return false;
+    }
+    return true;
+}
+
+static CSSValue* consumeTouchAction(CSSParserTokenRange&amp; range)
+{
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueManipulation) {
+        list-&gt;append(*consumeIdent(range));
+        return list;
+    }
+
+    CSSValue* panX = nullptr;
+    CSSValue* panY = nullptr;
+    if (!consumePan(range, panX, panY))
+        return nullptr;
+    if (!range.atEnd() &amp;&amp; !consumePan(range, panX, panY))
+        return nullptr;
+
+    if (panX)
+        list-&gt;append(*panX);
+    if (panY)
+        list-&gt;append(*panY);
+    return list;
+}
+
+static CSSPrimitiveValue* consumeLineClamp(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().type() != PercentageToken &amp;&amp; range.peek().type() != NumberToken)
+        return nullptr;
+    CSSPrimitiveValue* clampValue = consumePercent(range, ValueRangeNonNegative);
+    if (clampValue)
+        return clampValue;
+    // When specifying number of lines, don't allow 0 as a valid value.
+    return consumePositiveInteger(range);
+}
+
+static CSSValue* consumeLocale(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+    return consumeString(range);
+}
+
+static CSSValue* consumeColumnWidth(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+    // Always parse lengths in strict mode here, since it would be ambiguous otherwise when used in
+    // the 'columns' shorthand property.
+    CSSPrimitiveValue* columnWidth = consumeLength(range, HTMLStandardMode, ValueRangeNonNegative);
+    if (!columnWidth || (!columnWidth-&gt;isCalculated() &amp;&amp; columnWidth-&gt;getDoubleValue() == 0))
+        return nullptr;
+    return columnWidth;
+}
+
+static CSSValue* consumeColumnCount(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+    return consumePositiveInteger(range);
+}
+
+static CSSValue* consumeColumnGap(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (range.peek().id() == CSSValueNormal)
+        return consumeIdent(range);
+    return consumeLength(range, cssParserMode, ValueRangeNonNegative);
+}
+
+static CSSValue* consumeColumnSpan(CSSParserTokenRange&amp; range)
+{
+    return consumeIdent&lt;CSSValueAll, CSSValueNone&gt;(range);
+}
+
+static CSSValue* consumeZoom(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    const CSSParserToken&amp; token = range.peek();
+    CSSPrimitiveValue* zoom = nullptr;
+    if (token.type() == IdentToken) {
+        zoom = consumeIdent&lt;CSSValueNormal, CSSValueReset, CSSValueDocument&gt;(range);
+    } else {
+        zoom = consumePercent(range, ValueRangeNonNegative);
+        if (!zoom)
+            zoom = consumeNumber(range, ValueRangeNonNegative);
+    }
+    if (zoom &amp;&amp; context.useCounter()
+        &amp;&amp; !(token.id() == CSSValueNormal
+            || (token.type() == NumberToken &amp;&amp; zoom-&gt;getDoubleValue() == 1)
+            || (token.type() == PercentageToken &amp;&amp; zoom-&gt;getDoubleValue() == 100)))
+        context.useCounter()-&gt;count(UseCounter::CSSZoomNotEqualToOne);
+    return zoom;
+}
+
+static CSSValue* consumeAnimationIterationCount(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueInfinite)
+        return consumeIdent(range);
+    return consumeNumber(range, ValueRangeNonNegative);
+}
+
+static CSSValue* consumeAnimationName(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context, bool allowQuotedName)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+
+    if (allowQuotedName &amp;&amp; range.peek().type() == StringToken) {
+        // Legacy support for strings in prefixed animations.
+        if (context.useCounter())
+            context.useCounter()-&gt;count(UseCounter::QuotedAnimationName);
+
+        const CSSParserToken&amp; token = range.consumeIncludingWhitespace();
+        if (equalIgnoringASCIICase(token.value(), &quot;none&quot;))
+            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
+        return CSSCustomIdentValue::create(token.value().toString());
+    }
+
+    return consumeCustomIdent(range);
+}
+
+static CSSValue* consumeTransitionProperty(CSSParserTokenRange&amp; range)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (token.type() != IdentToken)
+        return nullptr;
+    if (token.id() == CSSValueNone)
+        return consumeIdent(range);
+
+    if (CSSPropertyID property = token.parseAsUnresolvedCSSPropertyID()) {
+        ASSERT(CSSPropertyMetadata::isEnabledProperty(property));
+        range.consumeIncludingWhitespace();
+        return CSSCustomIdentValue::create(property);
+    }
+    return consumeCustomIdent(range);
+}
+
+static CSSValue* consumeSteps(CSSParserTokenRange&amp; range)
+{
+    ASSERT(range.peek().functionId() == CSSValueSteps);
+    CSSParserTokenRange rangeCopy = range;
+    CSSParserTokenRange args = consumeFunction(rangeCopy);
+
+    CSSPrimitiveValue* steps = consumePositiveInteger(args);
+    if (!steps)
+        return nullptr;
+
+    StepsTimingFunction::StepPosition position = StepsTimingFunction::StepPosition::END;
+    if (consumeCommaIncludingWhitespace(args)) {
+        switch (args.consumeIncludingWhitespace().id()) {
+        case CSSValueMiddle:
+            if (!RuntimeEnabledFeatures::webAnimationsAPIEnabled())
+                return nullptr;
+            position = StepsTimingFunction::StepPosition::MIDDLE;
+            break;
+        case CSSValueStart:
+            position = StepsTimingFunction::StepPosition::START;
+            break;
+        case CSSValueEnd:
+            position = StepsTimingFunction::StepPosition::END;
+            break;
+        default:
+            return nullptr;
+        }
+    }
+
+    if (!args.atEnd())
+        return nullptr;
+
+    range = rangeCopy;
+    return CSSStepsTimingFunctionValue::create(steps-&gt;getIntValue(), position);
+}
+
+static CSSValue* consumeCubicBezier(CSSParserTokenRange&amp; range)
+{
+    ASSERT(range.peek().functionId() == CSSValueCubicBezier);
+    CSSParserTokenRange rangeCopy = range;
+    CSSParserTokenRange args = consumeFunction(rangeCopy);
+
+    double x1, y1, x2, y2;
+    if (consumeNumberRaw(args, x1)
+        &amp;&amp; x1 &gt;= 0 &amp;&amp; x1 &lt;= 1
+        &amp;&amp; consumeCommaIncludingWhitespace(args)
+        &amp;&amp; consumeNumberRaw(args, y1)
+        &amp;&amp; consumeCommaIncludingWhitespace(args)
+        &amp;&amp; consumeNumberRaw(args, x2)
+        &amp;&amp; x2 &gt;= 0 &amp;&amp; x2 &lt;= 1
+        &amp;&amp; consumeCommaIncludingWhitespace(args)
+        &amp;&amp; consumeNumberRaw(args, y2)
+        &amp;&amp; args.atEnd()) {
+        range = rangeCopy;
+        return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
+    }
+
+    return nullptr;
+}
+
+static CSSValue* consumeAnimationTimingFunction(CSSParserTokenRange&amp; range)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueEase || id == CSSValueLinear || id == CSSValueEaseIn
+        || id == CSSValueEaseOut || id == CSSValueEaseInOut || id == CSSValueStepStart
+        || id == CSSValueStepEnd || id == CSSValueStepMiddle)
+        return consumeIdent(range);
+
+    CSSValueID function = range.peek().functionId();
+    if (function == CSSValueSteps)
+        return consumeSteps(range);
+    if (function == CSSValueCubicBezier)
+        return consumeCubicBezier(range);
+    return nullptr;
+}
+
+static CSSValue* consumeAnimationValue(CSSPropertyID property, CSSParserTokenRange&amp; range, const CSSParserContext&amp; context, bool useLegacyParsing)
+{
+    switch (property) {
+    case CSSPropertyAnimationDelay:
+    case CSSPropertyTransitionDelay:
+        return consumeTime(range, ValueRangeAll);
+    case CSSPropertyAnimationDirection:
+        return consumeIdent&lt;CSSValueNormal, CSSValueAlternate, CSSValueReverse, CSSValueAlternateReverse&gt;(range);
+    case CSSPropertyAnimationDuration:
+    case CSSPropertyTransitionDuration:
+        return consumeTime(range, ValueRangeNonNegative);
+    case CSSPropertyAnimationFillMode:
+        return consumeIdent&lt;CSSValueNone, CSSValueForwards, CSSValueBackwards, CSSValueBoth&gt;(range);
+    case CSSPropertyAnimationIterationCount:
+        return consumeAnimationIterationCount(range);
+    case CSSPropertyAnimationName:
+        return consumeAnimationName(range, context, useLegacyParsing);
+    case CSSPropertyAnimationPlayState:
+        return consumeIdent&lt;CSSValueRunning, CSSValuePaused&gt;(range);
+    case CSSPropertyTransitionProperty:
+        return consumeTransitionProperty(range);
+    case CSSPropertyAnimationTimingFunction:
+    case CSSPropertyTransitionTimingFunction:
+        return consumeAnimationTimingFunction(range);
+    default:
+        ASSERT_NOT_REACHED();
+        return nullptr;
+    }
+}
+
+static bool isValidAnimationPropertyList(CSSPropertyID property, const CSSValueList&amp; valueList)
+{
+    if (property != CSSPropertyTransitionProperty || valueList.length() &lt; 2)
+        return true;
+    for (auto&amp; value : valueList) {
+        if (value-&gt;isPrimitiveValue() &amp;&amp; toCSSPrimitiveValue(*value).isValueID()
+            &amp;&amp; toCSSPrimitiveValue(*value).getValueID() == CSSValueNone)
+            return false;
+    }
+    return true;
+}
+
+static CSSValueList* consumeAnimationPropertyList(CSSPropertyID property, CSSParserTokenRange&amp; range, const CSSParserContext&amp; context, bool useLegacyParsing)
+{
+    CSSValueList* list = CSSValueList::createCommaSeparated();
+    do {
+        CSSValue* value = consumeAnimationValue(property, range, context, useLegacyParsing);
+        if (!value)
+            return nullptr;
+        list-&gt;append(*value);
+    } while (consumeCommaIncludingWhitespace(range));
+    if (!isValidAnimationPropertyList(property, *list))
+        return nullptr;
+    ASSERT(list-&gt;length());
+    return list;
+}
+
+bool CSSPropertyParser::consumeAnimationShorthand(const StylePropertyShorthand&amp; shorthand, bool useLegacyParsing, bool important)
+{
+    const unsigned longhandCount = shorthand.length();
+    CSSValueList* longhands[8];
+    ASSERT(longhandCount &lt;= 8);
+    for (size_t i = 0; i &lt; longhandCount; ++i)
+        longhands[i] = CSSValueList::createCommaSeparated();
+
+    do {
+        bool parsedLonghand[8] = { false };
+        do {
+            bool foundProperty = false;
+            for (size_t i = 0; i &lt; longhandCount; ++i) {
+                if (parsedLonghand[i])
+                    continue;
+
+                if (CSSValue* value = consumeAnimationValue(shorthand.properties()[i], m_range, m_context, useLegacyParsing)) {
+                    parsedLonghand[i] = true;
+                    foundProperty = true;
+                    longhands[i]-&gt;append(*value);
+                    break;
+                }
+            }
+            if (!foundProperty)
+                return false;
+        } while (!m_range.atEnd() &amp;&amp; m_range.peek().type() != CommaToken);
+
+        // FIXME: This will make invalid longhands, see crbug.com/386459
+        for (size_t i = 0; i &lt; longhandCount; ++i) {
+            if (!parsedLonghand[i])
+                longhands[i]-&gt;append(*CSSInitialValue::createLegacyImplicit());
+            parsedLonghand[i] = false;
+        }
+    } while (consumeCommaIncludingWhitespace(m_range));
+
+    for (size_t i = 0; i &lt; longhandCount; ++i) {
+        if (!isValidAnimationPropertyList(shorthand.properties()[i], *longhands[i]))
+            return false;
+    }
+
+    for (size_t i = 0; i &lt; longhandCount; ++i)
+        addProperty(shorthand.properties()[i], shorthand.id(), *longhands[i], important);
+
+    return m_range.atEnd();
+}
+
+static CSSValue* consumeZIndex(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+    return consumeInteger(range);
+}
+
+static CSSShadowValue* parseSingleShadow(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, bool allowInset, bool allowSpread)
+{
+    CSSPrimitiveValue* style = nullptr;
+    CSSValue* color = nullptr;
+
+    if (range.atEnd())
+        return nullptr;
+    if (range.peek().id() == CSSValueInset) {
+        if (!allowInset)
+            return nullptr;
+        style = consumeIdent(range);
+    }
+    color = consumeColor(range, cssParserMode);
+
+    CSSPrimitiveValue* horizontalOffset = consumeLength(range, cssParserMode, ValueRangeAll);
+    if (!horizontalOffset)
+        return nullptr;
+
+    CSSPrimitiveValue* verticalOffset = consumeLength(range, cssParserMode, ValueRangeAll);
+    if (!verticalOffset)
+        return nullptr;
+
+    CSSPrimitiveValue* blurRadius = consumeLength(range, cssParserMode, ValueRangeAll);
+    CSSPrimitiveValue* spreadDistance = nullptr;
+    if (blurRadius) {
+        // Blur radius must be non-negative.
+        if (blurRadius-&gt;getDoubleValue() &lt; 0)
+            return nullptr;
+        if (allowSpread)
+            spreadDistance = consumeLength(range, cssParserMode, ValueRangeAll);
+    }
+
+    if (!range.atEnd()) {
+        if (!color)
+            color = consumeColor(range, cssParserMode);
+        if (range.peek().id() == CSSValueInset) {
+            if (!allowInset || style)
+                return nullptr;
+            style = consumeIdent(range);
+        }
+    }
+    return CSSShadowValue::create(horizontalOffset, verticalOffset, blurRadius,
+        spreadDistance, style, color);
+}
+
+static CSSValue* consumeShadow(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, bool isBoxShadowProperty)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+
+    CSSValueList* shadowValueList = CSSValueList::createCommaSeparated();
+    do {
+        if (CSSShadowValue* shadowValue = parseSingleShadow(range, cssParserMode, isBoxShadowProperty, isBoxShadowProperty))
+            shadowValueList-&gt;append(*shadowValue);
+        else
+            return nullptr;
+    } while (consumeCommaIncludingWhitespace(range));
+    return shadowValueList;
+}
+
+static CSSFunctionValue* consumeFilterFunction(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    CSSValueID filterType = range.peek().functionId();
+    if (filterType &lt; CSSValueInvert || filterType &gt; CSSValueDropShadow)
+        return nullptr;
+    CSSParserTokenRange args = consumeFunction(range);
+    CSSFunctionValue* filterValue = CSSFunctionValue::create(filterType);
+    CSSValue* parsedValue = nullptr;
+
+    if (filterType == CSSValueDropShadow) {
+        parsedValue = parseSingleShadow(args, context.mode(), false, false);
+    } else {
+        if (args.atEnd()) {
+            if (context.useCounter())
+                context.useCounter()-&gt;count(UseCounter::CSSFilterFunctionNoArguments);
+            return filterValue;
+        }
+        if (filterType == CSSValueBrightness) {
+            // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
+            parsedValue = consumePercent(args, ValueRangeAll);
+            if (!parsedValue)
+                parsedValue = consumeNumber(args, ValueRangeAll);
+        } else if (filterType == CSSValueHueRotate) {
+            parsedValue = consumeAngle(args);
+        } else if (filterType == CSSValueBlur) {
+            parsedValue = consumeLength(args, HTMLStandardMode, ValueRangeNonNegative);
+        } else {
+            // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
+            parsedValue = consumePercent(args, ValueRangeNonNegative);
+            if (!parsedValue)
+                parsedValue = consumeNumber(args, ValueRangeNonNegative);
+            if (parsedValue &amp;&amp; filterType != CSSValueSaturate &amp;&amp; filterType != CSSValueContrast) {
+                bool isPercentage = toCSSPrimitiveValue(parsedValue)-&gt;isPercentage();
+                double maxAllowed = isPercentage ? 100.0 : 1.0;
+                if (toCSSPrimitiveValue(parsedValue)-&gt;getDoubleValue() &gt; maxAllowed) {
+                    parsedValue = CSSPrimitiveValue::create(
+                        maxAllowed,
+                        isPercentage ? CSSPrimitiveValue::UnitType::Percentage : CSSPrimitiveValue::UnitType::Number);
+                }
+            }
+        }
+    }
+    if (!parsedValue || !args.atEnd())
+        return nullptr;
+    filterValue-&gt;append(*parsedValue);
+    return filterValue;
+}
+
+static CSSValue* consumeFilter(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+    do {
+        CSSValue* filterValue = consumeUrl(range);
+        if (!filterValue) {
+            filterValue = consumeFilterFunction(range, context);
+            if (!filterValue)
+                return nullptr;
+        }
+        list-&gt;append(*filterValue);
+    } while (!range.atEnd());
+    return list;
+}
+
+static CSSValue* consumeTextDecorationLine(CSSParserTokenRange&amp; range)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueNone)
+        return consumeIdent(range);
+
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+    while (true) {
+        CSSPrimitiveValue* ident = consumeIdent&lt;CSSValueBlink, CSSValueUnderline, CSSValueOverline, CSSValueLineThrough&gt;(range);
+        if (!ident)
+            break;
+        if (list-&gt;hasValue(*ident))
+            return nullptr;
+        list-&gt;append(*ident);
+    }
+
+    if (!list-&gt;length())
+        return nullptr;
+    return list;
+}
+
+// none | strict | content | [ layout || style || paint || size ]
+static CSSValue* consumeContain(CSSParserTokenRange&amp; range)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueNone)
+        return consumeIdent(range);
+
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+    if (id == CSSValueStrict || id == CSSValueContent) {
+        list-&gt;append(*consumeIdent(range));
+        return list;
+    }
+    while (true) {
+        CSSPrimitiveValue* ident = consumeIdent&lt;CSSValuePaint, CSSValueLayout, CSSValueStyle, CSSValueSize&gt;(range);
+        if (!ident)
+            break;
+        if (list-&gt;hasValue(*ident))
+            return nullptr;
+        list-&gt;append(*ident);
+    }
+
+    if (!list-&gt;length())
+        return nullptr;
+    return list;
+}
+
+static CSSValue* consumePath(CSSParserTokenRange&amp; range)
+{
+    // FIXME: Add support for &lt;url&gt;, &lt;basic-shape&gt;, &lt;geometry-box&gt;.
+    if (range.peek().functionId() != CSSValuePath)
+        return nullptr;
+
+    CSSParserTokenRange functionRange = range;
+    CSSParserTokenRange functionArgs = consumeFunction(functionRange);
+
+    if (functionArgs.peek().type() != StringToken)
+        return nullptr;
+    String pathString = functionArgs.consumeIncludingWhitespace().value().toString();
+
+    std::unique_ptr&lt;SVGPathByteStream&gt; byteStream = SVGPathByteStream::create();
+    if (buildByteStreamFromString(pathString, *byteStream) != SVGParseStatus::NoError
+        || !functionArgs.atEnd())
+        return nullptr;
+
+    range = functionRange;
+    if (byteStream-&gt;isEmpty())
+        return CSSPrimitiveValue::createIdentifier(CSSValueNone);
+    return CSSPathValue::create(std::move(byteStream));
+}
+
+static CSSValue* consumePathOrNone(CSSParserTokenRange&amp; range)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueNone)
+        return consumeIdent(range);
+
+    return consumePath(range);
+}
+
+static CSSValue* consumeMotionRotation(CSSParserTokenRange&amp; range)
+{
+    CSSValue* angle = consumeAngle(range);
+    CSSValue* keyword = consumeIdent&lt;CSSValueAuto, CSSValueReverse&gt;(range);
+    if (!angle &amp;&amp; !keyword)
+        return nullptr;
+
+    if (!angle)
+        angle = consumeAngle(range);
+
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+    if (keyword)
+        list-&gt;append(*keyword);
+    if (angle)
+        list-&gt;append(*angle);
+    return list;
+}
+
+static CSSValue* consumeTextEmphasisStyle(CSSParserTokenRange&amp; range)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueNone)
+        return consumeIdent(range);
+
+    if (CSSValue* textEmphasisStyle = consumeString(range))
+        return textEmphasisStyle;
+
+    CSSPrimitiveValue* fill = consumeIdent&lt;CSSValueFilled, CSSValueOpen&gt;(range);
+    CSSPrimitiveValue* shape = consumeIdent&lt;CSSValueDot, CSSValueCircle, CSSValueDoubleCircle, CSSValueTriangle, CSSValueSesame&gt;(range);
+    if (!fill)
+        fill = consumeIdent&lt;CSSValueFilled, CSSValueOpen&gt;(range);
+    if (fill &amp;&amp; shape) {
+        CSSValueList* parsedValues = CSSValueList::createSpaceSeparated();
+        parsedValues-&gt;append(*fill);
+        parsedValues-&gt;append(*shape);
+        return parsedValues;
+    }
+    if (fill)
+        return fill;
+    if (shape)
+        return shape;
+    return nullptr;
+}
+
+static CSSValue* consumeOutlineColor(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    // Allow the special focus color even in HTML Standard parsing mode.
+    if (range.peek().id() == CSSValueWebkitFocusRingColor)
+        return consumeIdent(range);
+    return consumeColor(range, cssParserMode);
+}
+
+static CSSPrimitiveValue* consumeLineWidth(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
+        return consumeIdent(range);
+    return consumeLength(range, cssParserMode, ValueRangeNonNegative, unitless);
+}
+
+static CSSPrimitiveValue* consumeBorderWidth(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+    return consumeLineWidth(range, cssParserMode, unitless);
+}
+
+static CSSPrimitiveValue* consumeTextStrokeWidth(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid);
+}
+
+static CSSPrimitiveValue* consumeColumnRuleWidth(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid);
+}
+
+static bool consumeTranslate3d(CSSParserTokenRange&amp; args, CSSParserMode cssParserMode, CSSFunctionValue*&amp; transformValue)
+{
+    unsigned numberOfArguments = 2;
+    CSSValue* parsedValue = nullptr;
+    do {
+        parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+        if (!parsedValue)
+            return false;
+        transformValue-&gt;append(*parsedValue);
+        if (!consumeCommaIncludingWhitespace(args))
+            return false;
+    } while (--numberOfArguments);
+    parsedValue = consumeLength(args, cssParserMode, ValueRangeAll);
+    if (!parsedValue)
+        return false;
+    transformValue-&gt;append(*parsedValue);
+    return true;
+}
+
+static bool consumeNumbers(CSSParserTokenRange&amp; args, CSSFunctionValue*&amp; transformValue, unsigned numberOfArguments)
+{
+    do {
+        CSSValue* parsedValue = consumeNumber(args, ValueRangeAll);
+        if (!parsedValue)
+            return false;
+        transformValue-&gt;append(*parsedValue);
+        if (--numberOfArguments &amp;&amp; !consumeCommaIncludingWhitespace(args))
+            return false;
+    } while (numberOfArguments);
+    return true;
+}
+
+static bool consumePerspective(CSSParserTokenRange&amp; args, CSSParserMode cssParserMode, CSSFunctionValue*&amp; transformValue, bool useLegacyParsing)
+{
+    CSSPrimitiveValue* parsedValue = consumeLength(args, cssParserMode, ValueRangeNonNegative);
+    if (!parsedValue &amp;&amp; useLegacyParsing) {
+        double perspective;
+        if (!consumeNumberRaw(args, perspective) || perspective &lt; 0)
+            return false;
+        parsedValue = CSSPrimitiveValue::create(perspective, CSSPrimitiveValue::UnitType::Pixels);
+    }
+    if (!parsedValue)
+        return false;
+    transformValue-&gt;append(*parsedValue);
+    return true;
+}
+
+static CSSValue* consumeTransformValue(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, bool useLegacyParsing)
+{
+    CSSValueID functionId = range.peek().functionId();
+    if (functionId == CSSValueInvalid)
+        return nullptr;
+    CSSParserTokenRange args = consumeFunction(range);
+    if (args.atEnd())
+        return nullptr;
+    CSSFunctionValue* transformValue = CSSFunctionValue::create(functionId);
+    CSSValue* parsedValue = nullptr;
+    switch (functionId) {
+    case CSSValueRotate:
+    case CSSValueRotateX:
+    case CSSValueRotateY:
+    case CSSValueRotateZ:
+    case CSSValueSkewX:
+    case CSSValueSkewY:
+    case CSSValueSkew:
+        parsedValue = consumeAngle(args);
+        if (!parsedValue)
+            return nullptr;
+        if (functionId == CSSValueSkew &amp;&amp; consumeCommaIncludingWhitespace(args)) {
+            transformValue-&gt;append(*parsedValue);
+            parsedValue = consumeAngle(args);
+            if (!parsedValue)
+                return nullptr;
+        }
+        break;
+    case CSSValueScaleX:
+    case CSSValueScaleY:
+    case CSSValueScaleZ:
+    case CSSValueScale:
+        parsedValue = consumeNumber(args, ValueRangeAll);
+        if (!parsedValue)
+            return nullptr;
+        if (functionId == CSSValueScale &amp;&amp; consumeCommaIncludingWhitespace(args)) {
+            transformValue-&gt;append(*parsedValue);
+            parsedValue = consumeNumber(args, ValueRangeAll);
+            if (!parsedValue)
+                return nullptr;
+        }
+        break;
+    case CSSValuePerspective:
+        if (!consumePerspective(args, cssParserMode, transformValue, useLegacyParsing))
+            return nullptr;
+        break;
+    case CSSValueTranslateX:
+    case CSSValueTranslateY:
+    case CSSValueTranslate:
+        parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+        if (!parsedValue)
+            return nullptr;
+        if (functionId == CSSValueTranslate &amp;&amp; consumeCommaIncludingWhitespace(args)) {
+            transformValue-&gt;append(*parsedValue);
+            parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+            if (!parsedValue)
+                return nullptr;
+        }
+        break;
+    case CSSValueTranslateZ:
+        parsedValue = consumeLength(args, cssParserMode, ValueRangeAll);
+        break;
+    case CSSValueMatrix:
+    case CSSValueMatrix3d:
+        if (!consumeNumbers(args, transformValue, (functionId == CSSValueMatrix3d) ? 16 : 6))
+            return nullptr;
+        break;
+    case CSSValueScale3d:
+        if (!consumeNumbers(args, transformValue, 3))
+            return nullptr;
+        break;
+    case CSSValueRotate3d:
+        if (!consumeNumbers(args, transformValue, 3) || !consumeCommaIncludingWhitespace(args))
+            return nullptr;
+        parsedValue = consumeAngle(args);
+        if (!parsedValue)
+            return nullptr;
+        break;
+    case CSSValueTranslate3d:
+        if (!consumeTranslate3d(args, cssParserMode, transformValue))
+            return nullptr;
+        break;
+    default:
+        return nullptr;
+    }
+    if (parsedValue)
+        transformValue-&gt;append(*parsedValue);
+    if (!args.atEnd())
+        return nullptr;
+    return transformValue;
+}
+
+static CSSValue* consumeTransform(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, bool useLegacyParsing)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+    do {
+        CSSValue* parsedTransformValue = consumeTransformValue(range, cssParserMode, useLegacyParsing);
+        if (!parsedTransformValue)
+            return nullptr;
+        list-&gt;append(*parsedTransformValue);
+    } while (!range.atEnd());
+
+    return list;
+}
+
+template &lt;CSSValueID start, CSSValueID end&gt;
+static CSSValue* consumePositionLonghand(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (range.peek().type() == IdentToken) {
+        CSSValueID id = range.peek().id();
+        int percent;
+        if (id == start)
+            percent = 0;
+        else if (id == CSSValueCenter)
+            percent = 50;
+        else if (id == end)
+            percent = 100;
+        else
+            return nullptr;
+        range.consumeIncludingWhitespace();
+        return CSSPrimitiveValue::create(percent, CSSPrimitiveValue::UnitType::Percentage);
+    }
+    return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
+}
+
+static CSSValue* consumePositionX(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    return consumePositionLonghand&lt;CSSValueLeft, CSSValueRight&gt;(range, cssParserMode);
+}
+
+static CSSValue* consumePositionY(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    return consumePositionLonghand&lt;CSSValueTop, CSSValueBottom&gt;(range, cssParserMode);
+}
+
+static CSSValue* consumePaintStroke(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    CSSURIValue* url = consumeUrl(range);
+    if (url) {
+        CSSValue* parsedValue = nullptr;
+        if (range.peek().id() == CSSValueNone)
+            parsedValue = consumeIdent(range);
+        else
+            parsedValue = consumeColor(range, cssParserMode);
+        if (parsedValue) {
+            CSSValueList* values = CSSValueList::createSpaceSeparated();
+            values-&gt;append(*url);
+            values-&gt;append(*parsedValue);
+            return values;
+        }
+        return url;
+    }
+    return consumeColor(range, cssParserMode);
+}
+
+static CSSValue* consumePaintOrder(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueNormal)
+        return consumeIdent(range);
+
+    Vector&lt;CSSValueID, 3&gt; paintTypeList;
+    CSSPrimitiveValue* fill = nullptr;
+    CSSPrimitiveValue* stroke = nullptr;
+    CSSPrimitiveValue* markers = nullptr;
+    do {
+        CSSValueID id = range.peek().id();
+        if (id == CSSValueFill &amp;&amp; !fill)
+            fill = consumeIdent(range);
+        else if (id == CSSValueStroke &amp;&amp; !stroke)
+            stroke = consumeIdent(range);
+        else if (id == CSSValueMarkers &amp;&amp; !markers)
+            markers = consumeIdent(range);
+        else
+            return nullptr;
+        paintTypeList.append(id);
+    } while (!range.atEnd());
+
+    // After parsing we serialize the paint-order list. Since it is not possible to
+    // pop a last list items from CSSValueList without bigger cost, we create the
+    // list after parsing.
+    CSSValueID firstPaintOrderType = paintTypeList.at(0);
+    CSSValueList* paintOrderList = CSSValueList::createSpaceSeparated();
+    switch (firstPaintOrderType) {
+    case CSSValueFill:
+    case CSSValueStroke:
+        paintOrderList-&gt;append(firstPaintOrderType == CSSValueFill ? *fill : *stroke);
+        if (paintTypeList.size() &gt; 1) {
+            if (paintTypeList.at(1) == CSSValueMarkers)
+                paintOrderList-&gt;append(*markers);
+        }
+        break;
+    case CSSValueMarkers:
+        paintOrderList-&gt;append(*markers);
+        if (paintTypeList.size() &gt; 1) {
+            if (paintTypeList.at(1) == CSSValueStroke)
+                paintOrderList-&gt;append(*stroke);
+        }
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    return paintOrderList;
+}
+
+static CSSValue* consumeNoneOrURI(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    return consumeUrl(range);
+}
+
+static CSSValue* consumeFlexBasis(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    // FIXME: Support intrinsic dimensions too.
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+    return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
+}
+
+static CSSValue* consumeStrokeDasharray(CSSParserTokenRange&amp; range)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueNone)
+        return consumeIdent(range);
+
+    CSSValueList* dashes = CSSValueList::createCommaSeparated();
+    do {
+        CSSPrimitiveValue* dash = consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeNonNegative);
+        if (!dash || (consumeCommaIncludingWhitespace(range) &amp;&amp; range.atEnd()))
+            return nullptr;
+        dashes-&gt;append(*dash);
+    } while (!range.atEnd());
+    return dashes;
+}
+
+static CSSPrimitiveValue* consumeBaselineShift(CSSParserTokenRange&amp; range)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueBaseline || id == CSSValueSub || id == CSSValueSuper)
+        return consumeIdent(range);
+    return consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeAll);
+}
+
+static CSSPrimitiveValue* consumeRxOrRy(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+    return consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
+}
+
+static CSSValue* consumeCursor(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context, bool inQuirksMode)
+{
+    CSSValueList* list = nullptr;
+    while (CSSValue* image = consumeImage(range, context, ConsumeGeneratedImage::Forbid)) {
+        double num;
+        IntPoint hotSpot(-1, -1);
+        bool hotSpotSpecified = false;
+        if (consumeNumberRaw(range, num)) {
+            hotSpot.setX(int(num));
+            if (!consumeNumberRaw(range, num))
+                return nullptr;
+            hotSpot.setY(int(num));
+            hotSpotSpecified = true;
+        }
+
+        if (!list)
+            list = CSSValueList::createCommaSeparated();
+
+        list-&gt;append(*CSSCursorImageValue::create(image, hotSpotSpecified, hotSpot));
+        if (!consumeCommaIncludingWhitespace(range))
+            return nullptr;
+    }
+
+    CSSValueID id = range.peek().id();
+    if (!range.atEnd() &amp;&amp; context.useCounter()) {
+        if (id == CSSValueWebkitZoomIn)
+            context.useCounter()-&gt;count(UseCounter::PrefixedCursorZoomIn);
+        else if (id == CSSValueWebkitZoomOut)
+            context.useCounter()-&gt;count(UseCounter::PrefixedCursorZoomOut);
+    }
+    CSSValue* cursorType = nullptr;
+    if (id == CSSValueHand) {
+        if (!inQuirksMode) // Non-standard behavior
+            return nullptr;
+        cursorType = CSSPrimitiveValue::createIdentifier(CSSValuePointer);
+        range.consumeIncludingWhitespace();
+    } else if ((id &gt;= CSSValueAuto &amp;&amp; id &lt;= CSSValueWebkitZoomOut) || id == CSSValueCopy || id == CSSValueNone) {
+        cursorType = consumeIdent(range);
+    } else {
+        return nullptr;
+    }
+
+    if (!list)
+        return cursorType;
+    list-&gt;append(*cursorType);
+    return list;
+}
+
+static CSSValue* consumeAttr(CSSParserTokenRange args, CSSParserContext context)
+{
+    if (args.peek().type() != IdentToken)
+        return nullptr;
+
+    String attrName = args.consumeIncludingWhitespace().value().toString();
+    if (!args.atEnd())
+        return nullptr;
+
+    if (context.isHTMLDocument())
+        attrName = attrName.lower();
+
+    CSSFunctionValue* attrValue = CSSFunctionValue::create(CSSValueAttr);
+    attrValue-&gt;append(*CSSCustomIdentValue::create(attrName));
+    return attrValue;
+}
+
+static CSSValue* consumeCounterContent(CSSParserTokenRange args, bool counters)
+{
+    CSSCustomIdentValue* identifier = consumeCustomIdent(args);
+    if (!identifier)
+        return nullptr;
+
+    CSSStringValue* separator = nullptr;
+    if (!counters) {
+        separator = CSSStringValue::create(String());
+    } else {
+        if (!consumeCommaIncludingWhitespace(args) || args.peek().type() != StringToken)
+            return nullptr;
+        separator = CSSStringValue::create(args.consumeIncludingWhitespace().value().toString());
+    }
+
+    CSSPrimitiveValue* listStyle = nullptr;
+    if (consumeCommaIncludingWhitespace(args)) {
+        CSSValueID id = args.peek().id();
+        if ((id != CSSValueNone &amp;&amp; (id &lt; CSSValueDisc || id &gt; CSSValueKatakanaIroha)))
+            return nullptr;
+        listStyle = consumeIdent(args);
+    } else {
+        listStyle = CSSPrimitiveValue::createIdentifier(CSSValueDecimal);
+    }
+
+    if (!args.atEnd())
+        return nullptr;
+    return CSSCounterValue::create(identifier, listStyle, separator);
+}
+
+static CSSValue* consumeContent(CSSParserTokenRange&amp; range, CSSParserContext context)
+{
+    if (identMatches&lt;CSSValueNone, CSSValueNormal&gt;(range.peek().id()))
+        return consumeIdent(range);
+
+    CSSValueList* values = CSSValueList::createSpaceSeparated();
+
+    do {
+        CSSValue* parsedValue = consumeImage(range, context);
+        if (!parsedValue)
+            parsedValue = consumeIdent&lt;CSSValueOpenQuote, CSSValueCloseQuote, CSSValueNoOpenQuote, CSSValueNoCloseQuote&gt;(range);
+        if (!parsedValue)
+            parsedValue = consumeString(range);
+        if (!parsedValue) {
+            if (range.peek().functionId() == CSSValueAttr)
+                parsedValue = consumeAttr(consumeFunction(range), context);
+            else if (range.peek().functionId() == CSSValueCounter)
+                parsedValue = consumeCounterContent(consumeFunction(range), false);
+            else if (range.peek().functionId() == CSSValueCounters)
+                parsedValue = consumeCounterContent(consumeFunction(range), true);
+            if (!parsedValue)
+                return nullptr;
+        }
+        values-&gt;append(*parsedValue);
+    } while (!range.atEnd());
+
+    return values;
+}
+
+static CSSPrimitiveValue* consumePerspective(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, CSSPropertyID unresolvedProperty)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    CSSPrimitiveValue* parsedValue = consumeLength(range, cssParserMode, ValueRangeAll);
+    if (!parsedValue &amp;&amp; (unresolvedProperty == CSSPropertyAliasWebkitPerspective)) {
+        double perspective;
+        if (!consumeNumberRaw(range, perspective))
+            return nullptr;
+        parsedValue = CSSPrimitiveValue::create(perspective, CSSPrimitiveValue::UnitType::Pixels);
+    }
+    if (parsedValue &amp;&amp; (parsedValue-&gt;isCalculated() || parsedValue-&gt;getDoubleValue() &gt; 0))
+        return parsedValue;
+    return nullptr;
+}
+
+static CSSValueList* consumePositionList(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    CSSValueList* positions = CSSValueList::createCommaSeparated();
+    do {
+        CSSValue* position = consumePosition(range, cssParserMode, UnitlessQuirk::Forbid);
+        if (!position)
+            return nullptr;
+        positions-&gt;append(*position);
+    } while (consumeCommaIncludingWhitespace(range));
+    return positions;
+}
+
+static CSSValue* consumeScrollSnapCoordinate(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    return consumePositionList(range, cssParserMode);
+}
+
+static CSSValue* consumeScrollSnapPoints(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    if (range.peek().functionId() == CSSValueRepeat) {
+        CSSParserTokenRange args = consumeFunction(range);
+        CSSPrimitiveValue* parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeNonNegative);
+        if (args.atEnd() &amp;&amp; parsedValue &amp;&amp; (parsedValue-&gt;isCalculated() || parsedValue-&gt;getDoubleValue() &gt; 0)) {
+            CSSFunctionValue* result = CSSFunctionValue::create(CSSValueRepeat);
+            result-&gt;append(*parsedValue);
+            return result;
+        }
+    }
+    return nullptr;
+}
+
+static CSSValue* consumeBorderRadiusCorner(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    CSSValue* parsedValue1 = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
+    if (!parsedValue1)
+        return nullptr;
+    CSSValue* parsedValue2 = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
+    if (!parsedValue2)
+        parsedValue2 = parsedValue1;
+    return CSSValuePair::create(parsedValue1, parsedValue2, CSSValuePair::DropIdenticalValues);
+}
+
+static CSSPrimitiveValue* consumeVerticalAlign(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    CSSPrimitiveValue* parsedValue = consumeIdentRange(range, CSSValueBaseline, CSSValueWebkitBaselineMiddle);
+    if (!parsedValue)
+        parsedValue = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
+    return parsedValue;
+}
+
+static CSSPrimitiveValue* consumeShapeRadius(CSSParserTokenRange&amp; args, CSSParserMode cssParserMode)
+{
+    if (identMatches&lt;CSSValueClosestSide, CSSValueFarthestSide&gt;(args.peek().id()))
+        return consumeIdent(args);
+    return consumeLengthOrPercent(args, cssParserMode, ValueRangeNonNegative);
+}
+
+static CSSBasicShapeCircleValue* consumeBasicShapeCircle(CSSParserTokenRange&amp; args, const CSSParserContext&amp; context)
+{
+    // spec: https://drafts.csswg.org/css-shapes/#supported-basic-shapes
+    // circle( [&lt;shape-radius&gt;]? [at &lt;position&gt;]? )
+    CSSBasicShapeCircleValue* shape = CSSBasicShapeCircleValue::create();
+    if (CSSPrimitiveValue* radius = consumeShapeRadius(args, context.mode()))
+        shape-&gt;setRadius(radius);
+    if (consumeIdent&lt;CSSValueAt&gt;(args)) {
+        CSSValue* centerX = nullptr;
+        CSSValue* centerY = nullptr;
+        if (!consumePosition(args, context.mode(), UnitlessQuirk::Forbid, centerX, centerY))
+            return nullptr;
+        shape-&gt;setCenterX(centerX);
+        shape-&gt;setCenterY(centerY);
+    }
+    return shape;
+}
+
+static CSSBasicShapeEllipseValue* consumeBasicShapeEllipse(CSSParserTokenRange&amp; args, const CSSParserContext&amp; context)
+{
+    // spec: https://drafts.csswg.org/css-shapes/#supported-basic-shapes
+    // ellipse( [&lt;shape-radius&gt;{2}]? [at &lt;position&gt;]? )
+    CSSBasicShapeEllipseValue* shape = CSSBasicShapeEllipseValue::create();
+    if (CSSPrimitiveValue* radiusX = consumeShapeRadius(args, context.mode())) {
+        shape-&gt;setRadiusX(radiusX);
+        if (CSSPrimitiveValue* radiusY = consumeShapeRadius(args, context.mode()))
+            shape-&gt;setRadiusY(radiusY);
+    }
+    if (consumeIdent&lt;CSSValueAt&gt;(args)) {
+        CSSValue* centerX = nullptr;
+        CSSValue* centerY = nullptr;
+        if (!consumePosition(args, context.mode(), UnitlessQuirk::Forbid, centerX, centerY))
+            return nullptr;
+        shape-&gt;setCenterX(centerX);
+        shape-&gt;setCenterY(centerY);
+    }
+    return shape;
+}
+
+static CSSBasicShapePolygonValue* consumeBasicShapePolygon(CSSParserTokenRange&amp; args, const CSSParserContext&amp; context)
+{
+    CSSBasicShapePolygonValue* shape = CSSBasicShapePolygonValue::create();
+    if (identMatches&lt;CSSValueEvenodd, CSSValueNonzero&gt;(args.peek().id())) {
+        shape-&gt;setWindRule(args.consumeIncludingWhitespace().id() == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
+        if (!consumeCommaIncludingWhitespace(args))
+            return nullptr;
+    }
+
+    do {
+        CSSPrimitiveValue* xLength = consumeLengthOrPercent(args, context.mode(), ValueRangeAll);
+        if (!xLength)
+            return nullptr;
+        CSSPrimitiveValue* yLength = consumeLengthOrPercent(args, context.mode(), ValueRangeAll);
+        if (!yLength)
+            return nullptr;
+        shape-&gt;appendPoint(xLength, yLength);
+    } while (consumeCommaIncludingWhitespace(args));
+    return shape;
+}
+
+static void complete4Sides(CSSPrimitiveValue* side[4])
+{
+    if (side[3])
+        return;
+    if (!side[2]) {
+        if (!side[1])
+            side[1] = side[0];
+        side[2] = side[0];
+    }
+    side[3] = side[1];
+}
+
+static bool consumeRadii(CSSPrimitiveValue* horizontalRadii[4], CSSPrimitiveValue* verticalRadii[4], CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, bool useLegacyParsing)
+{
+    unsigned i = 0;
+    for (; i &lt; 4 &amp;&amp; !range.atEnd() &amp;&amp; range.peek().type() != DelimiterToken; ++i) {
+        horizontalRadii[i] = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
+        if (!horizontalRadii[i])
+            return false;
+    }
+    if (!horizontalRadii[0])
+        return false;
+    if (range.atEnd()) {
+        // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
+        if (useLegacyParsing &amp;&amp; i == 2) {
+            verticalRadii[0] = horizontalRadii[1];
+            horizontalRadii[1] = nullptr;
+        } else {
+            complete4Sides(horizontalRadii);
+            for (unsigned i = 0; i &lt; 4; ++i)
+                verticalRadii[i] = horizontalRadii[i];
+            return true;
+        }
+    } else {
+        if (!consumeSlashIncludingWhitespace(range))
+            return false;
+        for (i = 0; i &lt; 4 &amp;&amp; !range.atEnd(); ++i) {
+            verticalRadii[i] = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
+            if (!verticalRadii[i])
+                return false;
+        }
+        if (!verticalRadii[0] || !range.atEnd())
+            return false;
+    }
+    complete4Sides(horizontalRadii);
+    complete4Sides(verticalRadii);
+    return true;
+}
+
+static CSSBasicShapeInsetValue* consumeBasicShapeInset(CSSParserTokenRange&amp; args, const CSSParserContext&amp; context)
+{
+    CSSBasicShapeInsetValue* shape = CSSBasicShapeInsetValue::create();
+    CSSPrimitiveValue* top = consumeLengthOrPercent(args, context.mode(), ValueRangeAll);
+    if (!top)
+        return nullptr;
+    CSSPrimitiveValue* right = consumeLengthOrPercent(args, context.mode(), ValueRangeAll);
+    CSSPrimitiveValue* bottom = nullptr;
+    CSSPrimitiveValue* left = nullptr;
+    if (right) {
+        bottom = consumeLengthOrPercent(args, context.mode(), ValueRangeAll);
+        if (bottom)
+            left = consumeLengthOrPercent(args, context.mode(), ValueRangeAll);
+    }
+    if (left)
+        shape-&gt;updateShapeSize4Values(top, right, bottom, left);
+    else if (bottom)
+        shape-&gt;updateShapeSize3Values(top, right, bottom);
+    else if (right)
+        shape-&gt;updateShapeSize2Values(top, right);
+    else
+        shape-&gt;updateShapeSize1Value(top);
+
+    if (consumeIdent&lt;CSSValueRound&gt;(args)) {
+        CSSPrimitiveValue* horizontalRadii[4] = { 0 };
+        CSSPrimitiveValue* verticalRadii[4] = { 0 };
+        if (!consumeRadii(horizontalRadii, verticalRadii, args, context.mode(), false))
+            return nullptr;
+        shape-&gt;setTopLeftRadius(CSSValuePair::create(horizontalRadii[0], verticalRadii[0], CSSValuePair::DropIdenticalValues));
+        shape-&gt;setTopRightRadius(CSSValuePair::create(horizontalRadii[1], verticalRadii[1], CSSValuePair::DropIdenticalValues));
+        shape-&gt;setBottomRightRadius(CSSValuePair::create(horizontalRadii[2], verticalRadii[2], CSSValuePair::DropIdenticalValues));
+        shape-&gt;setBottomLeftRadius(CSSValuePair::create(horizontalRadii[3], verticalRadii[3], CSSValuePair::DropIdenticalValues));
+    }
+    return shape;
+}
+
+static CSSValue* consumeBasicShape(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    CSSValue* shape = nullptr;
+    if (range.peek().type() != FunctionToken)
+        return nullptr;
+    CSSValueID id = range.peek().functionId();
+    CSSParserTokenRange rangeCopy = range;
+    CSSParserTokenRange args = consumeFunction(rangeCopy);
+    if (id == CSSValueCircle)
+        shape = consumeBasicShapeCircle(args, context);
+    else if (id == CSSValueEllipse)
+        shape = consumeBasicShapeEllipse(args, context);
+    else if (id == CSSValuePolygon)
+        shape = consumeBasicShapePolygon(args, context);
+    else if (id == CSSValueInset)
+        shape = consumeBasicShapeInset(args, context);
+    if (!shape || !args.atEnd())
+        return nullptr;
+    range = rangeCopy;
+    return shape;
+}
+
+static CSSValue* consumeWebkitClipPath(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    if (CSSURIValue* url = consumeUrl(range))
+        return url;
+    return consumeBasicShape(range, context);
+}
+
+static CSSValue* consumeShapeOutside(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    if (CSSValue* imageValue = consumeImageOrNone(range, context))
+        return imageValue;
+    CSSValueList* list = CSSValueList::createSpaceSeparated();
+    if (CSSValue* boxValue = consumeIdent&lt;CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox&gt;(range))
+        list-&gt;append(*boxValue);
+    if (CSSValue* shapeValue = consumeBasicShape(range, context)) {
+        list-&gt;append(*shapeValue);
+        if (list-&gt;length() &lt; 2) {
+            if (CSSValue* boxValue = consumeIdent&lt;CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox&gt;(range))
+                list-&gt;append(*boxValue);
+        }
+    }
+    if (!list-&gt;length())
+        return nullptr;
+    return list;
+}
+
+static CSSValue* consumeContentDistributionOverflowPosition(CSSParserTokenRange&amp; range)
+{
+    if (identMatches&lt;CSSValueNormal, CSSValueBaseline, CSSValueLastBaseline&gt;(range.peek().id()))
+        return CSSContentDistributionValue::create(CSSValueInvalid, range.consumeIncludingWhitespace().id(), CSSValueInvalid);
+
+    CSSValueID distribution = CSSValueInvalid;
+    CSSValueID position = CSSValueInvalid;
+    CSSValueID overflow = CSSValueInvalid;
+    do {
+        CSSValueID id = range.peek().id();
+        if (identMatches&lt;CSSValueSpaceBetween, CSSValueSpaceAround, CSSValueSpaceEvenly, CSSValueStretch&gt;(id)) {
+            if (distribution != CSSValueInvalid)
+                return nullptr;
+            distribution = id;
+        } else if (identMatches&lt;CSSValueStart, CSSValueEnd, CSSValueCenter, CSSValueFlexStart, CSSValueFlexEnd, CSSValueLeft, CSSValueRight&gt;(id)) {
+            if (position != CSSValueInvalid)
+                return nullptr;
+            position = id;
+        } else if (identMatches&lt;CSSValueUnsafe, CSSValueSafe&gt;(id)) {
+            if (overflow != CSSValueInvalid)
+                return nullptr;
+            overflow = id;
+        } else {
+            return nullptr;
+        }
+        range.consumeIncludingWhitespace();
+    } while (!range.atEnd());
+
+    // The grammar states that we should have at least &lt;content-distribution&gt; or &lt;content-position&gt;.
+    if (position == CSSValueInvalid &amp;&amp; distribution == CSSValueInvalid)
+        return nullptr;
+
+    // The grammar states that &lt;overflow-position&gt; must be associated to &lt;content-position&gt;.
+    if (overflow != CSSValueInvalid &amp;&amp; position == CSSValueInvalid)
+        return nullptr;
+
+    return CSSContentDistributionValue::create(distribution, position, overflow);
+}
+
+static CSSPrimitiveValue* consumeBorderImageRepeatKeyword(CSSParserTokenRange&amp; range)
+{
+    return consumeIdent&lt;CSSValueStretch, CSSValueRepeat, CSSValueSpace, CSSValueRound&gt;(range);
+}
+
+static CSSValue* consumeBorderImageRepeat(CSSParserTokenRange&amp; range)
+{
+    CSSPrimitiveValue* horizontal = consumeBorderImageRepeatKeyword(range);
+    if (!horizontal)
+        return nullptr;
+    CSSPrimitiveValue* vertical = consumeBorderImageRepeatKeyword(range);
+    if (!vertical)
+        vertical = horizontal;
+    return CSSValuePair::create(horizontal, vertical, CSSValuePair::DropIdenticalValues);
+}
+
+static CSSValue* consumeBorderImageSlice(CSSPropertyID property, CSSParserTokenRange&amp; range)
+{
+    bool fill = consumeIdent&lt;CSSValueFill&gt;(range);
+    CSSPrimitiveValue* slices[4] = { 0 };
+
+    for (size_t index = 0; index &lt; 4; ++index) {
+        CSSPrimitiveValue* value = consumePercent(range, ValueRangeNonNegative);
+        if (!value)
+            value = consumeNumber(range, ValueRangeNonNegative);
+        if (!value)
+            break;
+        slices[index] = value;
+    }
+    if (!slices[0])
+        return nullptr;
+    if (consumeIdent&lt;CSSValueFill&gt;(range)) {
+        if (fill)
+            return nullptr;
+        fill = true;
+    }
+    complete4Sides(slices);
+    // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
+    // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
+    if (property == CSSPropertyWebkitBorderImage || property == CSSPropertyWebkitMaskBoxImage || property == CSSPropertyWebkitBoxReflect)
+        fill = true;
+    return CSSBorderImageSliceValue::create(CSSQuadValue::create(slices[0], slices[1], slices[2], slices[3], CSSQuadValue::SerializeAsQuad), fill);
+}
+
+static CSSValue* consumeBorderImageOutset(CSSParserTokenRange&amp; range)
+{
+    CSSPrimitiveValue* outsets[4] = { 0 };
+
+    CSSPrimitiveValue* value = nullptr;
+    for (size_t index = 0; index &lt; 4; ++index) {
+        value = consumeNumber(range, ValueRangeNonNegative);
+        if (!value)
+            value = consumeLength(range, HTMLStandardMode, ValueRangeNonNegative);
+        if (!value)
+            break;
+        outsets[index] = value;
+    }
+    if (!outsets[0])
+        return nullptr;
+    complete4Sides(outsets);
+    return CSSQuadValue::create(outsets[0], outsets[1], outsets[2], outsets[3], CSSQuadValue::SerializeAsQuad);
+}
+
+static CSSValue* consumeBorderImageWidth(CSSParserTokenRange&amp; range)
+{
+    CSSPrimitiveValue* widths[4] = { 0 };
+
+    CSSPrimitiveValue* value = nullptr;
+    for (size_t index = 0; index &lt; 4; ++index) {
+        value = consumeNumber(range, ValueRangeNonNegative);
+        if (!value)
+            value = consumeLengthOrPercent(range, HTMLStandardMode, ValueRangeNonNegative, UnitlessQuirk::Forbid);
+        if (!value)
+            value = consumeIdent&lt;CSSValueAuto&gt;(range);
+        if (!value)
+            break;
+        widths[index] = value;
+    }
+    if (!widths[0])
+        return nullptr;
+    complete4Sides(widths);
+    return CSSQuadValue::create(widths[0], widths[1], widths[2], widths[3], CSSQuadValue::SerializeAsQuad);
+}
+
+static bool consumeBorderImageComponents(CSSPropertyID property, CSSParserTokenRange&amp; range, const CSSParserContext&amp; context, CSSValue*&amp; source,
+    CSSValue*&amp; slice, CSSValue*&amp; width, CSSValue*&amp; outset, CSSValue*&amp; repeat)
+{
+    do {
+        if (!source) {
+            source = consumeImageOrNone(range, context);
+            if (source)
+                continue;
+        }
+        if (!repeat) {
+            repeat = consumeBorderImageRepeat(range);
+            if (repeat)
+                continue;
+        }
+        if (!slice) {
+            slice = consumeBorderImageSlice(property, range);
+            if (slice) {
+                ASSERT(!width &amp;&amp; !outset);
+                if (consumeSlashIncludingWhitespace(range)) {
+                    width = consumeBorderImageWidth(range);
+                    if (consumeSlashIncludingWhitespace(range)) {
+                        outset = consumeBorderImageOutset(range);
+                        if (!outset)
+                            return false;
+                    } else if (!width) {
+                        return false;
+                    }
+                }
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    } while (!range.atEnd());
+    return true;
+}
+
+static CSSValue* consumeWebkitBorderImage(CSSPropertyID property, CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    CSSValue* source = nullptr;
+    CSSValue* slice = nullptr;
+    CSSValue* width = nullptr;
+    CSSValue* outset = nullptr;
+    CSSValue* repeat = nullptr;
+    if (consumeBorderImageComponents(property, range, context, source, slice, width, outset, repeat))
+        return createBorderImageValue(source, slice, width, outset, repeat);
+    return nullptr;
+}
+
+static CSSValue* consumeReflect(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    CSSPrimitiveValue* direction = consumeIdent&lt;CSSValueAbove, CSSValueBelow, CSSValueLeft, CSSValueRight&gt;(range);
+    if (!direction)
+        return nullptr;
+
+    CSSPrimitiveValue* offset = nullptr;
+    if (range.atEnd()) {
+        offset = CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitType::Pixels);
+    } else {
+        offset = consumeLengthOrPercent(range, context.mode(), ValueRangeAll, UnitlessQuirk::Forbid);
+        if (!offset)
+            return nullptr;
+    }
+
+    CSSValue* mask = nullptr;
+    if (!range.atEnd()) {
+        mask = consumeWebkitBorderImage(CSSPropertyWebkitBoxReflect, range, context);
+        if (!mask)
+            return nullptr;
+    }
+    return CSSReflectValue::create(direction, offset, mask);
+}
+
+static CSSValue* consumeFontSizeAdjust(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    return consumeNumber(range, ValueRangeNonNegative);
+}
+
+static CSSValue* consumeImageOrientation(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueFromImage)
+        return consumeIdent(range);
+    if (range.peek().type() != NumberToken) {
+        CSSPrimitiveValue* angle = consumeAngle(range);
+        if (angle &amp;&amp; angle-&gt;getDoubleValue() == 0)
+            return angle;
+    }
+    return nullptr;
+}
+
+static CSSValue* consumeBackgroundBlendMode(CSSParserTokenRange&amp; range)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueNormal || id == CSSValueOverlay || (id &gt;= CSSValueMultiply &amp;&amp; id &lt;= CSSValueLuminosity))
+        return consumeIdent(range);
+    return nullptr;
+}
+
+static CSSValue* consumeBackgroundAttachment(CSSParserTokenRange&amp; range)
+{
+    return consumeIdent&lt;CSSValueScroll, CSSValueFixed, CSSValueLocal&gt;(range);
+}
+
+static CSSValue* consumeBackgroundBox(CSSParserTokenRange&amp; range)
+{
+    return consumeIdent&lt;CSSValueBorderBox, CSSValuePaddingBox, CSSValueContentBox&gt;(range);
+}
+
+static CSSValue* consumeBackgroundComposite(CSSParserTokenRange&amp; range)
+{
+    return consumeIdentRange(range, CSSValueClear, CSSValuePlusLighter);
+}
+
+static CSSValue* consumeMaskSourceType(CSSParserTokenRange&amp; range)
+{
+    ASSERT(RuntimeEnabledFeatures::cssMaskSourceTypeEnabled());
+    return consumeIdent&lt;CSSValueAuto, CSSValueAlpha, CSSValueLuminance&gt;(range);
+}
+
+static CSSValue* consumePrefixedBackgroundBox(CSSPropertyID property, CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    // The values 'border', 'padding' and 'content' are deprecated and do not apply to the version of the property that has the -webkit- prefix removed.
+    if (CSSValue* value = consumeIdentRange(range, CSSValueBorder, CSSValuePaddingBox))
+        return value;
+    if ((property == CSSPropertyWebkitBackgroundClip || property == CSSPropertyWebkitMaskClip) &amp;&amp; range.peek().id() == CSSValueText)
+        return consumeIdent(range);
+    return nullptr;
+}
+
+static CSSValue* consumeBackgroundSize(CSSPropertyID unresolvedProperty, CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (identMatches&lt;CSSValueContain, CSSValueCover&gt;(range.peek().id()))
+        return consumeIdent(range);
+
+    CSSPrimitiveValue* horizontal = consumeIdent&lt;CSSValueAuto&gt;(range);
+    if (!horizontal)
+        horizontal = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Forbid);
+
+    CSSPrimitiveValue* vertical = nullptr;
+    if (!range.atEnd()) {
+        if (range.peek().id() == CSSValueAuto) // `auto' is the default
+            range.consumeIncludingWhitespace();
+        else
+            vertical = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Forbid);
+    } else if (unresolvedProperty == CSSPropertyAliasWebkitBackgroundSize) {
+        // Legacy syntax: &quot;-webkit-background-size: 10px&quot; is equivalent to &quot;background-size: 10px 10px&quot;.
+        vertical = horizontal;
+    }
+    if (!vertical)
+        return horizontal;
+    return CSSValuePair::create(horizontal, vertical, CSSValuePair::KeepIdenticalValues);
+}
+
+static CSSValueList* consumeGridAutoFlow(CSSParserTokenRange&amp; range)
+{
+    CSSPrimitiveValue* rowOrColumnValue = consumeIdent&lt;CSSValueRow, CSSValueColumn&gt;(range);
+    CSSPrimitiveValue* denseAlgorithm = consumeIdent&lt;CSSValueDense&gt;(range);
+    if (!rowOrColumnValue) {
+        rowOrColumnValue = consumeIdent&lt;CSSValueRow, CSSValueColumn&gt;(range);
+        if (!rowOrColumnValue &amp;&amp; !denseAlgorithm)
+            return nullptr;
+    }
+    CSSValueList* parsedValues = CSSValueList::createSpaceSeparated();
+    if (rowOrColumnValue)
+        parsedValues-&gt;append(*rowOrColumnValue);
+    if (denseAlgorithm)
+        parsedValues-&gt;append(*denseAlgorithm);
+    return parsedValues;
+}
+
+static CSSValue* consumeBackgroundComponent(CSSPropertyID unresolvedProperty, CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    switch (unresolvedProperty) {
+    case CSSPropertyBackgroundClip:
+        return consumeBackgroundBox(range);
+    case CSSPropertyBackgroundBlendMode:
+        return consumeBackgroundBlendMode(range);
+    case CSSPropertyBackgroundAttachment:
+        return consumeBackgroundAttachment(range);
+    case CSSPropertyBackgroundOrigin:
+        return consumeBackgroundBox(range);
+    case CSSPropertyWebkitMaskComposite:
+        return consumeBackgroundComposite(range);
+    case CSSPropertyMaskSourceType:
+        return consumeMaskSourceType(range);
+    case CSSPropertyWebkitBackgroundClip:
+    case CSSPropertyWebkitBackgroundOrigin:
+    case CSSPropertyWebkitMaskClip:
+    case CSSPropertyWebkitMaskOrigin:
+        return consumePrefixedBackgroundBox(unresolvedProperty, range, context);
+    case CSSPropertyBackgroundImage:
+    case CSSPropertyWebkitMaskImage:
+        return consumeImageOrNone(range, context);
+    case CSSPropertyBackgroundPositionX:
+    case CSSPropertyWebkitMaskPositionX:
+        return consumePositionX(range, context.mode());
+    case CSSPropertyBackgroundPositionY:
+    case CSSPropertyWebkitMaskPositionY:
+        return consumePositionY(range, context.mode());
+    case CSSPropertyBackgroundSize:
+    case CSSPropertyAliasWebkitBackgroundSize:
+    case CSSPropertyWebkitMaskSize:
+        return consumeBackgroundSize(unresolvedProperty, range, context.mode());
+    case CSSPropertyBackgroundColor:
+        return consumeColor(range, context.mode());
+    default:
+        break;
+    };
+    return nullptr;
+}
+
+static void addBackgroundValue(CSSValue*&amp; list, CSSValue* value)
+{
+    if (list) {
+        if (!list-&gt;isBaseValueList()) {
+            CSSValue* firstValue = list;
+            list = CSSValueList::createCommaSeparated();
+            toCSSValueList(list)-&gt;append(*firstValue);
+        }
+        toCSSValueList(list)-&gt;append(*value);
+    } else {
+        // To conserve memory we don't actually wrap a single value in a list.
+        list = value;
+    }
+}
+
+static CSSValue* consumeCommaSeparatedBackgroundComponent(CSSPropertyID unresolvedProperty, CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    CSSValue* result = nullptr;
+    do {
+        CSSValue* value = consumeBackgroundComponent(unresolvedProperty, range, context);
+        if (!value)
+            return nullptr;
+        addBackgroundValue(result, value);
+    } while (consumeCommaIncludingWhitespace(range));
+    return result;
+}
+
+static CSSPrimitiveValue* consumeSelfPositionKeyword(CSSParserTokenRange&amp; range)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
+        || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
+        || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight)
+        return consumeIdent(range);
+    return nullptr;
+}
+
+static CSSValue* consumeSelfPositionOverflowPosition(CSSParserTokenRange&amp; range)
+{
+    if (identMatches&lt;CSSValueAuto, CSSValueNormal, CSSValueStretch, CSSValueBaseline, CSSValueLastBaseline&gt;(range.peek().id()))
+        return consumeIdent(range);
+
+    CSSPrimitiveValue* overflowPosition = consumeIdent&lt;CSSValueUnsafe, CSSValueSafe&gt;(range);
+    CSSPrimitiveValue* selfPosition = consumeSelfPositionKeyword(range);
+    if (!selfPosition)
+        return nullptr;
+    if (!overflowPosition)
+        overflowPosition = consumeIdent&lt;CSSValueUnsafe, CSSValueSafe&gt;(range);
+    if (overflowPosition)
+        return CSSValuePair::create(selfPosition, overflowPosition, CSSValuePair::DropIdenticalValues);
+    return selfPosition;
+}
+
+static CSSValue* consumeAlignItems(CSSParserTokenRange&amp; range)
+{
+    // align-items property does not allow the 'auto' value.
+    if (identMatches&lt;CSSValueAuto&gt;(range.peek().id()))
+        return nullptr;
+    return consumeSelfPositionOverflowPosition(range);
+}
+
+static CSSValue* consumeJustifyItems(CSSParserTokenRange&amp; range)
+{
+    CSSParserTokenRange rangeCopy = range;
+    CSSPrimitiveValue* legacy = consumeIdent&lt;CSSValueLegacy&gt;(rangeCopy);
+    CSSPrimitiveValue* positionKeyword = consumeIdent&lt;CSSValueCenter, CSSValueLeft, CSSValueRight&gt;(rangeCopy);
+    if (!legacy)
+        legacy = consumeIdent&lt;CSSValueLegacy&gt;(rangeCopy);
+    if (legacy &amp;&amp; positionKeyword) {
+        range = rangeCopy;
+        return CSSValuePair::create(legacy, positionKeyword, CSSValuePair::DropIdenticalValues);
+    }
+    return consumeSelfPositionOverflowPosition(range);
+}
+
+static CSSCustomIdentValue* consumeCustomIdentForGridLine(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueAuto || range.peek().id() == CSSValueSpan)
+        return nullptr;
+    return consumeCustomIdent(range);
+}
+
+static CSSValue* consumeGridLine(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueAuto)
+        return consumeIdent(range);
+
+    CSSPrimitiveValue* spanValue = nullptr;
+    CSSCustomIdentValue* gridLineName = nullptr;
+    CSSPrimitiveValue* numericValue = consumeInteger(range);
+    if (numericValue) {
+        gridLineName = consumeCustomIdentForGridLine(range);
+        spanValue = consumeIdent&lt;CSSValueSpan&gt;(range);
+    } else {
+        spanValue = consumeIdent&lt;CSSValueSpan&gt;(range);
+        if (spanValue) {
+            numericValue = consumeInteger(range);
+            gridLineName = consumeCustomIdentForGridLine(range);
+            if (!numericValue)
+                numericValue = consumeInteger(range);
+        } else {
+            gridLineName = consumeCustomIdentForGridLine(range);
+            if (gridLineName) {
+                numericValue = consumeInteger(range);
+                spanValue = consumeIdent&lt;CSSValueSpan&gt;(range);
+                if (!spanValue &amp;&amp; !numericValue)
+                    return gridLineName;
+            } else {
+                return nullptr;
+            }
+        }
+    }
+
+    if (spanValue &amp;&amp; !numericValue &amp;&amp; !gridLineName)
+        return nullptr; // &quot;span&quot; keyword alone is invalid.
+    if (spanValue &amp;&amp; numericValue &amp;&amp; numericValue-&gt;getIntValue() &lt; 0)
+        return nullptr; // Negative numbers are not allowed for span.
+    if (numericValue &amp;&amp; numericValue-&gt;getIntValue() == 0)
+        return nullptr; // An &lt;integer&gt; value of zero makes the declaration invalid.
+
+    CSSValueList* values = CSSValueList::createSpaceSeparated();
+    if (spanValue)
+        values-&gt;append(*spanValue);
+    if (numericValue)
+        values-&gt;append(*numericValue);
+    if (gridLineName)
+        values-&gt;append(*gridLineName);
+    ASSERT(values-&gt;length());
+    return values;
+}
+
+static bool isGridTrackFixedSized(const CSSPrimitiveValue&amp; primitiveValue)
+{
+    CSSValueID valueID = primitiveValue.getValueID();
+    if (valueID == CSSValueMinContent || valueID == CSSValueMaxContent || valueID == CSSValueAuto || primitiveValue.isFlex())
+        return false;
+
+    return true;
+}
+
+static bool isGridTrackFixedSized(const CSSValue&amp; value)
+{
+    if (value.isPrimitiveValue())
+        return isGridTrackFixedSized(toCSSPrimitiveValue(value));
+
+    const CSSPrimitiveValue&amp; minPrimitiveValue = toCSSPrimitiveValue(toCSSFunctionValue(value).item(0));
+    const CSSPrimitiveValue&amp; maxPrimitiveValue = toCSSPrimitiveValue(toCSSFunctionValue(value).item(1));
+    return isGridTrackFixedSized(minPrimitiveValue) || isGridTrackFixedSized(maxPrimitiveValue);
+}
+
+static Vector&lt;String&gt; parseGridTemplateAreasColumnNames(const String&amp; gridRowNames)
+{
+    ASSERT(!gridRowNames.isEmpty());
+    Vector&lt;String&gt; columnNames;
+    // Using StringImpl to avoid checks and indirection in every call to String::operator[].
+    StringImpl&amp; text = *gridRowNames.impl();
+
+    StringBuilder areaName;
+    for (unsigned i = 0; i &lt; text.length(); ++i) {
+        if (isCSSSpace(text[i])) {
+            if (!areaName.isEmpty()) {
+                columnNames.append(areaName.toString());
+                areaName.clear();
+            }
+            continue;
+        }
+        if (text[i] == '.') {
+            if (areaName == &quot;.&quot;)
+                continue;
+            if (!areaName.isEmpty()) {
+                columnNames.append(areaName.toString());
+                areaName.clear();
+            }
+        } else {
+            if (!isNameCodePoint(text[i]))
+                return Vector&lt;String&gt;();
+            if (areaName == &quot;.&quot;) {
+                columnNames.append(areaName.toString());
+                areaName.clear();
+            }
+        }
+
+        areaName.append(text[i]);
+    }
+
+    if (!areaName.isEmpty())
+        columnNames.append(areaName.toString());
+
+    return columnNames;
+}
+
+static bool parseGridTemplateAreasRow(const String&amp; gridRowNames, NamedGridAreaMap&amp; gridAreaMap, const size_t rowCount, size_t&amp; columnCount)
+{
+    if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace())
+        return false;
+
+    Vector&lt;String&gt; columnNames = parseGridTemplateAreasColumnNames(gridRowNames);
+    if (rowCount == 0) {
+        columnCount = columnNames.size();
+        if (columnCount == 0)
+            return false;
+    } else if (columnCount != columnNames.size()) {
+        // The declaration is invalid if all the rows don't have the number of columns.
+        return false;
+    }
+
+    for (size_t currentColumn = 0; currentColumn &lt; columnCount; ++currentColumn) {
+        const String&amp; gridAreaName = columnNames[currentColumn];
+
+        // Unamed areas are always valid (we consider them to be 1x1).
+        if (gridAreaName == &quot;.&quot;)
+            continue;
+
+        size_t lookAheadColumn = currentColumn + 1;
+        while (lookAheadColumn &lt; columnCount &amp;&amp; columnNames[lookAheadColumn] == gridAreaName)
+            lookAheadColumn++;
+
+        NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
+        if (gridAreaIt == gridAreaMap.end()) {
+            gridAreaMap.add(gridAreaName, GridArea(GridSpan::translatedDefiniteGridSpan(rowCount, rowCount + 1), GridSpan::translatedDefiniteGridSpan(currentColumn, lookAheadColumn)));
+        } else {
+            GridArea&amp; gridArea = gridAreaIt-&gt;value;
+
+            // The following checks test that the grid area is a single filled-in rectangle.
+            // 1. The new row is adjacent to the previously parsed row.
+            if (rowCount != gridArea.rows.endLine())
+                return false;
+
+            // 2. The new area starts at the same position as the previously parsed area.
+            if (currentColumn != gridArea.columns.startLine())
+                return false;
+
+            // 3. The new area ends at the same position as the previously parsed area.
+            if (lookAheadColumn != gridArea.columns.endLine())
+                return false;
+
+            gridArea.rows = GridSpan::translatedDefiniteGridSpan(gridArea.rows.startLine(), gridArea.rows.endLine() + 1);
+        }
+        currentColumn = lookAheadColumn - 1;
+    }
+
+    return true;
+}
+
+static CSSPrimitiveValue* consumeGridBreadth(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (identMatches&lt;CSSValueMinContent, CSSValueMaxContent, CSSValueAuto&gt;(token.id()))
+        return consumeIdent(range);
+    if (token.type() == DimensionToken &amp;&amp; token.unitType() == CSSPrimitiveValue::UnitType::Fraction) {
+        if (range.peek().numericValue() &lt; 0)
+            return nullptr;
+        return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitType::Fraction);
+    }
+    return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative, UnitlessQuirk::Allow);
+}
+
+static CSSValue* consumeGridTrackSize(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (identMatches&lt;CSSValueAuto&gt;(token.id()))
+        return consumeIdent(range);
+
+    if (token.functionId() == CSSValueMinmax) {
+        CSSParserTokenRange rangeCopy = range;
+        CSSParserTokenRange args = consumeFunction(rangeCopy);
+        CSSPrimitiveValue* minTrackBreadth = consumeGridBreadth(args, cssParserMode);
+        if (!minTrackBreadth || minTrackBreadth-&gt;isFlex() || !consumeCommaIncludingWhitespace(args))
+            return nullptr;
+        CSSPrimitiveValue* maxTrackBreadth = consumeGridBreadth(args, cssParserMode);
+        if (!maxTrackBreadth || !args.atEnd())
+            return nullptr;
+        range = rangeCopy;
+        CSSFunctionValue* result = CSSFunctionValue::create(CSSValueMinmax);
+        result-&gt;append(*minTrackBreadth);
+        result-&gt;append(*maxTrackBreadth);
+        return result;
+    }
+    return consumeGridBreadth(range, cssParserMode);
+}
+
+// Appends to the passed in CSSGridLineNamesValue if any, otherwise creates a new one.
+static CSSGridLineNamesValue* consumeGridLineNames(CSSParserTokenRange&amp; range, CSSGridLineNamesValue* lineNames = nullptr)
+{
+    CSSParserTokenRange rangeCopy = range;
+    if (rangeCopy.consumeIncludingWhitespace().type() != LeftBracketToken)
+        return nullptr;
+    if (!lineNames)
+        lineNames = CSSGridLineNamesValue::create();
+    while (CSSCustomIdentValue* lineName = consumeCustomIdentForGridLine(rangeCopy))
+        lineNames-&gt;append(*lineName);
+    if (rangeCopy.consumeIncludingWhitespace().type() != RightBracketToken)
+        return nullptr;
+    range = rangeCopy;
+    return lineNames;
+}
+
+static bool consumeGridTrackRepeatFunction(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, CSSValueList&amp; list, bool&amp; isAutoRepeat, bool&amp; allTracksAreFixedSized)
+{
+    CSSParserTokenRange args = consumeFunction(range);
+    // The number of repetitions for &lt;auto-repeat&gt; is not important at parsing level
+    // because it will be computed later, let's set it to 1.
+    size_t repetitions = 1;
+    isAutoRepeat = identMatches&lt;CSSValueAutoFill, CSSValueAutoFit&gt;(args.peek().id());
+    CSSValueList* repeatedValues;
+    if (isAutoRepeat) {
+        repeatedValues = CSSGridAutoRepeatValue::create(args.consumeIncludingWhitespace().id());
+    } else {
+        // FIXME: a consumeIntegerRaw would be more efficient here.
+        CSSPrimitiveValue* repetition = consumePositiveInteger(args);
+        if (!repetition)
+            return false;
+        repetitions = clampTo&lt;size_t&gt;(repetition-&gt;getDoubleValue(), 0, kGridMaxTracks);
+        repeatedValues = CSSValueList::createSpaceSeparated();
+    }
+    if (!consumeCommaIncludingWhitespace(args))
+        return false;
+    CSSGridLineNamesValue* lineNames = consumeGridLineNames(args);
+    if (lineNames)
+        repeatedValues-&gt;append(*lineNames);
+
+    size_t numberOfTracks = 0;
+    while (!args.atEnd()) {
+        CSSValue* trackSize = consumeGridTrackSize(args, cssParserMode);
+        if (!trackSize)
+            return false;
+        if (allTracksAreFixedSized)
+            allTracksAreFixedSized = isGridTrackFixedSized(*trackSize);
+        repeatedValues-&gt;append(*trackSize);
+        ++numberOfTracks;
+        lineNames = consumeGridLineNames(args);
+        if (lineNames)
+            repeatedValues-&gt;append(*lineNames);
+    }
+    // We should have found at least one &lt;track-size&gt; or else it is not a valid &lt;track-list&gt;.
+    if (!numberOfTracks)
+        return false;
+
+    if (isAutoRepeat) {
+        list.append(*repeatedValues);
+    } else {
+        // We clamp the repetitions to a multiple of the repeat() track list's size, while staying below the max grid size.
+        repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks);
+        for (size_t i = 0; i &lt; repetitions; ++i) {
+            for (size_t j = 0; j &lt; repeatedValues-&gt;length(); ++j)
+                list.append(repeatedValues-&gt;item(j));
+        }
+    }
+    return true;
+}
+
+enum TrackListType { GridTemplate, GridTemplateNoRepeat, GridAuto };
+
+static CSSValue* consumeGridTrackList(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, TrackListType trackListType)
+{
+    bool allowGridLineNames = trackListType != GridAuto;
+    CSSValueList* values = CSSValueList::createSpaceSeparated();
+    CSSGridLineNamesValue* lineNames = consumeGridLineNames(range);
+    if (lineNames) {
+        if (!allowGridLineNames)
+            return nullptr;
+        values-&gt;append(*lineNames);
+    }
+
+    bool allowRepeat = trackListType == GridTemplate;
+    bool seenAutoRepeat = false;
+    bool allTracksAreFixedSized = true;
+    do {
+        bool isAutoRepeat;
+        if (range.peek().functionId() == CSSValueRepeat) {
+            if (!allowRepeat)
+                return nullptr;
+            if (!consumeGridTrackRepeatFunction(range, cssParserMode, *values, isAutoRepeat, allTracksAreFixedSized))
+                return nullptr;
+            if (isAutoRepeat &amp;&amp; seenAutoRepeat)
+                return nullptr;
+            seenAutoRepeat = seenAutoRepeat || isAutoRepeat;
+        } else if (CSSValue* value = consumeGridTrackSize(range, cssParserMode)) {
+            if (allTracksAreFixedSized)
+                allTracksAreFixedSized = isGridTrackFixedSized(*value);
+            values-&gt;append(*value);
+        } else {
+            return nullptr;
+        }
+        if (seenAutoRepeat &amp;&amp; !allTracksAreFixedSized)
+            return nullptr;
+        lineNames = consumeGridLineNames(range);
+        if (lineNames) {
+            if (!allowGridLineNames)
+                return nullptr;
+            values-&gt;append(*lineNames);
+        }
+    } while (!range.atEnd() &amp;&amp; range.peek().type() != DelimiterToken);
+    return values;
+}
+
+static CSSValue* consumeGridTemplatesRowsOrColumns(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    return consumeGridTrackList(range, cssParserMode, GridTemplate);
+}
+
+static CSSValue* consumeGridTemplateAreas(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+
+    NamedGridAreaMap gridAreaMap;
+    size_t rowCount = 0;
+    size_t columnCount = 0;
+
+    while (range.peek().type() == StringToken) {
+        if (!parseGridTemplateAreasRow(range.consumeIncludingWhitespace().value().toString(), gridAreaMap, rowCount, columnCount))
+            return nullptr;
+        ++rowCount;
+    }
+
+    if (rowCount == 0)
+        return nullptr;
+    ASSERT(columnCount);
+    return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
+}
+
+static void countKeywordOnlyPropertyUsage(CSSPropertyID property, UseCounter* counter, CSSValueID valueID)
+{
+    if (!counter)
+        return;
+    switch (property) {
+    case CSSPropertyWebkitAppearance:
+        if (valueID == CSSValueNone) {
+            counter-&gt;count(UseCounter::CSSValueAppearanceNone);
+        } else {
+            counter-&gt;count(UseCounter::CSSValueAppearanceNotNone);
+            if (valueID == CSSValueButton)
+                counter-&gt;count(UseCounter::CSSValueAppearanceButton);
+            else if (valueID == CSSValueCaret)
+                counter-&gt;count(UseCounter::CSSValueAppearanceCaret);
+            else if (valueID == CSSValueCheckbox)
+                counter-&gt;count(UseCounter::CSSValueAppearanceCheckbox);
+            else if (valueID == CSSValueMenulist)
+                counter-&gt;count(UseCounter::CSSValueAppearanceMenulist);
+            else if (valueID == CSSValueMenulistButton)
+                counter-&gt;count(UseCounter::CSSValueAppearanceMenulistButton);
+            else if (valueID == CSSValueListbox)
+                counter-&gt;count(UseCounter::CSSValueAppearanceListbox);
+            else if (valueID == CSSValueRadio)
+                counter-&gt;count(UseCounter::CSSValueAppearanceRadio);
+            else if (valueID == CSSValueSearchfield)
+                counter-&gt;count(UseCounter::CSSValueAppearanceSearchField);
+            else if (valueID == CSSValueTextfield)
+                counter-&gt;count(UseCounter::CSSValueAppearanceTextField);
+            else
+                counter-&gt;count(UseCounter::CSSValueAppearanceOthers);
+        }
+        break;
+
+    default:
+        break;
+    }
+}
+
+const CSSValue* CSSPropertyParser::parseSingleValue(CSSPropertyID unresolvedProperty, CSSPropertyID currentShorthand)
+{
+    CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty);
+    if (CSSParserFastPaths::isKeywordPropertyID(property)) {
+        if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(property, m_range.peek().id(), m_context.mode()))
+            return nullptr;
+        countKeywordOnlyPropertyUsage(property, m_context.useCounter(), m_range.peek().id());
+        return consumeIdent(m_range);
+    }
+    switch (property) {
+    case CSSPropertyWillChange:
+        return consumeWillChange(m_range);
+    case CSSPropertyPage:
+        return consumePage(m_range);
+    case CSSPropertyQuotes:
+        return consumeQuotes(m_range);
+    case CSSPropertyWebkitHighlight:
+        return consumeWebkitHighlight(m_range);
+    case CSSPropertyFontVariantCaps:
+        return consumeFontVariantCaps(m_range);
+    case CSSPropertyFontVariantLigatures:
+        return consumeFontVariantLigatures(m_range);
+    case CSSPropertyFontVariantNumeric:
+        return consumeFontVariantNumeric(m_range);
+    case CSSPropertyFontFeatureSettings:
+        return consumeFontFeatureSettings(m_range);
+    case CSSPropertyFontFamily:
+        return consumeFontFamily(m_range);
+    case CSSPropertyFontWeight:
+        return consumeFontWeight(m_range);
+    case CSSPropertyLetterSpacing:
+    case CSSPropertyWordSpacing:
+        return consumeSpacing(m_range, m_context.mode());
+    case CSSPropertyTabSize:
+        return consumeTabSize(m_range, m_context.mode());
+    case CSSPropertyTextSizeAdjust:
+        return consumeTextSizeAdjust(m_range, m_context.mode());
+    case CSSPropertyFontSize:
+        return consumeFontSize(m_range, m_context.mode(), UnitlessQuirk::Allow);
+    case CSSPropertyLineHeight:
+        return consumeLineHeight(m_range, m_context.mode());
+    case CSSPropertyRotate:
+        return consumeRotation(m_range);
+    case CSSPropertyScale:
+        return consumeScale(m_range);
+    case CSSPropertyTranslate:
+        return consumeTranslate(m_range, m_context.mode());
+    case CSSPropertyWebkitBorderHorizontalSpacing:
+    case CSSPropertyWebkitBorderVerticalSpacing:
+        return consumeLength(m_range, m_context.mode(), ValueRangeNonNegative);
+    case CSSPropertyCounterIncrement:
+    case CSSPropertyCounterReset:
+        return consumeCounter(m_range, property == CSSPropertyCounterIncrement ? 1 : 0);
+    case CSSPropertySize:
+        return consumeSize(m_range, m_context.mode());
+    case CSSPropertySnapHeight:
+        return consumeSnapHeight(m_range, m_context.mode());
+    case CSSPropertyTextIndent:
+        return consumeTextIndent(m_range, m_context.mode());
+    case CSSPropertyMaxWidth:
+    case CSSPropertyMaxHeight:
+        return consumeMaxWidthOrHeight(m_range, m_context, UnitlessQuirk::Allow);
+    case CSSPropertyWebkitMaxLogicalWidth:
+    case CSSPropertyWebkitMaxLogicalHeight:
+        return consumeMaxWidthOrHeight(m_range, m_context);
+    case CSSPropertyMinWidth:
+    case CSSPropertyMinHeight:
+    case CSSPropertyWidth:
+    case CSSPropertyHeight:
+        return consumeWidthOrHeight(m_range, m_context, UnitlessQuirk::Allow);
+    case CSSPropertyWebkitMinLogicalWidth:
+    case CSSPropertyWebkitMinLogicalHeight:
+    case CSSPropertyWebkitLogicalWidth:
+    case CSSPropertyWebkitLogicalHeight:
+        return consumeWidthOrHeight(m_range, m_context);
+    case CSSPropertyMarginTop:
+    case CSSPropertyMarginRight:
+    case CSSPropertyMarginBottom:
+    case CSSPropertyMarginLeft:
+    case CSSPropertyBottom:
+    case CSSPropertyLeft:
+    case CSSPropertyRight:
+    case CSSPropertyTop:
+        return consumeMarginOrOffset(m_range, m_context.mode(), UnitlessQuirk::Allow);
+    case CSSPropertyWebkitMarginStart:
+    case CSSPropertyWebkitMarginEnd:
+    case CSSPropertyWebkitMarginBefore:
+    case CSSPropertyWebkitMarginAfter:
+        return consumeMarginOrOffset(m_range, m_context.mode(), UnitlessQuirk::Forbid);
+    case CSSPropertyPaddingTop:
+    case CSSPropertyPaddingRight:
+    case CSSPropertyPaddingBottom:
+    case CSSPropertyPaddingLeft:
+        return consumeLengthOrPercent(m_range, m_context.mode(), ValueRangeNonNegative, UnitlessQuirk::Allow);
+    case CSSPropertyWebkitPaddingStart:
+    case CSSPropertyWebkitPaddingEnd:
+    case CSSPropertyWebkitPaddingBefore:
+    case CSSPropertyWebkitPaddingAfter:
+        return consumeLengthOrPercent(m_range, m_context.mode(), ValueRangeNonNegative, UnitlessQuirk::Forbid);
+    case CSSPropertyClip:
+        return consumeClip(m_range, m_context.mode());
+    case CSSPropertyTouchAction:
+        return consumeTouchAction(m_range);
+    case CSSPropertyScrollSnapDestination:
+    case CSSPropertyObjectPosition:
+    case CSSPropertyPerspectiveOrigin:
+        return consumePosition(m_range, m_context.mode(), UnitlessQuirk::Forbid);
+    case CSSPropertyWebkitLineClamp:
+        return consumeLineClamp(m_range);
+    case CSSPropertyWebkitFontSizeDelta:
+        return consumeLength(m_range, m_context.mode(), ValueRangeAll, UnitlessQuirk::Allow);
+    case CSSPropertyWebkitHyphenateCharacter:
+    case CSSPropertyWebkitLocale:
+        return consumeLocale(m_range);
+    case CSSPropertyColumnWidth:
+        return consumeColumnWidth(m_range);
+    case CSSPropertyColumnCount:
+        return consumeColumnCount(m_range);
+    case CSSPropertyColumnGap:
+        return consumeColumnGap(m_range, m_context.mode());
+    case CSSPropertyColumnSpan:
+        return consumeColumnSpan(m_range);
+    case CSSPropertyZoom:
+        return consumeZoom(m_range, m_context);
+    case CSSPropertyAnimationDelay:
+    case CSSPropertyTransitionDelay:
+    case CSSPropertyAnimationDirection:
+    case CSSPropertyAnimationDuration:
+    case CSSPropertyTransitionDuration:
+    case CSSPropertyAnimationFillMode:
+    case CSSPropertyAnimationIterationCount:
+    case CSSPropertyAnimationName:
+    case CSSPropertyAnimationPlayState:
+    case CSSPropertyTransitionProperty:
+    case CSSPropertyAnimationTimingFunction:
+    case CSSPropertyTransitionTimingFunction:
+        return consumeAnimationPropertyList(property, m_range, m_context, unresolvedProperty == CSSPropertyAliasWebkitAnimationName);
+    case CSSPropertyGridColumnGap:
+    case CSSPropertyGridRowGap:
+        return consumeLength(m_range, m_context.mode(), ValueRangeNonNegative);
+    case CSSPropertyShapeMargin:
+        return consumeLengthOrPercent(m_range, m_context.mode(), ValueRangeNonNegative);
+    case CSSPropertyShapeImageThreshold:
+        return consumeNumber(m_range, ValueRangeAll);
+    case CSSPropertyWebkitBoxOrdinalGroup:
+    case CSSPropertyOrphans:
+    case CSSPropertyWidows:
+        return consumePositiveInteger(m_range);
+    case CSSPropertyTextDecorationColor:
+        ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
+        return consumeColor(m_range, m_context.mode());
+    case CSSPropertyWebkitTextStrokeWidth:
+        return consumeTextStrokeWidth(m_range, m_context.mode());
+    case CSSPropertyWebkitTextFillColor:
+    case CSSPropertyWebkitTapHighlightColor:
+    case CSSPropertyWebkitTextEmphasisColor:
+    case CSSPropertyWebkitBorderStartColor:
+    case CSSPropertyWebkitBorderEndColor:
+    case CSSPropertyWebkitBorderBeforeColor:
+    case CSSPropertyWebkitBorderAfterColor:
+    case CSSPropertyWebkitTextStrokeColor:
+    case CSSPropertyStopColor:
+    case CSSPropertyFloodColor:
+    case CSSPropertyLightingColor:
+    case CSSPropertyColumnRuleColor:
+        return consumeColor(m_range, m_context.mode());
+    case CSSPropertyColor:
+    case CSSPropertyBackgroundColor:
+        return consumeColor(m_range, m_context.mode(), inQuirksMode());
+    case CSSPropertyWebkitBorderStartWidth:
+    case CSSPropertyWebkitBorderEndWidth:
+    case CSSPropertyWebkitBorderBeforeWidth:
+    case CSSPropertyWebkitBorderAfterWidth:
+        return consumeBorderWidth(m_range, m_context.mode(), UnitlessQuirk::Forbid);
+    case CSSPropertyBorderBottomColor:
+    case CSSPropertyBorderLeftColor:
+    case CSSPropertyBorderRightColor:
+    case CSSPropertyBorderTopColor: {
+        bool allowQuirkyColors = inQuirksMode()
+            &amp;&amp; (currentShorthand == CSSPropertyInvalid || currentShorthand == CSSPropertyBorderColor);
+        return consumeColor(m_range, m_context.mode(), allowQuirkyColors);
+    }
+    case CSSPropertyBorderBottomWidth:
+    case CSSPropertyBorderLeftWidth:
+    case CSSPropertyBorderRightWidth:
+    case CSSPropertyBorderTopWidth: {
+        bool allowQuirkyLengths = inQuirksMode()
+            &amp;&amp; (currentShorthand == CSSPropertyInvalid || currentShorthand == CSSPropertyBorderWidth);
+        UnitlessQuirk unitless = allowQuirkyLengths ? UnitlessQuirk::Allow : UnitlessQuirk::Forbid;
+        return consumeBorderWidth(m_range, m_context.mode(), unitless);
+    }
+    case CSSPropertyZIndex:
+        return consumeZIndex(m_range);
+    case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
+    case CSSPropertyBoxShadow:
+        return consumeShadow(m_range, m_context.mode(), property == CSSPropertyBoxShadow);
+    case CSSPropertyFilter:
+    case CSSPropertyBackdropFilter:
+        return consumeFilter(m_range, m_context);
+    case CSSPropertyTextDecoration:
+        ASSERT(!RuntimeEnabledFeatures::css3TextDecorationsEnabled());
+        // fallthrough
+    case CSSPropertyWebkitTextDecorationsInEffect:
+    case CSSPropertyTextDecorationLine:
+        return consumeTextDecorationLine(m_range);
+    case CSSPropertyD:
+    case CSSPropertyMotionPath:
+        return consumePathOrNone(m_range);
+    case CSSPropertyMotionOffset:
+        return consumeLengthOrPercent(m_range, m_context.mode(), ValueRangeAll);
+    case CSSPropertyMotionRotation:
+        return consumeMotionRotation(m_range);
+    case CSSPropertyWebkitTextEmphasisStyle:
+        return consumeTextEmphasisStyle(m_range);
+    case CSSPropertyOutlineColor:
+        return consumeOutlineColor(m_range, m_context.mode());
+    case CSSPropertyOutlineOffset:
+        return consumeLength(m_range, m_context.mode(), ValueRangeAll);
+    case CSSPropertyOutlineWidth:
+        return consumeLineWidth(m_range, m_context.mode(), UnitlessQuirk::Forbid);
+    case CSSPropertyTransform:
+        return consumeTransform(m_range, m_context.mode(), unresolvedProperty == CSSPropertyAliasWebkitTransform);
+    case CSSPropertyWebkitTransformOriginX:
+    case CSSPropertyWebkitPerspectiveOriginX:
+        return consumePositionX(m_range, m_context.mode());
+    case CSSPropertyWebkitTransformOriginY:
+    case CSSPropertyWebkitPerspectiveOriginY:
+        return consumePositionY(m_range, m_context.mode());
+    case CSSPropertyWebkitTransformOriginZ:
+        return consumeLength(m_range, m_context.mode(), ValueRangeAll);
+    case CSSPropertyFill:
+    case CSSPropertyStroke:
+        return consumePaintStroke(m_range, m_context.mode());
+    case CSSPropertyPaintOrder:
+        return consumePaintOrder(m_range);
+    case CSSPropertyMarkerStart:
+    case CSSPropertyMarkerMid:
+    case CSSPropertyMarkerEnd:
+    case CSSPropertyClipPath:
+    case CSSPropertyMask:
+        return consumeNoneOrURI(m_range);
+    case CSSPropertyFlexBasis:
+        return consumeFlexBasis(m_range, m_context.mode());
+    case CSSPropertyFlexGrow:
+    case CSSPropertyFlexShrink:
+        return consumeNumber(m_range, ValueRangeNonNegative);
+    case CSSPropertyStrokeDasharray:
+        return consumeStrokeDasharray(m_range);
+    case CSSPropertyColumnRuleWidth:
+        return consumeColumnRuleWidth(m_range, m_context.mode());
+    case CSSPropertyStrokeOpacity:
+    case CSSPropertyFillOpacity:
+    case CSSPropertyStopOpacity:
+    case CSSPropertyFloodOpacity:
+    case CSSPropertyOpacity:
+    case CSSPropertyWebkitBoxFlex:
+        return consumeNumber(m_range, ValueRangeAll);
+    case CSSPropertyBaselineShift:
+        return consumeBaselineShift(m_range);
+    case CSSPropertyStrokeMiterlimit:
+        return consumeNumber(m_range, ValueRangeNonNegative);
+    case CSSPropertyStrokeWidth:
+    case CSSPropertyStrokeDashoffset:
+    case CSSPropertyCx:
+    case CSSPropertyCy:
+    case CSSPropertyX:
+    case CSSPropertyY:
+    case CSSPropertyR:
+        return consumeLengthOrPercent(m_range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
+    case CSSPropertyRx:
+    case CSSPropertyRy:
+        return consumeRxOrRy(m_range);
+    case CSSPropertyCursor:
+        return consumeCursor(m_range, m_context, inQuirksMode());
+    case CSSPropertyContain:
+        return consumeContain(m_range);
+    case CSSPropertyTransformOrigin:
+        return consumeTransformOrigin(m_range, m_context.mode(), UnitlessQuirk::Forbid);
+    case CSSPropertyContent:
+        return consumeContent(m_range, m_context);
+    case CSSPropertyListStyleImage:
+    case CSSPropertyBorderImageSource:
+    case CSSPropertyWebkitMaskBoxImageSource:
+        return consumeImageOrNone(m_range, m_context);
+    case CSSPropertyPerspective:
+        return consumePerspective(m_range, m_context.mode(), unresolvedProperty);
+    case CSSPropertyScrollSnapCoordinate:
+        return consumeScrollSnapCoordinate(m_range, m_context.mode());
+    case CSSPropertyScrollSnapPointsX:
+    case CSSPropertyScrollSnapPointsY:
+        return consumeScrollSnapPoints(m_range, m_context.mode());
+    case CSSPropertyBorderTopRightRadius:
+    case CSSPropertyBorderTopLeftRadius:
+    case CSSPropertyBorderBottomLeftRadius:
+    case CSSPropertyBorderBottomRightRadius:
+        return consumeBorderRadiusCorner(m_range, m_context.mode());
+    case CSSPropertyWebkitBoxFlexGroup:
+        return consumeInteger(m_range, 0);
+    case CSSPropertyOrder:
+        return consumeInteger(m_range);
+    case CSSPropertyTextUnderlinePosition:
+        // auto | [ under || [ left | right ] ], but we only support auto | under for now
+        ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
+        return consumeIdent&lt;CSSValueAuto, CSSValueUnder&gt;(m_range);
+    case CSSPropertyVerticalAlign:
+        return consumeVerticalAlign(m_range, m_context.mode());
+    case CSSPropertyShapeOutside:
+        return consumeShapeOutside(m_range, m_context);
+    case CSSPropertyWebkitClipPath:
+        return consumeWebkitClipPath(m_range, m_context);
+    case CSSPropertyJustifyContent:
+    case CSSPropertyAlignContent:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return consumeContentDistributionOverflowPosition(m_range);
+    case CSSPropertyBorderImageRepeat:
+    case CSSPropertyWebkitMaskBoxImageRepeat:
+        return consumeBorderImageRepeat(m_range);
+    case CSSPropertyBorderImageSlice:
+    case CSSPropertyWebkitMaskBoxImageSlice:
+        return consumeBorderImageSlice(property, m_range);
+    case CSSPropertyBorderImageOutset:
+    case CSSPropertyWebkitMaskBoxImageOutset:
+        return consumeBorderImageOutset(m_range);
+    case CSSPropertyBorderImageWidth:
+    case CSSPropertyWebkitMaskBoxImageWidth:
+        return consumeBorderImageWidth(m_range);
+    case CSSPropertyWebkitBorderImage:
+        return consumeWebkitBorderImage(property, m_range, m_context);
+    case CSSPropertyWebkitBoxReflect:
+        return consumeReflect(m_range, m_context);
+    case CSSPropertyFontSizeAdjust:
+        ASSERT(RuntimeEnabledFeatures::cssFontSizeAdjustEnabled());
+        return consumeFontSizeAdjust(m_range);
+    case CSSPropertyImageOrientation:
+        ASSERT(RuntimeEnabledFeatures::imageOrientationEnabled());
+        return consumeImageOrientation(m_range);
+    case CSSPropertyBackgroundAttachment:
+    case CSSPropertyBackgroundBlendMode:
+    case CSSPropertyBackgroundClip:
+    case CSSPropertyBackgroundImage:
+    case CSSPropertyBackgroundOrigin:
+    case CSSPropertyBackgroundPositionX:
+    case CSSPropertyBackgroundPositionY:
+    case CSSPropertyBackgroundSize:
+    case CSSPropertyMaskSourceType:
+    case CSSPropertyWebkitBackgroundClip:
+    case CSSPropertyWebkitBackgroundOrigin:
+    case CSSPropertyWebkitMaskClip:
+    case CSSPropertyWebkitMaskComposite:
+    case CSSPropertyWebkitMaskImage:
+    case CSSPropertyWebkitMaskOrigin:
+    case CSSPropertyWebkitMaskPositionX:
+    case CSSPropertyWebkitMaskPositionY:
+    case CSSPropertyWebkitMaskSize:
+        return consumeCommaSeparatedBackgroundComponent(unresolvedProperty, m_range, m_context);
+    case CSSPropertyWebkitMaskRepeatX:
+    case CSSPropertyWebkitMaskRepeatY:
+        return nullptr;
+    case CSSPropertyAlignItems:
+        DCHECK(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return consumeAlignItems(m_range);
+    case CSSPropertyJustifySelf:
+    case CSSPropertyAlignSelf:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return consumeSelfPositionOverflowPosition(m_range);
+    case CSSPropertyJustifyItems:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return consumeJustifyItems(m_range);
+    case CSSPropertyGridColumnEnd:
+    case CSSPropertyGridColumnStart:
+    case CSSPropertyGridRowEnd:
+    case CSSPropertyGridRowStart:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return consumeGridLine(m_range);
+    case CSSPropertyGridAutoColumns:
+    case CSSPropertyGridAutoRows:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return consumeGridTrackList(m_range, m_context.mode(), GridAuto);
+    case CSSPropertyGridTemplateColumns:
+    case CSSPropertyGridTemplateRows:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return consumeGridTemplatesRowsOrColumns(m_range, m_context.mode());
+    case CSSPropertyGridTemplateAreas:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return consumeGridTemplateAreas(m_range);
+    case CSSPropertyGridAutoFlow:
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+        return consumeGridAutoFlow(m_range);
+    default:
+        return nullptr;
+    }
+}
+
+static CSSPrimitiveValue* consumeFontDisplay(CSSParserTokenRange&amp; range)
+{
+    return consumeIdent&lt;CSSValueAuto, CSSValueBlock, CSSValueSwap, CSSValueFallback, CSSValueOptional&gt;(range);
+}
+
+static CSSValueList* consumeFontFaceUnicodeRange(CSSParserTokenRange&amp; range)
+{
+    CSSValueList* values = CSSValueList::createCommaSeparated();
+
+    do {
+        const CSSParserToken&amp; token = range.consumeIncludingWhitespace();
+        if (token.type() != UnicodeRangeToken)
+            return nullptr;
+
+        UChar32 start = token.unicodeRangeStart();
+        UChar32 end = token.unicodeRangeEnd();
+        if (start &gt; end)
+            return nullptr;
+        values-&gt;append(*CSSUnicodeRangeValue::create(start, end));
+    } while (consumeCommaIncludingWhitespace(range));
+
+    return values;
+}
+
+static CSSValue* consumeFontFaceSrcURI(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    String url = consumeUrlAsStringView(range).toString();
+    if (url.isNull())
+        return nullptr;
+    CSSFontFaceSrcValue* uriValue(CSSFontFaceSrcValue::create(url, context.completeURL(url), context.shouldCheckContentSecurityPolicy()));
+    uriValue-&gt;setReferrer(context.referrer());
+
+    if (range.peek().functionId() != CSSValueFormat)
+        return uriValue;
+
+    // FIXME: https://drafts.csswg.org/css-fonts says that format() contains a comma-separated list of strings,
+    // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
+    CSSParserTokenRange args = consumeFunction(range);
+    const CSSParserToken&amp; arg = args.consumeIncludingWhitespace();
+    if ((arg.type() != StringToken) || !args.atEnd())
+        return nullptr;
+    uriValue-&gt;setFormat(arg.value().toString());
+    return uriValue;
+}
+
+static CSSValue* consumeFontFaceSrcLocal(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    CSSParserTokenRange args = consumeFunction(range);
+    ContentSecurityPolicyDisposition shouldCheckContentSecurityPolicy = context.shouldCheckContentSecurityPolicy();
+    if (args.peek().type() == StringToken) {
+        const CSSParserToken&amp; arg = args.consumeIncludingWhitespace();
+        if (!args.atEnd())
+            return nullptr;
+        return CSSFontFaceSrcValue::createLocal(arg.value().toString(), shouldCheckContentSecurityPolicy);
+    }
+    if (args.peek().type() == IdentToken) {
+        String familyName = concatenateFamilyName(args);
+        if (!args.atEnd())
+            return nullptr;
+        return CSSFontFaceSrcValue::createLocal(familyName, shouldCheckContentSecurityPolicy);
+    }
+    return nullptr;
+}
+
+static CSSValueList* consumeFontFaceSrc(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    CSSValueList* values = CSSValueList::createCommaSeparated();
+
+    do {
+        const CSSParserToken&amp; token = range.peek();
+        CSSValue* parsedValue = nullptr;
+        if (token.functionId() == CSSValueLocal)
+            parsedValue = consumeFontFaceSrcLocal(range, context);
+        else
+            parsedValue = consumeFontFaceSrcURI(range, context);
+        if (!parsedValue)
+            return nullptr;
+        values-&gt;append(*parsedValue);
+    } while (consumeCommaIncludingWhitespace(range));
+    return values;
+}
+
+bool CSSPropertyParser::parseFontFaceDescriptor(CSSPropertyID propId)
+{
+    CSSValue* parsedValue = nullptr;
+    switch (propId) {
+    case CSSPropertyFontFamily:
+        if (consumeGenericFamily(m_range))
+            return false;
+        parsedValue = consumeFamilyName(m_range);
+        break;
+    case CSSPropertySrc: // This is a list of urls or local references.
+        parsedValue = consumeFontFaceSrc(m_range, m_context);
+        break;
+    case CSSPropertyUnicodeRange:
+        parsedValue = consumeFontFaceUnicodeRange(m_range);
+        break;
+    case CSSPropertyFontDisplay:
+        parsedValue = consumeFontDisplay(m_range);
+        break;
+    case CSSPropertyFontStretch:
+    case CSSPropertyFontStyle: {
+        CSSValueID id = m_range.consumeIncludingWhitespace().id();
+        if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id, m_context.mode()))
+            return false;
+        parsedValue = CSSPrimitiveValue::createIdentifier(id);
+        break;
+    }
+    case CSSPropertyFontVariant:
+        parsedValue = consumeFontVariantList(m_range);
+        break;
+    case CSSPropertyFontWeight:
+        parsedValue = consumeFontWeight(m_range);
+        break;
+    case CSSPropertyFontFeatureSettings:
+        parsedValue = consumeFontFeatureSettings(m_range);
+        break;
+    default:
+        break;
+    }
+
+    if (!parsedValue || !m_range.atEnd())
+        return false;
+
+    addProperty(propId, CSSPropertyInvalid, *parsedValue, false);
+    return true;
+}
+
+bool CSSPropertyParser::consumeSystemFont(bool important)
+{
+    CSSValueID systemFontID = m_range.consumeIncludingWhitespace().id();
+    ASSERT(systemFontID &gt;= CSSValueCaption &amp;&amp; systemFontID &lt;= CSSValueStatusBar);
+    if (!m_range.atEnd())
+        return false;
+
+    FontStyle fontStyle = FontStyleNormal;
+    FontWeight fontWeight = FontWeightNormal;
+    float fontSize = 0;
+    AtomicString fontFamily;
+    LayoutTheme::theme().systemFont(systemFontID, fontStyle, fontWeight, fontSize, fontFamily);
+
+    addProperty(CSSPropertyFontStyle, CSSPropertyFont, *CSSPrimitiveValue::createIdentifier(fontStyle == FontStyleItalic ? CSSValueItalic : CSSValueNormal), important);
+    addProperty(CSSPropertyFontWeight, CSSPropertyFont, *CSSPrimitiveValue::create(fontWeight), important);
+    addProperty(CSSPropertyFontSize, CSSPropertyFont, *CSSPrimitiveValue::create(fontSize, CSSPrimitiveValue::UnitType::Pixels), important);
+    CSSValueList* fontFamilyList = CSSValueList::createCommaSeparated();
+    fontFamilyList-&gt;append(*CSSFontFamilyValue::create(fontFamily));
+    addProperty(CSSPropertyFontFamily, CSSPropertyFont, *fontFamilyList, important);
+
+    addProperty(CSSPropertyFontStretch, CSSPropertyFont, *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+    addProperty(CSSPropertyFontVariantCaps, CSSPropertyFont, *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+    addProperty(CSSPropertyFontVariantLigatures, CSSPropertyFont, *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+    addProperty(CSSPropertyFontVariantNumeric, CSSPropertyFont, *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+    addProperty(CSSPropertyLineHeight, CSSPropertyFont, *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+    return true;
+}
+
+bool CSSPropertyParser::consumeFont(bool important)
+{
+    // Let's check if there is an inherit or initial somewhere in the shorthand.
+    CSSParserTokenRange range = m_range;
+    while (!range.atEnd()) {
+        CSSValueID id = range.consumeIncludingWhitespace().id();
+        if (id == CSSValueInherit || id == CSSValueInitial)
+            return false;
+    }
+    // Optional font-style, font-variant, font-stretch and font-weight.
+    CSSPrimitiveValue* fontStyle = nullptr;
+    CSSPrimitiveValue* fontVariantCaps = nullptr;
+    CSSPrimitiveValue* fontWeight = nullptr;
+    CSSPrimitiveValue* fontStretch = nullptr;
+    while (!m_range.atEnd()) {
+        CSSValueID id = m_range.peek().id();
+        if (!fontStyle &amp;&amp; CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyFontStyle, id, m_context.mode())) {
+            fontStyle = consumeIdent(m_range);
+            continue;
+        }
+        if (!fontVariantCaps &amp;&amp; (id == CSSValueNormal || id == CSSValueSmallCaps)) {
+            // Font variant in the shorthand is particular, it only accepts normal or small-caps.
+            // See https://drafts.csswg.org/css-fonts/#propdef-font
+            fontVariantCaps = consumeFontVariantCSS21(m_range);
+            if (fontVariantCaps)
+                continue;
+        }
+        if (!fontWeight) {
+            fontWeight = consumeFontWeight(m_range);
+            if (fontWeight)
+                continue;
+        }
+        if (!fontStretch &amp;&amp; CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyFontStretch, id, m_context.mode()))
+            fontStretch = consumeIdent(m_range);
+        else
+            break;
+    }
+
+    if (m_range.atEnd())
+        return false;
+
+    addProperty(CSSPropertyFontStyle, CSSPropertyFont, fontStyle ? *fontStyle : *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+    addProperty(CSSPropertyFontVariantCaps, CSSPropertyFont, fontVariantCaps ? *fontVariantCaps : *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+    addProperty(CSSPropertyFontVariantLigatures, CSSPropertyFont, *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+    addProperty(CSSPropertyFontVariantNumeric, CSSPropertyFont, *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+
+    addProperty(CSSPropertyFontWeight, CSSPropertyFont, fontWeight ? *fontWeight : *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+    addProperty(CSSPropertyFontStretch, CSSPropertyFont, fontStretch ? *fontStretch : *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+
+    // Now a font size _must_ come.
+    CSSValue* fontSize = consumeFontSize(m_range, m_context.mode());
+    if (!fontSize || m_range.atEnd())
+        return false;
+
+    addProperty(CSSPropertyFontSize, CSSPropertyFont, *fontSize, important);
+
+    if (consumeSlashIncludingWhitespace(m_range)) {
+        CSSPrimitiveValue* lineHeight = consumeLineHeight(m_range, m_context.mode());
+        if (!lineHeight)
+            return false;
+        addProperty(CSSPropertyLineHeight, CSSPropertyFont, *lineHeight, important);
+    } else {
+        addProperty(CSSPropertyLineHeight, CSSPropertyFont, *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+    }
+
+    // Font family must come now.
+    CSSValue* parsedFamilyValue = consumeFontFamily(m_range);
+    if (!parsedFamilyValue)
+        return false;
+
+    addProperty(CSSPropertyFontFamily, CSSPropertyFont, *parsedFamilyValue, important);
+
+    // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
+    // &quot;font-stretch&quot;, &quot;font-size-adjust&quot;, and &quot;font-kerning&quot; be reset to their initial values
+    // but we don't seem to support them at the moment. They should also be added here once implemented.
+    return m_range.atEnd();
+}
+
+bool CSSPropertyParser::consumeFontVariantShorthand(bool important)
+{
+    if (identMatches&lt;CSSValueNormal, CSSValueNone&gt;(m_range.peek().id())) {
+        addProperty(CSSPropertyFontVariantLigatures, CSSPropertyFontVariant, *consumeIdent(m_range), important);
+        addProperty(CSSPropertyFontVariantCaps, CSSPropertyFontVariant, *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+        return m_range.atEnd();
+    }
+
+    CSSPrimitiveValue* capsValue = nullptr;
+    FontVariantLigaturesParser ligaturesParser;
+    FontVariantNumericParser numericParser;
+    do {
+        FontVariantLigaturesParser::ParseResult ligaturesParseResult = ligaturesParser.consumeLigature(m_range);
+        FontVariantNumericParser::ParseResult numericParseResult = numericParser.consumeNumeric(m_range);
+        if (ligaturesParseResult == FontVariantLigaturesParser::ParseResult::ConsumedValue
+            || numericParseResult == FontVariantNumericParser::ParseResult::ConsumedValue)
+            continue;
+
+        if (ligaturesParseResult == FontVariantLigaturesParser::ParseResult::DisallowedValue
+            || numericParseResult == FontVariantNumericParser::ParseResult::DisallowedValue)
+            return false;
+
+        CSSValueID id = m_range.peek().id();
+        switch (id) {
+        case CSSValueSmallCaps:
+        case CSSValueAllSmallCaps:
+        case CSSValuePetiteCaps:
+        case CSSValueAllPetiteCaps:
+        case CSSValueUnicase:
+        case CSSValueTitlingCaps:
+            // Only one caps value permitted in font-variant grammar.
+            if (capsValue)
+                return false;
+            capsValue = consumeIdent(m_range);
+            break;
+        default:
+            return false;
+        }
+    } while (!m_range.atEnd());
+
+    addProperty(CSSPropertyFontVariantLigatures, CSSPropertyFontVariant, *ligaturesParser.finalizeValue(), important);
+    addProperty(CSSPropertyFontVariantNumeric, CSSPropertyFontVariant, *numericParser.finalizeValue(), important);
+    addProperty(CSSPropertyFontVariantCaps, CSSPropertyFontVariant, capsValue ? *capsValue : *CSSPrimitiveValue::createIdentifier(CSSValueNormal), important);
+    return true;
+}
+
+bool CSSPropertyParser::consumeBorderSpacing(bool important)
+{
+    CSSValue* horizontalSpacing = consumeLength(m_range, m_context.mode(), ValueRangeNonNegative, UnitlessQuirk::Allow);
+    if (!horizontalSpacing)
+        return false;
+    CSSValue* verticalSpacing = horizontalSpacing;
+    if (!m_range.atEnd())
+        verticalSpacing = consumeLength(m_range, m_context.mode(), ValueRangeNonNegative, UnitlessQuirk::Allow);
+    if (!verticalSpacing || !m_range.atEnd())
+        return false;
+    addProperty(CSSPropertyWebkitBorderHorizontalSpacing, CSSPropertyBorderSpacing, *horizontalSpacing, important);
+    addProperty(CSSPropertyWebkitBorderVerticalSpacing, CSSPropertyBorderSpacing, *verticalSpacing, important);
+    return true;
+}
+
+static CSSValue* consumeSingleViewportDescriptor(CSSParserTokenRange&amp; range, CSSPropertyID propId, CSSParserMode cssParserMode)
+{
+    CSSValueID id = range.peek().id();
+    switch (propId) {
+    case CSSPropertyMinWidth:
+    case CSSPropertyMaxWidth:
+    case CSSPropertyMinHeight:
+    case CSSPropertyMaxHeight:
+        if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom)
+            return consumeIdent(range);
+        return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
+    case CSSPropertyMinZoom:
+    case CSSPropertyMaxZoom:
+    case CSSPropertyZoom: {
+        if (id == CSSValueAuto)
+            return consumeIdent(range);
+        CSSValue* parsedValue = consumeNumber(range, ValueRangeNonNegative);
+        if (parsedValue)
+            return parsedValue;
+        return consumePercent(range, ValueRangeNonNegative);
+    }
+    case CSSPropertyUserZoom:
+        return consumeIdent&lt;CSSValueZoom, CSSValueFixed&gt;(range);
+    case CSSPropertyOrientation:
+        return consumeIdent&lt;CSSValueAuto, CSSValuePortrait, CSSValueLandscape&gt;(range);
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+
+    ASSERT_NOT_REACHED();
+    return nullptr;
+}
+
+bool CSSPropertyParser::parseViewportDescriptor(CSSPropertyID propId, bool important)
+{
+    ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_context.mode()));
+
+    switch (propId) {
+    case CSSPropertyWidth: {
+        CSSValue* minWidth = consumeSingleViewportDescriptor(m_range, CSSPropertyMinWidth, m_context.mode());
+        if (!minWidth)
+            return false;
+        CSSValue* maxWidth = minWidth;
+        if (!m_range.atEnd())
+            maxWidth = consumeSingleViewportDescriptor(m_range, CSSPropertyMaxWidth, m_context.mode());
+        if (!maxWidth || !m_range.atEnd())
+            return false;
+        addProperty(CSSPropertyMinWidth, CSSPropertyInvalid, *minWidth, important);
+        addProperty(CSSPropertyMaxWidth, CSSPropertyInvalid, *maxWidth, important);
+        return true;
+    }
+    case CSSPropertyHeight: {
+        CSSValue* minHeight = consumeSingleViewportDescriptor(m_range, CSSPropertyMinHeight, m_context.mode());
+        if (!minHeight)
+            return false;
+        CSSValue* maxHeight = minHeight;
+        if (!m_range.atEnd())
+            maxHeight = consumeSingleViewportDescriptor(m_range, CSSPropertyMaxHeight, m_context.mode());
+        if (!maxHeight || !m_range.atEnd())
+            return false;
+        addProperty(CSSPropertyMinHeight, CSSPropertyInvalid, *minHeight, important);
+        addProperty(CSSPropertyMaxHeight, CSSPropertyInvalid, *maxHeight, important);
+        return true;
+    }
+    case CSSPropertyMinWidth:
+    case CSSPropertyMaxWidth:
+    case CSSPropertyMinHeight:
+    case CSSPropertyMaxHeight:
+    case CSSPropertyMinZoom:
+    case CSSPropertyMaxZoom:
+    case CSSPropertyZoom:
+    case CSSPropertyUserZoom:
+    case CSSPropertyOrientation: {
+        CSSValue* parsedValue = consumeSingleViewportDescriptor(m_range, propId, m_context.mode());
+        if (!parsedValue || !m_range.atEnd())
+            return false;
+        addProperty(propId, CSSPropertyInvalid, *parsedValue, important);
+        return true;
+    }
+    default:
+        return false;
+    }
+}
+
+static bool consumeColumnWidthOrCount(CSSParserTokenRange&amp; range, CSSValue*&amp; columnWidth, CSSValue*&amp; columnCount)
+{
+    if (range.peek().id() == CSSValueAuto) {
+        consumeIdent(range);
+        return true;
+    }
+    if (!columnWidth) {
+        columnWidth = consumeColumnWidth(range);
+        if (columnWidth)
+            return true;
+    }
+    if (!columnCount)
+        columnCount = consumeColumnCount(range);
+    return columnCount;
+}
+
+bool CSSPropertyParser::consumeColumns(bool important)
+{
+    CSSValue* columnWidth = nullptr;
+    CSSValue* columnCount = nullptr;
+    if (!consumeColumnWidthOrCount(m_range, columnWidth, columnCount))
+        return false;
+    consumeColumnWidthOrCount(m_range, columnWidth, columnCount);
+    if (!m_range.atEnd())
+        return false;
+    if (!columnWidth)
+        columnWidth = CSSPrimitiveValue::createIdentifier(CSSValueAuto);
+    if (!columnCount)
+        columnCount = CSSPrimitiveValue::createIdentifier(CSSValueAuto);
+    addProperty(CSSPropertyColumnWidth, CSSPropertyInvalid, *columnWidth, important);
+    addProperty(CSSPropertyColumnCount, CSSPropertyInvalid, *columnCount, important);
+    return true;
+}
+
+bool CSSPropertyParser::consumeShorthandGreedily(const StylePropertyShorthand&amp; shorthand, bool important)
+{
+    ASSERT(shorthand.length() &lt;= 6); // Existing shorthands have at most 6 longhands.
+    const CSSValue* longhands[6] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
+    const CSSPropertyID* shorthandProperties = shorthand.properties();
+    do {
+        bool foundLonghand = false;
+        for (size_t i = 0; !foundLonghand &amp;&amp; i &lt; shorthand.length(); ++i) {
+            if (longhands[i])
+                continue;
+            longhands[i] = parseSingleValue(shorthandProperties[i], shorthand.id());
+            if (longhands[i])
+                foundLonghand = true;
+        }
+        if (!foundLonghand)
+            return false;
+    } while (!m_range.atEnd());
+
+    for (size_t i = 0; i &lt; shorthand.length(); ++i) {
+        if (longhands[i])
+            addProperty(shorthandProperties[i], shorthand.id(), *longhands[i], important);
+        else
+            addProperty(shorthandProperties[i], shorthand.id(), *CSSInitialValue::createLegacyImplicit(), important);
+    }
+    return true;
+}
+
+bool CSSPropertyParser::consumeFlex(bool important)
+{
+    static const double unsetValue = -1;
+    double flexGrow = unsetValue;
+    double flexShrink = unsetValue;
+    CSSPrimitiveValue* flexBasis = nullptr;
+
+    if (m_range.peek().id() == CSSValueNone) {
+        flexGrow = 0;
+        flexShrink = 0;
+        flexBasis = CSSPrimitiveValue::createIdentifier(CSSValueAuto);
+        m_range.consumeIncludingWhitespace();
+    } else {
+        unsigned index = 0;
+        while (!m_range.atEnd() &amp;&amp; index++ &lt; 3) {
+            double num;
+            if (consumeNumberRaw(m_range, num)) {
+                if (num &lt; 0)
+                    return false;
+                if (flexGrow == unsetValue)
+                    flexGrow = num;
+                else if (flexShrink == unsetValue)
+                    flexShrink = num;
+                else if (!num) // flex only allows a basis of 0 (sans units) if flex-grow and flex-shrink values have already been set.
+                    flexBasis = CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitType::Pixels);
+                else
+                    return false;
+            } else if (!flexBasis) {
+                if (m_range.peek().id() == CSSValueAuto)
+                    flexBasis = consumeIdent(m_range);
+                if (!flexBasis)
+                    flexBasis = consumeLengthOrPercent(m_range, m_context.mode(), ValueRangeNonNegative);
+                if (index == 2 &amp;&amp; !m_range.atEnd())
+                    return false;
+            }
+        }
+        if (index == 0)
+            return false;
+        if (flexGrow == unsetValue)
+            flexGrow = 1;
+        if (flexShrink == unsetValue)
+            flexShrink = 1;
+        if (!flexBasis)
+            flexBasis = CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitType::Percentage);
+    }
+
+    if (!m_range.atEnd())
+        return false;
+    addProperty(CSSPropertyFlexGrow, CSSPropertyFlex, *CSSPrimitiveValue::create(clampTo&lt;float&gt;(flexGrow), CSSPrimitiveValue::UnitType::Number), important);
+    addProperty(CSSPropertyFlexShrink, CSSPropertyFlex, *CSSPrimitiveValue::create(clampTo&lt;float&gt;(flexShrink), CSSPrimitiveValue::UnitType::Number), important);
+    addProperty(CSSPropertyFlexBasis, CSSPropertyFlex, *flexBasis, important);
+    return true;
+}
+
+bool CSSPropertyParser::consumeBorder(bool important)
+{
+    CSSValue* width = nullptr;
+    const CSSValue* style = nullptr;
+    CSSValue* color = nullptr;
+
+    while (!width || !style || !color) {
+        if (!width) {
+            width = consumeLineWidth(m_range, m_context.mode(), UnitlessQuirk::Forbid);
+            if (width)
+                continue;
+        }
+        if (!style) {
+            style = parseSingleValue(CSSPropertyBorderLeftStyle, CSSPropertyBorder);
+            if (style)
+                continue;
+        }
+        if (!color) {
+            color = consumeColor(m_range, m_context.mode());
+            if (color)
+                continue;
+        }
+        break;
+    }
+
+    if (!width &amp;&amp; !style &amp;&amp; !color)
+        return false;
+
+    if (!width)
+        width = CSSInitialValue::createLegacyImplicit();
+    if (!style)
+        style = CSSInitialValue::createLegacyImplicit();
+    if (!color)
+        color = CSSInitialValue::createLegacyImplicit();
+
+    addExpandedPropertyForValue(CSSPropertyBorderWidth, *width, important);
+    addExpandedPropertyForValue(CSSPropertyBorderStyle, *style, important);
+    addExpandedPropertyForValue(CSSPropertyBorderColor, *color, important);
+    addExpandedPropertyForValue(CSSPropertyBorderImage, *CSSInitialValue::createLegacyImplicit(), important);
+
+    return m_range.atEnd();
+}
+
+bool CSSPropertyParser::consume4Values(const StylePropertyShorthand&amp; shorthand, bool important)
+{
+    ASSERT(shorthand.length() == 4);
+    const CSSPropertyID* longhands = shorthand.properties();
+    const CSSValue* top = parseSingleValue(longhands[0], shorthand.id());
+    if (!top)
+        return false;
+
+    const CSSValue* right = parseSingleValue(longhands[1], shorthand.id());
+    const CSSValue* bottom = nullptr;
+    const CSSValue* left = nullptr;
+    if (right) {
+        bottom = parseSingleValue(longhands[2], shorthand.id());
+        if (bottom)
+            left = parseSingleValue(longhands[3], shorthand.id());
+    }
+
+    if (!right)
+        right = top;
+    if (!bottom)
+        bottom = top;
+    if (!left)
+        left = right;
+
+    addProperty(longhands[0], shorthand.id(), *top, important);
+    addProperty(longhands[1], shorthand.id(), *right, important);
+    addProperty(longhands[2], shorthand.id(), *bottom, important);
+    addProperty(longhands[3], shorthand.id(), *left, important);
+
+    return m_range.atEnd();
+}
+
+bool CSSPropertyParser::consumeBorderImage(CSSPropertyID property, bool important)
+{
+    CSSValue* source = nullptr;
+    CSSValue* slice = nullptr;
+    CSSValue* width = nullptr;
+    CSSValue* outset = nullptr;
+    CSSValue* repeat = nullptr;
+    if (consumeBorderImageComponents(property, m_range, m_context, source, slice, width, outset, repeat)) {
+        switch (property) {
+        case CSSPropertyWebkitMaskBoxImage:
+            addProperty(CSSPropertyWebkitMaskBoxImageSource, CSSPropertyWebkitMaskBoxImage, source ? *source : *CSSInitialValue::createLegacyImplicit(), important);
+            addProperty(CSSPropertyWebkitMaskBoxImageSlice, CSSPropertyWebkitMaskBoxImage, slice ? *slice : *CSSInitialValue::createLegacyImplicit(), important);
+            addProperty(CSSPropertyWebkitMaskBoxImageWidth, CSSPropertyWebkitMaskBoxImage, width ? *width : *CSSInitialValue::createLegacyImplicit(), important);
+            addProperty(CSSPropertyWebkitMaskBoxImageOutset, CSSPropertyWebkitMaskBoxImage, outset ? *outset : *CSSInitialValue::createLegacyImplicit(), important);
+            addProperty(CSSPropertyWebkitMaskBoxImageRepeat, CSSPropertyWebkitMaskBoxImage, repeat ? *repeat : *CSSInitialValue::createLegacyImplicit(), important);
+            return true;
+        case CSSPropertyBorderImage:
+            addProperty(CSSPropertyBorderImageSource, CSSPropertyBorderImage, source ? *source : *CSSInitialValue::createLegacyImplicit(), important);
+            addProperty(CSSPropertyBorderImageSlice, CSSPropertyBorderImage, slice ? *slice : *CSSInitialValue::createLegacyImplicit(), important);
+            addProperty(CSSPropertyBorderImageWidth, CSSPropertyBorderImage, width ? *width : *CSSInitialValue::createLegacyImplicit(), important);
+            addProperty(CSSPropertyBorderImageOutset, CSSPropertyBorderImage, outset ? *outset : *CSSInitialValue::createLegacyImplicit(), important);
+            addProperty(CSSPropertyBorderImageRepeat, CSSPropertyBorderImage, repeat ? *repeat : *CSSInitialValue::createLegacyImplicit(), important);
+            return true;
+        default:
+            ASSERT_NOT_REACHED();
+            return false;
+        }
+    }
+    return false;
+}
+
+static inline CSSValueID mapFromPageBreakBetween(CSSValueID value)
+{
+    if (value == CSSValueAlways)
+        return CSSValuePage;
+    if (value == CSSValueAuto || value == CSSValueAvoid || value == CSSValueLeft || value == CSSValueRight)
+        return value;
+    return CSSValueInvalid;
+}
+
+static inline CSSValueID mapFromColumnBreakBetween(CSSValueID value)
+{
+    if (value == CSSValueAlways)
+        return CSSValueColumn;
+    if (value == CSSValueAuto || value == CSSValueAvoid)
+        return value;
+    return CSSValueInvalid;
+}
+
+static inline CSSValueID mapFromColumnOrPageBreakInside(CSSValueID value)
+{
+    if (value == CSSValueAuto || value == CSSValueAvoid)
+        return value;
+    return CSSValueInvalid;
+}
+
+static inline CSSPropertyID mapFromLegacyBreakProperty(CSSPropertyID property)
+{
+    if (property == CSSPropertyPageBreakAfter || property == CSSPropertyWebkitColumnBreakAfter)
+        return CSSPropertyBreakAfter;
+    if (property == CSSPropertyPageBreakBefore || property == CSSPropertyWebkitColumnBreakBefore)
+        return CSSPropertyBreakBefore;
+    ASSERT(property == CSSPropertyPageBreakInside || property == CSSPropertyWebkitColumnBreakInside);
+    return CSSPropertyBreakInside;
+}
+
+bool CSSPropertyParser::consumeLegacyBreakProperty(CSSPropertyID property, bool important)
+{
+    // The fragmentation spec says that page-break-(after|before|inside) are to be treated as
+    // shorthands for their break-(after|before|inside) counterparts. We'll do the same for the
+    // non-standard properties -webkit-column-break-(after|before|inside).
+    CSSPrimitiveValue* keyword = consumeIdent(m_range);
+    if (!keyword)
+        return false;
+    if (!m_range.atEnd())
+        return false;
+    CSSValueID value = keyword-&gt;getValueID();
+    switch (property) {
+    case CSSPropertyPageBreakAfter:
+    case CSSPropertyPageBreakBefore:
+        value = mapFromPageBreakBetween(value);
+        break;
+    case CSSPropertyWebkitColumnBreakAfter:
+    case CSSPropertyWebkitColumnBreakBefore:
+        value = mapFromColumnBreakBetween(value);
+        break;
+    case CSSPropertyPageBreakInside:
+    case CSSPropertyWebkitColumnBreakInside:
+        value = mapFromColumnOrPageBreakInside(value);
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+    if (value == CSSValueInvalid)
+        return false;
+
+    CSSPropertyID genericBreakProperty = mapFromLegacyBreakProperty(property);
+    addProperty(genericBreakProperty, property, *CSSPrimitiveValue::createIdentifier(value), important);
+    return true;
+}
+
+static bool consumeBackgroundPosition(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context, UnitlessQuirk unitless, CSSValue*&amp; resultX, CSSValue*&amp; resultY)
+{
+    do {
+        CSSValue* positionX = nullptr;
+        CSSValue* positionY = nullptr;
+        if (!consumePosition(range, context.mode(), unitless, positionX, positionY))
+            return false;
+        addBackgroundValue(resultX, positionX);
+        addBackgroundValue(resultY, positionY);
+    } while (consumeCommaIncludingWhitespace(range));
+    return true;
+}
+
+static bool consumeRepeatStyleComponent(CSSParserTokenRange&amp; range, CSSValue*&amp; value1, CSSValue*&amp; value2, bool&amp; implicit)
+{
+    if (consumeIdent&lt;CSSValueRepeatX&gt;(range)) {
+        value1 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat);
+        value2 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat);
+        implicit = true;
+        return true;
+    }
+    if (consumeIdent&lt;CSSValueRepeatY&gt;(range)) {
+        value1 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat);
+        value2 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat);
+        implicit = true;
+        return true;
+    }
+    value1 = consumeIdent&lt;CSSValueRepeat, CSSValueNoRepeat, CSSValueRound, CSSValueSpace&gt;(range);
+    if (!value1)
+        return false;
+
+    value2 = consumeIdent&lt;CSSValueRepeat, CSSValueNoRepeat, CSSValueRound, CSSValueSpace&gt;(range);
+    if (!value2) {
+        value2 = value1;
+        implicit = true;
+    }
+    return true;
+}
+
+static bool consumeRepeatStyle(CSSParserTokenRange&amp; range, CSSValue*&amp; resultX, CSSValue*&amp; resultY, bool&amp; implicit)
+{
+    do {
+        CSSValue* repeatX = nullptr;
+        CSSValue* repeatY = nullptr;
+        if (!consumeRepeatStyleComponent(range, repeatX, repeatY, implicit))
+            return false;
+        addBackgroundValue(resultX, repeatX);
+        addBackgroundValue(resultY, repeatY);
+    } while (consumeCommaIncludingWhitespace(range));
+    return true;
+}
+
+// Note: consumeBackgroundShorthand assumes y properties (for example background-position-y) follow
+// the x properties in the shorthand array.
+bool CSSPropertyParser::consumeBackgroundShorthand(const StylePropertyShorthand&amp; shorthand, bool important)
+{
+    const unsigned longhandCount = shorthand.length();
+    CSSValue* longhands[10] = { 0 };
+    ASSERT(longhandCount &lt;= 10);
+
+    bool implicit = false;
+    do {
+        bool parsedLonghand[10] = { false };
+        CSSValue* originValue = nullptr;
+        do {
+            bool foundProperty = false;
+            for (size_t i = 0; i &lt; longhandCount; ++i) {
+                if (parsedLonghand[i])
+                    continue;
+
+                CSSValue* value = nullptr;
+                CSSValue* valueY = nullptr;
+                CSSPropertyID property = shorthand.properties()[i];
+                if (property == CSSPropertyBackgroundRepeatX || property == CSSPropertyWebkitMaskRepeatX) {
+                    consumeRepeatStyleComponent(m_range, value, valueY, implicit);
+                } else if (property == CSSPropertyBackgroundPositionX || property == CSSPropertyWebkitMaskPositionX) {
+                    CSSParserTokenRange rangeCopy = m_range;
+                    if (!consumePosition(rangeCopy, m_context.mode(), UnitlessQuirk::Forbid, value, valueY))
+                        continue;
+                    m_range = rangeCopy;
+                } else if (property == CSSPropertyBackgroundSize || property == CSSPropertyWebkitMaskSize) {
+                    if (!consumeSlashIncludingWhitespace(m_range))
+                        continue;
+                    value = consumeBackgroundSize(property, m_range, m_context.mode());
+                    if (!value || !parsedLonghand[i - 1]) // Position must have been parsed in the current layer.
+                        return false;
+                } else if (property == CSSPropertyBackgroundPositionY || property == CSSPropertyBackgroundRepeatY
+                    || property == CSSPropertyWebkitMaskPositionY || property == CSSPropertyWebkitMaskRepeatY) {
+                    continue;
+                } else {
+                    value = consumeBackgroundComponent(property, m_range, m_context);
+                }
+                if (value) {
+                    if (property == CSSPropertyBackgroundOrigin || property == CSSPropertyWebkitMaskOrigin)
+                        originValue = value;
+                    parsedLonghand[i] = true;
+                    foundProperty = true;
+                    addBackgroundValue(longhands[i], value);
+                    if (valueY) {
+                        parsedLonghand[i + 1] = true;
+                        addBackgroundValue(longhands[i + 1], valueY);
+                    }
+                }
+            }
+            if (!foundProperty)
+                return false;
+        } while (!m_range.atEnd() &amp;&amp; m_range.peek().type() != CommaToken);
+
+        // FIXME: This will make invalid longhands, see crbug.com/386459
+        for (size_t i = 0; i &lt; longhandCount; ++i) {
+            CSSPropertyID property = shorthand.properties()[i];
+            if (property == CSSPropertyBackgroundColor &amp;&amp; !m_range.atEnd()) {
+                if (parsedLonghand[i])
+                    return false; // Colors are only allowed in the last layer.
+                continue;
+            }
+            if ((property == CSSPropertyBackgroundClip || property == CSSPropertyWebkitMaskClip) &amp;&amp; !parsedLonghand[i] &amp;&amp; originValue) {
+                addBackgroundValue(longhands[i], originValue);
+                continue;
+            }
+            if (!parsedLonghand[i])
+                addBackgroundValue(longhands[i], CSSInitialValue::createLegacyImplicit());
+        }
+    } while (consumeCommaIncludingWhitespace(m_range));
+    if (!m_range.atEnd())
+        return false;
+
+    for (size_t i = 0; i &lt; longhandCount; ++i) {
+        CSSPropertyID property = shorthand.properties()[i];
+        if (property == CSSPropertyBackgroundSize &amp;&amp; longhands[i] &amp;&amp; m_context.useLegacyBackgroundSizeShorthandBehavior())
+            continue;
+        addProperty(property, shorthand.id(), *longhands[i], important, implicit);
+    }
+    return true;
+}
+
+bool CSSPropertyParser::consumeGridItemPositionShorthand(CSSPropertyID shorthandId, bool important)
+{
+    ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+    const StylePropertyShorthand&amp; shorthand = shorthandForProperty(shorthandId);
+    ASSERT(shorthand.length() == 2);
+    CSSValue* startValue = consumeGridLine(m_range);
+    if (!startValue)
+        return false;
+
+    CSSValue* endValue = nullptr;
+    if (consumeSlashIncludingWhitespace(m_range)) {
+        endValue = consumeGridLine(m_range);
+        if (!endValue)
+            return false;
+    } else {
+        endValue = startValue-&gt;isCustomIdentValue() ? startValue : CSSPrimitiveValue::createIdentifier(CSSValueAuto);
+    }
+    if (!m_range.atEnd())
+        return false;
+    addProperty(shorthand.properties()[0], shorthandId, *startValue, important);
+    addProperty(shorthand.properties()[1], shorthandId, *endValue, important);
+    return true;
+}
+
+bool CSSPropertyParser::consumeGridAreaShorthand(bool important)
+{
+    ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+    ASSERT(gridAreaShorthand().length() == 4);
+    CSSValue* rowStartValue = consumeGridLine(m_range);
+    if (!rowStartValue)
+        return false;
+    CSSValue* columnStartValue = nullptr;
+    CSSValue* rowEndValue = nullptr;
+    CSSValue* columnEndValue = nullptr;
+    if (consumeSlashIncludingWhitespace(m_range)) {
+        columnStartValue = consumeGridLine(m_range);
+        if (!columnStartValue)
+            return false;
+        if (consumeSlashIncludingWhitespace(m_range)) {
+            rowEndValue = consumeGridLine(m_range);
+            if (!rowEndValue)
+                return false;
+            if (consumeSlashIncludingWhitespace(m_range)) {
+                columnEndValue = consumeGridLine(m_range);
+                if (!columnEndValue)
+                    return false;
+            }
+        }
+    }
+    if (!m_range.atEnd())
+        return false;
+    if (!columnStartValue)
+        columnStartValue = rowStartValue-&gt;isCustomIdentValue() ? rowStartValue : CSSPrimitiveValue::createIdentifier(CSSValueAuto);
+    if (!rowEndValue)
+        rowEndValue = rowStartValue-&gt;isCustomIdentValue() ? rowStartValue : CSSPrimitiveValue::createIdentifier(CSSValueAuto);
+    if (!columnEndValue)
+        columnEndValue = columnStartValue-&gt;isCustomIdentValue() ? columnStartValue : CSSPrimitiveValue::createIdentifier(CSSValueAuto);
+
+    addProperty(CSSPropertyGridRowStart, CSSPropertyGridArea, *rowStartValue, important);
+    addProperty(CSSPropertyGridColumnStart, CSSPropertyGridArea, *columnStartValue, important);
+    addProperty(CSSPropertyGridRowEnd, CSSPropertyGridArea, *rowEndValue, important);
+    addProperty(CSSPropertyGridColumnEnd, CSSPropertyGridArea, *columnEndValue, important);
+    return true;
+}
+
+bool CSSPropertyParser::consumeGridTemplateRowsAndAreasAndColumns(CSSPropertyID shorthandId, bool important)
+{
+    NamedGridAreaMap gridAreaMap;
+    size_t rowCount = 0;
+    size_t columnCount = 0;
+    CSSValueList* templateRows = CSSValueList::createSpaceSeparated();
+
+    // Persists between loop iterations so we can use the same value for
+    // consecutive &lt;line-names&gt; values
+    CSSGridLineNamesValue* lineNames = nullptr;
+
+    do {
+        // Handle leading &lt;custom-ident&gt;*.
+        bool hasPreviousLineNames = lineNames;
+        lineNames = consumeGridLineNames(m_range, lineNames);
+        if (lineNames &amp;&amp; !hasPreviousLineNames)
+            templateRows-&gt;append(*lineNames);
+
+        // Handle a template-area's row.
+        if (m_range.peek().type() != StringToken || !parseGridTemplateAreasRow(m_range.consumeIncludingWhitespace().value().toString(), gridAreaMap, rowCount, columnCount))
+            return false;
+        ++rowCount;
+
+        // Handle template-rows's track-size.
+        CSSValue* value = consumeGridTrackSize(m_range, m_context.mode());
+        if (!value)
+            value = CSSPrimitiveValue::createIdentifier(CSSValueAuto);
+        templateRows-&gt;append(*value);
+
+        // This will handle the trailing/leading &lt;custom-ident&gt;* in the grammar.
+        lineNames = consumeGridLineNames(m_range);
+        if (lineNames)
+            templateRows-&gt;append(*lineNames);
+    } while (!m_range.atEnd() &amp;&amp; !(m_range.peek().type() == DelimiterToken &amp;&amp; m_range.peek().delimiter() == '/'));
+
+    CSSValue* columnsValue = nullptr;
+    if (!m_range.atEnd()) {
+        if (!consumeSlashIncludingWhitespace(m_range))
+            return false;
+        columnsValue = consumeGridTrackList(m_range, m_context.mode(), GridTemplateNoRepeat);
+        if (!columnsValue || !m_range.atEnd())
+            return false;
+    } else {
+        columnsValue = CSSPrimitiveValue::createIdentifier(CSSValueNone);
+    }
+    addProperty(CSSPropertyGridTemplateRows, shorthandId, *templateRows, important);
+    addProperty(CSSPropertyGridTemplateColumns, shorthandId, *columnsValue, important);
+    addProperty(CSSPropertyGridTemplateAreas, shorthandId, *CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount), important);
+    return true;
+}
+
+bool CSSPropertyParser::consumeGridTemplateShorthand(CSSPropertyID shorthandId, bool important)
+{
+    ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+    ASSERT(gridTemplateShorthand().length() == 3);
+
+    CSSParserTokenRange rangeCopy = m_range;
+    CSSValue* rowsValue = consumeIdent&lt;CSSValueNone&gt;(m_range);
+
+    // 1- 'none' case.
+    if (rowsValue &amp;&amp; m_range.atEnd()) {
+        addProperty(CSSPropertyGridTemplateRows, shorthandId, *CSSPrimitiveValue::createIdentifier(CSSValueNone), important);
+        addProperty(CSSPropertyGridTemplateColumns, shorthandId, *CSSPrimitiveValue::createIdentifier(CSSValueNone), important);
+        addProperty(CSSPropertyGridTemplateAreas, shorthandId, *CSSPrimitiveValue::createIdentifier(CSSValueNone), important);
+        return true;
+    }
+
+    // 2- &lt;grid-template-rows&gt; / &lt;grid-template-columns&gt;
+    if (!rowsValue)
+        rowsValue = consumeGridTrackList(m_range, m_context.mode(), GridTemplate);
+
+    if (rowsValue) {
+        if (!consumeSlashIncludingWhitespace(m_range))
+            return false;
+        CSSValue* columnsValue = consumeGridTemplatesRowsOrColumns(m_range, m_context.mode());
+        if (!columnsValue || !m_range.atEnd())
+            return false;
+
+        addProperty(CSSPropertyGridTemplateRows, shorthandId, *rowsValue, important);
+        addProperty(CSSPropertyGridTemplateColumns, shorthandId, *columnsValue, important);
+        addProperty(CSSPropertyGridTemplateAreas, shorthandId, *CSSPrimitiveValue::createIdentifier(CSSValueNone), important);
+        return true;
+    }
+
+    // 3- [ &lt;line-names&gt;? &lt;string&gt; &lt;track-size&gt;? &lt;line-names&gt;? ]+ [ / &lt;track-list&gt; ]?
+    m_range = rangeCopy;
+    return consumeGridTemplateRowsAndAreasAndColumns(shorthandId, important);
+}
+
+bool CSSPropertyParser::consumeGridShorthand(bool important)
+{
+    ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
+    ASSERT(shorthandForProperty(CSSPropertyGrid).length() == 8);
+
+    CSSParserTokenRange rangeCopy = m_range;
+
+    // 1- &lt;grid-template&gt;
+    if (consumeGridTemplateShorthand(CSSPropertyGrid, important)) {
+        // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
+        // The sub-properties not specified are set to their initial value, as normal for shorthands.
+        addProperty(CSSPropertyGridAutoFlow, CSSPropertyGrid, *CSSInitialValue::createLegacyImplicit(), important);
+        addProperty(CSSPropertyGridAutoColumns, CSSPropertyGrid, *CSSInitialValue::createLegacyImplicit(), important);
+        addProperty(CSSPropertyGridAutoRows, CSSPropertyGrid, *CSSInitialValue::createLegacyImplicit(), important);
+        addProperty(CSSPropertyGridColumnGap, CSSPropertyGrid, *CSSInitialValue::createLegacyImplicit(), important);
+        addProperty(CSSPropertyGridRowGap, CSSPropertyGrid, *CSSInitialValue::createLegacyImplicit(), important);
+        return true;
+    }
+
+    m_range = rangeCopy;
+
+    // 2- &lt;grid-auto-flow&gt; [ &lt;grid-auto-rows&gt; [ / &lt;grid-auto-columns&gt; ]? ]
+    CSSValueList* gridAutoFlow = consumeGridAutoFlow(m_range);
+    if (!gridAutoFlow)
+        return false;
+
+    CSSValue* autoColumnsValue = nullptr;
+    CSSValue* autoRowsValue = nullptr;
+
+    if (!m_range.atEnd()) {
+        autoRowsValue = consumeGridTrackList(m_range, m_context.mode(), GridAuto);
+        if (!autoRowsValue)
+            return false;
+        if (consumeSlashIncludingWhitespace(m_range)) {
+            autoColumnsValue = consumeGridTrackList(m_range, m_context.mode(), GridAuto);
+            if (!autoColumnsValue)
+                return false;
+        }
+        if (!m_range.atEnd())
+            return false;
+    } else {
+        // Other omitted values are set to their initial values.
+        autoColumnsValue = CSSInitialValue::createLegacyImplicit();
+        autoRowsValue = CSSInitialValue::createLegacyImplicit();
+    }
+
+    // if &lt;grid-auto-columns&gt; value is omitted, it is set to the value specified for grid-auto-rows.
+    if (!autoColumnsValue)
+        autoColumnsValue = autoRowsValue;
+
+    // It can only be specified the explicit or the implicit grid properties in a single grid declaration.
+    // The sub-properties not specified are set to their initial value, as normal for shorthands.
+    addProperty(CSSPropertyGridTemplateColumns, CSSPropertyGrid, *CSSInitialValue::createLegacyImplicit(), important);
+    addProperty(CSSPropertyGridTemplateRows, CSSPropertyGrid, *CSSInitialValue::createLegacyImplicit(), important);
+    addProperty(CSSPropertyGridTemplateAreas, CSSPropertyGrid, *CSSInitialValue::createLegacyImplicit(), important);
+    addProperty(CSSPropertyGridAutoFlow, CSSPropertyGrid, *gridAutoFlow, important);
+    addProperty(CSSPropertyGridAutoColumns, CSSPropertyGrid, *autoColumnsValue, important);
+    addProperty(CSSPropertyGridAutoRows, CSSPropertyGrid, *autoRowsValue, important);
+    addProperty(CSSPropertyGridColumnGap, CSSPropertyGrid, *CSSInitialValue::createLegacyImplicit(), important);
+    addProperty(CSSPropertyGridRowGap, CSSPropertyGrid, *CSSInitialValue::createLegacyImplicit(), important);
+    return true;
+}
+
+bool CSSPropertyParser::parseShorthand(CSSPropertyID unresolvedProperty, bool important)
+{
+    CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty);
+
+    switch (property) {
+    case CSSPropertyWebkitMarginCollapse: {
+        CSSValueID id = m_range.consumeIncludingWhitespace().id();
+        if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyWebkitMarginBeforeCollapse, id, m_context.mode()))
+            return false;
+        CSSValue* beforeCollapse = CSSPrimitiveValue::createIdentifier(id);
+        addProperty(CSSPropertyWebkitMarginBeforeCollapse, CSSPropertyWebkitMarginCollapse, *beforeCollapse, important);
+        if (m_range.atEnd()) {
+            addProperty(CSSPropertyWebkitMarginAfterCollapse, CSSPropertyWebkitMarginCollapse, *beforeCollapse, important);
+            return true;
+        }
+        id = m_range.consumeIncludingWhitespace().id();
+        if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyWebkitMarginAfterCollapse, id, m_context.mode()))
+            return false;
+        addProperty(CSSPropertyWebkitMarginAfterCollapse, CSSPropertyWebkitMarginCollapse, *CSSPrimitiveValue::createIdentifier(id), important);
+        return true;
+    }
+    case CSSPropertyOverflow: {
+        CSSValueID id = m_range.consumeIncludingWhitespace().id();
+        if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyOverflowY, id, m_context.mode()))
+            return false;
+        if (!m_range.atEnd())
+            return false;
+        CSSValue* overflowYValue = CSSPrimitiveValue::createIdentifier(id);
+
+        CSSValue* overflowXValue = nullptr;
+
+        // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
+        // set using the shorthand, then for now overflow-x will default to auto, but once we implement
+        // pagination controls, it should default to hidden. If the overflow-y value is anything but
+        // paged-x or paged-y, then overflow-x and overflow-y should have the same value.
+        if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
+            overflowXValue = CSSPrimitiveValue::createIdentifier(CSSValueAuto);
+        else
+            overflowXValue = overflowYValue;
+        addProperty(CSSPropertyOverflowX, CSSPropertyOverflow, *overflowXValue, important);
+        addProperty(CSSPropertyOverflowY, CSSPropertyOverflow, *overflowYValue, important);
+        return true;
+    }
+    case CSSPropertyFont: {
+        const CSSParserToken&amp; token = m_range.peek();
+        if (token.id() &gt;= CSSValueCaption &amp;&amp; token.id() &lt;= CSSValueStatusBar)
+            return consumeSystemFont(important);
+        return consumeFont(important);
+    }
+    case CSSPropertyFontVariant:
+        return consumeFontVariantShorthand(important);
+    case CSSPropertyBorderSpacing:
+        return consumeBorderSpacing(important);
+    case CSSPropertyColumns:
+        return consumeColumns(important);
+    case CSSPropertyAnimation:
+        return consumeAnimationShorthand(animationShorthandForParsing(), unresolvedProperty == CSSPropertyAliasWebkitAnimation, important);
+    case CSSPropertyTransition:
+        return consumeAnimationShorthand(transitionShorthandForParsing(), false, important);
+    case CSSPropertyTextDecoration:
+        ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
+        return consumeShorthandGreedily(textDecorationShorthand(), important);
+    case CSSPropertyMargin:
+        return consume4Values(marginShorthand(), important);
+    case CSSPropertyPadding:
+        return consume4Values(paddingShorthand(), important);
+    case CSSPropertyMotion:
+        return consumeShorthandGreedily(motionShorthand(), important);
+    case CSSPropertyWebkitTextEmphasis:
+        return consumeShorthandGreedily(webkitTextEmphasisShorthand(), important);
+    case CSSPropertyOutline:
+        return consumeShorthandGreedily(outlineShorthand(), important);
+    case CSSPropertyWebkitBorderStart:
+        return consumeShorthandGreedily(webkitBorderStartShorthand(), important);
+    case CSSPropertyWebkitBorderEnd:
+        return consumeShorthandGreedily(webkitBorderEndShorthand(), important);
+    case CSSPropertyWebkitBorderBefore:
+        return consumeShorthandGreedily(webkitBorderBeforeShorthand(), important);
+    case CSSPropertyWebkitBorderAfter:
+        return consumeShorthandGreedily(webkitBorderAfterShorthand(), important);
+    case CSSPropertyWebkitTextStroke:
+        return consumeShorthandGreedily(webkitTextStrokeShorthand(), important);
+    case CSSPropertyMarker: {
+        const CSSValue* marker = parseSingleValue(CSSPropertyMarkerStart);
+        if (!marker || !m_range.atEnd())
+            return false;
+        addProperty(CSSPropertyMarkerStart, CSSPropertyMarker, *marker, important);
+        addProperty(CSSPropertyMarkerMid, CSSPropertyMarker, *marker, important);
+        addProperty(CSSPropertyMarkerEnd, CSSPropertyMarker, *marker, important);
+        return true;
+    }
+    case CSSPropertyFlex:
+        return consumeFlex(important);
+    case CSSPropertyFlexFlow:
+        return consumeShorthandGreedily(flexFlowShorthand(), important);
+    case CSSPropertyColumnRule:
+        return consumeShorthandGreedily(columnRuleShorthand(), important);
+    case CSSPropertyListStyle:
+        return consumeShorthandGreedily(listStyleShorthand(), important);
+    case CSSPropertyBorderRadius: {
+        CSSPrimitiveValue* horizontalRadii[4] = { 0 };
+        CSSPrimitiveValue* verticalRadii[4] = { 0 };
+        if (!consumeRadii(horizontalRadii, verticalRadii, m_range, m_context.mode(), unresolvedProperty == CSSPropertyAliasWebkitBorderRadius))
+            return false;
+        addProperty(CSSPropertyBorderTopLeftRadius, CSSPropertyBorderRadius, *CSSValuePair::create(horizontalRadii[0], verticalRadii[0], CSSValuePair::DropIdenticalValues), important);
+        addProperty(CSSPropertyBorderTopRightRadius, CSSPropertyBorderRadius, *CSSValuePair::create(horizontalRadii[1], verticalRadii[1], CSSValuePair::DropIdenticalValues), important);
+        addProperty(CSSPropertyBorderBottomRightRadius, CSSPropertyBorderRadius, *CSSValuePair::create(horizontalRadii[2], verticalRadii[2], CSSValuePair::DropIdenticalValues), important);
+        addProperty(CSSPropertyBorderBottomLeftRadius, CSSPropertyBorderRadius, *CSSValuePair::create(horizontalRadii[3], verticalRadii[3], CSSValuePair::DropIdenticalValues), important);
+        return true;
+    }
+    case CSSPropertyBorderColor:
+        return consume4Values(borderColorShorthand(), important);
+    case CSSPropertyBorderStyle:
+        return consume4Values(borderStyleShorthand(), important);
+    case CSSPropertyBorderWidth:
+        return consume4Values(borderWidthShorthand(), important);
+    case CSSPropertyBorderTop:
+        return consumeShorthandGreedily(borderTopShorthand(), important);
+    case CSSPropertyBorderRight:
+        return consumeShorthandGreedily(borderRightShorthand(), important);
+    case CSSPropertyBorderBottom:
+        return consumeShorthandGreedily(borderBottomShorthand(), important);
+    case CSSPropertyBorderLeft:
+        return consumeShorthandGreedily(borderLeftShorthand(), important);
+    case CSSPropertyBorder:
+        return consumeBorder(important);
+    case CSSPropertyBorderImage:
+    case CSSPropertyWebkitMaskBoxImage:
+        return consumeBorderImage(property, important);
+    case CSSPropertyPageBreakAfter:
+    case CSSPropertyPageBreakBefore:
+    case CSSPropertyPageBreakInside:
+    case CSSPropertyWebkitColumnBreakAfter:
+    case CSSPropertyWebkitColumnBreakBefore:
+    case CSSPropertyWebkitColumnBreakInside:
+        return consumeLegacyBreakProperty(property, important);
+    case CSSPropertyWebkitMaskPosition:
+    case CSSPropertyBackgroundPosition: {
+        CSSValue* resultX = nullptr;
+        CSSValue* resultY = nullptr;
+        if (!consumeBackgroundPosition(m_range, m_context, UnitlessQuirk::Allow, resultX, resultY) || !m_range.atEnd())
+            return false;
+        addProperty(property == CSSPropertyBackgroundPosition ? CSSPropertyBackgroundPositionX : CSSPropertyWebkitMaskPositionX, property, *resultX, important);
+        addProperty(property == CSSPropertyBackgroundPosition ? CSSPropertyBackgroundPositionY : CSSPropertyWebkitMaskPositionY, property, *resultY, important);
+        return true;
+    }
+    case CSSPropertyBackgroundRepeat:
+    case CSSPropertyWebkitMaskRepeat: {
+        CSSValue* resultX = nullptr;
+        CSSValue* resultY = nullptr;
+        bool implicit = false;
+        if (!consumeRepeatStyle(m_range, resultX, resultY, implicit) || !m_range.atEnd())
+            return false;
+        addProperty(property == CSSPropertyBackgroundRepeat ? CSSPropertyBackgroundRepeatX : CSSPropertyWebkitMaskRepeatX, property, *resultX, important, implicit);
+        addProperty(property == CSSPropertyBackgroundRepeat ? CSSPropertyBackgroundRepeatY : CSSPropertyWebkitMaskRepeatY, property, *resultY, important, implicit);
+        return true;
+    }
+    case CSSPropertyBackground:
+        return consumeBackgroundShorthand(backgroundShorthand(), important);
+    case CSSPropertyWebkitMask:
+        return consumeBackgroundShorthand(webkitMaskShorthand(), important);
+    case CSSPropertyGridGap: {
+        ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled() &amp;&amp; shorthandForProperty(CSSPropertyGridGap).length() == 2);
+        CSSValue* rowGap = consumeLength(m_range, m_context.mode(), ValueRangeNonNegative);
+        CSSValue* columnGap = consumeLength(m_range, m_context.mode(), ValueRangeNonNegative);
+        if (!rowGap || !m_range.atEnd())
+            return false;
+        if (!columnGap)
+            columnGap = rowGap;
+        addProperty(CSSPropertyGridRowGap, CSSPropertyGridGap, *rowGap, important);
+        addProperty(CSSPropertyGridColumnGap, CSSPropertyGridGap, *columnGap, important);
+        return true;
+    }
+    case CSSPropertyGridColumn:
+    case CSSPropertyGridRow:
+        return consumeGridItemPositionShorthand(property, important);
+    case CSSPropertyGridArea:
+        return consumeGridAreaShorthand(important);
+    case CSSPropertyGridTemplate:
+        return consumeGridTemplateShorthand(CSSPropertyGridTemplate, important);
+    case CSSPropertyGrid:
+        return consumeGridShorthand(important);
+    default:
+        return false;
+    }
+}
+*/
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSPropertyParserh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSPropertyParser.h (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSPropertyParser.h                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSPropertyParser.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,110 @@
</span><ins>+/*
+ * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Eric Seidel &lt;eric@webkit.org&gt;
+ * Copyright (C) 2009 - 2010  Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef CSSPropertyParser_h
+#define CSSPropertyParser_h
+
+#include &quot;CSSParserTokenRange.h&quot;
+#include &quot;StyleRule.h&quot;
+#include &lt;wtf/text/StringView.h&gt;
+
+namespace WebCore {
+
+class CSSProperty;
+class CSSValue;
+class StylePropertyShorthand;
+
+// Inputs: PropertyID, isImportant bool, CSSParserTokenRange.
+// Outputs: Vector of CSSProperties
+
+class CSSPropertyParser {
+    WTF_MAKE_NONCOPYABLE(CSSPropertyParser);
+public:
+    static bool parseValue(CSSPropertyID, bool important,
+        const CSSParserTokenRange&amp;, const CSSParserContext&amp;,
+        Vector&lt;CSSProperty, 256&gt;&amp;, StyleRule::Type);
+
+    // Parses a non-shorthand CSS property
+    static const CSSValue* parseSingleValue(CSSPropertyID, const CSSParserTokenRange&amp;, const CSSParserContext&amp;);
+
+private:
+    CSSPropertyParser(const CSSParserTokenRange&amp;, const CSSParserContext&amp;,
+        Vector&lt;CSSProperty, 256&gt;*);
+
+    // FIXME: Rename once the CSSParserValue-based parseValue is removed
+    bool parseValueStart(CSSPropertyID unresolvedProperty, bool important);
+    bool consumeCSSWideKeyword(CSSPropertyID unresolvedProperty, bool important);
+    const CSSValue* parseSingleValue(CSSPropertyID, CSSPropertyID = CSSPropertyInvalid);
+
+    bool inQuirksMode() const { return m_context.mode == CSSQuirksMode; }
+
+    bool parseViewportDescriptor(CSSPropertyID propId, bool important);
+    bool parseFontFaceDescriptor(CSSPropertyID);
+
+    void addProperty(CSSPropertyID, CSSPropertyID, const CSSValue&amp;, bool important, bool implicit = false);
+    void addExpandedPropertyForValue(CSSPropertyID propId, const CSSValue&amp;, bool);
+
+    bool consumeBorder(bool important);
+
+    bool parseShorthand(CSSPropertyID, bool important);
+    bool consumeShorthandGreedily(const StylePropertyShorthand&amp;, bool important);
+    bool consume4Values(const StylePropertyShorthand&amp;, bool important);
+
+    // Legacy parsing allows &lt;string&gt;s for animation-name
+    bool consumeAnimationShorthand(const StylePropertyShorthand&amp;, bool useLegacyParsing, bool important);
+    bool consumeBackgroundShorthand(const StylePropertyShorthand&amp;, bool important);
+
+    bool consumeColumns(bool important);
+
+    bool consumeGridItemPositionShorthand(CSSPropertyID, bool important);
+    bool consumeGridTemplateRowsAndAreasAndColumns(CSSPropertyID, bool important);
+    bool consumeGridTemplateShorthand(CSSPropertyID, bool important);
+    bool consumeGridShorthand(bool important);
+    bool consumeGridAreaShorthand(bool important);
+
+    bool consumeFont(bool important);
+    bool consumeFontVariantShorthand(bool important);
+    bool consumeSystemFont(bool important);
+
+    bool consumeBorderSpacing(bool important);
+
+    // CSS3 Parsing Routines (for properties specific to CSS3)
+    bool consumeBorderImage(CSSPropertyID, bool important);
+
+    bool consumeFlex(bool important);
+
+    bool consumeLegacyBreakProperty(CSSPropertyID, bool important);
+
+private:
+    // Inputs:
+    CSSParserTokenRange m_range;
+    const CSSParserContext&amp; m_context;
+    // Outputs:
+    Vector&lt;CSSProperty, 256&gt;* m_parsedProperties;
+};
+
+CSSPropertyID unresolvedCSSPropertyID(StringView);
+CSSValueID cssValueKeywordID(StringView);
+
+} // namespace WebCore
+
+#endif // CSSPropertyParser_h
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSPropertyParserHelperscpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,1111 @@
</span><ins>+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include &quot;config.h&quot;
+#include &quot;CSSPropertyParserHelpers.h&quot;
+
+#include &quot;CSSCalculationValue.h&quot;
+// FIXME-NEWPARSER: #include &quot;CSSColorValue.h&quot;
+#include &quot;CSSCrossfadeValue.h&quot;
+#include &quot;CSSGradientValue.h&quot;
+#include &quot;CSSImageSetValue.h&quot;
+#include &quot;CSSImageValue.h&quot;
+// FIXME-NEWPARSER: #include &quot;CSSPaintValue.h&quot;
+// FIXME_NEWPARSER: #include &quot;CSSStringValue.h&quot;
+// FIXME-NEWPARSER: #include &quot;CSSURIValue.h&quot;
+// FIXME_NEWPARSER: #include &quot;CSSValuePair.h&quot;
+
+namespace WebCore {
+
+/* FIXME-NEWPARSER: Disable for now.

+namespace CSSPropertyParserHelpers {
+
+bool consumeCommaIncludingWhitespace(CSSParserTokenRange&amp; range)
+{
+    CSSParserToken value = range.peek();
+    if (value.type() != CommaToken)
+        return false;
+    range.consumeIncludingWhitespace();
+    return true;
+}
+
+bool consumeSlashIncludingWhitespace(CSSParserTokenRange&amp; range)
+{
+    CSSParserToken value = range.peek();
+    if (value.type() != DelimiterToken || value.delimiter() != '/')
+        return false;
+    range.consumeIncludingWhitespace();
+    return true;
+}
+
+CSSParserTokenRange consumeFunction(CSSParserTokenRange&amp; range)
+{
+    ASSERT(range.peek().type() == FunctionToken);
+    CSSParserTokenRange contents = range.consumeBlock();
+    range.consumeWhitespace();
+    contents.consumeWhitespace();
+    return contents;
+}
+
+// FIXME: consider pulling in the parsing logic from CSSCalculationValue.cpp.
+class CalcParser {
+
+public:
+    explicit CalcParser(CSSParserTokenRange&amp; range, ValueRange valueRange = ValueRangeAll)
+        : m_sourceRange(range)
+        , m_range(range)
+    {
+        const CSSParserToken&amp; token = range.peek();
+        if (token.functionId() == CSSValueCalc || token.functionId() == CSSValueWebkitCalc)
+            m_calcValue = CSSCalcValue::create(consumeFunction(m_range), valueRange);
+    }
+
+    const CSSCalcValue* value() const { return m_calcValue.get(); }
+    CSSPrimitiveValue* consumeValue()
+    {
+        if (!m_calcValue)
+            return nullptr;
+        m_sourceRange = m_range;
+        return CSSPrimitiveValue::create(m_calcValue.release());
+    }
+    CSSPrimitiveValue* consumeNumber()
+    {
+        if (!m_calcValue)
+            return nullptr;
+        m_sourceRange = m_range;
+        CSSPrimitiveValue::UnitType unitType = m_calcValue-&gt;isInt() ? CSSPrimitiveValue::UnitType::Integer : CSSPrimitiveValue::UnitType::Number;
+        return CSSPrimitiveValue::create(m_calcValue-&gt;doubleValue(), unitType);
+    }
+
+    bool consumeNumberRaw(double&amp; result)
+    {
+        if (!m_calcValue || m_calcValue-&gt;category() != CalcNumber)
+            return false;
+        m_sourceRange = m_range;
+        result = m_calcValue-&gt;doubleValue();
+        return true;
+    }
+
+private:
+    CSSParserTokenRange&amp; m_sourceRange;
+    CSSParserTokenRange m_range;
+    Member&lt;CSSCalcValue&gt; m_calcValue;
+};
+
+CSSPrimitiveValue* consumeInteger(CSSParserTokenRange&amp; range, double minimumValue)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (token.type() == NumberToken) {
+        if (token.numericValueType() == NumberValueType || token.numericValue() &lt; minimumValue)
+            return nullptr;
+        return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitType::Integer);
+    }
+    CalcParser calcParser(range);
+    if (const CSSCalcValue* calculation = calcParser.value()) {
+        if (calculation-&gt;category() != CalcNumber || !calculation-&gt;isInt())
+            return nullptr;
+        double value = calculation-&gt;doubleValue();
+        if (value &lt; minimumValue)
+            return nullptr;
+        return calcParser.consumeNumber();
+    }
+    return nullptr;
+}
+
+CSSPrimitiveValue* consumePositiveInteger(CSSParserTokenRange&amp; range)
+{
+    return consumeInteger(range, 1);
+}
+
+bool consumeNumberRaw(CSSParserTokenRange&amp; range, double&amp; result)
+{
+    if (range.peek().type() == NumberToken) {
+        result = range.consumeIncludingWhitespace().numericValue();
+        return true;
+    }
+    CalcParser calcParser(range, ValueRangeAll);
+    return calcParser.consumeNumberRaw(result);
+}
+
+// FIXME: Work out if this can just call consumeNumberRaw
+CSSPrimitiveValue* consumeNumber(CSSParserTokenRange&amp; range, ValueRange valueRange)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (token.type() == NumberToken) {
+        if (valueRange == ValueRangeNonNegative &amp;&amp; token.numericValue() &lt; 0)
+            return nullptr;
+        return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), token.unitType());
+    }
+    CalcParser calcParser(range, ValueRangeAll);
+    if (const CSSCalcValue* calculation = calcParser.value()) {
+        // FIXME: Calcs should not be subject to parse time range checks.
+        // spec: https://drafts.csswg.org/css-values-3/#calc-range
+        if (calculation-&gt;category() != CalcNumber || (valueRange == ValueRangeNonNegative &amp;&amp; calculation-&gt;isNegative()))
+            return nullptr;
+        return calcParser.consumeNumber();
+    }
+    return nullptr;
+}
+
+inline bool shouldAcceptUnitlessLength(double value, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+    // FIXME: Presentational HTML attributes shouldn't use the CSS parser for lengths
+    return value == 0
+        || isUnitLessLengthParsingEnabledForMode(cssParserMode)
+        || (cssParserMode == HTMLQuirksMode &amp;&amp; unitless == UnitlessQuirk::Allow);
+}
+
+CSSPrimitiveValue* consumeLength(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, ValueRange valueRange, UnitlessQuirk unitless)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (token.type() == DimensionToken) {
+        switch (token.unitType()) {
+        case CSSPrimitiveValue::UnitType::QuirkyEms:
+            if (cssParserMode != UASheetMode)
+                return nullptr;
+            FALLTHROUGH;
+        case CSSPrimitiveValue::UnitType::Ems:
+        case CSSPrimitiveValue::UnitType::Rems:
+        case CSSPrimitiveValue::UnitType::Chs:
+        case CSSPrimitiveValue::UnitType::Exs:
+        case CSSPrimitiveValue::UnitType::Pixels:
+        case CSSPrimitiveValue::UnitType::Centimeters:
+        case CSSPrimitiveValue::UnitType::Millimeters:
+        case CSSPrimitiveValue::UnitType::Inches:
+        case CSSPrimitiveValue::UnitType::Points:
+        case CSSPrimitiveValue::UnitType::Picas:
+        case CSSPrimitiveValue::UnitType::UserUnits:
+        case CSSPrimitiveValue::UnitType::ViewportWidth:
+        case CSSPrimitiveValue::UnitType::ViewportHeight:
+        case CSSPrimitiveValue::UnitType::ViewportMin:
+        case CSSPrimitiveValue::UnitType::ViewportMax:
+            break;
+        default:
+            return nullptr;
+        }
+        if (valueRange == ValueRangeNonNegative &amp;&amp; token.numericValue() &lt; 0)
+            return nullptr;
+        return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), token.unitType());
+    }
+    if (token.type() == NumberToken) {
+        if (!shouldAcceptUnitlessLength(token.numericValue(), cssParserMode, unitless)
+            || (valueRange == ValueRangeNonNegative &amp;&amp; token.numericValue() &lt; 0))
+            return nullptr;
+        CSSPrimitiveValue::UnitType unitType = CSSPrimitiveValue::UnitType::Pixels;
+        if (cssParserMode == SVGAttributeMode)
+            unitType = CSSPrimitiveValue::UnitType::UserUnits;
+        return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), unitType);
+    }
+    if (cssParserMode == SVGAttributeMode)
+        return nullptr;
+    CalcParser calcParser(range, valueRange);
+    if (calcParser.value() &amp;&amp; calcParser.value()-&gt;category() == CalcLength)
+        return calcParser.consumeValue();
+    return nullptr;
+}
+
+CSSPrimitiveValue* consumePercent(CSSParserTokenRange&amp; range, ValueRange valueRange)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (token.type() == PercentageToken) {
+        if (valueRange == ValueRangeNonNegative &amp;&amp; token.numericValue() &lt; 0)
+            return nullptr;
+        return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitType::Percentage);
+    }
+    CalcParser calcParser(range, valueRange);
+    if (const CSSCalcValue* calculation = calcParser.value()) {
+        if (calculation-&gt;category() == CalcPercent)
+            return calcParser.consumeValue();
+    }
+    return nullptr;
+}
+
+bool canConsumeCalcValue(CalculationCategory category, CSSParserMode cssParserMode)
+{
+    if (category == CalcLength || category == CalcPercent || category == CalcPercentLength)
+        return true;
+
+    if (cssParserMode != SVGAttributeMode)
+        return false;
+
+    if (category == CalcNumber || category == CalcPercentNumber || category == CalcLengthNumber || category == CalcPercentLengthNumber)
+        return true;
+
+    return false;
+}
+
+CSSPrimitiveValue* consumeLengthOrPercent(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, ValueRange valueRange, UnitlessQuirk unitless)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (token.type() == DimensionToken || token.type() == NumberToken)
+        return consumeLength(range, cssParserMode, valueRange, unitless);
+    if (token.type() == PercentageToken)
+        return consumePercent(range, valueRange);
+    CalcParser calcParser(range, valueRange);
+    if (const CSSCalcValue* calculation = calcParser.value()) {
+        if (canConsumeCalcValue(calculation-&gt;category(), cssParserMode))
+            return calcParser.consumeValue();
+    }
+    return nullptr;
+}
+
+CSSPrimitiveValue* consumeAngle(CSSParserTokenRange&amp; range)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (token.type() == DimensionToken) {
+        switch (token.unitType()) {
+        case CSSPrimitiveValue::UnitType::Degrees:
+        case CSSPrimitiveValue::UnitType::Radians:
+        case CSSPrimitiveValue::UnitType::Gradians:
+        case CSSPrimitiveValue::UnitType::Turns:
+            return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), token.unitType());
+        default:
+            return nullptr;
+        }
+    }
+    if (token.type() == NumberToken &amp;&amp; token.numericValue() == 0) {
+        range.consumeIncludingWhitespace();
+        return CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitType::Degrees);
+    }
+    CalcParser calcParser(range, ValueRangeAll);
+    if (const CSSCalcValue* calculation = calcParser.value()) {
+        if (calculation-&gt;category() == CalcAngle)
+            return calcParser.consumeValue();
+    }
+    return nullptr;
+}
+
+CSSPrimitiveValue* consumeTime(CSSParserTokenRange&amp; range, ValueRange valueRange)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (token.type() == DimensionToken) {
+        if (valueRange == ValueRangeNonNegative &amp;&amp; token.numericValue() &lt; 0)
+            return nullptr;
+        CSSPrimitiveValue::UnitType unit = token.unitType();
+        if (unit == CSSPrimitiveValue::UnitType::Milliseconds || unit == CSSPrimitiveValue::UnitType::Seconds)
+            return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), token.unitType());
+        return nullptr;
+    }
+    CalcParser calcParser(range, valueRange);
+    if (const CSSCalcValue* calculation = calcParser.value()) {
+        if (calculation-&gt;category() == CalcTime)
+            return calcParser.consumeValue();
+    }
+    return nullptr;
+}
+
+CSSPrimitiveValue* consumeIdent(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().type() != IdentToken)
+        return nullptr;
+    return CSSPrimitiveValue::createIdentifier(range.consumeIncludingWhitespace().id());
+}
+
+CSSPrimitiveValue* consumeIdentRange(CSSParserTokenRange&amp; range, CSSValueID lower, CSSValueID upper)
+{
+    if (range.peek().id() &lt; lower || range.peek().id() &gt; upper)
+        return nullptr;
+    return consumeIdent(range);
+}
+
+CSSCustomIdentValue* consumeCustomIdent(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().type() != IdentToken || isCSSWideKeyword(range.peek().id()))
+        return nullptr;
+    return CSSCustomIdentValue::create(range.consumeIncludingWhitespace().value().toString());
+}
+
+CSSStringValue* consumeString(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().type() != StringToken)
+        return nullptr;
+    return CSSStringValue::create(range.consumeIncludingWhitespace().value().toString());
+}
+
+StringView consumeUrlAsStringView(CSSParserTokenRange&amp; range)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (token.type() == UrlToken) {
+        range.consumeIncludingWhitespace();
+        return token.value();
+    }
+    if (token.functionId() == CSSValueUrl) {
+        CSSParserTokenRange urlRange = range;
+        CSSParserTokenRange urlArgs = urlRange.consumeBlock();
+        const CSSParserToken&amp; next = urlArgs.consumeIncludingWhitespace();
+        if (next.type() == BadStringToken || !urlArgs.atEnd())
+            return StringView();
+        ASSERT(next.type() == StringToken);
+        range = urlRange;
+        range.consumeWhitespace();
+        return next.value();
+    }
+
+    return StringView();
+}
+
+CSSURIValue* consumeUrl(CSSParserTokenRange&amp; range)
+{
+    StringView url = consumeUrlAsStringView(range);
+    if (url.isNull())
+        return nullptr;
+    return CSSURIValue::create(url.toString());
+}
+
+static int clampRGBComponent(const CSSPrimitiveValue&amp; value)
+{
+    double result = value.getDoubleValue();
+    // FIXME: Multiply by 2.55 and round instead of floor.
+    if (value.isPercentage())
+        result *= 2.56;
+    return clampTo&lt;int&gt;(result, 0, 255);
+}
+
+static bool parseRGBParameters(CSSParserTokenRange&amp; range, RGBA32&amp; result, bool parseAlpha)
+{
+    ASSERT(range.peek().functionId() == CSSValueRgb || range.peek().functionId() == CSSValueRgba);
+    CSSParserTokenRange args = consumeFunction(range);
+    CSSPrimitiveValue* colorParameter = consumeInteger(args);
+    if (!colorParameter)
+        colorParameter = consumePercent(args, ValueRangeAll);
+    if (!colorParameter)
+        return false;
+    const bool isPercent = colorParameter-&gt;isPercentage();
+    int colorArray[3];
+    colorArray[0] = clampRGBComponent(*colorParameter);
+    for (int i = 1; i &lt; 3; i++) {
+        if (!consumeCommaIncludingWhitespace(args))
+            return false;
+        colorParameter = isPercent ? consumePercent(args, ValueRangeAll) : consumeInteger(args);
+        if (!colorParameter)
+            return false;
+        colorArray[i] = clampRGBComponent(*colorParameter);
+    }
+    if (parseAlpha) {
+        if (!consumeCommaIncludingWhitespace(args))
+            return false;
+        double alpha;
+        if (!consumeNumberRaw(args, alpha))
+            return false;
+        // Convert the floating pointer number of alpha to an integer in the range [0, 256),
+        // with an equal distribution across all 256 values.
+        int alphaComponent = static_cast&lt;int&gt;(clampTo&lt;double&gt;(alpha, 0.0, 1.0) * nextafter(256.0, 0.0));
+        result = makeRGBA(colorArray[0], colorArray[1], colorArray[2], alphaComponent);
+    } else {
+        result = makeRGB(colorArray[0], colorArray[1], colorArray[2]);
+    }
+    return args.atEnd();
+}
+
+static bool parseHSLParameters(CSSParserTokenRange&amp; range, RGBA32&amp; result, bool parseAlpha)
+{
+    ASSERT(range.peek().functionId() == CSSValueHsl || range.peek().functionId() == CSSValueHsla);
+    CSSParserTokenRange args = consumeFunction(range);
+    CSSPrimitiveValue* hslValue = consumeNumber(args, ValueRangeAll);
+    if (!hslValue)
+        return false;
+    double colorArray[3];
+    colorArray[0] = (((hslValue-&gt;getIntValue() % 360) + 360) % 360) / 360.0;
+    for (int i = 1; i &lt; 3; i++) {
+        if (!consumeCommaIncludingWhitespace(args))
+            return false;
+        hslValue = consumePercent(args, ValueRangeAll);
+        if (!hslValue)
+            return false;
+        double doubleValue = hslValue-&gt;getDoubleValue();
+        colorArray[i] = clampTo&lt;double&gt;(doubleValue, 0.0, 100.0) / 100.0; // Needs to be value between 0 and 1.0.
+    }
+    double alpha = 1.0;
+    if (parseAlpha) {
+        if (!consumeCommaIncludingWhitespace(args))
+            return false;
+        if (!consumeNumberRaw(args, alpha))
+            return false;
+        alpha = clampTo&lt;double&gt;(alpha, 0.0, 1.0);
+    }
+    result = makeRGBAFromHSLA(colorArray[0], colorArray[1], colorArray[2], alpha);
+    return args.atEnd();
+}
+
+static bool parseHexColor(CSSParserTokenRange&amp; range, RGBA32&amp; result, bool acceptQuirkyColors)
+{
+    const CSSParserToken&amp; token = range.peek();
+    if (token.type() == HashToken) {
+        if (!Color::parseHexColor(token.value(), result))
+            return false;
+    } else if (acceptQuirkyColors) {
+        String color;
+        if (token.type() == NumberToken || token.type() == DimensionToken) {
+            if (token.numericValueType() != IntegerValueType
+                || token.numericValue() &lt; 0. || token.numericValue() &gt;= 1000000.)
+                return false;
+            if (token.type() == NumberToken) // e.g. 112233
+                color = String::format(&quot;%d&quot;, static_cast&lt;int&gt;(token.numericValue()));
+            else // e.g. 0001FF
+                color = String::number(static_cast&lt;int&gt;(token.numericValue())) + token.value().toString();
+            while (color.length() &lt; 6)
+                color = &quot;0&quot; + color;
+        } else if (token.type() == IdentToken) { // e.g. FF0000
+            color = token.value().toString();
+        }
+        unsigned length = color.length();
+        if (length != 3 &amp;&amp; length != 6)
+            return false;
+        if (!Color::parseHexColor(color, result))
+            return false;
+    } else {
+        return false;
+    }
+    range.consumeIncludingWhitespace();
+    return true;
+}
+
+static bool parseColorFunction(CSSParserTokenRange&amp; range, RGBA32&amp; result)
+{
+    CSSValueID functionId = range.peek().functionId();
+    if (functionId &lt; CSSValueRgb || functionId &gt; CSSValueHsla)
+        return false;
+    CSSParserTokenRange colorRange = range;
+    if ((functionId &lt;= CSSValueRgba &amp;&amp; !parseRGBParameters(colorRange, result, functionId == CSSValueRgba))
+        || (functionId &gt;= CSSValueHsl &amp;&amp; !parseHSLParameters(colorRange, result, functionId == CSSValueHsla)))
+        return false;
+    range = colorRange;
+    return true;
+}
+
+CSSValue* consumeColor(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, bool acceptQuirkyColors)
+{
+    CSSValueID id = range.peek().id();
+    if (StyleColor::isColorKeyword(id)) {
+        if (!isValueAllowedInMode(id, cssParserMode))
+            return nullptr;
+        return consumeIdent(range);
+    }
+    RGBA32 color = Color::transparent;
+    if (!parseHexColor(range, color, acceptQuirkyColors) &amp;&amp; !parseColorFunction(range, color))
+        return nullptr;
+    return CSSColorValue::create(color);
+}
+
+static CSSPrimitiveValue* consumePositionComponent(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+    if (range.peek().type() == IdentToken)
+        return consumeIdent&lt;CSSValueLeft, CSSValueTop, CSSValueBottom, CSSValueRight, CSSValueCenter&gt;(range);
+    return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, unitless);
+}
+
+static bool isHorizontalPositionKeywordOnly(const CSSPrimitiveValue&amp; value)
+{
+    return value.isValueID() &amp;&amp; (value.getValueID() == CSSValueLeft || value.getValueID() == CSSValueRight);
+}
+
+static bool isVerticalPositionKeywordOnly(const CSSPrimitiveValue&amp; value)
+{
+    return value.isValueID() &amp;&amp; (value.getValueID() == CSSValueTop || value.getValueID() == CSSValueBottom);
+}
+
+static void positionFromOneValue(CSSPrimitiveValue* value, CSSValue*&amp; resultX, CSSValue*&amp; resultY)
+{
+    bool valueAppliesToYAxisOnly = isVerticalPositionKeywordOnly(*value);
+    resultX = value;
+    resultY = CSSPrimitiveValue::createIdentifier(CSSValueCenter);
+    if (valueAppliesToYAxisOnly)
+        std::swap(resultX, resultY);
+}
+
+static bool positionFromTwoValues(CSSPrimitiveValue* value1, CSSPrimitiveValue* value2,
+    CSSValue*&amp; resultX, CSSValue*&amp; resultY)
+{
+    bool mustOrderAsXY = isHorizontalPositionKeywordOnly(*value1) || isVerticalPositionKeywordOnly(*value2)
+        || !value1-&gt;isValueID() || !value2-&gt;isValueID();
+    bool mustOrderAsYX = isVerticalPositionKeywordOnly(*value1) || isHorizontalPositionKeywordOnly(*value2);
+    if (mustOrderAsXY &amp;&amp; mustOrderAsYX)
+        return false;
+    resultX = value1;
+    resultY = value2;
+    if (mustOrderAsYX)
+        std::swap(resultX, resultY);
+    return true;
+}
+
+static bool positionFromThreeOrFourValues(CSSPrimitiveValue** values, CSSValue*&amp; resultX, CSSValue*&amp; resultY)
+{
+    CSSPrimitiveValue* center = nullptr;
+    for (int i = 0; values[i]; i++) {
+        CSSPrimitiveValue* currentValue = values[i];
+        if (!currentValue-&gt;isValueID())
+            return false;
+        CSSValueID id = currentValue-&gt;getValueID();
+
+        if (id == CSSValueCenter) {
+            if (center)
+                return false;
+            center = currentValue;
+            continue;
+        }
+
+        CSSValue* result = nullptr;
+        if (values[i + 1] &amp;&amp; !values[i + 1]-&gt;isValueID()) {
+            result = CSSValuePair::create(currentValue, values[++i], CSSValuePair::KeepIdenticalValues);
+        } else {
+            result = currentValue;
+        }
+
+        if (id == CSSValueLeft || id == CSSValueRight) {
+            if (resultX)
+                return false;
+            resultX = result;
+        } else {
+            ASSERT(id == CSSValueTop || id == CSSValueBottom);
+            if (resultY)
+                return false;
+            resultY = result;
+        }
+    }
+
+    if (center) {
+        ASSERT(resultX || resultY);
+        if (resultX &amp;&amp; resultY)
+            return false;
+        if (!resultX)
+            resultX = center;
+        else
+            resultY = center;
+    }
+
+    ASSERT(resultX &amp;&amp; resultY);
+    return true;
+}
+
+// FIXME: This may consume from the range upon failure. The background
+// shorthand works around it, but we should just fix it here.
+bool consumePosition(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, UnitlessQuirk unitless, CSSValue*&amp; resultX, CSSValue*&amp; resultY)
+{
+    CSSPrimitiveValue* value1 = consumePositionComponent(range, cssParserMode, unitless);
+    if (!value1)
+        return false;
+
+    CSSPrimitiveValue* value2 = consumePositionComponent(range, cssParserMode, unitless);
+    if (!value2) {
+        positionFromOneValue(value1, resultX, resultY);
+        return true;
+    }
+
+    CSSPrimitiveValue* value3 = consumePositionComponent(range, cssParserMode, unitless);
+    if (!value3)
+        return positionFromTwoValues(value1, value2, resultX, resultY);
+
+    CSSPrimitiveValue* value4 = consumePositionComponent(range, cssParserMode, unitless);
+    CSSPrimitiveValue* values[5];
+    values[0] = value1;
+    values[1] = value2;
+    values[2] = value3;
+    values[3] = value4;
+    values[4] = nullptr;
+    return positionFromThreeOrFourValues(values, resultX, resultY);
+}
+
+CSSValuePair* consumePosition(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+    CSSValue* resultX = nullptr;
+    CSSValue* resultY = nullptr;
+    if (consumePosition(range, cssParserMode, unitless, resultX, resultY))
+        return CSSValuePair::create(resultX, resultY, CSSValuePair::KeepIdenticalValues);
+    return nullptr;
+}
+
+bool consumeOneOrTwoValuedPosition(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, UnitlessQuirk unitless, CSSValue*&amp; resultX, CSSValue*&amp; resultY)
+{
+    CSSPrimitiveValue* value1 = consumePositionComponent(range, cssParserMode, unitless);
+    if (!value1)
+        return false;
+    CSSPrimitiveValue* value2 = consumePositionComponent(range, cssParserMode, unitless);
+    if (!value2) {
+        positionFromOneValue(value1, resultX, resultY);
+        return true;
+    }
+    return positionFromTwoValues(value1, value2, resultX, resultY);
+}
+
+// This should go away once we drop support for -webkit-gradient
+static CSSPrimitiveValue* consumeDeprecatedGradientPoint(CSSParserTokenRange&amp; args, bool horizontal)
+{
+    if (args.peek().type() == IdentToken) {
+        if ((horizontal &amp;&amp; consumeIdent&lt;CSSValueLeft&gt;(args)) || (!horizontal &amp;&amp; consumeIdent&lt;CSSValueTop&gt;(args)))
+            return CSSPrimitiveValue::create(0., CSSPrimitiveValue::UnitType::Percentage);
+        if ((horizontal &amp;&amp; consumeIdent&lt;CSSValueRight&gt;(args)) || (!horizontal &amp;&amp; consumeIdent&lt;CSSValueBottom&gt;(args)))
+            return CSSPrimitiveValue::create(100., CSSPrimitiveValue::UnitType::Percentage);
+        if (consumeIdent&lt;CSSValueCenter&gt;(args))
+            return CSSPrimitiveValue::create(50., CSSPrimitiveValue::UnitType::Percentage);
+        return nullptr;
+    }
+    CSSPrimitiveValue* result = consumePercent(args, ValueRangeAll);
+    if (!result)
+        result = consumeNumber(args, ValueRangeAll);
+    return result;
+}
+
+// Used to parse colors for -webkit-gradient(...).
+static CSSValue* consumeDeprecatedGradientStopColor(CSSParserTokenRange&amp; args, CSSParserMode cssParserMode)
+{
+    if (args.peek().id() == CSSValueCurrentcolor)
+        return nullptr;
+    return consumeColor(args, cssParserMode);
+}
+
+static bool consumeDeprecatedGradientColorStop(CSSParserTokenRange&amp; range, CSSGradientColorStop&amp; stop, CSSParserMode cssParserMode)
+{
+    CSSValueID id = range.peek().functionId();
+    if (id != CSSValueFrom &amp;&amp; id != CSSValueTo &amp;&amp; id != CSSValueColorStop)
+        return false;
+
+    CSSParserTokenRange args = consumeFunction(range);
+    double position;
+    if (id == CSSValueFrom || id == CSSValueTo) {
+        position = (id == CSSValueFrom) ? 0 : 1;
+    } else {
+        DCHECK(id == CSSValueColorStop);
+        const CSSParserToken&amp; arg = args.consumeIncludingWhitespace();
+        if (arg.type() == PercentageToken)
+            position = arg.numericValue() / 100.0;
+        else if (arg.type() == NumberToken)
+            position = arg.numericValue();
+        else
+            return false;
+
+        if (!consumeCommaIncludingWhitespace(args))
+            return false;
+    }
+
+    stop.m_position = CSSPrimitiveValue::create(position, CSSPrimitiveValue::UnitType::Number);
+    stop.m_color = consumeDeprecatedGradientStopColor(args, cssParserMode);
+    return stop.m_color &amp;&amp; args.atEnd();
+}
+
+static CSSValue* consumeDeprecatedGradient(CSSParserTokenRange&amp; args, CSSParserMode cssParserMode)
+{
+    CSSGradientValue* result = nullptr;
+    CSSValueID id = args.consumeIncludingWhitespace().id();
+    bool isDeprecatedRadialGradient = (id == CSSValueRadial);
+    if (isDeprecatedRadialGradient)
+        result = CSSRadialGradientValue::create(NonRepeating, CSSDeprecatedRadialGradient);
+    else if (id == CSSValueLinear)
+        result = CSSLinearGradientValue::create(NonRepeating, CSSDeprecatedLinearGradient);
+    if (!result || !consumeCommaIncludingWhitespace(args))
+        return nullptr;
+
+    CSSPrimitiveValue* point = consumeDeprecatedGradientPoint(args, true);
+    if (!point)
+        return nullptr;
+    result-&gt;setFirstX(point);
+    point = consumeDeprecatedGradientPoint(args, false);
+    if (!point)
+        return nullptr;
+    result-&gt;setFirstY(point);
+
+    if (!consumeCommaIncludingWhitespace(args))
+        return nullptr;
+
+    // For radial gradients only, we now expect a numeric radius.
+    if (isDeprecatedRadialGradient) {
+        CSSPrimitiveValue* radius = consumeNumber(args, ValueRangeAll);
+        if (!radius || !consumeCommaIncludingWhitespace(args))
+            return nullptr;
+        toCSSRadialGradientValue(result)-&gt;setFirstRadius(radius);
+    }
+
+    point = consumeDeprecatedGradientPoint(args, true);
+    if (!point)
+        return nullptr;
+    result-&gt;setSecondX(point);
+    point = consumeDeprecatedGradientPoint(args, false);
+    if (!point)
+        return nullptr;
+    result-&gt;setSecondY(point);
+
+    // For radial gradients only, we now expect the second radius.
+    if (isDeprecatedRadialGradient) {
+        if (!consumeCommaIncludingWhitespace(args))
+            return nullptr;
+        CSSPrimitiveValue* radius = consumeNumber(args, ValueRangeAll);
+        if (!radius)
+            return nullptr;
+        toCSSRadialGradientValue(result)-&gt;setSecondRadius(radius);
+    }
+
+    CSSGradientColorStop stop;
+    while (consumeCommaIncludingWhitespace(args)) {
+        if (!consumeDeprecatedGradientColorStop(args, stop, cssParserMode))
+            return nullptr;
+        result-&gt;addStop(stop);
+    }
+
+    return result;
+}
+
+static bool consumeGradientColorStops(CSSParserTokenRange&amp; range, CSSParserMode cssParserMode, CSSGradientValue* gradient)
+{
+    bool supportsColorHints = gradient-&gt;gradientType() == CSSLinearGradient || gradient-&gt;gradientType() == CSSRadialGradient;
+
+    // The first color stop cannot be a color hint.
+    bool previousStopWasColorHint = true;
+    do {
+        CSSGradientColorStop stop;
+        stop.m_color = consumeColor(range, cssParserMode);
+        // Two hints in a row are not allowed.
+        if (!stop.m_color &amp;&amp; (!supportsColorHints || previousStopWasColorHint))
+            return false;
+        previousStopWasColorHint = !stop.m_color;
+        stop.m_position = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
+        if (!stop.m_color &amp;&amp; !stop.m_position)
+            return false;
+        gradient-&gt;addStop(stop);
+    } while (consumeCommaIncludingWhitespace(range));
+
+    // The last color stop cannot be a color hint.
+    if (previousStopWasColorHint)
+        return false;
+
+    // Must have 2 or more stops to be valid.
+    return gradient-&gt;stopCount() &gt;= 2;
+}
+
+static CSSValue* consumeDeprecatedRadialGradient(CSSParserTokenRange&amp; args, CSSParserMode cssParserMode, CSSGradientRepeat repeating)
+{
+    CSSRadialGradientValue* result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient);
+    CSSValue* centerX = nullptr;
+    CSSValue* centerY = nullptr;
+    consumeOneOrTwoValuedPosition(args, cssParserMode, UnitlessQuirk::Forbid, centerX, centerY);
+    if ((centerX || centerY) &amp;&amp; !consumeCommaIncludingWhitespace(args))
+        return nullptr;
+
+    result-&gt;setFirstX(toCSSPrimitiveValue(centerX));
+    result-&gt;setSecondX(toCSSPrimitiveValue(centerX));
+    result-&gt;setFirstY(toCSSPrimitiveValue(centerY));
+    result-&gt;setSecondY(toCSSPrimitiveValue(centerY));
+
+    CSSPrimitiveValue* shape = consumeIdent&lt;CSSValueCircle, CSSValueEllipse&gt;(args);
+    CSSPrimitiveValue* sizeKeyword = consumeIdent&lt;CSSValueClosestSide, CSSValueClosestCorner, CSSValueFarthestSide, CSSValueFarthestCorner, CSSValueContain, CSSValueCover&gt;(args);
+    if (!shape)
+        shape = consumeIdent&lt;CSSValueCircle, CSSValueEllipse&gt;(args);
+    result-&gt;setShape(shape);
+    result-&gt;setSizingBehavior(sizeKeyword);
+
+    // Or, two lengths or percentages
+    if (!shape &amp;&amp; !sizeKeyword) {
+        CSSPrimitiveValue* horizontalSize = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+        CSSPrimitiveValue* verticalSize = nullptr;
+        if (horizontalSize) {
+            verticalSize = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+            if (!verticalSize)
+                return nullptr;
+            consumeCommaIncludingWhitespace(args);
+            result-&gt;setEndHorizontalSize(horizontalSize);
+            result-&gt;setEndVerticalSize(verticalSize);
+        }
+    } else {
+        consumeCommaIncludingWhitespace(args);
+    }
+    if (!consumeGradientColorStops(args, cssParserMode, result))
+        return nullptr;
+
+    return result;
+}
+
+static CSSValue* consumeRadialGradient(CSSParserTokenRange&amp; args, CSSParserMode cssParserMode, CSSGradientRepeat repeating)
+{
+    CSSRadialGradientValue* result = CSSRadialGradientValue::create(repeating, CSSRadialGradient);
+
+    CSSPrimitiveValue* shape = nullptr;
+    CSSPrimitiveValue* sizeKeyword = nullptr;
+    CSSPrimitiveValue* horizontalSize = nullptr;
+    CSSPrimitiveValue* verticalSize = nullptr;
+
+    // First part of grammar, the size/shape clause:
+    // [ circle || &lt;length&gt; ] |
+    // [ ellipse || [ &lt;length&gt; | &lt;percentage&gt; ]{2} ] |
+    // [ [ circle | ellipse] || &lt;size-keyword&gt; ]
+    for (int i = 0; i &lt; 3; ++i) {
+        if (args.peek().type() == IdentToken) {
+            CSSValueID id = args.peek().id();
+            if (id == CSSValueCircle || id == CSSValueEllipse) {
+                if (shape)
+                    return nullptr;
+                shape = consumeIdent(args);
+            } else if (id == CSSValueClosestSide || id == CSSValueClosestCorner || id == CSSValueFarthestSide || id == CSSValueFarthestCorner) {
+                if (sizeKeyword)
+                    return nullptr;
+                sizeKeyword = consumeIdent(args);
+            } else {
+                break;
+            }
+        } else {
+            CSSPrimitiveValue* center = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+            if (!center)
+                break;
+            if (horizontalSize)
+                return nullptr;
+            horizontalSize = center;
+            center = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+            if (center) {
+                verticalSize = center;
+                ++i;
+            }
+        }
+    }
+
+    // You can specify size as a keyword or a length/percentage, not both.
+    if (sizeKeyword &amp;&amp; horizontalSize)
+        return nullptr;
+    // Circles must have 0 or 1 lengths.
+    if (shape &amp;&amp; shape-&gt;getValueID() == CSSValueCircle &amp;&amp; verticalSize)
+        return nullptr;
+    // Ellipses must have 0 or 2 length/percentages.
+    if (shape &amp;&amp; shape-&gt;getValueID() == CSSValueEllipse &amp;&amp; horizontalSize &amp;&amp; !verticalSize)
+        return nullptr;
+    // If there's only one size, it must be a length.
+    if (!verticalSize &amp;&amp; horizontalSize &amp;&amp; horizontalSize-&gt;isPercentage())
+        return nullptr;
+    if ((horizontalSize &amp;&amp; horizontalSize-&gt;isCalculatedPercentageWithLength())
+        || (verticalSize &amp;&amp; verticalSize-&gt;isCalculatedPercentageWithLength()))
+        return nullptr;
+
+    result-&gt;setShape(shape);
+    result-&gt;setSizingBehavior(sizeKeyword);
+    result-&gt;setEndHorizontalSize(horizontalSize);
+    result-&gt;setEndVerticalSize(verticalSize);
+
+    CSSValue* centerX = nullptr;
+    CSSValue* centerY = nullptr;
+    if (args.peek().id() == CSSValueAt) {
+        args.consumeIncludingWhitespace();
+        consumePosition(args, cssParserMode, UnitlessQuirk::Forbid, centerX, centerY);
+        if (!(centerX &amp;&amp; centerY))
+            return nullptr;
+        result-&gt;setFirstX(centerX);
+        result-&gt;setFirstY(centerY);
+        // Right now, CSS radial gradients have the same start and end centers.
+        result-&gt;setSecondX(centerX);
+        result-&gt;setSecondY(centerY);
+    }
+
+    if ((shape || sizeKeyword || horizontalSize || centerX || centerY) &amp;&amp; !consumeCommaIncludingWhitespace(args))
+        return nullptr;
+    if (!consumeGradientColorStops(args, cssParserMode, result))
+        return nullptr;
+    return result;
+}
+
+static CSSValue* consumeLinearGradient(CSSParserTokenRange&amp; args, CSSParserMode cssParserMode, CSSGradientRepeat repeating, CSSGradientType gradientType)
+{
+    CSSLinearGradientValue* result = CSSLinearGradientValue::create(repeating, gradientType);
+
+    bool expectComma = true;
+    CSSPrimitiveValue* angle = consumeAngle(args);
+    if (angle) {
+        result-&gt;setAngle(angle);
+    } else if (gradientType == CSSPrefixedLinearGradient || consumeIdent&lt;CSSValueTo&gt;(args)) {
+        CSSPrimitiveValue* endX = consumeIdent&lt;CSSValueLeft, CSSValueRight&gt;(args);
+        CSSPrimitiveValue* endY = consumeIdent&lt;CSSValueBottom, CSSValueTop&gt;(args);
+        if (!endX &amp;&amp; !endY) {
+            if (gradientType == CSSLinearGradient)
+                return nullptr;
+            endY = CSSPrimitiveValue::createIdentifier(CSSValueTop);
+            expectComma = false;
+        } else if (!endX) {
+            endX = consumeIdent&lt;CSSValueLeft, CSSValueRight&gt;(args);
+        }
+
+        result-&gt;setFirstX(endX);
+        result-&gt;setFirstY(endY);
+    } else {
+        expectComma = false;
+    }
+
+    if (expectComma &amp;&amp; !consumeCommaIncludingWhitespace(args))
+        return nullptr;
+    if (!consumeGradientColorStops(args, cssParserMode, result))
+        return nullptr;
+    return result;
+}
+
+CSSValue* consumeImageOrNone(CSSParserTokenRange&amp; range, CSSParserContext context)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+    return consumeImage(range, context);
+}
+
+static CSSValue* consumeCrossFade(CSSParserTokenRange&amp; args, CSSParserContext context)
+{
+    CSSValue* fromImageValue = consumeImageOrNone(args, context);
+    if (!fromImageValue || !consumeCommaIncludingWhitespace(args))
+        return nullptr;
+    CSSValue* toImageValue = consumeImageOrNone(args, context);
+    if (!toImageValue || !consumeCommaIncludingWhitespace(args))
+        return nullptr;
+
+    CSSPrimitiveValue* percentage = nullptr;
+    const CSSParserToken&amp; percentageArg = args.consumeIncludingWhitespace();
+    if (percentageArg.type() == PercentageToken)
+        percentage = CSSPrimitiveValue::create(clampTo&lt;double&gt;(percentageArg.numericValue() / 100, 0, 1), CSSPrimitiveValue::UnitType::Number);
+    else if (percentageArg.type() == NumberToken)
+        percentage = CSSPrimitiveValue::create(clampTo&lt;double&gt;(percentageArg.numericValue(), 0, 1), CSSPrimitiveValue::UnitType::Number);
+
+    if (!percentage)
+        return nullptr;
+    return CSSCrossfadeValue::create(fromImageValue, toImageValue, percentage);
+}
+
+static CSSValue* consumePaint(CSSParserTokenRange&amp; args, CSSParserContext context)
+{
+    DCHECK(RuntimeEnabledFeatures::cssPaintAPIEnabled());
+
+    CSSCustomIdentValue* name = consumeCustomIdent(args);
+    if (!name)
+        return nullptr;
+
+    return CSSPaintValue::create(name);
+}
+
+static CSSValue* consumeGeneratedImage(CSSParserTokenRange&amp; range, CSSParserContext context)
+{
+    CSSValueID id = range.peek().functionId();
+    CSSParserTokenRange rangeCopy = range;
+    CSSParserTokenRange args = consumeFunction(rangeCopy);
+    CSSValue* result = nullptr;
+    if (id == CSSValueRadialGradient) {
+        result = consumeRadialGradient(args, context.mode(), NonRepeating);
+    } else if (id == CSSValueRepeatingRadialGradient) {
+        result = consumeRadialGradient(args, context.mode(), Repeating);
+    } else if (id == CSSValueWebkitLinearGradient) {
+        // FIXME: This should send a deprecation message.
+        if (context.useCounter())
+            context.useCounter()-&gt;count(UseCounter::DeprecatedWebKitLinearGradient);
+        result = consumeLinearGradient(args, context.mode(), NonRepeating, CSSPrefixedLinearGradient);
+    } else if (id == CSSValueWebkitRepeatingLinearGradient) {
+        // FIXME: This should send a deprecation message.
+        if (context.useCounter())
+            context.useCounter()-&gt;count(UseCounter::DeprecatedWebKitRepeatingLinearGradient);
+        result = consumeLinearGradient(args, context.mode(), Repeating, CSSPrefixedLinearGradient);
+    } else if (id == CSSValueRepeatingLinearGradient) {
+        result = consumeLinearGradient(args, context.mode(), Repeating, CSSLinearGradient);
+    } else if (id == CSSValueLinearGradient) {
+        result = consumeLinearGradient(args, context.mode(), NonRepeating, CSSLinearGradient);
+    } else if (id == CSSValueWebkitGradient) {
+        // FIXME: This should send a deprecation message.
+        if (context.useCounter())
+            context.useCounter()-&gt;count(UseCounter::DeprecatedWebKitGradient);
+        result = consumeDeprecatedGradient(args, context.mode());
+    } else if (id == CSSValueWebkitRadialGradient) {
+        // FIXME: This should send a deprecation message.
+        if (context.useCounter())
+            context.useCounter()-&gt;count(UseCounter::DeprecatedWebKitRadialGradient);
+        result = consumeDeprecatedRadialGradient(args, context.mode(), NonRepeating);
+    } else if (id == CSSValueWebkitRepeatingRadialGradient) {
+        if (context.useCounter())
+            context.useCounter()-&gt;count(UseCounter::DeprecatedWebKitRepeatingRadialGradient);
+        result = consumeDeprecatedRadialGradient(args, context.mode(), Repeating);
+    } else if (id == CSSValueWebkitCrossFade) {
+        result = consumeCrossFade(args, context);
+    } else if (id == CSSValuePaint) {
+        result = RuntimeEnabledFeatures::cssPaintAPIEnabled() ? consumePaint(args, context) : nullptr;
+    }
+    if (!result || !args.atEnd())
+        return nullptr;
+    range = rangeCopy;
+    return result;
+}
+
+static CSSValue* createCSSImageValueWithReferrer(const AtomicString&amp; rawValue, const CSSParserContext&amp; context)
+{
+    CSSValue* imageValue = CSSImageValue::create(rawValue, context.completeURL(rawValue));
+    toCSSImageValue(imageValue)-&gt;setReferrer(context.referrer());
+    return imageValue;
+}
+
+static CSSValue* consumeImageSet(CSSParserTokenRange&amp; range, const CSSParserContext&amp; context)
+{
+    CSSParserTokenRange rangeCopy = range;
+    CSSParserTokenRange args = consumeFunction(rangeCopy);
+    CSSImageSetValue* imageSet = CSSImageSetValue::create();
+    do {
+        AtomicString urlValue = consumeUrlAsStringView(args).toAtomicString();
+        if (urlValue.isNull())
+            return nullptr;
+
+        CSSValue* image = createCSSImageValueWithReferrer(urlValue, context);
+        imageSet-&gt;append(*image);
+
+        const CSSParserToken&amp; token = args.consumeIncludingWhitespace();
+        if (token.type() != DimensionToken)
+            return nullptr;
+        if (token.value() != &quot;x&quot;)
+            return nullptr;
+        DCHECK(token.unitType() == CSSPrimitiveValue::UnitType::Unknown);
+        double imageScaleFactor = token.numericValue();
+        if (imageScaleFactor &lt;= 0)
+            return nullptr;
+        imageSet-&gt;append(*CSSPrimitiveValue::create(imageScaleFactor, CSSPrimitiveValue::UnitType::Number));
+    } while (consumeCommaIncludingWhitespace(args));
+    if (!args.atEnd())
+        return nullptr;
+    range = rangeCopy;
+    return imageSet;
+}
+
+static bool isGeneratedImage(CSSValueID id)
+{
+    return id == CSSValueLinearGradient || id == CSSValueRadialGradient
+        || id == CSSValueRepeatingLinearGradient || id == CSSValueRepeatingRadialGradient
+        || id == CSSValueWebkitLinearGradient || id == CSSValueWebkitRadialGradient
+        || id == CSSValueWebkitRepeatingLinearGradient || id == CSSValueWebkitRepeatingRadialGradient
+        || id == CSSValueWebkitGradient || id == CSSValueWebkitCrossFade || id == CSSValuePaint;
+}
+
+CSSValue* consumeImage(CSSParserTokenRange&amp; range, CSSParserContext context, ConsumeGeneratedImage generatedImage)
+{
+    AtomicString uri = consumeUrlAsStringView(range).toAtomicString();
+    if (!uri.isNull())
+        return createCSSImageValueWithReferrer(uri, context);
+    if (range.peek().type() == FunctionToken) {
+        CSSValueID id = range.peek().functionId();
+        if (id == CSSValueWebkitImageSet)
+            return consumeImageSet(range, context);
+        if (generatedImage == ConsumeGeneratedImage::Allow &amp;&amp; isGeneratedImage(id))
+            return consumeGeneratedImage(range, context);
+    }
+    return nullptr;
+}
+
+} // namespace CSSPropertyParserHelpers
+*/
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSPropertyParserHelpersh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.h (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.h                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,122 @@
</span><ins>+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#ifndef CSSPropertyParserHelpers_h
+#define CSSPropertyParserHelpers_h
+
+// FIXME-NEWPARSER #include &quot;CSSCustomIdentValue.h&quot;
+#include &quot;CSSParserMode.h&quot;
+#include &quot;CSSParserTokenRange.h&quot;
+#include &quot;CSSPrimitiveValue.h&quot;
+#include &quot;Length.h&quot; // For ValueRange
+
+namespace WebCore {
+
+class CSSStringValue;
+class CSSURIValue;
+class CSSValuePair;
+
+// When these functions are successful, they will consume all the relevant
+// tokens from the range and also consume any whitespace which follows. When
+// the start of the range doesn't match the type we're looking for, the range
+// will not be modified.
+namespace CSSPropertyParserHelpers {
+
+// FIXME: These should probably just be consumeComma and consumeSlash.
+bool consumeCommaIncludingWhitespace(CSSParserTokenRange&amp;);
+bool consumeSlashIncludingWhitespace(CSSParserTokenRange&amp;);
+// consumeFunction expects the range starts with a FunctionToken.
+CSSParserTokenRange consumeFunction(CSSParserTokenRange&amp;);
+
+enum class UnitlessQuirk {
+    Allow,
+    Forbid
+};
+
+CSSPrimitiveValue* consumeInteger(CSSParserTokenRange&amp;, double minimumValue = -std::numeric_limits&lt;double&gt;::max());
+CSSPrimitiveValue* consumePositiveInteger(CSSParserTokenRange&amp;);
+bool consumeNumberRaw(CSSParserTokenRange&amp;, double&amp; result);
+CSSPrimitiveValue* consumeNumber(CSSParserTokenRange&amp;, ValueRange);
+CSSPrimitiveValue* consumeLength(CSSParserTokenRange&amp;, CSSParserMode, ValueRange, UnitlessQuirk = UnitlessQuirk::Forbid);
+CSSPrimitiveValue* consumePercent(CSSParserTokenRange&amp;, ValueRange);
+CSSPrimitiveValue* consumeLengthOrPercent(CSSParserTokenRange&amp;, CSSParserMode, ValueRange, UnitlessQuirk = UnitlessQuirk::Forbid);
+CSSPrimitiveValue* consumeAngle(CSSParserTokenRange&amp;);
+CSSPrimitiveValue* consumeTime(CSSParserTokenRange&amp;, ValueRange);
+
+CSSPrimitiveValue* consumeIdent(CSSParserTokenRange&amp;);
+CSSPrimitiveValue* consumeIdentRange(CSSParserTokenRange&amp;, CSSValueID lower, CSSValueID upper);
+template&lt;CSSValueID, CSSValueID...&gt; inline bool identMatches(CSSValueID id);
+template&lt;CSSValueID... allowedIdents&gt; CSSPrimitiveValue* consumeIdent(CSSParserTokenRange&amp;);
+
+// FIXME-NEWPARSER CSSCustomIdentValue* consumeCustomIdent(CSSParserTokenRange&amp;);
+CSSStringValue* consumeString(CSSParserTokenRange&amp;);
+StringView consumeUrlAsStringView(CSSParserTokenRange&amp;);
+CSSURIValue* consumeUrl(CSSParserTokenRange&amp;);
+
+CSSValue* consumeColor(CSSParserTokenRange&amp;, CSSParserMode, bool acceptQuirkyColors = false);
+
+CSSValuePair* consumePosition(CSSParserTokenRange&amp;, CSSParserMode, UnitlessQuirk);
+bool consumePosition(CSSParserTokenRange&amp;, CSSParserMode, UnitlessQuirk, CSSValue*&amp; resultX, CSSValue*&amp; resultY);
+bool consumeOneOrTwoValuedPosition(CSSParserTokenRange&amp;, CSSParserMode, UnitlessQuirk, CSSValue*&amp; resultX, CSSValue*&amp; resultY);
+
+enum class ConsumeGeneratedImage {
+    Allow,
+    Forbid
+};
+
+CSSValue* consumeImage(CSSParserTokenRange&amp;, CSSParserContext, ConsumeGeneratedImage = ConsumeGeneratedImage::Allow);
+CSSValue* consumeImageOrNone(CSSParserTokenRange&amp;, CSSParserContext);
+
+// Template implementations are at the bottom of the file for readability.
+
+template&lt;typename... emptyBaseCase&gt; inline bool identMatches(CSSValueID) { return false; }
+template&lt;CSSValueID head, CSSValueID... tail&gt; inline bool identMatches(CSSValueID id)
+{
+    return id == head || identMatches&lt;tail...&gt;(id);
+}
+
+// FIXME-NEWPARSER - converted to a RefPtr return type from a raw ptr.
+template&lt;CSSValueID... names&gt; RefPtr&lt;CSSPrimitiveValue&gt; consumeIdent(CSSParserTokenRange&amp; range)
+{
+    if (range.peek().type() != IdentToken || !identMatches&lt;names...&gt;(range.peek().id()))
+        return nullptr;
+    return CSSPrimitiveValue::createIdentifier(range.consumeIncludingWhitespace().id());
+}
+
+static inline bool isCSSWideKeyword(const CSSValueID&amp; id)
+{
+    return id == CSSValueInitial || id == CSSValueInherit || id == CSSValueUnset || id == CSSValueDefault;
+}
+
+} // namespace CSSPropertyParserHelpers
+
+} // namespace WebCore
+
+#endif // CSSPropertyParserHelpers_h
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSTokenizercpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSTokenizer.cpp (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSTokenizer.cpp                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSTokenizer.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,889 @@
</span><ins>+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include &quot;config.h&quot;
+#include &quot;CSSTokenizer.h&quot;
+
+#include &quot;CSSParserIdioms.h&quot;
+#include &quot;CSSParserObserverWrapper.h&quot;
+#include &quot;CSSParserTokenRange.h&quot;
+#include &quot;CSSTokenizerInputStream.h&quot;
+#include &quot;HTMLParserIdioms.h&quot;
+#include &lt;wtf/unicode/CharacterNames.h&gt;
+
+namespace WebCore {
+
+CSSTokenizer::Scope::Scope(const String&amp; string)
+    : m_string(string)
+{
+    // According to the spec, we should perform preprocessing here.
+    // See: http://dev.w3.org/csswg/css-syntax/#input-preprocessing
+    //
+    // However, we can skip this step since:
+    // * We're using HTML spaces (which accept \r and \f as a valid white space)
+    // * Do not count white spaces
+    // * CSSTokenizerInputStream::nextInputChar() replaces NULLs for replacement characters
+
+    if (string.isEmpty())
+        return;
+
+    // To avoid resizing we err on the side of reserving too much space.
+    // Most strings we tokenize have about 3.5 to 5 characters per token.
+    m_tokens.reserveInitialCapacity(string.length() / 3);
+
+    CSSTokenizerInputStream input(string);
+    CSSTokenizer tokenizer(input, *this);
+    while (true) {
+        CSSParserToken token = tokenizer.nextToken();
+        if (token.type() == CommentToken)
+            continue;
+        if (token.type() == EOFToken)
+            return;
+        m_tokens.append(token);
+    }
+}
+
+CSSTokenizer::Scope::Scope(const String&amp; string, CSSParserObserverWrapper&amp; wrapper)
+    : m_string(string)
+{
+    if (string.isEmpty())
+        return;
+
+    CSSTokenizerInputStream input(string);
+    CSSTokenizer tokenizer(input, *this);
+
+    unsigned offset = 0;
+    while (true) {
+        CSSParserToken token = tokenizer.nextToken();
+        if (token.type() == EOFToken)
+            break;
+        if (token.type() == CommentToken)
+            wrapper.addComment(offset, input.offset(), m_tokens.size());
+        else {
+            m_tokens.append(token);
+            wrapper.addToken(offset);
+        }
+        offset = input.offset();
+    }
+
+    wrapper.addToken(offset);
+    wrapper.finalizeConstruction(m_tokens.begin());
+}
+
+CSSParserTokenRange CSSTokenizer::Scope::tokenRange()
+{
+    return m_tokens;
+}
+
+unsigned CSSTokenizer::Scope::tokenCount()
+{
+    return m_tokens.size();
+}
+
+static bool isNewLine(UChar cc)
+{
+    // We check \r and \f here, since we have no preprocessing stage
+    return (cc == '\r' || cc == '\n' || cc == '\f');
+}
+
+// http://dev.w3.org/csswg/css-syntax/#check-if-two-code-points-are-a-valid-escape
+static bool twoCharsAreValidEscape(UChar first, UChar second)
+{
+    return first == '\\' &amp;&amp; !isNewLine(second);
+}
+
+CSSTokenizer::CSSTokenizer(CSSTokenizerInputStream&amp; inputStream, Scope&amp; scope)
+    : m_input(inputStream)
+    , m_scope(scope)
+{
+}
+
+void CSSTokenizer::reconsume(UChar c)
+{
+    m_input.pushBack(c);
+}
+
+UChar CSSTokenizer::consume()
+{
+    UChar current = m_input.nextInputChar();
+    m_input.advance();
+    return current;
+}
+
+CSSParserToken CSSTokenizer::whiteSpace(UChar /*cc*/)
+{
+    m_input.advanceUntilNonWhitespace();
+    return CSSParserToken(WhitespaceToken);
+}
+
+CSSParserToken CSSTokenizer::blockStart(CSSParserTokenType type)
+{
+    m_blockStack.append(type);
+    return CSSParserToken(type, CSSParserToken::BlockStart);
+}
+
+CSSParserToken CSSTokenizer::blockStart(CSSParserTokenType blockType, CSSParserTokenType type, StringView name)
+{
+    m_blockStack.append(blockType);
+    return CSSParserToken(type, name, CSSParserToken::BlockStart);
+}
+
+CSSParserToken CSSTokenizer::blockEnd(CSSParserTokenType type, CSSParserTokenType startType)
+{
+    if (!m_blockStack.isEmpty() &amp;&amp; m_blockStack.last() == startType) {
+        m_blockStack.removeLast();
+        return CSSParserToken(type, CSSParserToken::BlockEnd);
+    }
+    return CSSParserToken(type);
+}
+
+CSSParserToken CSSTokenizer::leftParenthesis(UChar /*cc*/)
+{
+    return blockStart(LeftParenthesisToken);
+}
+
+CSSParserToken CSSTokenizer::rightParenthesis(UChar /*cc*/)
+{
+    return blockEnd(RightParenthesisToken, LeftParenthesisToken);
+}
+
+CSSParserToken CSSTokenizer::leftBracket(UChar /*cc*/)
+{
+    return blockStart(LeftBracketToken);
+}
+
+CSSParserToken CSSTokenizer::rightBracket(UChar /*cc*/)
+{
+    return blockEnd(RightBracketToken, LeftBracketToken);
+}
+
+CSSParserToken CSSTokenizer::leftBrace(UChar /*cc*/)
+{
+    return blockStart(LeftBraceToken);
+}
+
+CSSParserToken CSSTokenizer::rightBrace(UChar /*cc*/)
+{
+    return blockEnd(RightBraceToken, LeftBraceToken);
+}
+
+CSSParserToken CSSTokenizer::plusOrFullStop(UChar cc)
+{
+    if (nextCharsAreNumber(cc)) {
+        reconsume(cc);
+        return consumeNumericToken();
+    }
+    return CSSParserToken(DelimiterToken, cc);
+}
+
+CSSParserToken CSSTokenizer::asterisk(UChar cc)
+{
+    ASSERT_UNUSED(cc, cc == '*');
+    if (consumeIfNext('='))
+        return CSSParserToken(SubstringMatchToken);
+    return CSSParserToken(DelimiterToken, '*');
+}
+
+CSSParserToken CSSTokenizer::lessThan(UChar cc)
+{
+    ASSERT_UNUSED(cc, cc == '&lt;');
+    if (m_input.peekWithoutReplacement(0) == '!'
+        &amp;&amp; m_input.peekWithoutReplacement(1) == '-'
+        &amp;&amp; m_input.peekWithoutReplacement(2) == '-') {
+        m_input.advance(3);
+        return CSSParserToken(CDOToken);
+    }
+    return CSSParserToken(DelimiterToken, '&lt;');
+}
+
+CSSParserToken CSSTokenizer::comma(UChar /*cc*/)
+{
+    return CSSParserToken(CommaToken);
+}
+
+CSSParserToken CSSTokenizer::hyphenMinus(UChar cc)
+{
+    if (nextCharsAreNumber(cc)) {
+        reconsume(cc);
+        return consumeNumericToken();
+    }
+    if (m_input.peekWithoutReplacement(0) == '-'
+        &amp;&amp; m_input.peekWithoutReplacement(1) == '&gt;') {
+        m_input.advance(2);
+        return CSSParserToken(CDCToken);
+    }
+    if (nextCharsAreIdentifier(cc)) {
+        reconsume(cc);
+        return consumeIdentLikeToken();
+    }
+    return CSSParserToken(DelimiterToken, cc);
+}
+
+CSSParserToken CSSTokenizer::solidus(UChar cc)
+{
+    if (consumeIfNext('*')) {
+        // These get ignored, but we need a value to return.
+        consumeUntilCommentEndFound();
+        return CSSParserToken(CommentToken);
+    }
+
+    return CSSParserToken(DelimiterToken, cc);
+}
+
+CSSParserToken CSSTokenizer::colon(UChar /*cc*/)
+{
+    return CSSParserToken(ColonToken);
+}
+
+CSSParserToken CSSTokenizer::semiColon(UChar /*cc*/)
+{
+    return CSSParserToken(SemicolonToken);
+}
+
+CSSParserToken CSSTokenizer::hash(UChar cc)
+{
+    UChar nextChar = m_input.peekWithoutReplacement(0);
+    if (isNameCodePoint(nextChar) || twoCharsAreValidEscape(nextChar, m_input.peekWithoutReplacement(1))) {
+        HashTokenType type = nextCharsAreIdentifier() ? HashTokenId : HashTokenUnrestricted;
+        return CSSParserToken(type, consumeName());
+    }
+
+    return CSSParserToken(DelimiterToken, cc);
+}
+
+CSSParserToken CSSTokenizer::circumflexAccent(UChar cc)
+{
+    ASSERT_UNUSED(cc, cc == '^');
+    if (consumeIfNext('='))
+        return CSSParserToken(PrefixMatchToken);
+    return CSSParserToken(DelimiterToken, '^');
+}
+
+CSSParserToken CSSTokenizer::dollarSign(UChar cc)
+{
+    ASSERT_UNUSED(cc, cc == '$');
+    if (consumeIfNext('='))
+        return CSSParserToken(SuffixMatchToken);
+    return CSSParserToken(DelimiterToken, '$');
+}
+
+CSSParserToken CSSTokenizer::verticalLine(UChar cc)
+{
+    ASSERT_UNUSED(cc, cc == '|');
+    if (consumeIfNext('='))
+        return CSSParserToken(DashMatchToken);
+    if (consumeIfNext('|'))
+        return CSSParserToken(ColumnToken);
+    return CSSParserToken(DelimiterToken, '|');
+}
+
+CSSParserToken CSSTokenizer::tilde(UChar cc)
+{
+    ASSERT_UNUSED(cc, cc == '~');
+    if (consumeIfNext('='))
+        return CSSParserToken(IncludeMatchToken);
+    return CSSParserToken(DelimiterToken, '~');
+}
+
+CSSParserToken CSSTokenizer::commercialAt(UChar cc)
+{
+    ASSERT_UNUSED(cc, cc == '@');
+    if (nextCharsAreIdentifier())
+        return CSSParserToken(AtKeywordToken, consumeName());
+    return CSSParserToken(DelimiterToken, '@');
+}
+
+CSSParserToken CSSTokenizer::reverseSolidus(UChar cc)
+{
+    if (twoCharsAreValidEscape(cc, m_input.peekWithoutReplacement(0))) {
+        reconsume(cc);
+        return consumeIdentLikeToken();
+    }
+    return CSSParserToken(DelimiterToken, cc);
+}
+
+CSSParserToken CSSTokenizer::asciiDigit(UChar cc)
+{
+    reconsume(cc);
+    return consumeNumericToken();
+}
+
+CSSParserToken CSSTokenizer::letterU(UChar cc)
+{
+    if (m_input.peekWithoutReplacement(0) == '+'
+        &amp;&amp; (isASCIIHexDigit(m_input.peekWithoutReplacement(1))
+            || m_input.peekWithoutReplacement(1) == '?')) {
+        m_input.advance();
+        return consumeUnicodeRange();
+    }
+    reconsume(cc);
+    return consumeIdentLikeToken();
+}
+
+CSSParserToken CSSTokenizer::nameStart(UChar cc)
+{
+    reconsume(cc);
+    return consumeIdentLikeToken();
+}
+
+CSSParserToken CSSTokenizer::stringStart(UChar cc)
+{
+    return consumeStringTokenUntil(cc);
+}
+
+CSSParserToken CSSTokenizer::endOfFile(UChar /*cc*/)
+{
+    return CSSParserToken(EOFToken);
+}
+
+const CSSTokenizer::CodePoint CSSTokenizer::codePoints[128] = {
+    &amp;CSSTokenizer::endOfFile,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    &amp;CSSTokenizer::whiteSpace,
+    &amp;CSSTokenizer::whiteSpace,
+    0,
+    &amp;CSSTokenizer::whiteSpace,
+    &amp;CSSTokenizer::whiteSpace,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    &amp;CSSTokenizer::whiteSpace,
+    0,
+    &amp;CSSTokenizer::stringStart,
+    &amp;CSSTokenizer::hash,
+    &amp;CSSTokenizer::dollarSign,
+    0,
+    0,
+    &amp;CSSTokenizer::stringStart,
+    &amp;CSSTokenizer::leftParenthesis,
+    &amp;CSSTokenizer::rightParenthesis,
+    &amp;CSSTokenizer::asterisk,
+    &amp;CSSTokenizer::plusOrFullStop,
+    &amp;CSSTokenizer::comma,
+    &amp;CSSTokenizer::hyphenMinus,
+    &amp;CSSTokenizer::plusOrFullStop,
+    &amp;CSSTokenizer::solidus,
+    &amp;CSSTokenizer::asciiDigit,
+    &amp;CSSTokenizer::asciiDigit,
+    &amp;CSSTokenizer::asciiDigit,
+    &amp;CSSTokenizer::asciiDigit,
+    &amp;CSSTokenizer::asciiDigit,
+    &amp;CSSTokenizer::asciiDigit,
+    &amp;CSSTokenizer::asciiDigit,
+    &amp;CSSTokenizer::asciiDigit,
+    &amp;CSSTokenizer::asciiDigit,
+    &amp;CSSTokenizer::asciiDigit,
+    &amp;CSSTokenizer::colon,
+    &amp;CSSTokenizer::semiColon,
+    &amp;CSSTokenizer::lessThan,
+    0,
+    0,
+    0,
+    &amp;CSSTokenizer::commercialAt,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::letterU,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::leftBracket,
+    &amp;CSSTokenizer::reverseSolidus,
+    &amp;CSSTokenizer::rightBracket,
+    &amp;CSSTokenizer::circumflexAccent,
+    &amp;CSSTokenizer::nameStart,
+    0,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::letterU,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::nameStart,
+    &amp;CSSTokenizer::leftBrace,
+    &amp;CSSTokenizer::verticalLine,
+    &amp;CSSTokenizer::rightBrace,
+    &amp;CSSTokenizer::tilde,
+    0,
+};
+#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
+const unsigned codePointsNumber = 128;
+#endif
+
+CSSParserToken CSSTokenizer::nextToken()
+{
+    // Unlike the HTMLTokenizer, the CSS Syntax spec is written
+    // as a stateless, (fixed-size) look-ahead tokenizer.
+    // We could move to the stateful model and instead create
+    // states for all the &quot;next 3 codepoints are X&quot; cases.
+    // State-machine tokenizers are easier to write to handle
+    // incremental tokenization of partial sources.
+    // However, for now we follow the spec exactly.
+    UChar cc = consume();
+    CodePoint codePointFunc = 0;
+
+    if (isASCII(cc)) {
+        ASSERT_WITH_SECURITY_IMPLICATION(cc &lt; codePointsNumber);
+        codePointFunc = codePoints[cc];
+    } else
+        codePointFunc = &amp;CSSTokenizer::nameStart;
+
+    if (codePointFunc)
+        return ((this)-&gt;*(codePointFunc))(cc);
+    return CSSParserToken(DelimiterToken, cc);
+}
+
+// This method merges the following spec sections for efficiency
+// http://www.w3.org/TR/css3-syntax/#consume-a-number
+// http://www.w3.org/TR/css3-syntax/#convert-a-string-to-a-number
+CSSParserToken CSSTokenizer::consumeNumber()
+{
+    ASSERT(nextCharsAreNumber());
+
+    NumericValueType type = IntegerValueType;
+    NumericSign sign = NoSign;
+    unsigned numberLength = 0;
+
+    UChar next = m_input.peekWithoutReplacement(0);
+    if (next == '+') {
+        ++numberLength;
+        sign = PlusSign;
+    } else if (next == '-') {
+        ++numberLength;
+        sign = MinusSign;
+    }
+
+    numberLength = m_input.skipWhilePredicate&lt;isASCIIDigit&gt;(numberLength);
+    next = m_input.peekWithoutReplacement(numberLength);
+    if (next == '.' &amp;&amp; isASCIIDigit(m_input.peekWithoutReplacement(numberLength + 1))) {
+        type = NumberValueType;
+        numberLength = m_input.skipWhilePredicate&lt;isASCIIDigit&gt;(numberLength + 2);
+        next = m_input.peekWithoutReplacement(numberLength);
+    }
+
+    if (next == 'E' || next == 'e') {
+        next = m_input.peekWithoutReplacement(numberLength + 1);
+        if (isASCIIDigit(next)) {
+            type = NumberValueType;
+            numberLength = m_input.skipWhilePredicate&lt;isASCIIDigit&gt;(numberLength + 1);
+        } else if ((next == '+' || next == '-') &amp;&amp; isASCIIDigit(m_input.peekWithoutReplacement(numberLength + 2))) {
+            type = NumberValueType;
+            numberLength = m_input.skipWhilePredicate&lt;isASCIIDigit&gt;(numberLength + 3);
+        }
+    }
+
+    double value = m_input.getDouble(0, numberLength);
+    m_input.advance(numberLength);
+
+    return CSSParserToken(NumberToken, value, type, sign);
+}
+
+// http://www.w3.org/TR/css3-syntax/#consume-a-numeric-token
+CSSParserToken CSSTokenizer::consumeNumericToken()
+{
+    CSSParserToken token = consumeNumber();
+    if (nextCharsAreIdentifier())
+        token.convertToDimensionWithUnit(consumeName());
+    else if (consumeIfNext('%'))
+        token.convertToPercentage();
+    return token;
+}
+
+// http://dev.w3.org/csswg/css-syntax/#consume-ident-like-token
+CSSParserToken CSSTokenizer::consumeIdentLikeToken()
+{
+    StringView name = consumeName();
+    if (consumeIfNext('(')) {
+        if (equalIgnoringASCIICase(name, &quot;url&quot;)) {
+            // The spec is slightly different so as to avoid dropping whitespace
+            // tokens, but they wouldn't be used and this is easier.
+            m_input.advanceUntilNonWhitespace();
+            UChar next = m_input.peekWithoutReplacement(0);
+            if (next != '&quot;' &amp;&amp; next != '\'')
+                return consumeUrlToken();
+        }
+        return blockStart(LeftParenthesisToken, FunctionToken, name);
+    }
+    return CSSParserToken(IdentToken, name);
+}
+
+// http://dev.w3.org/csswg/css-syntax/#consume-a-string-token
+CSSParserToken CSSTokenizer::consumeStringTokenUntil(UChar endingCodePoint)
+{
+    // Strings without escapes get handled without allocations
+    for (unsigned size = 0; ; size++) {
+        UChar cc = m_input.peekWithoutReplacement(size);
+        if (cc == endingCodePoint) {
+            unsigned startOffset = m_input.offset();
+            m_input.advance(size + 1);
+            return CSSParserToken(StringToken, m_input.rangeAt(startOffset, size));
+        }
+        if (isNewLine(cc)) {
+            m_input.advance(size);
+            return CSSParserToken(BadStringToken);
+        }
+        if (cc == '\0' || cc == '\\')
+            break;
+    }
+
+    StringBuilder output;
+    while (true) {
+        UChar cc = consume();
+        if (cc == endingCodePoint || cc == kEndOfFileMarker)
+            return CSSParserToken(StringToken, registerString(output.toString()));
+        if (isNewLine(cc)) {
+            reconsume(cc);
+            return CSSParserToken(BadStringToken);
+        }
+        if (cc == '\\') {
+            if (m_input.nextInputChar() == kEndOfFileMarker)
+                continue;
+            if (isNewLine(m_input.peekWithoutReplacement(0)))
+                consumeSingleWhitespaceIfNext(); // This handles \r\n for us
+            else
+                output.append(consumeEscape());
+        } else
+            output.append(cc);
+    }
+}
+
+CSSParserToken CSSTokenizer::consumeUnicodeRange()
+{
+    ASSERT(isASCIIHexDigit(m_input.peekWithoutReplacement(0)) || m_input.peekWithoutReplacement(0) == '?');
+    int lengthRemaining = 6;
+    UChar32 start = 0;
+
+    while (lengthRemaining &amp;&amp; isASCIIHexDigit(m_input.peekWithoutReplacement(0))) {
+        start = start * 16 + toASCIIHexValue(consume());
+        --lengthRemaining;
+    }
+
+    UChar32 end = start;
+    if (lengthRemaining &amp;&amp; consumeIfNext('?')) {
+        do {
+            start *= 16;
+            end = end * 16 + 0xF;
+            --lengthRemaining;
+        } while (lengthRemaining &amp;&amp; consumeIfNext('?'));
+    } else if (m_input.peekWithoutReplacement(0) == '-' &amp;&amp; isASCIIHexDigit(m_input.peekWithoutReplacement(1))) {
+        m_input.advance();
+        lengthRemaining = 6;
+        end = 0;
+        do {
+            end = end * 16 + toASCIIHexValue(consume());
+            --lengthRemaining;
+        } while (lengthRemaining &amp;&amp; isASCIIHexDigit(m_input.peekWithoutReplacement(0)));
+    }
+
+    return CSSParserToken(UnicodeRangeToken, start, end);
+}
+
+// http://dev.w3.org/csswg/css-syntax/#non-printable-code-point
+static bool isNonPrintableCodePoint(UChar cc)
+{
+    return cc &lt;= '\x8' || cc == '\xb' || (cc &gt;= '\xe' &amp;&amp; cc &lt;= '\x1f') || cc == '\x7f';
+}
+
+// http://dev.w3.org/csswg/css-syntax/#consume-url-token
+CSSParserToken CSSTokenizer::consumeUrlToken()
+{
+    m_input.advanceUntilNonWhitespace();
+
+    // URL tokens without escapes get handled without allocations
+    for (unsigned size = 0; ; size++) {
+        UChar cc = m_input.peekWithoutReplacement(size);
+        if (cc == ')') {
+            unsigned startOffset = m_input.offset();
+            m_input.advance(size + 1);
+            return CSSParserToken(UrlToken, m_input.rangeAt(startOffset, size));
+        }
+        if (cc &lt;= ' ' || cc == '\\' || cc == '&quot;' || cc == '\'' || cc == '(' || cc == '\x7f')
+            break;
+    }
+
+    StringBuilder result;
+    while (true) {
+        UChar cc = consume();
+        if (cc == ')' || cc == kEndOfFileMarker)
+            return CSSParserToken(UrlToken, registerString(result.toString()));
+
+        if (isHTMLSpace(cc)) {
+            m_input.advanceUntilNonWhitespace();
+            if (consumeIfNext(')') || m_input.nextInputChar() == kEndOfFileMarker)
+                return CSSParserToken(UrlToken, registerString(result.toString()));
+            break;
+        }
+
+        if (cc == '&quot;' || cc == '\'' || cc == '(' || isNonPrintableCodePoint(cc))
+            break;
+
+        if (cc == '\\') {
+            if (twoCharsAreValidEscape(cc, m_input.peekWithoutReplacement(0))) {
+                result.append(consumeEscape());
+                continue;
+            }
+            break;
+        }
+
+        result.append(cc);
+    }
+
+    consumeBadUrlRemnants();
+    return CSSParserToken(BadUrlToken);
+}
+
+// http://dev.w3.org/csswg/css-syntax/#consume-the-remnants-of-a-bad-url
+void CSSTokenizer::consumeBadUrlRemnants()
+{
+    while (true) {
+        UChar cc = consume();
+        if (cc == ')' || cc == kEndOfFileMarker)
+            return;
+        if (twoCharsAreValidEscape(cc, m_input.peekWithoutReplacement(0)))
+            consumeEscape();
+    }
+}
+
+void CSSTokenizer::consumeSingleWhitespaceIfNext()
+{
+    // We check for \r\n and HTML spaces since we don't do preprocessing
+    UChar next = m_input.peekWithoutReplacement(0);
+    if (next == '\r' &amp;&amp; m_input.peekWithoutReplacement(1) == '\n')
+        m_input.advance(2);
+    else if (isHTMLSpace(next))
+        m_input.advance();
+}
+
+void CSSTokenizer::consumeUntilCommentEndFound()
+{
+    UChar c = consume();
+    while (true) {
+        if (c == kEndOfFileMarker)
+            return;
+        if (c != '*') {
+            c = consume();
+            continue;
+        }
+        c = consume();
+        if (c == '/')
+            return;
+    }
+}
+
+bool CSSTokenizer::consumeIfNext(UChar character)
+{
+    // Since we're not doing replacement we can't tell the difference from
+    // a NUL in the middle and the kEndOfFileMarker, so character must not be
+    // NUL.
+    ASSERT(character);
+    if (m_input.peekWithoutReplacement(0) == character) {
+        m_input.advance();
+        return true;
+    }
+    return false;
+}
+
+// http://www.w3.org/TR/css3-syntax/#consume-a-name
+StringView CSSTokenizer::consumeName()
+{
+    // Names without escapes get handled without allocations
+    for (unsigned size = 0; ; ++size) {
+        UChar cc = m_input.peekWithoutReplacement(size);
+        if (isNameCodePoint(cc))
+            continue;
+        // peekWithoutReplacement will return NUL when we hit the end of the
+        // input. In that case we want to still use the rangeAt() fast path
+        // below.
+        if (cc == '\0' &amp;&amp; m_input.offset() + size &lt; m_input.length())
+            break;
+        if (cc == '\\')
+            break;
+        unsigned startOffset = m_input.offset();
+        m_input.advance(size);
+        return m_input.rangeAt(startOffset, size);
+    }
+
+    StringBuilder result;
+    while (true) {
+        UChar cc = consume();
+        if (isNameCodePoint(cc)) {
+            result.append(cc);
+            continue;
+        }
+        if (twoCharsAreValidEscape(cc, m_input.peekWithoutReplacement(0))) {
+            result.append(consumeEscape());
+            continue;
+        }
+        reconsume(cc);
+        return registerString(result.toString());
+    }
+}
+
+// http://dev.w3.org/csswg/css-syntax/#consume-an-escaped-code-point
+UChar32 CSSTokenizer::consumeEscape()
+{
+    UChar cc = consume();
+    ASSERT(!isNewLine(cc));
+    if (isASCIIHexDigit(cc)) {
+        unsigned consumedHexDigits = 1;
+        StringBuilder hexChars;
+        hexChars.append(cc);
+        while (consumedHexDigits &lt; 6 &amp;&amp; isASCIIHexDigit(m_input.peekWithoutReplacement(0))) {
+            cc = consume();
+            hexChars.append(cc);
+            consumedHexDigits++;
+        };
+        consumeSingleWhitespaceIfNext();
+        bool ok = false;
+        UChar32 codePoint = hexChars.toString().toUIntStrict(&amp;ok, 16);
+        ASSERT(ok);
+        if (!codePoint || (0xD800 &lt;= codePoint &amp;&amp; codePoint &lt;= 0xDFFF) || codePoint &gt; 0x10FFFF)
+            return replacementCharacter;
+        return codePoint;
+    }
+
+    if (cc == kEndOfFileMarker)
+        return replacementCharacter;
+    return cc;
+}
+
+bool CSSTokenizer::nextTwoCharsAreValidEscape()
+{
+    return twoCharsAreValidEscape(m_input.peekWithoutReplacement(0), m_input.peekWithoutReplacement(1));
+}
+
+// http://www.w3.org/TR/css3-syntax/#starts-with-a-number
+bool CSSTokenizer::nextCharsAreNumber(UChar first)
+{
+    UChar second = m_input.peekWithoutReplacement(0);
+    if (isASCIIDigit(first))
+        return true;
+    if (first == '+' || first == '-')
+        return ((isASCIIDigit(second)) || (second == '.' &amp;&amp; isASCIIDigit(m_input.peekWithoutReplacement(1))));
+    if (first =='.')
+        return (isASCIIDigit(second));
+    return false;
+}
+
+bool CSSTokenizer::nextCharsAreNumber()
+{
+    UChar first = consume();
+    bool areNumber = nextCharsAreNumber(first);
+    reconsume(first);
+    return areNumber;
+}
+
+// http://dev.w3.org/csswg/css-syntax/#would-start-an-identifier
+bool CSSTokenizer::nextCharsAreIdentifier(UChar first)
+{
+    UChar second = m_input.peekWithoutReplacement(0);
+    if (isNameStartCodePoint(first) || twoCharsAreValidEscape(first, second))
+        return true;
+
+    if (first == '-')
+        return isNameStartCodePoint(second) || second == '-' || nextTwoCharsAreValidEscape();
+
+    return false;
+}
+
+bool CSSTokenizer::nextCharsAreIdentifier()
+{
+    UChar first = consume();
+    bool areIdentifier = nextCharsAreIdentifier(first);
+    reconsume(first);
+    return areIdentifier;
+}
+
+StringView CSSTokenizer::registerString(const String&amp; string)
+{
+    m_scope.storeString(string);
+    return string;
+}
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSTokenizerh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSTokenizer.h (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSTokenizer.h                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSTokenizer.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,140 @@
</span><ins>+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CSSTokenizer_h
+#define CSSTokenizer_h
+
+#include &quot;CSSParserToken.h&quot;
+#include &quot;InputStreamPreprocessor.h&quot;
+#include &lt;climits&gt;
+#include &lt;wtf/text/StringView.h&gt;
+#include &lt;wtf/text/WTFString.h&gt;
+
+namespace WebCore {
+
+class CSSTokenizerInputStream;
+class CSSParserObserverWrapper;
+class CSSParserTokenRange;
+
+class CSSTokenizer {
+    WTF_MAKE_NONCOPYABLE(CSSTokenizer);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    class Scope {
+    public:
+        Scope(const String&amp;);
+        Scope(const String&amp;, CSSParserObserverWrapper&amp;); // For the inspector
+
+        CSSParserTokenRange tokenRange();
+        unsigned tokenCount();
+
+    private:
+        void storeString(const String&amp; string) { m_stringPool.append(string); }
+        Vector&lt;CSSParserToken, 32&gt; m_tokens;
+        // We only allocate strings when escapes are used.
+        Vector&lt;String&gt; m_stringPool;
+        String m_string;
+
+        friend class CSSTokenizer;
+    };
+
+private:
+    CSSTokenizer(CSSTokenizerInputStream&amp;, Scope&amp;);
+
+    CSSParserToken nextToken();
+
+    UChar consume();
+    void reconsume(UChar);
+
+    CSSParserToken consumeNumericToken();
+    CSSParserToken consumeIdentLikeToken();
+    CSSParserToken consumeNumber();
+    CSSParserToken consumeStringTokenUntil(UChar);
+    CSSParserToken consumeUnicodeRange();
+    CSSParserToken consumeUrlToken();
+
+    void consumeBadUrlRemnants();
+    void consumeSingleWhitespaceIfNext();
+    void consumeUntilCommentEndFound();
+
+    bool consumeIfNext(UChar);
+    StringView consumeName();
+    UChar32 consumeEscape();
+
+    bool nextTwoCharsAreValidEscape();
+    bool nextCharsAreNumber(UChar);
+    bool nextCharsAreNumber();
+    bool nextCharsAreIdentifier(UChar);
+    bool nextCharsAreIdentifier();
+
+    CSSParserToken blockStart(CSSParserTokenType);
+    CSSParserToken blockStart(CSSParserTokenType blockType, CSSParserTokenType, StringView);
+    CSSParserToken blockEnd(CSSParserTokenType, CSSParserTokenType startType);
+
+    CSSParserToken whiteSpace(UChar);
+    CSSParserToken leftParenthesis(UChar);
+    CSSParserToken rightParenthesis(UChar);
+    CSSParserToken leftBracket(UChar);
+    CSSParserToken rightBracket(UChar);
+    CSSParserToken leftBrace(UChar);
+    CSSParserToken rightBrace(UChar);
+    CSSParserToken plusOrFullStop(UChar);
+    CSSParserToken comma(UChar);
+    CSSParserToken hyphenMinus(UChar);
+    CSSParserToken asterisk(UChar);
+    CSSParserToken lessThan(UChar);
+    CSSParserToken solidus(UChar);
+    CSSParserToken colon(UChar);
+    CSSParserToken semiColon(UChar);
+    CSSParserToken hash(UChar);
+    CSSParserToken circumflexAccent(UChar);
+    CSSParserToken dollarSign(UChar);
+    CSSParserToken verticalLine(UChar);
+    CSSParserToken tilde(UChar);
+    CSSParserToken commercialAt(UChar);
+    CSSParserToken reverseSolidus(UChar);
+    CSSParserToken asciiDigit(UChar);
+    CSSParserToken letterU(UChar);
+    CSSParserToken nameStart(UChar);
+    CSSParserToken stringStart(UChar);
+    CSSParserToken endOfFile(UChar);
+
+    StringView registerString(const String&amp;);
+
+    using CodePoint = CSSParserToken (CSSTokenizer::*)(UChar);
+    static const CodePoint codePoints[];
+
+    Vector&lt;CSSParserTokenType, 8&gt; m_blockStack;
+    CSSTokenizerInputStream&amp; m_input;
+    Scope&amp; m_scope;
+};
+
+} // namespace WebCore
+
+#endif // CSSTokenizer_h
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSTokenizerInputStreamcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSTokenizerInputStream.cpp (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSTokenizerInputStream.cpp                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSTokenizerInputStream.cpp        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,73 @@
</span><ins>+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include &quot;config.h&quot;
+#include &quot;CSSTokenizerInputStream.h&quot;
+
+#include &quot;HTMLParserIdioms.h&quot;
+
+namespace WebCore {
+
+CSSTokenizerInputStream::CSSTokenizerInputStream(String input)
+    : m_offset(0)
+    , m_stringLength(input.length())
+    , m_string(input.impl())
+{
+}
+
+void CSSTokenizerInputStream::advanceUntilNonWhitespace()
+{
+    // Using HTML space here rather than CSS space since we don't do preprocessing
+    if (m_string-&gt;is8Bit()) {
+        const LChar* characters = m_string-&gt;characters8();
+        while (m_offset &lt; m_stringLength &amp;&amp; isHTMLSpace(characters[m_offset]))
+            ++m_offset;
+    } else {
+        const UChar* characters = m_string-&gt;characters16();
+        while (m_offset &lt; m_stringLength &amp;&amp; isHTMLSpace(characters[m_offset]))
+            ++m_offset;
+    }
+}
+
+double CSSTokenizerInputStream::getDouble(unsigned start, unsigned end) const
+{
+    ASSERT(start &lt;= end &amp;&amp; ((m_offset + end) &lt;= m_stringLength));
+    bool isResultOK = false;
+    double result = 0.0;
+    if (start &lt; end) {
+        if (m_string-&gt;is8Bit())
+            result = charactersToDouble(m_string-&gt;characters8() + m_offset + start, end - start, &amp;isResultOK);
+        else
+            result = charactersToDouble(m_string-&gt;characters16() + m_offset + start, end - start, &amp;isResultOK);
+    }
+    // FIXME: It looks like callers ensure we have a valid number
+    return isResultOK ? result : 0.0;
+}
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSTokenizerInputStreamh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/css/parser/CSSTokenizerInputStream.h (0 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSTokenizerInputStream.h                                (rev 0)
+++ trunk/Source/WebCore/css/parser/CSSTokenizerInputStream.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -0,0 +1,110 @@
</span><ins>+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright (C) 2016 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CSSTokenizerInputStream_h
+#define CSSTokenizerInputStream_h
+
+#include &lt;wtf/text/StringView.h&gt;
+#include &lt;wtf/text/WTFString.h&gt;
+
+namespace WebCore {
+
+class CSSTokenizerInputStream {
+    WTF_MAKE_NONCOPYABLE(CSSTokenizerInputStream);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit CSSTokenizerInputStream(String input);
+
+    // Gets the char in the stream replacing NUL characters with a unicode
+    // replacement character. Will return (NUL) kEndOfFileMarker when at the
+    // end of the stream.
+    UChar nextInputChar() const
+    {
+        if (m_offset &gt;= m_stringLength)
+            return '\0';
+        UChar result = (*m_string)[m_offset];
+        return result ? result : 0xFFFD;
+    }
+
+    // Gets the char at lookaheadOffset from the current stream position. Will
+    // return NUL (kEndOfFileMarker) if the stream position is at the end.
+    // NOTE: This may *also* return NUL if there's one in the input! Never
+    // compare the return value to '\0'.
+    UChar peekWithoutReplacement(unsigned lookaheadOffset) const
+    {
+        if ((m_offset + lookaheadOffset) &gt;= m_stringLength)
+            return '\0';
+        return (*m_string)[m_offset + lookaheadOffset];
+    }
+
+    void advance(unsigned offset = 1) { m_offset += offset; }
+    void pushBack(UChar cc)
+    {
+        --m_offset;
+        ASSERT_UNUSED(cc, nextInputChar() == cc);
+    }
+
+    double getDouble(unsigned start, unsigned end) const;
+
+    template&lt;bool characterPredicate(UChar)&gt;
+    unsigned skipWhilePredicate(unsigned offset)
+    {
+        if (m_string-&gt;is8Bit()) {
+            const LChar* characters8 = m_string-&gt;characters8();
+            while ((m_offset + offset) &lt; m_stringLength &amp;&amp; characterPredicate(characters8[m_offset + offset]))
+                ++offset;
+        } else {
+            const UChar* characters16 = m_string-&gt;characters16();
+            while ((m_offset + offset) &lt; m_stringLength &amp;&amp; characterPredicate(characters16[m_offset + offset]))
+                ++offset;
+        }
+        return offset;
+    }
+
+    void advanceUntilNonWhitespace();
+
+    unsigned length() const { return m_stringLength; }
+    unsigned offset() const { return std::min(m_offset, m_stringLength); }
+
+    StringView rangeAt(unsigned start, unsigned length) const
+    {
+        ASSERT(start + length &lt;= m_stringLength);
+        return StringView(m_string.get()).substring(start, length); // FIXME: Should make a constructor on StringView for this.
+    }
+
+private:
+    size_t m_offset;
+    const size_t m_stringLength;
+    const RefPtr&lt;StringImpl&gt; m_string;
+};
+
+} // namespace WebCore
+
+#endif // CSSTokenizerInputStream_h
+
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformLengthh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/Length.h (205102 => 205103)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/Length.h        2016-08-28 14:45:43 UTC (rev 205102)
+++ trunk/Source/WebCore/platform/Length.h        2016-08-28 15:46:11 UTC (rev 205103)
</span><span class="lines">@@ -40,6 +40,11 @@
</span><span class="cx">     Undefined
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+enum ValueRange {
+    ValueRangeAll,
+    ValueRangeNonNegative
+};
+
</ins><span class="cx"> class CalculationValue;
</span><span class="cx"> class TextStream;
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>