<!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 <hyatt@apple.com>
+
+ 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 <jfernandez@igalia.com>
</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 = "<group>"; };
</span><span class="cx">                 946D372C1D6CB28B0077084F /* CSSParserValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserValues.h; path = parser/CSSParserValues.h; sourceTree = "<group>"; };
</span><span class="cx">                 946D37321D6CC3720077084F /* SVGCSSParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SVGCSSParser.cpp; path = parser/SVGCSSParser.cpp; sourceTree = "<group>"; };
</span><ins>+                946D37341D6CDF980077084F /* CSSTokenizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSTokenizer.cpp; path = parser/CSSTokenizer.cpp; sourceTree = "<group>"; };
+                946D37351D6CDF980077084F /* CSSTokenizerInputStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSTokenizerInputStream.cpp; path = parser/CSSTokenizerInputStream.cpp; sourceTree = "<group>"; };
+                946D37371D6CDF980077084F /* CSSTokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSTokenizer.h; path = parser/CSSTokenizer.h; sourceTree = "<group>"; };
+                946D37381D6CDF980077084F /* CSSTokenizerInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSTokenizerInputStream.h; path = parser/CSSTokenizerInputStream.h; sourceTree = "<group>"; };
+                946D373D1D6CE31A0077084F /* CSSParserToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserToken.h; path = parser/CSSParserToken.h; sourceTree = "<group>"; };
+                946D373E1D6CE31A0077084F /* CSSParserToken.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSParserToken.cpp; path = parser/CSSParserToken.cpp; sourceTree = "<group>"; };
+                946D37411D6CF6320077084F /* CSSPropertyParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSPropertyParser.cpp; path = parser/CSSPropertyParser.cpp; sourceTree = "<group>"; };
+                946D37421D6CF6320077084F /* CSSPropertyParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSPropertyParser.h; path = parser/CSSPropertyParser.h; sourceTree = "<group>"; };
+                946D37431D6CF7880077084F /* CSSParserIdioms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserIdioms.h; path = parser/CSSParserIdioms.h; sourceTree = "<group>"; };
+                946D37471D6D060C0077084F /* CSSMarkup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSMarkup.cpp; sourceTree = "<group>"; };
+                946D37481D6D060C0077084F /* CSSMarkup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSMarkup.h; sourceTree = "<group>"; };
+                946D374B1D6D07F50077084F /* CSSParserTokenRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSParserTokenRange.cpp; path = parser/CSSParserTokenRange.cpp; sourceTree = "<group>"; };
+                946D374C1D6D07F50077084F /* CSSParserTokenRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserTokenRange.h; path = parser/CSSParserTokenRange.h; sourceTree = "<group>"; };
+                949C76FE1D6E1D8C00C0DE4F /* CSSParserFastPaths.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSParserFastPaths.cpp; path = parser/CSSParserFastPaths.cpp; sourceTree = "<group>"; };
+                949C76FF1D6E1D8C00C0DE4F /* CSSParserFastPaths.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserFastPaths.h; path = parser/CSSParserFastPaths.h; sourceTree = "<group>"; };
+                949C77021D6E393500C0DE4F /* CSSPropertyParserHelpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSPropertyParserHelpers.cpp; path = parser/CSSPropertyParserHelpers.cpp; sourceTree = "<group>"; };
+                949C77031D6E393500C0DE4F /* CSSPropertyParserHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSPropertyParserHelpers.h; path = parser/CSSPropertyParserHelpers.h; sourceTree = "<group>"; };
+                949C77061D6E48ED00C0DE4F /* CSSParserObserverWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CSSParserObserverWrapper.cpp; path = parser/CSSParserObserverWrapper.cpp; sourceTree = "<group>"; };
+                949C77071D6E48ED00C0DE4F /* CSSParserObserverWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserObserverWrapper.h; path = parser/CSSParserObserverWrapper.h; sourceTree = "<group>"; };
+                949C770A1D6E49C300C0DE4F /* CSSParserObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSSParserObserver.h; path = parser/CSSParserObserver.h; sourceTree = "<group>"; };
</ins><span class="cx">                 950C4C02BED8936F818E2F99 /* JSSVGGraphicsElement.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSSVGGraphicsElement.h; sourceTree = "<group>"; };
</span><span class="cx">                 96ABA42214BCB80E00D56204 /* GraphicsContext3DOpenGLCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GraphicsContext3DOpenGLCommon.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 97059973107D975200A50A7C /* PolicyCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PolicyCallback.cpp; sourceTree = "<group>"; };
</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 = "<group>"; };
</span><span class="cx">                 F916C48C0DB510F80076CD83 /* JSXMLHttpRequestProgressEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSXMLHttpRequestProgressEvent.h; sourceTree = "<group>"; };
</span><del>-                F98FFF4211A2676200F548E8 /* CSSOMUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSOMUtils.cpp; sourceTree = "<group>"; };
-                F98FFF4311A2676200F548E8 /* CSSOMUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSOMUtils.h; sourceTree = "<group>"; };
</del><span class="cx">                 F9F0ED770DB50CA200D16DB9 /* XMLHttpRequestProgressEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = XMLHttpRequestProgressEvent.h; sourceTree = "<group>"; };
</span><span class="cx">                 F9F0ED780DB50CA200D16DB9 /* XMLHttpRequestProgressEvent.idl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = XMLHttpRequestProgressEvent.idl; sourceTree = "<group>"; };
</span><span class="cx">                 FA654A631108ABB7002615E0 /* mathml.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = mathml.css; sourceTree = "<group>"; };
</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 = "<group>";
</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 "CSSKeyframeRule.cpp"
</span><span class="cx"> #include "CSSKeyframesRule.cpp"
</span><span class="cx"> #include "CSSLineBoxContainValue.cpp"
</span><ins>+#include "CSSMarkup.cpp"
</ins><span class="cx"> #include "CSSMediaRule.cpp"
</span><span class="cx"> #include "CSSNamedImageValue.cpp"
</span><del>-#include "CSSOMUtils.cpp"
</del><span class="cx"> #include "CSSPageRule.cpp"
</span><span class="cx"> #include "CSSParser.cpp"
</span><span class="cx"> #include "CSSParserValues.cpp"
</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 <webkit@nickshanks.com>
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ * 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 "config.h"
+#include "CSSMarkup.h"
+
+#include "CSSParserIdioms.h"
+#include <wtf/HexNumber.h>
+#include <wtf/text/StringBuffer.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+template <typename CharacterType>
+static inline bool isCSSTokenizerIdentifier(const CharacterType* characters, unsigned length)
+{
+ const CharacterType* end = characters + length;
+
+ // -?
+ if (characters != end && 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;
+}
+
+// "ident" from the CSS tokenizer, minus backslash-escape sequences
+static bool isCSSTokenizerIdentifier(const String& 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& appendTo)
+{
+ appendTo.append('\\');
+ appendTo.append(c);
+}
+
+static void serializeCharacterAsCodePoint(UChar32 c, StringBuilder& appendTo)
+{
+ appendTo.append('\\');
+ appendUnsignedAsHex(c, appendTo, Lowercase);
+ appendTo.append(' ');
+}
+
+void serializeIdentifier(const String& identifier, StringBuilder& appendTo, bool skipStartChecks)
+{
+ bool isFirst = !skipStartChecks;
+ bool isSecond = false;
+ bool isFirstCharHyphen = false;
+ unsigned index = 0;
+ while (index < 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 <= 0x1f || c == 0x7f || (0x30 <= c && c <= 0x39 && (isFirst || (isSecond && isFirstCharHyphen))))
+ serializeCharacterAsCodePoint(c, appendTo);
+ else if (c == 0x2d && isFirst && index == identifier.length())
+ serializeCharacter(c, appendTo);
+ else if (0x80 <= c || c == 0x2d || c == 0x5f || (0x30 <= c && c <= 0x39) || (0x41 <= c && c <= 0x5a) || (0x61 <= c && c <= 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& string, StringBuilder& appendTo)
+{
+ appendTo.append('\"');
+
+ unsigned index = 0;
+ while (index < string.length()) {
+ UChar32 c = string.characterStartingAt(index);
+ index += U16_LENGTH(c);
+
+ if (c <= 0x1f || c == 0x7f)
+ serializeCharacterAsCodePoint(c, appendTo);
+ else if (c == 0x22 || c == 0x5c)
+ serializeCharacter(c, appendTo);
+ else
+ appendTo.append(c);
+ }
+
+ appendTo.append('\"');
+}
+
+String serializeString(const String& string)
+{
+ StringBuilder builder;
+ serializeString(string, builder);
+ return builder.toString();
+}
+
+String serializeURI(const String& string)
+{
+ return "url(" + serializeString(string) + ")";
+}
+
+String serializeFontFamily(const String& 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 <eric@webkit.org>
+ * 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 <wtf/text/WTFString.h>
+
+// 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& identifier, StringBuilder& appendTo, bool skipStartChecks = false);
+void serializeString(const String&, StringBuilder& appendTo);
+String serializeString(const String&);
+String serializeURI(const String&);
+String serializeFontFamily(const String&);
+
+} // 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
- * "AS IS" 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 "config.h"
-#include "CSSOMUtils.h"
-
-#include <wtf/HexNumber.h>
-#include <wtf/text/StringBuilder.h>
-
-namespace WebCore {
-
-void serializeCharacter(UChar32 c, StringBuilder& appendTo)
-{
- appendTo.append('\\');
- appendTo.append(c);
-}
-
-void serializeCharacterAsCodePoint(UChar32 c, StringBuilder& appendTo)
-{
- appendTo.append('\\');
- appendUnsignedAsHex(c, appendTo, Lowercase);
- appendTo.append(' ');
-}
-
-void serializeIdentifier(const String& identifier, StringBuilder& appendTo)
-{
- bool isFirst = true;
- bool isSecond = false;
- bool isFirstCharHyphen = false;
- unsigned index = 0;
- while (index < 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 <= 0x1f || c == 0x7f || (0x30 <= c && c <= 0x39 && (isFirst || (isSecond && isFirstCharHyphen))))
- serializeCharacterAsCodePoint(c, appendTo);
- else if (c == 0x2d && isFirst && index == identifier.length())
- serializeCharacter(c, appendTo);
- else if (0x80 <= c || c == 0x2d || c == 0x5f || (0x30 <= c && c <= 0x39) || (0x41 <= c && c <= 0x5a) || (0x61 <= c && c <= 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& string, StringBuilder& appendTo)
-{
- appendTo.append('\"');
-
- unsigned index = 0;
- while (index < string.length()) {
- UChar32 c = string.characterStartingAt(index);
- index += U16_LENGTH(c);
- if (c <= 0x1f)
- serializeCharacterAsCodePoint(c, appendTo);
- else if (c == 0x22 || c == 0x5c)
- serializeCharacter(c, appendTo);
- else
- appendTo.append(c);
- }
-
- appendTo.append('\"');
-}
-
-} // 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
- * "AS IS" 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 <unicode/umachine.h>
-#include <wtf/Forward.h>
-
-// 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&);
-void serializeCharacterAsCodePoint(UChar32, StringBuilder&);
-void serializeIdentifier(const String& identifier, StringBuilder&);
-void serializeString(const String&, StringBuilder&);
-
-} // 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 "config.h"
</span><span class="cx"> #include "CSSSelector.h"
</span><span class="cx">
</span><del>-#include "CSSOMUtils.h"
</del><ins>+#include "CSSMarkup.h"
</ins><span class="cx"> #include "CSSSelectorList.h"
</span><span class="cx"> #include "HTMLNames.h"
</span><span class="cx"> #include "SelectorPseudoTypeMap.h"
</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 "config.h"
</span><span class="cx"> #include "DOMCSSNamespace.h"
</span><span class="cx">
</span><del>-#include "CSSOMUtils.h"
</del><ins>+#include "CSSMarkup.h"
</ins><span class="cx"> #include "CSSParser.h"
</span><span class="cx"> #include "StyleProperties.h"
</span><span class="cx"> #include <wtf/text/StringBuilder.h>
</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 <webkit@nickshanks.com>
</span><span class="cx"> * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
</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 <typename CharacterType>
</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"> // "ident" from the CSS tokenizer, minus backslash-escape sequences
</span><del>-static bool isCSSTokenizerIdentifier(const String& string)
</del><ins>+static bool isCSSTokenizerIdent(const String& 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 <typename CharacterType>
</span><span class="lines">@@ -13853,7 +13853,7 @@
</span><span class="cx">
</span><span class="cx"> String quoteCSSStringIfNeeded(const String& 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& 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
+// "AS IS" 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 "config.h"
+#include "CSSParserFastPaths.h"
+
+// FIXME-NEWPARSER: #include "CSSColorValue.h"
+#include "CSSFunctionValue.h"
+#include "CSSInheritedValue.h"
+#include "CSSInitialValue.h"
+#include "CSSParserIdioms.h"
+#include "CSSPrimitiveValue.h"
+#include "CSSPropertyParser.h"
+#include "HTMLParserIdioms.h"
+#include "RuntimeEnabledFeatures.h"
+// FIXME-NEWPARSER: #include "StyleColor.h"
+#include "StylePropertyShorthand.h"
+
+namespace WebCore {
+
+/* FIXME-NEWPARSER: Turn off for now.
+
+static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& 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 <typename CharacterType>
+static inline bool parseSimpleLength(const CharacterType* characters, unsigned length, CSSPrimitiveValue::UnitTypes& unit, double& number)
+{
+ if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
+ length -= 2;
+ unit = CSSPrimitiveValue::UnitTypes::CSS_PX;
+ } else if (length > 1 && characters[length - 1] == '%') {
+ length -= 1;
+ unit = CSSPrimitiveValue::UnitTypes::CSS_PERCENTAGE;
+ }
+
+ // We rely on charactersToDouble for validation as well. The function
+ // will set "ok" to "false" if the entire passed-in character range does
+ // not represent a double.
+ bool ok;
+ number = charactersToDouble(characters, length, &ok);
+ if (!ok)
+ return false;
+ number = clampTo<double>(number, -std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
+ return true;
+}
+
+static CSSValue* parseSimpleLengthValue(CSSPropertyID propertyId, const String& 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 < 0 && !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 <typename CharacterType>
+static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
+{
+ int length = end - string;
+ if (length < 1)
+ return 0;
+
+ bool decimalMarkSeen = false;
+ int processedLength = 0;
+
+ for (int i = 0; i < length; ++i) {
+ if (string[i] == terminator) {
+ processedLength = i;
+ break;
+ }
+ if (!isASCIIDigit(string[i])) {
+ if (!decimalMarkSeen && string[i] == '.')
+ decimalMarkSeen = true;
+ else
+ return 0;
+ }
+ }
+
+ if (decimalMarkSeen && processedLength == 1)
+ return 0;
+
+ return processedLength;
+}
+
+// Returns the number of characters consumed for parsing a valid double
+// terminated by the given terminator character
+template <typename CharacterType>
+static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& 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 < 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 < length && scale < maxScale) {
+ fraction = fraction * 10 + string[position++] - '0';
+ scale *= 10;
+ }
+
+ value = localValue + fraction / scale;
+ return length;
+}
+
+template <typename CharacterType>
+static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
+{
+ const CharacterType* current = string;
+ double localValue = 0;
+ bool negative = false;
+ while (current != end && isHTMLSpace<CharacterType>(*current))
+ current++;
+ if (current != end && *current == '-') {
+ negative = true;
+ current++;
+ }
+ if (current == end || !isASCIIDigit(*current))
+ return false;
+ while (current != end && isASCIIDigit(*current)) {
+ double newValue = localValue * 10 + *current++ - '0';
+ if (newValue >= 255) {
+ // Clamp values at 255.
+ localValue = 255;
+ while (current != end && isASCIIDigit(*current))
+ ++current;
+ break;
+ }
+ localValue = newValue;
+ }
+
+ if (current == end)
+ return false;
+
+ if (expect == CSSPrimitiveValue::UnitTypes::Number && (*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 && *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 > 255)
+ localValue = 255;
+ current++;
+ } else {
+ expect = CSSPrimitiveValue::UnitTypes::Number;
+ }
+
+ while (current != end && isHTMLSpace<CharacterType>(*current))
+ current++;
+ if (current == end || *current++ != terminator)
+ return false;
+ // Clamp negative values at zero.
+ value = negative ? 0 : static_cast<int>(localValue);
+ string = current;
+ return true;
+}
+
+template <typename CharacterType>
+static inline bool isTenthAlpha(const CharacterType* string, const int length)
+{
+ // "0.X"
+ if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
+ return true;
+
+ // ".X"
+ if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
+ return true;
+
+ return false;
+}
+
+template <typename CharacterType>
+static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
+{
+ while (string != end && isHTMLSpace<CharacterType>(*string))
+ string++;
+
+ bool negative = false;
+
+ if (string != end && *string == '-') {
+ negative = true;
+ string++;
+ }
+
+ value = 0;
+
+ int length = end - string;
+ if (length < 2)
+ return false;
+
+ if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
+ return false;
+
+ if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
+ if (checkForValidDouble(string, end, terminator)) {
+ value = negative ? 0 : 255;
+ string = end;
+ return true;
+ }
+ return false;
+ }
+
+ if (length == 2 && string[0] != '.') {
+ value = !negative && 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<int>(alpha * nextafter(256.0, 0.0));
+ string = end;
+ return true;
+}
+
+template <typename CharacterType>
+static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
+{
+ if (length < 5)
+ return false;
+ return characters[4] == '('
+ && isASCIIAlphaCaselessEqual(characters[0], 'r')
+ && isASCIIAlphaCaselessEqual(characters[1], 'g')
+ && isASCIIAlphaCaselessEqual(characters[2], 'b')
+ && isASCIIAlphaCaselessEqual(characters[3], 'a');
+}
+
+template <typename CharacterType>
+static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
+{
+ if (length < 4)
+ return false;
+ return characters[3] == '('
+ && isASCIIAlphaCaselessEqual(characters[0], 'r')
+ && isASCIIAlphaCaselessEqual(characters[1], 'g')
+ && isASCIIAlphaCaselessEqual(characters[2], 'b');
+}
+
+template <typename CharacterType>
+static bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length, bool quirksMode)
+{
+ CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::UnitTypes::Unknown;
+
+ if (length >= 4 && characters[0] == '#')
+ return Color::parseHexColor(characters + 1, length - 1, rgb);
+
+ if (quirksMode && (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& 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 >= CSSValueBeforeEdge && valueID <= 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: // <border-style>
+ 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 >= CSSValueNone && valueID <= 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 >= CSSValueInline && valueID <= CSSValueInlineFlex) || valueID == CSSValueWebkitFlex || valueID == CSSValueWebkitInlineFlex || valueID == CSSValueNone
+ || (RuntimeEnabledFeatures::cssGridLayoutEnabled() && (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 >= CSSValueUseScript && valueID <= CSSValueResetSize)
+ || (valueID >= CSSValueCentral && valueID <= 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 >= CSSValueUltraCondensed && valueID <= 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 >= CSSValueDisc && valueID <= 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: // (<border-style> except hidden) | auto
+ return valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= 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 >= CSSValueVisiblePainted && valueID <= CSSValueBoundingBox);
+ case CSSPropertyPosition: // static | relative | absolute | fixed | sticky
+ return valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed || (RuntimeEnabledFeatures::cssStickyPositionEnabled() && 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 >= CSSValueWebkitAuto && valueID <= CSSValueInternalCenter) || valueID == CSSValueStart || valueID == CSSValueEnd;
+ case CSSPropertyTextAlignLast:
+ // auto | start | end | left | right | center | justify
+ return (valueID >= CSSValueLeft && valueID <= 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 >= CSSValueCapitalize && valueID <= 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 >= CSSValueDrag && valueID <= CSSValueNoDrag;
+ case CSSPropertyWebkitAppearance:
+ return (valueID >= CSSValueCheckbox && valueID <= 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 <overflow-position>. 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 <overflow-position>. 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 >= CSSValueHorizontalTb && valueID <= 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& string, CSSParserMode parserMode)
+{
+ ASSERT(!string.isEmpty());
+
+ if (!CSSParserFastPaths::isKeywordPropertyID(propertyId)) {
+ // All properties accept the values of "initial" and "inherit".
+ if (!equalIgnoringASCIICase(string, "initial") && !equalIgnoringASCIICase(string, "inherit"))
+ 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 <typename CharType>
+static bool parseTransformTranslateArguments(CharType*& 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<unsigned>(delimiter);
+ CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::UnitTypes::Number;
+ double number;
+ if (!parseSimpleLength(pos, argumentLength, unit, number))
+ return false;
+ if (unit != CSSPrimitiveValue::UnitTypes::Pixels && (number || unit != CSSPrimitiveValue::UnitTypes::Number))
+ return false;
+ transformValue->append(*CSSPrimitiveValue::create(number, CSSPrimitiveValue::UnitTypes::Pixels));
+ pos += argumentLength + 1;
+ --expectedCount;
+ }
+ return true;
+}
+
+template <typename CharType>
+static bool parseTransformNumberArguments(CharType*& 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<unsigned>(delimiter);
+ bool ok;
+ double number = charactersToDouble(pos, argumentLength, &ok);
+ if (!ok)
+ return false;
+ transformValue->append(*CSSPrimitiveValue::create(number, CSSPrimitiveValue::UnitTypes::Number));
+ pos += argumentLength + 1;
+ --expectedCount;
+ }
+ return true;
+}
+
+static const int kShortestValidTransformStringLength = 12;
+
+template <typename CharType>
+static CSSFunctionValue* parseSimpleTransformValue(CharType*& pos, CharType* end)
+{
+ if (end - pos < kShortestValidTransformStringLength)
+ return nullptr;
+
+ const bool isTranslate = toASCIILower(pos[0]) == 't'
+ && toASCIILower(pos[1]) == 'r'
+ && toASCIILower(pos[2]) == 'a'
+ && toASCIILower(pos[3]) == 'n'
+ && toASCIILower(pos[4]) == 's'
+ && toASCIILower(pos[5]) == 'l'
+ && toASCIILower(pos[6]) == 'a'
+ && toASCIILower(pos[7]) == 't'
+ && toASCIILower(pos[8]) == 'e';
+
+ if (isTranslate) {
+ CSSValueID transformType;
+ unsigned expectedArgumentCount = 1;
+ unsigned argumentStart = 11;
+ CharType c9 = toASCIILower(pos[9]);
+ if (c9 == 'x' && pos[10] == '(') {
+ transformType = CSSValueTranslateX;
+ } else if (c9 == 'y' && pos[10] == '(') {
+ transformType = CSSValueTranslateY;
+ } else if (c9 == 'z' && pos[10] == '(') {
+ transformType = CSSValueTranslateZ;
+ } else if (c9 == '(') {
+ transformType = CSSValueTranslate;
+ expectedArgumentCount = 2;
+ argumentStart = 10;
+ } else if (c9 == '3' && toASCIILower(pos[10]) == 'd' && 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'
+ && toASCIILower(pos[1]) == 'a'
+ && toASCIILower(pos[2]) == 't'
+ && toASCIILower(pos[3]) == 'r'
+ && toASCIILower(pos[4]) == 'i'
+ && toASCIILower(pos[5]) == 'x'
+ && pos[6] == '3'
+ && toASCIILower(pos[7]) == 'd'
+ && 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'
+ && toASCIILower(pos[1]) == 'c'
+ && toASCIILower(pos[2]) == 'a'
+ && toASCIILower(pos[3]) == 'l'
+ && toASCIILower(pos[4]) == 'e'
+ && pos[5] == '3'
+ && toASCIILower(pos[6]) == 'd'
+ && pos[7] == '(';
+
+ if (isScale3d) {
+ pos += 8;
+ CSSFunctionValue* transformValue = CSSFunctionValue::create(CSSValueScale3d);
+ if (!parseTransformNumberArguments(pos, end, 3, transformValue))
+ return nullptr;
+ return transformValue;
+ }
+
+ return nullptr;
+}
+
+template <typename CharType>
+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->double
+ // conversions in parseSimpleTransformValue only to discard them when we
+ // run into a transform component we don't understand.
+ unsigned i = 0;
+ while (i < length) {
+ if (isCSSSpace(chars[i])) {
+ ++i;
+ continue;
+ }
+ if (length - i < 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 <typename CharType>
+static CSSValueList* parseSimpleTransformList(const CharType* chars, unsigned length)
+{
+ if (!transformCanLikelyUseFastPath(chars, length))
+ return nullptr;
+ const CharType*& pos = chars;
+ const CharType* end = chars + length;
+ CSSValueList* transformList = nullptr;
+ while (pos < end) {
+ while (pos < end && isCSSSpace(*pos))
+ ++pos;
+ if (pos >= end)
+ break;
+ CSSFunctionValue* transformValue = parseSimpleTransformValue(pos, end);
+ if (!transformValue)
+ return nullptr;
+ if (!transformList)
+ transformList = CSSValueList::createSpaceSeparated();
+ transformList->append(*transformValue);
+ }
+ return transformList;
+}
+
+static CSSValue* parseSimpleTransform(CSSPropertyID propertyID, const String& 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& 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
+// "AS IS" 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 "CSSParserMode.h"
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include <wtf/text/WTFString.h>
+
+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&, 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&, 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
+ * "AS IS" 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 <wtf/ASCIICType.h>
+
+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 <typename CharacterType>
+bool isNameStartCodePoint(CharacterType c)
+{
+ return isASCIIAlpha(c) || c == '_' || !isASCII(c);
+}
+
+// http://dev.w3.org/csswg/css-syntax/#name-code-point
+template <typename CharacterType>
+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 <eric@webkit.org>
+ * 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 "CSSPropertySourceData.h"
+#include "StyleRule.h"
+#include <wtf/Vector.h>
+
+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
+// "AS IS" 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 "config.h"
+#include "CSSParserObserverWrapper.h"
+
+#include "CSSParserTokenRange.h"
+
+namespace WebCore {
+
+unsigned CSSParserObserverWrapper::startOffset(const CSSParserTokenRange& range)
+{
+ return m_tokenOffsets[range.begin() - m_firstParserToken];
+}
+
+unsigned CSSParserObserverWrapper::previousTokenStartOffset(const CSSParserTokenRange& range)
+{
+ if (range.begin() == m_firstParserToken)
+ return 0;
+ return m_tokenOffsets[range.begin() - m_firstParserToken - 1];
+}
+
+unsigned CSSParserObserverWrapper::endOffset(const CSSParserTokenRange& range)
+{
+ return m_tokenOffsets[range.end() - m_firstParserToken];
+}
+
+void CSSParserObserverWrapper::skipCommentsBefore(const CSSParserTokenRange& range, bool leaveDirectlyBefore)
+{
+ unsigned startIndex = range.begin() - m_firstParserToken;
+ if (!leaveDirectlyBefore)
+ startIndex++;
+ while (m_commentIterator < m_commentOffsets.end() && m_commentIterator->tokensBefore < startIndex)
+ m_commentIterator++;
+}
+
+void CSSParserObserverWrapper::yieldCommentsBefore(const CSSParserTokenRange& range)
+{
+ unsigned startIndex = range.begin() - m_firstParserToken;
+ while (m_commentIterator < m_commentOffsets.end() && m_commentIterator->tokensBefore <= startIndex) {
+ m_observer.observeComment(m_commentIterator->startOffset, m_commentIterator->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
+// "AS IS" 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 "CSSParserObserver.h"
+
+namespace WebCore {
+
+class CSSParserObserverWrapper {
+public:
+ explicit CSSParserObserverWrapper(CSSParserObserver& observer)
+ : m_observer(observer)
+ { }
+
+ unsigned startOffset(const CSSParserTokenRange&);
+ unsigned previousTokenStartOffset(const CSSParserTokenRange&);
+ unsigned endOffset(const CSSParserTokenRange&); // Includes trailing comments
+
+ void skipCommentsBefore(const CSSParserTokenRange&, bool leaveDirectlyBefore);
+ void yieldCommentsBefore(const CSSParserTokenRange&);
+
+ CSSParserObserver& 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& m_observer;
+ Vector<unsigned> m_tokenOffsets;
+ CSSParserToken* m_firstParserToken;
+
+ struct CommentPosition {
+ unsigned startOffset;
+ unsigned endOffset;
+ unsigned tokensBefore;
+ };
+
+ Vector<CommentPosition> m_commentOffsets;
+ Vector<CommentPosition>::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
+// "AS IS" 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 "config.h"
+#include "CSSParserToken.h"
+
+#include "CSSMarkup.h"
+#include "CSSPrimitiveValue.h"
+#include "CSSPropertyParser.h"
+#include <limits.h>
+#include <wtf/HashMap.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+template<typename CharacterType>
+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' && 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' && toASCIILower(data[2]) == 'a' && toASCIILower(data[3]) == 'd')
+ return CSSPrimitiveValue::UnitTypes::CSS_GRAD;
+ break;
+ case 't':
+ if (toASCIILower(data[1]) == 'u' && toASCIILower(data[2]) == 'r' && 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]) == '_' && toASCIILower(data[2]) == 'q' && toASCIILower(data[3]) == 'e' && 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<unsigned>(CSSPrimitiveValue::UnitTypes::CSS_NUMBER))
+{
+ ASSERT(type == NumberToken);
+ m_numericValue = clampTo<double>(numericValue, -std::numeric_limits<float>::max(), std::numeric_limits<float>::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<unsigned>(stringToUnitType(unit));
+}
+
+void CSSParserToken::convertToPercentage()
+{
+ ASSERT(m_type == NumberToken);
+ m_type = PercentageToken;
+ m_unit = static_cast<unsigned>(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 <an+b> parsing on NumberTokens.
+ ASSERT(m_type == NumberToken);
+ return static_cast<NumericSign>(m_numericSign);
+}
+
+NumericValueType CSSParserToken::numericValueType() const
+{
+ ASSERT(m_type == NumberToken || m_type == PercentageToken || m_type == DimensionToken);
+ return static_cast<NumericValueType>(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 < 0)
+ m_id = cssValueKeywordID(value());
+ return static_cast<CSSValueID>(m_id);
+}
+
+CSSValueID CSSParserToken::functionId() const
+{
+ if (m_type != FunctionToken)
+ return CSSValueInvalid;
+ if (m_id < 0)
+ m_id = cssValueKeywordID(value());
+ return static_cast<CSSValueID>(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& string) const
+{
+ CSSParserToken copy(*this);
+ copy.initValueFromStringView(string);
+ return copy;
+}
+
+bool CSSParserToken::valueDataCharRawEqual(const CSSParserToken& other) const
+{
+ if (m_valueLength != other.m_valueLength)
+ return false;
+
+ if (m_valueDataCharRaw == other.m_valueDataCharRaw && m_valueIs8Bit == other.m_valueIs8Bit)
+ return true;
+
+ if (m_valueIs8Bit)
+ return other.m_valueIs8Bit ? equal(static_cast<const LChar*>(m_valueDataCharRaw), static_cast<const LChar*>(other.m_valueDataCharRaw), m_valueLength) : equal(static_cast<const LChar*>(m_valueDataCharRaw), static_cast<const UChar*>(other.m_valueDataCharRaw), m_valueLength);
+
+ return other.m_valueIs8Bit ? equal(static_cast<const UChar*>(m_valueDataCharRaw), static_cast<const LChar*>(other.m_valueDataCharRaw), m_valueLength) : equal(static_cast<const UChar*>(m_valueDataCharRaw), static_cast<const UChar*>(other.m_valueDataCharRaw), m_valueLength);
+}
+
+bool CSSParserToken::operator==(const CSSParserToken& 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 && m_numericValue == other.m_numericValue && m_numericValueType == other.m_numericValueType;
+ case UnicodeRangeToken:
+ return m_unicodeRange.start == other.m_unicodeRange.start && m_unicodeRange.end == other.m_unicodeRange.end;
+ default:
+ return true;
+ }
+}
+
+void CSSParserToken::serialize(StringBuilder& 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("url(");
+ serializeIdentifier(value().toString(), builder);
+ return builder.append(')');
+ case DelimiterToken:
+ if (delimiter() == '\\')
+ return builder.append("\\\n");
+ 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("U+%X-%X", unicodeRangeStart(), unicodeRangeEnd()));
+ case StringToken:
+ return serializeString(value().toString(), builder);
+
+ case IncludeMatchToken:
+ return builder.append("~=");
+ case DashMatchToken:
+ return builder.append("|=");
+ case PrefixMatchToken:
+ return builder.append("^=");
+ case SuffixMatchToken:
+ return builder.append("$=");
+ case SubstringMatchToken:
+ return builder.append("*=");
+ case ColumnToken:
+ return builder.append("||");
+ case CDOToken:
+ return builder.append("<!--");
+ case CDCToken:
+ return builder.append("-->");
+ case BadStringToken:
+ return builder.append("'\n");
+ case BadUrlToken:
+ return builder.append("url(()");
+ 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
+// "AS IS" 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 "CSSPrimitiveValue.h"
+#include <wtf/text/StringView.h>
+
+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& other) const;
+ bool operator!=(const CSSParserToken& other) const { return !(*this == other); }
+
+ // Converts NumberToken to DimensionToken.
+ void convertToDimensionWithUnit(StringView);
+
+ // Converts NumberToken to PercentageToken.
+ void convertToPercentage();
+
+ CSSParserTokenType type() const { return static_cast<CSSParserTokenType>(m_type); }
+ StringView value() const
+ {
+ if (m_valueIs8Bit)
+ return StringView(reinterpret_cast<const LChar*>(m_valueDataCharRaw), m_valueLength);
+ return StringView(reinterpret_cast<const UChar*>(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<BlockType>(m_blockType); }
+ CSSPrimitiveValue::UnitTypes unitType() const { return static_cast<CSSPrimitiveValue::UnitTypes>(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&) const;
+
+ CSSParserToken copyWithUpdatedString(const StringView&) const;
+
+private:
+ void initValueFromStringView(StringView string)
+ {
+ m_valueLength = string.length();
+ m_valueIs8Bit = string.is8Bit();
+ m_valueDataCharRaw = m_valueIs8Bit ? static_cast<const void*>(string.characters8()) : static_cast<const void*>(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& 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
+// "AS IS" 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 "config.h"
+#include "CSSParserTokenRange.h"
+
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+CSSParserToken& CSSParserTokenRange::eofToken()
+{
+ static NeverDestroyed<CSSParserToken> eofToken(EOFToken);
+ return eofToken.get();
+}
+
+CSSParserTokenRange CSSParserTokenRange::makeSubRange(const CSSParserToken* first, const CSSParserToken* last) const
+{
+ if (first == &eofToken())
+ first = m_last;
+ if (last == &eofToken())
+ last = m_last;
+ ASSERT(first <= last);
+ return CSSParserTokenRange(first, last);
+}
+
+CSSParserTokenRange CSSParserTokenRange::consumeBlock()
+{
+ ASSERT(peek().getBlockType() == CSSParserToken::BlockStart);
+ const CSSParserToken* start = &peek() + 1;
+ unsigned nestingLevel = 0;
+ do {
+ const CSSParserToken& token = consume();
+ if (token.getBlockType() == CSSParserToken::BlockStart)
+ nestingLevel++;
+ else if (token.getBlockType() == CSSParserToken::BlockEnd)
+ nestingLevel--;
+ } while (nestingLevel && m_first < 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& token = consume();
+ if (token.getBlockType() == CSSParserToken::BlockStart)
+ nestingLevel++;
+ else if (token.getBlockType() == CSSParserToken::BlockEnd)
+ nestingLevel--;
+ } while (nestingLevel && m_first < 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 < m_last; ++it)
+ it->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
+// "AS IS" 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 "CSSParserToken.h"
+#include <wtf/Vector.h>
+
+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<size_t inlineBuffer>
+ CSSParserTokenRange(const Vector<CSSParserToken, inlineBuffer>& 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& peek(unsigned offset = 0) const
+ {
+ if (m_first + offset >= m_last)
+ return eofToken();
+ return *(m_first + offset);
+ }
+
+ const CSSParserToken& consume()
+ {
+ if (m_first == m_last)
+ return eofToken();
+ return *m_first++;
+ }
+
+ const CSSParserToken& consumeIncludingWhitespace()
+ {
+ const CSSParserToken& 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& 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
+// "AS IS" 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 "config.h"
+#include "CSSPropertyParser.h"
+
+#include "CSSBasicShapes.h"
+#include "CSSBorderImage.h"
+#include "CSSContentDistributionValue.h"
+#include "CSSCursorImageValue.h"
+// FIXME-NEWPARSER #include "CSSCustomIdentValue.h"
+#include "CSSFontFaceSrcValue.h"
+// FIXME-NEWPARSER #include "CSSFontFamilyValue.h"
+#include "CSSFontFeatureValue.h"
+#include "CSSFunctionValue.h"
+#include "CSSGridAutoRepeatValue.h"
+#include "CSSGridLineNamesValue.h"
+#include "CSSGridTemplateAreasValue.h"
+#include "CSSInheritedValue.h"
+#include "CSSInitialValue.h"
+#include "CSSParserFastPaths.h"
+#include "CSSParserIdioms.h"
+// FIXME-NEWPARSER #include "CSSPathValue.h"
+// FIXME-NEWPARSER #include "CSSPendingSubstitutionValue.h"
+#include "CSSPrimitiveValueMappings.h"
+#include "CSSPropertyParserHelpers.h"
+// FIXME-NEWPARSER #include "CSSQuadValue.h"
+#include "CSSReflectValue.h"
+#include "CSSShadowValue.h"
+// FIXME-NEWPARSER #include "CSSStringValue.h"
+#include "CSSTimingFunctionValue.h"
+// FIXME-NEWPARSER #include "CSSURIValue.h"
+#include "CSSUnicodeRangeValue.h"
+#include "CSSUnsetValue.h"
+// FIXME-NEWPARSER #include "CSSValuePair.h"
+// FIXME-NEWPARSER #include "CSSVariableReferenceValue.h"
+// FIXME-NEWPARSER #include "CSSVariableParser.h"
+#include "Counter.h"
+#include "FontFace.h"
+#include "HashTools.h"
+#include "RenderTheme.h"
+#include "RuntimeEnabledFeatures.h"
+#include "SVGPathUtilities.h"
+#include "StylePropertyShorthand.h"
+#include <memory>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+static bool hasPrefix(const char* string, unsigned length, const char* prefix)
+{
+ for (unsigned i = 0; i < 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*& propertyNameAlias, unsigned& newLength)
+{
+ if (!strcmp(propertyName, "-webkit-hyphenate-locale")) {
+ // Worked in iOS 4.2.
+ static const char webkitLocale[] = "-webkit-locale";
+ propertyNameAlias = webkitLocale;
+ newLength = strlen(webkitLocale);
+ }
+}
+#endif
+
+template <typename CharacterType>
+static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
+{
+ char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
+
+ for (unsigned i = 0; i != length; ++i) {
+ CharacterType c = propertyName[i];
+ if (!c || c >= 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()
+ && (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-"))) {
+ memmove(buffer + 7, buffer + 6, length + 1 - 6);
+ memcpy(buffer, "-webkit", 7);
+ ++length;
+ }
+#endif
+#if PLATFORM(IOS)
+ cssPropertyNameIOSAliasing(buffer, name, length);
+#endif
+ }
+
+ const Property* hashTableEntry = findProperty(name, length);
+ return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
+}
+
+static bool isAppleLegacyCssValueKeyword(const char* valueKeyword, unsigned length)
+{
+ static const char applePrefix[] = "-apple-";
+ static const char appleSystemPrefix[] = "-apple-system";
+ static const char* appleWirelessPlaybackTargetActive = getValueName(CSSValueAppleWirelessPlaybackTargetActive);
+
+ return hasPrefix(valueKeyword, length, applePrefix)
+ && !hasPrefix(valueKeyword, length, appleSystemPrefix)
+ && !WTF::equal(reinterpret_cast<const LChar*>(valueKeyword), reinterpret_cast<const LChar*>(appleWirelessPlaybackTargetActive), length);
+}
+
+template <typename CharacterType>
+static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
+{
+ char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
+
+ for (unsigned i = 0; i != length; ++i) {
+ CharacterType c = valueKeyword[i];
+ if (!c || c >= 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, "-khtml-")) {
+ memmove(buffer + 7, buffer + 6, length + 1 - 6);
+ memcpy(buffer, "-webkit", 7);
+ ++length;
+ }
+ }
+
+ const Value* hashTableEntry = findValue(buffer, length);
+ return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
+}
+
+CSSValueID cssValueKeywordID(StringView string)
+{
+ unsigned length = string.length();
+ if (!length)
+ return CSSValueInvalid;
+ if (length > 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 > 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& range,
+ const CSSParserContext& context, Vector<CSSProperty, 256>* parsedProperties)
+ : m_range(range)
+ , m_context(context)
+ , m_parsedProperties(parsedProperties)
+{
+ m_range.consumeWhitespace();
+}
+
+void CSSPropertyParser::addProperty(CSSPropertyID property, CSSPropertyID currentShorthand, const CSSValue& value, bool important, bool implicit)
+{
+ ASSERT(!isPropertyAlias(property));
+
+ int shorthandIndex = 0;
+ bool setFromShorthand = false;
+
+ if (currentShorthand) {
+ Vector<StylePropertyShorthand, 4> shorthands;
+ getMatchingShorthandsForLonghand(property, &shorthands);
+ setFromShorthand = true;
+ if (shorthands.size() > 1)
+ shorthandIndex = indexOfShorthandForLonghand(currentShorthand, shorthands);
+ }
+
+ m_parsedProperties->append(CSSProperty(property, value, important, setFromShorthand, shorthandIndex, implicit));
+}
+
+void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID property, const CSSValue& value, bool important)
+{
+ const StylePropertyShorthand& shorthand = shorthandForProperty(property);
+ unsigned shorthandLength = shorthand.length();
+ ASSERT(shorthandLength);
+ const CSSPropertyID* longhands = shorthand.properties();
+ for (unsigned i = 0; i < shorthandLength; ++i)
+ addProperty(longhands[i], property, value, important);
+}
+
+bool CSSPropertyParser::parseValue(CSSPropertyID unresolvedProperty, bool important,
+ const CSSParserTokenRange& range, const CSSParserContext& context,
+ Vector<CSSProperty, 256>& parsedProperties, StyleRule::Type ruleType)
+{
+ int parsedPropertiesSize = parsedProperties.size();
+
+ CSSPropertyParser parser(range, context, &parsedProperties);
+ CSSPropertyID resolvedProperty = resolveCSSPropertyID(unresolvedProperty);
+ bool parseSuccess;
+
+ if (ruleType == StyleRule::Viewport) {
+ parseSuccess = (RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(context.mode()))
+ && 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 && context.useCounter())
+ context.useCounter()->count(context.mode(), unresolvedProperty);
+
+ if (!parseSuccess)
+ parsedProperties.shrink(parsedPropertiesSize);
+
+ return parseSuccess;
+}
+
+const CSSValue* CSSPropertyParser::parseSingleValue(
+ CSSPropertyID property, const CSSParserTokenRange& range, const CSSParserContext& 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() && CSSVariableParser::containsValidVariableReferences(originalRange)) {
+ CSSVariableReferenceValue* variable = CSSVariableReferenceValue::create(CSSVariableData::create(originalRange));
+
+ if (isShorthand) {
+ const CSSPendingSubstitutionValue& 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& 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& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+ CSSValue* resultX = nullptr;
+ CSSValue* resultY = nullptr;
+ if (consumeOneOrTwoValuedPosition(range, cssParserMode, unitless, resultX, resultY)) {
+ CSSValueList* list = CSSValueList::createSpaceSeparated();
+ list->append(*resultX);
+ list->append(*resultY);
+ CSSValue* resultZ = consumeLength(range, cssParserMode, ValueRangeAll);
+ if (!resultZ)
+ resultZ = CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitType::Pixels);
+ list->append(*resultZ);
+ return list;
+ }
+ return nullptr;
+}
+
+// Methods for consuming non-shorthand properties starts here.
+static CSSValue* consumeWillChange(CSSParserTokenRange& 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 "all" is used by both CSSValue and CSSPropertyValue.
+ // Need to return nullptr when currentValue is CSSPropertyAll.
+ if (unresolvedProperty == CSSPropertyWillChange || unresolvedProperty == CSSPropertyAll)
+ return nullptr;
+ values->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->append(*consumeIdent(range));
+ break;
+ default:
+ range.consumeIncludingWhitespace();
+ break;
+ }
+ }
+
+ if (range.atEnd())
+ break;
+ if (!consumeCommaIncludingWhitespace(range))
+ return nullptr;
+ }
+
+ return values;
+}
+
+static CSSFontFeatureValue* consumeFontFeatureTag(CSSParserTokenRange& range)
+{
+ // Feature tag name consists of 4-letter characters.
+ static const unsigned tagNameLength = 4;
+
+ const CSSParserToken& 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 < 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 < 0x20 || character > 0x7E)
+ return nullptr;
+ }
+
+ int tagValue = 1;
+ // Feature tag values could follow: <integer> | on | off
+ if (range.peek().type() == NumberToken && range.peek().numericValueType() == IntegerValueType && range.peek().numericValue() >= 0) {
+ tagValue = clampTo<int>(range.consumeIncludingWhitespace().numericValue());
+ if (tagValue < 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& range)
+{
+ if (range.peek().id() == CSSValueNormal)
+ return consumeIdent(range);
+ CSSValueList* settings = CSSValueList::createCommaSeparated();
+ do {
+ CSSFontFeatureValue* fontFeatureValue = consumeFontFeatureTag(range);
+ if (!fontFeatureValue)
+ return nullptr;
+ settings->append(*fontFeatureValue);
+ } while (consumeCommaIncludingWhitespace(range));
+ return settings;
+}
+
+static CSSValue* consumePage(CSSParserTokenRange& range)
+{
+ if (range.peek().id() == CSSValueAuto)
+ return consumeIdent(range);
+ return consumeCustomIdent(range);
+}
+
+static CSSValue* consumeQuotes(CSSParserTokenRange& 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->append(*parsedValue);
+ }
+ if (values->length() && values->length() % 2 == 0)
+ return values;
+ return nullptr;
+}
+
+static CSSValue* consumeWebkitHighlight(CSSParserTokenRange& 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& 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->append(*consumeIdent(range));
+ return ParseResult::ConsumedValue;
+ }
+
+ CSSValue* finalizeValue()
+ {
+ if (!m_result->length())
+ return CSSPrimitiveValue::createIdentifier(CSSValueNormal);
+ return m_result.release();
+ }
+
+private:
+ bool m_sawCommonLigaturesValue;
+ bool m_sawDiscretionaryLigaturesValue;
+ bool m_sawHistoricalLigaturesValue;
+ bool m_sawContextualLigaturesValue;
+ Member<CSSValueList> m_result;
+};
+
+static CSSValue* consumeFontVariantLigatures(CSSParserTokenRange& 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& range)
+{
+ return consumeIdent<CSSValueNormal, CSSValueSmallCaps, CSSValueAllSmallCaps,
+ CSSValuePetiteCaps, CSSValueAllPetiteCaps,
+ CSSValueUnicase, CSSValueTitlingCaps>(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& 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->append(*consumeIdent(range));
+ return ParseResult::ConsumedValue;
+ }
+
+ CSSValue* finalizeValue()
+ {
+ if (!m_result->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<CSSValueList> m_result;
+};
+
+static CSSValue* consumeFontVariantNumeric(CSSParserTokenRange& 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& range)
+{
+ return consumeIdent<CSSValueNormal, CSSValueSmallCaps>(range);
+}
+
+static CSSValue* consumeFontVariantList(CSSParserTokenRange& 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->length())
+ return nullptr;
+ return consumeIdent(range);
+ }
+ CSSPrimitiveValue* fontVariant = consumeFontVariantCSS21(range);
+ if (fontVariant)
+ values->append(*fontVariant);
+ } while (consumeCommaIncludingWhitespace(range));
+
+ if (values->length())
+ return values;
+
+ return nullptr;
+}
+
+static CSSPrimitiveValue* consumeFontWeight(CSSParserTokenRange& range)
+{
+ const CSSParserToken& token = range.peek();
+ if (token.id() >= CSSValueNormal && token.id() <= CSSValueLighter)
+ return consumeIdent(range);
+ if (token.type() != NumberToken || token.numericValueType() != IntegerValueType)
+ return nullptr;
+ int weight = static_cast<int>(token.numericValue());
+ if ((weight % 100) || weight < 100 || weight > 900)
+ return nullptr;
+ range.consumeIncludingWhitespace();
+ return CSSPrimitiveValue::createIdentifier(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1));
+}
+
+static String concatenateFamilyName(CSSParserTokenRange& range)
+{
+ StringBuilder builder;
+ bool addedSpace = false;
+ const CSSParserToken& firstToken = range.peek();
+ while (range.peek().type() == IdentToken) {
+ if (!builder.isEmpty()) {
+ builder.append(' ');
+ addedSpace = true;
+ }
+ builder.append(range.consumeIncludingWhitespace().value());
+ }
+ if (!addedSpace && isCSSWideKeyword(firstToken.id()))
+ return String();
+ return builder.toString();
+}
+
+static CSSValue* consumeFamilyName(CSSParserTokenRange& 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& range)
+{
+ return consumeIdentRange(range, CSSValueSerif, CSSValueWebkitBody);
+}
+
+static CSSValueList* consumeFontFamily(CSSParserTokenRange& range)
+{
+ CSSValueList* list = CSSValueList::createCommaSeparated();
+ do {
+ CSSValue* parsedValue = consumeGenericFamily(range);
+ if (parsedValue) {
+ list->append(*parsedValue);
+ } else {
+ parsedValue = consumeFamilyName(range);
+ if (parsedValue) {
+ list->append(*parsedValue);
+ } else {
+ return nullptr;
+ }
+ }
+ } while (consumeCommaIncludingWhitespace(range));
+ return list;
+}
+
+static CSSValue* consumeSpacing(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ if (range.peek().id() == CSSValueNormal)
+ return consumeIdent(range);
+ // FIXME: allow <percentage>s in word-spacing.
+ return consumeLength(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
+}
+
+static CSSValue* consumeTabSize(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ CSSPrimitiveValue* parsedValue = consumeInteger(range, 0);
+ if (parsedValue)
+ return parsedValue;
+ return consumeLength(range, cssParserMode, ValueRangeNonNegative);
+}
+
+static CSSValue* consumeTextSizeAdjust(CSSParserTokenRange& 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& range, CSSParserMode cssParserMode, UnitlessQuirk unitless = UnitlessQuirk::Forbid)
+{
+ if (range.peek().id() >= CSSValueXxSmall && range.peek().id() <= CSSValueLarger)
+ return consumeIdent(range);
+ return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative, unitless);
+}
+
+static CSSPrimitiveValue* consumeLineHeight(CSSParserTokenRange& 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& range)
+{
+ ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled());
+ CSSValueList* list = CSSValueList::createSpaceSeparated();
+
+ CSSValue* rotation = consumeAngle(range);
+ if (!rotation)
+ return nullptr;
+ list->append(*rotation);
+
+ if (range.atEnd())
+ return list;
+
+ for (unsigned i = 0; i < 3; i++) { // 3 dimensions of rotation
+ CSSValue* dimension = consumeNumber(range, ValueRangeAll);
+ if (!dimension)
+ return nullptr;
+ list->append(*dimension);
+ }
+
+ return list;
+}
+
+static CSSValueList* consumeScale(CSSParserTokenRange& range)
+{
+ ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled());
+
+ CSSValue* scale = consumeNumber(range, ValueRangeAll);
+ if (!scale)
+ return nullptr;
+ CSSValueList* list = CSSValueList::createSpaceSeparated();
+ list->append(*scale);
+ scale = consumeNumber(range, ValueRangeAll);
+ if (scale) {
+ list->append(*scale);
+ scale = consumeNumber(range, ValueRangeAll);
+ if (scale)
+ list->append(*scale);
+ }
+
+ return list;
+}
+
+static CSSValueList* consumeTranslate(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled());
+ CSSValue* translate = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
+ if (!translate)
+ return nullptr;
+ CSSValueList* list = CSSValueList::createSpaceSeparated();
+ list->append(*translate);
+ translate = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
+ if (translate) {
+ list->append(*translate);
+ translate = consumeLength(range, cssParserMode, ValueRangeAll);
+ if (translate)
+ list->append(*translate);
+ }
+
+ return list;
+}
+
+static CSSValue* consumeCounter(CSSParserTokenRange& 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<int>(counterValue->getDoubleValue());
+ list->append(*CSSValuePair::create(counterName,
+ CSSPrimitiveValue::create(i, CSSPrimitiveValue::UnitType::Integer),
+ CSSValuePair::DropIdenticalValues));
+ } while (!range.atEnd());
+ return list;
+}
+
+static CSSValue* consumePageSize(CSSParserTokenRange& range)
+{
+ return consumeIdent<CSSValueA3, CSSValueA4, CSSValueA5, CSSValueB4, CSSValueB5, CSSValueLedger, CSSValueLegal, CSSValueLetter>(range);
+}
+
+static CSSValueList* consumeSize(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ CSSValueList* result = CSSValueList::createSpaceSeparated();
+
+ if (range.peek().id() == CSSValueAuto) {
+ result->append(*consumeIdent(range));
+ return result;
+ }
+
+ if (CSSValue* width = consumeLength(range, cssParserMode, ValueRangeNonNegative)) {
+ CSSValue* height = consumeLength(range, cssParserMode, ValueRangeNonNegative);
+ result->append(*width);
+ if (height)
+ result->append(*height);
+ return result;
+ }
+
+ CSSValue* pageSize = consumePageSize(range);
+ CSSValue* orientation = consumeIdent<CSSValuePortrait, CSSValueLandscape>(range);
+ if (!pageSize)
+ pageSize = consumePageSize(range);
+
+ if (!orientation && !pageSize)
+ return nullptr;
+ if (pageSize)
+ result->append(*pageSize);
+ if (orientation)
+ result->append(*orientation);
+ return result;
+}
+
+static CSSValue* consumeSnapHeight(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ CSSPrimitiveValue* unit = consumeLength(range, cssParserMode, ValueRangeNonNegative);
+ if (!unit)
+ return nullptr;
+ CSSValueList* list = CSSValueList::createSpaceSeparated();
+ list->append(*unit);
+
+ if (CSSPrimitiveValue* position = consumePositiveInteger(range)) {
+ if (position->getIntValue() > 100)
+ return nullptr;
+ list->append(*position);
+ }
+
+ return list;
+}
+
+static CSSValue* consumeTextIndent(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ // [ <length> | <percentage> ] && hanging? && 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->append(*textIndent);
+ hasLengthOrPercentage = true;
+ continue;
+ }
+ }
+
+ if (RuntimeEnabledFeatures::css3TextEnabled()) {
+ CSSValueID id = range.peek().id();
+ if (!hasEachLine && id == CSSValueEachLine) {
+ list->append(*consumeIdent(range));
+ hasEachLine = true;
+ continue;
+ }
+ if (!hasHanging && id == CSSValueHanging) {
+ list->append(*consumeIdent(range));
+ hasHanging = true;
+ continue;
+ }
+ }
+ return nullptr;
+ } while (!range.atEnd());
+
+ if (!hasLengthOrPercentage)
+ return nullptr;
+
+ return list;
+}
+
+static bool validWidthOrHeightKeyword(CSSValueID id, const CSSParserContext& 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()->count(UseCounter::CSSValuePrefixedMinContent);
+ break;
+ case CSSValueWebkitMaxContent:
+ context.useCounter()->count(UseCounter::CSSValuePrefixedMaxContent);
+ break;
+ case CSSValueWebkitFillAvailable:
+ context.useCounter()->count(UseCounter::CSSValuePrefixedFillAvailable);
+ break;
+ case CSSValueWebkitFitContent:
+ context.useCounter()->count(UseCounter::CSSValuePrefixedFitContent);
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+static CSSValue* consumeMaxWidthOrHeight(CSSParserTokenRange& range, const CSSParserContext& 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& range, const CSSParserContext& 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& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+ if (range.peek().id() == CSSValueAuto)
+ return consumeIdent(range);
+ return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, unitless);
+}
+
+static CSSPrimitiveValue* consumeClipComponent(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ if (range.peek().id() == CSSValueAuto)
+ return consumeIdent(range);
+ return consumeLength(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
+}
+
+static CSSValue* consumeClip(CSSParserTokenRange& 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 && !consumeCommaIncludingWhitespace(args)))
+ return nullptr;
+ CSSPrimitiveValue* bottom = consumeClipComponent(args, cssParserMode);
+ if (!bottom || (needsComma && !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& range, CSSValue*& panX, CSSValue*& panY)
+{
+ CSSValueID id = range.peek().id();
+ if ((id == CSSValuePanX || id == CSSValuePanRight || id == CSSValuePanLeft) && !panX) {
+ if (id != CSSValuePanX && !RuntimeEnabledFeatures::cssTouchActionPanDirectionsEnabled())
+ return false;
+ panX = consumeIdent(range);
+ } else if ((id == CSSValuePanY || id == CSSValuePanDown || id == CSSValuePanUp) && !panY) {
+ if (id != CSSValuePanY && !RuntimeEnabledFeatures::cssTouchActionPanDirectionsEnabled())
+ return false;
+ panY = consumeIdent(range);
+ } else {
+ return false;
+ }
+ return true;
+}
+
+static CSSValue* consumeTouchAction(CSSParserTokenRange& range)
+{
+ CSSValueList* list = CSSValueList::createSpaceSeparated();
+ CSSValueID id = range.peek().id();
+ if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueManipulation) {
+ list->append(*consumeIdent(range));
+ return list;
+ }
+
+ CSSValue* panX = nullptr;
+ CSSValue* panY = nullptr;
+ if (!consumePan(range, panX, panY))
+ return nullptr;
+ if (!range.atEnd() && !consumePan(range, panX, panY))
+ return nullptr;
+
+ if (panX)
+ list->append(*panX);
+ if (panY)
+ list->append(*panY);
+ return list;
+}
+
+static CSSPrimitiveValue* consumeLineClamp(CSSParserTokenRange& range)
+{
+ if (range.peek().type() != PercentageToken && 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& range)
+{
+ if (range.peek().id() == CSSValueAuto)
+ return consumeIdent(range);
+ return consumeString(range);
+}
+
+static CSSValue* consumeColumnWidth(CSSParserTokenRange& 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->isCalculated() && columnWidth->getDoubleValue() == 0))
+ return nullptr;
+ return columnWidth;
+}
+
+static CSSValue* consumeColumnCount(CSSParserTokenRange& range)
+{
+ if (range.peek().id() == CSSValueAuto)
+ return consumeIdent(range);
+ return consumePositiveInteger(range);
+}
+
+static CSSValue* consumeColumnGap(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ if (range.peek().id() == CSSValueNormal)
+ return consumeIdent(range);
+ return consumeLength(range, cssParserMode, ValueRangeNonNegative);
+}
+
+static CSSValue* consumeColumnSpan(CSSParserTokenRange& range)
+{
+ return consumeIdent<CSSValueAll, CSSValueNone>(range);
+}
+
+static CSSValue* consumeZoom(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+ const CSSParserToken& token = range.peek();
+ CSSPrimitiveValue* zoom = nullptr;
+ if (token.type() == IdentToken) {
+ zoom = consumeIdent<CSSValueNormal, CSSValueReset, CSSValueDocument>(range);
+ } else {
+ zoom = consumePercent(range, ValueRangeNonNegative);
+ if (!zoom)
+ zoom = consumeNumber(range, ValueRangeNonNegative);
+ }
+ if (zoom && context.useCounter()
+ && !(token.id() == CSSValueNormal
+ || (token.type() == NumberToken && zoom->getDoubleValue() == 1)
+ || (token.type() == PercentageToken && zoom->getDoubleValue() == 100)))
+ context.useCounter()->count(UseCounter::CSSZoomNotEqualToOne);
+ return zoom;
+}
+
+static CSSValue* consumeAnimationIterationCount(CSSParserTokenRange& range)
+{
+ if (range.peek().id() == CSSValueInfinite)
+ return consumeIdent(range);
+ return consumeNumber(range, ValueRangeNonNegative);
+}
+
+static CSSValue* consumeAnimationName(CSSParserTokenRange& range, const CSSParserContext& context, bool allowQuotedName)
+{
+ if (range.peek().id() == CSSValueNone)
+ return consumeIdent(range);
+
+ if (allowQuotedName && range.peek().type() == StringToken) {
+ // Legacy support for strings in prefixed animations.
+ if (context.useCounter())
+ context.useCounter()->count(UseCounter::QuotedAnimationName);
+
+ const CSSParserToken& token = range.consumeIncludingWhitespace();
+ if (equalIgnoringASCIICase(token.value(), "none"))
+ return CSSPrimitiveValue::createIdentifier(CSSValueNone);
+ return CSSCustomIdentValue::create(token.value().toString());
+ }
+
+ return consumeCustomIdent(range);
+}
+
+static CSSValue* consumeTransitionProperty(CSSParserTokenRange& range)
+{
+ const CSSParserToken& 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& 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->getIntValue(), position);
+}
+
+static CSSValue* consumeCubicBezier(CSSParserTokenRange& range)
+{
+ ASSERT(range.peek().functionId() == CSSValueCubicBezier);
+ CSSParserTokenRange rangeCopy = range;
+ CSSParserTokenRange args = consumeFunction(rangeCopy);
+
+ double x1, y1, x2, y2;
+ if (consumeNumberRaw(args, x1)
+ && x1 >= 0 && x1 <= 1
+ && consumeCommaIncludingWhitespace(args)
+ && consumeNumberRaw(args, y1)
+ && consumeCommaIncludingWhitespace(args)
+ && consumeNumberRaw(args, x2)
+ && x2 >= 0 && x2 <= 1
+ && consumeCommaIncludingWhitespace(args)
+ && consumeNumberRaw(args, y2)
+ && args.atEnd()) {
+ range = rangeCopy;
+ return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
+ }
+
+ return nullptr;
+}
+
+static CSSValue* consumeAnimationTimingFunction(CSSParserTokenRange& 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& range, const CSSParserContext& context, bool useLegacyParsing)
+{
+ switch (property) {
+ case CSSPropertyAnimationDelay:
+ case CSSPropertyTransitionDelay:
+ return consumeTime(range, ValueRangeAll);
+ case CSSPropertyAnimationDirection:
+ return consumeIdent<CSSValueNormal, CSSValueAlternate, CSSValueReverse, CSSValueAlternateReverse>(range);
+ case CSSPropertyAnimationDuration:
+ case CSSPropertyTransitionDuration:
+ return consumeTime(range, ValueRangeNonNegative);
+ case CSSPropertyAnimationFillMode:
+ return consumeIdent<CSSValueNone, CSSValueForwards, CSSValueBackwards, CSSValueBoth>(range);
+ case CSSPropertyAnimationIterationCount:
+ return consumeAnimationIterationCount(range);
+ case CSSPropertyAnimationName:
+ return consumeAnimationName(range, context, useLegacyParsing);
+ case CSSPropertyAnimationPlayState:
+ return consumeIdent<CSSValueRunning, CSSValuePaused>(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& valueList)
+{
+ if (property != CSSPropertyTransitionProperty || valueList.length() < 2)
+ return true;
+ for (auto& value : valueList) {
+ if (value->isPrimitiveValue() && toCSSPrimitiveValue(*value).isValueID()
+ && toCSSPrimitiveValue(*value).getValueID() == CSSValueNone)
+ return false;
+ }
+ return true;
+}
+
+static CSSValueList* consumeAnimationPropertyList(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context, bool useLegacyParsing)
+{
+ CSSValueList* list = CSSValueList::createCommaSeparated();
+ do {
+ CSSValue* value = consumeAnimationValue(property, range, context, useLegacyParsing);
+ if (!value)
+ return nullptr;
+ list->append(*value);
+ } while (consumeCommaIncludingWhitespace(range));
+ if (!isValidAnimationPropertyList(property, *list))
+ return nullptr;
+ ASSERT(list->length());
+ return list;
+}
+
+bool CSSPropertyParser::consumeAnimationShorthand(const StylePropertyShorthand& shorthand, bool useLegacyParsing, bool important)
+{
+ const unsigned longhandCount = shorthand.length();
+ CSSValueList* longhands[8];
+ ASSERT(longhandCount <= 8);
+ for (size_t i = 0; i < longhandCount; ++i)
+ longhands[i] = CSSValueList::createCommaSeparated();
+
+ do {
+ bool parsedLonghand[8] = { false };
+ do {
+ bool foundProperty = false;
+ for (size_t i = 0; i < 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]->append(*value);
+ break;
+ }
+ }
+ if (!foundProperty)
+ return false;
+ } while (!m_range.atEnd() && m_range.peek().type() != CommaToken);
+
+ // FIXME: This will make invalid longhands, see crbug.com/386459
+ for (size_t i = 0; i < longhandCount; ++i) {
+ if (!parsedLonghand[i])
+ longhands[i]->append(*CSSInitialValue::createLegacyImplicit());
+ parsedLonghand[i] = false;
+ }
+ } while (consumeCommaIncludingWhitespace(m_range));
+
+ for (size_t i = 0; i < longhandCount; ++i) {
+ if (!isValidAnimationPropertyList(shorthand.properties()[i], *longhands[i]))
+ return false;
+ }
+
+ for (size_t i = 0; i < longhandCount; ++i)
+ addProperty(shorthand.properties()[i], shorthand.id(), *longhands[i], important);
+
+ return m_range.atEnd();
+}
+
+static CSSValue* consumeZIndex(CSSParserTokenRange& range)
+{
+ if (range.peek().id() == CSSValueAuto)
+ return consumeIdent(range);
+ return consumeInteger(range);
+}
+
+static CSSShadowValue* parseSingleShadow(CSSParserTokenRange& 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->getDoubleValue() < 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& 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->append(*shadowValue);
+ else
+ return nullptr;
+ } while (consumeCommaIncludingWhitespace(range));
+ return shadowValueList;
+}
+
+static CSSFunctionValue* consumeFilterFunction(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+ CSSValueID filterType = range.peek().functionId();
+ if (filterType < CSSValueInvert || filterType > 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()->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 && filterType != CSSValueSaturate && filterType != CSSValueContrast) {
+ bool isPercentage = toCSSPrimitiveValue(parsedValue)->isPercentage();
+ double maxAllowed = isPercentage ? 100.0 : 1.0;
+ if (toCSSPrimitiveValue(parsedValue)->getDoubleValue() > maxAllowed) {
+ parsedValue = CSSPrimitiveValue::create(
+ maxAllowed,
+ isPercentage ? CSSPrimitiveValue::UnitType::Percentage : CSSPrimitiveValue::UnitType::Number);
+ }
+ }
+ }
+ }
+ if (!parsedValue || !args.atEnd())
+ return nullptr;
+ filterValue->append(*parsedValue);
+ return filterValue;
+}
+
+static CSSValue* consumeFilter(CSSParserTokenRange& range, const CSSParserContext& 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->append(*filterValue);
+ } while (!range.atEnd());
+ return list;
+}
+
+static CSSValue* consumeTextDecorationLine(CSSParserTokenRange& range)
+{
+ CSSValueID id = range.peek().id();
+ if (id == CSSValueNone)
+ return consumeIdent(range);
+
+ CSSValueList* list = CSSValueList::createSpaceSeparated();
+ while (true) {
+ CSSPrimitiveValue* ident = consumeIdent<CSSValueBlink, CSSValueUnderline, CSSValueOverline, CSSValueLineThrough>(range);
+ if (!ident)
+ break;
+ if (list->hasValue(*ident))
+ return nullptr;
+ list->append(*ident);
+ }
+
+ if (!list->length())
+ return nullptr;
+ return list;
+}
+
+// none | strict | content | [ layout || style || paint || size ]
+static CSSValue* consumeContain(CSSParserTokenRange& range)
+{
+ CSSValueID id = range.peek().id();
+ if (id == CSSValueNone)
+ return consumeIdent(range);
+
+ CSSValueList* list = CSSValueList::createSpaceSeparated();
+ if (id == CSSValueStrict || id == CSSValueContent) {
+ list->append(*consumeIdent(range));
+ return list;
+ }
+ while (true) {
+ CSSPrimitiveValue* ident = consumeIdent<CSSValuePaint, CSSValueLayout, CSSValueStyle, CSSValueSize>(range);
+ if (!ident)
+ break;
+ if (list->hasValue(*ident))
+ return nullptr;
+ list->append(*ident);
+ }
+
+ if (!list->length())
+ return nullptr;
+ return list;
+}
+
+static CSSValue* consumePath(CSSParserTokenRange& range)
+{
+ // FIXME: Add support for <url>, <basic-shape>, <geometry-box>.
+ 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<SVGPathByteStream> byteStream = SVGPathByteStream::create();
+ if (buildByteStreamFromString(pathString, *byteStream) != SVGParseStatus::NoError
+ || !functionArgs.atEnd())
+ return nullptr;
+
+ range = functionRange;
+ if (byteStream->isEmpty())
+ return CSSPrimitiveValue::createIdentifier(CSSValueNone);
+ return CSSPathValue::create(std::move(byteStream));
+}
+
+static CSSValue* consumePathOrNone(CSSParserTokenRange& range)
+{
+ CSSValueID id = range.peek().id();
+ if (id == CSSValueNone)
+ return consumeIdent(range);
+
+ return consumePath(range);
+}
+
+static CSSValue* consumeMotionRotation(CSSParserTokenRange& range)
+{
+ CSSValue* angle = consumeAngle(range);
+ CSSValue* keyword = consumeIdent<CSSValueAuto, CSSValueReverse>(range);
+ if (!angle && !keyword)
+ return nullptr;
+
+ if (!angle)
+ angle = consumeAngle(range);
+
+ CSSValueList* list = CSSValueList::createSpaceSeparated();
+ if (keyword)
+ list->append(*keyword);
+ if (angle)
+ list->append(*angle);
+ return list;
+}
+
+static CSSValue* consumeTextEmphasisStyle(CSSParserTokenRange& range)
+{
+ CSSValueID id = range.peek().id();
+ if (id == CSSValueNone)
+ return consumeIdent(range);
+
+ if (CSSValue* textEmphasisStyle = consumeString(range))
+ return textEmphasisStyle;
+
+ CSSPrimitiveValue* fill = consumeIdent<CSSValueFilled, CSSValueOpen>(range);
+ CSSPrimitiveValue* shape = consumeIdent<CSSValueDot, CSSValueCircle, CSSValueDoubleCircle, CSSValueTriangle, CSSValueSesame>(range);
+ if (!fill)
+ fill = consumeIdent<CSSValueFilled, CSSValueOpen>(range);
+ if (fill && shape) {
+ CSSValueList* parsedValues = CSSValueList::createSpaceSeparated();
+ parsedValues->append(*fill);
+ parsedValues->append(*shape);
+ return parsedValues;
+ }
+ if (fill)
+ return fill;
+ if (shape)
+ return shape;
+ return nullptr;
+}
+
+static CSSValue* consumeOutlineColor(CSSParserTokenRange& 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& 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& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+ return consumeLineWidth(range, cssParserMode, unitless);
+}
+
+static CSSPrimitiveValue* consumeTextStrokeWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid);
+}
+
+static CSSPrimitiveValue* consumeColumnRuleWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid);
+}
+
+static bool consumeTranslate3d(CSSParserTokenRange& args, CSSParserMode cssParserMode, CSSFunctionValue*& transformValue)
+{
+ unsigned numberOfArguments = 2;
+ CSSValue* parsedValue = nullptr;
+ do {
+ parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+ if (!parsedValue)
+ return false;
+ transformValue->append(*parsedValue);
+ if (!consumeCommaIncludingWhitespace(args))
+ return false;
+ } while (--numberOfArguments);
+ parsedValue = consumeLength(args, cssParserMode, ValueRangeAll);
+ if (!parsedValue)
+ return false;
+ transformValue->append(*parsedValue);
+ return true;
+}
+
+static bool consumeNumbers(CSSParserTokenRange& args, CSSFunctionValue*& transformValue, unsigned numberOfArguments)
+{
+ do {
+ CSSValue* parsedValue = consumeNumber(args, ValueRangeAll);
+ if (!parsedValue)
+ return false;
+ transformValue->append(*parsedValue);
+ if (--numberOfArguments && !consumeCommaIncludingWhitespace(args))
+ return false;
+ } while (numberOfArguments);
+ return true;
+}
+
+static bool consumePerspective(CSSParserTokenRange& args, CSSParserMode cssParserMode, CSSFunctionValue*& transformValue, bool useLegacyParsing)
+{
+ CSSPrimitiveValue* parsedValue = consumeLength(args, cssParserMode, ValueRangeNonNegative);
+ if (!parsedValue && useLegacyParsing) {
+ double perspective;
+ if (!consumeNumberRaw(args, perspective) || perspective < 0)
+ return false;
+ parsedValue = CSSPrimitiveValue::create(perspective, CSSPrimitiveValue::UnitType::Pixels);
+ }
+ if (!parsedValue)
+ return false;
+ transformValue->append(*parsedValue);
+ return true;
+}
+
+static CSSValue* consumeTransformValue(CSSParserTokenRange& 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 && consumeCommaIncludingWhitespace(args)) {
+ transformValue->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 && consumeCommaIncludingWhitespace(args)) {
+ transformValue->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 && consumeCommaIncludingWhitespace(args)) {
+ transformValue->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->append(*parsedValue);
+ if (!args.atEnd())
+ return nullptr;
+ return transformValue;
+}
+
+static CSSValue* consumeTransform(CSSParserTokenRange& 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->append(*parsedTransformValue);
+ } while (!range.atEnd());
+
+ return list;
+}
+
+template <CSSValueID start, CSSValueID end>
+static CSSValue* consumePositionLonghand(CSSParserTokenRange& 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& range, CSSParserMode cssParserMode)
+{
+ return consumePositionLonghand<CSSValueLeft, CSSValueRight>(range, cssParserMode);
+}
+
+static CSSValue* consumePositionY(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ return consumePositionLonghand<CSSValueTop, CSSValueBottom>(range, cssParserMode);
+}
+
+static CSSValue* consumePaintStroke(CSSParserTokenRange& 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->append(*url);
+ values->append(*parsedValue);
+ return values;
+ }
+ return url;
+ }
+ return consumeColor(range, cssParserMode);
+}
+
+static CSSValue* consumePaintOrder(CSSParserTokenRange& range)
+{
+ if (range.peek().id() == CSSValueNormal)
+ return consumeIdent(range);
+
+ Vector<CSSValueID, 3> paintTypeList;
+ CSSPrimitiveValue* fill = nullptr;
+ CSSPrimitiveValue* stroke = nullptr;
+ CSSPrimitiveValue* markers = nullptr;
+ do {
+ CSSValueID id = range.peek().id();
+ if (id == CSSValueFill && !fill)
+ fill = consumeIdent(range);
+ else if (id == CSSValueStroke && !stroke)
+ stroke = consumeIdent(range);
+ else if (id == CSSValueMarkers && !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->append(firstPaintOrderType == CSSValueFill ? *fill : *stroke);
+ if (paintTypeList.size() > 1) {
+ if (paintTypeList.at(1) == CSSValueMarkers)
+ paintOrderList->append(*markers);
+ }
+ break;
+ case CSSValueMarkers:
+ paintOrderList->append(*markers);
+ if (paintTypeList.size() > 1) {
+ if (paintTypeList.at(1) == CSSValueStroke)
+ paintOrderList->append(*stroke);
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return paintOrderList;
+}
+
+static CSSValue* consumeNoneOrURI(CSSParserTokenRange& range)
+{
+ if (range.peek().id() == CSSValueNone)
+ return consumeIdent(range);
+ return consumeUrl(range);
+}
+
+static CSSValue* consumeFlexBasis(CSSParserTokenRange& 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& 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) && range.atEnd()))
+ return nullptr;
+ dashes->append(*dash);
+ } while (!range.atEnd());
+ return dashes;
+}
+
+static CSSPrimitiveValue* consumeBaselineShift(CSSParserTokenRange& 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& range)
+{
+ if (range.peek().id() == CSSValueAuto)
+ return consumeIdent(range);
+ return consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
+}
+
+static CSSValue* consumeCursor(CSSParserTokenRange& range, const CSSParserContext& 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->append(*CSSCursorImageValue::create(image, hotSpotSpecified, hotSpot));
+ if (!consumeCommaIncludingWhitespace(range))
+ return nullptr;
+ }
+
+ CSSValueID id = range.peek().id();
+ if (!range.atEnd() && context.useCounter()) {
+ if (id == CSSValueWebkitZoomIn)
+ context.useCounter()->count(UseCounter::PrefixedCursorZoomIn);
+ else if (id == CSSValueWebkitZoomOut)
+ context.useCounter()->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 >= CSSValueAuto && id <= CSSValueWebkitZoomOut) || id == CSSValueCopy || id == CSSValueNone) {
+ cursorType = consumeIdent(range);
+ } else {
+ return nullptr;
+ }
+
+ if (!list)
+ return cursorType;
+ list->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->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 && (id < CSSValueDisc || id > 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& range, CSSParserContext context)
+{
+ if (identMatches<CSSValueNone, CSSValueNormal>(range.peek().id()))
+ return consumeIdent(range);
+
+ CSSValueList* values = CSSValueList::createSpaceSeparated();
+
+ do {
+ CSSValue* parsedValue = consumeImage(range, context);
+ if (!parsedValue)
+ parsedValue = consumeIdent<CSSValueOpenQuote, CSSValueCloseQuote, CSSValueNoOpenQuote, CSSValueNoCloseQuote>(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->append(*parsedValue);
+ } while (!range.atEnd());
+
+ return values;
+}
+
+static CSSPrimitiveValue* consumePerspective(CSSParserTokenRange& range, CSSParserMode cssParserMode, CSSPropertyID unresolvedProperty)
+{
+ if (range.peek().id() == CSSValueNone)
+ return consumeIdent(range);
+ CSSPrimitiveValue* parsedValue = consumeLength(range, cssParserMode, ValueRangeAll);
+ if (!parsedValue && (unresolvedProperty == CSSPropertyAliasWebkitPerspective)) {
+ double perspective;
+ if (!consumeNumberRaw(range, perspective))
+ return nullptr;
+ parsedValue = CSSPrimitiveValue::create(perspective, CSSPrimitiveValue::UnitType::Pixels);
+ }
+ if (parsedValue && (parsedValue->isCalculated() || parsedValue->getDoubleValue() > 0))
+ return parsedValue;
+ return nullptr;
+}
+
+static CSSValueList* consumePositionList(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ CSSValueList* positions = CSSValueList::createCommaSeparated();
+ do {
+ CSSValue* position = consumePosition(range, cssParserMode, UnitlessQuirk::Forbid);
+ if (!position)
+ return nullptr;
+ positions->append(*position);
+ } while (consumeCommaIncludingWhitespace(range));
+ return positions;
+}
+
+static CSSValue* consumeScrollSnapCoordinate(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ if (range.peek().id() == CSSValueNone)
+ return consumeIdent(range);
+ return consumePositionList(range, cssParserMode);
+}
+
+static CSSValue* consumeScrollSnapPoints(CSSParserTokenRange& 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() && parsedValue && (parsedValue->isCalculated() || parsedValue->getDoubleValue() > 0)) {
+ CSSFunctionValue* result = CSSFunctionValue::create(CSSValueRepeat);
+ result->append(*parsedValue);
+ return result;
+ }
+ }
+ return nullptr;
+}
+
+static CSSValue* consumeBorderRadiusCorner(CSSParserTokenRange& 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& range, CSSParserMode cssParserMode)
+{
+ CSSPrimitiveValue* parsedValue = consumeIdentRange(range, CSSValueBaseline, CSSValueWebkitBaselineMiddle);
+ if (!parsedValue)
+ parsedValue = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
+ return parsedValue;
+}
+
+static CSSPrimitiveValue* consumeShapeRadius(CSSParserTokenRange& args, CSSParserMode cssParserMode)
+{
+ if (identMatches<CSSValueClosestSide, CSSValueFarthestSide>(args.peek().id()))
+ return consumeIdent(args);
+ return consumeLengthOrPercent(args, cssParserMode, ValueRangeNonNegative);
+}
+
+static CSSBasicShapeCircleValue* consumeBasicShapeCircle(CSSParserTokenRange& args, const CSSParserContext& context)
+{
+ // spec: https://drafts.csswg.org/css-shapes/#supported-basic-shapes
+ // circle( [<shape-radius>]? [at <position>]? )
+ CSSBasicShapeCircleValue* shape = CSSBasicShapeCircleValue::create();
+ if (CSSPrimitiveValue* radius = consumeShapeRadius(args, context.mode()))
+ shape->setRadius(radius);
+ if (consumeIdent<CSSValueAt>(args)) {
+ CSSValue* centerX = nullptr;
+ CSSValue* centerY = nullptr;
+ if (!consumePosition(args, context.mode(), UnitlessQuirk::Forbid, centerX, centerY))
+ return nullptr;
+ shape->setCenterX(centerX);
+ shape->setCenterY(centerY);
+ }
+ return shape;
+}
+
+static CSSBasicShapeEllipseValue* consumeBasicShapeEllipse(CSSParserTokenRange& args, const CSSParserContext& context)
+{
+ // spec: https://drafts.csswg.org/css-shapes/#supported-basic-shapes
+ // ellipse( [<shape-radius>{2}]? [at <position>]? )
+ CSSBasicShapeEllipseValue* shape = CSSBasicShapeEllipseValue::create();
+ if (CSSPrimitiveValue* radiusX = consumeShapeRadius(args, context.mode())) {
+ shape->setRadiusX(radiusX);
+ if (CSSPrimitiveValue* radiusY = consumeShapeRadius(args, context.mode()))
+ shape->setRadiusY(radiusY);
+ }
+ if (consumeIdent<CSSValueAt>(args)) {
+ CSSValue* centerX = nullptr;
+ CSSValue* centerY = nullptr;
+ if (!consumePosition(args, context.mode(), UnitlessQuirk::Forbid, centerX, centerY))
+ return nullptr;
+ shape->setCenterX(centerX);
+ shape->setCenterY(centerY);
+ }
+ return shape;
+}
+
+static CSSBasicShapePolygonValue* consumeBasicShapePolygon(CSSParserTokenRange& args, const CSSParserContext& context)
+{
+ CSSBasicShapePolygonValue* shape = CSSBasicShapePolygonValue::create();
+ if (identMatches<CSSValueEvenodd, CSSValueNonzero>(args.peek().id())) {
+ shape->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->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& range, CSSParserMode cssParserMode, bool useLegacyParsing)
+{
+ unsigned i = 0;
+ for (; i < 4 && !range.atEnd() && 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 && i == 2) {
+ verticalRadii[0] = horizontalRadii[1];
+ horizontalRadii[1] = nullptr;
+ } else {
+ complete4Sides(horizontalRadii);
+ for (unsigned i = 0; i < 4; ++i)
+ verticalRadii[i] = horizontalRadii[i];
+ return true;
+ }
+ } else {
+ if (!consumeSlashIncludingWhitespace(range))
+ return false;
+ for (i = 0; i < 4 && !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& args, const CSSParserContext& 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->updateShapeSize4Values(top, right, bottom, left);
+ else if (bottom)
+ shape->updateShapeSize3Values(top, right, bottom);
+ else if (right)
+ shape->updateShapeSize2Values(top, right);
+ else
+ shape->updateShapeSize1Value(top);
+
+ if (consumeIdent<CSSValueRound>(args)) {
+ CSSPrimitiveValue* horizontalRadii[4] = { 0 };
+ CSSPrimitiveValue* verticalRadii[4] = { 0 };
+ if (!consumeRadii(horizontalRadii, verticalRadii, args, context.mode(), false))
+ return nullptr;
+ shape->setTopLeftRadius(CSSValuePair::create(horizontalRadii[0], verticalRadii[0], CSSValuePair::DropIdenticalValues));
+ shape->setTopRightRadius(CSSValuePair::create(horizontalRadii[1], verticalRadii[1], CSSValuePair::DropIdenticalValues));
+ shape->setBottomRightRadius(CSSValuePair::create(horizontalRadii[2], verticalRadii[2], CSSValuePair::DropIdenticalValues));
+ shape->setBottomLeftRadius(CSSValuePair::create(horizontalRadii[3], verticalRadii[3], CSSValuePair::DropIdenticalValues));
+ }
+ return shape;
+}
+
+static CSSValue* consumeBasicShape(CSSParserTokenRange& range, const CSSParserContext& 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& range, const CSSParserContext& context)
+{
+ if (range.peek().id() == CSSValueNone)
+ return consumeIdent(range);
+ if (CSSURIValue* url = consumeUrl(range))
+ return url;
+ return consumeBasicShape(range, context);
+}
+
+static CSSValue* consumeShapeOutside(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+ if (CSSValue* imageValue = consumeImageOrNone(range, context))
+ return imageValue;
+ CSSValueList* list = CSSValueList::createSpaceSeparated();
+ if (CSSValue* boxValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox>(range))
+ list->append(*boxValue);
+ if (CSSValue* shapeValue = consumeBasicShape(range, context)) {
+ list->append(*shapeValue);
+ if (list->length() < 2) {
+ if (CSSValue* boxValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox>(range))
+ list->append(*boxValue);
+ }
+ }
+ if (!list->length())
+ return nullptr;
+ return list;
+}
+
+static CSSValue* consumeContentDistributionOverflowPosition(CSSParserTokenRange& range)
+{
+ if (identMatches<CSSValueNormal, CSSValueBaseline, CSSValueLastBaseline>(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<CSSValueSpaceBetween, CSSValueSpaceAround, CSSValueSpaceEvenly, CSSValueStretch>(id)) {
+ if (distribution != CSSValueInvalid)
+ return nullptr;
+ distribution = id;
+ } else if (identMatches<CSSValueStart, CSSValueEnd, CSSValueCenter, CSSValueFlexStart, CSSValueFlexEnd, CSSValueLeft, CSSValueRight>(id)) {
+ if (position != CSSValueInvalid)
+ return nullptr;
+ position = id;
+ } else if (identMatches<CSSValueUnsafe, CSSValueSafe>(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 <content-distribution> or <content-position>.
+ if (position == CSSValueInvalid && distribution == CSSValueInvalid)
+ return nullptr;
+
+ // The grammar states that <overflow-position> must be associated to <content-position>.
+ if (overflow != CSSValueInvalid && position == CSSValueInvalid)
+ return nullptr;
+
+ return CSSContentDistributionValue::create(distribution, position, overflow);
+}
+
+static CSSPrimitiveValue* consumeBorderImageRepeatKeyword(CSSParserTokenRange& range)
+{
+ return consumeIdent<CSSValueStretch, CSSValueRepeat, CSSValueSpace, CSSValueRound>(range);
+}
+
+static CSSValue* consumeBorderImageRepeat(CSSParserTokenRange& 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& range)
+{
+ bool fill = consumeIdent<CSSValueFill>(range);
+ CSSPrimitiveValue* slices[4] = { 0 };
+
+ for (size_t index = 0; index < 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<CSSValueFill>(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& range)
+{
+ CSSPrimitiveValue* outsets[4] = { 0 };
+
+ CSSPrimitiveValue* value = nullptr;
+ for (size_t index = 0; index < 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& range)
+{
+ CSSPrimitiveValue* widths[4] = { 0 };
+
+ CSSPrimitiveValue* value = nullptr;
+ for (size_t index = 0; index < 4; ++index) {
+ value = consumeNumber(range, ValueRangeNonNegative);
+ if (!value)
+ value = consumeLengthOrPercent(range, HTMLStandardMode, ValueRangeNonNegative, UnitlessQuirk::Forbid);
+ if (!value)
+ value = consumeIdent<CSSValueAuto>(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& range, const CSSParserContext& context, CSSValue*& source,
+ CSSValue*& slice, CSSValue*& width, CSSValue*& outset, CSSValue*& 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 && !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& range, const CSSParserContext& 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& range, const CSSParserContext& context)
+{
+ CSSPrimitiveValue* direction = consumeIdent<CSSValueAbove, CSSValueBelow, CSSValueLeft, CSSValueRight>(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& range)
+{
+ if (range.peek().id() == CSSValueNone)
+ return consumeIdent(range);
+ return consumeNumber(range, ValueRangeNonNegative);
+}
+
+static CSSValue* consumeImageOrientation(CSSParserTokenRange& range)
+{
+ if (range.peek().id() == CSSValueFromImage)
+ return consumeIdent(range);
+ if (range.peek().type() != NumberToken) {
+ CSSPrimitiveValue* angle = consumeAngle(range);
+ if (angle && angle->getDoubleValue() == 0)
+ return angle;
+ }
+ return nullptr;
+}
+
+static CSSValue* consumeBackgroundBlendMode(CSSParserTokenRange& range)
+{
+ CSSValueID id = range.peek().id();
+ if (id == CSSValueNormal || id == CSSValueOverlay || (id >= CSSValueMultiply && id <= CSSValueLuminosity))
+ return consumeIdent(range);
+ return nullptr;
+}
+
+static CSSValue* consumeBackgroundAttachment(CSSParserTokenRange& range)
+{
+ return consumeIdent<CSSValueScroll, CSSValueFixed, CSSValueLocal>(range);
+}
+
+static CSSValue* consumeBackgroundBox(CSSParserTokenRange& range)
+{
+ return consumeIdent<CSSValueBorderBox, CSSValuePaddingBox, CSSValueContentBox>(range);
+}
+
+static CSSValue* consumeBackgroundComposite(CSSParserTokenRange& range)
+{
+ return consumeIdentRange(range, CSSValueClear, CSSValuePlusLighter);
+}
+
+static CSSValue* consumeMaskSourceType(CSSParserTokenRange& range)
+{
+ ASSERT(RuntimeEnabledFeatures::cssMaskSourceTypeEnabled());
+ return consumeIdent<CSSValueAuto, CSSValueAlpha, CSSValueLuminance>(range);
+}
+
+static CSSValue* consumePrefixedBackgroundBox(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& 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) && range.peek().id() == CSSValueText)
+ return consumeIdent(range);
+ return nullptr;
+}
+
+static CSSValue* consumeBackgroundSize(CSSPropertyID unresolvedProperty, CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ if (identMatches<CSSValueContain, CSSValueCover>(range.peek().id()))
+ return consumeIdent(range);
+
+ CSSPrimitiveValue* horizontal = consumeIdent<CSSValueAuto>(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: "-webkit-background-size: 10px" is equivalent to "background-size: 10px 10px".
+ vertical = horizontal;
+ }
+ if (!vertical)
+ return horizontal;
+ return CSSValuePair::create(horizontal, vertical, CSSValuePair::KeepIdenticalValues);
+}
+
+static CSSValueList* consumeGridAutoFlow(CSSParserTokenRange& range)
+{
+ CSSPrimitiveValue* rowOrColumnValue = consumeIdent<CSSValueRow, CSSValueColumn>(range);
+ CSSPrimitiveValue* denseAlgorithm = consumeIdent<CSSValueDense>(range);
+ if (!rowOrColumnValue) {
+ rowOrColumnValue = consumeIdent<CSSValueRow, CSSValueColumn>(range);
+ if (!rowOrColumnValue && !denseAlgorithm)
+ return nullptr;
+ }
+ CSSValueList* parsedValues = CSSValueList::createSpaceSeparated();
+ if (rowOrColumnValue)
+ parsedValues->append(*rowOrColumnValue);
+ if (denseAlgorithm)
+ parsedValues->append(*denseAlgorithm);
+ return parsedValues;
+}
+
+static CSSValue* consumeBackgroundComponent(CSSPropertyID unresolvedProperty, CSSParserTokenRange& range, const CSSParserContext& 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*& list, CSSValue* value)
+{
+ if (list) {
+ if (!list->isBaseValueList()) {
+ CSSValue* firstValue = list;
+ list = CSSValueList::createCommaSeparated();
+ toCSSValueList(list)->append(*firstValue);
+ }
+ toCSSValueList(list)->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& range, const CSSParserContext& 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& 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& range)
+{
+ if (identMatches<CSSValueAuto, CSSValueNormal, CSSValueStretch, CSSValueBaseline, CSSValueLastBaseline>(range.peek().id()))
+ return consumeIdent(range);
+
+ CSSPrimitiveValue* overflowPosition = consumeIdent<CSSValueUnsafe, CSSValueSafe>(range);
+ CSSPrimitiveValue* selfPosition = consumeSelfPositionKeyword(range);
+ if (!selfPosition)
+ return nullptr;
+ if (!overflowPosition)
+ overflowPosition = consumeIdent<CSSValueUnsafe, CSSValueSafe>(range);
+ if (overflowPosition)
+ return CSSValuePair::create(selfPosition, overflowPosition, CSSValuePair::DropIdenticalValues);
+ return selfPosition;
+}
+
+static CSSValue* consumeAlignItems(CSSParserTokenRange& range)
+{
+ // align-items property does not allow the 'auto' value.
+ if (identMatches<CSSValueAuto>(range.peek().id()))
+ return nullptr;
+ return consumeSelfPositionOverflowPosition(range);
+}
+
+static CSSValue* consumeJustifyItems(CSSParserTokenRange& range)
+{
+ CSSParserTokenRange rangeCopy = range;
+ CSSPrimitiveValue* legacy = consumeIdent<CSSValueLegacy>(rangeCopy);
+ CSSPrimitiveValue* positionKeyword = consumeIdent<CSSValueCenter, CSSValueLeft, CSSValueRight>(rangeCopy);
+ if (!legacy)
+ legacy = consumeIdent<CSSValueLegacy>(rangeCopy);
+ if (legacy && positionKeyword) {
+ range = rangeCopy;
+ return CSSValuePair::create(legacy, positionKeyword, CSSValuePair::DropIdenticalValues);
+ }
+ return consumeSelfPositionOverflowPosition(range);
+}
+
+static CSSCustomIdentValue* consumeCustomIdentForGridLine(CSSParserTokenRange& range)
+{
+ if (range.peek().id() == CSSValueAuto || range.peek().id() == CSSValueSpan)
+ return nullptr;
+ return consumeCustomIdent(range);
+}
+
+static CSSValue* consumeGridLine(CSSParserTokenRange& 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<CSSValueSpan>(range);
+ } else {
+ spanValue = consumeIdent<CSSValueSpan>(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<CSSValueSpan>(range);
+ if (!spanValue && !numericValue)
+ return gridLineName;
+ } else {
+ return nullptr;
+ }
+ }
+ }
+
+ if (spanValue && !numericValue && !gridLineName)
+ return nullptr; // "span" keyword alone is invalid.
+ if (spanValue && numericValue && numericValue->getIntValue() < 0)
+ return nullptr; // Negative numbers are not allowed for span.
+ if (numericValue && numericValue->getIntValue() == 0)
+ return nullptr; // An <integer> value of zero makes the declaration invalid.
+
+ CSSValueList* values = CSSValueList::createSpaceSeparated();
+ if (spanValue)
+ values->append(*spanValue);
+ if (numericValue)
+ values->append(*numericValue);
+ if (gridLineName)
+ values->append(*gridLineName);
+ ASSERT(values->length());
+ return values;
+}
+
+static bool isGridTrackFixedSized(const CSSPrimitiveValue& primitiveValue)
+{
+ CSSValueID valueID = primitiveValue.getValueID();
+ if (valueID == CSSValueMinContent || valueID == CSSValueMaxContent || valueID == CSSValueAuto || primitiveValue.isFlex())
+ return false;
+
+ return true;
+}
+
+static bool isGridTrackFixedSized(const CSSValue& value)
+{
+ if (value.isPrimitiveValue())
+ return isGridTrackFixedSized(toCSSPrimitiveValue(value));
+
+ const CSSPrimitiveValue& minPrimitiveValue = toCSSPrimitiveValue(toCSSFunctionValue(value).item(0));
+ const CSSPrimitiveValue& maxPrimitiveValue = toCSSPrimitiveValue(toCSSFunctionValue(value).item(1));
+ return isGridTrackFixedSized(minPrimitiveValue) || isGridTrackFixedSized(maxPrimitiveValue);
+}
+
+static Vector<String> parseGridTemplateAreasColumnNames(const String& gridRowNames)
+{
+ ASSERT(!gridRowNames.isEmpty());
+ Vector<String> columnNames;
+ // Using StringImpl to avoid checks and indirection in every call to String::operator[].
+ StringImpl& text = *gridRowNames.impl();
+
+ StringBuilder areaName;
+ for (unsigned i = 0; i < text.length(); ++i) {
+ if (isCSSSpace(text[i])) {
+ if (!areaName.isEmpty()) {
+ columnNames.append(areaName.toString());
+ areaName.clear();
+ }
+ continue;
+ }
+ if (text[i] == '.') {
+ if (areaName == ".")
+ continue;
+ if (!areaName.isEmpty()) {
+ columnNames.append(areaName.toString());
+ areaName.clear();
+ }
+ } else {
+ if (!isNameCodePoint(text[i]))
+ return Vector<String>();
+ if (areaName == ".") {
+ columnNames.append(areaName.toString());
+ areaName.clear();
+ }
+ }
+
+ areaName.append(text[i]);
+ }
+
+ if (!areaName.isEmpty())
+ columnNames.append(areaName.toString());
+
+ return columnNames;
+}
+
+static bool parseGridTemplateAreasRow(const String& gridRowNames, NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount)
+{
+ if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace())
+ return false;
+
+ Vector<String> 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 < columnCount; ++currentColumn) {
+ const String& gridAreaName = columnNames[currentColumn];
+
+ // Unamed areas are always valid (we consider them to be 1x1).
+ if (gridAreaName == ".")
+ continue;
+
+ size_t lookAheadColumn = currentColumn + 1;
+ while (lookAheadColumn < columnCount && 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& gridArea = gridAreaIt->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& range, CSSParserMode cssParserMode)
+{
+ const CSSParserToken& token = range.peek();
+ if (identMatches<CSSValueMinContent, CSSValueMaxContent, CSSValueAuto>(token.id()))
+ return consumeIdent(range);
+ if (token.type() == DimensionToken && token.unitType() == CSSPrimitiveValue::UnitType::Fraction) {
+ if (range.peek().numericValue() < 0)
+ return nullptr;
+ return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitType::Fraction);
+ }
+ return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative, UnitlessQuirk::Allow);
+}
+
+static CSSValue* consumeGridTrackSize(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ const CSSParserToken& token = range.peek();
+ if (identMatches<CSSValueAuto>(token.id()))
+ return consumeIdent(range);
+
+ if (token.functionId() == CSSValueMinmax) {
+ CSSParserTokenRange rangeCopy = range;
+ CSSParserTokenRange args = consumeFunction(rangeCopy);
+ CSSPrimitiveValue* minTrackBreadth = consumeGridBreadth(args, cssParserMode);
+ if (!minTrackBreadth || minTrackBreadth->isFlex() || !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+ CSSPrimitiveValue* maxTrackBreadth = consumeGridBreadth(args, cssParserMode);
+ if (!maxTrackBreadth || !args.atEnd())
+ return nullptr;
+ range = rangeCopy;
+ CSSFunctionValue* result = CSSFunctionValue::create(CSSValueMinmax);
+ result->append(*minTrackBreadth);
+ result->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& 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->append(*lineName);
+ if (rangeCopy.consumeIncludingWhitespace().type() != RightBracketToken)
+ return nullptr;
+ range = rangeCopy;
+ return lineNames;
+}
+
+static bool consumeGridTrackRepeatFunction(CSSParserTokenRange& range, CSSParserMode cssParserMode, CSSValueList& list, bool& isAutoRepeat, bool& allTracksAreFixedSized)
+{
+ CSSParserTokenRange args = consumeFunction(range);
+ // The number of repetitions for <auto-repeat> is not important at parsing level
+ // because it will be computed later, let's set it to 1.
+ size_t repetitions = 1;
+ isAutoRepeat = identMatches<CSSValueAutoFill, CSSValueAutoFit>(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<size_t>(repetition->getDoubleValue(), 0, kGridMaxTracks);
+ repeatedValues = CSSValueList::createSpaceSeparated();
+ }
+ if (!consumeCommaIncludingWhitespace(args))
+ return false;
+ CSSGridLineNamesValue* lineNames = consumeGridLineNames(args);
+ if (lineNames)
+ repeatedValues->append(*lineNames);
+
+ size_t numberOfTracks = 0;
+ while (!args.atEnd()) {
+ CSSValue* trackSize = consumeGridTrackSize(args, cssParserMode);
+ if (!trackSize)
+ return false;
+ if (allTracksAreFixedSized)
+ allTracksAreFixedSized = isGridTrackFixedSized(*trackSize);
+ repeatedValues->append(*trackSize);
+ ++numberOfTracks;
+ lineNames = consumeGridLineNames(args);
+ if (lineNames)
+ repeatedValues->append(*lineNames);
+ }
+ // We should have found at least one <track-size> or else it is not a valid <track-list>.
+ 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 < repetitions; ++i) {
+ for (size_t j = 0; j < repeatedValues->length(); ++j)
+ list.append(repeatedValues->item(j));
+ }
+ }
+ return true;
+}
+
+enum TrackListType { GridTemplate, GridTemplateNoRepeat, GridAuto };
+
+static CSSValue* consumeGridTrackList(CSSParserTokenRange& range, CSSParserMode cssParserMode, TrackListType trackListType)
+{
+ bool allowGridLineNames = trackListType != GridAuto;
+ CSSValueList* values = CSSValueList::createSpaceSeparated();
+ CSSGridLineNamesValue* lineNames = consumeGridLineNames(range);
+ if (lineNames) {
+ if (!allowGridLineNames)
+ return nullptr;
+ values->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 && seenAutoRepeat)
+ return nullptr;
+ seenAutoRepeat = seenAutoRepeat || isAutoRepeat;
+ } else if (CSSValue* value = consumeGridTrackSize(range, cssParserMode)) {
+ if (allTracksAreFixedSized)
+ allTracksAreFixedSized = isGridTrackFixedSized(*value);
+ values->append(*value);
+ } else {
+ return nullptr;
+ }
+ if (seenAutoRepeat && !allTracksAreFixedSized)
+ return nullptr;
+ lineNames = consumeGridLineNames(range);
+ if (lineNames) {
+ if (!allowGridLineNames)
+ return nullptr;
+ values->append(*lineNames);
+ }
+ } while (!range.atEnd() && range.peek().type() != DelimiterToken);
+ return values;
+}
+
+static CSSValue* consumeGridTemplatesRowsOrColumns(CSSParserTokenRange& range, CSSParserMode cssParserMode)
+{
+ if (range.peek().id() == CSSValueNone)
+ return consumeIdent(range);
+ return consumeGridTrackList(range, cssParserMode, GridTemplate);
+}
+
+static CSSValue* consumeGridTemplateAreas(CSSParserTokenRange& 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->count(UseCounter::CSSValueAppearanceNone);
+ } else {
+ counter->count(UseCounter::CSSValueAppearanceNotNone);
+ if (valueID == CSSValueButton)
+ counter->count(UseCounter::CSSValueAppearanceButton);
+ else if (valueID == CSSValueCaret)
+ counter->count(UseCounter::CSSValueAppearanceCaret);
+ else if (valueID == CSSValueCheckbox)
+ counter->count(UseCounter::CSSValueAppearanceCheckbox);
+ else if (valueID == CSSValueMenulist)
+ counter->count(UseCounter::CSSValueAppearanceMenulist);
+ else if (valueID == CSSValueMenulistButton)
+ counter->count(UseCounter::CSSValueAppearanceMenulistButton);
+ else if (valueID == CSSValueListbox)
+ counter->count(UseCounter::CSSValueAppearanceListbox);
+ else if (valueID == CSSValueRadio)
+ counter->count(UseCounter::CSSValueAppearanceRadio);
+ else if (valueID == CSSValueSearchfield)
+ counter->count(UseCounter::CSSValueAppearanceSearchField);
+ else if (valueID == CSSValueTextfield)
+ counter->count(UseCounter::CSSValueAppearanceTextField);
+ else
+ counter->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()
+ && (currentShorthand == CSSPropertyInvalid || currentShorthand == CSSPropertyBorderColor);
+ return consumeColor(m_range, m_context.mode(), allowQuirkyColors);
+ }
+ case CSSPropertyBorderBottomWidth:
+ case CSSPropertyBorderLeftWidth:
+ case CSSPropertyBorderRightWidth:
+ case CSSPropertyBorderTopWidth: {
+ bool allowQuirkyLengths = inQuirksMode()
+ && (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<CSSValueAuto, CSSValueUnder>(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& range)
+{
+ return consumeIdent<CSSValueAuto, CSSValueBlock, CSSValueSwap, CSSValueFallback, CSSValueOptional>(range);
+}
+
+static CSSValueList* consumeFontFaceUnicodeRange(CSSParserTokenRange& range)
+{
+ CSSValueList* values = CSSValueList::createCommaSeparated();
+
+ do {
+ const CSSParserToken& token = range.consumeIncludingWhitespace();
+ if (token.type() != UnicodeRangeToken)
+ return nullptr;
+
+ UChar32 start = token.unicodeRangeStart();
+ UChar32 end = token.unicodeRangeEnd();
+ if (start > end)
+ return nullptr;
+ values->append(*CSSUnicodeRangeValue::create(start, end));
+ } while (consumeCommaIncludingWhitespace(range));
+
+ return values;
+}
+
+static CSSValue* consumeFontFaceSrcURI(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+ String url = consumeUrlAsStringView(range).toString();
+ if (url.isNull())
+ return nullptr;
+ CSSFontFaceSrcValue* uriValue(CSSFontFaceSrcValue::create(url, context.completeURL(url), context.shouldCheckContentSecurityPolicy()));
+ uriValue->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& arg = args.consumeIncludingWhitespace();
+ if ((arg.type() != StringToken) || !args.atEnd())
+ return nullptr;
+ uriValue->setFormat(arg.value().toString());
+ return uriValue;
+}
+
+static CSSValue* consumeFontFaceSrcLocal(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+ CSSParserTokenRange args = consumeFunction(range);
+ ContentSecurityPolicyDisposition shouldCheckContentSecurityPolicy = context.shouldCheckContentSecurityPolicy();
+ if (args.peek().type() == StringToken) {
+ const CSSParserToken& 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& range, const CSSParserContext& context)
+{
+ CSSValueList* values = CSSValueList::createCommaSeparated();
+
+ do {
+ const CSSParserToken& token = range.peek();
+ CSSValue* parsedValue = nullptr;
+ if (token.functionId() == CSSValueLocal)
+ parsedValue = consumeFontFaceSrcLocal(range, context);
+ else
+ parsedValue = consumeFontFaceSrcURI(range, context);
+ if (!parsedValue)
+ return nullptr;
+ values->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 >= CSSValueCaption && systemFontID <= 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->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 && CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyFontStyle, id, m_context.mode())) {
+ fontStyle = consumeIdent(m_range);
+ continue;
+ }
+ if (!fontVariantCaps && (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 && 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
+ // "font-stretch", "font-size-adjust", and "font-kerning" 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<CSSValueNormal, CSSValueNone>(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& 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<CSSValueZoom, CSSValueFixed>(range);
+ case CSSPropertyOrientation:
+ return consumeIdent<CSSValueAuto, CSSValuePortrait, CSSValueLandscape>(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& range, CSSValue*& columnWidth, CSSValue*& 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& shorthand, bool important)
+{
+ ASSERT(shorthand.length() <= 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 && i < 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 < 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() && index++ < 3) {
+ double num;
+ if (consumeNumberRaw(m_range, num)) {
+ if (num < 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 && !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<float>(flexGrow), CSSPrimitiveValue::UnitType::Number), important);
+ addProperty(CSSPropertyFlexShrink, CSSPropertyFlex, *CSSPrimitiveValue::create(clampTo<float>(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 && !style && !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& 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->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& range, const CSSParserContext& context, UnitlessQuirk unitless, CSSValue*& resultX, CSSValue*& 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& range, CSSValue*& value1, CSSValue*& value2, bool& implicit)
+{
+ if (consumeIdent<CSSValueRepeatX>(range)) {
+ value1 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat);
+ value2 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat);
+ implicit = true;
+ return true;
+ }
+ if (consumeIdent<CSSValueRepeatY>(range)) {
+ value1 = CSSPrimitiveValue::createIdentifier(CSSValueNoRepeat);
+ value2 = CSSPrimitiveValue::createIdentifier(CSSValueRepeat);
+ implicit = true;
+ return true;
+ }
+ value1 = consumeIdent<CSSValueRepeat, CSSValueNoRepeat, CSSValueRound, CSSValueSpace>(range);
+ if (!value1)
+ return false;
+
+ value2 = consumeIdent<CSSValueRepeat, CSSValueNoRepeat, CSSValueRound, CSSValueSpace>(range);
+ if (!value2) {
+ value2 = value1;
+ implicit = true;
+ }
+ return true;
+}
+
+static bool consumeRepeatStyle(CSSParserTokenRange& range, CSSValue*& resultX, CSSValue*& resultY, bool& 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& shorthand, bool important)
+{
+ const unsigned longhandCount = shorthand.length();
+ CSSValue* longhands[10] = { 0 };
+ ASSERT(longhandCount <= 10);
+
+ bool implicit = false;
+ do {
+ bool parsedLonghand[10] = { false };
+ CSSValue* originValue = nullptr;
+ do {
+ bool foundProperty = false;
+ for (size_t i = 0; i < 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() && m_range.peek().type() != CommaToken);
+
+ // FIXME: This will make invalid longhands, see crbug.com/386459
+ for (size_t i = 0; i < longhandCount; ++i) {
+ CSSPropertyID property = shorthand.properties()[i];
+ if (property == CSSPropertyBackgroundColor && !m_range.atEnd()) {
+ if (parsedLonghand[i])
+ return false; // Colors are only allowed in the last layer.
+ continue;
+ }
+ if ((property == CSSPropertyBackgroundClip || property == CSSPropertyWebkitMaskClip) && !parsedLonghand[i] && 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 < longhandCount; ++i) {
+ CSSPropertyID property = shorthand.properties()[i];
+ if (property == CSSPropertyBackgroundSize && longhands[i] && 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& 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->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->isCustomIdentValue() ? rowStartValue : CSSPrimitiveValue::createIdentifier(CSSValueAuto);
+ if (!rowEndValue)
+ rowEndValue = rowStartValue->isCustomIdentValue() ? rowStartValue : CSSPrimitiveValue::createIdentifier(CSSValueAuto);
+ if (!columnEndValue)
+ columnEndValue = columnStartValue->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 <line-names> values
+ CSSGridLineNamesValue* lineNames = nullptr;
+
+ do {
+ // Handle leading <custom-ident>*.
+ bool hasPreviousLineNames = lineNames;
+ lineNames = consumeGridLineNames(m_range, lineNames);
+ if (lineNames && !hasPreviousLineNames)
+ templateRows->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->append(*value);
+
+ // This will handle the trailing/leading <custom-ident>* in the grammar.
+ lineNames = consumeGridLineNames(m_range);
+ if (lineNames)
+ templateRows->append(*lineNames);
+ } while (!m_range.atEnd() && !(m_range.peek().type() == DelimiterToken && 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<CSSValueNone>(m_range);
+
+ // 1- 'none' case.
+ if (rowsValue && 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- <grid-template-rows> / <grid-template-columns>
+ 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- [ <line-names>? <string> <track-size>? <line-names>? ]+ [ / <track-list> ]?
+ 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- <grid-template>
+ 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- <grid-auto-flow> [ <grid-auto-rows> [ / <grid-auto-columns> ]? ]
+ 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 <grid-auto-columns> 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& token = m_range.peek();
+ if (token.id() >= CSSValueCaption && token.id() <= 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() && 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 <eric@webkit.org>
+ * 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 "CSSParserTokenRange.h"
+#include "StyleRule.h"
+#include <wtf/text/StringView.h>
+
+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&, const CSSParserContext&,
+ Vector<CSSProperty, 256>&, StyleRule::Type);
+
+ // Parses a non-shorthand CSS property
+ static const CSSValue* parseSingleValue(CSSPropertyID, const CSSParserTokenRange&, const CSSParserContext&);
+
+private:
+ CSSPropertyParser(const CSSParserTokenRange&, const CSSParserContext&,
+ Vector<CSSProperty, 256>*);
+
+ // 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&, bool important, bool implicit = false);
+ void addExpandedPropertyForValue(CSSPropertyID propId, const CSSValue&, bool);
+
+ bool consumeBorder(bool important);
+
+ bool parseShorthand(CSSPropertyID, bool important);
+ bool consumeShorthandGreedily(const StylePropertyShorthand&, bool important);
+ bool consume4Values(const StylePropertyShorthand&, bool important);
+
+ // Legacy parsing allows <string>s for animation-name
+ bool consumeAnimationShorthand(const StylePropertyShorthand&, bool useLegacyParsing, bool important);
+ bool consumeBackgroundShorthand(const StylePropertyShorthand&, 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& m_context;
+ // Outputs:
+ Vector<CSSProperty, 256>* 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
+// "AS IS" 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 "config.h"
+#include "CSSPropertyParserHelpers.h"
+
+#include "CSSCalculationValue.h"
+// FIXME-NEWPARSER: #include "CSSColorValue.h"
+#include "CSSCrossfadeValue.h"
+#include "CSSGradientValue.h"
+#include "CSSImageSetValue.h"
+#include "CSSImageValue.h"
+// FIXME-NEWPARSER: #include "CSSPaintValue.h"
+// FIXME_NEWPARSER: #include "CSSStringValue.h"
+// FIXME-NEWPARSER: #include "CSSURIValue.h"
+// FIXME_NEWPARSER: #include "CSSValuePair.h"
+
+namespace WebCore {
+
+/* FIXME-NEWPARSER: Disable for now.
+
+namespace CSSPropertyParserHelpers {
+
+bool consumeCommaIncludingWhitespace(CSSParserTokenRange& range)
+{
+ CSSParserToken value = range.peek();
+ if (value.type() != CommaToken)
+ return false;
+ range.consumeIncludingWhitespace();
+ return true;
+}
+
+bool consumeSlashIncludingWhitespace(CSSParserTokenRange& range)
+{
+ CSSParserToken value = range.peek();
+ if (value.type() != DelimiterToken || value.delimiter() != '/')
+ return false;
+ range.consumeIncludingWhitespace();
+ return true;
+}
+
+CSSParserTokenRange consumeFunction(CSSParserTokenRange& 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& range, ValueRange valueRange = ValueRangeAll)
+ : m_sourceRange(range)
+ , m_range(range)
+ {
+ const CSSParserToken& 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->isInt() ? CSSPrimitiveValue::UnitType::Integer : CSSPrimitiveValue::UnitType::Number;
+ return CSSPrimitiveValue::create(m_calcValue->doubleValue(), unitType);
+ }
+
+ bool consumeNumberRaw(double& result)
+ {
+ if (!m_calcValue || m_calcValue->category() != CalcNumber)
+ return false;
+ m_sourceRange = m_range;
+ result = m_calcValue->doubleValue();
+ return true;
+ }
+
+private:
+ CSSParserTokenRange& m_sourceRange;
+ CSSParserTokenRange m_range;
+ Member<CSSCalcValue> m_calcValue;
+};
+
+CSSPrimitiveValue* consumeInteger(CSSParserTokenRange& range, double minimumValue)
+{
+ const CSSParserToken& token = range.peek();
+ if (token.type() == NumberToken) {
+ if (token.numericValueType() == NumberValueType || token.numericValue() < minimumValue)
+ return nullptr;
+ return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitType::Integer);
+ }
+ CalcParser calcParser(range);
+ if (const CSSCalcValue* calculation = calcParser.value()) {
+ if (calculation->category() != CalcNumber || !calculation->isInt())
+ return nullptr;
+ double value = calculation->doubleValue();
+ if (value < minimumValue)
+ return nullptr;
+ return calcParser.consumeNumber();
+ }
+ return nullptr;
+}
+
+CSSPrimitiveValue* consumePositiveInteger(CSSParserTokenRange& range)
+{
+ return consumeInteger(range, 1);
+}
+
+bool consumeNumberRaw(CSSParserTokenRange& range, double& 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& range, ValueRange valueRange)
+{
+ const CSSParserToken& token = range.peek();
+ if (token.type() == NumberToken) {
+ if (valueRange == ValueRangeNonNegative && token.numericValue() < 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->category() != CalcNumber || (valueRange == ValueRangeNonNegative && calculation->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 && unitless == UnitlessQuirk::Allow);
+}
+
+CSSPrimitiveValue* consumeLength(CSSParserTokenRange& range, CSSParserMode cssParserMode, ValueRange valueRange, UnitlessQuirk unitless)
+{
+ const CSSParserToken& 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 && token.numericValue() < 0)
+ return nullptr;
+ return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), token.unitType());
+ }
+ if (token.type() == NumberToken) {
+ if (!shouldAcceptUnitlessLength(token.numericValue(), cssParserMode, unitless)
+ || (valueRange == ValueRangeNonNegative && token.numericValue() < 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() && calcParser.value()->category() == CalcLength)
+ return calcParser.consumeValue();
+ return nullptr;
+}
+
+CSSPrimitiveValue* consumePercent(CSSParserTokenRange& range, ValueRange valueRange)
+{
+ const CSSParserToken& token = range.peek();
+ if (token.type() == PercentageToken) {
+ if (valueRange == ValueRangeNonNegative && token.numericValue() < 0)
+ return nullptr;
+ return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitType::Percentage);
+ }
+ CalcParser calcParser(range, valueRange);
+ if (const CSSCalcValue* calculation = calcParser.value()) {
+ if (calculation->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& range, CSSParserMode cssParserMode, ValueRange valueRange, UnitlessQuirk unitless)
+{
+ const CSSParserToken& 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->category(), cssParserMode))
+ return calcParser.consumeValue();
+ }
+ return nullptr;
+}
+
+CSSPrimitiveValue* consumeAngle(CSSParserTokenRange& range)
+{
+ const CSSParserToken& 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 && token.numericValue() == 0) {
+ range.consumeIncludingWhitespace();
+ return CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitType::Degrees);
+ }
+ CalcParser calcParser(range, ValueRangeAll);
+ if (const CSSCalcValue* calculation = calcParser.value()) {
+ if (calculation->category() == CalcAngle)
+ return calcParser.consumeValue();
+ }
+ return nullptr;
+}
+
+CSSPrimitiveValue* consumeTime(CSSParserTokenRange& range, ValueRange valueRange)
+{
+ const CSSParserToken& token = range.peek();
+ if (token.type() == DimensionToken) {
+ if (valueRange == ValueRangeNonNegative && token.numericValue() < 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->category() == CalcTime)
+ return calcParser.consumeValue();
+ }
+ return nullptr;
+}
+
+CSSPrimitiveValue* consumeIdent(CSSParserTokenRange& range)
+{
+ if (range.peek().type() != IdentToken)
+ return nullptr;
+ return CSSPrimitiveValue::createIdentifier(range.consumeIncludingWhitespace().id());
+}
+
+CSSPrimitiveValue* consumeIdentRange(CSSParserTokenRange& range, CSSValueID lower, CSSValueID upper)
+{
+ if (range.peek().id() < lower || range.peek().id() > upper)
+ return nullptr;
+ return consumeIdent(range);
+}
+
+CSSCustomIdentValue* consumeCustomIdent(CSSParserTokenRange& range)
+{
+ if (range.peek().type() != IdentToken || isCSSWideKeyword(range.peek().id()))
+ return nullptr;
+ return CSSCustomIdentValue::create(range.consumeIncludingWhitespace().value().toString());
+}
+
+CSSStringValue* consumeString(CSSParserTokenRange& range)
+{
+ if (range.peek().type() != StringToken)
+ return nullptr;
+ return CSSStringValue::create(range.consumeIncludingWhitespace().value().toString());
+}
+
+StringView consumeUrlAsStringView(CSSParserTokenRange& range)
+{
+ const CSSParserToken& 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& 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& range)
+{
+ StringView url = consumeUrlAsStringView(range);
+ if (url.isNull())
+ return nullptr;
+ return CSSURIValue::create(url.toString());
+}
+
+static int clampRGBComponent(const CSSPrimitiveValue& value)
+{
+ double result = value.getDoubleValue();
+ // FIXME: Multiply by 2.55 and round instead of floor.
+ if (value.isPercentage())
+ result *= 2.56;
+ return clampTo<int>(result, 0, 255);
+}
+
+static bool parseRGBParameters(CSSParserTokenRange& range, RGBA32& 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->isPercentage();
+ int colorArray[3];
+ colorArray[0] = clampRGBComponent(*colorParameter);
+ for (int i = 1; i < 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<int>(clampTo<double>(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& range, RGBA32& 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->getIntValue() % 360) + 360) % 360) / 360.0;
+ for (int i = 1; i < 3; i++) {
+ if (!consumeCommaIncludingWhitespace(args))
+ return false;
+ hslValue = consumePercent(args, ValueRangeAll);
+ if (!hslValue)
+ return false;
+ double doubleValue = hslValue->getDoubleValue();
+ colorArray[i] = clampTo<double>(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<double>(alpha, 0.0, 1.0);
+ }
+ result = makeRGBAFromHSLA(colorArray[0], colorArray[1], colorArray[2], alpha);
+ return args.atEnd();
+}
+
+static bool parseHexColor(CSSParserTokenRange& range, RGBA32& result, bool acceptQuirkyColors)
+{
+ const CSSParserToken& 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() < 0. || token.numericValue() >= 1000000.)
+ return false;
+ if (token.type() == NumberToken) // e.g. 112233
+ color = String::format("%d", static_cast<int>(token.numericValue()));
+ else // e.g. 0001FF
+ color = String::number(static_cast<int>(token.numericValue())) + token.value().toString();
+ while (color.length() < 6)
+ color = "0" + color;
+ } else if (token.type() == IdentToken) { // e.g. FF0000
+ color = token.value().toString();
+ }
+ unsigned length = color.length();
+ if (length != 3 && length != 6)
+ return false;
+ if (!Color::parseHexColor(color, result))
+ return false;
+ } else {
+ return false;
+ }
+ range.consumeIncludingWhitespace();
+ return true;
+}
+
+static bool parseColorFunction(CSSParserTokenRange& range, RGBA32& result)
+{
+ CSSValueID functionId = range.peek().functionId();
+ if (functionId < CSSValueRgb || functionId > CSSValueHsla)
+ return false;
+ CSSParserTokenRange colorRange = range;
+ if ((functionId <= CSSValueRgba && !parseRGBParameters(colorRange, result, functionId == CSSValueRgba))
+ || (functionId >= CSSValueHsl && !parseHSLParameters(colorRange, result, functionId == CSSValueHsla)))
+ return false;
+ range = colorRange;
+ return true;
+}
+
+CSSValue* consumeColor(CSSParserTokenRange& 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) && !parseColorFunction(range, color))
+ return nullptr;
+ return CSSColorValue::create(color);
+}
+
+static CSSPrimitiveValue* consumePositionComponent(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+ if (range.peek().type() == IdentToken)
+ return consumeIdent<CSSValueLeft, CSSValueTop, CSSValueBottom, CSSValueRight, CSSValueCenter>(range);
+ return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, unitless);
+}
+
+static bool isHorizontalPositionKeywordOnly(const CSSPrimitiveValue& value)
+{
+ return value.isValueID() && (value.getValueID() == CSSValueLeft || value.getValueID() == CSSValueRight);
+}
+
+static bool isVerticalPositionKeywordOnly(const CSSPrimitiveValue& value)
+{
+ return value.isValueID() && (value.getValueID() == CSSValueTop || value.getValueID() == CSSValueBottom);
+}
+
+static void positionFromOneValue(CSSPrimitiveValue* value, CSSValue*& resultX, CSSValue*& 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*& resultX, CSSValue*& resultY)
+{
+ bool mustOrderAsXY = isHorizontalPositionKeywordOnly(*value1) || isVerticalPositionKeywordOnly(*value2)
+ || !value1->isValueID() || !value2->isValueID();
+ bool mustOrderAsYX = isVerticalPositionKeywordOnly(*value1) || isHorizontalPositionKeywordOnly(*value2);
+ if (mustOrderAsXY && mustOrderAsYX)
+ return false;
+ resultX = value1;
+ resultY = value2;
+ if (mustOrderAsYX)
+ std::swap(resultX, resultY);
+ return true;
+}
+
+static bool positionFromThreeOrFourValues(CSSPrimitiveValue** values, CSSValue*& resultX, CSSValue*& resultY)
+{
+ CSSPrimitiveValue* center = nullptr;
+ for (int i = 0; values[i]; i++) {
+ CSSPrimitiveValue* currentValue = values[i];
+ if (!currentValue->isValueID())
+ return false;
+ CSSValueID id = currentValue->getValueID();
+
+ if (id == CSSValueCenter) {
+ if (center)
+ return false;
+ center = currentValue;
+ continue;
+ }
+
+ CSSValue* result = nullptr;
+ if (values[i + 1] && !values[i + 1]->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 && resultY)
+ return false;
+ if (!resultX)
+ resultX = center;
+ else
+ resultY = center;
+ }
+
+ ASSERT(resultX && 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& range, CSSParserMode cssParserMode, UnitlessQuirk unitless, CSSValue*& resultX, CSSValue*& 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& 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& range, CSSParserMode cssParserMode, UnitlessQuirk unitless, CSSValue*& resultX, CSSValue*& 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& args, bool horizontal)
+{
+ if (args.peek().type() == IdentToken) {
+ if ((horizontal && consumeIdent<CSSValueLeft>(args)) || (!horizontal && consumeIdent<CSSValueTop>(args)))
+ return CSSPrimitiveValue::create(0., CSSPrimitiveValue::UnitType::Percentage);
+ if ((horizontal && consumeIdent<CSSValueRight>(args)) || (!horizontal && consumeIdent<CSSValueBottom>(args)))
+ return CSSPrimitiveValue::create(100., CSSPrimitiveValue::UnitType::Percentage);
+ if (consumeIdent<CSSValueCenter>(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& args, CSSParserMode cssParserMode)
+{
+ if (args.peek().id() == CSSValueCurrentcolor)
+ return nullptr;
+ return consumeColor(args, cssParserMode);
+}
+
+static bool consumeDeprecatedGradientColorStop(CSSParserTokenRange& range, CSSGradientColorStop& stop, CSSParserMode cssParserMode)
+{
+ CSSValueID id = range.peek().functionId();
+ if (id != CSSValueFrom && id != CSSValueTo && 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& 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 && args.atEnd();
+}
+
+static CSSValue* consumeDeprecatedGradient(CSSParserTokenRange& 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->setFirstX(point);
+ point = consumeDeprecatedGradientPoint(args, false);
+ if (!point)
+ return nullptr;
+ result->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)->setFirstRadius(radius);
+ }
+
+ point = consumeDeprecatedGradientPoint(args, true);
+ if (!point)
+ return nullptr;
+ result->setSecondX(point);
+ point = consumeDeprecatedGradientPoint(args, false);
+ if (!point)
+ return nullptr;
+ result->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)->setSecondRadius(radius);
+ }
+
+ CSSGradientColorStop stop;
+ while (consumeCommaIncludingWhitespace(args)) {
+ if (!consumeDeprecatedGradientColorStop(args, stop, cssParserMode))
+ return nullptr;
+ result->addStop(stop);
+ }
+
+ return result;
+}
+
+static bool consumeGradientColorStops(CSSParserTokenRange& range, CSSParserMode cssParserMode, CSSGradientValue* gradient)
+{
+ bool supportsColorHints = gradient->gradientType() == CSSLinearGradient || gradient->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 && (!supportsColorHints || previousStopWasColorHint))
+ return false;
+ previousStopWasColorHint = !stop.m_color;
+ stop.m_position = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
+ if (!stop.m_color && !stop.m_position)
+ return false;
+ gradient->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->stopCount() >= 2;
+}
+
+static CSSValue* consumeDeprecatedRadialGradient(CSSParserTokenRange& 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) && !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+
+ result->setFirstX(toCSSPrimitiveValue(centerX));
+ result->setSecondX(toCSSPrimitiveValue(centerX));
+ result->setFirstY(toCSSPrimitiveValue(centerY));
+ result->setSecondY(toCSSPrimitiveValue(centerY));
+
+ CSSPrimitiveValue* shape = consumeIdent<CSSValueCircle, CSSValueEllipse>(args);
+ CSSPrimitiveValue* sizeKeyword = consumeIdent<CSSValueClosestSide, CSSValueClosestCorner, CSSValueFarthestSide, CSSValueFarthestCorner, CSSValueContain, CSSValueCover>(args);
+ if (!shape)
+ shape = consumeIdent<CSSValueCircle, CSSValueEllipse>(args);
+ result->setShape(shape);
+ result->setSizingBehavior(sizeKeyword);
+
+ // Or, two lengths or percentages
+ if (!shape && !sizeKeyword) {
+ CSSPrimitiveValue* horizontalSize = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+ CSSPrimitiveValue* verticalSize = nullptr;
+ if (horizontalSize) {
+ verticalSize = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+ if (!verticalSize)
+ return nullptr;
+ consumeCommaIncludingWhitespace(args);
+ result->setEndHorizontalSize(horizontalSize);
+ result->setEndVerticalSize(verticalSize);
+ }
+ } else {
+ consumeCommaIncludingWhitespace(args);
+ }
+ if (!consumeGradientColorStops(args, cssParserMode, result))
+ return nullptr;
+
+ return result;
+}
+
+static CSSValue* consumeRadialGradient(CSSParserTokenRange& 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 || <length> ] |
+ // [ ellipse || [ <length> | <percentage> ]{2} ] |
+ // [ [ circle | ellipse] || <size-keyword> ]
+ for (int i = 0; i < 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 && horizontalSize)
+ return nullptr;
+ // Circles must have 0 or 1 lengths.
+ if (shape && shape->getValueID() == CSSValueCircle && verticalSize)
+ return nullptr;
+ // Ellipses must have 0 or 2 length/percentages.
+ if (shape && shape->getValueID() == CSSValueEllipse && horizontalSize && !verticalSize)
+ return nullptr;
+ // If there's only one size, it must be a length.
+ if (!verticalSize && horizontalSize && horizontalSize->isPercentage())
+ return nullptr;
+ if ((horizontalSize && horizontalSize->isCalculatedPercentageWithLength())
+ || (verticalSize && verticalSize->isCalculatedPercentageWithLength()))
+ return nullptr;
+
+ result->setShape(shape);
+ result->setSizingBehavior(sizeKeyword);
+ result->setEndHorizontalSize(horizontalSize);
+ result->setEndVerticalSize(verticalSize);
+
+ CSSValue* centerX = nullptr;
+ CSSValue* centerY = nullptr;
+ if (args.peek().id() == CSSValueAt) {
+ args.consumeIncludingWhitespace();
+ consumePosition(args, cssParserMode, UnitlessQuirk::Forbid, centerX, centerY);
+ if (!(centerX && centerY))
+ return nullptr;
+ result->setFirstX(centerX);
+ result->setFirstY(centerY);
+ // Right now, CSS radial gradients have the same start and end centers.
+ result->setSecondX(centerX);
+ result->setSecondY(centerY);
+ }
+
+ if ((shape || sizeKeyword || horizontalSize || centerX || centerY) && !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+ if (!consumeGradientColorStops(args, cssParserMode, result))
+ return nullptr;
+ return result;
+}
+
+static CSSValue* consumeLinearGradient(CSSParserTokenRange& args, CSSParserMode cssParserMode, CSSGradientRepeat repeating, CSSGradientType gradientType)
+{
+ CSSLinearGradientValue* result = CSSLinearGradientValue::create(repeating, gradientType);
+
+ bool expectComma = true;
+ CSSPrimitiveValue* angle = consumeAngle(args);
+ if (angle) {
+ result->setAngle(angle);
+ } else if (gradientType == CSSPrefixedLinearGradient || consumeIdent<CSSValueTo>(args)) {
+ CSSPrimitiveValue* endX = consumeIdent<CSSValueLeft, CSSValueRight>(args);
+ CSSPrimitiveValue* endY = consumeIdent<CSSValueBottom, CSSValueTop>(args);
+ if (!endX && !endY) {
+ if (gradientType == CSSLinearGradient)
+ return nullptr;
+ endY = CSSPrimitiveValue::createIdentifier(CSSValueTop);
+ expectComma = false;
+ } else if (!endX) {
+ endX = consumeIdent<CSSValueLeft, CSSValueRight>(args);
+ }
+
+ result->setFirstX(endX);
+ result->setFirstY(endY);
+ } else {
+ expectComma = false;
+ }
+
+ if (expectComma && !consumeCommaIncludingWhitespace(args))
+ return nullptr;
+ if (!consumeGradientColorStops(args, cssParserMode, result))
+ return nullptr;
+ return result;
+}
+
+CSSValue* consumeImageOrNone(CSSParserTokenRange& range, CSSParserContext context)
+{
+ if (range.peek().id() == CSSValueNone)
+ return consumeIdent(range);
+ return consumeImage(range, context);
+}
+
+static CSSValue* consumeCrossFade(CSSParserTokenRange& 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& percentageArg = args.consumeIncludingWhitespace();
+ if (percentageArg.type() == PercentageToken)
+ percentage = CSSPrimitiveValue::create(clampTo<double>(percentageArg.numericValue() / 100, 0, 1), CSSPrimitiveValue::UnitType::Number);
+ else if (percentageArg.type() == NumberToken)
+ percentage = CSSPrimitiveValue::create(clampTo<double>(percentageArg.numericValue(), 0, 1), CSSPrimitiveValue::UnitType::Number);
+
+ if (!percentage)
+ return nullptr;
+ return CSSCrossfadeValue::create(fromImageValue, toImageValue, percentage);
+}
+
+static CSSValue* consumePaint(CSSParserTokenRange& args, CSSParserContext context)
+{
+ DCHECK(RuntimeEnabledFeatures::cssPaintAPIEnabled());
+
+ CSSCustomIdentValue* name = consumeCustomIdent(args);
+ if (!name)
+ return nullptr;
+
+ return CSSPaintValue::create(name);
+}
+
+static CSSValue* consumeGeneratedImage(CSSParserTokenRange& 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()->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()->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()->count(UseCounter::DeprecatedWebKitGradient);
+ result = consumeDeprecatedGradient(args, context.mode());
+ } else if (id == CSSValueWebkitRadialGradient) {
+ // FIXME: This should send a deprecation message.
+ if (context.useCounter())
+ context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGradient);
+ result = consumeDeprecatedRadialGradient(args, context.mode(), NonRepeating);
+ } else if (id == CSSValueWebkitRepeatingRadialGradient) {
+ if (context.useCounter())
+ context.useCounter()->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& rawValue, const CSSParserContext& context)
+{
+ CSSValue* imageValue = CSSImageValue::create(rawValue, context.completeURL(rawValue));
+ toCSSImageValue(imageValue)->setReferrer(context.referrer());
+ return imageValue;
+}
+
+static CSSValue* consumeImageSet(CSSParserTokenRange& range, const CSSParserContext& 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->append(*image);
+
+ const CSSParserToken& token = args.consumeIncludingWhitespace();
+ if (token.type() != DimensionToken)
+ return nullptr;
+ if (token.value() != "x")
+ return nullptr;
+ DCHECK(token.unitType() == CSSPrimitiveValue::UnitType::Unknown);
+ double imageScaleFactor = token.numericValue();
+ if (imageScaleFactor <= 0)
+ return nullptr;
+ imageSet->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& 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 && 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
+// "AS IS" 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 "CSSCustomIdentValue.h"
+#include "CSSParserMode.h"
+#include "CSSParserTokenRange.h"
+#include "CSSPrimitiveValue.h"
+#include "Length.h" // 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&);
+bool consumeSlashIncludingWhitespace(CSSParserTokenRange&);
+// consumeFunction expects the range starts with a FunctionToken.
+CSSParserTokenRange consumeFunction(CSSParserTokenRange&);
+
+enum class UnitlessQuirk {
+ Allow,
+ Forbid
+};
+
+CSSPrimitiveValue* consumeInteger(CSSParserTokenRange&, double minimumValue = -std::numeric_limits<double>::max());
+CSSPrimitiveValue* consumePositiveInteger(CSSParserTokenRange&);
+bool consumeNumberRaw(CSSParserTokenRange&, double& result);
+CSSPrimitiveValue* consumeNumber(CSSParserTokenRange&, ValueRange);
+CSSPrimitiveValue* consumeLength(CSSParserTokenRange&, CSSParserMode, ValueRange, UnitlessQuirk = UnitlessQuirk::Forbid);
+CSSPrimitiveValue* consumePercent(CSSParserTokenRange&, ValueRange);
+CSSPrimitiveValue* consumeLengthOrPercent(CSSParserTokenRange&, CSSParserMode, ValueRange, UnitlessQuirk = UnitlessQuirk::Forbid);
+CSSPrimitiveValue* consumeAngle(CSSParserTokenRange&);
+CSSPrimitiveValue* consumeTime(CSSParserTokenRange&, ValueRange);
+
+CSSPrimitiveValue* consumeIdent(CSSParserTokenRange&);
+CSSPrimitiveValue* consumeIdentRange(CSSParserTokenRange&, CSSValueID lower, CSSValueID upper);
+template<CSSValueID, CSSValueID...> inline bool identMatches(CSSValueID id);
+template<CSSValueID... allowedIdents> CSSPrimitiveValue* consumeIdent(CSSParserTokenRange&);
+
+// FIXME-NEWPARSER CSSCustomIdentValue* consumeCustomIdent(CSSParserTokenRange&);
+CSSStringValue* consumeString(CSSParserTokenRange&);
+StringView consumeUrlAsStringView(CSSParserTokenRange&);
+CSSURIValue* consumeUrl(CSSParserTokenRange&);
+
+CSSValue* consumeColor(CSSParserTokenRange&, CSSParserMode, bool acceptQuirkyColors = false);
+
+CSSValuePair* consumePosition(CSSParserTokenRange&, CSSParserMode, UnitlessQuirk);
+bool consumePosition(CSSParserTokenRange&, CSSParserMode, UnitlessQuirk, CSSValue*& resultX, CSSValue*& resultY);
+bool consumeOneOrTwoValuedPosition(CSSParserTokenRange&, CSSParserMode, UnitlessQuirk, CSSValue*& resultX, CSSValue*& resultY);
+
+enum class ConsumeGeneratedImage {
+ Allow,
+ Forbid
+};
+
+CSSValue* consumeImage(CSSParserTokenRange&, CSSParserContext, ConsumeGeneratedImage = ConsumeGeneratedImage::Allow);
+CSSValue* consumeImageOrNone(CSSParserTokenRange&, CSSParserContext);
+
+// Template implementations are at the bottom of the file for readability.
+
+template<typename... emptyBaseCase> inline bool identMatches(CSSValueID) { return false; }
+template<CSSValueID head, CSSValueID... tail> inline bool identMatches(CSSValueID id)
+{
+ return id == head || identMatches<tail...>(id);
+}
+
+// FIXME-NEWPARSER - converted to a RefPtr return type from a raw ptr.
+template<CSSValueID... names> RefPtr<CSSPrimitiveValue> consumeIdent(CSSParserTokenRange& range)
+{
+ if (range.peek().type() != IdentToken || !identMatches<names...>(range.peek().id()))
+ return nullptr;
+ return CSSPrimitiveValue::createIdentifier(range.consumeIncludingWhitespace().id());
+}
+
+static inline bool isCSSWideKeyword(const CSSValueID& 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
+// "AS IS" 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 "config.h"
+#include "CSSTokenizer.h"
+
+#include "CSSParserIdioms.h"
+#include "CSSParserObserverWrapper.h"
+#include "CSSParserTokenRange.h"
+#include "CSSTokenizerInputStream.h"
+#include "HTMLParserIdioms.h"
+#include <wtf/unicode/CharacterNames.h>
+
+namespace WebCore {
+
+CSSTokenizer::Scope::Scope(const String& 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& string, CSSParserObserverWrapper& 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 == '\\' && !isNewLine(second);
+}
+
+CSSTokenizer::CSSTokenizer(CSSTokenizerInputStream& inputStream, Scope& 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() && 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 == '<');
+ if (m_input.peekWithoutReplacement(0) == '!'
+ && m_input.peekWithoutReplacement(1) == '-'
+ && m_input.peekWithoutReplacement(2) == '-') {
+ m_input.advance(3);
+ return CSSParserToken(CDOToken);
+ }
+ return CSSParserToken(DelimiterToken, '<');
+}
+
+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) == '-'
+ && m_input.peekWithoutReplacement(1) == '>') {
+ 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) == '+'
+ && (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] = {
+ &CSSTokenizer::endOfFile,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ &CSSTokenizer::whiteSpace,
+ &CSSTokenizer::whiteSpace,
+ 0,
+ &CSSTokenizer::whiteSpace,
+ &CSSTokenizer::whiteSpace,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ &CSSTokenizer::whiteSpace,
+ 0,
+ &CSSTokenizer::stringStart,
+ &CSSTokenizer::hash,
+ &CSSTokenizer::dollarSign,
+ 0,
+ 0,
+ &CSSTokenizer::stringStart,
+ &CSSTokenizer::leftParenthesis,
+ &CSSTokenizer::rightParenthesis,
+ &CSSTokenizer::asterisk,
+ &CSSTokenizer::plusOrFullStop,
+ &CSSTokenizer::comma,
+ &CSSTokenizer::hyphenMinus,
+ &CSSTokenizer::plusOrFullStop,
+ &CSSTokenizer::solidus,
+ &CSSTokenizer::asciiDigit,
+ &CSSTokenizer::asciiDigit,
+ &CSSTokenizer::asciiDigit,
+ &CSSTokenizer::asciiDigit,
+ &CSSTokenizer::asciiDigit,
+ &CSSTokenizer::asciiDigit,
+ &CSSTokenizer::asciiDigit,
+ &CSSTokenizer::asciiDigit,
+ &CSSTokenizer::asciiDigit,
+ &CSSTokenizer::asciiDigit,
+ &CSSTokenizer::colon,
+ &CSSTokenizer::semiColon,
+ &CSSTokenizer::lessThan,
+ 0,
+ 0,
+ 0,
+ &CSSTokenizer::commercialAt,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::letterU,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::leftBracket,
+ &CSSTokenizer::reverseSolidus,
+ &CSSTokenizer::rightBracket,
+ &CSSTokenizer::circumflexAccent,
+ &CSSTokenizer::nameStart,
+ 0,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::letterU,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::nameStart,
+ &CSSTokenizer::leftBrace,
+ &CSSTokenizer::verticalLine,
+ &CSSTokenizer::rightBrace,
+ &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 "next 3 codepoints are X" 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 < codePointsNumber);
+ codePointFunc = codePoints[cc];
+ } else
+ codePointFunc = &CSSTokenizer::nameStart;
+
+ if (codePointFunc)
+ return ((this)->*(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<isASCIIDigit>(numberLength);
+ next = m_input.peekWithoutReplacement(numberLength);
+ if (next == '.' && isASCIIDigit(m_input.peekWithoutReplacement(numberLength + 1))) {
+ type = NumberValueType;
+ numberLength = m_input.skipWhilePredicate<isASCIIDigit>(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<isASCIIDigit>(numberLength + 1);
+ } else if ((next == '+' || next == '-') && isASCIIDigit(m_input.peekWithoutReplacement(numberLength + 2))) {
+ type = NumberValueType;
+ numberLength = m_input.skipWhilePredicate<isASCIIDigit>(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, "url")) {
+ // 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 != '"' && 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 && isASCIIHexDigit(m_input.peekWithoutReplacement(0))) {
+ start = start * 16 + toASCIIHexValue(consume());
+ --lengthRemaining;
+ }
+
+ UChar32 end = start;
+ if (lengthRemaining && consumeIfNext('?')) {
+ do {
+ start *= 16;
+ end = end * 16 + 0xF;
+ --lengthRemaining;
+ } while (lengthRemaining && consumeIfNext('?'));
+ } else if (m_input.peekWithoutReplacement(0) == '-' && isASCIIHexDigit(m_input.peekWithoutReplacement(1))) {
+ m_input.advance();
+ lengthRemaining = 6;
+ end = 0;
+ do {
+ end = end * 16 + toASCIIHexValue(consume());
+ --lengthRemaining;
+ } while (lengthRemaining && 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 <= '\x8' || cc == '\xb' || (cc >= '\xe' && cc <= '\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 <= ' ' || cc == '\\' || cc == '"' || 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 == '"' || 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' && 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' && m_input.offset() + size < 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 < 6 && isASCIIHexDigit(m_input.peekWithoutReplacement(0))) {
+ cc = consume();
+ hexChars.append(cc);
+ consumedHexDigits++;
+ };
+ consumeSingleWhitespaceIfNext();
+ bool ok = false;
+ UChar32 codePoint = hexChars.toString().toUIntStrict(&ok, 16);
+ ASSERT(ok);
+ if (!codePoint || (0xD800 <= codePoint && codePoint <= 0xDFFF) || codePoint > 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 == '.' && 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& 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
+// "AS IS" 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 "CSSParserToken.h"
+#include "InputStreamPreprocessor.h"
+#include <climits>
+#include <wtf/text/StringView.h>
+#include <wtf/text/WTFString.h>
+
+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&);
+ Scope(const String&, CSSParserObserverWrapper&); // For the inspector
+
+ CSSParserTokenRange tokenRange();
+ unsigned tokenCount();
+
+ private:
+ void storeString(const String& string) { m_stringPool.append(string); }
+ Vector<CSSParserToken, 32> m_tokens;
+ // We only allocate strings when escapes are used.
+ Vector<String> m_stringPool;
+ String m_string;
+
+ friend class CSSTokenizer;
+ };
+
+private:
+ CSSTokenizer(CSSTokenizerInputStream&, Scope&);
+
+ 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&);
+
+ using CodePoint = CSSParserToken (CSSTokenizer::*)(UChar);
+ static const CodePoint codePoints[];
+
+ Vector<CSSParserTokenType, 8> m_blockStack;
+ CSSTokenizerInputStream& m_input;
+ Scope& 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
+// "AS IS" 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 "config.h"
+#include "CSSTokenizerInputStream.h"
+
+#include "HTMLParserIdioms.h"
+
+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->is8Bit()) {
+ const LChar* characters = m_string->characters8();
+ while (m_offset < m_stringLength && isHTMLSpace(characters[m_offset]))
+ ++m_offset;
+ } else {
+ const UChar* characters = m_string->characters16();
+ while (m_offset < m_stringLength && isHTMLSpace(characters[m_offset]))
+ ++m_offset;
+ }
+}
+
+double CSSTokenizerInputStream::getDouble(unsigned start, unsigned end) const
+{
+ ASSERT(start <= end && ((m_offset + end) <= m_stringLength));
+ bool isResultOK = false;
+ double result = 0.0;
+ if (start < end) {
+ if (m_string->is8Bit())
+ result = charactersToDouble(m_string->characters8() + m_offset + start, end - start, &isResultOK);
+ else
+ result = charactersToDouble(m_string->characters16() + m_offset + start, end - start, &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
+// "AS IS" 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 <wtf/text/StringView.h>
+#include <wtf/text/WTFString.h>
+
+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 >= 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) >= 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<bool characterPredicate(UChar)>
+ unsigned skipWhilePredicate(unsigned offset)
+ {
+ if (m_string->is8Bit()) {
+ const LChar* characters8 = m_string->characters8();
+ while ((m_offset + offset) < m_stringLength && characterPredicate(characters8[m_offset + offset]))
+ ++offset;
+ } else {
+ const UChar* characters16 = m_string->characters16();
+ while ((m_offset + offset) < m_stringLength && 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 <= 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<StringImpl> 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>